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 17 package com.android.internal.telephony.imsphone; 18 19 import android.app.ActivityManagerNative; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.AsyncResult; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.os.PowerManager; 26 import android.os.Registrant; 27 import android.os.RegistrantList; 28 import android.os.PowerManager.WakeLock; 29 import android.os.SystemProperties; 30 import android.os.UserHandle; 31 32 import android.telephony.PhoneNumberUtils; 33 import android.telephony.ServiceState; 34 import android.telephony.Rlog; 35 import android.telephony.SubscriptionManager; 36 import android.text.TextUtils; 37 38 import com.android.ims.ImsCallForwardInfo; 39 import com.android.ims.ImsCallProfile; 40 import com.android.ims.ImsEcbm; 41 import com.android.ims.ImsEcbmStateListener; 42 import com.android.ims.ImsException; 43 import com.android.ims.ImsReasonInfo; 44 import com.android.ims.ImsSsInfo; 45 import com.android.ims.ImsUtInterface; 46 47 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOC; 48 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOIC; 49 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOICxH; 50 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC; 51 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr; 52 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_ALL; 53 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MO; 54 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MT; 55 56 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE; 57 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; 58 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE; 59 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION; 60 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; 61 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; 62 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; 63 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; 64 import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; 65 import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; 66 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; 67 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NONE; 68 69 import com.android.internal.telephony.Call; 70 import com.android.internal.telephony.CallForwardInfo; 71 import com.android.internal.telephony.CallStateException; 72 import com.android.internal.telephony.CallTracker; 73 import com.android.internal.telephony.CommandException; 74 import com.android.internal.telephony.CommandsInterface; 75 import com.android.internal.telephony.Connection; 76 import com.android.internal.telephony.Phone; 77 import com.android.internal.telephony.PhoneBase; 78 import com.android.internal.telephony.PhoneConstants; 79 import com.android.internal.telephony.PhoneNotifier; 80 import com.android.internal.telephony.TelephonyIntents; 81 import com.android.internal.telephony.TelephonyProperties; 82 import com.android.internal.telephony.cdma.CDMAPhone; 83 import com.android.internal.telephony.gsm.GSMPhone; 84 import com.android.internal.telephony.uicc.IccRecords; 85 86 import java.util.ArrayList; 87 import java.util.List; 88 89 /** 90 * {@hide} 91 */ 92 public class ImsPhone extends ImsPhoneBase { 93 private static final String LOG_TAG = "ImsPhone"; 94 private static final boolean DBG = true; 95 private static final boolean VDBG = false; // STOPSHIP if true 96 97 protected static final int EVENT_SET_CALL_BARRING_DONE = EVENT_LAST + 1; 98 protected static final int EVENT_GET_CALL_BARRING_DONE = EVENT_LAST + 2; 99 protected static final int EVENT_SET_CALL_WAITING_DONE = EVENT_LAST + 3; 100 protected static final int EVENT_GET_CALL_WAITING_DONE = EVENT_LAST + 4; 101 102 public static final String CS_FALLBACK = "cs_fallback"; 103 104 static final int RESTART_ECM_TIMER = 0; // restart Ecm timer 105 static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer 106 107 // Default Emergency Callback Mode exit timer 108 private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000; 109 110 // Instance Variables 111 PhoneBase mDefaultPhone; 112 ImsPhoneCallTracker mCT; 113 ArrayList <ImsPhoneMmiCode> mPendingMMIs = new ArrayList<ImsPhoneMmiCode>(); 114 115 Registrant mPostDialHandler; 116 ServiceState mSS = new ServiceState(); 117 118 // To redial silently through GSM or CDMA when dialing through IMS fails 119 private String mLastDialString; 120 121 WakeLock mWakeLock; 122 protected boolean mIsPhoneInEcmState; 123 124 // mEcmExitRespRegistrant is informed after the phone has been exited the emergency 125 // callback mode keep track of if phone is in emergency callback mode 126 private Registrant mEcmExitRespRegistrant; 127 128 private final RegistrantList mSilentRedialRegistrants = new RegistrantList(); 129 130 private boolean mImsRegistered = false; 131 // A runnable which is used to automatically exit from Ecm after a period of time. 132 private Runnable mExitEcmRunnable = new Runnable() { 133 @Override 134 public void run() { 135 exitEmergencyCallbackMode(); 136 } 137 }; 138 139 // Create Cf (Call forward) so that dialling number & 140 // mIsCfu (true if reason is call forward unconditional) 141 // mOnComplete (Message object passed by client) can be packed & 142 // given as a single Cf object as user data to UtInterface. 143 private static class Cf { 144 final String mSetCfNumber; 145 final Message mOnComplete; 146 final boolean mIsCfu; 147 Cf(String cfNumber, boolean isCfu, Message onComplete)148 Cf(String cfNumber, boolean isCfu, Message onComplete) { 149 mSetCfNumber = cfNumber; 150 mIsCfu = isCfu; 151 mOnComplete = onComplete; 152 } 153 } 154 155 // Constructors 156 ImsPhone(Context context, PhoneNotifier notifier, Phone defaultPhone)157 ImsPhone(Context context, PhoneNotifier notifier, Phone defaultPhone) { 158 super("ImsPhone", context, notifier); 159 160 mDefaultPhone = (PhoneBase) defaultPhone; 161 mCT = new ImsPhoneCallTracker(this); 162 mSS.setStateOff(); 163 164 mPhoneId = mDefaultPhone.getPhoneId(); 165 166 // This is needed to handle phone process crashes 167 // Same property is used for both CDMA & IMS phone. 168 mIsPhoneInEcmState = SystemProperties.getBoolean( 169 TelephonyProperties.PROPERTY_INECM_MODE, false); 170 171 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 172 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); 173 mWakeLock.setReferenceCounted(false); 174 } 175 updateParentPhone(PhoneBase parentPhone)176 public void updateParentPhone(PhoneBase parentPhone) { 177 // synchronization is managed at the PhoneBase scope (which calls this function) 178 mDefaultPhone = parentPhone; 179 mPhoneId = mDefaultPhone.getPhoneId(); 180 } 181 182 @Override dispose()183 public void dispose() { 184 Rlog.d(LOG_TAG, "dispose"); 185 // Nothing to dispose in PhoneBase 186 //super.dispose(); 187 mPendingMMIs.clear(); 188 mCT.dispose(); 189 190 //Force all referenced classes to unregister their former registered events 191 } 192 193 @Override removeReferences()194 public void removeReferences() { 195 Rlog.d(LOG_TAG, "removeReferences"); 196 super.removeReferences(); 197 198 mCT = null; 199 mSS = null; 200 } 201 202 @Override 203 public ServiceState getServiceState()204 getServiceState() { 205 return mSS; 206 } 207 setServiceState(int state)208 /* package */ void setServiceState(int state) { 209 mSS.setState(state); 210 } 211 212 @Override getCallTracker()213 public CallTracker getCallTracker() { 214 return mCT; 215 } 216 217 @Override 218 public List<? extends ImsPhoneMmiCode> getPendingMmiCodes()219 getPendingMmiCodes() { 220 return mPendingMMIs; 221 } 222 223 224 @Override 225 public void acceptCall(int videoState)226 acceptCall(int videoState) throws CallStateException { 227 mCT.acceptCall(videoState); 228 } 229 230 @Override 231 public void rejectCall()232 rejectCall() throws CallStateException { 233 mCT.rejectCall(); 234 } 235 236 @Override 237 public void switchHoldingAndActive()238 switchHoldingAndActive() throws CallStateException { 239 mCT.switchWaitingOrHoldingAndActive(); 240 } 241 242 @Override canConference()243 public boolean canConference() { 244 return mCT.canConference(); 245 } 246 canDial()247 public boolean canDial() { 248 return mCT.canDial(); 249 } 250 251 @Override conference()252 public void conference() { 253 mCT.conference(); 254 } 255 256 @Override clearDisconnected()257 public void clearDisconnected() { 258 mCT.clearDisconnected(); 259 } 260 261 @Override canTransfer()262 public boolean canTransfer() { 263 return mCT.canTransfer(); 264 } 265 266 @Override explicitCallTransfer()267 public void explicitCallTransfer() { 268 mCT.explicitCallTransfer(); 269 } 270 271 @Override 272 public ImsPhoneCall getForegroundCall()273 getForegroundCall() { 274 return mCT.mForegroundCall; 275 } 276 277 @Override 278 public ImsPhoneCall getBackgroundCall()279 getBackgroundCall() { 280 return mCT.mBackgroundCall; 281 } 282 283 @Override 284 public ImsPhoneCall getRingingCall()285 getRingingCall() { 286 return mCT.mRingingCall; 287 } 288 handleCallDeflectionIncallSupplementaryService( String dialString)289 private boolean handleCallDeflectionIncallSupplementaryService( 290 String dialString) { 291 if (dialString.length() > 1) { 292 return false; 293 } 294 295 if (getRingingCall().getState() != ImsPhoneCall.State.IDLE) { 296 if (DBG) Rlog.d(LOG_TAG, "MmiCode 0: rejectCall"); 297 try { 298 mCT.rejectCall(); 299 } catch (CallStateException e) { 300 if (DBG) Rlog.d(LOG_TAG, "reject failed", e); 301 notifySuppServiceFailed(Phone.SuppService.REJECT); 302 } 303 } else if (getBackgroundCall().getState() != ImsPhoneCall.State.IDLE) { 304 if (DBG) Rlog.d(LOG_TAG, "MmiCode 0: hangupWaitingOrBackground"); 305 try { 306 mCT.hangup(getBackgroundCall()); 307 } catch (CallStateException e) { 308 if (DBG) Rlog.d(LOG_TAG, "hangup failed", e); 309 } 310 } 311 312 return true; 313 } 314 315 handleCallWaitingIncallSupplementaryService( String dialString)316 private boolean handleCallWaitingIncallSupplementaryService( 317 String dialString) { 318 int len = dialString.length(); 319 320 if (len > 2) { 321 return false; 322 } 323 324 ImsPhoneCall call = getForegroundCall(); 325 326 try { 327 if (len > 1) { 328 if (DBG) Rlog.d(LOG_TAG, "not support 1X SEND"); 329 notifySuppServiceFailed(Phone.SuppService.HANGUP); 330 } else { 331 if (call.getState() != ImsPhoneCall.State.IDLE) { 332 if (DBG) Rlog.d(LOG_TAG, "MmiCode 1: hangup foreground"); 333 mCT.hangup(call); 334 } else { 335 if (DBG) Rlog.d(LOG_TAG, "MmiCode 1: switchWaitingOrHoldingAndActive"); 336 mCT.switchWaitingOrHoldingAndActive(); 337 } 338 } 339 } catch (CallStateException e) { 340 if (DBG) Rlog.d(LOG_TAG, "hangup failed", e); 341 notifySuppServiceFailed(Phone.SuppService.HANGUP); 342 } 343 344 return true; 345 } 346 handleCallHoldIncallSupplementaryService(String dialString)347 private boolean handleCallHoldIncallSupplementaryService(String dialString) { 348 int len = dialString.length(); 349 350 if (len > 2) { 351 return false; 352 } 353 354 ImsPhoneCall call = getForegroundCall(); 355 356 if (len > 1) { 357 if (DBG) Rlog.d(LOG_TAG, "separate not supported"); 358 notifySuppServiceFailed(Phone.SuppService.SEPARATE); 359 } else { 360 try { 361 if (getRingingCall().getState() != ImsPhoneCall.State.IDLE) { 362 if (DBG) Rlog.d(LOG_TAG, "MmiCode 2: accept ringing call"); 363 mCT.acceptCall(ImsCallProfile.CALL_TYPE_VOICE); 364 } else { 365 if (DBG) Rlog.d(LOG_TAG, "MmiCode 2: switchWaitingOrHoldingAndActive"); 366 mCT.switchWaitingOrHoldingAndActive(); 367 } 368 } catch (CallStateException e) { 369 if (DBG) Rlog.d(LOG_TAG, "switch failed", e); 370 notifySuppServiceFailed(Phone.SuppService.SWITCH); 371 } 372 } 373 374 return true; 375 } 376 handleMultipartyIncallSupplementaryService( String dialString)377 private boolean handleMultipartyIncallSupplementaryService( 378 String dialString) { 379 if (dialString.length() > 1) { 380 return false; 381 } 382 383 if (DBG) Rlog.d(LOG_TAG, "MmiCode 3: merge calls"); 384 conference(); 385 return true; 386 } 387 handleEctIncallSupplementaryService(String dialString)388 private boolean handleEctIncallSupplementaryService(String dialString) { 389 390 int len = dialString.length(); 391 392 if (len != 1) { 393 return false; 394 } 395 396 if (DBG) Rlog.d(LOG_TAG, "MmiCode 4: not support explicit call transfer"); 397 notifySuppServiceFailed(Phone.SuppService.TRANSFER); 398 return true; 399 } 400 handleCcbsIncallSupplementaryService(String dialString)401 private boolean handleCcbsIncallSupplementaryService(String dialString) { 402 if (dialString.length() > 1) { 403 return false; 404 } 405 406 Rlog.i(LOG_TAG, "MmiCode 5: CCBS not supported!"); 407 // Treat it as an "unknown" service. 408 notifySuppServiceFailed(Phone.SuppService.UNKNOWN); 409 return true; 410 } 411 412 @Override handleInCallMmiCommands(String dialString)413 public boolean handleInCallMmiCommands(String dialString) { 414 if (!isInCall()) { 415 return false; 416 } 417 418 if (TextUtils.isEmpty(dialString)) { 419 return false; 420 } 421 422 boolean result = false; 423 char ch = dialString.charAt(0); 424 switch (ch) { 425 case '0': 426 result = handleCallDeflectionIncallSupplementaryService( 427 dialString); 428 break; 429 case '1': 430 result = handleCallWaitingIncallSupplementaryService( 431 dialString); 432 break; 433 case '2': 434 result = handleCallHoldIncallSupplementaryService(dialString); 435 break; 436 case '3': 437 result = handleMultipartyIncallSupplementaryService(dialString); 438 break; 439 case '4': 440 result = handleEctIncallSupplementaryService(dialString); 441 break; 442 case '5': 443 result = handleCcbsIncallSupplementaryService(dialString); 444 break; 445 default: 446 break; 447 } 448 449 return result; 450 } 451 isInCall()452 boolean isInCall() { 453 ImsPhoneCall.State foregroundCallState = getForegroundCall().getState(); 454 ImsPhoneCall.State backgroundCallState = getBackgroundCall().getState(); 455 ImsPhoneCall.State ringingCallState = getRingingCall().getState(); 456 457 return (foregroundCallState.isAlive() || 458 backgroundCallState.isAlive() || 459 ringingCallState.isAlive()); 460 } 461 notifyNewRingingConnection(Connection c)462 void notifyNewRingingConnection(Connection c) { 463 mDefaultPhone.notifyNewRingingConnectionP(c); 464 } 465 466 467 @Override 468 public Connection dial(String dialString, int videoState)469 dial(String dialString, int videoState) throws CallStateException { 470 return dialInternal(dialString, videoState); 471 } 472 dialInternal(String dialString, int videoState)473 protected Connection dialInternal(String dialString, int videoState) 474 throws CallStateException { 475 // Need to make sure dialString gets parsed properly 476 String newDialString = PhoneNumberUtils.stripSeparators(dialString); 477 478 // handle in-call MMI first if applicable 479 if (handleInCallMmiCommands(newDialString)) { 480 return null; 481 } 482 483 if (mDefaultPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) { 484 return mCT.dial(dialString, videoState); 485 } 486 487 // Only look at the Network portion for mmi 488 String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString); 489 ImsPhoneMmiCode mmi = 490 ImsPhoneMmiCode.newFromDialString(networkPortion, this); 491 if (DBG) Rlog.d(LOG_TAG, 492 "dialing w/ mmi '" + mmi + "'..."); 493 494 if (mmi == null) { 495 return mCT.dial(dialString, videoState); 496 } else if (mmi.isTemporaryModeCLIR()) { 497 return mCT.dial(mmi.getDialingNumber(), mmi.getCLIRMode(), videoState); 498 } else if (!mmi.isSupportedOverImsPhone()) { 499 // If the mmi is not supported by IMS service, 500 // try to initiate dialing with default phone 501 throw new CallStateException(CS_FALLBACK); 502 } else { 503 mPendingMMIs.add(mmi); 504 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 505 mmi.processCode(); 506 507 return null; 508 } 509 } 510 511 @Override 512 public void sendDtmf(char c)513 sendDtmf(char c) { 514 if (!PhoneNumberUtils.is12Key(c)) { 515 Rlog.e(LOG_TAG, 516 "sendDtmf called with invalid character '" + c + "'"); 517 } else { 518 if (mCT.mState == PhoneConstants.State.OFFHOOK) { 519 mCT.sendDtmf(c, null); 520 } 521 } 522 } 523 524 @Override 525 public void startDtmf(char c)526 startDtmf(char c) { 527 if (!(PhoneNumberUtils.is12Key(c) || (c >= 'A' && c <= 'D'))) { 528 Rlog.e(LOG_TAG, 529 "startDtmf called with invalid character '" + c + "'"); 530 } else { 531 mCT.startDtmf(c); 532 } 533 } 534 535 @Override 536 public void stopDtmf()537 stopDtmf() { 538 mCT.stopDtmf(); 539 } 540 541 @Override setOnPostDialCharacter(Handler h, int what, Object obj)542 public void setOnPostDialCharacter(Handler h, int what, Object obj) { 543 mPostDialHandler = new Registrant(h, what, obj); 544 } 545 notifyIncomingRing()546 /*package*/ void notifyIncomingRing() { 547 if (DBG) Rlog.d(LOG_TAG, "notifyIncomingRing"); 548 AsyncResult ar = new AsyncResult(null, null, null); 549 sendMessage(obtainMessage(EVENT_CALL_RING, ar)); 550 } 551 552 @Override setMute(boolean muted)553 public void setMute(boolean muted) { 554 mCT.setMute(muted); 555 } 556 557 @Override setUiTTYMode(int uiTtyMode, Message onComplete)558 public void setUiTTYMode(int uiTtyMode, Message onComplete) { 559 mCT.setUiTTYMode(uiTtyMode, onComplete); 560 } 561 562 @Override getMute()563 public boolean getMute() { 564 return mCT.getMute(); 565 } 566 567 @Override getState()568 public PhoneConstants.State getState() { 569 return mCT.mState; 570 } 571 isValidCommandInterfaceCFReason(int commandInterfaceCFReason)572 private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { 573 switch (commandInterfaceCFReason) { 574 case CF_REASON_UNCONDITIONAL: 575 case CF_REASON_BUSY: 576 case CF_REASON_NO_REPLY: 577 case CF_REASON_NOT_REACHABLE: 578 case CF_REASON_ALL: 579 case CF_REASON_ALL_CONDITIONAL: 580 return true; 581 default: 582 return false; 583 } 584 } 585 isValidCommandInterfaceCFAction(int commandInterfaceCFAction)586 private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { 587 switch (commandInterfaceCFAction) { 588 case CF_ACTION_DISABLE: 589 case CF_ACTION_ENABLE: 590 case CF_ACTION_REGISTRATION: 591 case CF_ACTION_ERASURE: 592 return true; 593 default: 594 return false; 595 } 596 } 597 isCfEnable(int action)598 private boolean isCfEnable(int action) { 599 return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); 600 } 601 getConditionFromCFReason(int reason)602 private int getConditionFromCFReason(int reason) { 603 switch(reason) { 604 case CF_REASON_UNCONDITIONAL: return ImsUtInterface.CDIV_CF_UNCONDITIONAL; 605 case CF_REASON_BUSY: return ImsUtInterface.CDIV_CF_BUSY; 606 case CF_REASON_NO_REPLY: return ImsUtInterface.CDIV_CF_NO_REPLY; 607 case CF_REASON_NOT_REACHABLE: return ImsUtInterface.CDIV_CF_NOT_REACHABLE; 608 case CF_REASON_ALL: return ImsUtInterface.CDIV_CF_ALL; 609 case CF_REASON_ALL_CONDITIONAL: return ImsUtInterface.CDIV_CF_ALL_CONDITIONAL; 610 default: 611 break; 612 } 613 614 return ImsUtInterface.INVALID; 615 } 616 getCFReasonFromCondition(int condition)617 private int getCFReasonFromCondition(int condition) { 618 switch(condition) { 619 case ImsUtInterface.CDIV_CF_UNCONDITIONAL: return CF_REASON_UNCONDITIONAL; 620 case ImsUtInterface.CDIV_CF_BUSY: return CF_REASON_BUSY; 621 case ImsUtInterface.CDIV_CF_NO_REPLY: return CF_REASON_NO_REPLY; 622 case ImsUtInterface.CDIV_CF_NOT_REACHABLE: return CF_REASON_NOT_REACHABLE; 623 case ImsUtInterface.CDIV_CF_ALL: return CF_REASON_ALL; 624 case ImsUtInterface.CDIV_CF_ALL_CONDITIONAL: return CF_REASON_ALL_CONDITIONAL; 625 default: 626 break; 627 } 628 629 return CF_REASON_NOT_REACHABLE; 630 } 631 getActionFromCFAction(int action)632 private int getActionFromCFAction(int action) { 633 switch(action) { 634 case CF_ACTION_DISABLE: return ImsUtInterface.ACTION_DEACTIVATION; 635 case CF_ACTION_ENABLE: return ImsUtInterface.ACTION_ACTIVATION; 636 case CF_ACTION_ERASURE: return ImsUtInterface.ACTION_ERASURE; 637 case CF_ACTION_REGISTRATION: return ImsUtInterface.ACTION_REGISTRATION; 638 default: 639 break; 640 } 641 642 return ImsUtInterface.INVALID; 643 } 644 645 @Override getCallForwardingOption(int commandInterfaceCFReason, Message onComplete)646 public void getCallForwardingOption(int commandInterfaceCFReason, 647 Message onComplete) { 648 if (DBG) Rlog.d(LOG_TAG, "getCallForwardingOption reason=" + commandInterfaceCFReason); 649 if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { 650 if (DBG) Rlog.d(LOG_TAG, "requesting call forwarding query."); 651 Message resp; 652 resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete); 653 654 try { 655 ImsUtInterface ut = mCT.getUtInterface(); 656 ut.queryCallForward(getConditionFromCFReason(commandInterfaceCFReason),null,resp); 657 } catch (ImsException e) { 658 sendErrorResponse(onComplete, e); 659 } 660 } else if (onComplete != null) { 661 sendErrorResponse(onComplete); 662 } 663 } 664 665 @Override setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int timerSeconds, Message onComplete)666 public void setCallForwardingOption(int commandInterfaceCFAction, 667 int commandInterfaceCFReason, 668 String dialingNumber, 669 int timerSeconds, 670 Message onComplete) { 671 if (DBG) Rlog.d(LOG_TAG, "setCallForwardingOption action=" + commandInterfaceCFAction 672 + ", reason=" + commandInterfaceCFReason); 673 if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && 674 (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { 675 Message resp; 676 Cf cf = new Cf(dialingNumber, 677 (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL ? true : false), 678 onComplete); 679 resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE, 680 isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, cf); 681 682 try { 683 ImsUtInterface ut = mCT.getUtInterface(); 684 ut.updateCallForward(getActionFromCFAction(commandInterfaceCFAction), 685 getConditionFromCFReason(commandInterfaceCFReason), 686 dialingNumber, 687 timerSeconds, 688 onComplete); 689 } catch (ImsException e) { 690 sendErrorResponse(onComplete, e); 691 } 692 } else if (onComplete != null) { 693 sendErrorResponse(onComplete); 694 } 695 } 696 697 @Override getCallWaiting(Message onComplete)698 public void getCallWaiting(Message onComplete) { 699 if (DBG) Rlog.d(LOG_TAG, "getCallWaiting"); 700 Message resp; 701 resp = obtainMessage(EVENT_GET_CALL_WAITING_DONE, onComplete); 702 703 try { 704 ImsUtInterface ut = mCT.getUtInterface(); 705 ut.queryCallWaiting(resp); 706 } catch (ImsException e) { 707 sendErrorResponse(onComplete, e); 708 } 709 } 710 711 @Override setCallWaiting(boolean enable, Message onComplete)712 public void setCallWaiting(boolean enable, Message onComplete) { 713 if (DBG) Rlog.d(LOG_TAG, "setCallWaiting enable=" + enable); 714 Message resp; 715 resp = obtainMessage(EVENT_SET_CALL_WAITING_DONE, onComplete); 716 717 try { 718 ImsUtInterface ut = mCT.getUtInterface(); 719 ut.updateCallWaiting(enable, resp); 720 } catch (ImsException e) { 721 sendErrorResponse(onComplete, e); 722 } 723 } 724 getCBTypeFromFacility(String facility)725 private int getCBTypeFromFacility(String facility) { 726 if (CB_FACILITY_BAOC.equals(facility)) { 727 return ImsUtInterface.CB_BAOC; 728 } else if (CB_FACILITY_BAOIC.equals(facility)) { 729 return ImsUtInterface.CB_BOIC; 730 } else if (CB_FACILITY_BAOICxH.equals(facility)) { 731 return ImsUtInterface.CB_BOIC_EXHC; 732 } else if (CB_FACILITY_BAIC.equals(facility)) { 733 return ImsUtInterface.CB_BAIC; 734 } else if (CB_FACILITY_BAICr.equals(facility)) { 735 return ImsUtInterface.CB_BIC_WR; 736 } else if (CB_FACILITY_BA_ALL.equals(facility)) { 737 return ImsUtInterface.CB_BA_ALL; 738 } else if (CB_FACILITY_BA_MO.equals(facility)) { 739 return ImsUtInterface.CB_BA_MO; 740 } else if (CB_FACILITY_BA_MT.equals(facility)) { 741 return ImsUtInterface.CB_BA_MT; 742 } 743 744 return 0; 745 } 746 747 /* package */ getCallBarring(String facility, Message onComplete)748 void getCallBarring(String facility, Message onComplete) { 749 if (DBG) Rlog.d(LOG_TAG, "getCallBarring facility=" + facility); 750 Message resp; 751 resp = obtainMessage(EVENT_GET_CALL_BARRING_DONE, onComplete); 752 753 try { 754 ImsUtInterface ut = mCT.getUtInterface(); 755 ut.queryCallBarring(getCBTypeFromFacility(facility), resp); 756 } catch (ImsException e) { 757 sendErrorResponse(onComplete, e); 758 } 759 } 760 761 /* package */ setCallBarring(String facility, boolean lockState, String password, Message onComplete)762 void setCallBarring(String facility, boolean lockState, String password, Message onComplete) { 763 if (DBG) Rlog.d(LOG_TAG, "setCallBarring facility=" + facility 764 + ", lockState=" + lockState); 765 Message resp; 766 resp = obtainMessage(EVENT_SET_CALL_BARRING_DONE, onComplete); 767 768 try { 769 ImsUtInterface ut = mCT.getUtInterface(); 770 // password is not required with Ut interface 771 ut.updateCallBarring(getCBTypeFromFacility(facility), lockState, resp, null); 772 } catch (ImsException e) { 773 sendErrorResponse(onComplete, e); 774 } 775 } 776 777 @Override sendUssdResponse(String ussdMessge)778 public void sendUssdResponse(String ussdMessge) { 779 Rlog.d(LOG_TAG, "sendUssdResponse"); 780 ImsPhoneMmiCode mmi = ImsPhoneMmiCode.newFromUssdUserInput(ussdMessge, this); 781 mPendingMMIs.add(mmi); 782 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 783 mmi.sendUssd(ussdMessge); 784 } 785 786 /* package */ sendUSSD(String ussdString, Message response)787 void sendUSSD (String ussdString, Message response) { 788 mCT.sendUSSD(ussdString, response); 789 } 790 791 /* package */ cancelUSSD()792 void cancelUSSD() { 793 mCT.cancelUSSD(); 794 } 795 796 /* package */ sendErrorResponse(Message onComplete)797 void sendErrorResponse(Message onComplete) { 798 Rlog.d(LOG_TAG, "sendErrorResponse"); 799 if (onComplete != null) { 800 AsyncResult.forMessage(onComplete, null, 801 new CommandException(CommandException.Error.GENERIC_FAILURE)); 802 onComplete.sendToTarget(); 803 } 804 } 805 806 /* package */ sendErrorResponse(Message onComplete, Throwable e)807 void sendErrorResponse(Message onComplete, Throwable e) { 808 Rlog.d(LOG_TAG, "sendErrorResponse"); 809 if (onComplete != null) { 810 AsyncResult.forMessage(onComplete, null, getCommandException(e)); 811 onComplete.sendToTarget(); 812 } 813 } 814 815 /* package */ sendErrorResponse(Message onComplete, ImsReasonInfo reasonInfo)816 void sendErrorResponse(Message onComplete, ImsReasonInfo reasonInfo) { 817 Rlog.d(LOG_TAG, "sendErrorResponse reasonCode=" + reasonInfo.getCode()); 818 if (onComplete != null) { 819 AsyncResult.forMessage(onComplete, null, getCommandException(reasonInfo.getCode())); 820 onComplete.sendToTarget(); 821 } 822 } 823 824 /* package */ getCommandException(int code)825 CommandException getCommandException(int code) { 826 Rlog.d(LOG_TAG, "getCommandException code=" + code); 827 CommandException.Error error = CommandException.Error.GENERIC_FAILURE; 828 829 switch(code) { 830 case ImsReasonInfo.CODE_UT_NOT_SUPPORTED: 831 error = CommandException.Error.REQUEST_NOT_SUPPORTED; 832 break; 833 case ImsReasonInfo.CODE_UT_CB_PASSWORD_MISMATCH: 834 error = CommandException.Error.PASSWORD_INCORRECT; 835 break; 836 default: 837 break; 838 } 839 840 return new CommandException(error); 841 } 842 843 /* package */ getCommandException(Throwable e)844 CommandException getCommandException(Throwable e) { 845 CommandException ex = null; 846 847 if (e instanceof ImsException) { 848 ex = getCommandException(((ImsException)e).getCode()); 849 } else { 850 Rlog.d(LOG_TAG, "getCommandException generic failure"); 851 ex = new CommandException(CommandException.Error.GENERIC_FAILURE); 852 } 853 return ex; 854 } 855 856 private void onNetworkInitiatedUssd(ImsPhoneMmiCode mmi)857 onNetworkInitiatedUssd(ImsPhoneMmiCode mmi) { 858 Rlog.d(LOG_TAG, "onNetworkInitiatedUssd"); 859 mMmiCompleteRegistrants.notifyRegistrants( 860 new AsyncResult(null, mmi, null)); 861 } 862 863 /* package */ onIncomingUSSD(int ussdMode, String ussdMessage)864 void onIncomingUSSD (int ussdMode, String ussdMessage) { 865 if (DBG) Rlog.d(LOG_TAG, "onIncomingUSSD ussdMode=" + ussdMode); 866 867 boolean isUssdError; 868 boolean isUssdRequest; 869 870 isUssdRequest 871 = (ussdMode == CommandsInterface.USSD_MODE_REQUEST); 872 873 isUssdError 874 = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY 875 && ussdMode != CommandsInterface.USSD_MODE_REQUEST); 876 877 ImsPhoneMmiCode found = null; 878 for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { 879 if(mPendingMMIs.get(i).isPendingUSSD()) { 880 found = mPendingMMIs.get(i); 881 break; 882 } 883 } 884 885 if (found != null) { 886 // Complete pending USSD 887 if (isUssdError) { 888 found.onUssdFinishedError(); 889 } else { 890 found.onUssdFinished(ussdMessage, isUssdRequest); 891 } 892 } else { // pending USSD not found 893 // The network may initiate its own USSD request 894 895 // ignore everything that isnt a Notify or a Request 896 // also, discard if there is no message to present 897 if (!isUssdError && ussdMessage != null) { 898 ImsPhoneMmiCode mmi; 899 mmi = ImsPhoneMmiCode.newNetworkInitiatedUssd(ussdMessage, 900 isUssdRequest, 901 ImsPhone.this); 902 onNetworkInitiatedUssd(mmi); 903 } 904 } 905 } 906 907 /** 908 * Removes the given MMI from the pending list and notifies 909 * registrants that it is complete. 910 * @param mmi MMI that is done 911 */ 912 /*package*/ void onMMIDone(ImsPhoneMmiCode mmi)913 onMMIDone(ImsPhoneMmiCode mmi) { 914 /* Only notify complete if it's on the pending list. 915 * Otherwise, it's already been handled (eg, previously canceled). 916 * The exception is cancellation of an incoming USSD-REQUEST, which is 917 * not on the list. 918 */ 919 if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest()) { 920 mMmiCompleteRegistrants.notifyRegistrants( 921 new AsyncResult(null, mmi, null)); 922 } 923 } 924 getHandoverConnection()925 public ArrayList<Connection> getHandoverConnection() { 926 ArrayList<Connection> connList = new ArrayList<Connection>(); 927 // Add all foreground call connections 928 connList.addAll(getForegroundCall().mConnections); 929 // Add all background call connections 930 connList.addAll(getBackgroundCall().mConnections); 931 // Add all background call connections 932 connList.addAll(getRingingCall().mConnections); 933 if (connList.size() > 0) { 934 return connList; 935 } else { 936 return null; 937 } 938 } 939 notifySrvccState(Call.SrvccState state)940 public void notifySrvccState(Call.SrvccState state) { 941 mCT.notifySrvccState(state); 942 } 943 944 /* package */ void initiateSilentRedial()945 initiateSilentRedial() { 946 String result = mLastDialString; 947 AsyncResult ar = new AsyncResult(null, result, null); 948 if (ar != null) { 949 mSilentRedialRegistrants.notifyRegistrants(ar); 950 } 951 } 952 registerForSilentRedial(Handler h, int what, Object obj)953 public void registerForSilentRedial(Handler h, int what, Object obj) { 954 mSilentRedialRegistrants.addUnique(h, what, obj); 955 } 956 unregisterForSilentRedial(Handler h)957 public void unregisterForSilentRedial(Handler h) { 958 mSilentRedialRegistrants.remove(h); 959 } 960 961 @Override getSubId()962 public int getSubId() { 963 return mDefaultPhone.getSubId(); 964 } 965 966 @Override getPhoneId()967 public int getPhoneId() { 968 return mDefaultPhone.getPhoneId(); 969 } 970 getIccRecords()971 private IccRecords getIccRecords() { 972 return mDefaultPhone.mIccRecords.get(); 973 } 974 getCallForwardInfo(ImsCallForwardInfo info)975 private CallForwardInfo getCallForwardInfo(ImsCallForwardInfo info) { 976 CallForwardInfo cfInfo = new CallForwardInfo(); 977 cfInfo.status = info.mStatus; 978 cfInfo.reason = getCFReasonFromCondition(info.mCondition); 979 cfInfo.serviceClass = SERVICE_CLASS_VOICE; 980 cfInfo.toa = info.mToA; 981 cfInfo.number = info.mNumber; 982 cfInfo.timeSeconds = info.mTimeSeconds; 983 return cfInfo; 984 } 985 handleCfQueryResult(ImsCallForwardInfo[] infos)986 private CallForwardInfo[] handleCfQueryResult(ImsCallForwardInfo[] infos) { 987 CallForwardInfo[] cfInfos = null; 988 989 if (infos != null && infos.length != 0) { 990 cfInfos = new CallForwardInfo[infos.length]; 991 } 992 993 IccRecords r = getIccRecords(); 994 if (infos == null || infos.length == 0) { 995 if (r != null) { 996 // Assume the default is not active 997 // Set unconditional CFF in SIM to false 998 r.setVoiceCallForwardingFlag(1, false, null); 999 } 1000 } else { 1001 for (int i = 0, s = infos.length; i < s; i++) { 1002 if (infos[i].mCondition == ImsUtInterface.CDIV_CF_UNCONDITIONAL) { 1003 if (r != null) { 1004 r.setVoiceCallForwardingFlag(1, (infos[i].mStatus == 1), 1005 infos[i].mNumber); 1006 } 1007 } 1008 cfInfos[i] = getCallForwardInfo(infos[i]); 1009 } 1010 } 1011 1012 return cfInfos; 1013 } 1014 handleCbQueryResult(ImsSsInfo[] infos)1015 private int[] handleCbQueryResult(ImsSsInfo[] infos) { 1016 int[] cbInfos = new int[1]; 1017 cbInfos[0] = SERVICE_CLASS_NONE; 1018 1019 if (infos[0].mStatus == 1) { 1020 cbInfos[0] = SERVICE_CLASS_VOICE; 1021 } 1022 1023 return cbInfos; 1024 } 1025 handleCwQueryResult(ImsSsInfo[] infos)1026 private int[] handleCwQueryResult(ImsSsInfo[] infos) { 1027 int[] cwInfos = new int[2]; 1028 cwInfos[0] = 0; 1029 1030 if (infos[0].mStatus == 1) { 1031 cwInfos[0] = 1; 1032 cwInfos[1] = SERVICE_CLASS_VOICE; 1033 } 1034 1035 return cwInfos; 1036 } 1037 1038 private void sendResponse(Message onComplete, Object result, Throwable e)1039 sendResponse(Message onComplete, Object result, Throwable e) { 1040 if (onComplete != null) { 1041 CommandException ex = null; 1042 ImsException imsEx = null; 1043 if (e != null) { 1044 if (e instanceof ImsException) { 1045 imsEx = (ImsException) e; 1046 AsyncResult.forMessage(onComplete, result, imsEx); 1047 } else { 1048 ex = getCommandException(e); 1049 AsyncResult.forMessage(onComplete, result, ex); 1050 } 1051 } else { 1052 AsyncResult.forMessage(onComplete, result, null); 1053 } 1054 onComplete.sendToTarget(); 1055 } 1056 } 1057 1058 @Override handleMessage(Message msg)1059 public void handleMessage (Message msg) { 1060 AsyncResult ar = (AsyncResult) msg.obj; 1061 Message onComplete; 1062 1063 if (DBG) Rlog.d(LOG_TAG, "handleMessage what=" + msg.what); 1064 switch (msg.what) { 1065 case EVENT_SET_CALL_FORWARD_DONE: 1066 IccRecords r = getIccRecords(); 1067 Cf cf = (Cf) ar.userObj; 1068 if (cf.mIsCfu && ar.exception == null && r != null) { 1069 r.setVoiceCallForwardingFlag(1, msg.arg1 == 1, cf.mSetCfNumber); 1070 } 1071 sendResponse(cf.mOnComplete, null, ar.exception); 1072 break; 1073 1074 case EVENT_GET_CALL_FORWARD_DONE: 1075 CallForwardInfo[] cfInfos = null; 1076 if (ar.exception == null) { 1077 cfInfos = handleCfQueryResult((ImsCallForwardInfo[])ar.result); 1078 } 1079 sendResponse((Message) ar.userObj, cfInfos, ar.exception); 1080 break; 1081 1082 case EVENT_GET_CALL_BARRING_DONE: 1083 case EVENT_GET_CALL_WAITING_DONE: 1084 int[] ssInfos = null; 1085 if (ar.exception == null) { 1086 if (msg.what == EVENT_GET_CALL_BARRING_DONE) { 1087 ssInfos = handleCbQueryResult((ImsSsInfo[])ar.result); 1088 } else if (msg.what == EVENT_GET_CALL_WAITING_DONE) { 1089 ssInfos = handleCwQueryResult((ImsSsInfo[])ar.result); 1090 } 1091 } 1092 sendResponse((Message) ar.userObj, ssInfos, ar.exception); 1093 break; 1094 1095 case EVENT_SET_CALL_BARRING_DONE: 1096 case EVENT_SET_CALL_WAITING_DONE: 1097 sendResponse((Message) ar.userObj, null, ar.exception); 1098 break; 1099 1100 default: 1101 super.handleMessage(msg); 1102 break; 1103 } 1104 } 1105 1106 /** 1107 * Listen to the IMS ECBM state change 1108 */ 1109 ImsEcbmStateListener mImsEcbmStateListener = 1110 new ImsEcbmStateListener() { 1111 @Override 1112 public void onECBMEntered() { 1113 if (DBG) Rlog.d(LOG_TAG, "onECBMEntered"); 1114 handleEnterEmergencyCallbackMode(); 1115 } 1116 1117 @Override 1118 public void onECBMExited() { 1119 if (DBG) Rlog.d(LOG_TAG, "onECBMExited"); 1120 handleExitEmergencyCallbackMode(); 1121 } 1122 }; 1123 isInEmergencyCall()1124 public boolean isInEmergencyCall() { 1125 return mCT.isInEmergencyCall(); 1126 } 1127 isInEcm()1128 public boolean isInEcm() { 1129 return mIsPhoneInEcmState; 1130 } 1131 sendEmergencyCallbackModeChange()1132 void sendEmergencyCallbackModeChange() { 1133 // Send an Intent 1134 Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 1135 intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, mIsPhoneInEcmState); 1136 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId()); 1137 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL); 1138 if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallbackModeChange"); 1139 } 1140 1141 @Override exitEmergencyCallbackMode()1142 public void exitEmergencyCallbackMode() { 1143 if (mWakeLock.isHeld()) { 1144 mWakeLock.release(); 1145 } 1146 if (DBG) Rlog.d(LOG_TAG, "exitEmergencyCallbackMode()"); 1147 1148 // Send a message which will invoke handleExitEmergencyCallbackMode 1149 ImsEcbm ecbm; 1150 try { 1151 ecbm = mCT.getEcbmInterface(); 1152 ecbm.exitEmergencyCallbackMode(); 1153 } catch (ImsException e) { 1154 e.printStackTrace(); 1155 } 1156 } 1157 handleEnterEmergencyCallbackMode()1158 private void handleEnterEmergencyCallbackMode() { 1159 if (DBG) { 1160 Rlog.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= " 1161 + mIsPhoneInEcmState); 1162 } 1163 // if phone is not in Ecm mode, and it's changed to Ecm mode 1164 if (mIsPhoneInEcmState == false) { 1165 mIsPhoneInEcmState = true; 1166 // notify change 1167 sendEmergencyCallbackModeChange(); 1168 setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true"); 1169 1170 // Post this runnable so we will automatically exit 1171 // if no one invokes exitEmergencyCallbackMode() directly. 1172 long delayInMillis = SystemProperties.getLong( 1173 TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE); 1174 postDelayed(mExitEcmRunnable, delayInMillis); 1175 // We don't want to go to sleep while in Ecm 1176 mWakeLock.acquire(); 1177 } 1178 } 1179 handleExitEmergencyCallbackMode()1180 private void handleExitEmergencyCallbackMode() { 1181 if (DBG) { 1182 Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode: mIsPhoneInEcmState = " 1183 + mIsPhoneInEcmState); 1184 } 1185 // Remove pending exit Ecm runnable, if any 1186 removeCallbacks(mExitEcmRunnable); 1187 1188 if (mEcmExitRespRegistrant != null) { 1189 mEcmExitRespRegistrant.notifyResult(Boolean.TRUE); 1190 } 1191 if (mIsPhoneInEcmState) { 1192 mIsPhoneInEcmState = false; 1193 setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false"); 1194 } 1195 // send an Intent 1196 sendEmergencyCallbackModeChange(); 1197 } 1198 1199 /** 1200 * Handle to cancel or restart Ecm timer in emergency call back mode if action is 1201 * CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled; otherwise, restart 1202 * Ecm timer and notify apps the timer is restarted. 1203 */ handleTimerInEmergencyCallbackMode(int action)1204 void handleTimerInEmergencyCallbackMode(int action) { 1205 switch (action) { 1206 case CANCEL_ECM_TIMER: 1207 removeCallbacks(mExitEcmRunnable); 1208 if (mDefaultPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) { 1209 ((GSMPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.TRUE); 1210 } else { // Should be CDMA - also go here by default 1211 ((CDMAPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.TRUE); 1212 } 1213 break; 1214 case RESTART_ECM_TIMER: 1215 long delayInMillis = SystemProperties.getLong( 1216 TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE); 1217 postDelayed(mExitEcmRunnable, delayInMillis); 1218 if (mDefaultPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) { 1219 ((GSMPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.FALSE); 1220 } else { // Should be CDMA - also go here by default 1221 ((CDMAPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.FALSE); 1222 } 1223 break; 1224 default: 1225 Rlog.e(LOG_TAG, "handleTimerInEmergencyCallbackMode, unsupported action " + action); 1226 } 1227 } 1228 setOnEcbModeExitResponse(Handler h, int what, Object obj)1229 public void setOnEcbModeExitResponse(Handler h, int what, Object obj) { 1230 mEcmExitRespRegistrant = new Registrant(h, what, obj); 1231 } 1232 unsetOnEcbModeExitResponse(Handler h)1233 public void unsetOnEcbModeExitResponse(Handler h) { 1234 mEcmExitRespRegistrant.clear(); 1235 } 1236 isVolteEnabled()1237 public boolean isVolteEnabled() { 1238 return mCT.isVolteEnabled(); 1239 } 1240 isVtEnabled()1241 public boolean isVtEnabled() { 1242 return mCT.isVtEnabled(); 1243 } 1244 getDefaultPhone()1245 public Phone getDefaultPhone() { 1246 return mDefaultPhone; 1247 } 1248 isImsRegistered()1249 public boolean isImsRegistered() { 1250 return mImsRegistered; 1251 } 1252 setImsRegistered(boolean value)1253 public void setImsRegistered(boolean value) { 1254 mImsRegistered = value; 1255 } 1256 callEndCleanupHandOverCallIfAny()1257 public void callEndCleanupHandOverCallIfAny() { 1258 mCT.callEndCleanupHandOverCallIfAny(); 1259 } 1260 } 1261