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