ImsPhone.java revision 888c60a7fe1c8f3612ab8e8ec5f2f7ca8f24e766
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.internal.telephony.imsphone; 18 19import android.content.Context; 20import android.os.AsyncResult; 21import android.os.Handler; 22import android.os.Message; 23import android.os.Registrant; 24import android.os.RegistrantList; 25 26import android.telephony.PhoneNumberUtils; 27import android.telephony.ServiceState; 28import android.telephony.Rlog; 29import android.text.TextUtils; 30 31import com.android.ims.ImsCallForwardInfo; 32import com.android.ims.ImsException; 33import com.android.ims.ImsReasonInfo; 34import com.android.ims.ImsSsInfo; 35import com.android.ims.ImsUtInterface; 36 37import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOC; 38import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOIC; 39import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOICxH; 40import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC; 41import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr; 42import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_ALL; 43import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MO; 44import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MT; 45 46import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE; 47import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; 48import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE; 49import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION; 50import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; 51import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; 52import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; 53import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; 54import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; 55import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; 56import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; 57import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NONE; 58 59import com.android.internal.telephony.Call; 60import com.android.internal.telephony.CallForwardInfo; 61import com.android.internal.telephony.CallStateException; 62import com.android.internal.telephony.CallTracker; 63import com.android.internal.telephony.CommandException; 64import com.android.internal.telephony.CommandsInterface; 65import com.android.internal.telephony.Connection; 66import com.android.internal.telephony.Phone; 67import com.android.internal.telephony.PhoneBase; 68import com.android.internal.telephony.PhoneConstants; 69import com.android.internal.telephony.PhoneNotifier; 70import com.android.internal.telephony.Subscription; 71import com.android.internal.telephony.uicc.IccRecords; 72 73import java.util.ArrayList; 74import java.util.List; 75 76/** 77 * {@hide} 78 */ 79public class ImsPhone extends ImsPhoneBase { 80 private static final String LOG_TAG = "ImsPhone"; 81 private static final boolean DBG = true; 82 private static final boolean VDBG = false; // STOPSHIP if true 83 84 protected static final int EVENT_SET_CALL_BARRING_DONE = EVENT_LAST + 1; 85 protected static final int EVENT_GET_CALL_BARRING_DONE = EVENT_LAST + 2; 86 protected static final int EVENT_SET_CALL_WAITING_DONE = EVENT_LAST + 3; 87 protected static final int EVENT_GET_CALL_WAITING_DONE = EVENT_LAST + 4; 88 89 public static final String CS_FALLBACK = "cs_fallback"; 90 91 // Instance Variables 92 PhoneBase mDefaultPhone; 93 ImsPhoneCallTracker mCT; 94 ArrayList <ImsPhoneMmiCode> mPendingMMIs = new ArrayList<ImsPhoneMmiCode>(); 95 96 Registrant mPostDialHandler; 97 ServiceState mSS = new ServiceState(); 98 99 // To redial silently through GSM or CDMA when dialing through IMS fails 100 private String mLastDialString; 101 102 private final RegistrantList mSilentRedialRegistrants 103 = new RegistrantList(); 104 105 // Create Cf (Call forward) so that dialling number & 106 // mIsCfu (true if reason is call forward unconditional) 107 // mOnComplete (Message object passed by client) can be packed & 108 // given as a single Cf object as user data to UtInterface. 109 private static class Cf { 110 final String mSetCfNumber; 111 final Message mOnComplete; 112 final boolean mIsCfu; 113 114 Cf(String cfNumber, boolean isCfu, Message onComplete) { 115 mSetCfNumber = cfNumber; 116 mIsCfu = isCfu; 117 mOnComplete = onComplete; 118 } 119 } 120 121 // Constructors 122 123 ImsPhone(Context context, PhoneNotifier notifier, Phone defaultPhone) { 124 super("ImsPhone", context, notifier); 125 126 mDefaultPhone = (PhoneBase) defaultPhone; 127 mCT = new ImsPhoneCallTracker(this); 128 mSS.setStateOff(); 129 130 mPhoneId = mDefaultPhone.getPhoneId(); 131 } 132 133 @Override 134 public void dispose() { 135 Rlog.d(LOG_TAG, "dispose"); 136 // Nothing to dispose in PhoneBase 137 //super.dispose(); 138 mPendingMMIs.clear(); 139 mCT.dispose(); 140 141 //Force all referenced classes to unregister their former registered events 142 } 143 144 @Override 145 public void removeReferences() { 146 Rlog.d(LOG_TAG, "removeReferences"); 147 super.removeReferences(); 148 149 mCT = null; 150 mSS = null; 151 } 152 153 @Override 154 public ServiceState 155 getServiceState() { 156 return mSS; 157 } 158 159 /* package */ void setServiceState(int state) { 160 mSS.setState(state); 161 } 162 163 @Override 164 public CallTracker getCallTracker() { 165 return mCT; 166 } 167 168 @Override 169 public List<? extends ImsPhoneMmiCode> 170 getPendingMmiCodes() { 171 return mPendingMMIs; 172 } 173 174 175 @Override 176 public void 177 acceptCall() throws CallStateException { 178 mCT.acceptCall(); 179 } 180 181 @Override 182 public void 183 rejectCall() throws CallStateException { 184 mCT.rejectCall(); 185 } 186 187 @Override 188 public void 189 switchHoldingAndActive() throws CallStateException { 190 mCT.switchWaitingOrHoldingAndActive(); 191 } 192 193 @Override 194 public boolean canConference() { 195 return mCT.canConference(); 196 } 197 198 public boolean canDial() { 199 return mCT.canDial(); 200 } 201 202 @Override 203 public void conference() { 204 mCT.conference(); 205 } 206 207 @Override 208 public void clearDisconnected() { 209 mCT.clearDisconnected(); 210 } 211 212 @Override 213 public boolean canTransfer() { 214 return mCT.canTransfer(); 215 } 216 217 @Override 218 public void explicitCallTransfer() { 219 mCT.explicitCallTransfer(); 220 } 221 222 @Override 223 public ImsPhoneCall 224 getForegroundCall() { 225 return mCT.mForegroundCall; 226 } 227 228 @Override 229 public ImsPhoneCall 230 getBackgroundCall() { 231 return mCT.mBackgroundCall; 232 } 233 234 @Override 235 public ImsPhoneCall 236 getRingingCall() { 237 return mCT.mRingingCall; 238 } 239 240 private boolean handleCallDeflectionIncallSupplementaryService( 241 String dialString) { 242 if (dialString.length() > 1) { 243 return false; 244 } 245 246 if (getRingingCall().getState() != ImsPhoneCall.State.IDLE) { 247 if (DBG) Rlog.d(LOG_TAG, "MmiCode 0: rejectCall"); 248 try { 249 mCT.rejectCall(); 250 } catch (CallStateException e) { 251 if (DBG) Rlog.d(LOG_TAG, "reject failed", e); 252 notifySuppServiceFailed(Phone.SuppService.REJECT); 253 } 254 } else if (getBackgroundCall().getState() != ImsPhoneCall.State.IDLE) { 255 if (DBG) Rlog.d(LOG_TAG, "MmiCode 0: hangupWaitingOrBackground"); 256 try { 257 mCT.hangup(getBackgroundCall()); 258 } catch (CallStateException e) { 259 if (DBG) Rlog.d(LOG_TAG, "hangup failed", e); 260 } 261 } 262 263 return true; 264 } 265 266 267 private boolean handleCallWaitingIncallSupplementaryService( 268 String dialString) { 269 int len = dialString.length(); 270 271 if (len > 2) { 272 return false; 273 } 274 275 ImsPhoneCall call = getForegroundCall(); 276 277 try { 278 if (len > 1) { 279 if (DBG) Rlog.d(LOG_TAG, "not support 1X SEND"); 280 notifySuppServiceFailed(Phone.SuppService.HANGUP); 281 } else { 282 if (call.getState() != ImsPhoneCall.State.IDLE) { 283 if (DBG) Rlog.d(LOG_TAG, "MmiCode 1: hangup foreground"); 284 mCT.hangup(call); 285 } else { 286 if (DBG) Rlog.d(LOG_TAG, "MmiCode 1: switchWaitingOrHoldingAndActive"); 287 mCT.switchWaitingOrHoldingAndActive(); 288 } 289 } 290 } catch (CallStateException e) { 291 if (DBG) Rlog.d(LOG_TAG, "hangup failed", e); 292 notifySuppServiceFailed(Phone.SuppService.HANGUP); 293 } 294 295 return true; 296 } 297 298 private boolean handleCallHoldIncallSupplementaryService(String dialString) { 299 int len = dialString.length(); 300 301 if (len > 2) { 302 return false; 303 } 304 305 ImsPhoneCall call = getForegroundCall(); 306 307 if (len > 1) { 308 if (DBG) Rlog.d(LOG_TAG, "separate not supported"); 309 notifySuppServiceFailed(Phone.SuppService.SEPARATE); 310 } else { 311 try { 312 if (getRingingCall().getState() != ImsPhoneCall.State.IDLE) { 313 if (DBG) Rlog.d(LOG_TAG, "MmiCode 2: accept ringing call"); 314 mCT.acceptCall(); 315 } else { 316 if (DBG) Rlog.d(LOG_TAG, "MmiCode 2: switchWaitingOrHoldingAndActive"); 317 mCT.switchWaitingOrHoldingAndActive(); 318 } 319 } catch (CallStateException e) { 320 if (DBG) Rlog.d(LOG_TAG, "switch failed", e); 321 notifySuppServiceFailed(Phone.SuppService.SWITCH); 322 } 323 } 324 325 return true; 326 } 327 328 private boolean handleMultipartyIncallSupplementaryService( 329 String dialString) { 330 if (dialString.length() > 1) { 331 return false; 332 } 333 334 if (DBG) Rlog.d(LOG_TAG, "MmiCode 3: merge calls"); 335 conference(); 336 return true; 337 } 338 339 private boolean handleEctIncallSupplementaryService(String dialString) { 340 341 int len = dialString.length(); 342 343 if (len != 1) { 344 return false; 345 } 346 347 if (DBG) Rlog.d(LOG_TAG, "MmiCode 4: not support explicit call transfer"); 348 notifySuppServiceFailed(Phone.SuppService.TRANSFER); 349 return true; 350 } 351 352 private boolean handleCcbsIncallSupplementaryService(String dialString) { 353 if (dialString.length() > 1) { 354 return false; 355 } 356 357 Rlog.i(LOG_TAG, "MmiCode 5: CCBS not supported!"); 358 // Treat it as an "unknown" service. 359 notifySuppServiceFailed(Phone.SuppService.UNKNOWN); 360 return true; 361 } 362 363 @Override 364 public boolean handleInCallMmiCommands(String dialString) { 365 if (!isInCall()) { 366 return false; 367 } 368 369 if (TextUtils.isEmpty(dialString)) { 370 return false; 371 } 372 373 boolean result = false; 374 char ch = dialString.charAt(0); 375 switch (ch) { 376 case '0': 377 result = handleCallDeflectionIncallSupplementaryService( 378 dialString); 379 break; 380 case '1': 381 result = handleCallWaitingIncallSupplementaryService( 382 dialString); 383 break; 384 case '2': 385 result = handleCallHoldIncallSupplementaryService(dialString); 386 break; 387 case '3': 388 result = handleMultipartyIncallSupplementaryService(dialString); 389 break; 390 case '4': 391 result = handleEctIncallSupplementaryService(dialString); 392 break; 393 case '5': 394 result = handleCcbsIncallSupplementaryService(dialString); 395 break; 396 default: 397 break; 398 } 399 400 return result; 401 } 402 403 boolean isInCall() { 404 ImsPhoneCall.State foregroundCallState = getForegroundCall().getState(); 405 ImsPhoneCall.State backgroundCallState = getBackgroundCall().getState(); 406 ImsPhoneCall.State ringingCallState = getRingingCall().getState(); 407 408 return (foregroundCallState.isAlive() || 409 backgroundCallState.isAlive() || 410 ringingCallState.isAlive()); 411 } 412 413 @Override 414 public Connection 415 dial(String dialString) throws CallStateException { 416 // Need to make sure dialString gets parsed properly 417 String newDialString = PhoneNumberUtils.stripSeparators(dialString); 418 419 // handle in-call MMI first if applicable 420 if (handleInCallMmiCommands(newDialString)) { 421 return null; 422 } 423 424 if (mDefaultPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) { 425 return mCT.dial(dialString); 426 } 427 428 // Only look at the Network portion for mmi 429 String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString); 430 ImsPhoneMmiCode mmi = 431 ImsPhoneMmiCode.newFromDialString(networkPortion, this); 432 if (DBG) Rlog.d(LOG_TAG, 433 "dialing w/ mmi '" + mmi + "'..."); 434 435 if (mmi == null) { 436 return mCT.dial(dialString); 437 } else if (mmi.isTemporaryModeCLIR()) { 438 return mCT.dial(mmi.getDialingNumber(), mmi.getCLIRMode()); 439 } else if (!mmi.isSupportedOverImsPhone()) { 440 // If the mmi is not supported by IMS service, 441 // try to initiate dialing with default phone 442 throw new CallStateException(CS_FALLBACK); 443 } else { 444 mPendingMMIs.add(mmi); 445 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 446 mmi.processCode(); 447 448 return null; 449 } 450 } 451 452 453 @Override 454 public void 455 sendDtmf(char c) { 456 if (!PhoneNumberUtils.is12Key(c)) { 457 Rlog.e(LOG_TAG, 458 "sendDtmf called with invalid character '" + c + "'"); 459 } else { 460 if (mCT.mState == PhoneConstants.State.OFFHOOK) { 461 mCT.sendDtmf(c); 462 } 463 } 464 } 465 466 @Override 467 public void 468 startDtmf(char c) { 469 if (!PhoneNumberUtils.is12Key(c)) { 470 Rlog.e(LOG_TAG, 471 "startDtmf called with invalid character '" + c + "'"); 472 } else { 473 sendDtmf(c); 474 } 475 } 476 477 @Override 478 public void 479 stopDtmf() { 480 // no op 481 } 482 483 @Override 484 public void setOnPostDialCharacter(Handler h, int what, Object obj) { 485 mPostDialHandler = new Registrant(h, what, obj); 486 } 487 488 /*package*/ void notifyIncomingRing() { 489 if (DBG) Rlog.d(LOG_TAG, "notifyIncomingRing"); 490 AsyncResult ar = new AsyncResult(null, null, null); 491 sendMessage(obtainMessage(EVENT_CALL_RING, ar)); 492 } 493 494 @Override 495 public void setMute(boolean muted) { 496 mCT.setMute(muted); 497 } 498 499 @Override 500 public boolean getMute() { 501 return mCT.getMute(); 502 } 503 504 @Override 505 public PhoneConstants.State getState() { 506 return mCT.mState; 507 } 508 509 private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { 510 switch (commandInterfaceCFReason) { 511 case CF_REASON_UNCONDITIONAL: 512 case CF_REASON_BUSY: 513 case CF_REASON_NO_REPLY: 514 case CF_REASON_NOT_REACHABLE: 515 case CF_REASON_ALL: 516 case CF_REASON_ALL_CONDITIONAL: 517 return true; 518 default: 519 return false; 520 } 521 } 522 523 private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { 524 switch (commandInterfaceCFAction) { 525 case CF_ACTION_DISABLE: 526 case CF_ACTION_ENABLE: 527 case CF_ACTION_REGISTRATION: 528 case CF_ACTION_ERASURE: 529 return true; 530 default: 531 return false; 532 } 533 } 534 535 private boolean isCfEnable(int action) { 536 return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); 537 } 538 539 private int getConditionFromCFReason(int reason) { 540 switch(reason) { 541 case CF_REASON_UNCONDITIONAL: return ImsUtInterface.CDIV_CF_UNCONDITIONAL; 542 case CF_REASON_BUSY: return ImsUtInterface.CDIV_CF_BUSY; 543 case CF_REASON_NO_REPLY: return ImsUtInterface.CDIV_CF_NO_REPLY; 544 case CF_REASON_NOT_REACHABLE: return ImsUtInterface.CDIV_CF_NOT_REACHABLE; 545 default: 546 break; 547 } 548 549 return ImsUtInterface.INVALID; 550 } 551 552 private int getCFReasonFromCondition(int condition) { 553 switch(condition) { 554 case ImsUtInterface.CDIV_CF_UNCONDITIONAL: return CF_REASON_UNCONDITIONAL; 555 case ImsUtInterface.CDIV_CF_BUSY: return CF_REASON_BUSY; 556 case ImsUtInterface.CDIV_CF_NO_REPLY: return CF_REASON_NO_REPLY; 557 case ImsUtInterface.CDIV_CF_NOT_REACHABLE: return CF_REASON_NOT_REACHABLE; 558 default: 559 break; 560 } 561 562 return CF_REASON_NOT_REACHABLE; 563 } 564 565 private int getActionFromCFAction(int action) { 566 switch(action) { 567 case CF_ACTION_DISABLE: return ImsUtInterface.ACTION_DEACTIVATION; 568 case CF_ACTION_ENABLE: return ImsUtInterface.ACTION_ACTIVATION; 569 case CF_ACTION_ERASURE: return ImsUtInterface.ACTION_ERASURE; 570 case CF_ACTION_REGISTRATION: return ImsUtInterface.ACTION_REGISTRATION; 571 default: 572 break; 573 } 574 575 return ImsUtInterface.INVALID; 576 } 577 578 @Override 579 public void getCallForwardingOption(int commandInterfaceCFReason, 580 Message onComplete) { 581 if (DBG) Rlog.d(LOG_TAG, "getCallForwardingOption reason=" + commandInterfaceCFReason); 582 if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { 583 if (DBG) Rlog.d(LOG_TAG, "requesting call forwarding query."); 584 Message resp; 585 resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete); 586 587 try { 588 ImsUtInterface ut = mCT.getUtInterface(); 589 ut.queryCallForward(getConditionFromCFReason(commandInterfaceCFReason),null,resp); 590 } catch (ImsException e) { 591 sendErrorResponse(onComplete, e); 592 } 593 } else if (onComplete != null) { 594 sendErrorResponse(onComplete); 595 } 596 } 597 598 @Override 599 public void setCallForwardingOption(int commandInterfaceCFAction, 600 int commandInterfaceCFReason, 601 String dialingNumber, 602 int timerSeconds, 603 Message onComplete) { 604 if (DBG) Rlog.d(LOG_TAG, "setCallForwardingOption action=" + commandInterfaceCFAction 605 + ", reason=" + commandInterfaceCFReason); 606 if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && 607 (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { 608 Message resp; 609 Cf cf = new Cf(dialingNumber, 610 (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL ? true : false), 611 onComplete); 612 resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE, 613 isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cf); 614 615 try { 616 ImsUtInterface ut = mCT.getUtInterface(); 617 ut.updateCallForward(getActionFromCFAction(commandInterfaceCFAction), 618 getConditionFromCFReason(commandInterfaceCFReason), 619 dialingNumber, 620 timerSeconds, 621 onComplete); 622 } catch (ImsException e) { 623 sendErrorResponse(onComplete, e); 624 } 625 } else if (onComplete != null) { 626 sendErrorResponse(onComplete); 627 } 628 } 629 630 @Override 631 public void getCallWaiting(Message onComplete) { 632 if (DBG) Rlog.d(LOG_TAG, "getCallWaiting"); 633 Message resp; 634 resp = obtainMessage(EVENT_GET_CALL_WAITING_DONE, onComplete); 635 636 try { 637 ImsUtInterface ut = mCT.getUtInterface(); 638 ut.queryCallWaiting(resp); 639 } catch (ImsException e) { 640 sendErrorResponse(onComplete, e); 641 } 642 } 643 644 @Override 645 public void setCallWaiting(boolean enable, Message onComplete) { 646 if (DBG) Rlog.d(LOG_TAG, "setCallWaiting enable=" + enable); 647 Message resp; 648 resp = obtainMessage(EVENT_SET_CALL_WAITING_DONE, onComplete); 649 650 try { 651 ImsUtInterface ut = mCT.getUtInterface(); 652 ut.updateCallWaiting(enable, resp); 653 } catch (ImsException e) { 654 sendErrorResponse(onComplete, e); 655 } 656 } 657 658 private int getCBTypeFromFacility(String facility) { 659 if (CB_FACILITY_BAOC.equals(facility)) { 660 return ImsUtInterface.CB_BAOC; 661 } else if (CB_FACILITY_BAOIC.equals(facility)) { 662 return ImsUtInterface.CB_BOIC; 663 } else if (CB_FACILITY_BAOICxH.equals(facility)) { 664 return ImsUtInterface.CB_BOIC_EXHC; 665 } else if (CB_FACILITY_BAIC.equals(facility)) { 666 return ImsUtInterface.CB_BAIC; 667 } else if (CB_FACILITY_BAICr.equals(facility)) { 668 return ImsUtInterface.CB_BIC_WR; 669 } else if (CB_FACILITY_BA_ALL.equals(facility)) { 670 return 0; 671 } else if (CB_FACILITY_BA_MO.equals(facility)) { 672 return 0; 673 } else if (CB_FACILITY_BA_MT.equals(facility)) { 674 return 0; 675 } 676 677 return 0; 678 } 679 680 /* package */ 681 void getCallBarring(String facility, Message onComplete) { 682 if (DBG) Rlog.d(LOG_TAG, "getCallBarring facility=" + facility); 683 Message resp; 684 resp = obtainMessage(EVENT_GET_CALL_BARRING_DONE, onComplete); 685 686 try { 687 ImsUtInterface ut = mCT.getUtInterface(); 688 ut.queryCallBarring(getCBTypeFromFacility(facility), resp); 689 } catch (ImsException e) { 690 sendErrorResponse(onComplete, e); 691 } 692 } 693 694 /* package */ 695 void setCallBarring(String facility, boolean lockState, String password, Message onComplete) { 696 if (DBG) Rlog.d(LOG_TAG, "setCallBarring facility=" + facility 697 + ", lockState=" + lockState); 698 Message resp; 699 resp = obtainMessage(EVENT_SET_CALL_BARRING_DONE, onComplete); 700 701 try { 702 ImsUtInterface ut = mCT.getUtInterface(); 703 // password is not required with Ut interface 704 ut.updateCallBarring(getCBTypeFromFacility(facility), lockState, resp); 705 } catch (ImsException e) { 706 sendErrorResponse(onComplete, e); 707 } 708 } 709 710 @Override 711 public void sendUssdResponse(String ussdMessge) { 712 Rlog.d(LOG_TAG, "sendUssdResponse"); 713 ImsPhoneMmiCode mmi = ImsPhoneMmiCode.newFromUssdUserInput(ussdMessge, this); 714 mPendingMMIs.add(mmi); 715 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 716 mmi.sendUssd(ussdMessge); 717 } 718 719 /* package */ 720 void sendUSSD (String ussdString, Message response) { 721 mCT.sendUSSD(ussdString, response); 722 } 723 724 /* package */ 725 void cancelUSSD() { 726 mCT.cancelUSSD(); 727 } 728 729 /* package */ 730 void sendErrorResponse(Message onComplete) { 731 Rlog.d(LOG_TAG, "sendErrorResponse"); 732 if (onComplete != null) { 733 AsyncResult.forMessage(onComplete, null, 734 new CommandException(CommandException.Error.GENERIC_FAILURE)); 735 onComplete.sendToTarget(); 736 } 737 } 738 739 /* package */ 740 void sendErrorResponse(Message onComplete, Throwable e) { 741 Rlog.d(LOG_TAG, "sendErrorResponse"); 742 if (onComplete != null) { 743 AsyncResult.forMessage(onComplete, null, getCommandException(e)); 744 onComplete.sendToTarget(); 745 } 746 } 747 748 /* package */ 749 void sendErrorResponse(Message onComplete, ImsReasonInfo reasonInfo) { 750 Rlog.d(LOG_TAG, "sendErrorResponse reasonCode=" + reasonInfo.getCode()); 751 if (onComplete != null) { 752 AsyncResult.forMessage(onComplete, null, getCommandException(reasonInfo.getCode())); 753 onComplete.sendToTarget(); 754 } 755 } 756 757 /* package */ 758 CommandException getCommandException(int code) { 759 Rlog.d(LOG_TAG, "getCommandException code=" + code); 760 CommandException.Error error = CommandException.Error.GENERIC_FAILURE; 761 762 switch(code) { 763 case ImsReasonInfo.CODE_UT_NOT_SUPPORTED: 764 error = CommandException.Error.REQUEST_NOT_SUPPORTED; 765 break; 766 case ImsReasonInfo.CODE_UT_CB_PASSWORD_MISMATCH: 767 error = CommandException.Error.PASSWORD_INCORRECT; 768 break; 769 default: 770 break; 771 } 772 773 return new CommandException(error); 774 } 775 776 /* package */ 777 CommandException getCommandException(Throwable e) { 778 CommandException ex = null; 779 780 if (e instanceof ImsException) { 781 ex = getCommandException(((ImsException)e).getCode()); 782 } else { 783 Rlog.d(LOG_TAG, "getCommandException generic failure"); 784 ex = new CommandException(CommandException.Error.GENERIC_FAILURE); 785 } 786 return ex; 787 } 788 789 private void 790 onNetworkInitiatedUssd(ImsPhoneMmiCode mmi) { 791 Rlog.d(LOG_TAG, "onNetworkInitiatedUssd"); 792 mMmiCompleteRegistrants.notifyRegistrants( 793 new AsyncResult(null, mmi, null)); 794 } 795 796 /* package */ 797 void onIncomingUSSD (int ussdMode, String ussdMessage) { 798 if (DBG) Rlog.d(LOG_TAG, "onIncomingUSSD ussdMode=" + ussdMode); 799 800 boolean isUssdError; 801 boolean isUssdRequest; 802 803 isUssdRequest 804 = (ussdMode == CommandsInterface.USSD_MODE_REQUEST); 805 806 isUssdError 807 = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY 808 && ussdMode != CommandsInterface.USSD_MODE_REQUEST); 809 810 ImsPhoneMmiCode found = null; 811 for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { 812 if(mPendingMMIs.get(i).isPendingUSSD()) { 813 found = mPendingMMIs.get(i); 814 break; 815 } 816 } 817 818 if (found != null) { 819 // Complete pending USSD 820 if (isUssdError) { 821 found.onUssdFinishedError(); 822 } else { 823 found.onUssdFinished(ussdMessage, isUssdRequest); 824 } 825 } else { // pending USSD not found 826 // The network may initiate its own USSD request 827 828 // ignore everything that isnt a Notify or a Request 829 // also, discard if there is no message to present 830 if (!isUssdError && ussdMessage != null) { 831 ImsPhoneMmiCode mmi; 832 mmi = ImsPhoneMmiCode.newNetworkInitiatedUssd(ussdMessage, 833 isUssdRequest, 834 ImsPhone.this); 835 onNetworkInitiatedUssd(mmi); 836 } 837 } 838 } 839 840 /** 841 * Removes the given MMI from the pending list and notifies 842 * registrants that it is complete. 843 * @param mmi MMI that is done 844 */ 845 /*package*/ void 846 onMMIDone(ImsPhoneMmiCode mmi) { 847 /* Only notify complete if it's on the pending list. 848 * Otherwise, it's already been handled (eg, previously canceled). 849 * The exception is cancellation of an incoming USSD-REQUEST, which is 850 * not on the list. 851 */ 852 if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest()) { 853 mMmiCompleteRegistrants.notifyRegistrants( 854 new AsyncResult(null, mmi, null)); 855 } 856 } 857 858 public ImsPhoneConnection getHandoverConnection() { 859 // handover for single foreground call 860 ImsPhoneConnection conn = getForegroundCall().getHandoverConnection(); 861 862 // handover for single background call 863 if (conn == null) { 864 conn = getBackgroundCall().getHandoverConnection(); 865 } 866 867 // handover for single ringing call 868 if (conn == null) { 869 conn = getRingingCall().getHandoverConnection(); 870 } 871 872 return conn; 873 } 874 875 public void notifySrvccState(Call.SrvccState state) { 876 mCT.notifySrvccState(state); 877 } 878 879 /* package */ void 880 initiateSilentRedial() { 881 String result = mLastDialString; 882 AsyncResult ar = new AsyncResult(null, result, null); 883 if (ar != null) { 884 mSilentRedialRegistrants.notifyRegistrants(ar); 885 } 886 } 887 888 public void registerForSilentRedial(Handler h, int what, Object obj) { 889 mSilentRedialRegistrants.addUnique(h, what, obj); 890 } 891 892 public void unregisterForSilentRedial(Handler h) { 893 mSilentRedialRegistrants.remove(h); 894 } 895 896 @Override 897 public long getSubId() { 898 return mDefaultPhone.getSubId(); 899 } 900 901 @Override 902 public int getPhoneId() { 903 return mDefaultPhone.getPhoneId(); 904 } 905 906 @Override 907 public Subscription getSubscriptionInfo() { 908 return mDefaultPhone.getSubscriptionInfo(); 909 } 910 911 private IccRecords getIccRecords() { 912 return mDefaultPhone.mIccRecords.get(); 913 } 914 915 private CallForwardInfo getCallForwardInfo(ImsCallForwardInfo info) { 916 CallForwardInfo cfInfo = new CallForwardInfo(); 917 cfInfo.status = info.mStatus; 918 cfInfo.reason = getCFReasonFromCondition(info.mCondition); 919 cfInfo.serviceClass = SERVICE_CLASS_VOICE; 920 cfInfo.toa = info.mToA; 921 cfInfo.number = info.mNumber; 922 cfInfo.timeSeconds = info.mTimeSeconds; 923 return cfInfo; 924 } 925 926 private CallForwardInfo[] handleCfQueryResult(ImsCallForwardInfo[] infos) { 927 CallForwardInfo[] cfInfos = null; 928 929 if (infos != null && infos.length != 0) { 930 cfInfos = new CallForwardInfo[infos.length]; 931 } 932 933 IccRecords r = getIccRecords(); 934 if (infos == null || infos.length == 0) { 935 if (r != null) { 936 // Assume the default is not active 937 // Set unconditional CFF in SIM to false 938 r.setVoiceCallForwardingFlag(1, false, null); 939 } 940 } else { 941 for (int i = 0, s = infos.length; i < s; i++) { 942 if (infos[i].mCondition == ImsUtInterface.CDIV_CF_UNCONDITIONAL) { 943 if (r != null) { 944 r.setVoiceCallForwardingFlag(1, (infos[i].mStatus == 1), 945 infos[i].mNumber); 946 } 947 } 948 cfInfos[i] = getCallForwardInfo(infos[i]); 949 } 950 } 951 952 return cfInfos; 953 } 954 955 private int[] handleCbQueryResult(ImsSsInfo[] infos) { 956 int[] cbInfos = new int[1]; 957 cbInfos[0] = SERVICE_CLASS_NONE; 958 959 if (infos[0].mStatus == 1) { 960 cbInfos[0] = SERVICE_CLASS_VOICE; 961 } 962 963 return cbInfos; 964 } 965 966 private int[] handleCwQueryResult(ImsSsInfo[] infos) { 967 int[] cwInfos = new int[2]; 968 cwInfos[0] = 0; 969 970 if (infos[0].mStatus == 1) { 971 cwInfos[0] = 1; 972 cwInfos[1] = SERVICE_CLASS_VOICE; 973 } 974 975 return cwInfos; 976 } 977 978 private void 979 sendResponse(Message onComplete, Object result, Throwable e) { 980 if (onComplete != null) { 981 CommandException ex = null; 982 if (e != null) { 983 ex = getCommandException(e); 984 } 985 AsyncResult.forMessage(onComplete, result, ex); 986 onComplete.sendToTarget(); 987 } 988 } 989 990 @Override 991 public void handleMessage (Message msg) { 992 AsyncResult ar = (AsyncResult) msg.obj; 993 Message onComplete; 994 995 if (DBG) Rlog.d(LOG_TAG, "handleMessage what=" + msg.what); 996 switch (msg.what) { 997 case EVENT_SET_CALL_FORWARD_DONE: 998 IccRecords r = getIccRecords(); 999 Cf cf = (Cf) ar.userObj; 1000 if (cf.mIsCfu && ar.exception == null && r != null) { 1001 r.setVoiceCallForwardingFlag(1, msg.arg1 == 1, cf.mSetCfNumber); 1002 } 1003 sendResponse(cf.mOnComplete, null, ar.exception); 1004 break; 1005 1006 case EVENT_GET_CALL_FORWARD_DONE: 1007 CallForwardInfo[] cfInfos = null; 1008 if (ar.exception == null) { 1009 cfInfos = handleCfQueryResult((ImsCallForwardInfo[])ar.result); 1010 } 1011 sendResponse((Message) ar.userObj, cfInfos, ar.exception); 1012 break; 1013 1014 case EVENT_GET_CALL_BARRING_DONE: 1015 case EVENT_GET_CALL_WAITING_DONE: 1016 int[] ssInfos = null; 1017 if (ar.exception == null) { 1018 if (msg.what == EVENT_GET_CALL_BARRING_DONE) { 1019 ssInfos = handleCbQueryResult((ImsSsInfo[])ar.result); 1020 } else if (msg.what == EVENT_GET_CALL_WAITING_DONE) { 1021 ssInfos = handleCwQueryResult((ImsSsInfo[])ar.result); 1022 } 1023 } 1024 sendResponse((Message) ar.userObj, ssInfos, ar.exception); 1025 break; 1026 1027 case EVENT_SET_CALL_BARRING_DONE: 1028 case EVENT_SET_CALL_WAITING_DONE: 1029 sendResponse((Message) ar.userObj, null, ar.exception); 1030 break; 1031 1032 default: 1033 super.handleMessage(msg); 1034 break; 1035 } 1036 } 1037} 1038