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.ims; 18 19 import static android.telephony.ims.ProvisioningManager.KEY_VOIMS_OPT_IN_STATUS; 20 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT; 21 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO; 22 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE; 23 import static android.telephony.ims.feature.RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE; 24 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; 25 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; 26 27 import android.annotation.NonNull; 28 import android.app.PendingIntent; 29 import android.compat.annotation.UnsupportedAppUsage; 30 import android.content.ContentResolver; 31 import android.content.Context; 32 import android.content.pm.PackageManager; 33 import android.os.Build; 34 import android.os.Message; 35 import android.os.PersistableBundle; 36 import android.os.RemoteException; 37 import android.os.ServiceSpecificException; 38 import android.os.SystemProperties; 39 import android.provider.Settings; 40 import android.telecom.TelecomManager; 41 import android.telephony.AccessNetworkConstants; 42 import android.telephony.BinderCacheManager; 43 import android.telephony.CarrierConfigManager; 44 import android.telephony.ServiceState; 45 import android.telephony.SubscriptionManager; 46 import android.telephony.TelephonyFrameworkInitializer; 47 import android.telephony.TelephonyManager; 48 import android.telephony.ims.ImsCallProfile; 49 import android.telephony.ims.ImsCallSession; 50 import android.telephony.ims.ImsMmTelManager; 51 import android.telephony.ims.ImsReasonInfo; 52 import android.telephony.ims.ImsService; 53 import android.telephony.ims.MediaQualityStatus; 54 import android.telephony.ims.MediaThreshold; 55 import android.telephony.ims.ProvisioningManager; 56 import android.telephony.ims.RegistrationManager; 57 import android.telephony.ims.RtpHeaderExtensionType; 58 import android.telephony.ims.SrvccCall; 59 import android.telephony.ims.aidl.IImsCapabilityCallback; 60 import android.telephony.ims.aidl.IImsConfig; 61 import android.telephony.ims.aidl.IImsConfigCallback; 62 import android.telephony.ims.aidl.IImsMmTelFeature; 63 import android.telephony.ims.aidl.IImsRegistration; 64 import android.telephony.ims.aidl.IImsRegistrationCallback; 65 import android.telephony.ims.aidl.IImsSmsListener; 66 import android.telephony.ims.aidl.ISipTransport; 67 import android.telephony.ims.aidl.ISrvccStartedCallback; 68 import android.telephony.ims.feature.CapabilityChangeRequest; 69 import android.telephony.ims.feature.ImsFeature; 70 import android.telephony.ims.feature.MmTelFeature; 71 import android.telephony.ims.stub.ImsCallSessionImplBase; 72 import android.telephony.ims.stub.ImsRegistrationImplBase; 73 import android.util.SparseArray; 74 75 import com.android.ims.internal.IImsCallSession; 76 import com.android.ims.internal.IImsServiceFeatureCallback; 77 import com.android.internal.annotations.VisibleForTesting; 78 import com.android.internal.telephony.flags.Flags; 79 import com.android.internal.telephony.ITelephony; 80 import com.android.telephony.Rlog; 81 82 import java.io.FileDescriptor; 83 import java.io.PrintWriter; 84 import java.util.ArrayList; 85 import java.util.Arrays; 86 import java.util.Set; 87 import java.util.concurrent.BlockingQueue; 88 import java.util.concurrent.CountDownLatch; 89 import java.util.concurrent.Executor; 90 import java.util.concurrent.Executors; 91 import java.util.concurrent.LinkedBlockingDeque; 92 import java.util.concurrent.TimeUnit; 93 import java.util.concurrent.atomic.AtomicReference; 94 import java.util.function.Consumer; 95 96 /** 97 * Provides APIs for MMTEL IMS services, such as initiating IMS calls, and provides access to 98 * the operator's IMS network. This class is the starting point for any IMS MMTEL actions. 99 * You can acquire an instance of it with {@link #getInstance getInstance()}. 100 * {Use {@link RcsFeatureManager} for RCS services}. 101 * For internal use ONLY! Use {@link ImsMmTelManager} instead. 102 * @hide 103 */ 104 public class ImsManager implements FeatureUpdates { 105 106 /* 107 * Debug flag to override configuration flag 108 */ 109 public static final String PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr"; 110 public static final int PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT = 0; 111 public static final String PROPERTY_DBG_VT_AVAIL_OVERRIDE = "persist.dbg.vt_avail_ovr"; 112 public static final int PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT = 0; 113 public static final String PROPERTY_DBG_WFC_AVAIL_OVERRIDE = "persist.dbg.wfc_avail_ovr"; 114 public static final int PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT = 0; 115 public static final String PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE = "persist.dbg.allow_ims_off"; 116 public static final int PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE_DEFAULT = 0; 117 118 /** 119 * The result code to be sent back with the incoming call {@link PendingIntent}. 120 * @see #open(MmTelFeature.Listener) 121 */ 122 public static final int INCOMING_CALL_RESULT_CODE = 101; 123 124 /** 125 * Key to retrieve the call ID from an incoming call intent. No longer used, see 126 * {@link ImsCallSessionImplBase#getCallId()}. 127 * @deprecated Not used in the framework, keeping around symbol to not break old vendor 128 * components. 129 */ 130 @Deprecated 131 public static final String EXTRA_CALL_ID = "android:imsCallID"; 132 133 /** 134 * Action to broadcast when ImsService is up. 135 * Internal use only. 136 * @deprecated 137 * @hide 138 */ 139 public static final String ACTION_IMS_SERVICE_UP = 140 "com.android.ims.IMS_SERVICE_UP"; 141 142 /** 143 * Action to broadcast when ImsService is down. 144 * Internal use only. 145 * @deprecated 146 * @hide 147 */ 148 public static final String ACTION_IMS_SERVICE_DOWN = 149 "com.android.ims.IMS_SERVICE_DOWN"; 150 151 /** 152 * Action to broadcast when ImsService registration fails. 153 * Internal use only. 154 * @hide 155 * @deprecated use {@link android.telephony.ims.ImsManager#ACTION_WFC_IMS_REGISTRATION_ERROR} 156 * instead. 157 */ 158 @Deprecated 159 public static final String ACTION_IMS_REGISTRATION_ERROR = 160 android.telephony.ims.ImsManager.ACTION_WFC_IMS_REGISTRATION_ERROR; 161 162 /** 163 * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents. 164 * A long value; the phone ID corresponding to the IMS service coming up or down. 165 * Internal use only. 166 * @hide 167 */ 168 public static final String EXTRA_PHONE_ID = "android:phone_id"; 169 170 /** 171 * Action for the incoming call intent for the Phone app. 172 * Internal use only. 173 * @hide 174 */ 175 public static final String ACTION_IMS_INCOMING_CALL = 176 "com.android.ims.IMS_INCOMING_CALL"; 177 178 /** 179 * Part of the ACTION_IMS_INCOMING_CALL intents. 180 * An integer value; service identifier obtained from {@link ImsManager#open}. 181 * Internal use only. 182 * @hide 183 * @deprecated Not used in the system, keeping around to not break old vendor components. 184 */ 185 @Deprecated 186 public static final String EXTRA_SERVICE_ID = "android:imsServiceId"; 187 188 /** 189 * Part of the ACTION_IMS_INCOMING_CALL intents. 190 * An boolean value; Flag to indicate that the incoming call is a normal call or call for USSD. 191 * The value "true" indicates that the incoming call is for USSD. 192 * Internal use only. 193 * @deprecated Keeping around to not break old vendor components. Use 194 * {@link MmTelFeature#EXTRA_IS_USSD} instead. 195 * @hide 196 */ 197 public static final String EXTRA_USSD = "android:ussd"; 198 199 /** 200 * Part of the ACTION_IMS_INCOMING_CALL intents. 201 * A boolean value; Flag to indicate whether the call is an unknown 202 * dialing call. Such calls are originated by sending commands (like 203 * AT commands) directly to modem without Android involvement. 204 * Even though they are not incoming calls, they are propagated 205 * to Phone app using same ACTION_IMS_INCOMING_CALL intent. 206 * Internal use only. 207 * @deprecated Keeping around to not break old vendor components. Use 208 * {@link MmTelFeature#EXTRA_IS_UNKNOWN_CALL} instead. 209 * @hide 210 */ 211 public static final String EXTRA_IS_UNKNOWN_CALL = "android:isUnknown"; 212 213 private static final int SUBINFO_PROPERTY_FALSE = 0; 214 215 private static final int SYSTEM_PROPERTY_NOT_SET = -1; 216 217 // -1 indicates a subscriptionProperty value that is never set. 218 private static final int SUB_PROPERTY_NOT_INITIALIZED = -1; 219 220 private static final String TAG = "ImsManager"; 221 private static final boolean DBG = true; 222 223 private static final int RESPONSE_WAIT_TIME_MS = 3000; 224 225 private static final int[] LOCAL_IMS_CONFIG_KEYS = { 226 KEY_VOIMS_OPT_IN_STATUS 227 }; 228 229 /** 230 * Create a Lazy Executor that is not instantiated for this instance unless it is used. This 231 * is to stop threads from being started on ImsManagers that are created to do simple tasks. 232 */ 233 private static class LazyExecutor implements Executor { 234 private Executor mExecutor; 235 236 @Override execute(Runnable runnable)237 public void execute(Runnable runnable) { 238 startExecutorIfNeeded(); 239 mExecutor.execute(runnable); 240 } 241 startExecutorIfNeeded()242 private synchronized void startExecutorIfNeeded() { 243 if (mExecutor != null) return; 244 mExecutor = Executors.newSingleThreadExecutor(); 245 } 246 } 247 248 @VisibleForTesting 249 public interface MmTelFeatureConnectionFactory { create(Context context, int phoneId, int subId, IImsMmTelFeature feature, IImsConfig c, IImsRegistration r, ISipTransport s)250 MmTelFeatureConnection create(Context context, int phoneId, int subId, 251 IImsMmTelFeature feature, IImsConfig c, IImsRegistration r, ISipTransport s); 252 } 253 254 @VisibleForTesting 255 public interface SettingsProxy { 256 /** @see Settings.Secure#getInt(ContentResolver, String, int) */ getSecureIntSetting(ContentResolver cr, String name, int def)257 int getSecureIntSetting(ContentResolver cr, String name, int def); 258 /** @see Settings.Secure#putInt(ContentResolver, String, int) */ putSecureIntSetting(ContentResolver cr, String name, int value)259 boolean putSecureIntSetting(ContentResolver cr, String name, int value); 260 } 261 262 @VisibleForTesting 263 public interface SubscriptionManagerProxy { isValidSubscriptionId(int subId)264 boolean isValidSubscriptionId(int subId); getSubscriptionId(int slotIndex)265 int getSubscriptionId(int slotIndex); getDefaultVoicePhoneId()266 int getDefaultVoicePhoneId(); getIntegerSubscriptionProperty(int subId, String propKey, int defValue)267 int getIntegerSubscriptionProperty(int subId, String propKey, int defValue); setSubscriptionProperty(int subId, String propKey, String propValue)268 void setSubscriptionProperty(int subId, String propKey, String propValue); getActiveSubscriptionIdList()269 int[] getActiveSubscriptionIdList(); 270 } 271 272 // Default implementations, which is mocked for testing 273 private static class DefaultSettingsProxy implements SettingsProxy { 274 @Override getSecureIntSetting(ContentResolver cr, String name, int def)275 public int getSecureIntSetting(ContentResolver cr, String name, int def) { 276 return Settings.Secure.getInt(cr, name, def); 277 } 278 279 @Override putSecureIntSetting(ContentResolver cr, String name, int value)280 public boolean putSecureIntSetting(ContentResolver cr, String name, int value) { 281 return Settings.Secure.putInt(cr, name, value); 282 } 283 } 284 285 // Default implementation which is mocked to make static dependency validation easier. 286 private static class DefaultSubscriptionManagerProxy implements SubscriptionManagerProxy { 287 288 private Context mContext; 289 DefaultSubscriptionManagerProxy(Context context)290 public DefaultSubscriptionManagerProxy(Context context) { 291 mContext = context; 292 } 293 294 @Override isValidSubscriptionId(int subId)295 public boolean isValidSubscriptionId(int subId) { 296 return SubscriptionManager.isValidSubscriptionId(subId); 297 } 298 299 @Override getSubscriptionId(int slotIndex)300 public int getSubscriptionId(int slotIndex) { 301 return SubscriptionManager.getSubscriptionId(slotIndex); 302 } 303 304 @Override getDefaultVoicePhoneId()305 public int getDefaultVoicePhoneId() { 306 return SubscriptionManager.getDefaultVoicePhoneId(); 307 } 308 309 @Override getIntegerSubscriptionProperty(int subId, String propKey, int defValue)310 public int getIntegerSubscriptionProperty(int subId, String propKey, int defValue) { 311 return SubscriptionManager.getIntegerSubscriptionProperty(subId, propKey, defValue, 312 mContext); 313 } 314 315 @Override setSubscriptionProperty(int subId, String propKey, String propValue)316 public void setSubscriptionProperty(int subId, String propKey, String propValue) { 317 SubscriptionManager.setSubscriptionProperty(subId, propKey, propValue); 318 } 319 320 @Override getActiveSubscriptionIdList()321 public int[] getActiveSubscriptionIdList() { 322 return getSubscriptionManager().getActiveSubscriptionIdList(); 323 } 324 getSubscriptionManager()325 private SubscriptionManager getSubscriptionManager() { 326 return mContext.getSystemService(SubscriptionManager.class); 327 } 328 } 329 330 /** 331 * Events that will be triggered as part of metrics collection. 332 */ 333 public interface ImsStatsCallback { 334 /** 335 * The MmTel capabilities that are enabled have changed. 336 * @param capability The MmTel capability 337 * @param regTech The IMS registration technology associated with the capability. 338 * @param isEnabled {@code true} if the capability is enabled, {@code false} if it is 339 * disabled. 340 */ onEnabledMmTelCapabilitiesChanged( @mTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int regTech, boolean isEnabled)341 void onEnabledMmTelCapabilitiesChanged( 342 @MmTelFeature.MmTelCapabilities.MmTelCapability int capability, 343 @ImsRegistrationImplBase.ImsRegistrationTech int regTech, 344 boolean isEnabled); 345 } 346 347 /** 348 * Internally we will create a FeatureConnector when {@link #getInstance(Context, int)} is 349 * called to keep the MmTelFeatureConnection instance fresh as new SIM cards are 350 * inserted/removed and MmTelFeature potentially changes. 351 * <p> 352 * For efficiency purposes, there is only one ImsManager created per-slot when using 353 * {@link #getInstance(Context, int)} and the same instance is returned for multiple callers. 354 * This is due to the ImsManager being a potentially heavyweight object depending on what it is 355 * being used for. 356 */ 357 private static class InstanceManager implements FeatureConnector.Listener<ImsManager> { 358 // If this is the first time connecting, wait a small amount of time in case IMS has already 359 // connected. Otherwise, ImsManager will become ready when the ImsService is connected. 360 private static final int CONNECT_TIMEOUT_MS = 50; 361 362 private final FeatureConnector<ImsManager> mConnector; 363 private final ImsManager mImsManager; 364 365 private final Object mLock = new Object(); 366 private boolean isConnectorActive = false; 367 private CountDownLatch mConnectedLatch; 368 InstanceManager(ImsManager manager)369 public InstanceManager(ImsManager manager) { 370 mImsManager = manager; 371 // Set a special prefix so that logs generated by getInstance are distinguishable. 372 mImsManager.mLogTagPostfix = "IM"; 373 374 ArrayList<Integer> readyFilter = new ArrayList<>(); 375 readyFilter.add(ImsFeature.STATE_READY); 376 readyFilter.add(ImsFeature.STATE_INITIALIZING); 377 readyFilter.add(ImsFeature.STATE_UNAVAILABLE); 378 // Pass a reference of the ImsManager being managed into the connector, allowing it to 379 // update the internal MmTelFeatureConnection as it is being updated. 380 mConnector = new FeatureConnector<>(manager.mContext, manager.mPhoneId, 381 (c,p) -> mImsManager, "InstanceManager", readyFilter, this, 382 manager.getImsThreadExecutor()); 383 } 384 getInstance()385 public ImsManager getInstance() { 386 return mImsManager; 387 } 388 reconnect()389 public void reconnect() { 390 boolean requiresReconnect = false; 391 synchronized (mLock) { 392 if (!isConnectorActive) { 393 requiresReconnect = true; 394 isConnectorActive = true; 395 mConnectedLatch = new CountDownLatch(1); 396 } 397 } 398 if (requiresReconnect) { 399 mConnector.connect(); 400 } 401 try { 402 // If this is during initial reconnect, let all threads wait for connect 403 // (or timeout) 404 if(!mConnectedLatch.await(CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 405 mImsManager.log("ImsService not up yet - timeout waiting for connection."); 406 } 407 } catch (InterruptedException e) { 408 // Do nothing and allow ImsService to attach behind the scenes 409 } 410 } 411 412 @Override connectionReady(ImsManager manager, int subId)413 public void connectionReady(ImsManager manager, int subId) { 414 synchronized (mLock) { 415 mImsManager.logi("connectionReady, subId: " + subId); 416 mConnectedLatch.countDown(); 417 } 418 } 419 420 @Override connectionUnavailable(int reason)421 public void connectionUnavailable(int reason) { 422 synchronized (mLock) { 423 mImsManager.logi("connectionUnavailable, reason: " + reason); 424 // only need to track the connection becoming unavailable due to telephony going 425 // down. 426 if (reason == FeatureConnector.UNAVAILABLE_REASON_SERVER_UNAVAILABLE) { 427 isConnectorActive = false; 428 } 429 mConnectedLatch.countDown(); 430 } 431 432 } 433 } 434 435 // Replaced with single-threaded executor for testing. 436 private final Executor mExecutor; 437 // Replaced With mock for testing 438 private MmTelFeatureConnectionFactory mMmTelFeatureConnectionFactory = 439 MmTelFeatureConnection::new; 440 private final SubscriptionManagerProxy mSubscriptionManagerProxy; 441 private final SettingsProxy mSettingsProxy; 442 443 private Context mContext; 444 private CarrierConfigManager mConfigManager; 445 private int mPhoneId; 446 private TelephonyManager mTelephonyManager; 447 private AtomicReference<MmTelFeatureConnection> mMmTelConnectionRef = new AtomicReference<>(); 448 // Used for debug purposes only currently 449 private boolean mConfigUpdated = false; 450 private BinderCacheManager<ITelephony> mBinderCache; 451 private ImsConfigListener mImsConfigListener; 452 453 public static final String TRUE = "true"; 454 public static final String FALSE = "false"; 455 // Map of phoneId -> InstanceManager 456 private static final SparseArray<InstanceManager> IMS_MANAGER_INSTANCES = new SparseArray<>(2); 457 // Map of phoneId -> ImsStatsCallback 458 private static final SparseArray<ImsStatsCallback> IMS_STATS_CALLBACKS = new SparseArray<>(2); 459 460 // A log prefix added to some instances of ImsManager to make it distinguishable from others. 461 // - "IM" added to ImsManager for ImsManagers created using getInstance. 462 private String mLogTagPostfix = ""; 463 464 /** 465 * Gets a manager instance and blocks for a limited period of time, connecting to the 466 * corresponding ImsService MmTelFeature if it exists. 467 * <p> 468 * If the ImsService is unavailable or becomes unavailable, the associated methods will fail and 469 * a new ImsManager will need to be requested. Instead, a {@link FeatureConnector} can be 470 * requested using {@link #getConnector}, which will notify the caller when a new ImsManager is 471 * available. 472 * 473 * @param context application context for creating the manager object 474 * @param phoneId the phone ID for the IMS Service 475 * @return the manager instance corresponding to the phoneId 476 */ 477 @UnsupportedAppUsage getInstance(Context context, int phoneId)478 public static ImsManager getInstance(Context context, int phoneId) { 479 InstanceManager instanceManager; 480 synchronized (IMS_MANAGER_INSTANCES) { 481 instanceManager = IMS_MANAGER_INSTANCES.get(phoneId); 482 if (instanceManager == null) { 483 ImsManager m = new ImsManager(context, phoneId); 484 instanceManager = new InstanceManager(m); 485 IMS_MANAGER_INSTANCES.put(phoneId, instanceManager); 486 } 487 } 488 // If the ImsManager became disconnected for some reason, try to reconnect it now. 489 instanceManager.reconnect(); 490 return instanceManager.getInstance(); 491 } 492 493 /** 494 * Retrieve an FeatureConnector for ImsManager, which allows a Listener to listen for when 495 * the ImsManager becomes available or unavailable due to the ImsService MmTelFeature moving to 496 * the READY state or destroyed on a specific phone modem index. 497 * 498 * @param context The Context that will be used to connect the ImsManager. 499 * @param phoneId The modem phone ID that the ImsManager will be created for. 500 * @param logPrefix The log prefix used for debugging purposes. 501 * @param listener The Listener that will deliver ImsManager updates as it becomes available. 502 * @param executor The Executor that the Listener callbacks will be called on. 503 * @return A FeatureConnector instance for generating ImsManagers as the associated 504 * MmTelFeatures become available. 505 */ getConnector(Context context, int phoneId, String logPrefix, FeatureConnector.Listener<ImsManager> listener, Executor executor)506 public static FeatureConnector<ImsManager> getConnector(Context context, 507 int phoneId, String logPrefix, FeatureConnector.Listener<ImsManager> listener, 508 Executor executor) { 509 // Only listen for the READY state from the MmTelFeature here. 510 ArrayList<Integer> readyFilter = new ArrayList<>(); 511 readyFilter.add(ImsFeature.STATE_READY); 512 return new FeatureConnector<>(context, phoneId, ImsManager::new, logPrefix, readyFilter, 513 listener, executor); 514 } 515 isImsSupportedOnDevice(Context context)516 public static boolean isImsSupportedOnDevice(Context context) { 517 return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS); 518 } 519 520 /** 521 * Sets the callback that will be called when events related to IMS metric collection occur. 522 * <p> 523 * Note: Subsequent calls to this method will replace the previous stats callback. 524 */ setImsStatsCallback(int phoneId, ImsStatsCallback cb)525 public static void setImsStatsCallback(int phoneId, ImsStatsCallback cb) { 526 synchronized (IMS_STATS_CALLBACKS) { 527 if (cb == null) { 528 IMS_STATS_CALLBACKS.remove(phoneId); 529 } else { 530 IMS_STATS_CALLBACKS.put(phoneId, cb); 531 } 532 } 533 } 534 535 /** 536 * @return the {@link ImsStatsCallback} instance associated with the provided phoneId or 537 * {@link null} if none currently exists. 538 */ getStatsCallback(int phoneId)539 private static ImsStatsCallback getStatsCallback(int phoneId) { 540 synchronized (IMS_STATS_CALLBACKS) { 541 return IMS_STATS_CALLBACKS.get(phoneId); 542 } 543 } 544 545 /** 546 * Returns the user configuration of Enhanced 4G LTE Mode setting. 547 * 548 * @deprecated Doesn't support MSIM devices. Use 549 * {@link #isEnhanced4gLteModeSettingEnabledByUser()} instead. 550 */ 551 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isEnhanced4gLteModeSettingEnabledByUser(Context context)552 public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) { 553 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 554 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 555 if (mgr != null) { 556 return mgr.isEnhanced4gLteModeSettingEnabledByUser(); 557 } 558 Rlog.e(TAG, "isEnhanced4gLteModeSettingEnabledByUser: ImsManager null, returning default" 559 + " value."); 560 return false; 561 } 562 563 /** 564 * Returns the user configuration of Enhanced 4G LTE Mode setting for slot. If the option is 565 * not editable ({@link CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL} is false), 566 * hidden ({@link CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL} is true), the setting is 567 * not initialized, and VoIMS opt-in status disabled, this method will return default value 568 * specified by {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}. 569 * 570 * Note that even if the setting was set, it may no longer be editable. If this is the case we 571 * return the default value. 572 */ isEnhanced4gLteModeSettingEnabledByUser()573 public boolean isEnhanced4gLteModeSettingEnabledByUser() { 574 int setting = mSubscriptionManagerProxy.getIntegerSubscriptionProperty( 575 getSubId(), SubscriptionManager.ENHANCED_4G_MODE_ENABLED, 576 SUB_PROPERTY_NOT_INITIALIZED); 577 boolean onByDefault = getBooleanCarrierConfig( 578 CarrierConfigManager.KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL); 579 boolean isUiUnEditable = 580 !getBooleanCarrierConfig(CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL) 581 || getBooleanCarrierConfig(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL); 582 boolean isSettingNotInitialized = setting == SUB_PROPERTY_NOT_INITIALIZED; 583 584 // If Enhanced 4G LTE Mode is uneditable, hidden, not initialized and VoIMS opt-in disabled 585 // we use the default value. If VoIMS opt-in is enabled, we will always allow the user to 586 // change the IMS enabled setting. 587 if ((isUiUnEditable || isSettingNotInitialized) && !isVoImsOptInEnabled()) { 588 return onByDefault; 589 } else { 590 return (setting == ProvisioningManager.PROVISIONING_VALUE_ENABLED); 591 } 592 } 593 594 /** 595 * Change persistent Enhanced 4G LTE Mode setting. 596 * 597 * @deprecated Doesn't support MSIM devices. Use {@link #setEnhanced4gLteModeSetting(boolean)} 598 * instead. 599 */ setEnhanced4gLteModeSetting(Context context, boolean enabled)600 public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) { 601 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 602 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 603 if (mgr != null) { 604 mgr.setEnhanced4gLteModeSetting(enabled); 605 } 606 Rlog.e(TAG, "setEnhanced4gLteModeSetting: ImsManager null, value not set."); 607 } 608 609 /** 610 * Change persistent Enhanced 4G LTE Mode setting. If the option is not editable 611 * ({@link CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL} is false), 612 * hidden ({@link CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL} is true), and VoIMS opt-in 613 * status disabled, this method will set the setting to the default value specified by 614 * {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}. 615 */ setEnhanced4gLteModeSetting(boolean enabled)616 public void setEnhanced4gLteModeSetting(boolean enabled) { 617 if (enabled && !isVolteProvisionedOnDevice()) { 618 log("setEnhanced4gLteModeSetting: Not possible to enable VoLTE due to provisioning."); 619 return; 620 } 621 int subId = getSubId(); 622 if (!isSubIdValid(subId)) { 623 loge("setEnhanced4gLteModeSetting: invalid sub id, can not set property in " + 624 " siminfo db; subId=" + subId); 625 return; 626 } 627 // If editable=false or hidden=true, we must keep default advanced 4G mode. 628 boolean isUiUnEditable = 629 !getBooleanCarrierConfig(CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL) || 630 getBooleanCarrierConfig(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL); 631 632 // If VoIMS opt-in is enabled, we will always allow the user to change the IMS enabled 633 // setting. 634 if (isUiUnEditable && !isVoImsOptInEnabled()) { 635 enabled = getBooleanCarrierConfig( 636 CarrierConfigManager.KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL); 637 } 638 639 int prevSetting = mSubscriptionManagerProxy.getIntegerSubscriptionProperty(subId, 640 SubscriptionManager.ENHANCED_4G_MODE_ENABLED, SUB_PROPERTY_NOT_INITIALIZED); 641 642 if (prevSetting == (enabled ? ProvisioningManager.PROVISIONING_VALUE_ENABLED : 643 ProvisioningManager.PROVISIONING_VALUE_DISABLED)) { 644 // No change in setting. 645 return; 646 } 647 mSubscriptionManagerProxy.setSubscriptionProperty(subId, 648 SubscriptionManager.ENHANCED_4G_MODE_ENABLED, 649 booleanToPropertyString(enabled)); 650 try { 651 if (enabled) { 652 CapabilityChangeRequest request = new CapabilityChangeRequest(); 653 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(); 654 // This affects voice and video enablement 655 updateVoiceCellFeatureValue(request, isNonTty); 656 updateVideoCallFeatureValue(request, isNonTty); 657 changeMmTelCapability(request); 658 // Ensure IMS is on if this setting is enabled. 659 turnOnIms(); 660 } else { 661 // This may trigger entire IMS interface to be disabled, so recalculate full state. 662 reevaluateCapabilities(); 663 } 664 } catch (ImsException e) { 665 loge("setEnhanced4gLteModeSetting couldn't set config: " + e); 666 } 667 } 668 669 /** 670 * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is 671 * supported. 672 * @deprecated Does not support MSIM devices. Please use 673 * {@link #isNonTtyOrTtyOnVolteEnabled()} instead. 674 */ 675 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isNonTtyOrTtyOnVolteEnabled(Context context)676 public static boolean isNonTtyOrTtyOnVolteEnabled(Context context) { 677 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 678 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 679 if (mgr != null) { 680 return mgr.isNonTtyOrTtyOnVolteEnabled(); 681 } 682 Rlog.e(TAG, "isNonTtyOrTtyOnVolteEnabled: ImsManager null, returning default value."); 683 return false; 684 } 685 686 /** 687 * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is 688 * supported on a per slot basis. 689 */ isNonTtyOrTtyOnVolteEnabled()690 public boolean isNonTtyOrTtyOnVolteEnabled() { 691 if (isTtyOnVoLteCapable()) { 692 return true; 693 } 694 695 TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); 696 if (tm == null) { 697 logw("isNonTtyOrTtyOnVolteEnabled: telecom not available"); 698 return true; 699 } 700 return tm.getCurrentTtyMode() == TelecomManager.TTY_MODE_OFF; 701 } 702 isTtyOnVoLteCapable()703 public boolean isTtyOnVoLteCapable() { 704 return getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL); 705 } 706 707 /** 708 * @return true if we are either not on TTY or TTY over VoWiFi is enabled. If we 709 * are on TTY and TTY over VoWiFi is not allowed, this method will return false. 710 */ isNonTtyOrTtyOnVoWifiEnabled()711 public boolean isNonTtyOrTtyOnVoWifiEnabled() { 712 713 if (isTtyOnVoWifiCapable()) { 714 return true; 715 } 716 717 TelecomManager tm = mContext.getSystemService(TelecomManager.class); 718 if (tm == null) { 719 logw("isNonTtyOrTtyOnVoWifiEnabled: telecom not available"); 720 return true; 721 } 722 return tm.getCurrentTtyMode() == TelecomManager.TTY_MODE_OFF; 723 } 724 isTtyOnVoWifiCapable()725 public boolean isTtyOnVoWifiCapable() { 726 return getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_VOWIFI_TTY_SUPPORTED_BOOL); 727 } 728 729 /** 730 * Returns a platform configuration for VoLTE which may override the user setting. 731 * @deprecated Does not support MSIM devices. Please use 732 * {@link #isVolteEnabledByPlatform()} instead. 733 */ 734 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isVolteEnabledByPlatform(Context context)735 public static boolean isVolteEnabledByPlatform(Context context) { 736 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 737 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 738 if (mgr != null) { 739 return mgr.isVolteEnabledByPlatform(); 740 } 741 Rlog.e(TAG, "isVolteEnabledByPlatform: ImsManager null, returning default value."); 742 return false; 743 } 744 745 /** 746 * Asynchronous call to ImsService to determine whether or not a specific MmTel capability is 747 * supported. 748 */ isSupported(int capability, int transportType, Consumer<Boolean> result)749 public void isSupported(int capability, int transportType, Consumer<Boolean> result) { 750 getImsThreadExecutor().execute(() -> { 751 switch(transportType) { 752 // Does not take into account NR, as NR is a superset of LTE support currently. 753 case (AccessNetworkConstants.TRANSPORT_TYPE_WWAN): { 754 switch (capability) { 755 case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE): { 756 result.accept(isVolteEnabledByPlatform()); 757 return; 758 } case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO): { 759 result.accept(isVtEnabledByPlatform()); 760 return; 761 }case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT): { 762 result.accept(isSuppServicesOverUtEnabledByPlatform()); 763 return; 764 } case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS): { 765 // There is currently no carrier config defined for this. 766 result.accept(true); 767 return; 768 } 769 } 770 break; 771 } case (AccessNetworkConstants.TRANSPORT_TYPE_WLAN): { 772 switch (capability) { 773 case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE) : { 774 result.accept(isWfcEnabledByPlatform()); 775 return; 776 } case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO) : { 777 // This is not transport dependent at this time. 778 result.accept(isVtEnabledByPlatform()); 779 return; 780 } case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT) : { 781 // This is not transport dependent at this time. 782 result.accept(isSuppServicesOverUtEnabledByPlatform()); 783 return; 784 } case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS) : { 785 // There is currently no carrier config defined for this. 786 result.accept(true); 787 return; 788 } 789 } 790 break; 791 } 792 } 793 // false for unknown capability/transport types. 794 result.accept(false); 795 }); 796 797 } 798 799 /** 800 * Returns a platform configuration for VoLTE which may override the user setting on a per Slot 801 * basis. 802 */ isVolteEnabledByPlatform()803 public boolean isVolteEnabledByPlatform() { 804 // We first read the per slot value. If doesn't exist, we read the general value. If still 805 // doesn't exist, we use the hardcoded default value. 806 if (SystemProperties.getInt( 807 PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE + Integer.toString(mPhoneId), 808 SYSTEM_PROPERTY_NOT_SET) == 1 || 809 SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE, 810 SYSTEM_PROPERTY_NOT_SET) == 1) { 811 return true; 812 } 813 814 if (getLocalImsConfigKeyInt(KEY_VOIMS_OPT_IN_STATUS) 815 == ProvisioningManager.PROVISIONING_VALUE_ENABLED) { 816 return true; 817 } 818 819 return mContext.getResources().getBoolean( 820 com.android.internal.R.bool.config_device_volte_available) 821 && getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL) 822 && isGbaValid(); 823 } 824 825 /** 826 * @return {@code true} if IMS over NR is enabled by the platform, {@code false} otherwise. 827 */ isImsOverNrEnabledByPlatform()828 public boolean isImsOverNrEnabledByPlatform() { 829 int[] nrCarrierCaps = getIntArrayCarrierConfig( 830 CarrierConfigManager.KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY); 831 if (nrCarrierCaps == null) return false; 832 boolean voNrCarrierSupported = Arrays.stream(nrCarrierCaps) 833 .anyMatch(cap -> cap == CarrierConfigManager.CARRIER_NR_AVAILABILITY_SA); 834 if (!voNrCarrierSupported) return false; 835 return isGbaValid(); 836 } 837 838 /** 839 * Indicates whether VoLTE is provisioned on device. 840 * 841 * @deprecated Does not support MSIM devices. Please use 842 * {@link #isVolteProvisionedOnDevice()} instead. 843 */ isVolteProvisionedOnDevice(Context context)844 public static boolean isVolteProvisionedOnDevice(Context context) { 845 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 846 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 847 if (mgr != null) { 848 return mgr.isVolteProvisionedOnDevice(); 849 } 850 Rlog.e(TAG, "isVolteProvisionedOnDevice: ImsManager null, returning default value."); 851 return true; 852 } 853 854 /** 855 * Indicates whether VoLTE is provisioned on this slot. 856 */ isVolteProvisionedOnDevice()857 public boolean isVolteProvisionedOnDevice() { 858 if (isMmTelProvisioningRequired(CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE)) { 859 return isVolteProvisioned(); 860 } 861 862 return true; 863 } 864 865 /** 866 * Indicates whether EAB is provisioned on this slot. 867 */ isEabProvisionedOnDevice()868 public boolean isEabProvisionedOnDevice() { 869 if (isRcsProvisioningRequired(CAPABILITY_TYPE_PRESENCE_UCE, REGISTRATION_TECH_LTE)) { 870 return isEabProvisioned(); 871 } 872 873 return true; 874 } 875 876 /** 877 * Indicates whether VoWifi is provisioned on device. 878 * 879 * When CarrierConfig KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL is true, and VoLTE is not 880 * provisioned on device, this method returns false. 881 * 882 * @deprecated Does not support MSIM devices. Please use 883 * {@link #isWfcProvisionedOnDevice()} instead. 884 */ isWfcProvisionedOnDevice(Context context)885 public static boolean isWfcProvisionedOnDevice(Context context) { 886 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 887 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 888 if (mgr != null) { 889 return mgr.isWfcProvisionedOnDevice(); 890 } 891 Rlog.e(TAG, "isWfcProvisionedOnDevice: ImsManager null, returning default value."); 892 return true; 893 } 894 895 /** 896 * Indicates whether VoWifi is provisioned on slot. 897 * 898 * When CarrierConfig KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL is true, and VoLTE is not 899 * provisioned on device, this method returns false. 900 */ isWfcProvisionedOnDevice()901 public boolean isWfcProvisionedOnDevice() { 902 if (getBooleanCarrierConfig( 903 CarrierConfigManager.KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL)) { 904 if (!isVolteProvisionedOnDevice()) { 905 return false; 906 } 907 } 908 909 if (isMmTelProvisioningRequired(CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_IWLAN)) { 910 return isWfcProvisioned(); 911 } 912 913 return true; 914 } 915 916 /** 917 * Indicates whether VT is provisioned on device 918 * 919 * @deprecated Does not support MSIM devices. Please use 920 * {@link #isVtProvisionedOnDevice()} instead. 921 */ isVtProvisionedOnDevice(Context context)922 public static boolean isVtProvisionedOnDevice(Context context) { 923 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 924 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 925 if (mgr != null) { 926 return mgr.isVtProvisionedOnDevice(); 927 } 928 Rlog.e(TAG, "isVtProvisionedOnDevice: ImsManager null, returning default value."); 929 return true; 930 } 931 932 /** 933 * Indicates whether VT is provisioned on slot. 934 */ isVtProvisionedOnDevice()935 public boolean isVtProvisionedOnDevice() { 936 if (isMmTelProvisioningRequired(CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_LTE)) { 937 return isVtProvisioned(); 938 } 939 940 return true; 941 } 942 943 /** 944 * Returns a platform configuration for VT which may override the user setting. 945 * 946 * Note: VT presumes that VoLTE is enabled (these are configuration settings 947 * which must be done correctly). 948 * 949 * @deprecated Does not support MSIM devices. Please use 950 * {@link #isVtEnabledByPlatform()} instead. 951 */ isVtEnabledByPlatform(Context context)952 public static boolean isVtEnabledByPlatform(Context context) { 953 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 954 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 955 if (mgr != null) { 956 return mgr.isVtEnabledByPlatform(); 957 } 958 Rlog.e(TAG, "isVtEnabledByPlatform: ImsManager null, returning default value."); 959 return false; 960 } 961 962 /** 963 * Returns a platform configuration for VT which may override the user setting. 964 * 965 * Note: VT presumes that VoLTE is enabled (these are configuration settings 966 * which must be done correctly). 967 */ isVtEnabledByPlatform()968 public boolean isVtEnabledByPlatform() { 969 // We first read the per slot value. If doesn't exist, we read the general value. If still 970 // doesn't exist, we use the hardcoded default value. 971 if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE + 972 Integer.toString(mPhoneId), SYSTEM_PROPERTY_NOT_SET) == 1 || 973 SystemProperties.getInt( 974 PROPERTY_DBG_VT_AVAIL_OVERRIDE, SYSTEM_PROPERTY_NOT_SET) == 1) { 975 return true; 976 } 977 978 return mContext.getResources().getBoolean( 979 com.android.internal.R.bool.config_device_vt_available) && 980 getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_VT_AVAILABLE_BOOL) && 981 isGbaValid(); 982 } 983 984 /** 985 * Returns the user configuration of VT setting 986 * @deprecated Does not support MSIM devices. Please use 987 * {@link #isVtEnabledByUser()} instead. 988 */ isVtEnabledByUser(Context context)989 public static boolean isVtEnabledByUser(Context context) { 990 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 991 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 992 if (mgr != null) { 993 return mgr.isVtEnabledByUser(); 994 } 995 Rlog.e(TAG, "isVtEnabledByUser: ImsManager null, returning default value."); 996 return false; 997 } 998 999 /** 1000 * Returns the user configuration of VT setting per slot. If not set, it 1001 * returns true as default value. 1002 */ isVtEnabledByUser()1003 public boolean isVtEnabledByUser() { 1004 int setting = mSubscriptionManagerProxy.getIntegerSubscriptionProperty( 1005 getSubId(), SubscriptionManager.VT_IMS_ENABLED, 1006 SUB_PROPERTY_NOT_INITIALIZED); 1007 1008 // If it's never set, by default we return true. 1009 return (setting == SUB_PROPERTY_NOT_INITIALIZED 1010 || setting == ProvisioningManager.PROVISIONING_VALUE_ENABLED); 1011 } 1012 1013 /** 1014 * Returns whether the user sets call composer setting per sub. 1015 */ isCallComposerEnabledByUser()1016 public boolean isCallComposerEnabledByUser() { 1017 if (mTelephonyManager == null) { 1018 loge("isCallComposerEnabledByUser: TelephonyManager is null, returning false"); 1019 return false; 1020 } 1021 return mTelephonyManager.getCallComposerStatus() 1022 == TelephonyManager.CALL_COMPOSER_STATUS_ON; 1023 } 1024 1025 /** 1026 * Returns whether the business only call composer is on. 1027 */ isBusinessOnlyCallComposerEnabledByUser()1028 public boolean isBusinessOnlyCallComposerEnabledByUser() { 1029 TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); 1030 if (tm == null) { 1031 loge("isBusinessOnlyCallComposerEnabledByUser: TelephonyManager is null"); 1032 return false; 1033 } 1034 return tm.getCallComposerStatus() == TelephonyManager.CALL_COMPOSER_STATUS_BUSINESS_ONLY; 1035 } 1036 1037 /** 1038 * Change persistent VT enabled setting 1039 * 1040 * @deprecated Does not support MSIM devices. Please use {@link #setVtSetting(boolean)} instead. 1041 */ setVtSetting(Context context, boolean enabled)1042 public static void setVtSetting(Context context, boolean enabled) { 1043 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 1044 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 1045 if (mgr != null) { 1046 mgr.setVtSetting(enabled); 1047 } 1048 Rlog.e(TAG, "setVtSetting: ImsManager null, can not set value."); 1049 } 1050 1051 /** 1052 * Change persistent VT enabled setting for slot. 1053 */ setVtSetting(boolean enabled)1054 public void setVtSetting(boolean enabled) { 1055 if (enabled && !isVtProvisionedOnDevice()) { 1056 log("setVtSetting: Not possible to enable Vt due to provisioning."); 1057 return; 1058 } 1059 1060 int subId = getSubId(); 1061 if (!isSubIdValid(subId)) { 1062 loge("setVtSetting: sub id invalid, skip modifying vt state in subinfo db; subId=" 1063 + subId); 1064 return; 1065 } 1066 mSubscriptionManagerProxy.setSubscriptionProperty(subId, SubscriptionManager.VT_IMS_ENABLED, 1067 booleanToPropertyString(enabled)); 1068 try { 1069 if (enabled) { 1070 CapabilityChangeRequest request = new CapabilityChangeRequest(); 1071 updateVideoCallFeatureValue(request, isNonTtyOrTtyOnVolteEnabled()); 1072 changeMmTelCapability(request); 1073 // ensure IMS is enabled. 1074 turnOnIms(); 1075 } else { 1076 // This may cause IMS to be disabled, re-evaluate all. 1077 reevaluateCapabilities(); 1078 } 1079 } catch (ImsException e) { 1080 // The ImsService is down. Since the SubscriptionManager already recorded the user's 1081 // preference, it will be resent in updateImsServiceConfig when the ImsPhoneCallTracker 1082 // reconnects. 1083 loge("setVtSetting(b): ", e); 1084 } 1085 } 1086 1087 /** 1088 * Returns whether turning off ims is allowed by platform. 1089 * The platform property may override the carrier config. 1090 */ isTurnOffImsAllowedByPlatform()1091 private boolean isTurnOffImsAllowedByPlatform() { 1092 // We first read the per slot value. If doesn't exist, we read the general value. If still 1093 // doesn't exist, we use the hardcoded default value. 1094 if (SystemProperties.getInt(PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE + 1095 Integer.toString(mPhoneId), SYSTEM_PROPERTY_NOT_SET) == 1 || 1096 SystemProperties.getInt( 1097 PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE, SYSTEM_PROPERTY_NOT_SET) == 1) { 1098 return true; 1099 } 1100 1101 return getBooleanCarrierConfig( 1102 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL); 1103 } 1104 1105 /** 1106 * Returns the user configuration of WFC setting 1107 * 1108 * @deprecated Does not support MSIM devices. Please use 1109 * {@link #isWfcEnabledByUser()} instead. 1110 */ isWfcEnabledByUser(Context context)1111 public static boolean isWfcEnabledByUser(Context context) { 1112 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 1113 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 1114 if (mgr != null) { 1115 return mgr.isWfcEnabledByUser(); 1116 } 1117 Rlog.e(TAG, "isWfcEnabledByUser: ImsManager null, returning default value."); 1118 return true; 1119 } 1120 1121 /** 1122 * Returns the user configuration of WFC setting for slot. If not set, it 1123 * queries CarrierConfig value as default. 1124 */ isWfcEnabledByUser()1125 public boolean isWfcEnabledByUser() { 1126 int setting = mSubscriptionManagerProxy.getIntegerSubscriptionProperty( 1127 getSubId(), SubscriptionManager.WFC_IMS_ENABLED, 1128 SUB_PROPERTY_NOT_INITIALIZED); 1129 1130 // SUB_PROPERTY_NOT_INITIALIZED indicates it's never set in sub db. 1131 if (setting == SUB_PROPERTY_NOT_INITIALIZED) { 1132 return getBooleanCarrierConfig( 1133 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL); 1134 } else { 1135 return setting == ProvisioningManager.PROVISIONING_VALUE_ENABLED; 1136 } 1137 } 1138 1139 /** 1140 * Change persistent WFC enabled setting. 1141 * @deprecated Does not support MSIM devices. Please use 1142 * {@link #setWfcSetting} instead. 1143 */ setWfcSetting(Context context, boolean enabled)1144 public static void setWfcSetting(Context context, boolean enabled) { 1145 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 1146 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 1147 if (mgr != null) { 1148 mgr.setWfcSetting(enabled); 1149 } 1150 Rlog.e(TAG, "setWfcSetting: ImsManager null, can not set value."); 1151 } 1152 1153 /** 1154 * Change persistent WFC enabled setting for slot. 1155 */ setWfcSetting(boolean enabled)1156 public void setWfcSetting(boolean enabled) { 1157 if (enabled && !isWfcProvisionedOnDevice()) { 1158 log("setWfcSetting: Not possible to enable WFC due to provisioning."); 1159 return; 1160 } 1161 int subId = getSubId(); 1162 if (!isSubIdValid(subId)) { 1163 loge("setWfcSetting: invalid sub id, can not set WFC setting in siminfo db; subId=" 1164 + subId); 1165 return; 1166 } 1167 mSubscriptionManagerProxy.setSubscriptionProperty(subId, 1168 SubscriptionManager.WFC_IMS_ENABLED, booleanToPropertyString(enabled)); 1169 1170 try { 1171 if (enabled) { 1172 boolean isNonTtyWifi = isNonTtyOrTtyOnVoWifiEnabled(); 1173 CapabilityChangeRequest request = new CapabilityChangeRequest(); 1174 updateVoiceWifiFeatureAndProvisionedValues(request, isNonTtyWifi); 1175 changeMmTelCapability(request); 1176 // Ensure IMS is on if this setting is updated. 1177 turnOnIms(); 1178 } else { 1179 // This may cause IMS to be disabled, re-evaluate all caps 1180 reevaluateCapabilities(); 1181 } 1182 } catch (ImsException e) { 1183 loge("setWfcSetting: " + e); 1184 } 1185 } 1186 1187 /** 1188 * @return true if the user's setting for Voice over Cross SIM is enabled and 1189 * false if it is not 1190 */ isCrossSimCallingEnabledByUser()1191 public boolean isCrossSimCallingEnabledByUser() { 1192 int setting = mSubscriptionManagerProxy.getIntegerSubscriptionProperty( 1193 getSubId(), SubscriptionManager.CROSS_SIM_CALLING_ENABLED, 1194 SUB_PROPERTY_NOT_INITIALIZED); 1195 1196 // SUB_PROPERTY_NOT_INITIALIZED indicates it's never set in sub db. 1197 if (setting == SUB_PROPERTY_NOT_INITIALIZED) { 1198 return false; 1199 } else { 1200 return setting == ProvisioningManager.PROVISIONING_VALUE_ENABLED; 1201 } 1202 } 1203 1204 /** 1205 * @return true if Voice over Cross SIM is provisioned and enabled by user and platform. 1206 * false if any of them is not true 1207 */ isCrossSimCallingEnabled()1208 public boolean isCrossSimCallingEnabled() { 1209 boolean userEnabled = isCrossSimCallingEnabledByUser(); 1210 boolean platformEnabled = isCrossSimEnabledByPlatform(); 1211 boolean isProvisioned = isWfcProvisionedOnDevice(); 1212 1213 log("isCrossSimCallingEnabled: platformEnabled = " + platformEnabled 1214 + ", provisioned = " + isProvisioned 1215 + ", userEnabled = " + userEnabled); 1216 return userEnabled && platformEnabled && isProvisioned; 1217 } 1218 1219 /** 1220 * Sets the user's setting for whether or not Voice over Cross SIM is enabled. 1221 */ setCrossSimCallingEnabled(boolean enabled)1222 public void setCrossSimCallingEnabled(boolean enabled) { 1223 if (enabled && !isWfcProvisionedOnDevice()) { 1224 log("setCrossSimCallingEnabled: Not possible to enable WFC due to provisioning."); 1225 return; 1226 } 1227 int subId = getSubId(); 1228 if (!isSubIdValid(subId)) { 1229 loge("setCrossSimCallingEnabled: " 1230 + "invalid sub id, can not set Cross SIM setting in siminfo db; subId=" 1231 + subId); 1232 return; 1233 } 1234 mSubscriptionManagerProxy.setSubscriptionProperty(subId, 1235 SubscriptionManager.CROSS_SIM_CALLING_ENABLED, booleanToPropertyString(enabled)); 1236 try { 1237 if (enabled) { 1238 CapabilityChangeRequest request = new CapabilityChangeRequest(); 1239 updateCrossSimFeatureAndProvisionedValues(request); 1240 changeMmTelCapability(request); 1241 turnOnIms(); 1242 } else { 1243 // Recalculate all caps to determine if IMS needs to be disabled. 1244 reevaluateCapabilities(); 1245 } 1246 } catch (ImsException e) { 1247 loge("setCrossSimCallingEnabled(): ", e); 1248 } 1249 } 1250 1251 /** 1252 * Non-persistently change WFC enabled setting and WFC mode for slot 1253 * 1254 * @param enabled If true, WFC and WFC while roaming will be enabled for the associated 1255 * subscription, if supported by the carrier. If false, WFC will be disabled for 1256 * the associated subscription. 1257 * @param wfcMode The WFC preference if WFC is enabled 1258 */ setWfcNonPersistent(boolean enabled, int wfcMode)1259 public void setWfcNonPersistent(boolean enabled, int wfcMode) { 1260 // Force IMS to register over LTE when turning off WFC 1261 int imsWfcModeFeatureValue = 1262 enabled ? wfcMode : ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED; 1263 try { 1264 changeMmTelCapability(enabled, MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1265 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); 1266 // Set the mode and roaming enabled settings before turning on IMS 1267 setWfcModeInternal(imsWfcModeFeatureValue); 1268 // If enabled is false, shortcut to false because of the ImsService 1269 // implementation for WFC roaming, otherwise use the correct user's setting. 1270 setWfcRoamingSettingInternal(enabled && isWfcRoamingEnabledByUser()); 1271 // Do not re-evaluate all capabilities because this is a temporary override of WFC 1272 // settings. 1273 if (enabled) { 1274 log("setWfcNonPersistent() : turnOnIms"); 1275 // Ensure IMS is turned on if this is enabled. 1276 turnOnIms(); 1277 } 1278 } catch (ImsException e) { 1279 loge("setWfcNonPersistent(): ", e); 1280 } 1281 } 1282 1283 /** 1284 * Returns the user configuration of WFC preference setting. 1285 * 1286 * @deprecated Doesn't support MSIM devices. Use {@link #getWfcMode(boolean roaming)} instead. 1287 */ getWfcMode(Context context)1288 public static int getWfcMode(Context context) { 1289 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 1290 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 1291 if (mgr != null) { 1292 return mgr.getWfcMode(); 1293 } 1294 Rlog.e(TAG, "getWfcMode: ImsManager null, returning default value."); 1295 return ImsMmTelManager.WIFI_MODE_WIFI_ONLY; 1296 } 1297 1298 /** 1299 * Returns the user configuration of WFC preference setting 1300 * @deprecated. Use {@link #getWfcMode(boolean roaming)} instead. 1301 */ getWfcMode()1302 public int getWfcMode() { 1303 return getWfcMode(false); 1304 } 1305 1306 /** 1307 * Change persistent WFC preference setting. 1308 * 1309 * @deprecated Doesn't support MSIM devices. Use {@link #setWfcMode(int)} instead. 1310 */ setWfcMode(Context context, int wfcMode)1311 public static void setWfcMode(Context context, int wfcMode) { 1312 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 1313 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 1314 if (mgr != null) { 1315 mgr.setWfcMode(wfcMode); 1316 } 1317 Rlog.e(TAG, "setWfcMode: ImsManager null, can not set value."); 1318 } 1319 1320 /** 1321 * Change persistent WFC preference setting for slot when not roaming. 1322 * @deprecated Use {@link #setWfcMode(int, boolean)} instead. 1323 */ setWfcMode(int wfcMode)1324 public void setWfcMode(int wfcMode) { 1325 setWfcMode(wfcMode, false /*isRoaming*/); 1326 } 1327 1328 /** 1329 * Returns the user configuration of WFC preference setting 1330 * 1331 * @param roaming {@code false} for home network setting, {@code true} for roaming setting 1332 * 1333 * @deprecated Doesn't support MSIM devices. Use {@link #getWfcMode(boolean)} instead. 1334 */ getWfcMode(Context context, boolean roaming)1335 public static int getWfcMode(Context context, boolean roaming) { 1336 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 1337 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 1338 if (mgr != null) { 1339 return mgr.getWfcMode(roaming); 1340 } 1341 Rlog.e(TAG, "getWfcMode: ImsManager null, returning default value."); 1342 return ImsMmTelManager.WIFI_MODE_WIFI_ONLY; 1343 } 1344 1345 /** 1346 * Returns the user configuration of WFC preference setting for slot. If not set, it 1347 * queries CarrierConfig value as default. 1348 * 1349 * @param roaming {@code false} for home network setting, {@code true} for roaming setting 1350 */ getWfcMode(boolean roaming)1351 public int getWfcMode(boolean roaming) { 1352 int setting; 1353 if (!roaming) { 1354 // The WFC mode is not editable, return the default setting in the CarrierConfig, not 1355 // the user set value. 1356 if (!getBooleanCarrierConfig(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL)) { 1357 setting = getIntCarrierConfig( 1358 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT); 1359 1360 } else { 1361 setting = getSettingFromSubscriptionManager(SubscriptionManager.WFC_IMS_MODE, 1362 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT); 1363 } 1364 if (DBG) log("getWfcMode - setting=" + setting); 1365 } else { 1366 if (getBooleanCarrierConfig( 1367 CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)) { 1368 setting = getWfcMode(false); 1369 } else if (overrideWfcRoamingModeWhileUsingNTN()) { 1370 if (DBG) log("getWfcMode (roaming) " 1371 + "- override Wfc roaming mode to WIFI_PREFERRED"); 1372 setting = ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED; 1373 } else if (!getBooleanCarrierConfig( 1374 CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL)) { 1375 setting = getIntCarrierConfig( 1376 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT); 1377 } else { 1378 setting = getSettingFromSubscriptionManager( 1379 SubscriptionManager.WFC_IMS_ROAMING_MODE, 1380 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT); 1381 } 1382 if (DBG) log("getWfcMode (roaming) - setting=" + setting); 1383 } 1384 return setting; 1385 } 1386 1387 /** 1388 * Returns the SubscriptionManager setting for the subSetting string. If it is not set, default 1389 * to the default CarrierConfig value for defaultConfigKey. 1390 */ getSettingFromSubscriptionManager(String subSetting, String defaultConfigKey)1391 private int getSettingFromSubscriptionManager(String subSetting, String defaultConfigKey) { 1392 int result; 1393 result = mSubscriptionManagerProxy.getIntegerSubscriptionProperty(getSubId(), subSetting, 1394 SUB_PROPERTY_NOT_INITIALIZED); 1395 1396 // SUB_PROPERTY_NOT_INITIALIZED indicates it's never set in sub db. 1397 if (result == SUB_PROPERTY_NOT_INITIALIZED) { 1398 result = getIntCarrierConfig(defaultConfigKey); 1399 } 1400 return result; 1401 } 1402 1403 /** 1404 * Change persistent WFC preference setting 1405 * 1406 * @param roaming {@code false} for home network setting, {@code true} for roaming setting 1407 * 1408 * @deprecated Doesn't support MSIM devices. Please use {@link #setWfcMode(int, boolean)} 1409 * instead. 1410 */ setWfcMode(Context context, int wfcMode, boolean roaming)1411 public static void setWfcMode(Context context, int wfcMode, boolean roaming) { 1412 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 1413 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 1414 if (mgr != null) { 1415 mgr.setWfcMode(wfcMode, roaming); 1416 } 1417 Rlog.e(TAG, "setWfcMode: ImsManager null, can not set value."); 1418 } 1419 1420 /** 1421 * Change persistent WFC preference setting 1422 * 1423 * @param roaming {@code false} for home network setting, {@code true} for roaming setting 1424 */ setWfcMode(int wfcMode, boolean roaming)1425 public void setWfcMode(int wfcMode, boolean roaming) { 1426 int subId = getSubId(); 1427 if (isSubIdValid(subId)) { 1428 if (!roaming) { 1429 if (DBG) log("setWfcMode(i,b) - setting=" + wfcMode); 1430 mSubscriptionManagerProxy.setSubscriptionProperty(subId, SubscriptionManager.WFC_IMS_MODE, 1431 Integer.toString(wfcMode)); 1432 } else { 1433 if (DBG) log("setWfcMode(i,b) (roaming) - setting=" + wfcMode); 1434 mSubscriptionManagerProxy.setSubscriptionProperty(subId, 1435 SubscriptionManager.WFC_IMS_ROAMING_MODE, Integer.toString(wfcMode)); 1436 } 1437 } else { 1438 loge("setWfcMode(i,b): invalid sub id, skip setting setting in siminfo db; subId=" 1439 + subId); 1440 } 1441 1442 if (mTelephonyManager == null) { 1443 loge("setWfcMode: TelephonyManager is null, can not set WFC."); 1444 return; 1445 } 1446 TelephonyManager tm = mTelephonyManager.createForSubscriptionId(getSubId()); 1447 // Unfortunately, the WFC mode is the same for home/roaming (we do not have separate 1448 // config keys), so we have to change the WFC mode when moving home<->roaming. So, only 1449 // call setWfcModeInternal when roaming == telephony roaming status. Otherwise, ignore. 1450 if (roaming == tm.isNetworkRoaming()) { 1451 setWfcModeInternal(wfcMode); 1452 } 1453 } 1454 getSubId()1455 private int getSubId() { 1456 return mSubscriptionManagerProxy.getSubscriptionId(mPhoneId); 1457 } 1458 setWfcModeInternal(int wfcMode)1459 private void setWfcModeInternal(int wfcMode) { 1460 final int value = wfcMode; 1461 getImsThreadExecutor().execute(() -> { 1462 try { 1463 getConfigInterface().setConfig( 1464 ProvisioningManager.KEY_VOICE_OVER_WIFI_MODE_OVERRIDE, value); 1465 } catch (ImsException e) { 1466 // do nothing 1467 } 1468 }); 1469 } 1470 1471 /** 1472 * Returns the user configuration of WFC roaming setting 1473 * 1474 * @deprecated Does not support MSIM devices. Please use 1475 * {@link #isWfcRoamingEnabledByUser()} instead. 1476 */ isWfcRoamingEnabledByUser(Context context)1477 public static boolean isWfcRoamingEnabledByUser(Context context) { 1478 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 1479 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 1480 if (mgr != null) { 1481 return mgr.isWfcRoamingEnabledByUser(); 1482 } 1483 Rlog.e(TAG, "isWfcRoamingEnabledByUser: ImsManager null, returning default value."); 1484 return false; 1485 } 1486 1487 /** 1488 * Returns the user configuration of WFC roaming setting for slot. If not set, it 1489 * queries CarrierConfig value as default. 1490 */ isWfcRoamingEnabledByUser()1491 public boolean isWfcRoamingEnabledByUser() { 1492 int setting = mSubscriptionManagerProxy.getIntegerSubscriptionProperty( 1493 getSubId(), SubscriptionManager.WFC_IMS_ROAMING_ENABLED, 1494 SUB_PROPERTY_NOT_INITIALIZED); 1495 if (setting == SUB_PROPERTY_NOT_INITIALIZED) { 1496 return getBooleanCarrierConfig( 1497 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL); 1498 } else { 1499 return setting == ProvisioningManager.PROVISIONING_VALUE_ENABLED; 1500 } 1501 } 1502 1503 /** 1504 * Change persistent WFC roaming enabled setting 1505 */ setWfcRoamingSetting(Context context, boolean enabled)1506 public static void setWfcRoamingSetting(Context context, boolean enabled) { 1507 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 1508 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 1509 if (mgr != null) { 1510 mgr.setWfcRoamingSetting(enabled); 1511 } 1512 Rlog.e(TAG, "setWfcRoamingSetting: ImsManager null, value not set."); 1513 } 1514 1515 /** 1516 * Change persistent WFC roaming enabled setting 1517 */ setWfcRoamingSetting(boolean enabled)1518 public void setWfcRoamingSetting(boolean enabled) { 1519 mSubscriptionManagerProxy.setSubscriptionProperty(getSubId(), 1520 SubscriptionManager.WFC_IMS_ROAMING_ENABLED, booleanToPropertyString(enabled) 1521 ); 1522 1523 setWfcRoamingSettingInternal(enabled); 1524 } 1525 setWfcRoamingSettingInternal(boolean enabled)1526 private void setWfcRoamingSettingInternal(boolean enabled) { 1527 final int value = enabled 1528 ? ProvisioningManager.PROVISIONING_VALUE_ENABLED 1529 : ProvisioningManager.PROVISIONING_VALUE_DISABLED; 1530 getImsThreadExecutor().execute(() -> { 1531 try { 1532 getConfigInterface().setConfig( 1533 ProvisioningManager.KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE, value); 1534 } catch (ImsException e) { 1535 // do nothing 1536 } 1537 }); 1538 } 1539 1540 /** 1541 * Returns a platform configuration for WFC which may override the user 1542 * setting. Note: WFC presumes that VoLTE is enabled (these are 1543 * configuration settings which must be done correctly). 1544 * 1545 * @deprecated Doesn't work for MSIM devices. Use {@link #isWfcEnabledByPlatform()} 1546 * instead. 1547 */ isWfcEnabledByPlatform(Context context)1548 public static boolean isWfcEnabledByPlatform(Context context) { 1549 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 1550 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 1551 if (mgr != null) { 1552 return mgr.isWfcEnabledByPlatform(); 1553 } 1554 Rlog.e(TAG, "isWfcEnabledByPlatform: ImsManager null, returning default value."); 1555 return false; 1556 } 1557 1558 /** 1559 * Returns a platform configuration for WFC which may override the user 1560 * setting per slot. Note: WFC presumes that VoLTE is enabled (these are 1561 * configuration settings which must be done correctly). 1562 */ isWfcEnabledByPlatform()1563 public boolean isWfcEnabledByPlatform() { 1564 // We first read the per slot value. If doesn't exist, we read the general value. If still 1565 // doesn't exist, we use the hardcoded default value. 1566 if (SystemProperties.getInt(PROPERTY_DBG_WFC_AVAIL_OVERRIDE + 1567 Integer.toString(mPhoneId), SYSTEM_PROPERTY_NOT_SET) == 1 || 1568 SystemProperties.getInt( 1569 PROPERTY_DBG_WFC_AVAIL_OVERRIDE, SYSTEM_PROPERTY_NOT_SET) == 1) { 1570 return true; 1571 } 1572 1573 return mContext.getResources().getBoolean( 1574 com.android.internal.R.bool.config_device_wfc_ims_available) && 1575 getBooleanCarrierConfig( 1576 CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL) && 1577 isGbaValid(); 1578 } 1579 1580 /** 1581 * Returns a platform configuration for Cross SIM which may override the user 1582 * setting per slot. Note: Cross SIM presumes that VoLTE is enabled (these are 1583 * configuration settings which must be done correctly). 1584 */ isCrossSimEnabledByPlatform()1585 public boolean isCrossSimEnabledByPlatform() { 1586 if (isWfcEnabledByPlatform()) { 1587 return getBooleanCarrierConfig( 1588 CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL); 1589 } 1590 return false; 1591 } 1592 isSuppServicesOverUtEnabledByPlatform()1593 public boolean isSuppServicesOverUtEnabledByPlatform() { 1594 int cardState = mTelephonyManager.getSimState(mPhoneId); 1595 if (cardState != TelephonyManager.SIM_STATE_READY) { 1596 // Do not report enabled until we actually have an active subscription. 1597 return false; 1598 } 1599 return getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL) && 1600 isGbaValid(); 1601 } 1602 1603 /** 1604 * If carrier requires that IMS is only available if GBA capable SIM is used, 1605 * then this function checks GBA bit in EF IST. 1606 * 1607 * Format of EF IST is defined in 3GPP TS 31.103 (Section 4.2.7). 1608 */ isGbaValid()1609 private boolean isGbaValid() { 1610 if (getBooleanCarrierConfig( 1611 CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) { 1612 if (mTelephonyManager == null) { 1613 loge("isGbaValid: TelephonyManager is null, returning false."); 1614 return false; 1615 } 1616 TelephonyManager tm = mTelephonyManager.createForSubscriptionId(getSubId()); 1617 String efIst = tm.getIsimIst(); 1618 if (efIst == null) { 1619 loge("isGbaValid - ISF is NULL"); 1620 return true; 1621 } 1622 boolean result = efIst != null && efIst.length() > 1 && 1623 (0x02 & (byte)efIst.charAt(1)) != 0; 1624 if (DBG) log("isGbaValid - GBA capable=" + result + ", ISF=" + efIst); 1625 return result; 1626 } 1627 return true; 1628 } 1629 1630 /** 1631 * Will return with MmTel config value or return false if we receive an error from the AOSP 1632 * storage(ImsProvisioningController) implementation for that value. 1633 */ getImsProvisionedBoolNoException(int capability, int tech)1634 private boolean getImsProvisionedBoolNoException(int capability, int tech) { 1635 int subId = getSubId(); 1636 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 1637 logw("getImsProvisionedBoolNoException subId is invalid"); 1638 return false; 1639 } 1640 1641 ITelephony iTelephony = getITelephony(); 1642 if (iTelephony == null) { 1643 logw("getImsProvisionedBoolNoException ITelephony interface is invalid"); 1644 return false; 1645 } 1646 1647 try { 1648 return iTelephony.getImsProvisioningStatusForCapability(subId, capability, tech); 1649 } catch (RemoteException | IllegalArgumentException e) { 1650 logw("getImsProvisionedBoolNoException: operation failed for capability=" + capability 1651 + ". Exception:" + e.getMessage() + ". Returning false."); 1652 return false; 1653 } 1654 } 1655 1656 /** 1657 * Will return with Rcs config value or return false if we receive an error from the AOSP 1658 * storage(ImsProvisioningController) implementation for that value. 1659 */ getRcsProvisionedBoolNoException(int capability, int tech)1660 private boolean getRcsProvisionedBoolNoException(int capability, int tech) { 1661 int subId = getSubId(); 1662 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 1663 logw("getRcsProvisionedBoolNoException subId is invalid"); 1664 return false; 1665 } 1666 1667 ITelephony iTelephony = getITelephony(); 1668 if (iTelephony == null) { 1669 logw("getRcsProvisionedBoolNoException ITelephony interface is invalid"); 1670 return false; 1671 } 1672 1673 try { 1674 return iTelephony.getRcsProvisioningStatusForCapability(subId, capability, tech); 1675 } catch (RemoteException | IllegalArgumentException e) { 1676 logw("getRcsProvisionedBoolNoException: operation failed for capability=" + capability 1677 + ". Exception:" + e.getMessage() + ". Returning false."); 1678 return false; 1679 } 1680 } 1681 1682 /** 1683 * Push configuration updates to the ImsService implementation. 1684 */ updateImsServiceConfig()1685 public void updateImsServiceConfig() { 1686 try { 1687 int subId = getSubId(); 1688 if (!isSubIdValid(subId)) { 1689 loge("updateImsServiceConfig: invalid sub id, skipping!"); 1690 return; 1691 } 1692 PersistableBundle imsCarrierConfigs = 1693 mConfigManager.getConfigByComponentForSubId( 1694 CarrierConfigManager.Ims.KEY_PREFIX, subId); 1695 updateImsCarrierConfigs(imsCarrierConfigs); 1696 reevaluateCapabilities(); 1697 mConfigUpdated = true; 1698 } catch (ImsException e) { 1699 loge("updateImsServiceConfig: ", e); 1700 mConfigUpdated = false; 1701 } 1702 } 1703 1704 /** 1705 * Evaluate the state of the IMS capabilities and push the updated state to the ImsService. 1706 */ reevaluateCapabilities()1707 private void reevaluateCapabilities() throws ImsException { 1708 logi("reevaluateCapabilities"); 1709 CapabilityChangeRequest request = new CapabilityChangeRequest(); 1710 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(); 1711 boolean isNonTtyWifi = isNonTtyOrTtyOnVoWifiEnabled(); 1712 updateVoiceCellFeatureValue(request, isNonTty); 1713 updateVoiceWifiFeatureAndProvisionedValues(request, isNonTtyWifi); 1714 updateCrossSimFeatureAndProvisionedValues(request); 1715 updateVideoCallFeatureValue(request, isNonTty); 1716 if (com.android.server.telecom.flags.Flags.businessCallComposer()) { 1717 updateCallComposerFeatureValue(request); 1718 } else { 1719 updateCallComposerFeatureValueLegacy(request); 1720 } 1721 // Only turn on IMS for RTT if there's an active subscription present. If not, the 1722 // modem will be in emergency-call-only mode and will use separate signaling to 1723 // establish an RTT emergency call. 1724 boolean isImsNeededForRtt = updateRttConfigValue() && isActiveSubscriptionPresent(); 1725 // Supplementary services over UT do not require IMS registration. Do not alter IMS 1726 // registration based on UT. 1727 updateUtFeatureValue(request); 1728 1729 // Send the batched request to the modem. 1730 changeMmTelCapability(request); 1731 1732 if (isImsNeededForRtt || !isTurnOffImsAllowedByPlatform() || isImsNeeded(request)) { 1733 // Turn on IMS if it is used. 1734 // Also, if turning off is not allowed for current carrier, 1735 // we need to turn IMS on because it might be turned off before 1736 // phone switched to current carrier. 1737 log("reevaluateCapabilities: turnOnIms"); 1738 turnOnIms(); 1739 } else { 1740 // Turn off IMS if it is not used AND turning off is allowed for carrier. 1741 log("reevaluateCapabilities: turnOffIms"); 1742 turnOffIms(); 1743 } 1744 } 1745 1746 /** 1747 * @return {@code true} if IMS needs to be turned on for the request, {@code false} if it can 1748 * be disabled. 1749 */ isImsNeeded(CapabilityChangeRequest r)1750 private boolean isImsNeeded(CapabilityChangeRequest r) { 1751 return r.getCapabilitiesToEnable().stream() 1752 .anyMatch(c -> isImsNeededForCapability(c.getCapability())); 1753 } 1754 1755 /** 1756 * @return {@code true} if IMS needs to be turned on for the capability. 1757 */ isImsNeededForCapability(int capability)1758 private boolean isImsNeededForCapability(int capability) { 1759 if (com.android.server.telecom.flags.Flags.businessCallComposer()) { 1760 // UT does not require IMS to be enabled. 1761 return capability != MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT && 1762 // call composer is used as part of calling, so it should not trigger the 1763 // enablement 1764 // of IMS. 1765 capability != MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER && 1766 capability != MmTelFeature.MmTelCapabilities 1767 .CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY; 1768 } else { 1769 // UT does not require IMS to be enabled. 1770 return capability != MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT && 1771 // call composer is used as part of calling, so it should not trigger the 1772 // enablement 1773 // of IMS. 1774 capability != MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER; 1775 } 1776 } 1777 1778 /** 1779 * Update VoLTE config 1780 */ updateVoiceCellFeatureValue(CapabilityChangeRequest request, boolean isNonTty)1781 private void updateVoiceCellFeatureValue(CapabilityChangeRequest request, boolean isNonTty) { 1782 boolean available = isVolteEnabledByPlatform(); 1783 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(); 1784 boolean isProvisioned = isVolteProvisionedOnDevice(); 1785 boolean voLteFeatureOn = available && enabled && isNonTty && isProvisioned; 1786 boolean voNrAvailable = isImsOverNrEnabledByPlatform(); 1787 1788 log("updateVoiceCellFeatureValue: available = " + available 1789 + ", enabled = " + enabled 1790 + ", nonTTY = " + isNonTty 1791 + ", provisioned = " + isProvisioned 1792 + ", voLteFeatureOn = " + voLteFeatureOn 1793 + ", voNrAvailable = " + voNrAvailable); 1794 1795 if (voLteFeatureOn) { 1796 request.addCapabilitiesToEnableForTech( 1797 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1798 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1799 } else { 1800 request.addCapabilitiesToDisableForTech( 1801 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1802 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1803 } 1804 if (voLteFeatureOn && voNrAvailable) { 1805 request.addCapabilitiesToEnableForTech( 1806 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1807 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 1808 } else { 1809 request.addCapabilitiesToDisableForTech( 1810 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1811 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 1812 } 1813 } 1814 1815 /** 1816 * Update video call configuration 1817 */ updateVideoCallFeatureValue(CapabilityChangeRequest request, boolean isNonTty)1818 private void updateVideoCallFeatureValue(CapabilityChangeRequest request, boolean isNonTty) { 1819 boolean available = isVtEnabledByPlatform(); 1820 boolean vtEnabled = isVtEnabledByUser(); 1821 boolean advancedEnabled = isEnhanced4gLteModeSettingEnabledByUser(); 1822 boolean isDataEnabled = isDataEnabled(); 1823 boolean ignoreDataEnabledChanged = getBooleanCarrierConfig( 1824 CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS); 1825 boolean isProvisioned = isVtProvisionedOnDevice(); 1826 // TODO: Support carrier config setting about if VT settings should be associated with 1827 // advanced calling settings. 1828 boolean isLteFeatureOn = available && vtEnabled && isNonTty && isProvisioned 1829 && advancedEnabled && (ignoreDataEnabledChanged || isDataEnabled); 1830 boolean nrAvailable = isImsOverNrEnabledByPlatform(); 1831 1832 log("updateVideoCallFeatureValue: available = " + available 1833 + ", vtenabled = " + vtEnabled 1834 + ", advancedCallEnabled = " + advancedEnabled 1835 + ", nonTTY = " + isNonTty 1836 + ", data enabled = " + isDataEnabled 1837 + ", provisioned = " + isProvisioned 1838 + ", isLteFeatureOn = " + isLteFeatureOn 1839 + ", nrAvailable = " + nrAvailable); 1840 1841 if (isLteFeatureOn) { 1842 request.addCapabilitiesToEnableForTech( 1843 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 1844 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1845 // VT does not differentiate transport today, do not set IWLAN. 1846 } else { 1847 request.addCapabilitiesToDisableForTech( 1848 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 1849 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1850 // VT does not differentiate transport today, do not set IWLAN. 1851 } 1852 1853 if (isLteFeatureOn && nrAvailable) { 1854 request.addCapabilitiesToEnableForTech( 1855 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 1856 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 1857 } else { 1858 request.addCapabilitiesToDisableForTech( 1859 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 1860 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 1861 } 1862 } 1863 1864 /** 1865 * Update WFC config 1866 */ updateVoiceWifiFeatureAndProvisionedValues(CapabilityChangeRequest request, boolean isNonTty)1867 private void updateVoiceWifiFeatureAndProvisionedValues(CapabilityChangeRequest request, 1868 boolean isNonTty) { 1869 boolean isNetworkRoaming = false; 1870 if (mTelephonyManager == null) { 1871 loge("updateVoiceWifiFeatureAndProvisionedValues: TelephonyManager is null, assuming" 1872 + " not roaming."); 1873 } else { 1874 TelephonyManager tm = mTelephonyManager.createForSubscriptionId(getSubId()); 1875 isNetworkRoaming = tm.isNetworkRoaming(); 1876 } 1877 1878 boolean available = isWfcEnabledByPlatform(); 1879 boolean enabled = isWfcEnabledByUser(); 1880 boolean isProvisioned = isWfcProvisionedOnDevice(); 1881 int mode = getWfcMode(isNetworkRoaming); 1882 boolean roaming = isWfcRoamingEnabledByUser(); 1883 boolean isFeatureOn = available && enabled && isProvisioned; 1884 1885 log("updateWfcFeatureAndProvisionedValues: available = " + available 1886 + ", enabled = " + enabled 1887 + ", mode = " + mode 1888 + ", provisioned = " + isProvisioned 1889 + ", roaming = " + roaming 1890 + ", isFeatureOn = " + isFeatureOn 1891 + ", isNonTtyWifi = " + isNonTty); 1892 1893 if (isFeatureOn && isNonTty) { 1894 request.addCapabilitiesToEnableForTech( 1895 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1896 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); 1897 } else { 1898 request.addCapabilitiesToDisableForTech( 1899 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1900 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); 1901 } 1902 1903 if (!isFeatureOn) { 1904 mode = ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED; 1905 roaming = false; 1906 } 1907 setWfcModeInternal(mode); 1908 setWfcRoamingSettingInternal(roaming); 1909 } 1910 1911 /** 1912 * Update Cross SIM config 1913 */ updateCrossSimFeatureAndProvisionedValues(CapabilityChangeRequest request)1914 private void updateCrossSimFeatureAndProvisionedValues(CapabilityChangeRequest request) { 1915 if (isCrossSimCallingEnabled()) { 1916 request.addCapabilitiesToEnableForTech( 1917 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1918 ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM); 1919 } else { 1920 request.addCapabilitiesToDisableForTech( 1921 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1922 ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM); 1923 } 1924 } 1925 1926 updateUtFeatureValue(CapabilityChangeRequest request)1927 private void updateUtFeatureValue(CapabilityChangeRequest request) { 1928 boolean isCarrierSupported = isSuppServicesOverUtEnabledByPlatform(); 1929 1930 // check new carrier config first KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE 1931 // if that returns false, check deprecated carrier config 1932 // KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL 1933 boolean requiresProvisioning = isMmTelProvisioningRequired(CAPABILITY_TYPE_UT, 1934 REGISTRATION_TECH_LTE) || getBooleanCarrierConfig( 1935 CarrierConfigManager.KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL); 1936 // Count as "provisioned" if we do not require provisioning. 1937 boolean isProvisioned = true; 1938 if (requiresProvisioning) { 1939 ITelephony telephony = getITelephony(); 1940 // Only track UT over LTE, since we do not differentiate between UT over LTE and IWLAN 1941 // currently. 1942 try { 1943 if (telephony != null) { 1944 isProvisioned = telephony.getImsProvisioningStatusForCapability(getSubId(), 1945 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, 1946 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1947 } 1948 } catch (RemoteException e) { 1949 loge("updateUtFeatureValue: couldn't reach telephony! returning provisioned"); 1950 } 1951 } 1952 boolean isFeatureOn = isCarrierSupported && isProvisioned; 1953 1954 log("updateUtFeatureValue: available = " + isCarrierSupported 1955 + ", isProvisioned = " + isProvisioned 1956 + ", enabled = " + isFeatureOn); 1957 1958 if (isFeatureOn) { 1959 request.addCapabilitiesToEnableForTech( 1960 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, 1961 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1962 } else { 1963 request.addCapabilitiesToDisableForTech( 1964 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, 1965 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1966 } 1967 } 1968 1969 /** 1970 * Update call composer capability 1971 */ updateCallComposerFeatureValueLegacy(CapabilityChangeRequest request)1972 private void updateCallComposerFeatureValueLegacy(CapabilityChangeRequest request) { 1973 boolean isUserSetEnabled = isCallComposerEnabledByUser(); 1974 boolean isCarrierConfigEnabled = getBooleanCarrierConfig( 1975 CarrierConfigManager.KEY_SUPPORTS_CALL_COMPOSER_BOOL); 1976 1977 boolean isFeatureOn = isUserSetEnabled && isCarrierConfigEnabled; 1978 boolean nrAvailable = isImsOverNrEnabledByPlatform(); 1979 1980 log("updateCallComposerFeatureValue: isUserSetEnabled = " + isUserSetEnabled 1981 + ", isCarrierConfigEnabled = " + isCarrierConfigEnabled 1982 + ", isFeatureOn = " + isFeatureOn 1983 + ", nrAvailable = " + nrAvailable); 1984 1985 if (isFeatureOn) { 1986 request.addCapabilitiesToEnableForTech( 1987 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER, 1988 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1989 } else { 1990 request.addCapabilitiesToDisableForTech( 1991 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER, 1992 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1993 } 1994 if (isFeatureOn && nrAvailable) { 1995 request.addCapabilitiesToEnableForTech( 1996 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER, 1997 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 1998 } else { 1999 request.addCapabilitiesToDisableForTech( 2000 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER, 2001 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 2002 } 2003 } 2004 2005 /** 2006 * Update call composer capability 2007 */ updateCallComposerFeatureValue(CapabilityChangeRequest request)2008 private void updateCallComposerFeatureValue(CapabilityChangeRequest request) { 2009 // query user set values 2010 boolean isCallComposerEnabledByUser = isCallComposerEnabledByUser(); 2011 boolean isBusinessComposerEnabledByUser = isBusinessOnlyCallComposerEnabledByUser(); 2012 // query carrier set values 2013 boolean isCallComposerEnabledByConfig = getBooleanCarrierConfig( 2014 CarrierConfigManager.KEY_SUPPORTS_CALL_COMPOSER_BOOL); 2015 boolean isBusinessComposerEnabledByConfig = getBooleanCarrierConfig( 2016 CarrierConfigManager.KEY_SUPPORTS_BUSINESS_CALL_COMPOSER_BOOL); 2017 // determine feature settings 2018 boolean isCallComposerFeatureOn = isCallComposerEnabledByUser 2019 && isCallComposerEnabledByConfig; 2020 boolean isBusinessOnlyComposerFeatureOn = isBusinessComposerEnabledByUser 2021 && isBusinessComposerEnabledByConfig; 2022 2023 boolean nrAvailable = isImsOverNrEnabledByPlatform(); 2024 2025 logi("updateCallComposerFeatureValue:" 2026 + " isCallComposerEnabledByUser = " + isCallComposerEnabledByUser 2027 + ", isCallComposerEnabledByConfig = " + isCallComposerEnabledByConfig 2028 + ", isCallComposerFeatureOn = " + isCallComposerFeatureOn 2029 + ", isBusinessOnlyComposerFeatureOn = " + isBusinessOnlyComposerFeatureOn 2030 + ", isBusinessComposerEnabledByUser = " + isBusinessComposerEnabledByUser 2031 + ", isBusinessComposerEnabledByConfig = " + isBusinessComposerEnabledByConfig 2032 + ", nrAvailable = " + nrAvailable); 2033 2034 // enable/disable composers for LTE 2035 if (isCallComposerFeatureOn) { 2036 request.addCapabilitiesToEnableForTech( 2037 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER, 2038 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 2039 request.addCapabilitiesToEnableForTech( 2040 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY, 2041 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 2042 } else if (isBusinessOnlyComposerFeatureOn) { 2043 request.addCapabilitiesToEnableForTech( 2044 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY, 2045 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 2046 request.addCapabilitiesToDisableForTech( 2047 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER, 2048 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 2049 } else { 2050 request.addCapabilitiesToDisableForTech( 2051 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER, 2052 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 2053 request.addCapabilitiesToDisableForTech( 2054 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY, 2055 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 2056 } 2057 2058 // enable/disable composers for NR 2059 if (isCallComposerFeatureOn && nrAvailable) { 2060 request.addCapabilitiesToEnableForTech( 2061 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER, 2062 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 2063 request.addCapabilitiesToEnableForTech( 2064 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY, 2065 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 2066 } else if (isBusinessOnlyComposerFeatureOn && nrAvailable) { 2067 request.addCapabilitiesToEnableForTech( 2068 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY, 2069 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 2070 request.addCapabilitiesToDisableForTech( 2071 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER, 2072 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 2073 } else { 2074 request.addCapabilitiesToDisableForTech( 2075 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER, 2076 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 2077 request.addCapabilitiesToDisableForTech( 2078 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER_BUSINESS_ONLY, 2079 ImsRegistrationImplBase.REGISTRATION_TECH_NR); 2080 } 2081 } 2082 2083 /** 2084 * Do NOT use this directly, instead use {@link #getInstance(Context, int)}. 2085 */ ImsManager(Context context, int phoneId)2086 private ImsManager(Context context, int phoneId) { 2087 mContext = context; 2088 mPhoneId = phoneId; 2089 mTelephonyManager = context.getSystemService(TelephonyManager.class); 2090 mSubscriptionManagerProxy = new DefaultSubscriptionManagerProxy(context); 2091 mSettingsProxy = new DefaultSettingsProxy(); 2092 mConfigManager = (CarrierConfigManager) context.getSystemService( 2093 Context.CARRIER_CONFIG_SERVICE); 2094 mExecutor = new LazyExecutor(); 2095 mBinderCache = new BinderCacheManager<>(ImsManager::getITelephonyInterface); 2096 // Start off with an empty MmTelFeatureConnection, which will be replaced one an 2097 // ImsService is available (ImsManager expects a non-null FeatureConnection) 2098 associate(null /*container*/, SubscriptionManager.INVALID_SUBSCRIPTION_ID); 2099 } 2100 2101 /** 2102 * Used for testing only to inject dependencies. 2103 */ 2104 @VisibleForTesting ImsManager(Context context, int phoneId, MmTelFeatureConnectionFactory factory, SubscriptionManagerProxy subManagerProxy, SettingsProxy settingsProxy, BinderCacheManager binderCacheManager)2105 public ImsManager(Context context, int phoneId, MmTelFeatureConnectionFactory factory, 2106 SubscriptionManagerProxy subManagerProxy, SettingsProxy settingsProxy, 2107 BinderCacheManager binderCacheManager) { 2108 mContext = context; 2109 mPhoneId = phoneId; 2110 mMmTelFeatureConnectionFactory = factory; 2111 mTelephonyManager = context.getSystemService(TelephonyManager.class); 2112 mSubscriptionManagerProxy = subManagerProxy; 2113 mSettingsProxy = settingsProxy; 2114 mConfigManager = (CarrierConfigManager) context.getSystemService( 2115 Context.CARRIER_CONFIG_SERVICE); 2116 // Do not multithread tests 2117 mExecutor = Runnable::run; 2118 mBinderCache = binderCacheManager; 2119 // MmTelFeatureConnection should be replaced for tests with mMmTelFeatureConnectionFactory. 2120 associate(null /*container*/, SubscriptionManager.INVALID_SUBSCRIPTION_ID); 2121 } 2122 2123 /* 2124 * Returns a flag indicating whether the IMS service is available. 2125 */ isServiceAvailable()2126 public boolean isServiceAvailable() { 2127 return mMmTelConnectionRef.get().isBinderAlive(); 2128 } 2129 2130 /* 2131 * Returns a flag indicating whether the IMS service is ready to send requests to lower layers. 2132 */ isServiceReady()2133 public boolean isServiceReady() { 2134 return mMmTelConnectionRef.get().isBinderReady(); 2135 } 2136 2137 /** 2138 * Opens the IMS service for making calls and/or receiving generic IMS calls as well as 2139 * register listeners for ECBM, Multiendpoint, and UT if the ImsService supports it. 2140 * <p> 2141 * The caller may make subsequent calls through {@link #makeCall}. 2142 * The IMS service will register the device to the operator's network with the credentials 2143 * (from ISIM) periodically in order to receive calls from the operator's network. 2144 * When the IMS service receives a new call, it will call 2145 * {@link MmTelFeature.Listener#onIncomingCall} 2146 * @param listener A {@link MmTelFeature.Listener}, which is the interface the 2147 * {@link MmTelFeature} uses to notify the framework of updates. 2148 * @param ecbmListener Listener used for ECBM indications. 2149 * @param multiEndpointListener Listener used for multiEndpoint indications. 2150 * @throws NullPointerException if {@code listener} is null 2151 * @throws ImsException if calling the IMS service results in an error 2152 */ open(MmTelFeature.Listener listener, ImsEcbmStateListener ecbmListener, ImsExternalCallStateListener multiEndpointListener)2153 public void open(MmTelFeature.Listener listener, ImsEcbmStateListener ecbmListener, 2154 ImsExternalCallStateListener multiEndpointListener) throws ImsException { 2155 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2156 2157 if (listener == null) { 2158 throw new NullPointerException("listener can't be null"); 2159 } 2160 2161 try { 2162 c.openConnection(listener, ecbmListener, multiEndpointListener); 2163 } catch (RemoteException e) { 2164 throw new ImsException("open()", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2165 } 2166 } 2167 2168 /** 2169 * Adds registration listener to the IMS service. 2170 * 2171 * @param serviceClass a service class specified in {@link ImsServiceClass} 2172 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}. 2173 * @param listener To listen to IMS registration events; It cannot be null 2174 * @throws NullPointerException if {@code listener} is null 2175 * @throws ImsException if calling the IMS service results in an error 2176 * 2177 * @deprecated Use {@link #addRegistrationListener(ImsConnectionStateListener)} instead. 2178 */ addRegistrationListener(int serviceClass, ImsConnectionStateListener listener)2179 public void addRegistrationListener(int serviceClass, ImsConnectionStateListener listener) 2180 throws ImsException { 2181 addRegistrationListener(listener); 2182 } 2183 2184 /** 2185 * Adds registration listener to the IMS service. 2186 * 2187 * @param listener To listen to IMS registration events; It cannot be null 2188 * @throws NullPointerException if {@code listener} is null 2189 * @throws ImsException if calling the IMS service results in an error 2190 * @deprecated use {@link #addRegistrationCallback(RegistrationManager.RegistrationCallback, 2191 * Executor)} instead. 2192 */ addRegistrationListener(ImsConnectionStateListener listener)2193 public void addRegistrationListener(ImsConnectionStateListener listener) throws ImsException { 2194 if (listener == null) { 2195 throw new NullPointerException("listener can't be null"); 2196 } 2197 addRegistrationCallback(listener, getImsThreadExecutor()); 2198 // connect the ImsConnectionStateListener to the new CapabilityCallback. 2199 addCapabilitiesCallback(new ImsMmTelManager.CapabilityCallback() { 2200 @Override 2201 public void onCapabilitiesStatusChanged( 2202 MmTelFeature.MmTelCapabilities capabilities) { 2203 listener.onFeatureCapabilityChangedAdapter(getRegistrationTech(), capabilities); 2204 } 2205 }, getImsThreadExecutor()); 2206 log("Registration Callback registered."); 2207 } 2208 2209 /** 2210 * Adds a callback that gets called when IMS registration has changed for the slot ID 2211 * associated with this ImsManager. 2212 * @param callback A {@link RegistrationManager.RegistrationCallback} that will notify the 2213 * caller when IMS registration status has changed. 2214 * @param executor The Executor that the callback should be called on. 2215 * @throws ImsException when the ImsService connection is not available. 2216 */ addRegistrationCallback(RegistrationManager.RegistrationCallback callback, Executor executor)2217 public void addRegistrationCallback(RegistrationManager.RegistrationCallback callback, 2218 Executor executor) 2219 throws ImsException { 2220 if (callback == null) { 2221 throw new NullPointerException("registration callback can't be null"); 2222 } 2223 2224 try { 2225 callback.setExecutor(executor); 2226 mMmTelConnectionRef.get().addRegistrationCallback(callback.getBinder()); 2227 log("Registration Callback registered."); 2228 // Only record if there isn't a RemoteException. 2229 } catch (IllegalStateException e) { 2230 throw new ImsException("addRegistrationCallback(IRIB)", e, 2231 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2232 } 2233 } 2234 2235 /** 2236 * Removes a previously added registration callback that was added via 2237 * {@link #addRegistrationCallback(RegistrationManager.RegistrationCallback, Executor)} . 2238 * @param callback A {@link RegistrationManager.RegistrationCallback} that was previously added. 2239 */ removeRegistrationListener(RegistrationManager.RegistrationCallback callback)2240 public void removeRegistrationListener(RegistrationManager.RegistrationCallback callback) { 2241 if (callback == null) { 2242 throw new NullPointerException("registration callback can't be null"); 2243 } 2244 mMmTelConnectionRef.get().removeRegistrationCallback(callback.getBinder()); 2245 log("Registration callback removed."); 2246 } 2247 2248 /** 2249 * Adds a callback that gets called when IMS registration has changed for a specific 2250 * subscription. 2251 * 2252 * @param callback A {@link RegistrationManager.RegistrationCallback} that will notify the 2253 * caller when IMS registration status has changed. 2254 * @param subId The subscription ID to register this registration callback for. 2255 * @throws RemoteException when the ImsService connection is not available. 2256 */ addRegistrationCallbackForSubscription(IImsRegistrationCallback callback, int subId)2257 public void addRegistrationCallbackForSubscription(IImsRegistrationCallback callback, int subId) 2258 throws RemoteException { 2259 if (callback == null) { 2260 throw new IllegalArgumentException("registration callback can't be null"); 2261 } 2262 mMmTelConnectionRef.get().addRegistrationCallbackForSubscription(callback, subId); 2263 log("Registration Callback registered."); 2264 // Only record if there isn't a RemoteException. 2265 } 2266 2267 /** 2268 * Removes a previously registered {@link RegistrationManager.RegistrationCallback} callback 2269 * that is associated with a specific subscription. 2270 */ removeRegistrationCallbackForSubscription(IImsRegistrationCallback callback, int subId)2271 public void removeRegistrationCallbackForSubscription(IImsRegistrationCallback callback, 2272 int subId) { 2273 if (callback == null) { 2274 throw new IllegalArgumentException("registration callback can't be null"); 2275 } 2276 mMmTelConnectionRef.get().removeRegistrationCallbackForSubscription(callback, subId); 2277 } 2278 2279 /** 2280 * Adds a callback that gets called when IMS emergency registration has changed for a specific 2281 * subscription. 2282 * 2283 * @param callback A {@link RegistrationManager.RegistrationCallback} that will notify the 2284 * caller when IMS registration status has changed. 2285 * @param subId The subscription ID to register this registration callback for. 2286 * @throws RemoteException when the ImsService connection is not available. 2287 */ addEmergencyRegistrationCallbackForSubscription( IImsRegistrationCallback callback, int subId)2288 public void addEmergencyRegistrationCallbackForSubscription( 2289 IImsRegistrationCallback callback, int subId) throws RemoteException { 2290 if (callback == null) { 2291 throw new IllegalArgumentException("emergency registration callback can't be null"); 2292 } 2293 mMmTelConnectionRef.get().addEmergencyRegistrationCallbackForSubscription(callback, subId); 2294 log("Emergency registration Callback registered."); 2295 // Only record if there isn't a RemoteException. 2296 } 2297 2298 /** 2299 * Removes a previously registered {@link RegistrationManager.RegistrationCallback} callback 2300 * that is associated with a specific subscription. 2301 */ removeEmergencyRegistrationCallbackForSubscription( IImsRegistrationCallback callback, int subId)2302 public void removeEmergencyRegistrationCallbackForSubscription( 2303 IImsRegistrationCallback callback, int subId) { 2304 if (callback == null) { 2305 throw new IllegalArgumentException("emergency registration callback can't be null"); 2306 } 2307 mMmTelConnectionRef.get().removeEmergencyRegistrationCallbackForSubscription(callback, 2308 subId); 2309 } 2310 2311 /** 2312 * Adds a callback that gets called when MMTel capability status has changed, for example when 2313 * Voice over IMS or VT over IMS is not available currently. 2314 * @param callback A {@link ImsMmTelManager.CapabilityCallback} that will notify the caller when 2315 * MMTel capability status has changed. 2316 * @param executor The Executor that the callback should be called on. 2317 * @throws ImsException when the ImsService connection is not available. 2318 */ addCapabilitiesCallback(ImsMmTelManager.CapabilityCallback callback, Executor executor)2319 public void addCapabilitiesCallback(ImsMmTelManager.CapabilityCallback callback, 2320 Executor executor) throws ImsException { 2321 if (callback == null) { 2322 throw new NullPointerException("capabilities callback can't be null"); 2323 } 2324 2325 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2326 try { 2327 callback.setExecutor(executor); 2328 c.addCapabilityCallback(callback.getBinder()); 2329 log("Capability Callback registered."); 2330 // Only record if there isn't a RemoteException. 2331 } catch (IllegalStateException e) { 2332 throw new ImsException("addCapabilitiesCallback(IF)", e, 2333 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2334 } 2335 } 2336 2337 /** 2338 * Removes a previously registered {@link ImsMmTelManager.CapabilityCallback} callback. 2339 */ removeCapabilitiesCallback(ImsMmTelManager.CapabilityCallback callback)2340 public void removeCapabilitiesCallback(ImsMmTelManager.CapabilityCallback callback) { 2341 if (callback == null) { 2342 throw new NullPointerException("capabilities callback can't be null"); 2343 } 2344 2345 try { 2346 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2347 c.removeCapabilityCallback(callback.getBinder()); 2348 } catch (ImsException e) { 2349 log("Exception removing Capability , exception=" + e); 2350 } 2351 } 2352 2353 /** 2354 * Adds a callback that gets called when IMS capabilities have changed for a specified 2355 * subscription. 2356 * @param callback A {@link ImsMmTelManager.CapabilityCallback} that will notify the caller 2357 * when the IMS Capabilities have changed. 2358 * @param subId The subscription that is associated with the callback. 2359 * @throws RemoteException when the ImsService connection is not available. 2360 */ addCapabilitiesCallbackForSubscription(IImsCapabilityCallback callback, int subId)2361 public void addCapabilitiesCallbackForSubscription(IImsCapabilityCallback callback, int subId) 2362 throws RemoteException { 2363 if (callback == null) { 2364 throw new IllegalArgumentException("registration callback can't be null"); 2365 } 2366 mMmTelConnectionRef.get().addCapabilityCallbackForSubscription(callback, subId); 2367 log("Capability Callback registered for subscription."); 2368 } 2369 2370 /** 2371 * Removes a previously registered {@link ImsMmTelManager.CapabilityCallback} that was 2372 * associated with a specific subscription. 2373 */ removeCapabilitiesCallbackForSubscription(IImsCapabilityCallback callback, int subId)2374 public void removeCapabilitiesCallbackForSubscription(IImsCapabilityCallback callback, 2375 int subId) { 2376 if (callback == null) { 2377 throw new IllegalArgumentException("capabilities callback can't be null"); 2378 } 2379 mMmTelConnectionRef.get().removeCapabilityCallbackForSubscription(callback, subId); 2380 } 2381 2382 /** 2383 * Removes the registration listener from the IMS service. 2384 * 2385 * @param listener Previously registered listener that will be removed. Can not be null. 2386 * @throws NullPointerException if {@code listener} is null 2387 * @throws ImsException if calling the IMS service results in an error 2388 * instead. 2389 */ removeRegistrationListener(ImsConnectionStateListener listener)2390 public void removeRegistrationListener(ImsConnectionStateListener listener) 2391 throws ImsException { 2392 if (listener == null) { 2393 throw new NullPointerException("listener can't be null"); 2394 } 2395 2396 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2397 c.removeRegistrationCallback(listener.getBinder()); 2398 log("Registration Callback/Listener registered."); 2399 // Only record if there isn't a RemoteException. 2400 } 2401 2402 /** 2403 * Adds a callback that gets called when Provisioning has changed for a specified subscription. 2404 * @param callback A {@link ProvisioningManager.Callback} that will notify the caller when 2405 * provisioning has changed. 2406 * @param subId The subscription that is associated with the callback. 2407 * @throws IllegalStateException when the {@link ImsService} connection is not available. 2408 * @throws IllegalArgumentException when the {@link IImsConfigCallback} argument is null. 2409 */ addProvisioningCallbackForSubscription(IImsConfigCallback callback, int subId)2410 public void addProvisioningCallbackForSubscription(IImsConfigCallback callback, int subId) { 2411 if (callback == null) { 2412 throw new IllegalArgumentException("provisioning callback can't be null"); 2413 } 2414 2415 mMmTelConnectionRef.get().addProvisioningCallbackForSubscription(callback, subId); 2416 log("Capability Callback registered for subscription."); 2417 } 2418 2419 /** 2420 * Removes a previously registered {@link ProvisioningManager.Callback} that was associated with 2421 * a specific subscription. 2422 * @throws IllegalStateException when the {@link ImsService} connection is not available. 2423 * @throws IllegalArgumentException when the {@link IImsConfigCallback} argument is null. 2424 */ removeProvisioningCallbackForSubscription(IImsConfigCallback callback, int subId)2425 public void removeProvisioningCallbackForSubscription(IImsConfigCallback callback, int subId) { 2426 if (callback == null) { 2427 throw new IllegalArgumentException("provisioning callback can't be null"); 2428 } 2429 2430 mMmTelConnectionRef.get().removeProvisioningCallbackForSubscription(callback, subId); 2431 } 2432 getRegistrationTech()2433 public @ImsRegistrationImplBase.ImsRegistrationTech int getRegistrationTech() { 2434 try { 2435 return mMmTelConnectionRef.get().getRegistrationTech(); 2436 } catch (RemoteException e) { 2437 logw("getRegistrationTech: no connection to ImsService."); 2438 return ImsRegistrationImplBase.REGISTRATION_TECH_NONE; 2439 } 2440 } 2441 getRegistrationTech(Consumer<Integer> callback)2442 public void getRegistrationTech(Consumer<Integer> callback) { 2443 getImsThreadExecutor().execute(() -> { 2444 try { 2445 int tech = mMmTelConnectionRef.get().getRegistrationTech(); 2446 callback.accept(tech); 2447 } catch (RemoteException e) { 2448 logw("getRegistrationTech(C): no connection to ImsService."); 2449 callback.accept(ImsRegistrationImplBase.REGISTRATION_TECH_NONE); 2450 } 2451 }); 2452 } 2453 2454 /** 2455 * Closes the connection opened in {@link #open} and removes the associated listeners. 2456 */ close()2457 public void close() { 2458 mMmTelConnectionRef.get().closeConnection(); 2459 } 2460 2461 /** 2462 * Create or get the existing configuration interface to provision / withdraw the supplementary 2463 * service settings. 2464 * <p> 2465 * There can only be one connection to the UT interface, so this may only be called by one 2466 * ImsManager instance. Otherwise, an IllegalStateException will be thrown. 2467 * 2468 * @return the Ut interface instance 2469 * @throws ImsException if getting the Ut interface results in an error 2470 */ createOrGetSupplementaryServiceConfiguration()2471 public ImsUtInterface createOrGetSupplementaryServiceConfiguration() throws ImsException { 2472 ImsUt iUt; 2473 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2474 try { 2475 iUt = c.createOrGetUtInterface(); 2476 if (iUt == null) { 2477 throw new ImsException("getSupplementaryServiceConfiguration()", 2478 ImsReasonInfo.CODE_UT_NOT_SUPPORTED); 2479 } 2480 } catch (RemoteException e) { 2481 throw new ImsException("getSupplementaryServiceConfiguration()", e, 2482 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2483 } 2484 return iUt; 2485 } 2486 2487 /** 2488 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state. 2489 * 2490 * @param serviceType a service type that is specified in {@link ImsCallProfile} 2491 * {@link ImsCallProfile#SERVICE_TYPE_NONE} 2492 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 2493 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 2494 * @param callType a call type that is specified in {@link ImsCallProfile} 2495 * {@link ImsCallProfile#CALL_TYPE_VOICE} 2496 * {@link ImsCallProfile#CALL_TYPE_VT} 2497 * {@link ImsCallProfile#CALL_TYPE_VT_TX} 2498 * {@link ImsCallProfile#CALL_TYPE_VT_RX} 2499 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR} 2500 * {@link ImsCallProfile#CALL_TYPE_VS} 2501 * {@link ImsCallProfile#CALL_TYPE_VS_TX} 2502 * {@link ImsCallProfile#CALL_TYPE_VS_RX} 2503 * @return a {@link ImsCallProfile} object 2504 * @throws ImsException if calling the IMS service results in an error 2505 */ createCallProfile(int serviceType, int callType)2506 public ImsCallProfile createCallProfile(int serviceType, int callType) throws ImsException { 2507 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2508 2509 try { 2510 return c.createCallProfile(serviceType, callType); 2511 } catch (RemoteException e) { 2512 throw new ImsException("createCallProfile()", e, 2513 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2514 } 2515 } 2516 2517 /** 2518 * Informs the {@link ImsService} of the {@link RtpHeaderExtensionType}s which the framework 2519 * intends to use for incoming and outgoing calls. 2520 * <p> 2521 * See {@link RtpHeaderExtensionType} for more information. 2522 * @param types The RTP header extension types to use for incoming and outgoing calls, or 2523 * empty list if none defined. 2524 * @throws ImsException 2525 */ setOfferedRtpHeaderExtensionTypes(@onNull Set<RtpHeaderExtensionType> types)2526 public void setOfferedRtpHeaderExtensionTypes(@NonNull Set<RtpHeaderExtensionType> types) 2527 throws ImsException { 2528 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2529 2530 try { 2531 c.changeOfferedRtpHeaderExtensionTypes(types); 2532 } catch (RemoteException e) { 2533 throw new ImsException("setOfferedRtpHeaderExtensionTypes()", e, 2534 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2535 } 2536 } 2537 2538 /** 2539 * Creates a {@link ImsCall} to make a call. 2540 * 2541 * @param profile a call profile to make the call 2542 * (it contains service type, call type, media information, etc.) 2543 * @param callees participants to invite the conference call 2544 * @param listener listen to the call events from {@link ImsCall} 2545 * @return a {@link ImsCall} object 2546 * @throws ImsException if calling the IMS service results in an error 2547 */ makeCall(ImsCallProfile profile, String[] callees, ImsCall.Listener listener)2548 public ImsCall makeCall(ImsCallProfile profile, String[] callees, 2549 ImsCall.Listener listener) throws ImsException { 2550 if (DBG) { 2551 log("makeCall :: profile=" + profile); 2552 } 2553 2554 // Check we are still alive 2555 getOrThrowExceptionIfServiceUnavailable(); 2556 2557 ImsCall call = new ImsCall(mContext, profile); 2558 2559 call.setListener(listener); 2560 ImsCallSession session = createCallSession(profile); 2561 2562 if ((callees != null) && (callees.length == 1) && !(session.isMultiparty())) { 2563 call.start(session, callees[0]); 2564 } else { 2565 call.start(session, callees); 2566 } 2567 2568 return call; 2569 } 2570 2571 /** 2572 * Creates a {@link ImsCall} to take an incoming call. 2573 * 2574 * @param listener to listen to the call events from {@link ImsCall} 2575 * @return a {@link ImsCall} object 2576 * @throws ImsException if calling the IMS service results in an error 2577 */ takeCall(IImsCallSession session, ImsCall.Listener listener)2578 public ImsCall takeCall(IImsCallSession session, ImsCall.Listener listener) 2579 throws ImsException { 2580 // Check we are still alive 2581 getOrThrowExceptionIfServiceUnavailable(); 2582 try { 2583 if (session == null) { 2584 throw new ImsException("No pending session for the call", 2585 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL); 2586 } 2587 2588 ImsCall call = new ImsCall(mContext, session.getCallProfile()); 2589 2590 call.attachSession(new ImsCallSession(session)); 2591 call.setListener(listener); 2592 2593 if (Flags.ignoreAlreadyTerminatedIncomingCallBeforeRegisteringListener()){ 2594 // If the call session already terminated before registering callback then the 2595 // framework should ignore incoming call. 2596 if (!ImsCall.isSessionAlive(call.getSession())) { 2597 loge("takeCall : ImsCallSession is not alive"); 2598 throw new ImsException("takeCall() : ImsCallSession is not alive", 2599 ImsReasonInfo.CODE_UNSPECIFIED); 2600 } 2601 } 2602 return call; 2603 } catch (Throwable t) { 2604 loge("takeCall caught: ", t); 2605 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED); 2606 } 2607 } 2608 2609 /** 2610 * Gets the config interface to get/set service/capability parameters. 2611 * 2612 * @return the ImsConfig instance. 2613 * @throws ImsException if getting the setting interface results in an error. 2614 */ 2615 @UnsupportedAppUsage getConfigInterface()2616 public ImsConfig getConfigInterface() throws ImsException { 2617 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2618 2619 IImsConfig config = c.getConfig(); 2620 if (config == null) { 2621 throw new ImsException("getConfigInterface()", 2622 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE); 2623 } 2624 return new ImsConfig(config); 2625 } 2626 2627 /** 2628 * Enable or disable a capability for multiple radio technologies. 2629 */ changeMmTelCapability(boolean isEnabled, int capability, int... radioTechs)2630 public void changeMmTelCapability(boolean isEnabled, int capability, 2631 int... radioTechs) throws ImsException { 2632 CapabilityChangeRequest request = new CapabilityChangeRequest(); 2633 if (isEnabled) { 2634 for (int tech : radioTechs) { 2635 request.addCapabilitiesToEnableForTech(capability, tech); 2636 } 2637 } else { 2638 for (int tech : radioTechs) { 2639 request.addCapabilitiesToDisableForTech(capability, tech); 2640 } 2641 } 2642 changeMmTelCapability(request); 2643 } 2644 changeMmTelCapability(CapabilityChangeRequest r)2645 private void changeMmTelCapability(CapabilityChangeRequest r) throws ImsException { 2646 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2647 try { 2648 logi("changeMmTelCapability: changing capabilities for sub: " + getSubId() 2649 + ", request: " + r); 2650 c.changeEnabledCapabilities(r, null); 2651 ImsStatsCallback cb = getStatsCallback(mPhoneId); 2652 if (cb == null) { 2653 return; 2654 } 2655 for (CapabilityChangeRequest.CapabilityPair enabledCaps : r.getCapabilitiesToEnable()) { 2656 cb.onEnabledMmTelCapabilitiesChanged(enabledCaps.getCapability(), 2657 enabledCaps.getRadioTech(), true); 2658 } 2659 for (CapabilityChangeRequest.CapabilityPair disabledCaps : 2660 r.getCapabilitiesToDisable()) { 2661 cb.onEnabledMmTelCapabilitiesChanged(disabledCaps.getCapability(), 2662 disabledCaps.getRadioTech(), false); 2663 } 2664 } catch (RemoteException e) { 2665 throw new ImsException("changeMmTelCapability(CCR)", e, 2666 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2667 } 2668 } 2669 updateRttConfigValue()2670 private boolean updateRttConfigValue() { 2671 // If there's no active sub anywhere on the device, enable RTT on the modem so that 2672 // the device can make an emergency call. 2673 2674 boolean isActiveSubscriptionPresent = isActiveSubscriptionPresent(); 2675 boolean isCarrierSupported = 2676 getBooleanCarrierConfig(CarrierConfigManager.KEY_RTT_SUPPORTED_BOOL) 2677 || !isActiveSubscriptionPresent; 2678 2679 int defaultRttMode = 2680 getIntCarrierConfig(CarrierConfigManager.KEY_DEFAULT_RTT_MODE_INT); 2681 int rttMode = mSettingsProxy.getSecureIntSetting(mContext.getContentResolver(), 2682 Settings.Secure.RTT_CALLING_MODE, defaultRttMode); 2683 logi("defaultRttMode = " + defaultRttMode + " rttMode = " + rttMode); 2684 boolean isRttAlwaysOnCarrierConfig = getBooleanCarrierConfig( 2685 CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL); 2686 if (isRttAlwaysOnCarrierConfig && rttMode == defaultRttMode) { 2687 mSettingsProxy.putSecureIntSetting(mContext.getContentResolver(), 2688 Settings.Secure.RTT_CALLING_MODE, defaultRttMode); 2689 } 2690 2691 boolean isRttUiSettingEnabled = mSettingsProxy.getSecureIntSetting( 2692 mContext.getContentResolver(), Settings.Secure.RTT_CALLING_MODE, 0) != 0; 2693 2694 boolean shouldImsRttBeOn = isRttUiSettingEnabled || isRttAlwaysOnCarrierConfig; 2695 logi("update RTT: settings value: " + isRttUiSettingEnabled + " always-on carrierconfig: " 2696 + isRttAlwaysOnCarrierConfig 2697 + "isActiveSubscriptionPresent: " + isActiveSubscriptionPresent); 2698 2699 if (isCarrierSupported) { 2700 setRttConfig(shouldImsRttBeOn); 2701 } else { 2702 setRttConfig(false); 2703 } 2704 return isCarrierSupported && shouldImsRttBeOn; 2705 } 2706 setRttConfig(boolean enabled)2707 private void setRttConfig(boolean enabled) { 2708 final int value = enabled ? ProvisioningManager.PROVISIONING_VALUE_ENABLED : 2709 ProvisioningManager.PROVISIONING_VALUE_DISABLED; 2710 getImsThreadExecutor().execute(() -> { 2711 try { 2712 logi("Setting RTT enabled to " + enabled); 2713 getConfigInterface().setProvisionedValue( 2714 ImsConfig.ConfigConstants.RTT_SETTING_ENABLED, value); 2715 } catch (ImsException e) { 2716 loge("Unable to set RTT value enabled to " + enabled + ": " + e); 2717 } 2718 }); 2719 } 2720 queryMmTelCapability( @mTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)2721 public boolean queryMmTelCapability( 2722 @MmTelFeature.MmTelCapabilities.MmTelCapability int capability, 2723 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) throws ImsException { 2724 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2725 2726 BlockingQueue<Boolean> result = new LinkedBlockingDeque<>(1); 2727 2728 try { 2729 c.queryEnabledCapabilities(capability, radioTech, new IImsCapabilityCallback.Stub() { 2730 @Override 2731 public void onQueryCapabilityConfiguration(int resCap, int resTech, 2732 boolean enabled) { 2733 if (resCap == capability && resTech == radioTech) { 2734 result.offer(enabled); 2735 } 2736 } 2737 2738 @Override 2739 public void onChangeCapabilityConfigurationError(int capability, 2740 int radioTech, int reason) { 2741 2742 } 2743 2744 @Override 2745 public void onCapabilitiesStatusChanged(int config) { 2746 2747 } 2748 }); 2749 } catch (RemoteException e) { 2750 throw new ImsException("queryMmTelCapability()", e, 2751 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2752 } 2753 2754 try { 2755 return result.poll(RESPONSE_WAIT_TIME_MS, TimeUnit.MILLISECONDS); 2756 } catch (InterruptedException e) { 2757 logw("queryMmTelCapability: interrupted while waiting for response"); 2758 } 2759 return false; 2760 } 2761 queryMmTelCapabilityStatus( @mTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)2762 public boolean queryMmTelCapabilityStatus( 2763 @MmTelFeature.MmTelCapabilities.MmTelCapability int capability, 2764 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) throws ImsException { 2765 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2766 2767 if (getRegistrationTech() != radioTech) 2768 return false; 2769 2770 try { 2771 2772 MmTelFeature.MmTelCapabilities capabilities = 2773 c.queryCapabilityStatus(); 2774 2775 return capabilities.isCapable(capability); 2776 } catch (RemoteException e) { 2777 throw new ImsException("queryMmTelCapabilityStatus()", e, 2778 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2779 } 2780 } 2781 2782 /** 2783 * Enable the RTT configuration on this device. 2784 */ setRttEnabled(boolean enabled)2785 public void setRttEnabled(boolean enabled) { 2786 if (enabled) { 2787 // Override this setting if RTT is enabled. 2788 setEnhanced4gLteModeSetting(true /*enabled*/); 2789 } 2790 setRttConfig(enabled); 2791 } 2792 2793 /** 2794 * Set the TTY mode. This is the actual tty mode (varies depending on peripheral status) 2795 */ setTtyMode(int ttyMode)2796 public void setTtyMode(int ttyMode) throws ImsException { 2797 boolean isNonTtyOrTtyOnVolteEnabled = isTtyOnVoLteCapable() || 2798 (ttyMode == TelecomManager.TTY_MODE_OFF); 2799 2800 boolean isNonTtyOrTtyOnWifiEnabled = isTtyOnVoWifiCapable() || 2801 (ttyMode == TelecomManager.TTY_MODE_OFF); 2802 2803 CapabilityChangeRequest request = new CapabilityChangeRequest(); 2804 updateVoiceCellFeatureValue(request, isNonTtyOrTtyOnVolteEnabled); 2805 updateVideoCallFeatureValue(request, isNonTtyOrTtyOnVolteEnabled); 2806 updateVoiceWifiFeatureAndProvisionedValues(request, isNonTtyOrTtyOnWifiEnabled); 2807 // update MMTEL caps for the new configuration. 2808 changeMmTelCapability(request); 2809 if (isImsNeeded(request)) { 2810 // Only turn on IMS if voice/video is enabled now in the new configuration. 2811 turnOnIms(); 2812 } 2813 } 2814 2815 /** 2816 * Sets the UI TTY mode. This is the preferred TTY mode that the user sets in the call 2817 * settings screen. 2818 * @param uiTtyMode TTY Mode, valid options are: 2819 * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF} 2820 * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL} 2821 * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO} 2822 * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO} 2823 * @param onComplete A Message that will be called by the ImsService when it has completed this 2824 * operation or null if not waiting for an async response. The Message must contain a 2825 * valid {@link Message#replyTo} {@link android.os.Messenger}, since it will be passed 2826 * through Binder to another process. 2827 */ setUiTTYMode(Context context, int uiTtyMode, Message onComplete)2828 public void setUiTTYMode(Context context, int uiTtyMode, Message onComplete) 2829 throws ImsException { 2830 2831 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2832 try { 2833 c.setUiTTYMode(uiTtyMode, onComplete); 2834 } catch (RemoteException e) { 2835 throw new ImsException("setTTYMode()", e, 2836 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2837 } 2838 } 2839 2840 /** 2841 * Notifies the change of user setting. 2842 * 2843 * @param enabled indicates whether the user setting for call waiting is enabled or not. 2844 */ setTerminalBasedCallWaitingStatus(boolean enabled)2845 public void setTerminalBasedCallWaitingStatus(boolean enabled) throws ImsException { 2846 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2847 try { 2848 c.setTerminalBasedCallWaitingStatus(enabled); 2849 } catch (ServiceSpecificException se) { 2850 if (se.errorCode 2851 == android.telephony.ims.ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) { 2852 throw new ImsException("setTerminalBasedCallWaitingStatus()", se, 2853 ImsReasonInfo.CODE_LOCAL_IMS_NOT_SUPPORTED_ON_DEVICE); 2854 } else { 2855 throw new ImsException("setTerminalBasedCallWaitingStatus()", se, 2856 ImsReasonInfo.CODE_LOCAL_INTERNAL_ERROR); 2857 } 2858 } catch (RemoteException e) { 2859 throw new ImsException("setTerminalBasedCallWaitingStatus()", e, 2860 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2861 } 2862 } 2863 2864 /** 2865 * Returns whether all of the capabilities specified are capable or not. 2866 */ isCapable(@msService.ImsServiceCapability long capabilities)2867 public boolean isCapable(@ImsService.ImsServiceCapability long capabilities) 2868 throws ImsException { 2869 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2870 try { 2871 return c.isCapable(capabilities); 2872 } catch (RemoteException e) { 2873 throw new ImsException("isCapable()", e, 2874 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2875 } 2876 } 2877 2878 /** 2879 * Notifies SRVCC started. 2880 * @param cb The callback to receive the list of {@link SrvccCall}. 2881 */ notifySrvccStarted(ISrvccStartedCallback cb)2882 public void notifySrvccStarted(ISrvccStartedCallback cb) 2883 throws ImsException { 2884 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2885 try { 2886 c.notifySrvccStarted(cb); 2887 } catch (RemoteException e) { 2888 throw new ImsException("notifySrvccStarted", e, 2889 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2890 } 2891 } 2892 2893 /** 2894 * Notifies SRVCC is completed, IMS service will hang up all calls. 2895 */ notifySrvccCompleted()2896 public void notifySrvccCompleted() throws ImsException { 2897 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2898 try { 2899 c.notifySrvccCompleted(); 2900 } catch (RemoteException e) { 2901 throw new ImsException("notifySrvccCompleted", e, 2902 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2903 } 2904 } 2905 2906 /** 2907 * Notifies SRVCC failed. IMS service will recover and continue calls over IMS. 2908 */ notifySrvccFailed()2909 public void notifySrvccFailed() throws ImsException { 2910 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2911 try { 2912 c.notifySrvccFailed(); 2913 } catch (RemoteException e) { 2914 throw new ImsException("notifySrvccFailed", e, 2915 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2916 } 2917 } 2918 2919 /** 2920 * Notifies SRVCC is canceled. IMS service will recover and continue calls over IMS. 2921 */ notifySrvccCanceled()2922 public void notifySrvccCanceled() throws ImsException { 2923 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2924 try { 2925 c.notifySrvccCanceled(); 2926 } catch (RemoteException e) { 2927 throw new ImsException("notifySrvccCanceled", e, 2928 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2929 } 2930 } 2931 2932 /** 2933 * Notifies that radio triggered IMS deregistration. 2934 * @param reason the reason why the deregistration is triggered. 2935 */ triggerDeregistration(@msRegistrationImplBase.ImsDeregistrationReason int reason)2936 public void triggerDeregistration(@ImsRegistrationImplBase.ImsDeregistrationReason int reason) 2937 throws ImsException { 2938 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2939 try { 2940 c.triggerDeregistration(reason); 2941 } catch (RemoteException e) { 2942 throw new ImsException("triggerDeregistration", e, 2943 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2944 } 2945 } 2946 getImsServiceState()2947 public int getImsServiceState() throws ImsException { 2948 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2949 return c.getFeatureState(); 2950 } 2951 setMediaThreshold(@ediaQualityStatus.MediaSessionType int sessionType, MediaThreshold threshold)2952 public void setMediaThreshold(@MediaQualityStatus.MediaSessionType int sessionType, 2953 MediaThreshold threshold) throws ImsException { 2954 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2955 try { 2956 c.setMediaThreshold(sessionType, threshold); 2957 } catch (RemoteException e) { 2958 loge("setMediaThreshold Failed."); 2959 } 2960 } 2961 queryMediaQualityStatus( @ediaQualityStatus.MediaSessionType int sessionType)2962 public MediaQualityStatus queryMediaQualityStatus ( 2963 @MediaQualityStatus.MediaSessionType int sessionType) throws ImsException { 2964 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 2965 try { 2966 return c.queryMediaQualityStatus(sessionType); 2967 } catch (RemoteException e) { 2968 loge("queryMediaQualityStatus Failed."); 2969 return null; 2970 } 2971 } 2972 2973 @Override updateFeatureState(int state)2974 public void updateFeatureState(int state) { 2975 mMmTelConnectionRef.get().updateFeatureState(state); 2976 } 2977 2978 @Override updateFeatureCapabilities(long capabilities)2979 public void updateFeatureCapabilities(long capabilities) { 2980 mMmTelConnectionRef.get().updateFeatureCapabilities(capabilities); 2981 } 2982 getImsServiceState(Consumer<Integer> result)2983 public void getImsServiceState(Consumer<Integer> result) { 2984 getImsThreadExecutor().execute(() -> { 2985 try { 2986 result.accept(getImsServiceState()); 2987 } catch (ImsException e) { 2988 // In the case that the ImsService is not available, report unavailable. 2989 result.accept(ImsFeature.STATE_UNAVAILABLE); 2990 } 2991 }); 2992 } 2993 2994 /** 2995 * @return An Executor that should be used to execute potentially long-running operations. 2996 */ getImsThreadExecutor()2997 private Executor getImsThreadExecutor() { 2998 return mExecutor; 2999 } 3000 3001 /** 3002 * Get the boolean config from carrier config manager. 3003 * 3004 * @param key config key defined in CarrierConfigManager 3005 * @return boolean value of corresponding key. 3006 */ getBooleanCarrierConfig(String key)3007 private boolean getBooleanCarrierConfig(String key) { 3008 PersistableBundle b = null; 3009 if (mConfigManager != null) { 3010 // If an invalid subId is used, this bundle will contain default values. 3011 b = mConfigManager.getConfigForSubId(getSubId()); 3012 } 3013 if (b != null) { 3014 return b.getBoolean(key); 3015 } else { 3016 // Return static default defined in CarrierConfigManager. 3017 return CarrierConfigManager.getDefaultConfig().getBoolean(key); 3018 } 3019 } 3020 3021 /** 3022 * Get the int config from carrier config manager. 3023 * 3024 * @param key config key defined in CarrierConfigManager 3025 * @return integer value of corresponding key. 3026 */ getIntCarrierConfig(String key)3027 private int getIntCarrierConfig(String key) { 3028 PersistableBundle b = null; 3029 if (mConfigManager != null) { 3030 // If an invalid subId is used, this bundle will contain default values. 3031 b = mConfigManager.getConfigForSubId(getSubId()); 3032 } 3033 if (b != null) { 3034 return b.getInt(key); 3035 } else { 3036 // Return static default defined in CarrierConfigManager. 3037 return CarrierConfigManager.getDefaultConfig().getInt(key); 3038 } 3039 } 3040 3041 /** 3042 * Get the int[] config from carrier config manager. 3043 * 3044 * @param key config key defined in CarrierConfigManager 3045 * @return int[] values of the corresponding key. 3046 */ getIntArrayCarrierConfig(String key)3047 private int[] getIntArrayCarrierConfig(String key) { 3048 PersistableBundle b = null; 3049 if (mConfigManager != null) { 3050 // If an invalid subId is used, this bundle will contain default values. 3051 b = mConfigManager.getConfigForSubId(getSubId()); 3052 } 3053 if (b != null) { 3054 return b.getIntArray(key); 3055 } else { 3056 // Return static default defined in CarrierConfigManager. 3057 return CarrierConfigManager.getDefaultConfig().getIntArray(key); 3058 } 3059 } 3060 3061 /** 3062 * Checks to see if the ImsService Binder is connected. If it is not, we try to create the 3063 * connection again. 3064 */ getOrThrowExceptionIfServiceUnavailable()3065 private MmTelFeatureConnection getOrThrowExceptionIfServiceUnavailable() 3066 throws ImsException { 3067 if (!isImsSupportedOnDevice(mContext)) { 3068 throw new ImsException("IMS not supported on device.", 3069 ImsReasonInfo.CODE_LOCAL_IMS_NOT_SUPPORTED_ON_DEVICE); 3070 } 3071 MmTelFeatureConnection c = mMmTelConnectionRef.get(); 3072 if (c == null || !c.isBinderAlive()) { 3073 throw new ImsException("Service is unavailable", 3074 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3075 } 3076 if (getSubId() != c.getSubId()) { 3077 logi("Trying to get MmTelFeature when it is still setting up, curr subId=" + getSubId() 3078 + ", target subId=" + c.getSubId()); 3079 throw new ImsException("Service is still initializing", 3080 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3081 } 3082 return c; 3083 } 3084 3085 @Override registerFeatureCallback(int slotId, IImsServiceFeatureCallback cb)3086 public void registerFeatureCallback(int slotId, IImsServiceFeatureCallback cb) { 3087 try { 3088 ITelephony telephony = mBinderCache.listenOnBinder(cb, () -> { 3089 try { 3090 cb.imsFeatureRemoved( 3091 FeatureConnector.UNAVAILABLE_REASON_SERVER_UNAVAILABLE); 3092 } catch (RemoteException ignore) {} // This is local. 3093 }); 3094 3095 if (telephony != null) { 3096 telephony.registerMmTelFeatureCallback(slotId, cb); 3097 } else { 3098 cb.imsFeatureRemoved(FeatureConnector.UNAVAILABLE_REASON_SERVER_UNAVAILABLE); 3099 } 3100 } catch (ServiceSpecificException e) { 3101 try { 3102 switch (e.errorCode) { 3103 case android.telephony.ims.ImsException.CODE_ERROR_UNSUPPORTED_OPERATION: 3104 cb.imsFeatureRemoved(FeatureConnector.UNAVAILABLE_REASON_IMS_UNSUPPORTED); 3105 break; 3106 default: { 3107 cb.imsFeatureRemoved( 3108 FeatureConnector.UNAVAILABLE_REASON_SERVER_UNAVAILABLE); 3109 } 3110 } 3111 } catch (RemoteException ignore) {} // Already dead anyway if this happens. 3112 } catch (RemoteException e) { 3113 try { 3114 cb.imsFeatureRemoved(FeatureConnector.UNAVAILABLE_REASON_SERVER_UNAVAILABLE); 3115 } catch (RemoteException ignore) {} // Already dead if this happens. 3116 } 3117 } 3118 3119 @Override unregisterFeatureCallback(IImsServiceFeatureCallback cb)3120 public void unregisterFeatureCallback(IImsServiceFeatureCallback cb) { 3121 try { 3122 ITelephony telephony = mBinderCache.removeRunnable(cb); 3123 if (telephony != null) { 3124 telephony.unregisterImsFeatureCallback(cb); 3125 } 3126 } catch (RemoteException e) { 3127 // This means that telephony died, so do not worry about it. 3128 loge("unregisterImsFeatureCallback (MMTEL), RemoteException: " + e.getMessage()); 3129 } 3130 } 3131 3132 @Override associate(ImsFeatureContainer c, int subId)3133 public void associate(ImsFeatureContainer c, int subId) { 3134 if (c == null) { 3135 mMmTelConnectionRef.set(mMmTelFeatureConnectionFactory.create( 3136 mContext, mPhoneId, subId, null, null, null, null)); 3137 } else { 3138 mMmTelConnectionRef.set(mMmTelFeatureConnectionFactory.create( 3139 mContext, mPhoneId, subId, IImsMmTelFeature.Stub.asInterface(c.imsFeature), 3140 c.imsConfig, c.imsRegistration, c.sipTransport)); 3141 } 3142 } 3143 3144 @Override invalidate()3145 public void invalidate() { 3146 mMmTelConnectionRef.get().onRemovedOrDied(); 3147 } 3148 getITelephony()3149 private ITelephony getITelephony() { 3150 return mBinderCache.getBinder(); 3151 } 3152 getITelephonyInterface()3153 private static ITelephony getITelephonyInterface() { 3154 return ITelephony.Stub.asInterface( 3155 TelephonyFrameworkInitializer 3156 .getTelephonyServiceManager() 3157 .getTelephonyServiceRegisterer() 3158 .get()); 3159 } 3160 3161 /** 3162 * Creates a {@link ImsCallSession} with the specified call profile. 3163 * Use other methods, if applicable, instead of interacting with 3164 * {@link ImsCallSession} directly. 3165 * 3166 * @param profile a call profile to make the call 3167 */ createCallSession(ImsCallProfile profile)3168 private ImsCallSession createCallSession(ImsCallProfile profile) throws ImsException { 3169 try { 3170 MmTelFeatureConnection c = mMmTelConnectionRef.get(); 3171 // Throws an exception if the ImsService Feature is not ready to accept commands. 3172 return new ImsCallSession(c.createCallSession(profile)); 3173 } catch (RemoteException e) { 3174 logw("CreateCallSession: Error, remote exception: " + e.getMessage()); 3175 throw new ImsException("createCallSession()", e, 3176 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3177 3178 } 3179 } 3180 log(String s)3181 private void log(String s) { 3182 Rlog.d(TAG + mLogTagPostfix + " [" + mPhoneId + "]", s); 3183 } 3184 logi(String s)3185 private void logi(String s) { 3186 Rlog.i(TAG + mLogTagPostfix + " [" + mPhoneId + "]", s); 3187 } 3188 logw(String s)3189 private void logw(String s) { 3190 Rlog.w(TAG + mLogTagPostfix + " [" + mPhoneId + "]", s); 3191 } 3192 loge(String s)3193 private void loge(String s) { 3194 Rlog.e(TAG + mLogTagPostfix + " [" + mPhoneId + "]", s); 3195 } 3196 loge(String s, Throwable t)3197 private void loge(String s, Throwable t) { 3198 Rlog.e(TAG + mLogTagPostfix + " [" + mPhoneId + "]", s, t); 3199 } 3200 3201 /** 3202 * Used for turning on IMS.if its off already 3203 */ turnOnIms()3204 private void turnOnIms() throws ImsException { 3205 mTelephonyManager.enableIms(mPhoneId); 3206 } 3207 isImsTurnOffAllowed()3208 private boolean isImsTurnOffAllowed() { 3209 return isTurnOffImsAllowedByPlatform() 3210 && (!isWfcEnabledByPlatform() 3211 || !isWfcEnabledByUser()); 3212 } 3213 3214 /** 3215 * Used for turning off IMS completely in order to make the device CSFB'ed. 3216 * Once turned off, all calls will be over CS. 3217 */ turnOffIms()3218 private void turnOffIms() throws ImsException { 3219 mTelephonyManager.disableIms(mPhoneId); 3220 } 3221 3222 /** 3223 * Gets the ECBM interface to request ECBM exit. 3224 * <p> 3225 * This should only be called after {@link #open} has been called. 3226 * 3227 * @return the ECBM interface instance 3228 * @throws ImsException if getting the ECBM interface results in an error 3229 */ getEcbmInterface()3230 public ImsEcbm getEcbmInterface() throws ImsException { 3231 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 3232 ImsEcbm iEcbm = c.getEcbmInterface(); 3233 3234 if (iEcbm == null) { 3235 throw new ImsException("getEcbmInterface()", 3236 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED); 3237 } 3238 return iEcbm; 3239 } 3240 sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, byte[] pdu)3241 public void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, 3242 byte[] pdu) throws ImsException { 3243 try { 3244 mMmTelConnectionRef.get().sendSms(token, messageRef, format, smsc, isRetry, pdu); 3245 } catch (RemoteException e) { 3246 throw new ImsException("sendSms()", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3247 } 3248 } 3249 onMemoryAvailable(int token)3250 public void onMemoryAvailable(int token) throws ImsException { 3251 try { 3252 mMmTelConnectionRef.get().onMemoryAvailable(token); 3253 } catch (RemoteException e) { 3254 throw new ImsException("onMemoryAvailable()", e, 3255 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3256 } 3257 } 3258 acknowledgeSms(int token, int messageRef, int result)3259 public void acknowledgeSms(int token, int messageRef, int result) throws ImsException { 3260 try { 3261 mMmTelConnectionRef.get().acknowledgeSms(token, messageRef, result); 3262 } catch (RemoteException e) { 3263 throw new ImsException("acknowledgeSms()", e, 3264 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3265 } 3266 } 3267 acknowledgeSms(int token, int messageRef, int result, byte[] pdu)3268 public void acknowledgeSms(int token, int messageRef, int result, byte[] pdu) throws ImsException { 3269 try { 3270 mMmTelConnectionRef.get().acknowledgeSms(token, messageRef, result, pdu); 3271 } catch (RemoteException e) { 3272 throw new ImsException("acknowledgeSms()", e, 3273 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3274 } 3275 } 3276 acknowledgeSmsReport(int token, int messageRef, int result)3277 public void acknowledgeSmsReport(int token, int messageRef, int result) throws ImsException{ 3278 try { 3279 mMmTelConnectionRef.get().acknowledgeSmsReport(token, messageRef, result); 3280 } catch (RemoteException e) { 3281 throw new ImsException("acknowledgeSmsReport()", e, 3282 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3283 } 3284 } 3285 getSmsFormat()3286 public String getSmsFormat() throws ImsException{ 3287 try { 3288 return mMmTelConnectionRef.get().getSmsFormat(); 3289 } catch (RemoteException e) { 3290 throw new ImsException("getSmsFormat()", e, 3291 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3292 } 3293 } 3294 setSmsListener(IImsSmsListener listener)3295 public void setSmsListener(IImsSmsListener listener) throws ImsException { 3296 try { 3297 mMmTelConnectionRef.get().setSmsListener(listener); 3298 } catch (RemoteException e) { 3299 throw new ImsException("setSmsListener()", e, 3300 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3301 } 3302 } 3303 onSmsReady()3304 public void onSmsReady() throws ImsException { 3305 try { 3306 mMmTelConnectionRef.get().onSmsReady(); 3307 } catch (RemoteException e) { 3308 throw new ImsException("onSmsReady()", e, 3309 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3310 } 3311 } 3312 3313 /** 3314 * Determines whether or not a call with the specified numbers should be placed over IMS or over 3315 * CSFB. 3316 * @param isEmergency is at least one call an emergency number. 3317 * @param numbers A {@link String} array containing the numbers in the call being placed. Can 3318 * be multiple numbers in the case of dialing out a conference. 3319 * @return The result of the query, one of the following values: 3320 * - {@link MmTelFeature#PROCESS_CALL_IMS} 3321 * - {@link MmTelFeature#PROCESS_CALL_CSFB} 3322 * @throws ImsException if the ImsService is not available. In this case, we should fall back 3323 * to CSFB anyway. 3324 */ shouldProcessCall(boolean isEmergency, String[] numbers)3325 public @MmTelFeature.ProcessCallResult int shouldProcessCall(boolean isEmergency, 3326 String[] numbers) throws ImsException { 3327 try { 3328 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 3329 return c.shouldProcessCall(isEmergency, numbers); 3330 } catch (RemoteException e) { 3331 throw new ImsException("shouldProcessCall()", e, 3332 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3333 } 3334 } 3335 3336 /** 3337 * Resets ImsManager settings back to factory defaults. 3338 * 3339 * @deprecated Doesn't support MSIM devices. Use {@link #factoryReset()} instead. 3340 * 3341 * @hide 3342 */ factoryReset(Context context)3343 public static void factoryReset(Context context) { 3344 DefaultSubscriptionManagerProxy p = new DefaultSubscriptionManagerProxy(context); 3345 ImsManager mgr = ImsManager.getInstance(context, p.getDefaultVoicePhoneId()); 3346 if (mgr != null) { 3347 mgr.factoryReset(); 3348 } 3349 Rlog.e(TAG, "factoryReset: ImsManager null."); 3350 } 3351 3352 /** 3353 * Resets ImsManager settings back to factory defaults. 3354 * 3355 * @hide 3356 */ factoryReset()3357 public void factoryReset() { 3358 int subId = getSubId(); 3359 if (!isSubIdValid(subId)) { 3360 loge("factoryReset: invalid sub id, can not reset siminfo db settings; subId=" 3361 + subId); 3362 return; 3363 } 3364 // Set VoLTE to default 3365 mSubscriptionManagerProxy.setSubscriptionProperty(subId, 3366 SubscriptionManager.ENHANCED_4G_MODE_ENABLED, 3367 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 3368 3369 // Set VoWiFi to default 3370 mSubscriptionManagerProxy.setSubscriptionProperty(subId, 3371 SubscriptionManager.WFC_IMS_ENABLED, 3372 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 3373 3374 // Set VoWiFi mode to default 3375 mSubscriptionManagerProxy.setSubscriptionProperty(subId, 3376 SubscriptionManager.WFC_IMS_MODE, 3377 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 3378 3379 // Set VoWiFi roaming to default 3380 mSubscriptionManagerProxy.setSubscriptionProperty(subId, 3381 SubscriptionManager.WFC_IMS_ROAMING_ENABLED, 3382 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 3383 3384 // Set VoWiFi roaming mode to default 3385 mSubscriptionManagerProxy.setSubscriptionProperty(subId, 3386 SubscriptionManager.WFC_IMS_ROAMING_MODE, 3387 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 3388 3389 3390 // Set VT to default 3391 mSubscriptionManagerProxy.setSubscriptionProperty(subId, 3392 SubscriptionManager.VT_IMS_ENABLED, 3393 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 3394 3395 // Set RCS UCE to default 3396 mSubscriptionManagerProxy.setSubscriptionProperty(subId, 3397 SubscriptionManager.IMS_RCS_UCE_ENABLED, Integer.toString( 3398 SUBINFO_PROPERTY_FALSE)); 3399 // Push settings 3400 try { 3401 reevaluateCapabilities(); 3402 } catch (ImsException e) { 3403 loge("factoryReset, exception: " + e); 3404 } 3405 } 3406 isDataEnabled()3407 private boolean isDataEnabled() { 3408 if (mTelephonyManager == null) { 3409 loge("isDataEnabled: TelephonyManager not available, returning false..."); 3410 return false; 3411 } 3412 TelephonyManager tm = mTelephonyManager.createForSubscriptionId(getSubId()); 3413 return tm.isDataConnectionAllowed(); 3414 } 3415 isVolteProvisioned()3416 private boolean isVolteProvisioned() { 3417 return getImsProvisionedBoolNoException(CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_LTE); 3418 } 3419 isEabProvisioned()3420 private boolean isEabProvisioned() { 3421 return getRcsProvisionedBoolNoException(CAPABILITY_TYPE_PRESENCE_UCE, 3422 REGISTRATION_TECH_LTE); 3423 } 3424 isWfcProvisioned()3425 private boolean isWfcProvisioned() { 3426 return getImsProvisionedBoolNoException(CAPABILITY_TYPE_VOICE, REGISTRATION_TECH_IWLAN); 3427 } 3428 isVtProvisioned()3429 private boolean isVtProvisioned() { 3430 return getImsProvisionedBoolNoException(CAPABILITY_TYPE_VIDEO, REGISTRATION_TECH_LTE); 3431 } 3432 isMmTelProvisioningRequired(int capability, int tech)3433 private boolean isMmTelProvisioningRequired(int capability, int tech) { 3434 int subId = getSubId(); 3435 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 3436 logw("isMmTelProvisioningRequired subId is invalid"); 3437 return false; 3438 } 3439 3440 ITelephony iTelephony = getITelephony(); 3441 if (iTelephony == null) { 3442 logw("isMmTelProvisioningRequired ITelephony interface is invalid"); 3443 return false; 3444 } 3445 3446 boolean required = false; 3447 try { 3448 required = iTelephony.isProvisioningRequiredForCapability(subId, capability, 3449 tech); 3450 } catch (RemoteException | IllegalArgumentException e) { 3451 logw("isMmTelProvisioningRequired : operation failed" + " capability=" + capability 3452 + " tech=" + tech + ". Exception:" + e.getMessage()); 3453 } 3454 3455 log("MmTel Provisioning required " + required + " for capability " + capability); 3456 return required; 3457 } 3458 isRcsProvisioningRequired(int capability, int tech)3459 private boolean isRcsProvisioningRequired(int capability, int tech) { 3460 int subId = getSubId(); 3461 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 3462 logw("isRcsProvisioningRequired subId is invalid"); 3463 return false; 3464 } 3465 3466 ITelephony iTelephony = getITelephony(); 3467 if (iTelephony == null) { 3468 logw("isRcsProvisioningRequired ITelephony interface is invalid"); 3469 return false; 3470 } 3471 3472 boolean required = false; 3473 try { 3474 required = iTelephony.isRcsProvisioningRequiredForCapability(subId, capability, 3475 tech); 3476 } catch (RemoteException | IllegalArgumentException e) { 3477 logw("isRcsProvisioningRequired : operation failed" + " capability=" + capability 3478 + " tech=" + tech + ". Exception:" + e.getMessage()); 3479 } 3480 3481 log("Rcs Provisioning required " + required + " for capability " + capability); 3482 return required; 3483 } 3484 booleanToPropertyString(boolean bool)3485 private static String booleanToPropertyString(boolean bool) { 3486 return bool ? "1" : "0"; 3487 } 3488 getConfigInt(int key)3489 public int getConfigInt(int key) throws ImsException { 3490 if (isLocalImsConfigKey(key)) { 3491 return getLocalImsConfigKeyInt(key); 3492 } else { 3493 return getConfigInterface().getConfigInt(key); 3494 } 3495 } 3496 getConfigString(int key)3497 public String getConfigString(int key) throws ImsException { 3498 if (isLocalImsConfigKey(key)) { 3499 return getLocalImsConfigKeyString(key); 3500 } else { 3501 return getConfigInterface().getConfigString(key); 3502 } 3503 } 3504 setConfig(int key, int value)3505 public int setConfig(int key, int value) throws ImsException, RemoteException { 3506 if (isLocalImsConfigKey(key)) { 3507 return setLocalImsConfigKeyInt(key, value); 3508 } else { 3509 return getConfigInterface().setConfig(key, value); 3510 } 3511 } 3512 setConfig(int key, String value)3513 public int setConfig(int key, String value) throws ImsException, RemoteException { 3514 if (isLocalImsConfigKey(key)) { 3515 return setLocalImsConfigKeyString(key, value); 3516 } else { 3517 return getConfigInterface().setConfig(key, value); 3518 } 3519 } 3520 3521 /** 3522 * Gets the configuration value that supported in frameworks. 3523 * 3524 * @param key, as defined in com.android.ims.ProvisioningManager. 3525 * @return the value in Integer format 3526 */ getLocalImsConfigKeyInt(int key)3527 private int getLocalImsConfigKeyInt(int key) { 3528 int result = ProvisioningManager.PROVISIONING_RESULT_UNKNOWN; 3529 3530 switch (key) { 3531 case KEY_VOIMS_OPT_IN_STATUS: 3532 result = isVoImsOptInEnabled() ? 1 : 0; 3533 break; 3534 } 3535 log("getLocalImsConfigKeInt() for key:" + key + ", result: " + result); 3536 return result; 3537 } 3538 3539 /** 3540 * Gets the configuration value that supported in frameworks. 3541 * 3542 * @param key, as defined in com.android.ims.ProvisioningManager. 3543 * @return the value in String format 3544 */ getLocalImsConfigKeyString(int key)3545 private String getLocalImsConfigKeyString(int key) { 3546 String result = ""; 3547 3548 switch (key) { 3549 case KEY_VOIMS_OPT_IN_STATUS: 3550 result = booleanToPropertyString(isVoImsOptInEnabled()); 3551 3552 break; 3553 } 3554 log("getLocalImsConfigKeyString() for key:" + key + ", result: " + result); 3555 return result; 3556 } 3557 3558 /** 3559 * Sets the configuration value that supported in frameworks. 3560 * 3561 * @param key, as defined in com.android.ims.ProvisioningManager. 3562 * @param value in Integer format. 3563 * @return as defined in com.android.ims.ProvisioningManager#OperationStatusConstants 3564 */ setLocalImsConfigKeyInt(int key, int value)3565 private int setLocalImsConfigKeyInt(int key, int value) throws ImsException, RemoteException { 3566 int result = ImsConfig.OperationStatusConstants.UNKNOWN; 3567 3568 switch (key) { 3569 case KEY_VOIMS_OPT_IN_STATUS: 3570 result = setVoImsOptInSetting(value); 3571 reevaluateCapabilities(); 3572 break; 3573 } 3574 log("setLocalImsConfigKeyInt() for" + 3575 " key: " + key + 3576 ", value: " + value + 3577 ", result: " + result); 3578 3579 // Notify ims config changed 3580 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 3581 IImsConfig config = c.getConfig(); 3582 config.notifyIntImsConfigChanged(key, value); 3583 3584 return result; 3585 } 3586 3587 /** 3588 * Sets the configuration value that supported in frameworks. 3589 * 3590 * @param key, as defined in com.android.ims.ProvisioningManager. 3591 * @param value in String format. 3592 * @return as defined in com.android.ims.ProvisioningManager#OperationStatusConstants 3593 */ setLocalImsConfigKeyString(int key, String value)3594 private int setLocalImsConfigKeyString(int key, String value) 3595 throws ImsException, RemoteException { 3596 int result = ImsConfig.OperationStatusConstants.UNKNOWN; 3597 3598 switch (key) { 3599 case KEY_VOIMS_OPT_IN_STATUS: 3600 result = setVoImsOptInSetting(Integer.parseInt(value)); 3601 reevaluateCapabilities(); 3602 break; 3603 } 3604 log("setLocalImsConfigKeyString() for" + 3605 " key: " + key + 3606 ", value: " + value + 3607 ", result: " + result); 3608 3609 // Notify ims config changed 3610 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 3611 IImsConfig config = c.getConfig(); 3612 config.notifyStringImsConfigChanged(key, value); 3613 3614 return result; 3615 } 3616 3617 /** 3618 * Check the config whether supported by framework. 3619 * 3620 * @param key, as defined in com.android.ims.ProvisioningManager. 3621 * @return true if the config is supported by framework. 3622 */ isLocalImsConfigKey(int key)3623 private boolean isLocalImsConfigKey(int key) { 3624 return Arrays.stream(LOCAL_IMS_CONFIG_KEYS).anyMatch(value -> value == key); 3625 } 3626 isVoImsOptInEnabled()3627 private boolean isVoImsOptInEnabled() { 3628 int setting = mSubscriptionManagerProxy.getIntegerSubscriptionProperty( 3629 getSubId(), SubscriptionManager.VOIMS_OPT_IN_STATUS, 3630 SUB_PROPERTY_NOT_INITIALIZED); 3631 return (setting == ProvisioningManager.PROVISIONING_VALUE_ENABLED); 3632 } 3633 setVoImsOptInSetting(int value)3634 private int setVoImsOptInSetting(int value) { 3635 mSubscriptionManagerProxy.setSubscriptionProperty( 3636 getSubId(), 3637 SubscriptionManager.VOIMS_OPT_IN_STATUS, 3638 String.valueOf(value)); 3639 return ImsConfig.OperationStatusConstants.SUCCESS; 3640 } 3641 dump(FileDescriptor fd, PrintWriter pw, String[] args)3642 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 3643 pw.println("ImsManager:"); 3644 pw.println(" device supports IMS = " + isImsSupportedOnDevice(mContext)); 3645 pw.println(" mPhoneId = " + mPhoneId); 3646 pw.println(" mConfigUpdated = " + mConfigUpdated); 3647 pw.println(" mImsServiceProxy = " + mMmTelConnectionRef.get()); 3648 pw.println(" mDataEnabled = " + isDataEnabled()); 3649 pw.println(" ignoreDataEnabledChanged = " + getBooleanCarrierConfig( 3650 CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS)); 3651 3652 pw.println(" isGbaValid = " + isGbaValid()); 3653 pw.println(" isImsTurnOffAllowed = " + isImsTurnOffAllowed()); 3654 pw.println(" isNonTtyOrTtyOnVolteEnabled = " + isNonTtyOrTtyOnVolteEnabled()); 3655 3656 pw.println(" isVolteEnabledByPlatform = " + isVolteEnabledByPlatform()); 3657 pw.println(" isVoImsOptInEnabled = " + isVoImsOptInEnabled()); 3658 pw.println(" isVolteProvisionedOnDevice = " + isVolteProvisionedOnDevice()); 3659 pw.println(" isEnhanced4gLteModeSettingEnabledByUser = " + 3660 isEnhanced4gLteModeSettingEnabledByUser()); 3661 pw.println(" isVtEnabledByPlatform = " + isVtEnabledByPlatform()); 3662 pw.println(" isVtEnabledByUser = " + isVtEnabledByUser()); 3663 3664 pw.println(" isWfcEnabledByPlatform = " + isWfcEnabledByPlatform()); 3665 pw.println(" isWfcEnabledByUser = " + isWfcEnabledByUser()); 3666 pw.println(" getWfcMode(non-roaming) = " + getWfcMode(false)); 3667 pw.println(" getWfcMode(roaming) = " + getWfcMode(true)); 3668 pw.println(" isWfcRoamingEnabledByUser = " + isWfcRoamingEnabledByUser()); 3669 3670 pw.println(" isVtProvisionedOnDevice = " + isVtProvisionedOnDevice()); 3671 pw.println(" isWfcProvisionedOnDevice = " + isWfcProvisionedOnDevice()); 3672 3673 pw.println(" isCrossSimEnabledByPlatform = " + isCrossSimEnabledByPlatform()); 3674 pw.println(" isCrossSimCallingEnabledByUser = " + isCrossSimCallingEnabledByUser()); 3675 pw.println(" isImsOverNrEnabledByPlatform = " + isImsOverNrEnabledByPlatform()); 3676 pw.flush(); 3677 } 3678 3679 /** 3680 * Determines if a sub id is valid. 3681 * Mimics the logic in SubscriptionController.validateSubId. 3682 * @param subId The sub id to check. 3683 * @return {@code true} if valid, {@code false} otherwise. 3684 */ isSubIdValid(int subId)3685 private boolean isSubIdValid(int subId) { 3686 return mSubscriptionManagerProxy.isValidSubscriptionId(subId) && 3687 subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; 3688 } 3689 isActiveSubscriptionPresent()3690 private boolean isActiveSubscriptionPresent() { 3691 return mSubscriptionManagerProxy.getActiveSubscriptionIdList().length > 0; 3692 } 3693 updateImsCarrierConfigs(PersistableBundle configs)3694 private void updateImsCarrierConfigs(PersistableBundle configs) throws ImsException { 3695 MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); 3696 3697 IImsConfig config = c.getConfig(); 3698 if (config == null) { 3699 throw new ImsException("getConfigInterface()", 3700 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE); 3701 } 3702 try { 3703 config.updateImsCarrierConfigs(configs); 3704 } catch (RemoteException e) { 3705 throw new ImsException("updateImsCarrierConfigs()", e, 3706 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 3707 } 3708 } 3709 3710 /** 3711 * Determine whether to override roaming Wi-Fi calling preference when device is connected to 3712 * non-terrestrial network. 3713 * 3714 * @return {@code true} if phone is connected to non-terrestrial network and if 3715 * {@link CarrierConfigManager#KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL} is true, 3716 * {@code false} otherwise. 3717 */ overrideWfcRoamingModeWhileUsingNTN()3718 private boolean overrideWfcRoamingModeWhileUsingNTN() { 3719 if (!Flags.carrierEnabledSatelliteFlag()) { 3720 return false; 3721 } 3722 3723 if (mTelephonyManager == null) { 3724 return false; 3725 } 3726 3727 TelephonyManager tm = mTelephonyManager.createForSubscriptionId(getSubId()); 3728 ServiceState serviceState = tm.getServiceState(); 3729 if (serviceState == null) { 3730 return false; 3731 } 3732 3733 if (!serviceState.isUsingNonTerrestrialNetwork()) { 3734 return false; 3735 } 3736 3737 return getBooleanCarrierConfig( 3738 CarrierConfigManager.KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL); 3739 } 3740 } 3741