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