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 static android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE; 20 import static android.telephony.ims.ImsManager.EXTRA_WFC_REGISTRATION_FAILURE_TITLE; 21 22 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC; 23 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr; 24 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOC; 25 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOIC; 26 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOICxH; 27 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_ALL; 28 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MO; 29 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MT; 30 import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BIC_ACR; 31 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE; 32 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; 33 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE; 34 import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION; 35 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; 36 import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; 37 import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; 38 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; 39 import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; 40 import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; 41 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NONE; 42 import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; 43 44 import android.app.Activity; 45 import android.app.ActivityManager; 46 import android.app.Notification; 47 import android.app.NotificationManager; 48 import android.app.PendingIntent; 49 import android.compat.annotation.UnsupportedAppUsage; 50 import android.content.BroadcastReceiver; 51 import android.content.Context; 52 import android.content.Intent; 53 import android.net.Uri; 54 import android.os.AsyncResult; 55 import android.os.Bundle; 56 import android.os.Handler; 57 import android.os.Message; 58 import android.os.PersistableBundle; 59 import android.os.PowerManager; 60 import android.os.PowerManager.WakeLock; 61 import android.os.Registrant; 62 import android.os.RegistrantList; 63 import android.os.ResultReceiver; 64 import android.os.UserHandle; 65 import android.sysprop.TelephonyProperties; 66 import android.telephony.AccessNetworkConstants; 67 import android.telephony.CarrierConfigManager; 68 import android.telephony.NetworkRegistrationInfo; 69 import android.telephony.PhoneNumberUtils; 70 import android.telephony.ServiceState; 71 import android.telephony.SubscriptionManager; 72 import android.telephony.TelephonyManager; 73 import android.telephony.UssdResponse; 74 import android.telephony.ims.ImsCallForwardInfo; 75 import android.telephony.ims.ImsCallProfile; 76 import android.telephony.ims.ImsReasonInfo; 77 import android.telephony.ims.ImsSsData; 78 import android.telephony.ims.ImsSsInfo; 79 import android.telephony.ims.RegistrationManager; 80 import android.telephony.ims.stub.ImsUtImplBase; 81 import android.text.TextUtils; 82 import android.util.LocalLog; 83 84 import com.android.ims.ImsEcbm; 85 import com.android.ims.ImsEcbmStateListener; 86 import com.android.ims.ImsException; 87 import com.android.ims.ImsManager; 88 import com.android.ims.ImsUtInterface; 89 import com.android.internal.annotations.VisibleForTesting; 90 import com.android.internal.telephony.Call; 91 import com.android.internal.telephony.CallFailCause; 92 import com.android.internal.telephony.CallForwardInfo; 93 import com.android.internal.telephony.CallStateException; 94 import com.android.internal.telephony.CallTracker; 95 import com.android.internal.telephony.CommandException; 96 import com.android.internal.telephony.CommandsInterface; 97 import com.android.internal.telephony.Connection; 98 import com.android.internal.telephony.GsmCdmaPhone; 99 import com.android.internal.telephony.MmiCode; 100 import com.android.internal.telephony.Phone; 101 import com.android.internal.telephony.PhoneConstants; 102 import com.android.internal.telephony.PhoneNotifier; 103 import com.android.internal.telephony.ServiceStateTracker; 104 import com.android.internal.telephony.TelephonyComponentFactory; 105 import com.android.internal.telephony.TelephonyIntents; 106 import com.android.internal.telephony.dataconnection.TransportManager; 107 import com.android.internal.telephony.emergency.EmergencyNumberTracker; 108 import com.android.internal.telephony.gsm.GsmMmiCode; 109 import com.android.internal.telephony.gsm.SuppServiceNotification; 110 import com.android.internal.telephony.metrics.TelephonyMetrics; 111 import com.android.internal.telephony.metrics.VoiceCallSessionStats; 112 import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState; 113 import com.android.internal.telephony.uicc.IccRecords; 114 import com.android.internal.telephony.util.NotificationChannelController; 115 import com.android.internal.util.IndentingPrintWriter; 116 import com.android.telephony.Rlog; 117 118 import java.io.FileDescriptor; 119 import java.io.PrintWriter; 120 import java.util.ArrayList; 121 import java.util.List; 122 import java.util.function.Consumer; 123 124 /** 125 * {@hide} 126 */ 127 public class ImsPhone extends ImsPhoneBase { 128 private static final String LOG_TAG = "ImsPhone"; 129 private static final boolean DBG = true; 130 private static final boolean VDBG = false; // STOPSHIP if true 131 132 private static final int EVENT_SET_CALL_BARRING_DONE = EVENT_LAST + 1; 133 private static final int EVENT_GET_CALL_BARRING_DONE = EVENT_LAST + 2; 134 private static final int EVENT_SET_CALL_WAITING_DONE = EVENT_LAST + 3; 135 private static final int EVENT_GET_CALL_WAITING_DONE = EVENT_LAST + 4; 136 private static final int EVENT_SET_CLIR_DONE = EVENT_LAST + 5; 137 private static final int EVENT_GET_CLIR_DONE = EVENT_LAST + 6; 138 private static final int EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED = EVENT_LAST + 7; 139 @VisibleForTesting 140 public static final int EVENT_SERVICE_STATE_CHANGED = EVENT_LAST + 8; 141 private static final int EVENT_VOICE_CALL_ENDED = EVENT_LAST + 9; 142 private static final int EVENT_INITIATE_VOLTE_SILENT_REDIAL = EVENT_LAST + 10; 143 private static final int EVENT_GET_CLIP_DONE = EVENT_LAST + 11; 144 145 static final int RESTART_ECM_TIMER = 0; // restart Ecm timer 146 static final int CANCEL_ECM_TIMER = 1; // cancel Ecm timer 147 148 // Default Emergency Callback Mode exit timer 149 private static final long DEFAULT_ECM_EXIT_TIMER_VALUE = 300000; 150 151 public static class ImsDialArgs extends DialArgs { 152 public static class Builder extends DialArgs.Builder<ImsDialArgs.Builder> { 153 private android.telecom.Connection.RttTextStream mRttTextStream; 154 private int mClirMode = CommandsInterface.CLIR_DEFAULT; 155 private int mRetryCallFailCause = ImsReasonInfo.CODE_UNSPECIFIED; 156 private int mRetryCallFailNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; 157 from(DialArgs dialArgs)158 public static ImsDialArgs.Builder from(DialArgs dialArgs) { 159 return new ImsDialArgs.Builder() 160 .setUusInfo(dialArgs.uusInfo) 161 .setVideoState(dialArgs.videoState) 162 .setIntentExtras(dialArgs.intentExtras); 163 } 164 from(ImsDialArgs dialArgs)165 public static ImsDialArgs.Builder from(ImsDialArgs dialArgs) { 166 return new ImsDialArgs.Builder() 167 .setUusInfo(dialArgs.uusInfo) 168 .setVideoState(dialArgs.videoState) 169 .setIntentExtras(dialArgs.intentExtras) 170 .setRttTextStream(dialArgs.rttTextStream) 171 .setClirMode(dialArgs.clirMode) 172 .setRetryCallFailCause(dialArgs.retryCallFailCause) 173 .setRetryCallFailNetworkType(dialArgs.retryCallFailNetworkType); 174 } 175 setRttTextStream( android.telecom.Connection.RttTextStream s)176 public ImsDialArgs.Builder setRttTextStream( 177 android.telecom.Connection.RttTextStream s) { 178 mRttTextStream = s; 179 return this; 180 } 181 setClirMode(int clirMode)182 public ImsDialArgs.Builder setClirMode(int clirMode) { 183 this.mClirMode = clirMode; 184 return this; 185 } 186 setRetryCallFailCause(int retryCallFailCause)187 public ImsDialArgs.Builder setRetryCallFailCause(int retryCallFailCause) { 188 this.mRetryCallFailCause = retryCallFailCause; 189 return this; 190 } 191 setRetryCallFailNetworkType(int retryCallFailNetworkType)192 public ImsDialArgs.Builder setRetryCallFailNetworkType(int retryCallFailNetworkType) { 193 this.mRetryCallFailNetworkType = retryCallFailNetworkType; 194 return this; 195 } 196 build()197 public ImsDialArgs build() { 198 return new ImsDialArgs(this); 199 } 200 } 201 202 /** 203 * The RTT text stream. If non-null, indicates that connection supports RTT 204 * communication with the in-call app. 205 */ 206 public final android.telecom.Connection.RttTextStream rttTextStream; 207 208 /** The CLIR mode to use */ 209 public final int clirMode; 210 public final int retryCallFailCause; 211 public final int retryCallFailNetworkType; 212 ImsDialArgs(ImsDialArgs.Builder b)213 private ImsDialArgs(ImsDialArgs.Builder b) { 214 super(b); 215 this.rttTextStream = b.mRttTextStream; 216 this.clirMode = b.mClirMode; 217 this.retryCallFailCause = b.mRetryCallFailCause; 218 this.retryCallFailNetworkType = b.mRetryCallFailNetworkType; 219 } 220 } 221 222 // Instance Variables 223 Phone mDefaultPhone; 224 @UnsupportedAppUsage 225 ImsPhoneCallTracker mCT; 226 ImsExternalCallTracker mExternalCallTracker; 227 @UnsupportedAppUsage 228 private ArrayList <ImsPhoneMmiCode> mPendingMMIs = new ArrayList<ImsPhoneMmiCode>(); 229 @UnsupportedAppUsage 230 private ServiceState mSS = new ServiceState(); 231 232 // To redial silently through GSM or CDMA when dialing through IMS fails 233 private String mLastDialString; 234 235 private WakeLock mWakeLock; 236 237 // mEcmExitRespRegistrant is informed after the phone has been exited the emergency 238 // callback mode keep track of if phone is in emergency callback mode 239 private Registrant mEcmExitRespRegistrant; 240 241 private final RegistrantList mSilentRedialRegistrants = new RegistrantList(); 242 243 private final LocalLog mRegLocalLog = new LocalLog(100); 244 private TelephonyMetrics mMetrics; 245 246 // The helper class to receive and store the MmTel registration status updated. 247 private ImsRegistrationCallbackHelper mImsMmTelRegistrationHelper; 248 249 private boolean mRoaming = false; 250 251 private boolean mIsInImsEcm = false; 252 253 // List of Registrants to send supplementary service notifications to. 254 private RegistrantList mSsnRegistrants = new RegistrantList(); 255 256 // A runnable which is used to automatically exit from Ecm after a period of time. 257 private Runnable mExitEcmRunnable = new Runnable() { 258 @Override 259 public void run() { 260 exitEmergencyCallbackMode(); 261 } 262 }; 263 264 private Uri[] mCurrentSubscriberUris; 265 setCurrentSubscriberUris(Uri[] currentSubscriberUris)266 protected void setCurrentSubscriberUris(Uri[] currentSubscriberUris) { 267 this.mCurrentSubscriberUris = currentSubscriberUris; 268 } 269 270 @UnsupportedAppUsage 271 @Override notifyCallForwardingIndicator()272 public void notifyCallForwardingIndicator() { 273 super.notifyCallForwardingIndicator(); 274 } 275 276 @UnsupportedAppUsage 277 @Override notifyPreciseCallStateChanged()278 public void notifyPreciseCallStateChanged() { 279 super.notifyPreciseCallStateChanged(); 280 } 281 282 @Override getCurrentSubscriberUris()283 public Uri[] getCurrentSubscriberUris() { 284 return mCurrentSubscriberUris; 285 } 286 287 @Override getEmergencyNumberDbVersion()288 public int getEmergencyNumberDbVersion() { 289 return getEmergencyNumberTracker().getEmergencyNumberDbVersion(); 290 } 291 292 @Override getEmergencyNumberTracker()293 public EmergencyNumberTracker getEmergencyNumberTracker() { 294 return mDefaultPhone.getEmergencyNumberTracker(); 295 } 296 297 @Override getServiceStateTracker()298 public ServiceStateTracker getServiceStateTracker() { 299 return mDefaultPhone.getServiceStateTracker(); 300 } 301 302 // Create Cf (Call forward) so that dialling number & 303 // mIsCfu (true if reason is call forward unconditional) 304 // mOnComplete (Message object passed by client) can be packed & 305 // given as a single Cf object as user data to UtInterface. 306 private static class Cf { 307 final String mSetCfNumber; 308 final Message mOnComplete; 309 final boolean mIsCfu; 310 311 @UnsupportedAppUsage Cf(String cfNumber, boolean isCfu, Message onComplete)312 Cf(String cfNumber, boolean isCfu, Message onComplete) { 313 mSetCfNumber = cfNumber; 314 mIsCfu = isCfu; 315 mOnComplete = onComplete; 316 } 317 } 318 319 // Create SS (Supplementary Service) so that save SS params & 320 // mOnComplete (Message object passed by client) can be packed 321 // given as a single SS object as user data to UtInterface. 322 @VisibleForTesting 323 public static class SS { 324 int mCfAction; 325 int mCfReason; 326 String mDialingNumber; 327 int mTimerSeconds; 328 boolean mEnable; 329 int mClirMode; 330 String mFacility; 331 boolean mLockState; 332 String mPassword; 333 int mServiceClass; 334 @VisibleForTesting 335 public Message mOnComplete; 336 337 // Default // Query CW, CLIR, CLIP SS(Message onComplete)338 SS(Message onComplete) { 339 mOnComplete = onComplete; 340 } 341 342 // Update CLIP SS(boolean enable, Message onComplete)343 SS(boolean enable, Message onComplete) { 344 mEnable = enable; 345 mOnComplete = onComplete; 346 } 347 348 // Update CLIR SS(int clirMode, Message onComplete)349 SS(int clirMode, Message onComplete) { 350 mClirMode = clirMode; 351 mOnComplete = onComplete; 352 } 353 354 // Update CW SS(boolean enable, int serviceClass, Message onComplete)355 SS(boolean enable, int serviceClass, Message onComplete) { 356 mEnable = enable; 357 mServiceClass = serviceClass; 358 mOnComplete = onComplete; 359 } 360 361 // Query CF SS(int cfReason, int serviceClass, Message onComplete)362 SS(int cfReason, int serviceClass, Message onComplete) { 363 mCfReason = cfReason; 364 mServiceClass = serviceClass; 365 mOnComplete = onComplete; 366 } 367 368 // Update CF SS(int cfAction, int cfReason, String dialingNumber, int serviceClass, int timerSeconds, Message onComplete)369 SS(int cfAction, int cfReason, String dialingNumber, 370 int serviceClass, int timerSeconds, Message onComplete) { 371 mCfAction = cfAction; 372 mCfReason = cfReason; 373 mDialingNumber = dialingNumber; 374 mServiceClass = serviceClass; 375 mTimerSeconds = timerSeconds; 376 mOnComplete = onComplete; 377 } 378 379 // Query CB SS(String facility, String password, int serviceClass, Message onComplete)380 SS(String facility, String password, int serviceClass, Message onComplete) { 381 mFacility = facility; 382 mPassword = password; 383 mServiceClass = serviceClass; 384 mOnComplete = onComplete; 385 } 386 387 // Update CB SS(String facility, boolean lockState, String password, int serviceClass, Message onComplete)388 SS(String facility, boolean lockState, String password, 389 int serviceClass, Message onComplete) { 390 mFacility = facility; 391 mLockState = lockState; 392 mPassword = password; 393 mServiceClass = serviceClass; 394 mOnComplete = onComplete; 395 } 396 } 397 398 // Constructors ImsPhone(Context context, PhoneNotifier notifier, Phone defaultPhone)399 public ImsPhone(Context context, PhoneNotifier notifier, Phone defaultPhone) { 400 this(context, notifier, defaultPhone, false); 401 } 402 403 @VisibleForTesting ImsPhone(Context context, PhoneNotifier notifier, Phone defaultPhone, boolean unitTestMode)404 public ImsPhone(Context context, PhoneNotifier notifier, Phone defaultPhone, 405 boolean unitTestMode) { 406 super("ImsPhone", context, notifier, unitTestMode); 407 408 mDefaultPhone = defaultPhone; 409 // The ImsExternalCallTracker needs to be defined before the ImsPhoneCallTracker, as the 410 // ImsPhoneCallTracker uses a thread to spool up the ImsManager. Part of this involves 411 // setting the multiendpoint listener on the external call tracker. So we need to ensure 412 // the external call tracker is available first to avoid potential timing issues. 413 mExternalCallTracker = 414 TelephonyComponentFactory.getInstance() 415 .inject(ImsExternalCallTracker.class.getName()) 416 .makeImsExternalCallTracker(this); 417 mCT = TelephonyComponentFactory.getInstance().inject(ImsPhoneCallTracker.class.getName()) 418 .makeImsPhoneCallTracker(this); 419 mCT.registerPhoneStateListener(mExternalCallTracker); 420 mExternalCallTracker.setCallPuller(mCT); 421 422 mSS.setStateOff(); 423 424 mPhoneId = mDefaultPhone.getPhoneId(); 425 426 mMetrics = TelephonyMetrics.getInstance(); 427 428 mImsMmTelRegistrationHelper = new ImsRegistrationCallbackHelper(mMmTelRegistrationUpdate, 429 context.getMainExecutor()); 430 431 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 432 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); 433 mWakeLock.setReferenceCounted(false); 434 435 if (mDefaultPhone.getServiceStateTracker() != null 436 && mDefaultPhone.getTransportManager() != null) { 437 for (int transport : mDefaultPhone.getTransportManager().getAvailableTransports()) { 438 mDefaultPhone.getServiceStateTracker() 439 .registerForDataRegStateOrRatChanged(transport, this, 440 EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED, null); 441 } 442 } 443 // Sets the Voice reg state to STATE_OUT_OF_SERVICE and also queries the data service 444 // state. We don't ever need the voice reg state to be anything other than in or out of 445 // service. 446 setServiceState(ServiceState.STATE_OUT_OF_SERVICE); 447 448 mDefaultPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); 449 // Force initial roaming state update later, on EVENT_CARRIER_CONFIG_CHANGED. 450 // Settings provider or CarrierConfig may not be loaded now. 451 452 mDefaultPhone.registerForVolteSilentRedial(this, EVENT_INITIATE_VOLTE_SILENT_REDIAL, null); 453 } 454 455 //todo: get rid of this function. It is not needed since parentPhone obj never changes 456 @Override dispose()457 public void dispose() { 458 logd("dispose"); 459 // Nothing to dispose in Phone 460 //super.dispose(); 461 mPendingMMIs.clear(); 462 mExternalCallTracker.tearDown(); 463 mCT.unregisterPhoneStateListener(mExternalCallTracker); 464 mCT.unregisterForVoiceCallEnded(this); 465 mCT.dispose(); 466 467 //Force all referenced classes to unregister their former registered events 468 if (mDefaultPhone != null && mDefaultPhone.getServiceStateTracker() != null) { 469 for (int transport : mDefaultPhone.getTransportManager().getAvailableTransports()) { 470 mDefaultPhone.getServiceStateTracker() 471 .unregisterForDataRegStateOrRatChanged(transport, this); 472 } 473 mDefaultPhone.unregisterForServiceStateChanged(this); 474 } 475 476 if (mDefaultPhone != null) { 477 mDefaultPhone.unregisterForVolteSilentRedial(this); 478 } 479 } 480 481 @UnsupportedAppUsage 482 @Override getServiceState()483 public ServiceState getServiceState() { 484 return mSS; 485 } 486 487 @UnsupportedAppUsage 488 @VisibleForTesting setServiceState(int state)489 public void setServiceState(int state) { 490 boolean isVoiceRegStateChanged = false; 491 492 synchronized (this) { 493 isVoiceRegStateChanged = mSS.getState() != state; 494 mSS.setVoiceRegState(state); 495 } 496 updateDataServiceState(); 497 498 if (isVoiceRegStateChanged) { 499 if (mDefaultPhone.getServiceStateTracker() != null) { 500 mDefaultPhone.getServiceStateTracker().onImsServiceStateChanged(); 501 } 502 } 503 } 504 505 @Override getCallTracker()506 public CallTracker getCallTracker() { 507 return mCT; 508 } 509 getExternalCallTracker()510 public ImsExternalCallTracker getExternalCallTracker() { 511 return mExternalCallTracker; 512 } 513 514 @Override 515 public List<? extends ImsPhoneMmiCode> getPendingMmiCodes()516 getPendingMmiCodes() { 517 return mPendingMMIs; 518 } 519 520 @Override 521 public void acceptCall(int videoState)522 acceptCall(int videoState) throws CallStateException { 523 mCT.acceptCall(videoState); 524 } 525 526 @Override 527 public void rejectCall()528 rejectCall() throws CallStateException { 529 mCT.rejectCall(); 530 } 531 532 @Override 533 public void switchHoldingAndActive()534 switchHoldingAndActive() throws CallStateException { 535 throw new UnsupportedOperationException("Use hold() and unhold() instead."); 536 } 537 538 @Override canConference()539 public boolean canConference() { 540 return mCT.canConference(); 541 } 542 canDial()543 public boolean canDial() { 544 try { 545 mCT.checkForDialIssues(); 546 } catch (CallStateException cse) { 547 return false; 548 } 549 return true; 550 } 551 552 @Override conference()553 public void conference() { 554 mCT.conference(); 555 } 556 557 @Override clearDisconnected()558 public void clearDisconnected() { 559 mCT.clearDisconnected(); 560 } 561 562 @Override canTransfer()563 public boolean canTransfer() { 564 return mCT.canTransfer(); 565 } 566 567 @Override explicitCallTransfer()568 public void explicitCallTransfer() throws CallStateException { 569 mCT.explicitCallTransfer(); 570 } 571 572 @UnsupportedAppUsage 573 @Override 574 public ImsPhoneCall getForegroundCall()575 getForegroundCall() { 576 return mCT.mForegroundCall; 577 } 578 579 @UnsupportedAppUsage 580 @Override 581 public ImsPhoneCall getBackgroundCall()582 getBackgroundCall() { 583 return mCT.mBackgroundCall; 584 } 585 586 @UnsupportedAppUsage 587 @Override 588 public ImsPhoneCall getRingingCall()589 getRingingCall() { 590 return mCT.mRingingCall; 591 } 592 593 @Override isImsAvailable()594 public boolean isImsAvailable() { 595 return mCT.isImsServiceReady(); 596 } 597 598 /** 599 * Hold the currently active call, possibly unholding a currently held call. 600 * @throws CallStateException 601 */ holdActiveCall()602 public void holdActiveCall() throws CallStateException { 603 mCT.holdActiveCall(); 604 } 605 606 /** 607 * Unhold the currently active call, possibly holding a currently active call. 608 * If the call tracker is already in the middle of a hold operation, this is a noop. 609 * @throws CallStateException 610 */ unholdHeldCall()611 public void unholdHeldCall() throws CallStateException { 612 mCT.unholdHeldCall(); 613 } 614 handleCallDeflectionIncallSupplementaryService( String dialString)615 private boolean handleCallDeflectionIncallSupplementaryService( 616 String dialString) { 617 if (dialString.length() > 1) { 618 return false; 619 } 620 621 if (getRingingCall().getState() != ImsPhoneCall.State.IDLE) { 622 if (DBG) logd("MmiCode 0: rejectCall"); 623 try { 624 mCT.rejectCall(); 625 } catch (CallStateException e) { 626 if (DBG) Rlog.d(LOG_TAG, "reject failed", e); 627 notifySuppServiceFailed(Phone.SuppService.REJECT); 628 } 629 } else if (getBackgroundCall().getState() != ImsPhoneCall.State.IDLE) { 630 if (DBG) logd("MmiCode 0: hangupWaitingOrBackground"); 631 try { 632 mCT.hangup(getBackgroundCall()); 633 } catch (CallStateException e) { 634 if (DBG) Rlog.d(LOG_TAG, "hangup failed", e); 635 } 636 } 637 638 return true; 639 } 640 sendUssdResponse(String ussdRequest, CharSequence message, int returnCode, ResultReceiver wrappedCallback)641 private void sendUssdResponse(String ussdRequest, CharSequence message, int returnCode, 642 ResultReceiver wrappedCallback) { 643 UssdResponse response = new UssdResponse(ussdRequest, message); 644 Bundle returnData = new Bundle(); 645 returnData.putParcelable(TelephonyManager.USSD_RESPONSE, response); 646 wrappedCallback.send(returnCode, returnData); 647 648 } 649 650 @Override handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback)651 public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) 652 throws CallStateException { 653 if (mPendingMMIs.size() > 0) { 654 // There are MMI codes in progress; fail attempt now. 655 logi("handleUssdRequest: queue full: " + Rlog.pii(LOG_TAG, ussdRequest)); 656 sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE, 657 wrappedCallback ); 658 return true; 659 } 660 try { 661 dialInternal(ussdRequest, new ImsDialArgs.Builder().build(), wrappedCallback); 662 } catch (CallStateException cse) { 663 if (CS_FALLBACK.equals(cse.getMessage())) { 664 throw cse; 665 } else { 666 Rlog.w(LOG_TAG, "Could not execute USSD " + cse); 667 sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE, 668 wrappedCallback); 669 } 670 } catch (Exception e) { 671 Rlog.w(LOG_TAG, "Could not execute USSD " + e); 672 sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE, 673 wrappedCallback); 674 return false; 675 } 676 return true; 677 } 678 handleCallWaitingIncallSupplementaryService( String dialString)679 private boolean handleCallWaitingIncallSupplementaryService( 680 String dialString) { 681 int len = dialString.length(); 682 683 if (len > 2) { 684 return false; 685 } 686 687 ImsPhoneCall call = getForegroundCall(); 688 689 try { 690 if (len > 1) { 691 if (DBG) logd("not support 1X SEND"); 692 notifySuppServiceFailed(Phone.SuppService.HANGUP); 693 } else { 694 if (call.getState() != ImsPhoneCall.State.IDLE) { 695 if (DBG) logd("MmiCode 1: hangup foreground"); 696 mCT.hangup(call); 697 } else { 698 if (DBG) logd("MmiCode 1: holdActiveCallForWaitingCall"); 699 mCT.holdActiveCallForWaitingCall(); 700 } 701 } 702 } catch (CallStateException e) { 703 if (DBG) Rlog.d(LOG_TAG, "hangup failed", e); 704 notifySuppServiceFailed(Phone.SuppService.HANGUP); 705 } 706 707 return true; 708 } 709 handleCallHoldIncallSupplementaryService(String dialString)710 private boolean handleCallHoldIncallSupplementaryService(String dialString) { 711 int len = dialString.length(); 712 713 if (len > 2) { 714 return false; 715 } 716 717 if (len > 1) { 718 if (DBG) logd("separate not supported"); 719 notifySuppServiceFailed(Phone.SuppService.SEPARATE); 720 } else { 721 try { 722 if (getRingingCall().getState() != ImsPhoneCall.State.IDLE) { 723 if (DBG) logd("MmiCode 2: accept ringing call"); 724 mCT.acceptCall(ImsCallProfile.CALL_TYPE_VOICE); 725 } else if (getBackgroundCall().getState() == ImsPhoneCall.State.HOLDING) { 726 // If there's an active ongoing call as well, hold it and the background one 727 // should automatically unhold. Otherwise just unhold the background call. 728 if (getForegroundCall().getState() != ImsPhoneCall.State.IDLE) { 729 if (DBG) logd("MmiCode 2: switch holding and active"); 730 mCT.holdActiveCall(); 731 } else { 732 if (DBG) logd("MmiCode 2: unhold held call"); 733 mCT.unholdHeldCall(); 734 } 735 } else if (getForegroundCall().getState() != ImsPhoneCall.State.IDLE) { 736 if (DBG) logd("MmiCode 2: hold active call"); 737 mCT.holdActiveCall(); 738 } 739 } catch (CallStateException e) { 740 if (DBG) Rlog.d(LOG_TAG, "switch failed", e); 741 notifySuppServiceFailed(Phone.SuppService.SWITCH); 742 } 743 } 744 745 return true; 746 } 747 handleMultipartyIncallSupplementaryService( String dialString)748 private boolean handleMultipartyIncallSupplementaryService( 749 String dialString) { 750 if (dialString.length() > 1) { 751 return false; 752 } 753 754 if (DBG) logd("MmiCode 3: merge calls"); 755 conference(); 756 return true; 757 } 758 handleEctIncallSupplementaryService(String dialString)759 private boolean handleEctIncallSupplementaryService(String dialString) { 760 if (dialString.length() != 1) { 761 return false; 762 } 763 764 if (DBG) logd("MmiCode 4: explicit call transfer"); 765 try { 766 explicitCallTransfer(); 767 } catch (CallStateException e) { 768 if (DBG) Rlog.d(LOG_TAG, "explicit call transfer failed", e); 769 notifySuppServiceFailed(Phone.SuppService.TRANSFER); 770 } 771 return true; 772 } 773 handleCcbsIncallSupplementaryService(String dialString)774 private boolean handleCcbsIncallSupplementaryService(String dialString) { 775 if (dialString.length() > 1) { 776 return false; 777 } 778 779 logi("MmiCode 5: CCBS not supported!"); 780 // Treat it as an "unknown" service. 781 notifySuppServiceFailed(Phone.SuppService.UNKNOWN); 782 return true; 783 } 784 notifySuppSvcNotification(SuppServiceNotification suppSvc)785 public void notifySuppSvcNotification(SuppServiceNotification suppSvc) { 786 logd("notifySuppSvcNotification: suppSvc = " + suppSvc); 787 788 AsyncResult ar = new AsyncResult(null, suppSvc, null); 789 mSsnRegistrants.notifyRegistrants(ar); 790 } 791 792 @UnsupportedAppUsage 793 @Override handleInCallMmiCommands(String dialString)794 public boolean handleInCallMmiCommands(String dialString) { 795 if (!isInCall()) { 796 return false; 797 } 798 799 if (TextUtils.isEmpty(dialString)) { 800 return false; 801 } 802 803 boolean result = false; 804 char ch = dialString.charAt(0); 805 switch (ch) { 806 case '0': 807 result = handleCallDeflectionIncallSupplementaryService( 808 dialString); 809 break; 810 case '1': 811 result = handleCallWaitingIncallSupplementaryService( 812 dialString); 813 break; 814 case '2': 815 result = handleCallHoldIncallSupplementaryService(dialString); 816 break; 817 case '3': 818 result = handleMultipartyIncallSupplementaryService(dialString); 819 break; 820 case '4': 821 result = handleEctIncallSupplementaryService(dialString); 822 break; 823 case '5': 824 result = handleCcbsIncallSupplementaryService(dialString); 825 break; 826 default: 827 break; 828 } 829 830 return result; 831 } 832 isInCall()833 boolean isInCall() { 834 ImsPhoneCall.State foregroundCallState = getForegroundCall().getState(); 835 ImsPhoneCall.State backgroundCallState = getBackgroundCall().getState(); 836 ImsPhoneCall.State ringingCallState = getRingingCall().getState(); 837 838 return (foregroundCallState.isAlive() || 839 backgroundCallState.isAlive() || 840 ringingCallState.isAlive()); 841 } 842 843 @Override isInImsEcm()844 public boolean isInImsEcm() { 845 return mIsInImsEcm; 846 } 847 848 @Override isInEcm()849 public boolean isInEcm() { 850 return mDefaultPhone.isInEcm(); 851 } 852 853 @Override setIsInEcm(boolean isInEcm)854 public void setIsInEcm(boolean isInEcm){ 855 mIsInImsEcm = isInEcm; 856 mDefaultPhone.setIsInEcm(isInEcm); 857 } 858 notifyNewRingingConnection(Connection c)859 public void notifyNewRingingConnection(Connection c) { 860 mDefaultPhone.notifyNewRingingConnectionP(c); 861 } 862 863 @UnsupportedAppUsage notifyUnknownConnection(Connection c)864 void notifyUnknownConnection(Connection c) { 865 mDefaultPhone.notifyUnknownConnectionP(c); 866 } 867 868 @Override notifyForVideoCapabilityChanged(boolean isVideoCapable)869 public void notifyForVideoCapabilityChanged(boolean isVideoCapable) { 870 mIsVideoCapable = isVideoCapable; 871 mDefaultPhone.notifyForVideoCapabilityChanged(isVideoCapable); 872 } 873 874 @Override setRadioPower(boolean on, boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall, boolean forceApply)875 public void setRadioPower(boolean on, boolean forEmergencyCall, 876 boolean isSelectedPhoneForEmergencyCall, boolean forceApply) { 877 mDefaultPhone.setRadioPower(on, forEmergencyCall, isSelectedPhoneForEmergencyCall, 878 forceApply); 879 } 880 881 @Override startConference(String[] participantsToDial, DialArgs dialArgs)882 public Connection startConference(String[] participantsToDial, DialArgs dialArgs) 883 throws CallStateException { 884 ImsDialArgs.Builder imsDialArgsBuilder; 885 if (!(dialArgs instanceof ImsDialArgs)) { 886 imsDialArgsBuilder = ImsDialArgs.Builder.from(dialArgs); 887 } else { 888 imsDialArgsBuilder = ImsDialArgs.Builder.from((ImsDialArgs) dialArgs); 889 } 890 return mCT.startConference(participantsToDial, imsDialArgsBuilder.build()); 891 } 892 893 @Override dial(String dialString, DialArgs dialArgs)894 public Connection dial(String dialString, DialArgs dialArgs) throws CallStateException { 895 return dialInternal(dialString, dialArgs, null); 896 } 897 dialInternal(String dialString, DialArgs dialArgs, ResultReceiver wrappedCallback)898 private Connection dialInternal(String dialString, DialArgs dialArgs, 899 ResultReceiver wrappedCallback) 900 throws CallStateException { 901 902 mLastDialString = dialString; 903 904 // Need to make sure dialString gets parsed properly 905 String newDialString = PhoneNumberUtils.stripSeparators(dialString); 906 907 // handle in-call MMI first if applicable 908 if (handleInCallMmiCommands(newDialString)) { 909 return null; 910 } 911 912 ImsDialArgs.Builder imsDialArgsBuilder; 913 // Get the CLIR info if needed 914 if (!(dialArgs instanceof ImsDialArgs)) { 915 imsDialArgsBuilder = ImsDialArgs.Builder.from(dialArgs); 916 } else { 917 imsDialArgsBuilder = ImsDialArgs.Builder.from((ImsDialArgs) dialArgs); 918 } 919 imsDialArgsBuilder.setClirMode(mCT.getClirMode()); 920 921 if (mDefaultPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) { 922 return mCT.dial(dialString, imsDialArgsBuilder.build()); 923 } 924 925 // Only look at the Network portion for mmi 926 String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString); 927 ImsPhoneMmiCode mmi = 928 ImsPhoneMmiCode.newFromDialString(networkPortion, this, wrappedCallback); 929 if (DBG) logd("dialInternal: dialing w/ mmi '" + mmi + "'..."); 930 931 if (mmi == null) { 932 return mCT.dial(dialString, imsDialArgsBuilder.build()); 933 } else if (mmi.isTemporaryModeCLIR()) { 934 imsDialArgsBuilder.setClirMode(mmi.getCLIRMode()); 935 return mCT.dial(mmi.getDialingNumber(), imsDialArgsBuilder.build()); 936 } else if (!mmi.isSupportedOverImsPhone()) { 937 // If the mmi is not supported by IMS service, 938 // try to initiate dialing with default phone 939 // Note: This code is never reached; there is a bug in isSupportedOverImsPhone which 940 // causes it to return true even though the "processCode" method ultimately throws the 941 // exception. 942 logi("dialInternal: USSD not supported by IMS; fallback to CS."); 943 throw new CallStateException(CS_FALLBACK); 944 } else { 945 mPendingMMIs.add(mmi); 946 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 947 948 try { 949 mmi.processCode(); 950 } catch (CallStateException cse) { 951 if (CS_FALLBACK.equals(cse.getMessage())) { 952 logi("dialInternal: fallback to GSM required."); 953 // Make sure we remove from the list of pending MMIs since it will handover to 954 // GSM. 955 mPendingMMIs.remove(mmi); 956 throw cse; 957 } 958 } 959 960 return null; 961 } 962 } 963 964 @Override 965 public void sendDtmf(char c)966 sendDtmf(char c) { 967 if (!PhoneNumberUtils.is12Key(c)) { 968 loge("sendDtmf called with invalid character '" + c + "'"); 969 } else { 970 if (mCT.getState() == PhoneConstants.State.OFFHOOK) { 971 mCT.sendDtmf(c, null); 972 } 973 } 974 } 975 976 @Override 977 public void startDtmf(char c)978 startDtmf(char c) { 979 if (!(PhoneNumberUtils.is12Key(c) || (c >= 'A' && c <= 'D'))) { 980 loge("startDtmf called with invalid character '" + c + "'"); 981 } else { 982 mCT.startDtmf(c); 983 } 984 } 985 986 @Override 987 public void stopDtmf()988 stopDtmf() { 989 mCT.stopDtmf(); 990 } 991 notifyIncomingRing()992 public void notifyIncomingRing() { 993 if (DBG) logd("notifyIncomingRing"); 994 AsyncResult ar = new AsyncResult(null, null, null); 995 sendMessage(obtainMessage(EVENT_CALL_RING, ar)); 996 } 997 998 @Override setMute(boolean muted)999 public void setMute(boolean muted) { 1000 mCT.setMute(muted); 1001 } 1002 1003 @Override setTTYMode(int ttyMode, Message onComplete)1004 public void setTTYMode(int ttyMode, Message onComplete) { 1005 mCT.setTtyMode(ttyMode); 1006 } 1007 1008 @Override setUiTTYMode(int uiTtyMode, Message onComplete)1009 public void setUiTTYMode(int uiTtyMode, Message onComplete) { 1010 mCT.setUiTTYMode(uiTtyMode, onComplete); 1011 } 1012 1013 @Override getMute()1014 public boolean getMute() { 1015 return mCT.getMute(); 1016 } 1017 1018 @UnsupportedAppUsage 1019 @Override getState()1020 public PhoneConstants.State getState() { 1021 return mCT.getState(); 1022 } 1023 1024 @UnsupportedAppUsage isValidCommandInterfaceCFReason(int commandInterfaceCFReason)1025 private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { 1026 switch (commandInterfaceCFReason) { 1027 case CF_REASON_UNCONDITIONAL: 1028 case CF_REASON_BUSY: 1029 case CF_REASON_NO_REPLY: 1030 case CF_REASON_NOT_REACHABLE: 1031 case CF_REASON_ALL: 1032 case CF_REASON_ALL_CONDITIONAL: 1033 return true; 1034 default: 1035 return false; 1036 } 1037 } 1038 1039 @UnsupportedAppUsage isValidCommandInterfaceCFAction(int commandInterfaceCFAction)1040 private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { 1041 switch (commandInterfaceCFAction) { 1042 case CF_ACTION_DISABLE: 1043 case CF_ACTION_ENABLE: 1044 case CF_ACTION_REGISTRATION: 1045 case CF_ACTION_ERASURE: 1046 return true; 1047 default: 1048 return false; 1049 } 1050 } 1051 1052 @UnsupportedAppUsage isCfEnable(int action)1053 private boolean isCfEnable(int action) { 1054 return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); 1055 } 1056 1057 @UnsupportedAppUsage getConditionFromCFReason(int reason)1058 private int getConditionFromCFReason(int reason) { 1059 switch(reason) { 1060 case CF_REASON_UNCONDITIONAL: return ImsUtInterface.CDIV_CF_UNCONDITIONAL; 1061 case CF_REASON_BUSY: return ImsUtInterface.CDIV_CF_BUSY; 1062 case CF_REASON_NO_REPLY: return ImsUtInterface.CDIV_CF_NO_REPLY; 1063 case CF_REASON_NOT_REACHABLE: return ImsUtInterface.CDIV_CF_NOT_REACHABLE; 1064 case CF_REASON_ALL: return ImsUtInterface.CDIV_CF_ALL; 1065 case CF_REASON_ALL_CONDITIONAL: return ImsUtInterface.CDIV_CF_ALL_CONDITIONAL; 1066 default: 1067 break; 1068 } 1069 1070 return ImsUtInterface.INVALID; 1071 } 1072 getCFReasonFromCondition(int condition)1073 private int getCFReasonFromCondition(int condition) { 1074 switch(condition) { 1075 case ImsUtInterface.CDIV_CF_UNCONDITIONAL: return CF_REASON_UNCONDITIONAL; 1076 case ImsUtInterface.CDIV_CF_BUSY: return CF_REASON_BUSY; 1077 case ImsUtInterface.CDIV_CF_NO_REPLY: return CF_REASON_NO_REPLY; 1078 case ImsUtInterface.CDIV_CF_NOT_REACHABLE: return CF_REASON_NOT_REACHABLE; 1079 case ImsUtInterface.CDIV_CF_ALL: return CF_REASON_ALL; 1080 case ImsUtInterface.CDIV_CF_ALL_CONDITIONAL: return CF_REASON_ALL_CONDITIONAL; 1081 default: 1082 break; 1083 } 1084 1085 return CF_REASON_NOT_REACHABLE; 1086 } 1087 1088 @UnsupportedAppUsage getActionFromCFAction(int action)1089 private int getActionFromCFAction(int action) { 1090 switch(action) { 1091 case CF_ACTION_DISABLE: return ImsUtInterface.ACTION_DEACTIVATION; 1092 case CF_ACTION_ENABLE: return ImsUtInterface.ACTION_ACTIVATION; 1093 case CF_ACTION_ERASURE: return ImsUtInterface.ACTION_ERASURE; 1094 case CF_ACTION_REGISTRATION: return ImsUtInterface.ACTION_REGISTRATION; 1095 default: 1096 break; 1097 } 1098 1099 return ImsUtInterface.INVALID; 1100 } 1101 1102 @Override getOutgoingCallerIdDisplay(Message onComplete)1103 public void getOutgoingCallerIdDisplay(Message onComplete) { 1104 if (DBG) logd("getCLIR"); 1105 Message resp; 1106 SS ss = new SS(onComplete); 1107 resp = obtainMessage(EVENT_GET_CLIR_DONE, ss); 1108 1109 try { 1110 ImsUtInterface ut = mCT.getUtInterface(); 1111 ut.queryCLIR(resp); 1112 } catch (ImsException e) { 1113 sendErrorResponse(onComplete, e); 1114 } 1115 } 1116 1117 @Override setOutgoingCallerIdDisplay(int clirMode, Message onComplete)1118 public void setOutgoingCallerIdDisplay(int clirMode, Message onComplete) { 1119 if (DBG) logd("setCLIR action= " + clirMode); 1120 Message resp; 1121 // Packing CLIR value in the message. This will be required for 1122 // SharedPreference caching, if the message comes back as part of 1123 // a success response. 1124 SS ss = new SS(clirMode, onComplete); 1125 resp = obtainMessage(EVENT_SET_CLIR_DONE, ss); 1126 try { 1127 ImsUtInterface ut = mCT.getUtInterface(); 1128 ut.updateCLIR(clirMode, resp); 1129 } catch (ImsException e) { 1130 sendErrorResponse(onComplete, e); 1131 } 1132 } 1133 1134 @Override queryCLIP(Message onComplete)1135 public void queryCLIP(Message onComplete) { 1136 Message resp; 1137 SS ss = new SS(onComplete); 1138 resp = obtainMessage(EVENT_GET_CLIP_DONE, ss); 1139 1140 try { 1141 Rlog.d(LOG_TAG, "ut.queryCLIP"); 1142 ImsUtInterface ut = mCT.getUtInterface(); 1143 ut.queryCLIP(resp); 1144 } catch (ImsException e) { 1145 sendErrorResponse(onComplete, e); 1146 } 1147 } 1148 1149 @UnsupportedAppUsage 1150 @Override getCallForwardingOption(int commandInterfaceCFReason, Message onComplete)1151 public void getCallForwardingOption(int commandInterfaceCFReason, 1152 Message onComplete) { 1153 getCallForwardingOption(commandInterfaceCFReason, 1154 SERVICE_CLASS_VOICE, onComplete); 1155 } 1156 1157 @Override getCallForwardingOption(int commandInterfaceCFReason, int serviceClass, Message onComplete)1158 public void getCallForwardingOption(int commandInterfaceCFReason, int serviceClass, 1159 Message onComplete) { 1160 if (DBG) logd("getCallForwardingOption reason=" + commandInterfaceCFReason); 1161 if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { 1162 if (DBG) logd("requesting call forwarding query."); 1163 Message resp; 1164 SS ss = new SS(commandInterfaceCFReason, serviceClass, onComplete); 1165 resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, ss); 1166 1167 try { 1168 ImsUtInterface ut = mCT.getUtInterface(); 1169 ut.queryCallForward(getConditionFromCFReason(commandInterfaceCFReason), null, resp); 1170 } catch (ImsException e) { 1171 sendErrorResponse(onComplete, e); 1172 } 1173 } else if (onComplete != null) { 1174 sendErrorResponse(onComplete); 1175 } 1176 } 1177 1178 @Override setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int timerSeconds, Message onComplete)1179 public void setCallForwardingOption(int commandInterfaceCFAction, 1180 int commandInterfaceCFReason, 1181 String dialingNumber, 1182 int timerSeconds, 1183 Message onComplete) { 1184 setCallForwardingOption(commandInterfaceCFAction, commandInterfaceCFReason, dialingNumber, 1185 CommandsInterface.SERVICE_CLASS_VOICE, timerSeconds, onComplete); 1186 } 1187 1188 @UnsupportedAppUsage 1189 @Override setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int serviceClass, int timerSeconds, Message onComplete)1190 public void setCallForwardingOption(int commandInterfaceCFAction, 1191 int commandInterfaceCFReason, 1192 String dialingNumber, 1193 int serviceClass, 1194 int timerSeconds, 1195 Message onComplete) { 1196 if (DBG) { 1197 logd("setCallForwardingOption action=" + commandInterfaceCFAction 1198 + ", reason=" + commandInterfaceCFReason + " serviceClass=" + serviceClass); 1199 } 1200 if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && 1201 (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { 1202 Message resp; 1203 SS ss = new SS(commandInterfaceCFAction, commandInterfaceCFReason, 1204 dialingNumber, serviceClass, timerSeconds, onComplete); 1205 resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE, ss); 1206 1207 try { 1208 ImsUtInterface ut = mCT.getUtInterface(); 1209 ut.updateCallForward(getActionFromCFAction(commandInterfaceCFAction), 1210 getConditionFromCFReason(commandInterfaceCFReason), 1211 dialingNumber, 1212 serviceClass, 1213 timerSeconds, 1214 resp); 1215 } catch (ImsException e) { 1216 sendErrorResponse(onComplete, e); 1217 } 1218 } else if (onComplete != null) { 1219 sendErrorResponse(onComplete); 1220 } 1221 } 1222 1223 @UnsupportedAppUsage 1224 @Override getCallWaiting(Message onComplete)1225 public void getCallWaiting(Message onComplete) { 1226 if (DBG) logd("getCallWaiting"); 1227 Message resp; 1228 SS ss = new SS(onComplete); 1229 resp = obtainMessage(EVENT_GET_CALL_WAITING_DONE, ss); 1230 1231 try { 1232 ImsUtInterface ut = mCT.getUtInterface(); 1233 ut.queryCallWaiting(resp); 1234 } catch (ImsException e) { 1235 sendErrorResponse(onComplete, e); 1236 } 1237 } 1238 1239 @UnsupportedAppUsage 1240 @Override setCallWaiting(boolean enable, Message onComplete)1241 public void setCallWaiting(boolean enable, Message onComplete) { 1242 int serviceClass = CommandsInterface.SERVICE_CLASS_VOICE; 1243 CarrierConfigManager configManager = (CarrierConfigManager) 1244 getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); 1245 PersistableBundle b = configManager.getConfigForSubId(getSubId()); 1246 if (b != null) { 1247 serviceClass = b.getInt(CarrierConfigManager.KEY_CALL_WAITING_SERVICE_CLASS_INT, 1248 CommandsInterface.SERVICE_CLASS_VOICE); 1249 } 1250 setCallWaiting(enable, serviceClass, onComplete); 1251 } 1252 setCallWaiting(boolean enable, int serviceClass, Message onComplete)1253 public void setCallWaiting(boolean enable, int serviceClass, Message onComplete) { 1254 if (DBG) logd("setCallWaiting enable=" + enable); 1255 Message resp; 1256 SS ss = new SS(enable, serviceClass, onComplete); 1257 resp = obtainMessage(EVENT_SET_CALL_WAITING_DONE, ss); 1258 1259 try { 1260 ImsUtInterface ut = mCT.getUtInterface(); 1261 ut.updateCallWaiting(enable, serviceClass, resp); 1262 } catch (ImsException e) { 1263 sendErrorResponse(onComplete, e); 1264 } 1265 } 1266 getCBTypeFromFacility(String facility)1267 private int getCBTypeFromFacility(String facility) { 1268 if (CB_FACILITY_BAOC.equals(facility)) { 1269 return ImsUtImplBase.CALL_BARRING_ALL_OUTGOING; 1270 } else if (CB_FACILITY_BAOIC.equals(facility)) { 1271 return ImsUtImplBase.CALL_BARRING_OUTGOING_INTL; 1272 } else if (CB_FACILITY_BAOICxH.equals(facility)) { 1273 return ImsUtImplBase.CALL_BARRING_OUTGOING_INTL_EXCL_HOME; 1274 } else if (CB_FACILITY_BAIC.equals(facility)) { 1275 return ImsUtImplBase.CALL_BARRING_ALL_INCOMING; 1276 } else if (CB_FACILITY_BAICr.equals(facility)) { 1277 return ImsUtImplBase.CALL_BLOCKING_INCOMING_WHEN_ROAMING; 1278 } else if (CB_FACILITY_BA_ALL.equals(facility)) { 1279 return ImsUtImplBase.CALL_BARRING_ALL; 1280 } else if (CB_FACILITY_BA_MO.equals(facility)) { 1281 return ImsUtImplBase.CALL_BARRING_OUTGOING_ALL_SERVICES; 1282 } else if (CB_FACILITY_BA_MT.equals(facility)) { 1283 return ImsUtImplBase.CALL_BARRING_INCOMING_ALL_SERVICES; 1284 } else if (CB_FACILITY_BIC_ACR.equals(facility)) { 1285 return ImsUtImplBase.CALL_BARRING_ANONYMOUS_INCOMING; 1286 } 1287 1288 return 0; 1289 } 1290 getCallBarring(String facility, Message onComplete)1291 public void getCallBarring(String facility, Message onComplete) { 1292 getCallBarring(facility, onComplete, CommandsInterface.SERVICE_CLASS_VOICE); 1293 } 1294 getCallBarring(String facility, Message onComplete, int serviceClass)1295 public void getCallBarring(String facility, Message onComplete, int serviceClass) { 1296 getCallBarring(facility, "", onComplete, serviceClass); 1297 } 1298 1299 @Override getCallBarring(String facility, String password, Message onComplete, int serviceClass)1300 public void getCallBarring(String facility, String password, Message onComplete, 1301 int serviceClass) { 1302 if (DBG) logd("getCallBarring facility=" + facility + ", serviceClass = " + serviceClass); 1303 Message resp; 1304 SS ss = new SS(facility, password, serviceClass, onComplete); 1305 resp = obtainMessage(EVENT_GET_CALL_BARRING_DONE, ss); 1306 1307 try { 1308 ImsUtInterface ut = mCT.getUtInterface(); 1309 // password is not required with Ut interface 1310 ut.queryCallBarring(getCBTypeFromFacility(facility), resp, serviceClass); 1311 } catch (ImsException e) { 1312 sendErrorResponse(onComplete, e); 1313 } 1314 } 1315 setCallBarring(String facility, boolean lockState, String password, Message onComplete)1316 public void setCallBarring(String facility, boolean lockState, String password, 1317 Message onComplete) { 1318 setCallBarring(facility, lockState, password, onComplete, 1319 CommandsInterface.SERVICE_CLASS_VOICE); 1320 } 1321 1322 @Override setCallBarring(String facility, boolean lockState, String password, Message onComplete, int serviceClass)1323 public void setCallBarring(String facility, boolean lockState, String password, 1324 Message onComplete, int serviceClass) { 1325 if (DBG) { 1326 logd("setCallBarring facility=" + facility 1327 + ", lockState=" + lockState + ", serviceClass = " + serviceClass); 1328 } 1329 Message resp; 1330 SS ss = new SS(facility, lockState, password, serviceClass, onComplete); 1331 resp = obtainMessage(EVENT_SET_CALL_BARRING_DONE, ss); 1332 1333 int action; 1334 if (lockState) { 1335 action = CommandsInterface.CF_ACTION_ENABLE; 1336 } 1337 else { 1338 action = CommandsInterface.CF_ACTION_DISABLE; 1339 } 1340 1341 try { 1342 ImsUtInterface ut = mCT.getUtInterface(); 1343 ut.updateCallBarring(getCBTypeFromFacility(facility), action, 1344 resp, null, serviceClass, password); 1345 } catch (ImsException e) { 1346 sendErrorResponse(onComplete, e); 1347 } 1348 } 1349 1350 @Override sendUssdResponse(String ussdMessge)1351 public void sendUssdResponse(String ussdMessge) { 1352 logd("sendUssdResponse"); 1353 ImsPhoneMmiCode mmi = ImsPhoneMmiCode.newFromUssdUserInput(ussdMessge, this); 1354 mPendingMMIs.add(mmi); 1355 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 1356 mmi.sendUssd(ussdMessge); 1357 } 1358 sendUSSD(String ussdString, Message response)1359 public void sendUSSD(String ussdString, Message response) { 1360 Rlog.d(LOG_TAG, "sendUssd ussdString = " + ussdString); 1361 mLastDialString = ussdString; 1362 mCT.sendUSSD(ussdString, response); 1363 } 1364 1365 @Override cancelUSSD(Message msg)1366 public void cancelUSSD(Message msg) { 1367 mCT.cancelUSSD(msg); 1368 } 1369 1370 @UnsupportedAppUsage sendErrorResponse(Message onComplete)1371 private void sendErrorResponse(Message onComplete) { 1372 logd("sendErrorResponse"); 1373 if (onComplete != null) { 1374 AsyncResult.forMessage(onComplete, null, 1375 new CommandException(CommandException.Error.GENERIC_FAILURE)); 1376 onComplete.sendToTarget(); 1377 } 1378 } 1379 1380 @UnsupportedAppUsage 1381 @VisibleForTesting sendErrorResponse(Message onComplete, Throwable e)1382 public void sendErrorResponse(Message onComplete, Throwable e) { 1383 logd("sendErrorResponse"); 1384 if (onComplete != null) { 1385 AsyncResult.forMessage(onComplete, null, getCommandException(e)); 1386 onComplete.sendToTarget(); 1387 } 1388 } 1389 getCommandException(int code, String errorString)1390 private CommandException getCommandException(int code, String errorString) { 1391 logd("getCommandException code= " + code + ", errorString= " + errorString); 1392 CommandException.Error error = CommandException.Error.GENERIC_FAILURE; 1393 1394 switch(code) { 1395 case ImsReasonInfo.CODE_UT_NOT_SUPPORTED: 1396 error = CommandException.Error.REQUEST_NOT_SUPPORTED; 1397 break; 1398 case ImsReasonInfo.CODE_UT_CB_PASSWORD_MISMATCH: 1399 error = CommandException.Error.PASSWORD_INCORRECT; 1400 break; 1401 case ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE: 1402 error = CommandException.Error.RADIO_NOT_AVAILABLE; 1403 break; 1404 case ImsReasonInfo.CODE_FDN_BLOCKED: 1405 error = CommandException.Error.FDN_CHECK_FAILURE; 1406 break; 1407 case ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_DIAL: 1408 error = CommandException.Error.SS_MODIFIED_TO_DIAL; 1409 break; 1410 case ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_USSD: 1411 error = CommandException.Error.SS_MODIFIED_TO_USSD; 1412 break; 1413 case ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_SS: 1414 error = CommandException.Error.SS_MODIFIED_TO_SS; 1415 break; 1416 case ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO: 1417 error = CommandException.Error.SS_MODIFIED_TO_DIAL_VIDEO; 1418 break; 1419 default: 1420 break; 1421 } 1422 1423 return new CommandException(error, errorString); 1424 } 1425 getCommandException(Throwable e)1426 private CommandException getCommandException(Throwable e) { 1427 CommandException ex = null; 1428 1429 if (e instanceof ImsException) { 1430 ex = getCommandException(((ImsException)e).getCode(), e.getMessage()); 1431 } else { 1432 logd("getCommandException generic failure"); 1433 ex = new CommandException(CommandException.Error.GENERIC_FAILURE); 1434 } 1435 return ex; 1436 } 1437 1438 private void onNetworkInitiatedUssd(ImsPhoneMmiCode mmi)1439 onNetworkInitiatedUssd(ImsPhoneMmiCode mmi) { 1440 logd("onNetworkInitiatedUssd"); 1441 mMmiCompleteRegistrants.notifyRegistrants( 1442 new AsyncResult(null, mmi, null)); 1443 } 1444 1445 /* package */ onIncomingUSSD(int ussdMode, String ussdMessage)1446 void onIncomingUSSD(int ussdMode, String ussdMessage) { 1447 if (DBG) logd("onIncomingUSSD ussdMode=" + ussdMode); 1448 1449 boolean isUssdError; 1450 boolean isUssdRequest; 1451 1452 isUssdRequest 1453 = (ussdMode == CommandsInterface.USSD_MODE_REQUEST); 1454 1455 isUssdError 1456 = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY 1457 && ussdMode != CommandsInterface.USSD_MODE_REQUEST); 1458 1459 ImsPhoneMmiCode found = null; 1460 for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { 1461 if(mPendingMMIs.get(i).isPendingUSSD()) { 1462 found = mPendingMMIs.get(i); 1463 break; 1464 } 1465 } 1466 1467 if (found != null) { 1468 // Complete pending USSD 1469 if (isUssdError) { 1470 found.onUssdFinishedError(); 1471 } else { 1472 found.onUssdFinished(ussdMessage, isUssdRequest); 1473 } 1474 } else if (!isUssdError && !TextUtils.isEmpty(ussdMessage)) { 1475 // pending USSD not found 1476 // The network may initiate its own USSD request 1477 1478 // ignore everything that isnt a Notify or a Request 1479 // also, discard if there is no message to present 1480 ImsPhoneMmiCode mmi; 1481 mmi = ImsPhoneMmiCode.newNetworkInitiatedUssd(ussdMessage, 1482 isUssdRequest, 1483 this); 1484 onNetworkInitiatedUssd(mmi); 1485 } 1486 } 1487 1488 /** 1489 * Removes the given MMI from the pending list and notifies 1490 * registrants that it is complete. 1491 * @param mmi MMI that is done 1492 */ 1493 @UnsupportedAppUsage onMMIDone(ImsPhoneMmiCode mmi)1494 public void onMMIDone(ImsPhoneMmiCode mmi) { 1495 /* Only notify complete if it's on the pending list. 1496 * Otherwise, it's already been handled (eg, previously canceled). 1497 * The exception is cancellation of an incoming USSD-REQUEST, which is 1498 * not on the list. 1499 */ 1500 logd("onMMIDone: mmi=" + mmi); 1501 if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest() || mmi.isSsInfo()) { 1502 ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver(); 1503 if (receiverCallback != null) { 1504 int returnCode = (mmi.getState() == MmiCode.State.COMPLETE) ? 1505 TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE; 1506 sendUssdResponse(mmi.getDialString(), mmi.getMessage(), returnCode, 1507 receiverCallback ); 1508 } else { 1509 logv("onMMIDone: notifyRegistrants"); 1510 mMmiCompleteRegistrants.notifyRegistrants( 1511 new AsyncResult(null, mmi, null)); 1512 } 1513 } 1514 } 1515 1516 @Override getHandoverConnection()1517 public ArrayList<Connection> getHandoverConnection() { 1518 ArrayList<Connection> connList = new ArrayList<Connection>(); 1519 // Add all foreground call connections 1520 connList.addAll(getForegroundCall().getConnections()); 1521 // Add all background call connections 1522 connList.addAll(getBackgroundCall().getConnections()); 1523 // Add all background call connections 1524 connList.addAll(getRingingCall().getConnections()); 1525 if (connList.size() > 0) { 1526 return connList; 1527 } else { 1528 return null; 1529 } 1530 } 1531 1532 @Override notifySrvccState(Call.SrvccState state)1533 public void notifySrvccState(Call.SrvccState state) { 1534 mCT.notifySrvccState(state); 1535 } 1536 1537 /* package */ void initiateSilentRedial()1538 initiateSilentRedial() { 1539 String result = mLastDialString; 1540 AsyncResult ar = new AsyncResult(null, result, null); 1541 if (ar != null) { 1542 mSilentRedialRegistrants.notifyRegistrants(ar); 1543 } 1544 } 1545 1546 @Override registerForSilentRedial(Handler h, int what, Object obj)1547 public void registerForSilentRedial(Handler h, int what, Object obj) { 1548 mSilentRedialRegistrants.addUnique(h, what, obj); 1549 } 1550 1551 @Override unregisterForSilentRedial(Handler h)1552 public void unregisterForSilentRedial(Handler h) { 1553 mSilentRedialRegistrants.remove(h); 1554 } 1555 1556 @Override registerForSuppServiceNotification(Handler h, int what, Object obj)1557 public void registerForSuppServiceNotification(Handler h, int what, Object obj) { 1558 mSsnRegistrants.addUnique(h, what, obj); 1559 } 1560 1561 @Override unregisterForSuppServiceNotification(Handler h)1562 public void unregisterForSuppServiceNotification(Handler h) { 1563 mSsnRegistrants.remove(h); 1564 } 1565 1566 @Override getSubId()1567 public int getSubId() { 1568 return mDefaultPhone.getSubId(); 1569 } 1570 1571 @Override getPhoneId()1572 public int getPhoneId() { 1573 return mDefaultPhone.getPhoneId(); 1574 } 1575 getCallForwardInfo(ImsCallForwardInfo info)1576 private CallForwardInfo getCallForwardInfo(ImsCallForwardInfo info) { 1577 CallForwardInfo cfInfo = new CallForwardInfo(); 1578 cfInfo.status = info.getStatus(); 1579 cfInfo.reason = getCFReasonFromCondition(info.getCondition()); 1580 cfInfo.serviceClass = SERVICE_CLASS_VOICE; 1581 cfInfo.toa = info.getToA(); 1582 cfInfo.number = info.getNumber(); 1583 cfInfo.timeSeconds = info.getTimeSeconds(); 1584 return cfInfo; 1585 } 1586 1587 @Override getLine1Number()1588 public String getLine1Number() { 1589 return mDefaultPhone.getLine1Number(); 1590 } 1591 1592 /** 1593 * Used to Convert ImsCallForwardInfo[] to CallForwardInfo[]. 1594 * Update received call forward status to default IccRecords. 1595 */ handleCfQueryResult(ImsCallForwardInfo[] infos)1596 public CallForwardInfo[] handleCfQueryResult(ImsCallForwardInfo[] infos) { 1597 CallForwardInfo[] cfInfos = null; 1598 1599 if (infos != null && infos.length != 0) { 1600 cfInfos = new CallForwardInfo[infos.length]; 1601 } 1602 1603 if (infos == null || infos.length == 0) { 1604 // Assume the default is not active 1605 // Set unconditional CFF in SIM to false 1606 setVoiceCallForwardingFlag(getIccRecords(), 1, false, null); 1607 } else { 1608 for (int i = 0, s = infos.length; i < s; i++) { 1609 if (infos[i].getCondition() == ImsUtInterface.CDIV_CF_UNCONDITIONAL) { 1610 setVoiceCallForwardingFlag(getIccRecords(), 1, (infos[i].getStatus() == 1), 1611 infos[i].getNumber()); 1612 } 1613 cfInfos[i] = getCallForwardInfo(infos[i]); 1614 } 1615 } 1616 1617 return cfInfos; 1618 } 1619 handleCbQueryResult(ImsSsInfo[] infos)1620 private int[] handleCbQueryResult(ImsSsInfo[] infos) { 1621 int[] cbInfos = new int[1]; 1622 cbInfos[0] = SERVICE_CLASS_NONE; 1623 1624 if (infos[0].getStatus() == 1) { 1625 cbInfos[0] = SERVICE_CLASS_VOICE; 1626 } 1627 1628 return cbInfos; 1629 } 1630 handleCwQueryResult(ImsSsInfo[] infos)1631 private int[] handleCwQueryResult(ImsSsInfo[] infos) { 1632 int[] cwInfos = new int[2]; 1633 cwInfos[0] = 0; 1634 1635 if (infos[0].getStatus() == 1) { 1636 cwInfos[0] = 1; 1637 cwInfos[1] = SERVICE_CLASS_VOICE; 1638 } 1639 1640 return cwInfos; 1641 } 1642 1643 private void sendResponse(Message onComplete, Object result, Throwable e)1644 sendResponse(Message onComplete, Object result, Throwable e) { 1645 if (onComplete != null) { 1646 CommandException ex = null; 1647 if (e != null) { 1648 ex = getCommandException(e); 1649 } 1650 AsyncResult.forMessage(onComplete, result, ex); 1651 onComplete.sendToTarget(); 1652 } 1653 } 1654 updateDataServiceState()1655 private void updateDataServiceState() { 1656 if (mSS != null && mDefaultPhone.getServiceStateTracker() != null 1657 && mDefaultPhone.getServiceStateTracker().mSS != null) { 1658 ServiceState ss = mDefaultPhone.getServiceStateTracker().mSS; 1659 mSS.setDataRegState(ss.getDataRegistrationState()); 1660 List<NetworkRegistrationInfo> nriList = 1661 ss.getNetworkRegistrationInfoListForDomain(NetworkRegistrationInfo.DOMAIN_PS); 1662 for (NetworkRegistrationInfo nri : nriList) { 1663 mSS.addNetworkRegistrationInfo(nri); 1664 } 1665 1666 mSS.setIwlanPreferred(ss.isIwlanPreferred()); 1667 logd("updateDataServiceState: defSs = " + ss + " imsSs = " + mSS); 1668 } 1669 } 1670 isCsRetryException(Throwable e)1671 boolean isCsRetryException(Throwable e) { 1672 if ((e != null) && (e instanceof ImsException) 1673 && (((ImsException)e).getCode() 1674 == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED)) { 1675 return true; 1676 } 1677 return false; 1678 } 1679 setCsfbBundle(boolean isCsRetry)1680 private Bundle setCsfbBundle(boolean isCsRetry) { 1681 Bundle b = new Bundle(); 1682 b.putBoolean(CS_FALLBACK_SS, isCsRetry); 1683 return b; 1684 } 1685 sendResponseOrRetryOnCsfbSs(SS ss, int what, Throwable e, Object obj)1686 private void sendResponseOrRetryOnCsfbSs(SS ss, int what, Throwable e, Object obj) { 1687 if (!isCsRetryException(e)) { 1688 sendResponse(ss.mOnComplete, obj, e); 1689 return; 1690 } 1691 1692 Rlog.d(LOG_TAG, "Try CSFB: " + what); 1693 ss.mOnComplete.setData(setCsfbBundle(true)); 1694 1695 switch (what) { 1696 case EVENT_GET_CALL_FORWARD_DONE: 1697 mDefaultPhone.getCallForwardingOption(ss.mCfReason, 1698 ss.mServiceClass, 1699 ss.mOnComplete); 1700 break; 1701 case EVENT_SET_CALL_FORWARD_DONE: 1702 mDefaultPhone.setCallForwardingOption(ss.mCfAction, 1703 ss.mCfReason, 1704 ss.mDialingNumber, 1705 ss.mServiceClass, 1706 ss.mTimerSeconds, 1707 ss.mOnComplete); 1708 break; 1709 case EVENT_GET_CALL_BARRING_DONE: 1710 mDefaultPhone.getCallBarring(ss.mFacility, 1711 ss.mPassword, 1712 ss.mOnComplete, 1713 ss.mServiceClass); 1714 break; 1715 case EVENT_SET_CALL_BARRING_DONE: 1716 mDefaultPhone.setCallBarring(ss.mFacility, 1717 ss.mLockState, 1718 ss.mPassword, 1719 ss.mOnComplete, 1720 ss.mServiceClass); 1721 break; 1722 case EVENT_GET_CALL_WAITING_DONE: 1723 mDefaultPhone.getCallWaiting(ss.mOnComplete); 1724 break; 1725 case EVENT_SET_CALL_WAITING_DONE: 1726 mDefaultPhone.setCallWaiting(ss.mEnable, 1727 ss.mServiceClass, 1728 ss.mOnComplete); 1729 break; 1730 case EVENT_GET_CLIR_DONE: 1731 mDefaultPhone.getOutgoingCallerIdDisplay(ss.mOnComplete); 1732 break; 1733 case EVENT_SET_CLIR_DONE: 1734 mDefaultPhone.setOutgoingCallerIdDisplay(ss.mClirMode, ss.mOnComplete); 1735 break; 1736 case EVENT_GET_CLIP_DONE: 1737 mDefaultPhone.queryCLIP(ss.mOnComplete); 1738 break; 1739 default: 1740 break; 1741 } 1742 } 1743 1744 @Override handleMessage(Message msg)1745 public void handleMessage(Message msg) { 1746 AsyncResult ar = (AsyncResult) msg.obj; 1747 Message onComplete; 1748 SS ss = null; 1749 if (ar.userObj instanceof SS) { 1750 ss = (SS) ar.userObj; 1751 } 1752 1753 if (DBG) logd("handleMessage what=" + msg.what); 1754 switch (msg.what) { 1755 case EVENT_SET_CALL_FORWARD_DONE: 1756 if (ar.exception == null && ss != null && 1757 (ss.mCfReason == CF_REASON_UNCONDITIONAL)) { 1758 setVoiceCallForwardingFlag(getIccRecords(), 1, isCfEnable(ss.mCfAction), 1759 ss.mDialingNumber); 1760 } 1761 if (ss != null) { 1762 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, null); 1763 } 1764 break; 1765 1766 case EVENT_GET_CALL_FORWARD_DONE: 1767 CallForwardInfo[] cfInfos = null; 1768 if (ar.exception == null) { 1769 cfInfos = handleCfQueryResult((ImsCallForwardInfo[])ar.result); 1770 } 1771 if (ss != null) { 1772 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, cfInfos); 1773 } 1774 break; 1775 1776 case EVENT_GET_CALL_BARRING_DONE: 1777 case EVENT_GET_CALL_WAITING_DONE: 1778 int[] ssInfos = null; 1779 if (ar.exception == null) { 1780 if (msg.what == EVENT_GET_CALL_BARRING_DONE) { 1781 ssInfos = handleCbQueryResult((ImsSsInfo[])ar.result); 1782 } else if (msg.what == EVENT_GET_CALL_WAITING_DONE) { 1783 ssInfos = handleCwQueryResult((ImsSsInfo[])ar.result); 1784 } 1785 } 1786 if (ss != null) { 1787 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, ssInfos); 1788 } 1789 break; 1790 1791 case EVENT_GET_CLIR_DONE: 1792 ImsSsInfo ssInfo = (ImsSsInfo) ar.result; 1793 int[] clirInfo = null; 1794 if (ssInfo != null) { 1795 // Unfortunately callers still use the old {n,m} format of ImsSsInfo, so return 1796 // that for compatibility 1797 clirInfo = ssInfo.getCompatArray(ImsSsData.SS_CLIR); 1798 } 1799 if (ss != null) { 1800 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, clirInfo); 1801 } 1802 break; 1803 1804 case EVENT_GET_CLIP_DONE: 1805 Bundle ssInfoResp = null; 1806 if (ar.exception == null) { 1807 ssInfoResp = (Bundle) ar.result; 1808 } 1809 if (ss != null) { 1810 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, ssInfoResp); 1811 } 1812 break; 1813 1814 case EVENT_SET_CLIR_DONE: 1815 if (ar.exception == null) { 1816 if (ss != null) { 1817 saveClirSetting(ss.mClirMode); 1818 } 1819 } 1820 // (Intentional fallthrough) 1821 case EVENT_SET_CALL_BARRING_DONE: 1822 case EVENT_SET_CALL_WAITING_DONE: 1823 if (ss != null) { 1824 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, null); 1825 } 1826 break; 1827 1828 case EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED: 1829 if (DBG) logd("EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED"); 1830 updateDataServiceState(); 1831 break; 1832 1833 case EVENT_SERVICE_STATE_CHANGED: 1834 if (VDBG) logd("EVENT_SERVICE_STATE_CHANGED"); 1835 ar = (AsyncResult) msg.obj; 1836 ServiceState newServiceState = (ServiceState) ar.result; 1837 updateRoamingState(newServiceState); 1838 break; 1839 case EVENT_VOICE_CALL_ENDED: 1840 if (DBG) logd("Voice call ended. Handle pending updateRoamingState."); 1841 mCT.unregisterForVoiceCallEnded(this); 1842 // Get the current unmodified ServiceState from the tracker, as it has more info 1843 // about the cell roaming state. 1844 ServiceStateTracker sst = getDefaultPhone().getServiceStateTracker(); 1845 if (sst != null) { 1846 updateRoamingState(sst.mSS); 1847 } 1848 break; 1849 case EVENT_INITIATE_VOLTE_SILENT_REDIAL: { 1850 if (VDBG) logd("EVENT_INITIATE_VOLTE_SILENT_REDIAL"); 1851 ar = (AsyncResult) msg.obj; 1852 if (ar.exception == null && ar.result != null) { 1853 SilentRedialParam result = (SilentRedialParam) ar.result; 1854 String dialString = result.dialString; 1855 int causeCode = result.causeCode; 1856 DialArgs dialArgs = result.dialArgs; 1857 if (VDBG) logd("dialString=" + dialString + " causeCode=" + causeCode); 1858 1859 try { 1860 Connection cn = dial(dialString, 1861 updateDialArgsForVolteSilentRedial(dialArgs, causeCode)); 1862 Rlog.d(LOG_TAG, "Notify volte redial connection changed cn: " + cn); 1863 if (mDefaultPhone != null) { 1864 // don't care it is null or not. 1865 mDefaultPhone.notifyRedialConnectionChanged(cn); 1866 } 1867 } catch (CallStateException e) { 1868 Rlog.e(LOG_TAG, "volte silent redial failed: " + e); 1869 if (mDefaultPhone != null) { 1870 mDefaultPhone.notifyRedialConnectionChanged(null); 1871 } 1872 } 1873 } else { 1874 if (VDBG) logd("EVENT_INITIATE_VOLTE_SILENT_REDIAL" + 1875 " has exception or empty result"); 1876 } 1877 break; 1878 } 1879 1880 default: 1881 super.handleMessage(msg); 1882 break; 1883 } 1884 } 1885 1886 /** 1887 * Listen to the IMS ECBM state change 1888 */ 1889 private ImsEcbmStateListener mImsEcbmStateListener = 1890 new ImsEcbmStateListener() { 1891 @Override 1892 public void onECBMEntered() { 1893 if (DBG) logd("onECBMEntered"); 1894 handleEnterEmergencyCallbackMode(); 1895 } 1896 1897 @Override 1898 public void onECBMExited() { 1899 if (DBG) logd("onECBMExited"); 1900 handleExitEmergencyCallbackMode(); 1901 } 1902 }; 1903 1904 @VisibleForTesting getImsEcbmStateListener()1905 public ImsEcbmStateListener getImsEcbmStateListener() { 1906 return mImsEcbmStateListener; 1907 } 1908 1909 @Override isInEmergencyCall()1910 public boolean isInEmergencyCall() { 1911 return mCT.isInEmergencyCall(); 1912 } 1913 sendEmergencyCallbackModeChange()1914 private void sendEmergencyCallbackModeChange() { 1915 // Send an Intent 1916 Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 1917 intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, isInEcm()); 1918 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId()); 1919 ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL); 1920 if (DBG) logd("sendEmergencyCallbackModeChange: isInEcm=" + isInEcm()); 1921 } 1922 1923 @Override exitEmergencyCallbackMode()1924 public void exitEmergencyCallbackMode() { 1925 if (mWakeLock.isHeld()) { 1926 mWakeLock.release(); 1927 } 1928 if (DBG) logd("exitEmergencyCallbackMode()"); 1929 1930 // Send a message which will invoke handleExitEmergencyCallbackMode 1931 ImsEcbm ecbm; 1932 try { 1933 ecbm = mCT.getEcbmInterface(); 1934 ecbm.exitEmergencyCallbackMode(); 1935 } catch (ImsException e) { 1936 e.printStackTrace(); 1937 } 1938 } 1939 1940 @UnsupportedAppUsage handleEnterEmergencyCallbackMode()1941 private void handleEnterEmergencyCallbackMode() { 1942 if (DBG) logd("handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= " + isInEcm()); 1943 // if phone is not in Ecm mode, and it's changed to Ecm mode 1944 if (!isInEcm()) { 1945 setIsInEcm(true); 1946 // notify change 1947 sendEmergencyCallbackModeChange(); 1948 ((GsmCdmaPhone) mDefaultPhone).notifyEmergencyCallRegistrants(true); 1949 1950 // Post this runnable so we will automatically exit 1951 // if no one invokes exitEmergencyCallbackMode() directly. 1952 long delayInMillis = TelephonyProperties.ecm_exit_timer() 1953 .orElse(DEFAULT_ECM_EXIT_TIMER_VALUE); 1954 postDelayed(mExitEcmRunnable, delayInMillis); 1955 // We don't want to go to sleep while in Ecm 1956 mWakeLock.acquire(); 1957 } 1958 } 1959 1960 @UnsupportedAppUsage 1961 @Override handleExitEmergencyCallbackMode()1962 protected void handleExitEmergencyCallbackMode() { 1963 if (DBG) logd("handleExitEmergencyCallbackMode: mIsPhoneInEcmState = " + isInEcm()); 1964 1965 if (isInEcm()) { 1966 setIsInEcm(false); 1967 } 1968 1969 // Remove pending exit Ecm runnable, if any 1970 removeCallbacks(mExitEcmRunnable); 1971 1972 if (mEcmExitRespRegistrant != null) { 1973 mEcmExitRespRegistrant.notifyResult(Boolean.TRUE); 1974 } 1975 1976 // release wakeLock 1977 if (mWakeLock.isHeld()) { 1978 mWakeLock.release(); 1979 } 1980 1981 // send an Intent 1982 sendEmergencyCallbackModeChange(); 1983 ((GsmCdmaPhone) mDefaultPhone).notifyEmergencyCallRegistrants(false); 1984 } 1985 1986 /** 1987 * Handle to cancel or restart Ecm timer in emergency call back mode if action is 1988 * CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled; otherwise, restart 1989 * Ecm timer and notify apps the timer is restarted. 1990 */ handleTimerInEmergencyCallbackMode(int action)1991 void handleTimerInEmergencyCallbackMode(int action) { 1992 switch (action) { 1993 case CANCEL_ECM_TIMER: 1994 removeCallbacks(mExitEcmRunnable); 1995 ((GsmCdmaPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.TRUE); 1996 setEcmCanceledForEmergency(true /*isCanceled*/); 1997 break; 1998 case RESTART_ECM_TIMER: 1999 long delayInMillis = TelephonyProperties.ecm_exit_timer() 2000 .orElse(DEFAULT_ECM_EXIT_TIMER_VALUE); 2001 postDelayed(mExitEcmRunnable, delayInMillis); 2002 ((GsmCdmaPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.FALSE); 2003 setEcmCanceledForEmergency(false /*isCanceled*/); 2004 break; 2005 default: 2006 loge("handleTimerInEmergencyCallbackMode, unsupported action " + action); 2007 } 2008 } 2009 2010 @UnsupportedAppUsage 2011 @Override setOnEcbModeExitResponse(Handler h, int what, Object obj)2012 public void setOnEcbModeExitResponse(Handler h, int what, Object obj) { 2013 mEcmExitRespRegistrant = new Registrant(h, what, obj); 2014 } 2015 2016 @Override unsetOnEcbModeExitResponse(Handler h)2017 public void unsetOnEcbModeExitResponse(Handler h) { 2018 mEcmExitRespRegistrant.clear(); 2019 } 2020 onFeatureCapabilityChanged()2021 public void onFeatureCapabilityChanged() { 2022 mDefaultPhone.getServiceStateTracker().onImsCapabilityChanged(); 2023 } 2024 2025 @Override isImsCapabilityAvailable(int capability, int regTech)2026 public boolean isImsCapabilityAvailable(int capability, int regTech) throws ImsException { 2027 return mCT.isImsCapabilityAvailable(capability, regTech); 2028 } 2029 2030 @UnsupportedAppUsage 2031 @Override isVolteEnabled()2032 public boolean isVolteEnabled() { 2033 return mCT.isVolteEnabled(); 2034 } 2035 2036 @Override isWifiCallingEnabled()2037 public boolean isWifiCallingEnabled() { 2038 return mCT.isVowifiEnabled(); 2039 } 2040 2041 @Override isVideoEnabled()2042 public boolean isVideoEnabled() { 2043 return mCT.isVideoCallEnabled(); 2044 } 2045 2046 @Override getImsRegistrationTech()2047 public int getImsRegistrationTech() { 2048 return mCT.getImsRegistrationTech(); 2049 } 2050 2051 @Override getImsRegistrationTech(Consumer<Integer> callback)2052 public void getImsRegistrationTech(Consumer<Integer> callback) { 2053 mCT.getImsRegistrationTech(callback); 2054 } 2055 2056 @Override getImsRegistrationState(Consumer<Integer> callback)2057 public void getImsRegistrationState(Consumer<Integer> callback) { 2058 callback.accept(mImsMmTelRegistrationHelper.getImsRegistrationState()); 2059 } 2060 2061 @Override getDefaultPhone()2062 public Phone getDefaultPhone() { 2063 return mDefaultPhone; 2064 } 2065 2066 @Override isImsRegistered()2067 public boolean isImsRegistered() { 2068 return mImsMmTelRegistrationHelper.isImsRegistered(); 2069 } 2070 2071 // Not used, but not removed due to UnsupportedAppUsage tag. 2072 @UnsupportedAppUsage setImsRegistered(boolean isRegistered)2073 public void setImsRegistered(boolean isRegistered) { 2074 mImsMmTelRegistrationHelper.updateRegistrationState( 2075 isRegistered ? RegistrationManager.REGISTRATION_STATE_REGISTERED : 2076 RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED); 2077 } 2078 setImsRegistrationState(@egistrationManager.ImsRegistrationState int value)2079 public void setImsRegistrationState(@RegistrationManager.ImsRegistrationState int value) { 2080 if (DBG) logd("setImsRegistrationState: " + value); 2081 mImsMmTelRegistrationHelper.updateRegistrationState(value); 2082 } 2083 2084 @Override callEndCleanupHandOverCallIfAny()2085 public void callEndCleanupHandOverCallIfAny() { 2086 mCT.callEndCleanupHandOverCallIfAny(); 2087 } 2088 2089 private BroadcastReceiver mResultReceiver = new BroadcastReceiver() { 2090 @Override 2091 public void onReceive(Context context, Intent intent) { 2092 // Add notification only if alert was not shown by WfcSettings 2093 if (getResultCode() == Activity.RESULT_OK) { 2094 // Default result code (as passed to sendOrderedBroadcast) 2095 // means that intent was not received by WfcSettings. 2096 2097 CharSequence title = 2098 intent.getCharSequenceExtra(EXTRA_WFC_REGISTRATION_FAILURE_TITLE); 2099 CharSequence messageAlert = 2100 intent.getCharSequenceExtra(EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE); 2101 CharSequence messageNotification = 2102 intent.getCharSequenceExtra(EXTRA_KEY_NOTIFICATION_MESSAGE); 2103 2104 Intent resultIntent = new Intent(Intent.ACTION_MAIN); 2105 resultIntent.setClassName("com.android.settings", 2106 "com.android.settings.Settings$WifiCallingSettingsActivity"); 2107 resultIntent.putExtra(EXTRA_KEY_ALERT_SHOW, true); 2108 resultIntent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_TITLE, title); 2109 resultIntent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE, messageAlert); 2110 PendingIntent resultPendingIntent = 2111 PendingIntent.getActivity( 2112 mContext, 2113 0, 2114 resultIntent, 2115 PendingIntent.FLAG_UPDATE_CURRENT 2116 ); 2117 2118 final Notification notification = new Notification.Builder(mContext) 2119 .setSmallIcon(android.R.drawable.stat_sys_warning) 2120 .setContentTitle(title) 2121 .setContentText(messageNotification) 2122 .setAutoCancel(true) 2123 .setContentIntent(resultPendingIntent) 2124 .setStyle(new Notification.BigTextStyle() 2125 .bigText(messageNotification)) 2126 .setChannelId(NotificationChannelController.CHANNEL_ID_WFC) 2127 .build(); 2128 final String notificationTag = "wifi_calling"; 2129 final int notificationId = 1; 2130 2131 NotificationManager notificationManager = 2132 (NotificationManager) mContext.getSystemService( 2133 Context.NOTIFICATION_SERVICE); 2134 notificationManager.notify(notificationTag, notificationId, 2135 notification); 2136 } 2137 } 2138 }; 2139 2140 /** 2141 * Show notification in case of some error codes. 2142 */ processDisconnectReason(ImsReasonInfo imsReasonInfo)2143 public void processDisconnectReason(ImsReasonInfo imsReasonInfo) { 2144 if (imsReasonInfo.mCode == imsReasonInfo.CODE_REGISTRATION_ERROR 2145 && imsReasonInfo.mExtraMessage != null) { 2146 // Suppress WFC Registration notifications if WFC is not enabled by the user. 2147 if (ImsManager.getInstance(mContext, mPhoneId).isWfcEnabledByUser()) { 2148 processWfcDisconnectForNotification(imsReasonInfo); 2149 } 2150 } 2151 } 2152 2153 // Processes an IMS disconnect cause for possible WFC registration errors and optionally 2154 // disable WFC. processWfcDisconnectForNotification(ImsReasonInfo imsReasonInfo)2155 private void processWfcDisconnectForNotification(ImsReasonInfo imsReasonInfo) { 2156 CarrierConfigManager configManager = 2157 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 2158 if (configManager == null) { 2159 loge("processDisconnectReason: CarrierConfigManager is not ready"); 2160 return; 2161 } 2162 PersistableBundle pb = configManager.getConfigForSubId(getSubId()); 2163 if (pb == null) { 2164 loge("processDisconnectReason: no config for subId " + getSubId()); 2165 return; 2166 } 2167 final String[] wfcOperatorErrorCodes = 2168 pb.getStringArray( 2169 CarrierConfigManager.KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY); 2170 if (wfcOperatorErrorCodes == null) { 2171 // no operator-specific error codes 2172 return; 2173 } 2174 2175 final String[] wfcOperatorErrorAlertMessages = 2176 mContext.getResources().getStringArray( 2177 com.android.internal.R.array.wfcOperatorErrorAlertMessages); 2178 final String[] wfcOperatorErrorNotificationMessages = 2179 mContext.getResources().getStringArray( 2180 com.android.internal.R.array.wfcOperatorErrorNotificationMessages); 2181 2182 for (int i = 0; i < wfcOperatorErrorCodes.length; i++) { 2183 String[] codes = wfcOperatorErrorCodes[i].split("\\|"); 2184 if (codes.length != 2) { 2185 loge("Invalid carrier config: " + wfcOperatorErrorCodes[i]); 2186 continue; 2187 } 2188 2189 // Match error code. 2190 if (!imsReasonInfo.mExtraMessage.startsWith( 2191 codes[0])) { 2192 continue; 2193 } 2194 // If there is no delimiter at the end of error code string 2195 // then we need to verify that we are not matching partial code. 2196 // EXAMPLE: "REG9" must not match "REG99". 2197 // NOTE: Error code must not be empty. 2198 int codeStringLength = codes[0].length(); 2199 char lastChar = codes[0].charAt(codeStringLength - 1); 2200 if (Character.isLetterOrDigit(lastChar)) { 2201 if (imsReasonInfo.mExtraMessage.length() > codeStringLength) { 2202 char nextChar = imsReasonInfo.mExtraMessage.charAt(codeStringLength); 2203 if (Character.isLetterOrDigit(nextChar)) { 2204 continue; 2205 } 2206 } 2207 } 2208 2209 final CharSequence title = mContext.getText( 2210 com.android.internal.R.string.wfcRegErrorTitle); 2211 2212 int idx = Integer.parseInt(codes[1]); 2213 if (idx < 0 2214 || idx >= wfcOperatorErrorAlertMessages.length 2215 || idx >= wfcOperatorErrorNotificationMessages.length) { 2216 loge("Invalid index: " + wfcOperatorErrorCodes[i]); 2217 continue; 2218 } 2219 String messageAlert = imsReasonInfo.mExtraMessage; 2220 String messageNotification = imsReasonInfo.mExtraMessage; 2221 if (!wfcOperatorErrorAlertMessages[idx].isEmpty()) { 2222 messageAlert = String.format( 2223 wfcOperatorErrorAlertMessages[idx], 2224 imsReasonInfo.mExtraMessage); // Fill IMS error code into alert message 2225 } 2226 if (!wfcOperatorErrorNotificationMessages[idx].isEmpty()) { 2227 messageNotification = String.format( 2228 wfcOperatorErrorNotificationMessages[idx], 2229 imsReasonInfo.mExtraMessage); // Fill IMS error code into notification 2230 } 2231 2232 // If WfcSettings are active then alert will be shown 2233 // otherwise notification will be added. 2234 Intent intent = new Intent( 2235 android.telephony.ims.ImsManager.ACTION_WFC_IMS_REGISTRATION_ERROR); 2236 intent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_TITLE, title); 2237 intent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE, messageAlert); 2238 intent.putExtra(EXTRA_KEY_NOTIFICATION_MESSAGE, messageNotification); 2239 mContext.sendOrderedBroadcast(intent, null, mResultReceiver, 2240 null, Activity.RESULT_OK, null, null); 2241 2242 // We can only match a single error code 2243 // so should break the loop after a successful match. 2244 break; 2245 } 2246 } 2247 2248 @UnsupportedAppUsage 2249 @Override isUtEnabled()2250 public boolean isUtEnabled() { 2251 return mCT.isUtEnabled(); 2252 } 2253 2254 @Override sendEmergencyCallStateChange(boolean callActive)2255 public void sendEmergencyCallStateChange(boolean callActive) { 2256 mDefaultPhone.sendEmergencyCallStateChange(callActive); 2257 } 2258 2259 @Override setBroadcastEmergencyCallStateChanges(boolean broadcast)2260 public void setBroadcastEmergencyCallStateChanges(boolean broadcast) { 2261 mDefaultPhone.setBroadcastEmergencyCallStateChanges(broadcast); 2262 } 2263 2264 @VisibleForTesting getWakeLock()2265 public PowerManager.WakeLock getWakeLock() { 2266 return mWakeLock; 2267 } 2268 2269 /** 2270 * Update roaming state and WFC mode in the following situations: 2271 * 1) voice is in service. 2272 * 2) data is in service and it is not IWLAN (if in legacy mode). 2273 * @param ss non-null ServiceState 2274 */ updateRoamingState(ServiceState ss)2275 private void updateRoamingState(ServiceState ss) { 2276 if (ss == null) { 2277 loge("updateRoamingState: null ServiceState!"); 2278 return; 2279 } 2280 boolean newRoamingState = ss.getRoaming(); 2281 // Do not recalculate if there is no change to state. 2282 if (mRoaming == newRoamingState) { 2283 return; 2284 } 2285 boolean isInService = (ss.getState() == ServiceState.STATE_IN_SERVICE 2286 || ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE); 2287 // If we are not IN_SERVICE for voice or data, ignore change roaming state, as we always 2288 // move to home in this case. 2289 if (!isInService) { 2290 logi("updateRoamingState: we are OUT_OF_SERVICE, ignoring roaming change."); 2291 return; 2292 } 2293 // We ignore roaming changes when moving to IWLAN because it always sets the roaming 2294 // mode to home and masks the actual cellular roaming status if voice is not registered. If 2295 // we just moved to IWLAN because WFC roaming mode is IWLAN preferred and WFC home mode is 2296 // cell preferred, we can get into a condition where the modem keeps bouncing between 2297 // IWLAN->cell->IWLAN->cell... 2298 if (isCsNotInServiceAndPsWwanReportingWlan(ss)) { 2299 logi("updateRoamingState: IWLAN masking roaming, ignore roaming change."); 2300 return; 2301 } 2302 if (mCT.getState() == PhoneConstants.State.IDLE) { 2303 if (DBG) logd("updateRoamingState now: " + newRoamingState); 2304 mRoaming = newRoamingState; 2305 CarrierConfigManager configManager = (CarrierConfigManager) 2306 getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); 2307 // Don't set wfc mode if carrierconfig has not loaded. It will be set by GsmCdmaPhone 2308 // when receives ACTION_CARRIER_CONFIG_CHANGED broadcast. 2309 if (configManager != null && CarrierConfigManager.isConfigForIdentifiedCarrier( 2310 configManager.getConfigForSubId(getSubId()))) { 2311 ImsManager imsManager = ImsManager.getInstance(mContext, mPhoneId); 2312 imsManager.setWfcMode(imsManager.getWfcMode(newRoamingState), newRoamingState); 2313 } 2314 } else { 2315 if (DBG) logd("updateRoamingState postponed: " + newRoamingState); 2316 mCT.registerForVoiceCallEnded(this, EVENT_VOICE_CALL_ENDED, null); 2317 } 2318 } 2319 2320 /** 2321 * In legacy mode, data registration will report IWLAN when we are using WLAN for data, 2322 * effectively masking the true roaming state of the device if voice is not registered. 2323 * 2324 * @return true if we are reporting not in service for CS domain over WWAN transport and WLAN 2325 * for PS domain over WWAN transport. 2326 */ isCsNotInServiceAndPsWwanReportingWlan(ServiceState ss)2327 private boolean isCsNotInServiceAndPsWwanReportingWlan(ServiceState ss) { 2328 TransportManager tm = mDefaultPhone.getTransportManager(); 2329 // We can not get into this condition if we are in AP-Assisted mode. 2330 if (tm == null || !tm.isInLegacyMode()) { 2331 return false; 2332 } 2333 NetworkRegistrationInfo csInfo = ss.getNetworkRegistrationInfo( 2334 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 2335 NetworkRegistrationInfo psInfo = ss.getNetworkRegistrationInfo( 2336 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 2337 // We will return roaming state correctly if the CS domain is in service because 2338 // ss.getRoaming() returns isVoiceRoaming||isDataRoaming result and isDataRoaming==false 2339 // when the modem reports IWLAN RAT. 2340 return psInfo != null && csInfo != null && !csInfo.isInService() 2341 && psInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN; 2342 } 2343 getImsMmTelRegistrationCallback()2344 public RegistrationManager.RegistrationCallback getImsMmTelRegistrationCallback() { 2345 return mImsMmTelRegistrationHelper.getCallback(); 2346 } 2347 2348 /** 2349 * Reset the IMS registration state. 2350 */ resetImsRegistrationState()2351 public void resetImsRegistrationState() { 2352 if (DBG) logd("resetImsRegistrationState"); 2353 mImsMmTelRegistrationHelper.reset(); 2354 } 2355 2356 private ImsRegistrationCallbackHelper.ImsRegistrationUpdate mMmTelRegistrationUpdate = new 2357 ImsRegistrationCallbackHelper.ImsRegistrationUpdate() { 2358 @Override 2359 public void handleImsRegistered(int imsRadioTech) { 2360 if (DBG) { 2361 logd("onImsMmTelConnected imsRadioTech=" 2362 + AccessNetworkConstants.transportTypeToString(imsRadioTech)); 2363 } 2364 mRegLocalLog.log("onImsMmTelConnected imsRadioTech=" 2365 + AccessNetworkConstants.transportTypeToString(imsRadioTech)); 2366 setServiceState(ServiceState.STATE_IN_SERVICE); 2367 mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.CONNECTED, null); 2368 } 2369 2370 @Override 2371 public void handleImsRegistering(int imsRadioTech) { 2372 if (DBG) { 2373 logd("onImsMmTelProgressing imsRadioTech=" 2374 + AccessNetworkConstants.transportTypeToString(imsRadioTech)); 2375 } 2376 mRegLocalLog.log("onImsMmTelProgressing imsRadioTech=" 2377 + AccessNetworkConstants.transportTypeToString(imsRadioTech)); 2378 setServiceState(ServiceState.STATE_OUT_OF_SERVICE); 2379 mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.PROGRESSING, 2380 null); 2381 } 2382 2383 @Override 2384 public void handleImsUnregistered(ImsReasonInfo imsReasonInfo) { 2385 if (DBG) logd("onImsMmTelDisconnected imsReasonInfo=" + imsReasonInfo); 2386 mRegLocalLog.log("onImsMmTelDisconnected imsRadioTech=" + imsReasonInfo); 2387 setServiceState(ServiceState.STATE_OUT_OF_SERVICE); 2388 processDisconnectReason(imsReasonInfo); 2389 mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.DISCONNECTED, 2390 imsReasonInfo); 2391 } 2392 2393 @Override 2394 public void handleImsSubscriberAssociatedUriChanged(Uri[] uris) { 2395 if (DBG) logd("handleImsSubscriberAssociatedUriChanged"); 2396 setCurrentSubscriberUris(uris); 2397 } 2398 }; 2399 getIccRecords()2400 public IccRecords getIccRecords() { 2401 return mDefaultPhone.getIccRecords(); 2402 } 2403 updateDialArgsForVolteSilentRedial(DialArgs dialArgs, int causeCode)2404 public DialArgs updateDialArgsForVolteSilentRedial(DialArgs dialArgs, int causeCode) { 2405 if (dialArgs != null) { 2406 ImsPhone.ImsDialArgs.Builder imsDialArgsBuilder; 2407 if (dialArgs instanceof ImsPhone.ImsDialArgs) { 2408 imsDialArgsBuilder = ImsPhone.ImsDialArgs.Builder 2409 .from((ImsPhone.ImsDialArgs) dialArgs); 2410 } else { 2411 imsDialArgsBuilder = ImsPhone.ImsDialArgs.Builder 2412 .from(dialArgs); 2413 } 2414 Bundle extras = new Bundle(dialArgs.intentExtras); 2415 if (causeCode == CallFailCause.EMC_REDIAL_ON_VOWIFI && isWifiCallingEnabled()) { 2416 extras.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE, 2417 String.valueOf(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)); 2418 logd("trigger VoWifi emergency call"); 2419 imsDialArgsBuilder.setIntentExtras(extras); 2420 } else if (causeCode == CallFailCause.EMC_REDIAL_ON_IMS) { 2421 logd("trigger VoLte emergency call"); 2422 } 2423 return imsDialArgsBuilder.build(); 2424 } 2425 return new DialArgs.Builder<>().build(); 2426 } 2427 2428 @Override getVoiceCallSessionStats()2429 public VoiceCallSessionStats getVoiceCallSessionStats() { 2430 return mDefaultPhone.getVoiceCallSessionStats(); 2431 } 2432 hasAliveCall()2433 public boolean hasAliveCall() { 2434 return (getForegroundCall().getState() != Call.State.IDLE || 2435 getBackgroundCall().getState() != Call.State.IDLE); 2436 } 2437 2438 @Override dump(FileDescriptor fd, PrintWriter printWriter, String[] args)2439 public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { 2440 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 2441 pw.println("ImsPhone extends:"); 2442 super.dump(fd, pw, args); 2443 pw.flush(); 2444 2445 pw.println("ImsPhone:"); 2446 pw.println(" mDefaultPhone = " + mDefaultPhone); 2447 pw.println(" mPendingMMIs = " + mPendingMMIs); 2448 pw.println(" mPostDialHandler = " + mPostDialHandler); 2449 pw.println(" mSS = " + mSS); 2450 pw.println(" mWakeLock = " + mWakeLock); 2451 pw.println(" mIsPhoneInEcmState = " + isInEcm()); 2452 pw.println(" mEcmExitRespRegistrant = " + mEcmExitRespRegistrant); 2453 pw.println(" mSilentRedialRegistrants = " + mSilentRedialRegistrants); 2454 pw.println(" mImsMmTelRegistrationState = " 2455 + mImsMmTelRegistrationHelper.getImsRegistrationState()); 2456 pw.println(" mRoaming = " + mRoaming); 2457 pw.println(" mSsnRegistrants = " + mSsnRegistrants); 2458 pw.println(" Registration Log:"); 2459 pw.increaseIndent(); 2460 mRegLocalLog.dump(pw); 2461 pw.decreaseIndent(); 2462 pw.flush(); 2463 } 2464 logi(String s)2465 private void logi(String s) { 2466 Rlog.i(LOG_TAG, "[" + mPhoneId + "] " + s); 2467 } 2468 logv(String s)2469 private void logv(String s) { 2470 Rlog.v(LOG_TAG, "[" + mPhoneId + "] " + s); 2471 } 2472 logd(String s)2473 private void logd(String s) { 2474 Rlog.d(LOG_TAG, "[" + mPhoneId + "] " + s); 2475 } 2476 loge(String s)2477 private void loge(String s) { 2478 Rlog.e(LOG_TAG, "[" + mPhoneId + "] " + s); 2479 } 2480 } 2481