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