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