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