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