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 // handle in-call MMI first if applicable 1004 if (handleInCallMmiCommands(newDialString)) { 1005 return null; 1006 } 1007 1008 ImsDialArgs.Builder imsDialArgsBuilder; 1009 imsDialArgsBuilder = ImsDialArgs.Builder.from(dialArgs); 1010 // Get the CLIR info if needed 1011 imsDialArgsBuilder.setClirMode(mCT.getClirMode()); 1012 1013 if (mDefaultPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA) { 1014 return mCT.dial(dialString, imsDialArgsBuilder.build()); 1015 } 1016 1017 // Only look at the Network portion for mmi 1018 String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString); 1019 ImsPhoneMmiCode mmi = 1020 ImsPhoneMmiCode.newFromDialString(networkPortion, this, wrappedCallback); 1021 if (DBG) logd("dialInternal: dialing w/ mmi '" + mmi + "'..."); 1022 1023 if (mmi == null) { 1024 return mCT.dial(dialString, imsDialArgsBuilder.build()); 1025 } else if (mmi.isTemporaryModeCLIR()) { 1026 imsDialArgsBuilder.setClirMode(mmi.getCLIRMode()); 1027 return mCT.dial(mmi.getDialingNumber(), imsDialArgsBuilder.build()); 1028 } else if (!mmi.isSupportedOverImsPhone()) { 1029 // If the mmi is not supported by IMS service, 1030 // try to initiate dialing with default phone 1031 // Note: This code is never reached; there is a bug in isSupportedOverImsPhone which 1032 // causes it to return true even though the "processCode" method ultimately throws the 1033 // exception. 1034 logi("dialInternal: USSD not supported by IMS; fallback to CS."); 1035 throw new CallStateException(CS_FALLBACK); 1036 } else { 1037 mPendingMMIs.add(mmi); 1038 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 1039 1040 try { 1041 mmi.processCode(); 1042 } catch (CallStateException cse) { 1043 if (CS_FALLBACK.equals(cse.getMessage())) { 1044 logi("dialInternal: fallback to GSM required."); 1045 // Make sure we remove from the list of pending MMIs since it will handover to 1046 // GSM. 1047 mPendingMMIs.remove(mmi); 1048 throw cse; 1049 } 1050 } 1051 1052 return null; 1053 } 1054 } 1055 1056 @Override 1057 public void sendDtmf(char c)1058 sendDtmf(char c) { 1059 if (!PhoneNumberUtils.is12Key(c)) { 1060 loge("sendDtmf called with invalid character '" + c + "'"); 1061 } else { 1062 if (mCT.getState() == PhoneConstants.State.OFFHOOK) { 1063 mCT.sendDtmf(c, null); 1064 } 1065 } 1066 } 1067 1068 @Override 1069 public void startDtmf(char c)1070 startDtmf(char c) { 1071 if (!(PhoneNumberUtils.is12Key(c) || (c >= 'A' && c <= 'D'))) { 1072 loge("startDtmf called with invalid character '" + c + "'"); 1073 } else { 1074 mCT.startDtmf(c); 1075 } 1076 } 1077 1078 @Override 1079 public void stopDtmf()1080 stopDtmf() { 1081 mCT.stopDtmf(); 1082 } 1083 notifyIncomingRing()1084 public void notifyIncomingRing() { 1085 if (DBG) logd("notifyIncomingRing"); 1086 AsyncResult ar = new AsyncResult(null, null, null); 1087 sendMessage(obtainMessage(EVENT_CALL_RING, ar)); 1088 } 1089 1090 @Override setMute(boolean muted)1091 public void setMute(boolean muted) { 1092 mCT.setMute(muted); 1093 } 1094 1095 @Override setTTYMode(int ttyMode, Message onComplete)1096 public void setTTYMode(int ttyMode, Message onComplete) { 1097 mCT.setTtyMode(ttyMode); 1098 } 1099 1100 @Override setUiTTYMode(int uiTtyMode, Message onComplete)1101 public void setUiTTYMode(int uiTtyMode, Message onComplete) { 1102 mCT.setUiTTYMode(uiTtyMode, onComplete); 1103 } 1104 1105 @Override getMute()1106 public boolean getMute() { 1107 return mCT.getMute(); 1108 } 1109 1110 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1111 @Override getState()1112 public PhoneConstants.State getState() { 1113 return mCT.getState(); 1114 } 1115 1116 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isValidCommandInterfaceCFReason(int commandInterfaceCFReason)1117 private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { 1118 switch (commandInterfaceCFReason) { 1119 case CF_REASON_UNCONDITIONAL: 1120 case CF_REASON_BUSY: 1121 case CF_REASON_NO_REPLY: 1122 case CF_REASON_NOT_REACHABLE: 1123 case CF_REASON_ALL: 1124 case CF_REASON_ALL_CONDITIONAL: 1125 return true; 1126 default: 1127 return false; 1128 } 1129 } 1130 1131 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isValidCommandInterfaceCFAction(int commandInterfaceCFAction)1132 private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { 1133 switch (commandInterfaceCFAction) { 1134 case CF_ACTION_DISABLE: 1135 case CF_ACTION_ENABLE: 1136 case CF_ACTION_REGISTRATION: 1137 case CF_ACTION_ERASURE: 1138 return true; 1139 default: 1140 return false; 1141 } 1142 } 1143 1144 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isCfEnable(int action)1145 private boolean isCfEnable(int action) { 1146 return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); 1147 } 1148 1149 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getConditionFromCFReason(int reason)1150 private int getConditionFromCFReason(int reason) { 1151 switch(reason) { 1152 case CF_REASON_UNCONDITIONAL: return ImsUtInterface.CDIV_CF_UNCONDITIONAL; 1153 case CF_REASON_BUSY: return ImsUtInterface.CDIV_CF_BUSY; 1154 case CF_REASON_NO_REPLY: return ImsUtInterface.CDIV_CF_NO_REPLY; 1155 case CF_REASON_NOT_REACHABLE: return ImsUtInterface.CDIV_CF_NOT_REACHABLE; 1156 case CF_REASON_ALL: return ImsUtInterface.CDIV_CF_ALL; 1157 case CF_REASON_ALL_CONDITIONAL: return ImsUtInterface.CDIV_CF_ALL_CONDITIONAL; 1158 default: 1159 break; 1160 } 1161 1162 return ImsUtInterface.INVALID; 1163 } 1164 getCFReasonFromCondition(int condition)1165 private int getCFReasonFromCondition(int condition) { 1166 switch(condition) { 1167 case ImsUtInterface.CDIV_CF_UNCONDITIONAL: return CF_REASON_UNCONDITIONAL; 1168 case ImsUtInterface.CDIV_CF_BUSY: return CF_REASON_BUSY; 1169 case ImsUtInterface.CDIV_CF_NO_REPLY: return CF_REASON_NO_REPLY; 1170 case ImsUtInterface.CDIV_CF_NOT_REACHABLE: return CF_REASON_NOT_REACHABLE; 1171 case ImsUtInterface.CDIV_CF_ALL: return CF_REASON_ALL; 1172 case ImsUtInterface.CDIV_CF_ALL_CONDITIONAL: return CF_REASON_ALL_CONDITIONAL; 1173 default: 1174 break; 1175 } 1176 1177 return CF_REASON_NOT_REACHABLE; 1178 } 1179 1180 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getActionFromCFAction(int action)1181 private int getActionFromCFAction(int action) { 1182 switch(action) { 1183 case CF_ACTION_DISABLE: return ImsUtInterface.ACTION_DEACTIVATION; 1184 case CF_ACTION_ENABLE: return ImsUtInterface.ACTION_ACTIVATION; 1185 case CF_ACTION_ERASURE: return ImsUtInterface.ACTION_ERASURE; 1186 case CF_ACTION_REGISTRATION: return ImsUtInterface.ACTION_REGISTRATION; 1187 default: 1188 break; 1189 } 1190 1191 return ImsUtInterface.INVALID; 1192 } 1193 1194 @Override getOutgoingCallerIdDisplay(Message onComplete)1195 public void getOutgoingCallerIdDisplay(Message onComplete) { 1196 if (DBG) logd("getCLIR"); 1197 Message resp; 1198 SS ss = new SS(onComplete); 1199 resp = obtainMessage(EVENT_GET_CLIR_DONE, ss); 1200 1201 try { 1202 ImsUtInterface ut = mCT.getUtInterface(); 1203 ut.queryCLIR(resp); 1204 } catch (ImsException e) { 1205 sendErrorResponse(onComplete, e); 1206 } 1207 } 1208 1209 @Override setOutgoingCallerIdDisplay(int clirMode, Message onComplete)1210 public void setOutgoingCallerIdDisplay(int clirMode, Message onComplete) { 1211 if (DBG) logd("setCLIR action= " + clirMode); 1212 Message resp; 1213 // Packing CLIR value in the message. This will be required for 1214 // SharedPreference caching, if the message comes back as part of 1215 // a success response. 1216 SS ss = new SS(clirMode, onComplete); 1217 resp = obtainMessage(EVENT_SET_CLIR_DONE, ss); 1218 try { 1219 ImsUtInterface ut = mCT.getUtInterface(); 1220 ut.updateCLIR(clirMode, resp); 1221 } catch (ImsException e) { 1222 sendErrorResponse(onComplete, e); 1223 } 1224 } 1225 1226 @Override queryCLIP(Message onComplete)1227 public void queryCLIP(Message onComplete) { 1228 Message resp; 1229 SS ss = new SS(onComplete); 1230 resp = obtainMessage(EVENT_GET_CLIP_DONE, ss); 1231 1232 try { 1233 Rlog.d(LOG_TAG, "ut.queryCLIP"); 1234 ImsUtInterface ut = mCT.getUtInterface(); 1235 ut.queryCLIP(resp); 1236 } catch (ImsException e) { 1237 sendErrorResponse(onComplete, e); 1238 } 1239 } 1240 1241 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1242 @Override getCallForwardingOption(int commandInterfaceCFReason, Message onComplete)1243 public void getCallForwardingOption(int commandInterfaceCFReason, 1244 Message onComplete) { 1245 getCallForwardingOption(commandInterfaceCFReason, 1246 SERVICE_CLASS_VOICE, onComplete); 1247 } 1248 1249 @Override getCallForwardingOption(int commandInterfaceCFReason, int serviceClass, Message onComplete)1250 public void getCallForwardingOption(int commandInterfaceCFReason, int serviceClass, 1251 Message onComplete) { 1252 if (DBG) logd("getCallForwardingOption reason=" + commandInterfaceCFReason); 1253 if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { 1254 if (DBG) logd("requesting call forwarding query."); 1255 Message resp; 1256 SS ss = new SS(commandInterfaceCFReason, serviceClass, onComplete); 1257 resp = obtainMessage(EVENT_GET_CALL_FORWARD_DONE, ss); 1258 1259 try { 1260 ImsUtInterface ut = mCT.getUtInterface(); 1261 ut.queryCallForward(getConditionFromCFReason(commandInterfaceCFReason), null, resp); 1262 } catch (ImsException e) { 1263 sendErrorResponse(onComplete, e); 1264 } 1265 } else if (onComplete != null) { 1266 sendErrorResponse(onComplete); 1267 } 1268 } 1269 1270 @Override setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int timerSeconds, Message onComplete)1271 public void setCallForwardingOption(int commandInterfaceCFAction, 1272 int commandInterfaceCFReason, 1273 String dialingNumber, 1274 int timerSeconds, 1275 Message onComplete) { 1276 setCallForwardingOption(commandInterfaceCFAction, commandInterfaceCFReason, dialingNumber, 1277 CommandsInterface.SERVICE_CLASS_VOICE, timerSeconds, onComplete); 1278 } 1279 1280 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1281 @Override setCallForwardingOption(int commandInterfaceCFAction, int commandInterfaceCFReason, String dialingNumber, int serviceClass, int timerSeconds, Message onComplete)1282 public void setCallForwardingOption(int commandInterfaceCFAction, 1283 int commandInterfaceCFReason, 1284 String dialingNumber, 1285 int serviceClass, 1286 int timerSeconds, 1287 Message onComplete) { 1288 if (DBG) { 1289 logd("setCallForwardingOption action=" + commandInterfaceCFAction 1290 + ", reason=" + commandInterfaceCFReason + " serviceClass=" + serviceClass); 1291 } 1292 if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && 1293 (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { 1294 Message resp; 1295 SS ss = new SS(commandInterfaceCFAction, commandInterfaceCFReason, 1296 dialingNumber, serviceClass, timerSeconds, onComplete); 1297 resp = obtainMessage(EVENT_SET_CALL_FORWARD_DONE, ss); 1298 1299 try { 1300 ImsUtInterface ut = mCT.getUtInterface(); 1301 ut.updateCallForward(getActionFromCFAction(commandInterfaceCFAction), 1302 getConditionFromCFReason(commandInterfaceCFReason), 1303 dialingNumber, 1304 serviceClass, 1305 timerSeconds, 1306 resp); 1307 } catch (ImsException e) { 1308 sendErrorResponse(onComplete, e); 1309 } 1310 } else if (onComplete != null) { 1311 sendErrorResponse(onComplete); 1312 } 1313 } 1314 1315 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1316 @Override getCallWaiting(Message onComplete)1317 public void getCallWaiting(Message onComplete) { 1318 if (DBG) logd("getCallWaiting"); 1319 Message resp; 1320 SS ss = new SS(onComplete); 1321 resp = obtainMessage(EVENT_GET_CALL_WAITING_DONE, ss); 1322 1323 try { 1324 ImsUtInterface ut = mCT.getUtInterface(); 1325 ut.queryCallWaiting(resp); 1326 } catch (ImsException e) { 1327 sendErrorResponse(onComplete, e); 1328 } 1329 } 1330 1331 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1332 @Override setCallWaiting(boolean enable, Message onComplete)1333 public void setCallWaiting(boolean enable, Message onComplete) { 1334 int serviceClass = CommandsInterface.SERVICE_CLASS_VOICE; 1335 CarrierConfigManager configManager = (CarrierConfigManager) 1336 getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); 1337 PersistableBundle b = configManager.getConfigForSubId(getSubId()); 1338 if (b != null) { 1339 serviceClass = b.getInt(CarrierConfigManager.KEY_CALL_WAITING_SERVICE_CLASS_INT, 1340 CommandsInterface.SERVICE_CLASS_VOICE); 1341 } 1342 setCallWaiting(enable, serviceClass, onComplete); 1343 } 1344 setCallWaiting(boolean enable, int serviceClass, Message onComplete)1345 public void setCallWaiting(boolean enable, int serviceClass, Message onComplete) { 1346 if (DBG) logd("setCallWaiting enable=" + enable); 1347 Message resp; 1348 SS ss = new SS(enable, serviceClass, onComplete); 1349 resp = obtainMessage(EVENT_SET_CALL_WAITING_DONE, ss); 1350 1351 try { 1352 ImsUtInterface ut = mCT.getUtInterface(); 1353 ut.updateCallWaiting(enable, serviceClass, resp); 1354 } catch (ImsException e) { 1355 sendErrorResponse(onComplete, e); 1356 } 1357 } 1358 getCBTypeFromFacility(String facility)1359 private int getCBTypeFromFacility(String facility) { 1360 if (CB_FACILITY_BAOC.equals(facility)) { 1361 return ImsUtImplBase.CALL_BARRING_ALL_OUTGOING; 1362 } else if (CB_FACILITY_BAOIC.equals(facility)) { 1363 return ImsUtImplBase.CALL_BARRING_OUTGOING_INTL; 1364 } else if (CB_FACILITY_BAOICxH.equals(facility)) { 1365 return ImsUtImplBase.CALL_BARRING_OUTGOING_INTL_EXCL_HOME; 1366 } else if (CB_FACILITY_BAIC.equals(facility)) { 1367 return ImsUtImplBase.CALL_BARRING_ALL_INCOMING; 1368 } else if (CB_FACILITY_BAICr.equals(facility)) { 1369 return ImsUtImplBase.CALL_BLOCKING_INCOMING_WHEN_ROAMING; 1370 } else if (CB_FACILITY_BA_ALL.equals(facility)) { 1371 return ImsUtImplBase.CALL_BARRING_ALL; 1372 } else if (CB_FACILITY_BA_MO.equals(facility)) { 1373 return ImsUtImplBase.CALL_BARRING_OUTGOING_ALL_SERVICES; 1374 } else if (CB_FACILITY_BA_MT.equals(facility)) { 1375 return ImsUtImplBase.CALL_BARRING_INCOMING_ALL_SERVICES; 1376 } else if (CB_FACILITY_BIC_ACR.equals(facility)) { 1377 return ImsUtImplBase.CALL_BARRING_ANONYMOUS_INCOMING; 1378 } 1379 1380 return 0; 1381 } 1382 getCallBarring(String facility, Message onComplete)1383 public void getCallBarring(String facility, Message onComplete) { 1384 getCallBarring(facility, onComplete, CommandsInterface.SERVICE_CLASS_VOICE); 1385 } 1386 getCallBarring(String facility, Message onComplete, int serviceClass)1387 public void getCallBarring(String facility, Message onComplete, int serviceClass) { 1388 getCallBarring(facility, "", onComplete, serviceClass); 1389 } 1390 1391 @Override getCallBarring(String facility, String password, Message onComplete, int serviceClass)1392 public void getCallBarring(String facility, String password, Message onComplete, 1393 int serviceClass) { 1394 if (DBG) logd("getCallBarring facility=" + facility + ", serviceClass = " + serviceClass); 1395 Message resp; 1396 SS ss = new SS(facility, password, serviceClass, onComplete); 1397 resp = obtainMessage(EVENT_GET_CALL_BARRING_DONE, ss); 1398 1399 try { 1400 ImsUtInterface ut = mCT.getUtInterface(); 1401 // password is not required with Ut interface 1402 ut.queryCallBarring(getCBTypeFromFacility(facility), resp, serviceClass); 1403 } catch (ImsException e) { 1404 sendErrorResponse(onComplete, e); 1405 } 1406 } 1407 setCallBarring(String facility, boolean lockState, String password, Message onComplete)1408 public void setCallBarring(String facility, boolean lockState, String password, 1409 Message onComplete) { 1410 setCallBarring(facility, lockState, password, onComplete, 1411 CommandsInterface.SERVICE_CLASS_VOICE); 1412 } 1413 1414 @Override setCallBarring(String facility, boolean lockState, String password, Message onComplete, int serviceClass)1415 public void setCallBarring(String facility, boolean lockState, String password, 1416 Message onComplete, int serviceClass) { 1417 if (DBG) { 1418 logd("setCallBarring facility=" + facility 1419 + ", lockState=" + lockState + ", serviceClass = " + serviceClass); 1420 } 1421 Message resp; 1422 SS ss = new SS(facility, lockState, password, serviceClass, onComplete); 1423 resp = obtainMessage(EVENT_SET_CALL_BARRING_DONE, ss); 1424 1425 int action; 1426 if (lockState) { 1427 action = CommandsInterface.CF_ACTION_ENABLE; 1428 } 1429 else { 1430 action = CommandsInterface.CF_ACTION_DISABLE; 1431 } 1432 1433 try { 1434 ImsUtInterface ut = mCT.getUtInterface(); 1435 ut.updateCallBarring(getCBTypeFromFacility(facility), action, 1436 resp, null, serviceClass, password); 1437 } catch (ImsException e) { 1438 sendErrorResponse(onComplete, e); 1439 } 1440 } 1441 1442 @Override sendUssdResponse(String ussdMessge)1443 public void sendUssdResponse(String ussdMessge) { 1444 logd("sendUssdResponse"); 1445 ImsPhoneMmiCode mmi = ImsPhoneMmiCode.newFromUssdUserInput(ussdMessge, this); 1446 mPendingMMIs.add(mmi); 1447 mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); 1448 mmi.sendUssd(ussdMessge); 1449 } 1450 sendUSSD(String ussdString, Message response)1451 public void sendUSSD(String ussdString, Message response) { 1452 Rlog.d(LOG_TAG, "sendUssd ussdString = " + ussdString); 1453 mLastDialString = ussdString; 1454 mCT.sendUSSD(ussdString, response); 1455 } 1456 1457 @Override cancelUSSD(Message msg)1458 public void cancelUSSD(Message msg) { 1459 mCT.cancelUSSD(msg); 1460 } 1461 1462 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) sendErrorResponse(Message onComplete)1463 private void sendErrorResponse(Message onComplete) { 1464 logd("sendErrorResponse"); 1465 if (onComplete != null) { 1466 AsyncResult.forMessage(onComplete, null, 1467 new CommandException(CommandException.Error.GENERIC_FAILURE)); 1468 onComplete.sendToTarget(); 1469 } 1470 } 1471 1472 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1473 @VisibleForTesting sendErrorResponse(Message onComplete, Throwable e)1474 public void sendErrorResponse(Message onComplete, Throwable e) { 1475 logd("sendErrorResponse"); 1476 if (onComplete != null) { 1477 AsyncResult.forMessage(onComplete, null, getCommandException(e)); 1478 onComplete.sendToTarget(); 1479 } 1480 } 1481 getCommandException(int code, String errorString)1482 private CommandException getCommandException(int code, String errorString) { 1483 logd("getCommandException code= " + code + ", errorString= " + errorString); 1484 CommandException.Error error = CommandException.Error.GENERIC_FAILURE; 1485 1486 switch(code) { 1487 case ImsReasonInfo.CODE_UT_NOT_SUPPORTED: 1488 // fall through 1489 case ImsReasonInfo.CODE_UT_OPERATION_NOT_ALLOWED: 1490 // not allowed is reported by operators when the network doesn't support a specific 1491 // type of barring. 1492 error = CommandException.Error.REQUEST_NOT_SUPPORTED; 1493 break; 1494 case ImsReasonInfo.CODE_UT_CB_PASSWORD_MISMATCH: 1495 error = CommandException.Error.PASSWORD_INCORRECT; 1496 break; 1497 case ImsReasonInfo.CODE_UT_SERVICE_UNAVAILABLE: 1498 error = CommandException.Error.RADIO_NOT_AVAILABLE; 1499 break; 1500 case ImsReasonInfo.CODE_FDN_BLOCKED: 1501 error = CommandException.Error.FDN_CHECK_FAILURE; 1502 break; 1503 case ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_DIAL: 1504 error = CommandException.Error.SS_MODIFIED_TO_DIAL; 1505 break; 1506 case ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_USSD: 1507 error = CommandException.Error.SS_MODIFIED_TO_USSD; 1508 break; 1509 case ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_SS: 1510 error = CommandException.Error.SS_MODIFIED_TO_SS; 1511 break; 1512 case ImsReasonInfo.CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO: 1513 error = CommandException.Error.SS_MODIFIED_TO_DIAL_VIDEO; 1514 break; 1515 default: 1516 break; 1517 } 1518 1519 return new CommandException(error, errorString); 1520 } 1521 getCommandException(Throwable e)1522 private CommandException getCommandException(Throwable e) { 1523 CommandException ex = null; 1524 1525 if (e instanceof ImsException) { 1526 ex = getCommandException(((ImsException)e).getCode(), e.getMessage()); 1527 } else { 1528 logd("getCommandException generic failure"); 1529 ex = new CommandException(CommandException.Error.GENERIC_FAILURE); 1530 } 1531 return ex; 1532 } 1533 1534 private void onNetworkInitiatedUssd(ImsPhoneMmiCode mmi)1535 onNetworkInitiatedUssd(ImsPhoneMmiCode mmi) { 1536 logd("onNetworkInitiatedUssd"); 1537 mMmiCompleteRegistrants.notifyRegistrants( 1538 new AsyncResult(null, mmi, null)); 1539 } 1540 1541 /* package */ onIncomingUSSD(int ussdMode, String ussdMessage)1542 void onIncomingUSSD(int ussdMode, String ussdMessage) { 1543 if (DBG) logd("onIncomingUSSD ussdMode=" + ussdMode); 1544 1545 boolean isUssdError; 1546 boolean isUssdRequest; 1547 1548 isUssdRequest 1549 = (ussdMode == CommandsInterface.USSD_MODE_REQUEST); 1550 1551 isUssdError 1552 = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY 1553 && ussdMode != CommandsInterface.USSD_MODE_REQUEST); 1554 1555 ImsPhoneMmiCode found = null; 1556 for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { 1557 if(mPendingMMIs.get(i).isPendingUSSD()) { 1558 found = mPendingMMIs.get(i); 1559 break; 1560 } 1561 } 1562 1563 if (found != null) { 1564 // Complete pending USSD 1565 if (isUssdError) { 1566 found.onUssdFinishedError(); 1567 } else { 1568 found.onUssdFinished(ussdMessage, isUssdRequest); 1569 } 1570 } else if (!isUssdError && !TextUtils.isEmpty(ussdMessage)) { 1571 // pending USSD not found 1572 // The network may initiate its own USSD request 1573 1574 // ignore everything that isnt a Notify or a Request 1575 // also, discard if there is no message to present 1576 ImsPhoneMmiCode mmi; 1577 mmi = ImsPhoneMmiCode.newNetworkInitiatedUssd(ussdMessage, 1578 isUssdRequest, 1579 this); 1580 onNetworkInitiatedUssd(mmi); 1581 } else if (isUssdError) { 1582 ImsPhoneMmiCode mmi; 1583 mmi = ImsPhoneMmiCode.newNetworkInitiatedUssd(ussdMessage, 1584 true, 1585 this); 1586 mmi.onUssdFinishedError(); 1587 } 1588 } 1589 1590 /** 1591 * Removes the given MMI from the pending list and notifies 1592 * registrants that it is complete. 1593 * @param mmi MMI that is done 1594 */ 1595 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onMMIDone(ImsPhoneMmiCode mmi)1596 public void onMMIDone(ImsPhoneMmiCode mmi) { 1597 /* Only notify complete if it's on the pending list. 1598 * Otherwise, it's already been handled (eg, previously canceled). 1599 * The exception is cancellation of an incoming USSD-REQUEST, which is 1600 * not on the list. 1601 */ 1602 logd("onMMIDone: mmi=" + mmi); 1603 if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest() || mmi.isSsInfo()) { 1604 ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver(); 1605 if (receiverCallback != null) { 1606 int returnCode = (mmi.getState() == MmiCode.State.COMPLETE) ? 1607 TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE; 1608 sendUssdResponse(mmi.getDialString(), mmi.getMessage(), returnCode, 1609 receiverCallback ); 1610 } else { 1611 logv("onMMIDone: notifyRegistrants"); 1612 mMmiCompleteRegistrants.notifyRegistrants( 1613 new AsyncResult(null, mmi, null)); 1614 } 1615 } 1616 } 1617 1618 @Override getHandoverConnection()1619 public ArrayList<Connection> getHandoverConnection() { 1620 ArrayList<Connection> connList = new ArrayList<Connection>(); 1621 // Add all foreground call connections 1622 connList.addAll(getForegroundCall().getConnections()); 1623 // Add all background call connections 1624 connList.addAll(getBackgroundCall().getConnections()); 1625 // Add all background call connections 1626 connList.addAll(getRingingCall().getConnections()); 1627 if (connList.size() > 0) { 1628 return connList; 1629 } else { 1630 return null; 1631 } 1632 } 1633 1634 @Override notifySrvccState(int state)1635 public void notifySrvccState(int state) { 1636 mCT.notifySrvccState(state); 1637 } 1638 1639 /* package */ void initiateSilentRedial()1640 initiateSilentRedial() { 1641 initiateSilentRedial(false, EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED); 1642 } 1643 1644 /* package */ void initiateSilentRedial(boolean isEmergency, int eccCategory)1645 initiateSilentRedial(boolean isEmergency, int eccCategory) { 1646 DialArgs dialArgs = new DialArgs.Builder() 1647 .setIsEmergency(isEmergency) 1648 .setEccCategory(eccCategory) 1649 .build(); 1650 int cause = CallFailCause.LOCAL_CALL_CS_RETRY_REQUIRED; 1651 AsyncResult ar = new AsyncResult(null, 1652 new SilentRedialParam(mLastDialString, cause, dialArgs), 1653 null); 1654 if (ar != null) { 1655 // There is a race condition that can happen in some cases: 1656 // (Main thread) dial start 1657 // (Binder Thread) onCallSessionFailed 1658 // (Binder Thread) schedule a redial for CS on the main thread 1659 // (Main Thread) dial finish 1660 // (Main Thread) schedule to associate ImsPhoneConnection with 1661 // GsmConnection on the main thread 1662 // If scheduling the CS redial occurs before the command to schedule the 1663 // ImsPhoneConnection to be associated with the GsmConnection, the CS redial will occur 1664 // before GsmConnection has had callbacks to ImsPhone correctly updated. This will cause 1665 // Callbacks back to GsmCdmaPhone to never be set up correctly and we will lose track of 1666 // the instance. 1667 // Instead, schedule this redial to happen on the main thread, so that we know dial has 1668 // finished before scheduling a redial: 1669 // (Main thread) dial start 1670 // (Binder Thread) onCallSessionFailed -> move notify registrants to main thread 1671 // (Main Thread) dial finish 1672 // (Main Thread) schedule on main thread to associate ImsPhoneConnection with 1673 // GsmConnection 1674 // (Main Thread) schedule a redial for CS 1675 mContext.getMainExecutor().execute(() -> { 1676 logd("initiateSilentRedial: notifying registrants, isEmergency=" + isEmergency 1677 + ", eccCategory=" + eccCategory); 1678 mSilentRedialRegistrants.notifyRegistrants(ar); 1679 }); 1680 } 1681 } 1682 registerForImsRegistrationChanges(Handler h, int what, Object obj)1683 public void registerForImsRegistrationChanges(Handler h, int what, Object obj) { 1684 mImsRegistrationUpdateRegistrants.addUnique(h, what, obj); 1685 } 1686 unregisterForImsRegistrationChanges(Handler h)1687 public void unregisterForImsRegistrationChanges(Handler h) { 1688 mImsRegistrationUpdateRegistrants.remove(h); 1689 } 1690 1691 @Override registerForSilentRedial(Handler h, int what, Object obj)1692 public void registerForSilentRedial(Handler h, int what, Object obj) { 1693 mSilentRedialRegistrants.addUnique(h, what, obj); 1694 } 1695 1696 @Override unregisterForSilentRedial(Handler h)1697 public void unregisterForSilentRedial(Handler h) { 1698 mSilentRedialRegistrants.remove(h); 1699 } 1700 1701 @Override registerForSuppServiceNotification(Handler h, int what, Object obj)1702 public void registerForSuppServiceNotification(Handler h, int what, Object obj) { 1703 mSsnRegistrants.addUnique(h, what, obj); 1704 } 1705 1706 @Override unregisterForSuppServiceNotification(Handler h)1707 public void unregisterForSuppServiceNotification(Handler h) { 1708 mSsnRegistrants.remove(h); 1709 } 1710 1711 @Override getSubId()1712 public int getSubId() { 1713 return mDefaultPhone.getSubId(); 1714 } 1715 1716 @Override getPhoneId()1717 public int getPhoneId() { 1718 return mDefaultPhone.getPhoneId(); 1719 } 1720 getCallForwardInfo(ImsCallForwardInfo info)1721 private CallForwardInfo getCallForwardInfo(ImsCallForwardInfo info) { 1722 CallForwardInfo cfInfo = new CallForwardInfo(); 1723 cfInfo.status = info.getStatus(); 1724 cfInfo.reason = getCFReasonFromCondition(info.getCondition()); 1725 cfInfo.serviceClass = SERVICE_CLASS_VOICE; 1726 cfInfo.toa = info.getToA(); 1727 cfInfo.number = info.getNumber(); 1728 cfInfo.timeSeconds = info.getTimeSeconds(); 1729 return cfInfo; 1730 } 1731 1732 @Override getLine1Number()1733 public String getLine1Number() { 1734 return mDefaultPhone.getLine1Number(); 1735 } 1736 1737 /** 1738 * Used to Convert ImsCallForwardInfo[] to CallForwardInfo[]. 1739 * Update received call forward status to default IccRecords. 1740 */ handleCfQueryResult(ImsCallForwardInfo[] infos)1741 public CallForwardInfo[] handleCfQueryResult(ImsCallForwardInfo[] infos) { 1742 CallForwardInfo[] cfInfos = null; 1743 1744 if (infos != null && infos.length != 0) { 1745 cfInfos = new CallForwardInfo[infos.length]; 1746 } 1747 1748 if (infos == null || infos.length == 0) { 1749 // Assume the default is not active 1750 // Set unconditional CFF in SIM to false 1751 setVoiceCallForwardingFlag(getIccRecords(), 1, false, null); 1752 } else { 1753 for (int i = 0, s = infos.length; i < s; i++) { 1754 if (infos[i].getCondition() == ImsUtInterface.CDIV_CF_UNCONDITIONAL) { 1755 setVoiceCallForwardingFlag(getIccRecords(), 1, (infos[i].getStatus() == 1), 1756 infos[i].getNumber()); 1757 } 1758 cfInfos[i] = getCallForwardInfo(infos[i]); 1759 } 1760 } 1761 1762 return cfInfos; 1763 } 1764 handleCbQueryResult(ImsSsInfo[] infos)1765 private int[] handleCbQueryResult(ImsSsInfo[] infos) { 1766 int[] cbInfos = new int[1]; 1767 cbInfos[0] = SERVICE_CLASS_NONE; 1768 1769 if (infos[0].getStatus() == 1) { 1770 cbInfos[0] = SERVICE_CLASS_VOICE; 1771 } 1772 1773 return cbInfos; 1774 } 1775 handleCwQueryResult(ImsSsInfo[] infos)1776 private int[] handleCwQueryResult(ImsSsInfo[] infos) { 1777 int[] cwInfos = new int[2]; 1778 cwInfos[0] = 0; 1779 1780 if (infos[0].getStatus() == 1) { 1781 cwInfos[0] = 1; 1782 cwInfos[1] = SERVICE_CLASS_VOICE; 1783 } 1784 1785 return cwInfos; 1786 } 1787 1788 private void sendResponse(Message onComplete, Object result, Throwable e)1789 sendResponse(Message onComplete, Object result, Throwable e) { 1790 if (onComplete != null) { 1791 CommandException ex = null; 1792 if (e != null) { 1793 ex = getCommandException(e); 1794 } 1795 AsyncResult.forMessage(onComplete, result, ex); 1796 onComplete.sendToTarget(); 1797 } 1798 } 1799 updateDataServiceState()1800 private void updateDataServiceState() { 1801 if (mSS != null && mDefaultPhone.getServiceStateTracker() != null 1802 && mDefaultPhone.getServiceStateTracker().mSS != null) { 1803 ServiceState ss = mDefaultPhone.getServiceStateTracker().mSS; 1804 mSS.setDataRegState(ss.getDataRegistrationState()); 1805 List<NetworkRegistrationInfo> nriList = 1806 ss.getNetworkRegistrationInfoListForDomain(NetworkRegistrationInfo.DOMAIN_PS); 1807 for (NetworkRegistrationInfo nri : nriList) { 1808 mSS.addNetworkRegistrationInfo(nri); 1809 } 1810 1811 mSS.setIwlanPreferred(ss.isIwlanPreferred()); 1812 logd("updateDataServiceState: defSs = " + ss + " imsSs = " + mSS); 1813 } 1814 } 1815 isCsRetryException(Throwable e)1816 boolean isCsRetryException(Throwable e) { 1817 if ((e != null) && (e instanceof ImsException) 1818 && (((ImsException)e).getCode() 1819 == ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED)) { 1820 return true; 1821 } 1822 return false; 1823 } 1824 setCsfbBundle(boolean isCsRetry)1825 private Bundle setCsfbBundle(boolean isCsRetry) { 1826 Bundle b = new Bundle(); 1827 b.putBoolean(CS_FALLBACK_SS, isCsRetry); 1828 return b; 1829 } 1830 sendResponseOrRetryOnCsfbSs(SS ss, int what, Throwable e, Object obj)1831 private void sendResponseOrRetryOnCsfbSs(SS ss, int what, Throwable e, Object obj) { 1832 if (!isCsRetryException(e)) { 1833 sendResponse(ss.mOnComplete, obj, e); 1834 return; 1835 } 1836 1837 Rlog.d(LOG_TAG, "Try CSFB: " + what); 1838 ss.mOnComplete.setData(setCsfbBundle(true)); 1839 1840 switch (what) { 1841 case EVENT_GET_CALL_FORWARD_DONE: 1842 mDefaultPhone.getCallForwardingOption(ss.mCfReason, 1843 ss.mServiceClass, 1844 ss.mOnComplete); 1845 break; 1846 case EVENT_SET_CALL_FORWARD_DONE: 1847 mDefaultPhone.setCallForwardingOption(ss.mCfAction, 1848 ss.mCfReason, 1849 ss.mDialingNumber, 1850 ss.mServiceClass, 1851 ss.mTimerSeconds, 1852 ss.mOnComplete); 1853 break; 1854 case EVENT_GET_CALL_BARRING_DONE: 1855 mDefaultPhone.getCallBarring(ss.mFacility, 1856 ss.mPassword, 1857 ss.mOnComplete, 1858 ss.mServiceClass); 1859 break; 1860 case EVENT_SET_CALL_BARRING_DONE: 1861 mDefaultPhone.setCallBarring(ss.mFacility, 1862 ss.mLockState, 1863 ss.mPassword, 1864 ss.mOnComplete, 1865 ss.mServiceClass); 1866 break; 1867 case EVENT_GET_CALL_WAITING_DONE: 1868 mDefaultPhone.getCallWaiting(ss.mOnComplete); 1869 break; 1870 case EVENT_SET_CALL_WAITING_DONE: 1871 mDefaultPhone.setCallWaiting(ss.mEnable, 1872 ss.mServiceClass, 1873 ss.mOnComplete); 1874 break; 1875 case EVENT_GET_CLIR_DONE: 1876 mDefaultPhone.getOutgoingCallerIdDisplay(ss.mOnComplete); 1877 break; 1878 case EVENT_SET_CLIR_DONE: 1879 mDefaultPhone.setOutgoingCallerIdDisplay(ss.mClirMode, ss.mOnComplete); 1880 break; 1881 case EVENT_GET_CLIP_DONE: 1882 mDefaultPhone.queryCLIP(ss.mOnComplete); 1883 break; 1884 default: 1885 break; 1886 } 1887 } 1888 1889 @Override handleMessage(Message msg)1890 public void handleMessage(Message msg) { 1891 AsyncResult ar = (AsyncResult) msg.obj; 1892 Message onComplete; 1893 SS ss = null; 1894 if (ar != null && ar.userObj instanceof SS) { 1895 ss = (SS) ar.userObj; 1896 } 1897 1898 if (DBG) logd("handleMessage what=" + msg.what); 1899 switch (msg.what) { 1900 case EVENT_SET_CALL_FORWARD_DONE: 1901 if (ar.exception == null && ss != null && 1902 (ss.mCfReason == CF_REASON_UNCONDITIONAL)) { 1903 setVoiceCallForwardingFlag(getIccRecords(), 1, isCfEnable(ss.mCfAction), 1904 ss.mDialingNumber); 1905 } 1906 if (ss != null) { 1907 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, null); 1908 } 1909 break; 1910 1911 case EVENT_GET_CALL_FORWARD_DONE: 1912 CallForwardInfo[] cfInfos = null; 1913 if (ar.exception == null) { 1914 cfInfos = handleCfQueryResult((ImsCallForwardInfo[])ar.result); 1915 } 1916 if (ss != null) { 1917 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, cfInfos); 1918 } 1919 break; 1920 1921 case EVENT_GET_CALL_BARRING_DONE: 1922 case EVENT_GET_CALL_WAITING_DONE: 1923 int[] ssInfos = null; 1924 if (ar.exception == null) { 1925 if (msg.what == EVENT_GET_CALL_BARRING_DONE) { 1926 ssInfos = handleCbQueryResult((ImsSsInfo[])ar.result); 1927 } else if (msg.what == EVENT_GET_CALL_WAITING_DONE) { 1928 ssInfos = handleCwQueryResult((ImsSsInfo[])ar.result); 1929 } 1930 } 1931 if (ss != null) { 1932 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, ssInfos); 1933 } 1934 break; 1935 1936 case EVENT_GET_CLIR_DONE: 1937 ImsSsInfo ssInfo = (ImsSsInfo) ar.result; 1938 int[] clirInfo = null; 1939 if (ssInfo != null) { 1940 // Unfortunately callers still use the old {n,m} format of ImsSsInfo, so return 1941 // that for compatibility 1942 clirInfo = ssInfo.getCompatArray(ImsSsData.SS_CLIR); 1943 } 1944 if (ss != null) { 1945 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, clirInfo); 1946 } 1947 break; 1948 1949 case EVENT_GET_CLIP_DONE: 1950 ImsSsInfo ssInfoResp = null; 1951 if (ar.exception == null && ar.result instanceof ImsSsInfo) { 1952 ssInfoResp = (ImsSsInfo) ar.result; 1953 } 1954 if (ss != null) { 1955 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, ssInfoResp); 1956 } 1957 break; 1958 1959 case EVENT_SET_CLIR_DONE: 1960 if (ar.exception == null) { 1961 if (ss != null) { 1962 saveClirSetting(ss.mClirMode); 1963 } 1964 } 1965 // (Intentional fallthrough) 1966 case EVENT_SET_CALL_BARRING_DONE: 1967 case EVENT_SET_CALL_WAITING_DONE: 1968 if (ss != null) { 1969 sendResponseOrRetryOnCsfbSs(ss, msg.what, ar.exception, null); 1970 } 1971 break; 1972 1973 case EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED: 1974 if (DBG) logd("EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED"); 1975 updateDataServiceState(); 1976 break; 1977 1978 case EVENT_SERVICE_STATE_CHANGED: 1979 if (VDBG) logd("EVENT_SERVICE_STATE_CHANGED"); 1980 ar = (AsyncResult) msg.obj; 1981 ServiceState newServiceState = (ServiceState) ar.result; 1982 updateRoamingState(newServiceState); 1983 break; 1984 case EVENT_VOICE_CALL_ENDED: 1985 if (DBG) logd("Voice call ended. Handle pending updateRoamingState."); 1986 mCT.unregisterForVoiceCallEnded(this); 1987 // Get the current unmodified ServiceState from the tracker, as it has more info 1988 // about the cell roaming state. 1989 ServiceStateTracker sst = getDefaultPhone().getServiceStateTracker(); 1990 if (sst != null) { 1991 updateRoamingState(sst.mSS); 1992 } 1993 break; 1994 case EVENT_INITIATE_VOLTE_SILENT_REDIAL: { 1995 // This is a CS -> IMS redial 1996 if (VDBG) logd("EVENT_INITIATE_VOLTE_SILENT_REDIAL"); 1997 ar = (AsyncResult) msg.obj; 1998 if (ar.exception == null && ar.result != null) { 1999 SilentRedialParam result = (SilentRedialParam) ar.result; 2000 String dialString = result.dialString; 2001 int causeCode = result.causeCode; 2002 DialArgs dialArgs = result.dialArgs; 2003 if (VDBG) logd("dialString=" + dialString + " causeCode=" + causeCode); 2004 2005 try { 2006 Connection cn = dial(dialString, 2007 updateDialArgsForVolteSilentRedial(dialArgs, causeCode)); 2008 // The GSM/CDMA Connection that is owned by the GsmCdmaPhone is currently 2009 // the one with a callback registered to TelephonyConnection. Notify the 2010 // redial happened over that Phone so that it can be replaced with the 2011 // new ImsPhoneConnection. 2012 Rlog.d(LOG_TAG, "Notify volte redial connection changed cn: " + cn); 2013 if (mDefaultPhone != null) { 2014 // don't care it is null or not. 2015 mDefaultPhone.notifyRedialConnectionChanged(cn); 2016 } 2017 } catch (CallStateException e) { 2018 Rlog.e(LOG_TAG, "volte silent redial failed: " + e); 2019 if (mDefaultPhone != null) { 2020 mDefaultPhone.notifyRedialConnectionChanged(null); 2021 } 2022 } 2023 } else { 2024 if (VDBG) logd("EVENT_INITIATE_VOLTE_SILENT_REDIAL" + 2025 " has exception or empty result"); 2026 } 2027 break; 2028 } 2029 2030 default: 2031 super.handleMessage(msg); 2032 break; 2033 } 2034 } 2035 2036 /** 2037 * Listen to the IMS ECBM state change 2038 */ 2039 private ImsEcbmStateListener mImsEcbmStateListener = 2040 new ImsEcbmStateListener(mContext.getMainExecutor()) { 2041 @Override 2042 public void onECBMEntered(Executor executor) { 2043 if (DBG) logd("onECBMEntered"); 2044 2045 TelephonyUtils.runWithCleanCallingIdentity(()-> 2046 handleEnterEmergencyCallbackMode(), executor); 2047 } 2048 2049 2050 2051 @Override 2052 public void onECBMExited(Executor executor) { 2053 if (DBG) logd("onECBMExited"); 2054 TelephonyUtils.runWithCleanCallingIdentity(()-> 2055 handleExitEmergencyCallbackMode(), executor); 2056 } 2057 }; 2058 2059 @VisibleForTesting getImsEcbmStateListener()2060 public ImsEcbmStateListener getImsEcbmStateListener() { 2061 return mImsEcbmStateListener; 2062 } 2063 2064 @Override isInEmergencyCall()2065 public boolean isInEmergencyCall() { 2066 return mCT.isInEmergencyCall(); 2067 } 2068 sendEmergencyCallbackModeChange()2069 private void sendEmergencyCallbackModeChange() { 2070 // Send an Intent 2071 Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 2072 intent.putExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, isInEcm()); 2073 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId()); 2074 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2075 if (DBG) logd("sendEmergencyCallbackModeChange: isInEcm=" + isInEcm()); 2076 } 2077 2078 @Override exitEmergencyCallbackMode()2079 public void exitEmergencyCallbackMode() { 2080 if (mWakeLock.isHeld()) { 2081 mWakeLock.release(); 2082 } 2083 if (DBG) logd("exitEmergencyCallbackMode()"); 2084 2085 // Send a message which will invoke handleExitEmergencyCallbackMode 2086 ImsEcbm ecbm; 2087 try { 2088 ecbm = mCT.getEcbmInterface(); 2089 ecbm.exitEmergencyCallbackMode(); 2090 } catch (ImsException e) { 2091 e.printStackTrace(); 2092 } 2093 } 2094 2095 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) handleEnterEmergencyCallbackMode()2096 private void handleEnterEmergencyCallbackMode() { 2097 if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { 2098 logd("DomainSelection enabled: ignore ECBM enter event."); 2099 return; 2100 } 2101 if (DBG) logd("handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= " + isInEcm()); 2102 // if phone is not in Ecm mode, and it's changed to Ecm mode 2103 if (!isInEcm()) { 2104 setIsInEcm(true); 2105 // notify change 2106 sendEmergencyCallbackModeChange(); 2107 ((GsmCdmaPhone) mDefaultPhone).notifyEmergencyCallRegistrants(true); 2108 2109 // Post this runnable so we will automatically exit 2110 // if no one invokes exitEmergencyCallbackMode() directly. 2111 long delayInMillis = TelephonyProperties.ecm_exit_timer() 2112 .orElse(DEFAULT_ECM_EXIT_TIMER_VALUE); 2113 postDelayed(mExitEcmRunnable, delayInMillis); 2114 // We don't want to go to sleep while in Ecm 2115 mWakeLock.acquire(); 2116 } 2117 } 2118 2119 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2120 @Override handleExitEmergencyCallbackMode()2121 protected void handleExitEmergencyCallbackMode() { 2122 if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) { 2123 logd("DomainSelection enabled: ignore ECBM exit event."); 2124 return; 2125 } 2126 if (DBG) logd("handleExitEmergencyCallbackMode: mIsPhoneInEcmState = " + isInEcm()); 2127 2128 if (isInEcm()) { 2129 setIsInEcm(false); 2130 } 2131 2132 // Remove pending exit Ecm runnable, if any 2133 removeCallbacks(mExitEcmRunnable); 2134 2135 if (mEcmExitRespRegistrant != null) { 2136 mEcmExitRespRegistrant.notifyResult(Boolean.TRUE); 2137 } 2138 2139 // release wakeLock 2140 if (mWakeLock.isHeld()) { 2141 mWakeLock.release(); 2142 } 2143 2144 // send an Intent 2145 sendEmergencyCallbackModeChange(); 2146 ((GsmCdmaPhone) mDefaultPhone).notifyEmergencyCallRegistrants(false); 2147 } 2148 2149 /** 2150 * Handle to cancel or restart Ecm timer in emergency call back mode if action is 2151 * CANCEL_ECM_TIMER, cancel Ecm timer and notify apps the timer is canceled; otherwise, restart 2152 * Ecm timer and notify apps the timer is restarted. 2153 */ handleTimerInEmergencyCallbackMode(int action)2154 void handleTimerInEmergencyCallbackMode(int action) { 2155 if (DomainSelectionResolver.getInstance().isDomainSelectionSupported()) return; 2156 switch (action) { 2157 case CANCEL_ECM_TIMER: 2158 removeCallbacks(mExitEcmRunnable); 2159 ((GsmCdmaPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.TRUE); 2160 setEcmCanceledForEmergency(true /*isCanceled*/); 2161 break; 2162 case RESTART_ECM_TIMER: 2163 long delayInMillis = TelephonyProperties.ecm_exit_timer() 2164 .orElse(DEFAULT_ECM_EXIT_TIMER_VALUE); 2165 postDelayed(mExitEcmRunnable, delayInMillis); 2166 ((GsmCdmaPhone) mDefaultPhone).notifyEcbmTimerReset(Boolean.FALSE); 2167 setEcmCanceledForEmergency(false /*isCanceled*/); 2168 break; 2169 default: 2170 loge("handleTimerInEmergencyCallbackMode, unsupported action " + action); 2171 } 2172 } 2173 2174 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2175 @Override setOnEcbModeExitResponse(Handler h, int what, Object obj)2176 public void setOnEcbModeExitResponse(Handler h, int what, Object obj) { 2177 mEcmExitRespRegistrant = new Registrant(h, what, obj); 2178 } 2179 2180 @Override unsetOnEcbModeExitResponse(Handler h)2181 public void unsetOnEcbModeExitResponse(Handler h) { 2182 mEcmExitRespRegistrant.clear(); 2183 } 2184 onFeatureCapabilityChanged()2185 public void onFeatureCapabilityChanged() { 2186 mDefaultPhone.getServiceStateTracker().onImsCapabilityChanged(); 2187 } 2188 2189 @Override isImsCapabilityAvailable(int capability, int regTech)2190 public boolean isImsCapabilityAvailable(int capability, int regTech) throws ImsException { 2191 return mCT.isImsCapabilityAvailable(capability, regTech); 2192 } 2193 2194 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2195 @Override isVolteEnabled()2196 public boolean isVolteEnabled() { 2197 return isVoiceOverCellularImsEnabled(); 2198 } 2199 2200 @Override isVoiceOverCellularImsEnabled()2201 public boolean isVoiceOverCellularImsEnabled() { 2202 return mCT.isVoiceOverCellularImsEnabled(); 2203 } 2204 2205 @Override isWifiCallingEnabled()2206 public boolean isWifiCallingEnabled() { 2207 return mCT.isVowifiEnabled(); 2208 } 2209 2210 @Override isVideoEnabled()2211 public boolean isVideoEnabled() { 2212 return mCT.isVideoCallEnabled(); 2213 } 2214 2215 @Override getImsRegistrationTech()2216 public int getImsRegistrationTech() { 2217 return mCT.getImsRegistrationTech(); 2218 } 2219 2220 @Override getImsRegistrationTech(Consumer<Integer> callback)2221 public void getImsRegistrationTech(Consumer<Integer> callback) { 2222 mCT.getImsRegistrationTech(callback); 2223 } 2224 2225 @Override getImsRegistrationState(Consumer<Integer> callback)2226 public void getImsRegistrationState(Consumer<Integer> callback) { 2227 callback.accept(mImsMmTelRegistrationHelper.getImsRegistrationState()); 2228 } 2229 2230 @Override getDefaultPhone()2231 public Phone getDefaultPhone() { 2232 return mDefaultPhone; 2233 } 2234 2235 @Override isImsRegistered()2236 public boolean isImsRegistered() { 2237 return mImsMmTelRegistrationHelper.isImsRegistered(); 2238 } 2239 2240 // Not used, but not removed due to UnsupportedAppUsage tag. 2241 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setImsRegistered(boolean isRegistered)2242 public void setImsRegistered(boolean isRegistered) { 2243 mImsMmTelRegistrationHelper.updateRegistrationState( 2244 isRegistered ? RegistrationManager.REGISTRATION_STATE_REGISTERED : 2245 RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED); 2246 } 2247 2248 @Override callEndCleanupHandOverCallIfAny()2249 public void callEndCleanupHandOverCallIfAny() { 2250 mCT.callEndCleanupHandOverCallIfAny(); 2251 } 2252 2253 private BroadcastReceiver mResultReceiver = new BroadcastReceiver() { 2254 @Override 2255 public void onReceive(Context context, Intent intent) { 2256 // Add notification only if alert was not shown by WfcSettings 2257 if (getResultCode() == Activity.RESULT_OK) { 2258 // Default result code (as passed to sendOrderedBroadcast) 2259 // means that intent was not received by WfcSettings. 2260 2261 CharSequence title = 2262 intent.getCharSequenceExtra(EXTRA_WFC_REGISTRATION_FAILURE_TITLE); 2263 CharSequence messageAlert = 2264 intent.getCharSequenceExtra(EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE); 2265 CharSequence messageNotification = 2266 intent.getCharSequenceExtra(EXTRA_KEY_NOTIFICATION_MESSAGE); 2267 2268 Intent resultIntent = new Intent(Intent.ACTION_MAIN); 2269 // Note: If the classname below is ever removed, the call to 2270 // PendingIntent.getActivity should also specify FLAG_IMMUTABLE to ensure the 2271 // pending intent cannot be tampered with. 2272 resultIntent.setClassName("com.android.settings", 2273 "com.android.settings.Settings$WifiCallingSettingsActivity"); 2274 resultIntent.putExtra(EXTRA_KEY_ALERT_SHOW, true); 2275 resultIntent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_TITLE, title); 2276 resultIntent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE, messageAlert); 2277 PendingIntent resultPendingIntent = 2278 PendingIntent.getActivity( 2279 mContext, 2280 0, 2281 resultIntent, 2282 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE 2283 ); 2284 2285 final Notification notification = new Notification.Builder(mContext) 2286 .setSmallIcon(android.R.drawable.stat_sys_warning) 2287 .setContentTitle(title) 2288 .setContentText(messageNotification) 2289 .setAutoCancel(true) 2290 .setContentIntent(resultPendingIntent) 2291 .setStyle(new Notification.BigTextStyle() 2292 .bigText(messageNotification)) 2293 .setChannelId(NotificationChannelController.CHANNEL_ID_WFC) 2294 .build(); 2295 final String notificationTag = "wifi_calling"; 2296 final int notificationId = 1; 2297 2298 NotificationManager notificationManager = 2299 (NotificationManager) mContext.getSystemService( 2300 Context.NOTIFICATION_SERVICE); 2301 notificationManager.notify(notificationTag, notificationId, 2302 notification); 2303 } 2304 } 2305 }; 2306 2307 /** 2308 * Show notification in case of some error codes. 2309 */ processDisconnectReason(ImsReasonInfo imsReasonInfo)2310 public void processDisconnectReason(ImsReasonInfo imsReasonInfo) { 2311 if (imsReasonInfo.mCode == imsReasonInfo.CODE_REGISTRATION_ERROR 2312 && imsReasonInfo.mExtraMessage != null) { 2313 // Suppress WFC Registration notifications if WFC is not enabled by the user. 2314 if (mImsManagerFactory.create(mContext, mPhoneId).isWfcEnabledByUser()) { 2315 processWfcDisconnectForNotification(imsReasonInfo); 2316 } 2317 } 2318 } 2319 2320 // Processes an IMS disconnect cause for possible WFC registration errors and optionally 2321 // disable WFC. processWfcDisconnectForNotification(ImsReasonInfo imsReasonInfo)2322 private void processWfcDisconnectForNotification(ImsReasonInfo imsReasonInfo) { 2323 CarrierConfigManager configManager = 2324 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 2325 if (configManager == null) { 2326 loge("processDisconnectReason: CarrierConfigManager is not ready"); 2327 return; 2328 } 2329 PersistableBundle pb = configManager.getConfigForSubId(getSubId()); 2330 if (pb == null) { 2331 loge("processDisconnectReason: no config for subId " + getSubId()); 2332 return; 2333 } 2334 final String[] wfcOperatorErrorCodes = 2335 pb.getStringArray( 2336 CarrierConfigManager.KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY); 2337 if (wfcOperatorErrorCodes == null) { 2338 // no operator-specific error codes 2339 return; 2340 } 2341 2342 final String[] wfcOperatorErrorAlertMessages = 2343 mContext.getResources().getStringArray( 2344 com.android.internal.R.array.wfcOperatorErrorAlertMessages); 2345 final String[] wfcOperatorErrorNotificationMessages = 2346 mContext.getResources().getStringArray( 2347 com.android.internal.R.array.wfcOperatorErrorNotificationMessages); 2348 2349 for (int i = 0; i < wfcOperatorErrorCodes.length; i++) { 2350 String[] codes = wfcOperatorErrorCodes[i].split("\\|"); 2351 if (codes.length != 2) { 2352 loge("Invalid carrier config: " + wfcOperatorErrorCodes[i]); 2353 continue; 2354 } 2355 2356 // Match error code. 2357 if (!imsReasonInfo.mExtraMessage.startsWith( 2358 codes[0])) { 2359 continue; 2360 } 2361 // If there is no delimiter at the end of error code string 2362 // then we need to verify that we are not matching partial code. 2363 // EXAMPLE: "REG9" must not match "REG99". 2364 // NOTE: Error code must not be empty. 2365 int codeStringLength = codes[0].length(); 2366 char lastChar = codes[0].charAt(codeStringLength - 1); 2367 if (Character.isLetterOrDigit(lastChar)) { 2368 if (imsReasonInfo.mExtraMessage.length() > codeStringLength) { 2369 char nextChar = imsReasonInfo.mExtraMessage.charAt(codeStringLength); 2370 if (Character.isLetterOrDigit(nextChar)) { 2371 continue; 2372 } 2373 } 2374 } 2375 2376 final CharSequence title = mContext.getText( 2377 com.android.internal.R.string.wfcRegErrorTitle); 2378 2379 int idx = Integer.parseInt(codes[1]); 2380 if (idx < 0 2381 || idx >= wfcOperatorErrorAlertMessages.length 2382 || idx >= wfcOperatorErrorNotificationMessages.length) { 2383 loge("Invalid index: " + wfcOperatorErrorCodes[i]); 2384 continue; 2385 } 2386 String messageAlert = imsReasonInfo.mExtraMessage; 2387 String messageNotification = imsReasonInfo.mExtraMessage; 2388 if (!wfcOperatorErrorAlertMessages[idx].isEmpty()) { 2389 messageAlert = String.format( 2390 wfcOperatorErrorAlertMessages[idx], 2391 imsReasonInfo.mExtraMessage); // Fill IMS error code into alert message 2392 } 2393 if (!wfcOperatorErrorNotificationMessages[idx].isEmpty()) { 2394 messageNotification = String.format( 2395 wfcOperatorErrorNotificationMessages[idx], 2396 imsReasonInfo.mExtraMessage); // Fill IMS error code into notification 2397 } 2398 2399 // If WfcSettings are active then alert will be shown 2400 // otherwise notification will be added. 2401 Intent intent = new Intent( 2402 android.telephony.ims.ImsManager.ACTION_WFC_IMS_REGISTRATION_ERROR); 2403 intent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_TITLE, title); 2404 intent.putExtra(EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE, messageAlert); 2405 intent.putExtra(EXTRA_KEY_NOTIFICATION_MESSAGE, messageNotification); 2406 mContext.sendOrderedBroadcast(intent, null, mResultReceiver, 2407 null, Activity.RESULT_OK, null, null); 2408 2409 // We can only match a single error code 2410 // so should break the loop after a successful match. 2411 break; 2412 } 2413 } 2414 2415 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2416 @Override isUtEnabled()2417 public boolean isUtEnabled() { 2418 return mCT.isUtEnabled(); 2419 } 2420 2421 @Override sendEmergencyCallStateChange(boolean callActive)2422 public void sendEmergencyCallStateChange(boolean callActive) { 2423 mDefaultPhone.sendEmergencyCallStateChange(callActive); 2424 } 2425 2426 @Override setBroadcastEmergencyCallStateChanges(boolean broadcast)2427 public void setBroadcastEmergencyCallStateChanges(boolean broadcast) { 2428 mDefaultPhone.setBroadcastEmergencyCallStateChanges(broadcast); 2429 } 2430 2431 @VisibleForTesting getWakeLock()2432 public PowerManager.WakeLock getWakeLock() { 2433 return mWakeLock; 2434 } 2435 2436 /** 2437 * Update roaming state and WFC mode in the following situations: 2438 * 1) voice is in service. 2439 * 2) data is in service. 2440 * @param ss non-null ServiceState 2441 */ updateRoamingState(ServiceState ss)2442 private void updateRoamingState(ServiceState ss) { 2443 if (ss == null) { 2444 loge("updateRoamingState: null ServiceState!"); 2445 return; 2446 } 2447 boolean newRoamingState = ss.getRoaming(); 2448 // Do not recalculate if there is no change to state. 2449 if (mLastKnownRoamingState == newRoamingState) { 2450 return; 2451 } 2452 boolean isInService = (ss.getState() == ServiceState.STATE_IN_SERVICE 2453 || ss.getDataRegistrationState() == ServiceState.STATE_IN_SERVICE); 2454 // If we are not IN_SERVICE for voice or data, ignore change roaming state, as we always 2455 // move to home in this case. 2456 if (!isInService || !mDefaultPhone.isRadioOn()) { 2457 logi("updateRoamingState: we are not IN_SERVICE, ignoring roaming change."); 2458 return; 2459 } 2460 2461 if (mCT.getState() == PhoneConstants.State.IDLE) { 2462 if (DBG) logd("updateRoamingState now: " + newRoamingState); 2463 if (!mFeatureFlags.updateRoamingStateToSetWfcMode()) { 2464 mLastKnownRoamingState = newRoamingState; 2465 } 2466 CarrierConfigManager configManager = (CarrierConfigManager) 2467 getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); 2468 // Don't set wfc mode if carrierconfig has not loaded. It will be set by GsmCdmaPhone 2469 // when receives ACTION_CARRIER_CONFIG_CHANGED broadcast. 2470 if (configManager != null && CarrierConfigManager.isConfigForIdentifiedCarrier( 2471 configManager.getConfigForSubId(getSubId()))) { 2472 ImsManager imsManager = mImsManagerFactory.create(mContext, mPhoneId); 2473 imsManager.setWfcMode(imsManager.getWfcMode(newRoamingState), newRoamingState); 2474 if (mFeatureFlags.updateRoamingStateToSetWfcMode()) { 2475 mLastKnownRoamingState = newRoamingState; 2476 } 2477 } 2478 } else { 2479 if (DBG) logd("updateRoamingState postponed: " + newRoamingState); 2480 mCT.registerForVoiceCallEnded(this, EVENT_VOICE_CALL_ENDED, null); 2481 } 2482 } 2483 getImsMmTelRegistrationCallback()2484 public RegistrationManager.RegistrationCallback getImsMmTelRegistrationCallback() { 2485 return mImsMmTelRegistrationHelper.getCallback(); 2486 } 2487 2488 /** 2489 * Reset the IMS registration state. 2490 */ resetImsRegistrationState()2491 public void resetImsRegistrationState() { 2492 if (DBG) logd("resetImsRegistrationState"); 2493 mImsMmTelRegistrationHelper.reset(); 2494 int subId = getSubId(); 2495 if (SubscriptionManager.isValidSubscriptionId(subId)) { 2496 updateImsRegistrationInfo(REGISTRATION_STATE_NOT_REGISTERED, 2497 REGISTRATION_TECH_NONE, SUGGESTED_ACTION_NONE, TRANSPORT_TYPE_INVALID); 2498 } 2499 } 2500 2501 private ImsRegistrationCallbackHelper.ImsRegistrationUpdate mMmTelRegistrationUpdate = new 2502 ImsRegistrationCallbackHelper.ImsRegistrationUpdate() { 2503 @Override 2504 public void handleImsRegistered(@NonNull ImsRegistrationAttributes attributes) { 2505 int imsTransportType = attributes.getTransportType(); 2506 if (DBG) { 2507 logd("handleImsRegistered: onImsMmTelConnected imsTransportType=" 2508 + AccessNetworkConstants.transportTypeToString(imsTransportType)); 2509 } 2510 mRegLocalLog.log("handleImsRegistered: onImsMmTelConnected imsTransportType=" 2511 + AccessNetworkConstants.transportTypeToString(imsTransportType)); 2512 setServiceState(ServiceState.STATE_IN_SERVICE); 2513 getDefaultPhone().setImsRegistrationState(true); 2514 mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.CONNECTED, null); 2515 mImsStats.onImsRegistered(attributes); 2516 mImsNrSaModeHandler.onImsRegistered( 2517 attributes.getRegistrationTechnology(), attributes.getFeatureTags()); 2518 updateImsRegistrationInfo(REGISTRATION_STATE_REGISTERED, 2519 attributes.getRegistrationTechnology(), SUGGESTED_ACTION_NONE, 2520 imsTransportType); 2521 2522 AsyncResult ar; 2523 if (mFeatureFlags.changeMethodOfObtainingImsRegistrationRadioTech()) { 2524 ar = new AsyncResult(null, new ImsRegistrationRadioTechInfo(mPhoneId, 2525 attributes.getRegistrationTechnology(), REGISTRATION_STATE_REGISTERED), 2526 null); 2527 } else { 2528 ar = new AsyncResult(null, null, null); 2529 } 2530 mImsRegistrationUpdateRegistrants.notifyRegistrants(ar); 2531 } 2532 2533 @Override 2534 public void handleImsRegistering(int imsRadioTech) { 2535 if (DBG) { 2536 logd("handleImsRegistering: onImsMmTelProgressing imsRadioTech=" 2537 + AccessNetworkConstants.transportTypeToString(imsRadioTech)); 2538 } 2539 mRegLocalLog.log("handleImsRegistering: onImsMmTelProgressing imsRadioTech=" 2540 + AccessNetworkConstants.transportTypeToString(imsRadioTech)); 2541 setServiceState(ServiceState.STATE_OUT_OF_SERVICE); 2542 getDefaultPhone().setImsRegistrationState(false); 2543 mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.PROGRESSING, 2544 null); 2545 mImsStats.onImsRegistering(imsRadioTech); 2546 2547 AsyncResult ar; 2548 if (mFeatureFlags.changeMethodOfObtainingImsRegistrationRadioTech()) { 2549 ar = new AsyncResult(null, new ImsRegistrationRadioTechInfo(mPhoneId, 2550 imsRadioTech, REGISTRATION_STATE_REGISTERING), 2551 null); 2552 } else { 2553 ar = new AsyncResult(null, null, null); 2554 } 2555 mImsRegistrationUpdateRegistrants.notifyRegistrants(ar); 2556 } 2557 2558 @Override 2559 public void handleImsUnregistered(ImsReasonInfo imsReasonInfo, 2560 @RegistrationManager.SuggestedAction int suggestedAction, 2561 @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) { 2562 if (DBG) { 2563 logd("handleImsUnregistered: onImsMmTelDisconnected imsReasonInfo=" 2564 + imsReasonInfo + ", suggestedAction=" + suggestedAction 2565 + ", disconnectedRadioTech=" + imsRadioTech); 2566 } 2567 mRegLocalLog.log("handleImsUnregistered: onImsMmTelDisconnected imsRadioTech=" 2568 + imsReasonInfo); 2569 setServiceState(ServiceState.STATE_OUT_OF_SERVICE); 2570 processDisconnectReason(imsReasonInfo); 2571 getDefaultPhone().setImsRegistrationState(false); 2572 mMetrics.writeOnImsConnectionState(mPhoneId, ImsConnectionState.State.DISCONNECTED, 2573 imsReasonInfo); 2574 mImsStats.onImsUnregistered(imsReasonInfo); 2575 mImsNrSaModeHandler.onImsUnregistered(imsRadioTech); 2576 mImsRegistrationTech = REGISTRATION_TECH_NONE; 2577 int suggestedModemAction = SUGGESTED_ACTION_NONE; 2578 if (imsReasonInfo.getCode() == ImsReasonInfo.CODE_REGISTRATION_ERROR) { 2579 if ((suggestedAction == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK) 2580 || (suggestedAction == SUGGESTED_ACTION_TRIGGER_PLMN_BLOCK_WITH_TIMEOUT)) { 2581 suggestedModemAction = suggestedAction; 2582 } else if (mFeatureFlags.addRatRelatedSuggestedActionToImsRegistration()) { 2583 if ((suggestedAction == SUGGESTED_ACTION_TRIGGER_RAT_BLOCK) 2584 || (suggestedAction == SUGGESTED_ACTION_TRIGGER_CLEAR_RAT_BLOCKS)) { 2585 suggestedModemAction = suggestedAction; 2586 } 2587 } 2588 } 2589 updateImsRegistrationInfo(REGISTRATION_STATE_NOT_REGISTERED, 2590 imsRadioTech, suggestedModemAction, TRANSPORT_TYPE_INVALID); 2591 2592 if (mFeatureFlags.clearCachedImsPhoneNumberWhenDeviceLostImsRegistration()) { 2593 // Clear the phone number from P-Associated-Uri 2594 setCurrentSubscriberUris(null); 2595 clearPhoneNumberForSourceIms(); 2596 } 2597 2598 AsyncResult ar; 2599 if (mFeatureFlags.changeMethodOfObtainingImsRegistrationRadioTech()) { 2600 ar = new AsyncResult(null, new ImsRegistrationRadioTechInfo(mPhoneId, 2601 REGISTRATION_TECH_NONE, REGISTRATION_STATE_NOT_REGISTERED), 2602 null); 2603 } else { 2604 ar = new AsyncResult(null, null, null); 2605 } 2606 mImsRegistrationUpdateRegistrants.notifyRegistrants(ar); 2607 } 2608 2609 @Override 2610 public void handleImsSubscriberAssociatedUriChanged(Uri[] uris) { 2611 if (DBG) logd("handleImsSubscriberAssociatedUriChanged"); 2612 setCurrentSubscriberUris(uris); 2613 setPhoneNumberForSourceIms(uris); 2614 } 2615 }; 2616 2617 /** Clear the IMS phone number from IMS associated Uris when IMS registration is lost. */ 2618 @VisibleForTesting clearPhoneNumberForSourceIms()2619 public void clearPhoneNumberForSourceIms() { 2620 int subId = getSubId(); 2621 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 2622 return; 2623 } 2624 2625 if (DBG) logd("clearPhoneNumberForSourceIms"); 2626 mSubscriptionManagerService.setNumberFromIms(subId, new String("")); 2627 } 2628 2629 /** Sets the IMS phone number from IMS associated URIs, if any found. */ 2630 @VisibleForTesting setPhoneNumberForSourceIms(Uri[] uris)2631 public void setPhoneNumberForSourceIms(Uri[] uris) { 2632 int subId = getSubId(); 2633 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 2634 // Defending b/219080264: 2635 // SubscriptionManagerService.setSubscriptionProperty validates input subId 2636 // so do not proceed if subId invalid. This may be happening because cached 2637 // IMS callbacks are sent back to telephony after SIM state changed. 2638 return; 2639 } 2640 SubscriptionInfoInternal subInfo = mSubscriptionManagerService 2641 .getSubscriptionInfoInternal(subId); 2642 if (subInfo == null) { 2643 loge("trigger setPhoneNumberForSourceIms, but subInfo is null"); 2644 return; 2645 } 2646 String subCountryIso = subInfo.getCountryIso(); 2647 String phoneNumber = extractPhoneNumberFromAssociatedUris(uris, /*isGlobalFormat*/true); 2648 if (phoneNumber != null) { 2649 phoneNumber = PhoneNumberUtils.formatNumberToE164(phoneNumber, subCountryIso); 2650 if (phoneNumber == null) { 2651 loge("format to E164 failed"); 2652 return; 2653 } 2654 mSubscriptionManagerService.setNumberFromIms(subId, phoneNumber); 2655 } else if (isAllowNonGlobalNumberFormat()) { 2656 // If carrier config has true for KEY_IGNORE_GLOBAL_PHONE_NUMBER_FORMAT_BOOL and 2657 // P-Associated-Uri does not have global number, 2658 // try to find phone number excluding '+' one more time. 2659 phoneNumber = extractPhoneNumberFromAssociatedUris(uris, /*isGlobalFormat*/false); 2660 if (phoneNumber == null) { 2661 loge("extract phone number without '+' failed"); 2662 return; 2663 } 2664 mSubscriptionManagerService.setNumberFromIms(subId, phoneNumber); 2665 } else { 2666 logd("extract phone number failed"); 2667 } 2668 } 2669 2670 /** 2671 * Finds the phone number from associated URIs. 2672 * 2673 * <p>Associated URIs are public user identities, and phone number could be used: 2674 * see 3GPP TS 24.229 5.4.1.2 and 3GPP TS 23.003 13.4. This algotihm look for the 2675 * possible "global number" in E.164 format. 2676 * <p>If true try finding phone number even if the P-Associated-Uri does not have global 2677 * number format. 2678 */ extractPhoneNumberFromAssociatedUris(Uri[] uris, boolean isGlobalFormat)2679 private static String extractPhoneNumberFromAssociatedUris(Uri[] uris, boolean isGlobalFormat) { 2680 if (uris == null) { 2681 return null; 2682 } 2683 2684 Stream<String> intermediate = Arrays.stream(uris) 2685 // Phone number is an opaque URI "tel:<phone-number>" or "sip:<phone-number>@<...>" 2686 .filter(u -> u != null && u.isOpaque()) 2687 .filter(u -> "tel".equalsIgnoreCase(u.getScheme()) 2688 || "sip".equalsIgnoreCase(u.getScheme())) 2689 .map(Uri::getSchemeSpecificPart); 2690 2691 if (isGlobalFormat) { 2692 // "Global number" should be in E.164 format starting with "+" e.g. "+447539447777" 2693 return intermediate.filter(ssp -> ssp != null && ssp.startsWith("+")) 2694 // Remove whatever after "@" for sip URI 2695 .map(ssp -> ssp.split("@")[0]) 2696 // Returns the first winner 2697 .findFirst() 2698 .orElse(null); 2699 } else { 2700 // non global number format 2701 return intermediate.filter(ssp -> ssp != null) 2702 // Remove whatever after "@" for sip URI 2703 .map(ssp -> ssp.split("@")[0]) 2704 // regular expression, allow only number 2705 .filter(ssp -> ssp.matches("^[0-9]+$")) 2706 // Returns the first winner 2707 .findFirst() 2708 .orElse(null); 2709 } 2710 } 2711 getIccRecords()2712 public IccRecords getIccRecords() { 2713 return mDefaultPhone.getIccRecords(); 2714 } 2715 updateDialArgsForVolteSilentRedial(DialArgs dialArgs, int causeCode)2716 public DialArgs updateDialArgsForVolteSilentRedial(DialArgs dialArgs, int causeCode) { 2717 if (dialArgs != null) { 2718 ImsPhone.ImsDialArgs.Builder imsDialArgsBuilder; 2719 imsDialArgsBuilder = ImsPhone.ImsDialArgs.Builder.from(dialArgs); 2720 2721 Bundle extras = new Bundle(dialArgs.intentExtras); 2722 if (causeCode == CallFailCause.EMC_REDIAL_ON_VOWIFI) { 2723 extras.putString(ImsCallProfile.EXTRA_CALL_RAT_TYPE, 2724 String.valueOf(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)); 2725 logd("trigger VoWifi emergency call"); 2726 imsDialArgsBuilder.setIntentExtras(extras); 2727 } else if (causeCode == CallFailCause.EMC_REDIAL_ON_IMS) { 2728 logd("trigger VoLte emergency call"); 2729 } 2730 return imsDialArgsBuilder.build(); 2731 } 2732 return new DialArgs.Builder<>().build(); 2733 } 2734 2735 @Override getVoiceCallSessionStats()2736 public VoiceCallSessionStats getVoiceCallSessionStats() { 2737 return mDefaultPhone.getVoiceCallSessionStats(); 2738 } 2739 2740 /** Returns the {@link ImsStats} for this IMS phone. */ getImsStats()2741 public ImsStats getImsStats() { 2742 return mImsStats; 2743 } 2744 2745 /** Returns the {@link AccessNetworkConstants.TransportType} used to register this IMS phone. */ getTransportType()2746 public @AccessNetworkConstants.TransportType int getTransportType() { 2747 return mTransportType; 2748 } 2749 2750 /** Sets the {@link ImsStats} mock for this IMS phone during unit testing. */ 2751 @VisibleForTesting setImsStats(ImsStats imsStats)2752 public void setImsStats(ImsStats imsStats) { 2753 mImsStats = imsStats; 2754 } 2755 hasAliveCall()2756 public boolean hasAliveCall() { 2757 return (getForegroundCall().getState() != Call.State.IDLE || 2758 getBackgroundCall().getState() != Call.State.IDLE); 2759 } 2760 getLastKnownRoamingState()2761 public boolean getLastKnownRoamingState() { 2762 return mLastKnownRoamingState; 2763 } 2764 2765 /** 2766 * Update IMS registration information to modem. 2767 * 2768 * @param capabilities indicate MMTEL capability such as VOICE, VIDEO and SMS. 2769 */ updateImsRegistrationInfo(int capabilities)2770 public void updateImsRegistrationInfo(int capabilities) { 2771 if (mImsRegistrationState == REGISTRATION_STATE_REGISTERED) { 2772 if (mNotifiedRegisteredState && (capabilities == mImsRegistrationCapabilities)) { 2773 // Duplicated notification, no change in capabilities. 2774 return; 2775 } 2776 2777 mImsRegistrationCapabilities = capabilities; 2778 if (capabilities == 0) { 2779 // Ignore this as this usually happens just before onUnregistered callback. 2780 // We can notify modem when onUnregistered() flow occurs. 2781 return; 2782 } 2783 2784 mDefaultPhone.mCi.updateImsRegistrationInfo(mImsRegistrationState, 2785 mImsRegistrationTech, 0, capabilities, null); 2786 mNotifiedRegisteredState = true; 2787 } 2788 } 2789 2790 /** 2791 * Update IMS registration info 2792 * 2793 * @param regState indicates IMS registration state. 2794 * @param imsRadioTech indicates the type of the radio access network where IMS is registered. 2795 * @param suggestedAction indicates the suggested action for the radio to perform. 2796 */ updateImsRegistrationInfo( @egistrationManager.ImsRegistrationState int regState, @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech, @RegistrationManager.SuggestedAction int suggestedAction, @AccessNetworkConstants.TransportType int transportType)2797 private void updateImsRegistrationInfo( 2798 @RegistrationManager.ImsRegistrationState int regState, 2799 @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech, 2800 @RegistrationManager.SuggestedAction int suggestedAction, 2801 @AccessNetworkConstants.TransportType int transportType) { 2802 2803 if (regState == mImsRegistrationState) { 2804 // In NOT_REGISTERED state, the current PLMN can be blocked with a suggested action. 2805 // But in this case, the same behavior is able to occur in different PLMNs with 2806 // same radio tech and suggested action. 2807 if ((regState == REGISTRATION_STATE_REGISTERED && imsRadioTech == mImsRegistrationTech) 2808 || (regState == REGISTRATION_STATE_NOT_REGISTERED 2809 && suggestedAction == SUGGESTED_ACTION_NONE 2810 && mImsRegistrationSuggestedAction == SUGGESTED_ACTION_NONE 2811 && imsRadioTech == mImsDeregistrationTech)) { 2812 // Filter duplicate notification. 2813 return; 2814 } 2815 } 2816 2817 if (regState == REGISTRATION_STATE_NOT_REGISTERED) { 2818 mDefaultPhone.mCi.updateImsRegistrationInfo(regState, 2819 imsRadioTech, suggestedAction, 0, null); 2820 } else if (mImsRegistrationState == REGISTRATION_STATE_REGISTERED) { 2821 // This happens when radio tech is changed while in REGISTERED state. 2822 if (mImsRegistrationCapabilities > 0) { 2823 // Capability has been updated. Notify REGISTRATION_STATE_REGISTERED. 2824 mDefaultPhone.mCi.updateImsRegistrationInfo(regState, imsRadioTech, 0, 2825 mImsRegistrationCapabilities, null); 2826 mImsRegistrationTech = imsRadioTech; 2827 mTransportType = transportType; 2828 mNotifiedRegisteredState = true; 2829 return; 2830 } 2831 } 2832 2833 mImsRegistrationState = regState; 2834 mImsRegistrationTech = imsRadioTech; 2835 mTransportType = transportType; 2836 mImsRegistrationSuggestedAction = suggestedAction; 2837 if (regState == REGISTRATION_STATE_NOT_REGISTERED) { 2838 mImsDeregistrationTech = imsRadioTech; 2839 } else { 2840 mImsDeregistrationTech = REGISTRATION_TECH_NONE; 2841 } 2842 mImsRegistrationCapabilities = 0; 2843 // REGISTRATION_STATE_REGISTERED will be notified when the capability is updated. 2844 mNotifiedRegisteredState = false; 2845 } 2846 2847 @Override setTerminalBasedCallWaitingStatus(int state)2848 public void setTerminalBasedCallWaitingStatus(int state) { 2849 mCT.setTerminalBasedCallWaitingStatus(state); 2850 } 2851 2852 @Override triggerEpsFallback(@mTelFeature.EpsFallbackReason int reason, Message response)2853 public void triggerEpsFallback(@MmTelFeature.EpsFallbackReason int reason, Message response) { 2854 mDefaultPhone.triggerEpsFallback(reason, response); 2855 } 2856 2857 @Override startImsTraffic(int token, @MmTelFeature.ImsTrafficType int trafficType, @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, @MmTelFeature.ImsTrafficDirection int trafficDirection, Message response)2858 public void startImsTraffic(int token, 2859 @MmTelFeature.ImsTrafficType int trafficType, 2860 @AccessNetworkConstants.RadioAccessNetworkType int accessNetworkType, 2861 @MmTelFeature.ImsTrafficDirection int trafficDirection, Message response) { 2862 mDefaultPhone.startImsTraffic(token, trafficType, 2863 accessNetworkType, trafficDirection, response); 2864 } 2865 2866 @Override stopImsTraffic(int token, Message response)2867 public void stopImsTraffic(int token, Message response) { 2868 mDefaultPhone.stopImsTraffic(token, response); 2869 } 2870 2871 @Override registerForConnectionSetupFailure(Handler h, int what, Object obj)2872 public void registerForConnectionSetupFailure(Handler h, int what, Object obj) { 2873 mDefaultPhone.registerForConnectionSetupFailure(h, what, obj); 2874 } 2875 2876 @Override unregisterForConnectionSetupFailure(Handler h)2877 public void unregisterForConnectionSetupFailure(Handler h) { 2878 mDefaultPhone.unregisterForConnectionSetupFailure(h); 2879 } 2880 2881 @Override triggerImsDeregistration( @msRegistrationImplBase.ImsDeregistrationReason int reason)2882 public void triggerImsDeregistration( 2883 @ImsRegistrationImplBase.ImsDeregistrationReason int reason) { 2884 mCT.triggerImsDeregistration(reason); 2885 } 2886 2887 @Override updateImsCallStatus(List<ImsCallInfo> imsCallInfo, Message response)2888 public void updateImsCallStatus(List<ImsCallInfo> imsCallInfo, Message response) { 2889 mDefaultPhone.updateImsCallStatus(imsCallInfo, response); 2890 } 2891 2892 @Override triggerNotifyAnbr(int mediaType, int direction, int bitsPerSecond)2893 public void triggerNotifyAnbr(int mediaType, int direction, int bitsPerSecond) { 2894 mCT.triggerNotifyAnbr(mediaType, direction, bitsPerSecond); 2895 } 2896 2897 /** 2898 * Check whether making a call using Wi-Fi is possible or not. 2899 * @return {code true} if IMS is registered over IWLAN else return {code false}. 2900 */ canMakeWifiCall()2901 public boolean canMakeWifiCall() { 2902 return isImsRegistered() && (getImsRegistrationTech() 2903 == ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); 2904 } 2905 2906 @Override dump(FileDescriptor fd, PrintWriter printWriter, String[] args)2907 public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { 2908 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 2909 pw.println("ImsPhone extends:"); 2910 super.dump(fd, pw, args); 2911 pw.flush(); 2912 2913 pw.println("ImsPhone:"); 2914 pw.println(" mDefaultPhone = " + mDefaultPhone); 2915 pw.println(" mPendingMMIs = " + mPendingMMIs); 2916 pw.println(" mPostDialHandler = " + mPostDialHandler); 2917 pw.println(" mSS = " + mSS); 2918 pw.println(" mWakeLock = " + mWakeLock); 2919 pw.println(" mIsPhoneInEcmState = " + isInEcm()); 2920 pw.println(" mEcmExitRespRegistrant = " + mEcmExitRespRegistrant); 2921 pw.println(" mSilentRedialRegistrants = " + mSilentRedialRegistrants); 2922 pw.println(" mImsMmTelRegistrationState = " 2923 + mImsMmTelRegistrationHelper.getImsRegistrationState()); 2924 pw.println(" mLastKnownRoamingState = " + mLastKnownRoamingState); 2925 pw.println(" mSsnRegistrants = " + mSsnRegistrants); 2926 pw.println(" Registration Log:"); 2927 pw.increaseIndent(); 2928 mRegLocalLog.dump(pw); 2929 pw.decreaseIndent(); 2930 pw.flush(); 2931 } 2932 isAllowNonGlobalNumberFormat()2933 private boolean isAllowNonGlobalNumberFormat() { 2934 PersistableBundle persistableBundle = null; 2935 CarrierConfigManager carrierConfigManager = (CarrierConfigManager) mContext 2936 .getSystemService(Context.CARRIER_CONFIG_SERVICE); 2937 if (carrierConfigManager != null) { 2938 persistableBundle = carrierConfigManager.getConfigForSubId(getSubId(), 2939 CarrierConfigManager.Ims.KEY_ALLOW_NON_GLOBAL_PHONE_NUMBER_FORMAT_BOOL); 2940 } 2941 if (persistableBundle != null) { 2942 return persistableBundle.getBoolean( 2943 CarrierConfigManager.Ims.KEY_ALLOW_NON_GLOBAL_PHONE_NUMBER_FORMAT_BOOL, false); 2944 } 2945 2946 return false; 2947 } 2948 logi(String s)2949 private void logi(String s) { 2950 Rlog.i(LOG_TAG, "[" + mPhoneId + "] " + s); 2951 } 2952 logv(String s)2953 private void logv(String s) { 2954 Rlog.v(LOG_TAG, "[" + mPhoneId + "] " + s); 2955 } 2956 logd(String s)2957 private void logd(String s) { 2958 Rlog.d(LOG_TAG, "[" + mPhoneId + "] " + s); 2959 } 2960 loge(String s)2961 private void loge(String s) { 2962 Rlog.e(LOG_TAG, "[" + mPhoneId + "] " + s); 2963 } 2964 } 2965