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