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