ImsPhone.java revision 6d05f561549a66b597a5119665ccc3bf8a962d16
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(int videoState) 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, int videoState) throws CallStateException { 416 return dialInternal(dialString, videoState); 417 } 418 419 protected Connection dialInternal(String dialString, int videoState) 420 throws CallStateException { 421 // Need to make sure dialString gets parsed properly 422 String newDialString = PhoneNumberUtils.stripSeparators(dialString); 423 424 // handle in-call MMI first if applicable 425 if (handleInCallMmiCommands(newDialString)) { 426 return null; 427 } 428 429 if (mDefaultPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) { 430 return mCT.dial(dialString, videoState); 431 } 432 433 // Only look at the Network portion for mmi 434 String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString); 435 ImsPhoneMmiCode mmi = 436 ImsPhoneMmiCode.newFromDialString(networkPortion, this); 437 if (DBG) Rlog.d(LOG_TAG, 438 "dialing w/ mmi '" + mmi + "'..."); 439 440 if (mmi == null) { 441 return mCT.dial(dialString, videoState); 442 } else if (mmi.isTemporaryModeCLIR()) { 443 return mCT.dial(mmi.getDialingNumber(), mmi.getCLIRMode(), videoState); 444 } else if (!mmi.isSupportedOverImsPhone()) { 445 // If the mmi is not supported by IMS service, 446 // try to initiate dialing with default phone 447 throw new CallStateException(CS_FALLBACK); 448 } else { 449 mPendingMMIs.add(mmi); 450 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 451 mmi.processCode(); 452 453 return null; 454 } 455 } 456 457 @Override 458 public void 459 sendDtmf(char c) { 460 if (!PhoneNumberUtils.is12Key(c)) { 461 Rlog.e(LOG_TAG, 462 "sendDtmf called with invalid character '" + c + "'"); 463 } else { 464 if (mCT.mState == PhoneConstants.State.OFFHOOK) { 465 mCT.sendDtmf(c); 466 } 467 } 468 } 469 470 @Override 471 public void 472 startDtmf(char c) { 473 if (!PhoneNumberUtils.is12Key(c)) { 474 Rlog.e(LOG_TAG, 475 "startDtmf called with invalid character '" + c + "'"); 476 } else { 477 sendDtmf(c); 478 } 479 } 480 481 @Override 482 public void 483 stopDtmf() { 484 // no op 485 } 486 487 @Override 488 public void setOnPostDialCharacter(Handler h, int what, Object obj) { 489 mPostDialHandler = new Registrant(h, what, obj); 490 } 491 492 /*package*/ void notifyIncomingRing() { 493 if (DBG) Rlog.d(LOG_TAG, "notifyIncomingRing"); 494 AsyncResult ar = new AsyncResult(null, null, null); 495 sendMessage(obtainMessage(EVENT_CALL_RING, ar)); 496 } 497 498 @Override 499 public void setMute(boolean muted) { 500 mCT.setMute(muted); 501 } 502 503 @Override 504 public boolean getMute() { 505 return mCT.getMute(); 506 } 507 508 @Override 509 public PhoneConstants.State getState() { 510 return mCT.mState; 511 } 512 513 private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { 514 switch (commandInterfaceCFReason) { 515 case CF_REASON_UNCONDITIONAL: 516 case CF_REASON_BUSY: 517 case CF_REASON_NO_REPLY: 518 case CF_REASON_NOT_REACHABLE: 519 case CF_REASON_ALL: 520 case CF_REASON_ALL_CONDITIONAL: 521 return true; 522 default: 523 return false; 524 } 525 } 526 527 private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { 528 switch (commandInterfaceCFAction) { 529 case CF_ACTION_DISABLE: 530 case CF_ACTION_ENABLE: 531 case CF_ACTION_REGISTRATION: 532 case CF_ACTION_ERASURE: 533 return true; 534 default: 535 return false; 536 } 537 } 538 539 private boolean isCfEnable(int action) { 540 return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); 541 } 542 543 private int getConditionFromCFReason(int reason) { 544 switch(reason) { 545 case CF_REASON_UNCONDITIONAL: return ImsUtInterface.CDIV_CF_UNCONDITIONAL; 546 case CF_REASON_BUSY: return ImsUtInterface.CDIV_CF_BUSY; 547 case CF_REASON_NO_REPLY: return ImsUtInterface.CDIV_CF_NO_REPLY; 548 case CF_REASON_NOT_REACHABLE: return ImsUtInterface.CDIV_CF_NOT_REACHABLE; 549 default: 550 break; 551 } 552 553 return ImsUtInterface.INVALID; 554 } 555 556 private int getCFReasonFromCondition(int condition) { 557 switch(condition) { 558 case ImsUtInterface.CDIV_CF_UNCONDITIONAL: return CF_REASON_UNCONDITIONAL; 559 case ImsUtInterface.CDIV_CF_BUSY: return CF_REASON_BUSY; 560 case ImsUtInterface.CDIV_CF_NO_REPLY: return CF_REASON_NO_REPLY; 561 case ImsUtInterface.CDIV_CF_NOT_REACHABLE: return CF_REASON_NOT_REACHABLE; 562 default: 563 break; 564 } 565 566 return CF_REASON_NOT_REACHABLE; 567 } 568 569 private int getActionFromCFAction(int action) { 570 switch(action) { 571 case CF_ACTION_DISABLE: return ImsUtInterface.ACTION_DEACTIVATION; 572 case CF_ACTION_ENABLE: return ImsUtInterface.ACTION_ACTIVATION; 573 case CF_ACTION_ERASURE: return ImsUtInterface.ACTION_ERASURE; 574 case CF_ACTION_REGISTRATION: return ImsUtInterface.ACTION_REGISTRATION; 575 default: 576 break; 577 } 578 579 return ImsUtInterface.INVALID; 580 } 581 582 @Override 583 public void getCallForwardingOption(int commandInterfaceCFReason, 584 Message onComplete) { 585 if (DBG) Rlog.d(LOG_TAG, "getCallForwardingOption reason=" + commandInterfaceCFReason); 586 if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { 587 if (DBG) Rlog.d(LOG_TAG, "requesting call forwarding query."); 588 Message resp; 589 resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete); 590 591 try { 592 ImsUtInterface ut = mCT.getUtInterface(); 593 ut.queryCallForward(getConditionFromCFReason(commandInterfaceCFReason),null,resp); 594 } catch (ImsException e) { 595 sendErrorResponse(onComplete, e); 596 } 597 } else if (onComplete != null) { 598 sendErrorResponse(onComplete); 599 } 600 } 601 602 @Override 603 public void setCallForwardingOption(int commandInterfaceCFAction, 604 int commandInterfaceCFReason, 605 String dialingNumber, 606 int timerSeconds, 607 Message onComplete) { 608 if (DBG) Rlog.d(LOG_TAG, "setCallForwardingOption action=" + commandInterfaceCFAction 609 + ", reason=" + commandInterfaceCFReason); 610 if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && 611 (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { 612 Message resp; 613 Cf cf = new Cf(dialingNumber, 614 (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL ? true : false), 615 onComplete); 616 resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE, 617 isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cf); 618 619 try { 620 ImsUtInterface ut = mCT.getUtInterface(); 621 ut.updateCallForward(getActionFromCFAction(commandInterfaceCFAction), 622 getConditionFromCFReason(commandInterfaceCFReason), 623 dialingNumber, 624 timerSeconds, 625 onComplete); 626 } catch (ImsException e) { 627 sendErrorResponse(onComplete, e); 628 } 629 } else if (onComplete != null) { 630 sendErrorResponse(onComplete); 631 } 632 } 633 634 @Override 635 public void getCallWaiting(Message onComplete) { 636 if (DBG) Rlog.d(LOG_TAG, "getCallWaiting"); 637 Message resp; 638 resp = obtainMessage(EVENT_GET_CALL_WAITING_DONE, onComplete); 639 640 try { 641 ImsUtInterface ut = mCT.getUtInterface(); 642 ut.queryCallWaiting(resp); 643 } catch (ImsException e) { 644 sendErrorResponse(onComplete, e); 645 } 646 } 647 648 @Override 649 public void setCallWaiting(boolean enable, Message onComplete) { 650 if (DBG) Rlog.d(LOG_TAG, "setCallWaiting enable=" + enable); 651 Message resp; 652 resp = obtainMessage(EVENT_SET_CALL_WAITING_DONE, onComplete); 653 654 try { 655 ImsUtInterface ut = mCT.getUtInterface(); 656 ut.updateCallWaiting(enable, resp); 657 } catch (ImsException e) { 658 sendErrorResponse(onComplete, e); 659 } 660 } 661 662 private int getCBTypeFromFacility(String facility) { 663 if (CB_FACILITY_BAOC.equals(facility)) { 664 return ImsUtInterface.CB_BAOC; 665 } else if (CB_FACILITY_BAOIC.equals(facility)) { 666 return ImsUtInterface.CB_BOIC; 667 } else if (CB_FACILITY_BAOICxH.equals(facility)) { 668 return ImsUtInterface.CB_BOIC_EXHC; 669 } else if (CB_FACILITY_BAIC.equals(facility)) { 670 return ImsUtInterface.CB_BAIC; 671 } else if (CB_FACILITY_BAICr.equals(facility)) { 672 return ImsUtInterface.CB_BIC_WR; 673 } else if (CB_FACILITY_BA_ALL.equals(facility)) { 674 return 0; 675 } else if (CB_FACILITY_BA_MO.equals(facility)) { 676 return 0; 677 } else if (CB_FACILITY_BA_MT.equals(facility)) { 678 return 0; 679 } 680 681 return 0; 682 } 683 684 /* package */ 685 void getCallBarring(String facility, Message onComplete) { 686 if (DBG) Rlog.d(LOG_TAG, "getCallBarring facility=" + facility); 687 Message resp; 688 resp = obtainMessage(EVENT_GET_CALL_BARRING_DONE, onComplete); 689 690 try { 691 ImsUtInterface ut = mCT.getUtInterface(); 692 ut.queryCallBarring(getCBTypeFromFacility(facility), resp); 693 } catch (ImsException e) { 694 sendErrorResponse(onComplete, e); 695 } 696 } 697 698 /* package */ 699 void setCallBarring(String facility, boolean lockState, String password, Message onComplete) { 700 if (DBG) Rlog.d(LOG_TAG, "setCallBarring facility=" + facility 701 + ", lockState=" + lockState); 702 Message resp; 703 resp = obtainMessage(EVENT_SET_CALL_BARRING_DONE, onComplete); 704 705 try { 706 ImsUtInterface ut = mCT.getUtInterface(); 707 // password is not required with Ut interface 708 ut.updateCallBarring(getCBTypeFromFacility(facility), lockState, resp); 709 } catch (ImsException e) { 710 sendErrorResponse(onComplete, e); 711 } 712 } 713 714 @Override 715 public void sendUssdResponse(String ussdMessge) { 716 Rlog.d(LOG_TAG, "sendUssdResponse"); 717 ImsPhoneMmiCode mmi = ImsPhoneMmiCode.newFromUssdUserInput(ussdMessge, this); 718 mPendingMMIs.add(mmi); 719 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 720 mmi.sendUssd(ussdMessge); 721 } 722 723 /* package */ 724 void sendUSSD (String ussdString, Message response) { 725 mCT.sendUSSD(ussdString, response); 726 } 727 728 /* package */ 729 void cancelUSSD() { 730 mCT.cancelUSSD(); 731 } 732 733 /* package */ 734 void sendErrorResponse(Message onComplete) { 735 Rlog.d(LOG_TAG, "sendErrorResponse"); 736 if (onComplete != null) { 737 AsyncResult.forMessage(onComplete, null, 738 new CommandException(CommandException.Error.GENERIC_FAILURE)); 739 onComplete.sendToTarget(); 740 } 741 } 742 743 /* package */ 744 void sendErrorResponse(Message onComplete, Throwable e) { 745 Rlog.d(LOG_TAG, "sendErrorResponse"); 746 if (onComplete != null) { 747 AsyncResult.forMessage(onComplete, null, getCommandException(e)); 748 onComplete.sendToTarget(); 749 } 750 } 751 752 /* package */ 753 void sendErrorResponse(Message onComplete, ImsReasonInfo reasonInfo) { 754 Rlog.d(LOG_TAG, "sendErrorResponse reasonCode=" + reasonInfo.getCode()); 755 if (onComplete != null) { 756 AsyncResult.forMessage(onComplete, null, getCommandException(reasonInfo.getCode())); 757 onComplete.sendToTarget(); 758 } 759 } 760 761 /* package */ 762 CommandException getCommandException(int code) { 763 Rlog.d(LOG_TAG, "getCommandException code=" + code); 764 CommandException.Error error = CommandException.Error.GENERIC_FAILURE; 765 766 switch(code) { 767 case ImsReasonInfo.CODE_UT_NOT_SUPPORTED: 768 error = CommandException.Error.REQUEST_NOT_SUPPORTED; 769 break; 770 case ImsReasonInfo.CODE_UT_CB_PASSWORD_MISMATCH: 771 error = CommandException.Error.PASSWORD_INCORRECT; 772 break; 773 default: 774 break; 775 } 776 777 return new CommandException(error); 778 } 779 780 /* package */ 781 CommandException getCommandException(Throwable e) { 782 CommandException ex = null; 783 784 if (e instanceof ImsException) { 785 ex = getCommandException(((ImsException)e).getCode()); 786 } else { 787 Rlog.d(LOG_TAG, "getCommandException generic failure"); 788 ex = new CommandException(CommandException.Error.GENERIC_FAILURE); 789 } 790 return ex; 791 } 792 793 private void 794 onNetworkInitiatedUssd(ImsPhoneMmiCode mmi) { 795 Rlog.d(LOG_TAG, "onNetworkInitiatedUssd"); 796 mMmiCompleteRegistrants.notifyRegistrants( 797 new AsyncResult(null, mmi, null)); 798 } 799 800 /* package */ 801 void onIncomingUSSD (int ussdMode, String ussdMessage) { 802 if (DBG) Rlog.d(LOG_TAG, "onIncomingUSSD ussdMode=" + ussdMode); 803 804 boolean isUssdError; 805 boolean isUssdRequest; 806 807 isUssdRequest 808 = (ussdMode == CommandsInterface.USSD_MODE_REQUEST); 809 810 isUssdError 811 = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY 812 && ussdMode != CommandsInterface.USSD_MODE_REQUEST); 813 814 ImsPhoneMmiCode found = null; 815 for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { 816 if(mPendingMMIs.get(i).isPendingUSSD()) { 817 found = mPendingMMIs.get(i); 818 break; 819 } 820 } 821 822 if (found != null) { 823 // Complete pending USSD 824 if (isUssdError) { 825 found.onUssdFinishedError(); 826 } else { 827 found.onUssdFinished(ussdMessage, isUssdRequest); 828 } 829 } else { // pending USSD not found 830 // The network may initiate its own USSD request 831 832 // ignore everything that isnt a Notify or a Request 833 // also, discard if there is no message to present 834 if (!isUssdError && ussdMessage != null) { 835 ImsPhoneMmiCode mmi; 836 mmi = ImsPhoneMmiCode.newNetworkInitiatedUssd(ussdMessage, 837 isUssdRequest, 838 ImsPhone.this); 839 onNetworkInitiatedUssd(mmi); 840 } 841 } 842 } 843 844 /** 845 * Removes the given MMI from the pending list and notifies 846 * registrants that it is complete. 847 * @param mmi MMI that is done 848 */ 849 /*package*/ void 850 onMMIDone(ImsPhoneMmiCode mmi) { 851 /* Only notify complete if it's on the pending list. 852 * Otherwise, it's already been handled (eg, previously canceled). 853 * The exception is cancellation of an incoming USSD-REQUEST, which is 854 * not on the list. 855 */ 856 if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest()) { 857 mMmiCompleteRegistrants.notifyRegistrants( 858 new AsyncResult(null, mmi, null)); 859 } 860 } 861 862 public ImsPhoneConnection getHandoverConnection() { 863 // handover for single foreground call 864 ImsPhoneConnection conn = getForegroundCall().getHandoverConnection(); 865 866 // handover for single background call 867 if (conn == null) { 868 conn = getBackgroundCall().getHandoverConnection(); 869 } 870 871 // handover for single ringing call 872 if (conn == null) { 873 conn = getRingingCall().getHandoverConnection(); 874 } 875 876 return conn; 877 } 878 879 public void notifySrvccState(Call.SrvccState state) { 880 mCT.notifySrvccState(state); 881 } 882 883 /* package */ void 884 initiateSilentRedial() { 885 String result = mLastDialString; 886 AsyncResult ar = new AsyncResult(null, result, null); 887 if (ar != null) { 888 mSilentRedialRegistrants.notifyRegistrants(ar); 889 } 890 } 891 892 public void registerForSilentRedial(Handler h, int what, Object obj) { 893 mSilentRedialRegistrants.addUnique(h, what, obj); 894 } 895 896 public void unregisterForSilentRedial(Handler h) { 897 mSilentRedialRegistrants.remove(h); 898 } 899 900 @Override 901 public long getSubId() { 902 return mDefaultPhone.getSubId(); 903 } 904 905 @Override 906 public int getPhoneId() { 907 return mDefaultPhone.getPhoneId(); 908 } 909 910 @Override 911 public Subscription getSubscriptionInfo() { 912 return mDefaultPhone.getSubscriptionInfo(); 913 } 914 915 private IccRecords getIccRecords() { 916 return mDefaultPhone.mIccRecords.get(); 917 } 918 919 private CallForwardInfo getCallForwardInfo(ImsCallForwardInfo info) { 920 CallForwardInfo cfInfo = new CallForwardInfo(); 921 cfInfo.status = info.mStatus; 922 cfInfo.reason = getCFReasonFromCondition(info.mCondition); 923 cfInfo.serviceClass = SERVICE_CLASS_VOICE; 924 cfInfo.toa = info.mToA; 925 cfInfo.number = info.mNumber; 926 cfInfo.timeSeconds = info.mTimeSeconds; 927 return cfInfo; 928 } 929 930 private CallForwardInfo[] handleCfQueryResult(ImsCallForwardInfo[] infos) { 931 CallForwardInfo[] cfInfos = null; 932 933 if (infos != null && infos.length != 0) { 934 cfInfos = new CallForwardInfo[infos.length]; 935 } 936 937 IccRecords r = getIccRecords(); 938 if (infos == null || infos.length == 0) { 939 if (r != null) { 940 // Assume the default is not active 941 // Set unconditional CFF in SIM to false 942 r.setVoiceCallForwardingFlag(1, false, null); 943 } 944 } else { 945 for (int i = 0, s = infos.length; i < s; i++) { 946 if (infos[i].mCondition == ImsUtInterface.CDIV_CF_UNCONDITIONAL) { 947 if (r != null) { 948 r.setVoiceCallForwardingFlag(1, (infos[i].mStatus == 1), 949 infos[i].mNumber); 950 } 951 } 952 cfInfos[i] = getCallForwardInfo(infos[i]); 953 } 954 } 955 956 return cfInfos; 957 } 958 959 private int[] handleCbQueryResult(ImsSsInfo[] infos) { 960 int[] cbInfos = new int[1]; 961 cbInfos[0] = SERVICE_CLASS_NONE; 962 963 if (infos[0].mStatus == 1) { 964 cbInfos[0] = SERVICE_CLASS_VOICE; 965 } 966 967 return cbInfos; 968 } 969 970 private int[] handleCwQueryResult(ImsSsInfo[] infos) { 971 int[] cwInfos = new int[2]; 972 cwInfos[0] = 0; 973 974 if (infos[0].mStatus == 1) { 975 cwInfos[0] = 1; 976 cwInfos[1] = SERVICE_CLASS_VOICE; 977 } 978 979 return cwInfos; 980 } 981 982 private void 983 sendResponse(Message onComplete, Object result, Throwable e) { 984 if (onComplete != null) { 985 CommandException ex = null; 986 if (e != null) { 987 ex = getCommandException(e); 988 } 989 AsyncResult.forMessage(onComplete, result, ex); 990 onComplete.sendToTarget(); 991 } 992 } 993 994 @Override 995 public void handleMessage (Message msg) { 996 AsyncResult ar = (AsyncResult) msg.obj; 997 Message onComplete; 998 999 if (DBG) Rlog.d(LOG_TAG, "handleMessage what=" + msg.what); 1000 switch (msg.what) { 1001 case EVENT_SET_CALL_FORWARD_DONE: 1002 IccRecords r = getIccRecords(); 1003 Cf cf = (Cf) ar.userObj; 1004 if (cf.mIsCfu && ar.exception == null && r != null) { 1005 r.setVoiceCallForwardingFlag(1, msg.arg1 == 1, cf.mSetCfNumber); 1006 } 1007 sendResponse(cf.mOnComplete, null, ar.exception); 1008 break; 1009 1010 case EVENT_GET_CALL_FORWARD_DONE: 1011 CallForwardInfo[] cfInfos = null; 1012 if (ar.exception == null) { 1013 cfInfos = handleCfQueryResult((ImsCallForwardInfo[])ar.result); 1014 } 1015 sendResponse((Message) ar.userObj, cfInfos, ar.exception); 1016 break; 1017 1018 case EVENT_GET_CALL_BARRING_DONE: 1019 case EVENT_GET_CALL_WAITING_DONE: 1020 int[] ssInfos = null; 1021 if (ar.exception == null) { 1022 if (msg.what == EVENT_GET_CALL_BARRING_DONE) { 1023 ssInfos = handleCbQueryResult((ImsSsInfo[])ar.result); 1024 } else if (msg.what == EVENT_GET_CALL_WAITING_DONE) { 1025 ssInfos = handleCwQueryResult((ImsSsInfo[])ar.result); 1026 } 1027 } 1028 sendResponse((Message) ar.userObj, ssInfos, ar.exception); 1029 break; 1030 1031 case EVENT_SET_CALL_BARRING_DONE: 1032 case EVENT_SET_CALL_WAITING_DONE: 1033 sendResponse((Message) ar.userObj, null, ar.exception); 1034 break; 1035 1036 default: 1037 super.handleMessage(msg); 1038 break; 1039 } 1040 } 1041} 1042