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 android.annotation.Nullable; 20 import android.app.PendingIntent; 21 import android.compat.annotation.UnsupportedAppUsage; 22 import android.content.Context; 23 import android.content.pm.PackageManager; 24 import android.os.Handler; 25 import android.os.HandlerThread; 26 import android.os.Looper; 27 import android.os.Message; 28 import android.os.Parcel; 29 import android.os.PersistableBundle; 30 import android.os.RemoteException; 31 import android.os.ServiceManager; 32 import android.os.SystemProperties; 33 import android.provider.Settings; 34 import android.telecom.TelecomManager; 35 import android.telephony.AccessNetworkConstants; 36 import android.telephony.CarrierConfigManager; 37 import android.telephony.SubscriptionManager; 38 import android.telephony.TelephonyManager; 39 import android.telephony.ims.ImsCallProfile; 40 import android.telephony.ims.ImsCallSession; 41 import android.telephony.ims.ImsMmTelManager; 42 import android.telephony.ims.ImsReasonInfo; 43 import android.telephony.ims.ImsService; 44 import android.telephony.ims.ProvisioningManager; 45 import android.telephony.ims.RegistrationManager; 46 import android.telephony.ims.aidl.IImsCapabilityCallback; 47 import android.telephony.ims.aidl.IImsConfig; 48 import android.telephony.ims.aidl.IImsConfigCallback; 49 import android.telephony.ims.aidl.IImsRegistrationCallback; 50 import android.telephony.ims.aidl.IImsSmsListener; 51 import android.telephony.ims.feature.CapabilityChangeRequest; 52 import android.telephony.ims.feature.ImsFeature; 53 import android.telephony.ims.feature.MmTelFeature; 54 import android.telephony.ims.stub.ImsCallSessionImplBase; 55 import android.telephony.ims.stub.ImsConfigImplBase; 56 import android.telephony.ims.stub.ImsRegistrationImplBase; 57 58 import com.android.ims.internal.IImsCallSession; 59 import com.android.ims.internal.IImsEcbm; 60 import com.android.ims.internal.IImsMultiEndpoint; 61 import com.android.ims.internal.IImsUt; 62 import com.android.internal.annotations.VisibleForTesting; 63 import com.android.internal.telephony.ITelephony; 64 import com.android.internal.telephony.util.HandlerExecutor; 65 import com.android.telephony.Rlog; 66 67 import java.io.FileDescriptor; 68 import java.io.PrintWriter; 69 import java.util.ArrayList; 70 import java.util.HashMap; 71 import java.util.Set; 72 import java.util.concurrent.BlockingQueue; 73 import java.util.concurrent.ConcurrentLinkedDeque; 74 import java.util.concurrent.CopyOnWriteArraySet; 75 import java.util.concurrent.Executor; 76 import java.util.concurrent.LinkedBlockingDeque; 77 import java.util.concurrent.TimeUnit; 78 import java.util.function.Consumer; 79 80 /** 81 * Provides APIs for IMS services, such as initiating IMS calls, and provides access to 82 * the operator's IMS network. This class is the starting point for any IMS actions. 83 * You can acquire an instance of it with {@link #getInstance getInstance()}.</p> 84 * For internal use ONLY! Use {@link ImsMmTelManager} instead. 85 * @hide 86 */ 87 public class ImsManager implements IFeatureConnector { 88 89 /* 90 * Debug flag to override configuration flag 91 */ 92 public static final String PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr"; 93 public static final int PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT = 0; 94 public static final String PROPERTY_DBG_VT_AVAIL_OVERRIDE = "persist.dbg.vt_avail_ovr"; 95 public static final int PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT = 0; 96 public static final String PROPERTY_DBG_WFC_AVAIL_OVERRIDE = "persist.dbg.wfc_avail_ovr"; 97 public static final int PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT = 0; 98 public static final String PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE = "persist.dbg.allow_ims_off"; 99 public static final int PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE_DEFAULT = 0; 100 101 /** 102 * The result code to be sent back with the incoming call {@link PendingIntent}. 103 * @see #open(MmTelFeature.Listener) 104 */ 105 public static final int INCOMING_CALL_RESULT_CODE = 101; 106 107 /** 108 * Key to retrieve the call ID from an incoming call intent. No longer used, see 109 * {@link ImsCallSessionImplBase#getCallId()}. 110 * @deprecated Not used in the framework, keeping around symbol to not break old vendor 111 * components. 112 */ 113 @Deprecated 114 public static final String EXTRA_CALL_ID = "android:imsCallID"; 115 116 /** 117 * Action to broadcast when ImsService is up. 118 * Internal use only. 119 * @deprecated 120 * @hide 121 */ 122 public static final String ACTION_IMS_SERVICE_UP = 123 "com.android.ims.IMS_SERVICE_UP"; 124 125 /** 126 * Action to broadcast when ImsService is down. 127 * Internal use only. 128 * @deprecated 129 * @hide 130 */ 131 public static final String ACTION_IMS_SERVICE_DOWN = 132 "com.android.ims.IMS_SERVICE_DOWN"; 133 134 /** 135 * Action to broadcast when ImsService registration fails. 136 * Internal use only. 137 * @hide 138 * @deprecated use {@link android.telephony.ims.ImsManager#ACTION_WFC_IMS_REGISTRATION_ERROR} 139 * instead. 140 */ 141 @Deprecated 142 public static final String ACTION_IMS_REGISTRATION_ERROR = 143 android.telephony.ims.ImsManager.ACTION_WFC_IMS_REGISTRATION_ERROR; 144 145 /** 146 * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents. 147 * A long value; the phone ID corresponding to the IMS service coming up or down. 148 * Internal use only. 149 * @hide 150 */ 151 public static final String EXTRA_PHONE_ID = "android:phone_id"; 152 153 /** 154 * Action for the incoming call intent for the Phone app. 155 * Internal use only. 156 * @hide 157 */ 158 public static final String ACTION_IMS_INCOMING_CALL = 159 "com.android.ims.IMS_INCOMING_CALL"; 160 161 /** 162 * Part of the ACTION_IMS_INCOMING_CALL intents. 163 * An integer value; service identifier obtained from {@link ImsManager#open}. 164 * Internal use only. 165 * @hide 166 * @deprecated Not used in the system, keeping around to not break old vendor components. 167 */ 168 @Deprecated 169 public static final String EXTRA_SERVICE_ID = "android:imsServiceId"; 170 171 /** 172 * Part of the ACTION_IMS_INCOMING_CALL intents. 173 * An boolean value; Flag to indicate that the incoming call is a normal call or call for USSD. 174 * The value "true" indicates that the incoming call is for USSD. 175 * Internal use only. 176 * @deprecated Keeping around to not break old vendor components. Use 177 * {@link MmTelFeature#EXTRA_USSD} instead. 178 * @hide 179 */ 180 public static final String EXTRA_USSD = "android:ussd"; 181 182 /** 183 * Part of the ACTION_IMS_INCOMING_CALL intents. 184 * A boolean value; Flag to indicate whether the call is an unknown 185 * dialing call. Such calls are originated by sending commands (like 186 * AT commands) directly to modem without Android involvement. 187 * Even though they are not incoming calls, they are propagated 188 * to Phone app using same ACTION_IMS_INCOMING_CALL intent. 189 * Internal use only. 190 * @deprecated Keeping around to not break old vendor components. Use 191 * {@link MmTelFeature#EXTRA_IS_UNKNOWN_CALL} instead. 192 * @hide 193 */ 194 public static final String EXTRA_IS_UNKNOWN_CALL = "android:isUnknown"; 195 196 private static final int SUBINFO_PROPERTY_FALSE = 0; 197 198 private static final int SYSTEM_PROPERTY_NOT_SET = -1; 199 200 // -1 indicates a subscriptionProperty value that is never set. 201 private static final int SUB_PROPERTY_NOT_INITIALIZED = -1; 202 203 private static final String TAG = "ImsManager"; 204 private static final boolean DBG = true; 205 206 private static final int RESPONSE_WAIT_TIME_MS = 3000; 207 208 @VisibleForTesting 209 public interface ExecutorFactory { executeRunnable(Runnable runnable)210 void executeRunnable(Runnable runnable); 211 } 212 213 @VisibleForTesting 214 public static class ImsExecutorFactory implements ExecutorFactory { 215 216 private final HandlerThread mThreadHandler; 217 private final Handler mHandler; 218 ImsExecutorFactory()219 public ImsExecutorFactory() { 220 mThreadHandler = new HandlerThread("ImsHandlerThread"); 221 mThreadHandler.start(); 222 mHandler = new Handler(mThreadHandler.getLooper()); 223 } 224 225 @Override executeRunnable(Runnable runnable)226 public void executeRunnable(Runnable runnable) { 227 mHandler.post(runnable); 228 } 229 destroy()230 public void destroy() { 231 mThreadHandler.quit(); 232 } 233 } 234 235 // Replaced with single-threaded executor for testing. 236 @VisibleForTesting 237 public ExecutorFactory mExecutorFactory = new ImsExecutorFactory(); 238 239 private static HashMap<Integer, ImsManager> sImsManagerInstances = 240 new HashMap<Integer, ImsManager>(); 241 242 private Context mContext; 243 private CarrierConfigManager mConfigManager; 244 private int mPhoneId; 245 private @Nullable MmTelFeatureConnection mMmTelFeatureConnection = null; 246 private boolean mConfigUpdated = false; 247 248 private ImsConfigListener mImsConfigListener; 249 250 //TODO: Move these caches into the MmTelFeature Connection and restrict their lifetimes to the 251 // lifetime of the MmTelFeature. 252 // Ut interface for the supplementary service configuration 253 private ImsUt mUt = null; 254 // ECBM interface 255 private ImsEcbm mEcbm = null; 256 private ImsMultiEndpoint mMultiEndpoint = null; 257 258 private Set<FeatureConnection.IFeatureUpdate> mStatusCallbacks = new CopyOnWriteArraySet<>(); 259 260 public static final String TRUE = "true"; 261 public static final String FALSE = "false"; 262 263 // mRecentDisconnectReasons stores the last 16 disconnect reasons 264 private static final int MAX_RECENT_DISCONNECT_REASONS = 16; 265 private ConcurrentLinkedDeque<ImsReasonInfo> mRecentDisconnectReasons = 266 new ConcurrentLinkedDeque<>(); 267 268 /** 269 * Gets a manager instance. 270 * 271 * @param context application context for creating the manager object 272 * @param phoneId the phone ID for the IMS Service 273 * @return the manager instance corresponding to the phoneId 274 */ 275 @UnsupportedAppUsage getInstance(Context context, int phoneId)276 public static ImsManager getInstance(Context context, int phoneId) { 277 synchronized (sImsManagerInstances) { 278 if (sImsManagerInstances.containsKey(phoneId)) { 279 ImsManager m = sImsManagerInstances.get(phoneId); 280 // May be null for some tests 281 if (m != null) { 282 m.connectIfServiceIsAvailable(); 283 } 284 return m; 285 } 286 287 ImsManager mgr = new ImsManager(context, phoneId); 288 sImsManagerInstances.put(phoneId, mgr); 289 290 return mgr; 291 } 292 } 293 isImsSupportedOnDevice(Context context)294 public static boolean isImsSupportedOnDevice(Context context) { 295 return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS); 296 } 297 298 /** 299 * Returns the user configuration of Enhanced 4G LTE Mode setting. 300 * 301 * @deprecated Doesn't support MSIM devices. Use 302 * {@link #isEnhanced4gLteModeSettingEnabledByUser()} instead. 303 */ 304 @UnsupportedAppUsage isEnhanced4gLteModeSettingEnabledByUser(Context context)305 public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) { 306 ImsManager mgr = ImsManager.getInstance(context, 307 SubscriptionManager.getDefaultVoicePhoneId()); 308 if (mgr != null) { 309 return mgr.isEnhanced4gLteModeSettingEnabledByUser(); 310 } 311 Rlog.e(TAG, "isEnhanced4gLteModeSettingEnabledByUser: ImsManager null, returning default" 312 + " value."); 313 return false; 314 } 315 316 /** 317 * Returns the user configuration of Enhanced 4G LTE Mode setting for slot. If the option is 318 * not editable ({@link CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL} is false), 319 * hidden ({@link CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL} is true), or 320 * the setting is not initialized, this method will return default value specified by 321 * {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}. 322 * 323 * Note that even if the setting was set, it may no longer be editable. If this is the case we 324 * return the default value. 325 */ isEnhanced4gLteModeSettingEnabledByUser()326 public boolean isEnhanced4gLteModeSettingEnabledByUser() { 327 int setting = SubscriptionManager.getIntegerSubscriptionProperty( 328 getSubId(), SubscriptionManager.ENHANCED_4G_MODE_ENABLED, 329 SUB_PROPERTY_NOT_INITIALIZED, mContext); 330 boolean onByDefault = getBooleanCarrierConfig( 331 CarrierConfigManager.KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL); 332 333 // If Enhanced 4G LTE Mode is uneditable, hidden or not initialized, we use the default 334 // value 335 if (!getBooleanCarrierConfig(CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL) 336 || getBooleanCarrierConfig(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL) 337 || setting == SUB_PROPERTY_NOT_INITIALIZED) { 338 return onByDefault; 339 } else { 340 return (setting == ProvisioningManager.PROVISIONING_VALUE_ENABLED); 341 } 342 } 343 344 /** 345 * Change persistent Enhanced 4G LTE Mode setting. 346 * 347 * @deprecated Doesn't support MSIM devices. Use {@link #setEnhanced4gLteModeSetting(boolean)} 348 * instead. 349 */ setEnhanced4gLteModeSetting(Context context, boolean enabled)350 public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) { 351 ImsManager mgr = ImsManager.getInstance(context, 352 SubscriptionManager.getDefaultVoicePhoneId()); 353 if (mgr != null) { 354 mgr.setEnhanced4gLteModeSetting(enabled); 355 } 356 Rlog.e(TAG, "setEnhanced4gLteModeSetting: ImsManager null, value not set."); 357 } 358 359 /** 360 * Change persistent Enhanced 4G LTE Mode setting. If the option is not editable 361 * ({@link CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL} is false) 362 * or hidden ({@link CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL} is true), 363 * this method will set the setting to the default value specified by 364 * {@link CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL}. 365 */ setEnhanced4gLteModeSetting(boolean enabled)366 public void setEnhanced4gLteModeSetting(boolean enabled) { 367 if (enabled && !isVolteProvisionedOnDevice()) { 368 log("setEnhanced4gLteModeSetting: Not possible to enable VoLTE due to provisioning."); 369 return; 370 } 371 int subId = getSubId(); 372 // If editable=false or hidden=true, we must keep default advanced 4G mode. 373 if (!getBooleanCarrierConfig(CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL) || 374 getBooleanCarrierConfig(CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL)) { 375 enabled = getBooleanCarrierConfig( 376 CarrierConfigManager.KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL); 377 } 378 379 int prevSetting = SubscriptionManager.getIntegerSubscriptionProperty(subId, 380 SubscriptionManager.ENHANCED_4G_MODE_ENABLED, SUB_PROPERTY_NOT_INITIALIZED, 381 mContext); 382 383 if (prevSetting != (enabled ? 384 ProvisioningManager.PROVISIONING_VALUE_ENABLED : 385 ProvisioningManager.PROVISIONING_VALUE_DISABLED)) { 386 if (isSubIdValid(subId)) { 387 SubscriptionManager.setSubscriptionProperty(subId, 388 SubscriptionManager.ENHANCED_4G_MODE_ENABLED, 389 booleanToPropertyString(enabled)); 390 } else { 391 loge("setEnhanced4gLteModeSetting: invalid sub id, can not set property in " + 392 " siminfo db; subId=" + subId); 393 } 394 if (isNonTtyOrTtyOnVolteEnabled()) { 395 try { 396 setAdvanced4GMode(enabled); 397 } catch (ImsException ie) { 398 // do nothing 399 } 400 } 401 } 402 } 403 404 /** 405 * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is 406 * supported. 407 * @deprecated Does not support MSIM devices. Please use 408 * {@link #isNonTtyOrTtyOnVolteEnabled()} instead. 409 */ 410 @UnsupportedAppUsage isNonTtyOrTtyOnVolteEnabled(Context context)411 public static boolean isNonTtyOrTtyOnVolteEnabled(Context context) { 412 ImsManager mgr = ImsManager.getInstance(context, 413 SubscriptionManager.getDefaultVoicePhoneId()); 414 if (mgr != null) { 415 return mgr.isNonTtyOrTtyOnVolteEnabled(); 416 } 417 Rlog.e(TAG, "isNonTtyOrTtyOnVolteEnabled: ImsManager null, returning default value."); 418 return false; 419 } 420 421 /** 422 * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is 423 * supported on a per slot basis. 424 */ isNonTtyOrTtyOnVolteEnabled()425 public boolean isNonTtyOrTtyOnVolteEnabled() { 426 if (isTtyOnVoLteCapable()) { 427 return true; 428 } 429 430 TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE); 431 if (tm == null) { 432 logw("isNonTtyOrTtyOnVolteEnabled: telecom not available"); 433 return true; 434 } 435 return tm.getCurrentTtyMode() == TelecomManager.TTY_MODE_OFF; 436 } 437 isTtyOnVoLteCapable()438 public boolean isTtyOnVoLteCapable() { 439 return getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL); 440 } 441 442 /** 443 * Returns a platform configuration for VoLTE which may override the user setting. 444 * @deprecated Does not support MSIM devices. Please use 445 * {@link #isVolteEnabledByPlatform()} instead. 446 */ 447 @UnsupportedAppUsage isVolteEnabledByPlatform(Context context)448 public static boolean isVolteEnabledByPlatform(Context context) { 449 ImsManager mgr = ImsManager.getInstance(context, 450 SubscriptionManager.getDefaultVoicePhoneId()); 451 if (mgr != null) { 452 return mgr.isVolteEnabledByPlatform(); 453 } 454 Rlog.e(TAG, "isVolteEnabledByPlatform: ImsManager null, returning default value."); 455 return false; 456 } 457 458 /** 459 * Asynchronous call to ImsService to determine whether or not a specific MmTel capability is 460 * supported. 461 */ isSupported(int capability, int transportType, Consumer<Boolean> result)462 public void isSupported(int capability, int transportType, Consumer<Boolean> result) { 463 mExecutorFactory.executeRunnable(() -> { 464 switch(transportType) { 465 case (AccessNetworkConstants.TRANSPORT_TYPE_WWAN): { 466 switch (capability) { 467 case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE): { 468 result.accept(isVolteEnabledByPlatform()); 469 return; 470 } case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO): { 471 result.accept(isVtEnabledByPlatform()); 472 return; 473 }case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT): { 474 result.accept(isSuppServicesOverUtEnabledByPlatform()); 475 return; 476 } case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS): { 477 // There is currently no carrier config defined for this. 478 result.accept(true); 479 return; 480 } 481 } 482 break; 483 } case (AccessNetworkConstants.TRANSPORT_TYPE_WLAN): { 484 switch (capability) { 485 case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE) : { 486 result.accept(isWfcEnabledByPlatform()); 487 return; 488 } case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO) : { 489 // This is not transport dependent at this time. 490 result.accept(isVtEnabledByPlatform()); 491 return; 492 } case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT) : { 493 // This is not transport dependent at this time. 494 result.accept(isSuppServicesOverUtEnabledByPlatform()); 495 return; 496 } case (MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS) : { 497 // There is currently no carrier config defined for this. 498 result.accept(true); 499 return; 500 } 501 } 502 break; 503 } 504 } 505 // false for unknown capability/transport types. 506 result.accept(false); 507 }); 508 509 } 510 511 /** 512 * Returns a platform configuration for VoLTE which may override the user setting on a per Slot 513 * basis. 514 */ isVolteEnabledByPlatform()515 public boolean isVolteEnabledByPlatform() { 516 // We first read the per slot value. If doesn't exist, we read the general value. If still 517 // doesn't exist, we use the hardcoded default value. 518 if (SystemProperties.getInt( 519 PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE + Integer.toString(mPhoneId), 520 SYSTEM_PROPERTY_NOT_SET) == 1 || 521 SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE, 522 SYSTEM_PROPERTY_NOT_SET) == 1) { 523 return true; 524 } 525 526 return mContext.getResources().getBoolean( 527 com.android.internal.R.bool.config_device_volte_available) 528 && getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL) 529 && isGbaValid(); 530 } 531 532 /** 533 * Indicates whether VoLTE is provisioned on device. 534 * 535 * @deprecated Does not support MSIM devices. Please use 536 * {@link #isVolteProvisionedOnDevice()} instead. 537 */ isVolteProvisionedOnDevice(Context context)538 public static boolean isVolteProvisionedOnDevice(Context context) { 539 ImsManager mgr = ImsManager.getInstance(context, 540 SubscriptionManager.getDefaultVoicePhoneId()); 541 if (mgr != null) { 542 return mgr.isVolteProvisionedOnDevice(); 543 } 544 Rlog.e(TAG, "isVolteProvisionedOnDevice: ImsManager null, returning default value."); 545 return true; 546 } 547 548 /** 549 * Indicates whether VoLTE is provisioned on this slot. 550 */ isVolteProvisionedOnDevice()551 public boolean isVolteProvisionedOnDevice() { 552 if (getBooleanCarrierConfig( 553 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) { 554 return isVolteProvisioned(); 555 } 556 557 return true; 558 } 559 560 /** 561 * Indicates whether EAB is provisioned on this slot. 562 */ isEabProvisionedOnDevice()563 public boolean isEabProvisionedOnDevice() { 564 if (getBooleanCarrierConfig( 565 CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL)) { 566 return isEabProvisioned(); 567 } 568 569 return true; 570 } 571 572 /** 573 * Indicates whether VoWifi is provisioned on device. 574 * 575 * When CarrierConfig KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL is true, and VoLTE is not 576 * provisioned on device, this method returns false. 577 * 578 * @deprecated Does not support MSIM devices. Please use 579 * {@link #isWfcProvisionedOnDevice()} instead. 580 */ isWfcProvisionedOnDevice(Context context)581 public static boolean isWfcProvisionedOnDevice(Context context) { 582 ImsManager mgr = ImsManager.getInstance(context, 583 SubscriptionManager.getDefaultVoicePhoneId()); 584 if (mgr != null) { 585 return mgr.isWfcProvisionedOnDevice(); 586 } 587 Rlog.e(TAG, "isWfcProvisionedOnDevice: ImsManager null, returning default value."); 588 return true; 589 } 590 591 /** 592 * Indicates whether VoWifi is provisioned on slot. 593 * 594 * When CarrierConfig KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL is true, and VoLTE is not 595 * provisioned on device, this method returns false. 596 */ isWfcProvisionedOnDevice()597 public boolean isWfcProvisionedOnDevice() { 598 if (getBooleanCarrierConfig( 599 CarrierConfigManager.KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL)) { 600 if (!isVolteProvisionedOnDevice()) { 601 return false; 602 } 603 } 604 605 if (getBooleanCarrierConfig( 606 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) { 607 return isWfcProvisioned(); 608 } 609 610 return true; 611 } 612 613 /** 614 * Indicates whether VT is provisioned on device 615 * 616 * @deprecated Does not support MSIM devices. Please use 617 * {@link #isVtProvisionedOnDevice()} instead. 618 */ isVtProvisionedOnDevice(Context context)619 public static boolean isVtProvisionedOnDevice(Context context) { 620 ImsManager mgr = ImsManager.getInstance(context, 621 SubscriptionManager.getDefaultVoicePhoneId()); 622 if (mgr != null) { 623 return mgr.isVtProvisionedOnDevice(); 624 } 625 Rlog.e(TAG, "isVtProvisionedOnDevice: ImsManager null, returning default value."); 626 return true; 627 } 628 629 /** 630 * Indicates whether VT is provisioned on slot. 631 */ isVtProvisionedOnDevice()632 public boolean isVtProvisionedOnDevice() { 633 if (getBooleanCarrierConfig( 634 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) { 635 return isVtProvisioned(); 636 } 637 638 return true; 639 } 640 641 /** 642 * Returns a platform configuration for VT which may override the user setting. 643 * 644 * Note: VT presumes that VoLTE is enabled (these are configuration settings 645 * which must be done correctly). 646 * 647 * @deprecated Does not support MSIM devices. Please use 648 * {@link #isVtEnabledByPlatform()} instead. 649 */ isVtEnabledByPlatform(Context context)650 public static boolean isVtEnabledByPlatform(Context context) { 651 ImsManager mgr = ImsManager.getInstance(context, 652 SubscriptionManager.getDefaultVoicePhoneId()); 653 if (mgr != null) { 654 return mgr.isVtEnabledByPlatform(); 655 } 656 Rlog.e(TAG, "isVtEnabledByPlatform: ImsManager null, returning default value."); 657 return false; 658 } 659 660 /** 661 * Returns a platform configuration for VT which may override the user setting. 662 * 663 * Note: VT presumes that VoLTE is enabled (these are configuration settings 664 * which must be done correctly). 665 */ isVtEnabledByPlatform()666 public boolean isVtEnabledByPlatform() { 667 // We first read the per slot value. If doesn't exist, we read the general value. If still 668 // doesn't exist, we use the hardcoded default value. 669 if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE + 670 Integer.toString(mPhoneId), SYSTEM_PROPERTY_NOT_SET) == 1 || 671 SystemProperties.getInt( 672 PROPERTY_DBG_VT_AVAIL_OVERRIDE, SYSTEM_PROPERTY_NOT_SET) == 1) { 673 return true; 674 } 675 676 return mContext.getResources().getBoolean( 677 com.android.internal.R.bool.config_device_vt_available) && 678 getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_VT_AVAILABLE_BOOL) && 679 isGbaValid(); 680 } 681 682 /** 683 * Returns the user configuration of VT setting 684 * @deprecated Does not support MSIM devices. Please use 685 * {@link #isVtEnabledByUser()} instead. 686 */ isVtEnabledByUser(Context context)687 public static boolean isVtEnabledByUser(Context context) { 688 ImsManager mgr = ImsManager.getInstance(context, 689 SubscriptionManager.getDefaultVoicePhoneId()); 690 if (mgr != null) { 691 return mgr.isVtEnabledByUser(); 692 } 693 Rlog.e(TAG, "isVtEnabledByUser: ImsManager null, returning default value."); 694 return false; 695 } 696 697 /** 698 * Returns the user configuration of VT setting per slot. If not set, it 699 * returns true as default value. 700 */ isVtEnabledByUser()701 public boolean isVtEnabledByUser() { 702 int setting = SubscriptionManager.getIntegerSubscriptionProperty( 703 getSubId(), SubscriptionManager.VT_IMS_ENABLED, 704 SUB_PROPERTY_NOT_INITIALIZED, mContext); 705 706 // If it's never set, by default we return true. 707 return (setting == SUB_PROPERTY_NOT_INITIALIZED 708 || setting == ProvisioningManager.PROVISIONING_VALUE_ENABLED); 709 } 710 711 /** 712 * Change persistent VT enabled setting 713 * 714 * @deprecated Does not support MSIM devices. Please use {@link #setVtSetting(boolean)} instead. 715 */ setVtSetting(Context context, boolean enabled)716 public static void setVtSetting(Context context, boolean enabled) { 717 ImsManager mgr = ImsManager.getInstance(context, 718 SubscriptionManager.getDefaultVoicePhoneId()); 719 if (mgr != null) { 720 mgr.setVtSetting(enabled); 721 } 722 Rlog.e(TAG, "setVtSetting: ImsManager null, can not set value."); 723 } 724 725 /** 726 * Change persistent VT enabled setting for slot. 727 */ setVtSetting(boolean enabled)728 public void setVtSetting(boolean enabled) { 729 if (enabled && !isVtProvisionedOnDevice()) { 730 log("setVtSetting: Not possible to enable Vt due to provisioning."); 731 return; 732 } 733 734 int subId = getSubId(); 735 if (isSubIdValid(subId)) { 736 SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.VT_IMS_ENABLED, 737 booleanToPropertyString(enabled)); 738 } else { 739 loge("setVtSetting: sub id invalid, skip modifying vt state in subinfo db; subId=" 740 + subId); 741 } 742 743 try { 744 changeMmTelCapability(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 745 ImsRegistrationImplBase.REGISTRATION_TECH_LTE, enabled); 746 747 if (enabled) { 748 log("setVtSetting(b) : turnOnIms"); 749 turnOnIms(); 750 } else if (isTurnOffImsAllowedByPlatform() 751 && (!isVolteEnabledByPlatform() 752 || !isEnhanced4gLteModeSettingEnabledByUser())) { 753 log("setVtSetting(b) : imsServiceAllowTurnOff -> turnOffIms"); 754 turnOffIms(); 755 } 756 } catch (ImsException e) { 757 // The ImsService is down. Since the SubscriptionManager already recorded the user's 758 // preference, it will be resent in updateImsServiceConfig when the ImsPhoneCallTracker 759 // reconnects. 760 loge("setVtSetting(b): ", e); 761 } 762 } 763 764 /** 765 * Returns whether turning off ims is allowed by platform. 766 * The platform property may override the carrier config. 767 * 768 * @deprecated Does not support MSIM devices. Please use 769 * {@link #isTurnOffImsAllowedByPlatform()} instead. 770 */ isTurnOffImsAllowedByPlatform(Context context)771 private static boolean isTurnOffImsAllowedByPlatform(Context context) { 772 ImsManager mgr = ImsManager.getInstance(context, 773 SubscriptionManager.getDefaultVoicePhoneId()); 774 if (mgr != null) { 775 return mgr.isTurnOffImsAllowedByPlatform(); 776 } 777 Rlog.e(TAG, "isTurnOffImsAllowedByPlatform: ImsManager null, returning default value."); 778 return true; 779 } 780 781 /** 782 * Returns whether turning off ims is allowed by platform. 783 * The platform property may override the carrier config. 784 */ isTurnOffImsAllowedByPlatform()785 private boolean isTurnOffImsAllowedByPlatform() { 786 // We first read the per slot value. If doesn't exist, we read the general value. If still 787 // doesn't exist, we use the hardcoded default value. 788 if (SystemProperties.getInt(PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE + 789 Integer.toString(mPhoneId), SYSTEM_PROPERTY_NOT_SET) == 1 || 790 SystemProperties.getInt( 791 PROPERTY_DBG_ALLOW_IMS_OFF_OVERRIDE, SYSTEM_PROPERTY_NOT_SET) == 1) { 792 return true; 793 } 794 795 return getBooleanCarrierConfig( 796 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL); 797 } 798 799 /** 800 * Returns the user configuration of WFC setting 801 * 802 * @deprecated Does not support MSIM devices. Please use 803 * {@link #isWfcEnabledByUser()} instead. 804 */ isWfcEnabledByUser(Context context)805 public static boolean isWfcEnabledByUser(Context context) { 806 ImsManager mgr = ImsManager.getInstance(context, 807 SubscriptionManager.getDefaultVoicePhoneId()); 808 if (mgr != null) { 809 return mgr.isWfcEnabledByUser(); 810 } 811 Rlog.e(TAG, "isWfcEnabledByUser: ImsManager null, returning default value."); 812 return true; 813 } 814 815 /** 816 * Returns the user configuration of WFC setting for slot. If not set, it 817 * queries CarrierConfig value as default. 818 */ isWfcEnabledByUser()819 public boolean isWfcEnabledByUser() { 820 int setting = SubscriptionManager.getIntegerSubscriptionProperty( 821 getSubId(), SubscriptionManager.WFC_IMS_ENABLED, 822 SUB_PROPERTY_NOT_INITIALIZED, mContext); 823 824 // SUB_PROPERTY_NOT_INITIALIZED indicates it's never set in sub db. 825 if (setting == SUB_PROPERTY_NOT_INITIALIZED) { 826 return getBooleanCarrierConfig( 827 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL); 828 } else { 829 return setting == ProvisioningManager.PROVISIONING_VALUE_ENABLED; 830 } 831 } 832 833 /** 834 * Change persistent WFC enabled setting. 835 * @deprecated Does not support MSIM devices. Please use 836 * {@link #setWfcSetting} instead. 837 */ setWfcSetting(Context context, boolean enabled)838 public static void setWfcSetting(Context context, boolean enabled) { 839 ImsManager mgr = ImsManager.getInstance(context, 840 SubscriptionManager.getDefaultVoicePhoneId()); 841 if (mgr != null) { 842 mgr.setWfcSetting(enabled); 843 } 844 Rlog.e(TAG, "setWfcSetting: ImsManager null, can not set value."); 845 } 846 847 /** 848 * Change persistent WFC enabled setting for slot. 849 */ setWfcSetting(boolean enabled)850 public void setWfcSetting(boolean enabled) { 851 if (enabled && !isWfcProvisionedOnDevice()) { 852 log("setWfcSetting: Not possible to enable WFC due to provisioning."); 853 return; 854 } 855 856 int subId = getSubId(); 857 if (isSubIdValid(subId)) { 858 SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.WFC_IMS_ENABLED, 859 booleanToPropertyString(enabled)); 860 } else { 861 loge("setWfcSetting: invalid sub id, can not set WFC setting in siminfo db; subId=" 862 + subId); 863 } 864 865 TelephonyManager tm = (TelephonyManager) 866 mContext.getSystemService(Context.TELEPHONY_SERVICE); 867 boolean isRoaming = tm.isNetworkRoaming(subId); 868 setWfcNonPersistent(enabled, getWfcMode(isRoaming)); 869 } 870 871 /** 872 * Non-persistently change WFC enabled setting and WFC mode for slot 873 * 874 * @param enabled If true, WFC and WFC while roaming will be enabled for the associated 875 * subscription, if supported by the carrier. If false, WFC will be disabled for 876 * the associated subscription. 877 * @param wfcMode The WFC preference if WFC is enabled 878 */ setWfcNonPersistent(boolean enabled, int wfcMode)879 public void setWfcNonPersistent(boolean enabled, int wfcMode) { 880 // Force IMS to register over LTE when turning off WFC 881 int imsWfcModeFeatureValue = 882 enabled ? wfcMode : ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED; 883 884 try { 885 changeMmTelCapability(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 886 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, enabled); 887 888 // Set the mode and roaming enabled settings before turning on IMS 889 setWfcModeInternal(imsWfcModeFeatureValue); 890 // If enabled is false, shortcut to false because of the ImsService 891 // implementation for WFC roaming, otherwise use the correct user's setting. 892 setWfcRoamingSettingInternal(enabled && isWfcRoamingEnabledByUser()); 893 894 if (enabled) { 895 log("setWfcSetting() : turnOnIms"); 896 turnOnIms(); 897 } else if (isTurnOffImsAllowedByPlatform() 898 && (!isVolteEnabledByPlatform() 899 || !isEnhanced4gLteModeSettingEnabledByUser())) { 900 log("setWfcSetting() : imsServiceAllowTurnOff -> turnOffIms"); 901 turnOffIms(); 902 } 903 } catch (ImsException e) { 904 loge("setWfcSetting(): ", e); 905 } 906 } 907 908 /** 909 * Returns the user configuration of WFC preference setting. 910 * 911 * @deprecated Doesn't support MSIM devices. Use {@link #getWfcMode(boolean roaming)} instead. 912 */ getWfcMode(Context context)913 public static int getWfcMode(Context context) { 914 ImsManager mgr = ImsManager.getInstance(context, 915 SubscriptionManager.getDefaultVoicePhoneId()); 916 if (mgr != null) { 917 return mgr.getWfcMode(); 918 } 919 Rlog.e(TAG, "getWfcMode: ImsManager null, returning default value."); 920 return ImsMmTelManager.WIFI_MODE_WIFI_ONLY; 921 } 922 923 /** 924 * Returns the user configuration of WFC preference setting 925 * @deprecated. Use {@link #getWfcMode(boolean roaming)} instead. 926 */ getWfcMode()927 public int getWfcMode() { 928 return getWfcMode(false); 929 } 930 931 /** 932 * Change persistent WFC preference setting. 933 * 934 * @deprecated Doesn't support MSIM devices. Use {@link #setWfcMode(int)} instead. 935 */ setWfcMode(Context context, int wfcMode)936 public static void setWfcMode(Context context, int wfcMode) { 937 ImsManager mgr = ImsManager.getInstance(context, 938 SubscriptionManager.getDefaultVoicePhoneId()); 939 if (mgr != null) { 940 mgr.setWfcMode(wfcMode); 941 } 942 Rlog.e(TAG, "setWfcMode: ImsManager null, can not set value."); 943 } 944 945 /** 946 * Change persistent WFC preference setting for slot when not roaming. 947 * @deprecated Use {@link #setWfcMode(int, boolean)} instead. 948 */ setWfcMode(int wfcMode)949 public void setWfcMode(int wfcMode) { 950 setWfcMode(wfcMode, false /*isRoaming*/); 951 } 952 953 /** 954 * Returns the user configuration of WFC preference setting 955 * 956 * @param roaming {@code false} for home network setting, {@code true} for roaming setting 957 * 958 * @deprecated Doesn't support MSIM devices. Use {@link #getWfcMode(boolean)} instead. 959 */ getWfcMode(Context context, boolean roaming)960 public static int getWfcMode(Context context, boolean roaming) { 961 ImsManager mgr = ImsManager.getInstance(context, 962 SubscriptionManager.getDefaultVoicePhoneId()); 963 if (mgr != null) { 964 return mgr.getWfcMode(roaming); 965 } 966 Rlog.e(TAG, "getWfcMode: ImsManager null, returning default value."); 967 return ImsMmTelManager.WIFI_MODE_WIFI_ONLY; 968 } 969 970 /** 971 * Returns the user configuration of WFC preference setting for slot. If not set, it 972 * queries CarrierConfig value as default. 973 * 974 * @param roaming {@code false} for home network setting, {@code true} for roaming setting 975 */ getWfcMode(boolean roaming)976 public int getWfcMode(boolean roaming) { 977 int setting; 978 if (!roaming) { 979 // The WFC mode is not editable, return the default setting in the CarrierConfig, not 980 // the user set value. 981 if (!getBooleanCarrierConfig(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL)) { 982 setting = getIntCarrierConfig( 983 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT); 984 985 } else { 986 setting = getSettingFromSubscriptionManager(SubscriptionManager.WFC_IMS_MODE, 987 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT); 988 } 989 if (DBG) log("getWfcMode - setting=" + setting); 990 } else { 991 if (getBooleanCarrierConfig( 992 CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)) { 993 setting = getWfcMode(false); 994 } else if (!getBooleanCarrierConfig( 995 CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL)) { 996 setting = getIntCarrierConfig( 997 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT); 998 } else { 999 setting = getSettingFromSubscriptionManager( 1000 SubscriptionManager.WFC_IMS_ROAMING_MODE, 1001 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT); 1002 } 1003 if (DBG) log("getWfcMode (roaming) - setting=" + setting); 1004 } 1005 return setting; 1006 } 1007 1008 /** 1009 * Returns the SubscriptionManager setting for the subSetting string. If it is not set, default 1010 * to the default CarrierConfig value for defaultConfigKey. 1011 */ getSettingFromSubscriptionManager(String subSetting, String defaultConfigKey)1012 private int getSettingFromSubscriptionManager(String subSetting, String defaultConfigKey) { 1013 int result; 1014 result = SubscriptionManager.getIntegerSubscriptionProperty(getSubId(), subSetting, 1015 SUB_PROPERTY_NOT_INITIALIZED, mContext); 1016 1017 // SUB_PROPERTY_NOT_INITIALIZED indicates it's never set in sub db. 1018 if (result == SUB_PROPERTY_NOT_INITIALIZED) { 1019 result = getIntCarrierConfig(defaultConfigKey); 1020 } 1021 return result; 1022 } 1023 1024 /** 1025 * Change persistent WFC preference setting 1026 * 1027 * @param roaming {@code false} for home network setting, {@code true} for roaming setting 1028 * 1029 * @deprecated Doesn't support MSIM devices. Please use {@link #setWfcMode(int, boolean)} 1030 * instead. 1031 */ setWfcMode(Context context, int wfcMode, boolean roaming)1032 public static void setWfcMode(Context context, int wfcMode, boolean roaming) { 1033 ImsManager mgr = ImsManager.getInstance(context, 1034 SubscriptionManager.getDefaultVoicePhoneId()); 1035 if (mgr != null) { 1036 mgr.setWfcMode(wfcMode, roaming); 1037 } 1038 Rlog.e(TAG, "setWfcMode: ImsManager null, can not set value."); 1039 } 1040 1041 /** 1042 * Change persistent WFC preference setting 1043 * 1044 * @param roaming {@code false} for home network setting, {@code true} for roaming setting 1045 */ setWfcMode(int wfcMode, boolean roaming)1046 public void setWfcMode(int wfcMode, boolean roaming) { 1047 int subId = getSubId(); 1048 if (isSubIdValid(subId)) { 1049 if (!roaming) { 1050 if (DBG) log("setWfcMode(i,b) - setting=" + wfcMode); 1051 SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.WFC_IMS_MODE, 1052 Integer.toString(wfcMode)); 1053 } else { 1054 if (DBG) log("setWfcMode(i,b) (roaming) - setting=" + wfcMode); 1055 SubscriptionManager.setSubscriptionProperty(subId, 1056 SubscriptionManager.WFC_IMS_ROAMING_MODE, Integer.toString(wfcMode)); 1057 } 1058 } else { 1059 loge("setWfcMode(i,b): invalid sub id, skip setting setting in siminfo db; subId=" 1060 + subId); 1061 } 1062 1063 TelephonyManager tm = (TelephonyManager) 1064 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1065 // Unfortunately, the WFC mode is the same for home/roaming (we do not have separate 1066 // config keys), so we have to change the WFC mode when moving home<->roaming. So, only 1067 // call setWfcModeInternal when roaming == telephony roaming status. Otherwise, ignore. 1068 if (roaming == tm.isNetworkRoaming(getSubId())) { 1069 setWfcModeInternal(wfcMode); 1070 } 1071 } 1072 getSubId()1073 private int getSubId() { 1074 int[] subIds = SubscriptionManager.getSubId(mPhoneId); 1075 int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 1076 if (subIds != null && subIds.length >= 1) { 1077 subId = subIds[0]; 1078 } 1079 return subId; 1080 } 1081 setWfcModeInternal(int wfcMode)1082 private void setWfcModeInternal(int wfcMode) { 1083 final int value = wfcMode; 1084 mExecutorFactory.executeRunnable(() -> { 1085 try { 1086 getConfigInterface().setConfig( 1087 ProvisioningManager.KEY_VOICE_OVER_WIFI_MODE_OVERRIDE, value); 1088 } catch (ImsException e) { 1089 // do nothing 1090 } 1091 }); 1092 } 1093 1094 /** 1095 * Returns the user configuration of WFC roaming setting 1096 * 1097 * @deprecated Does not support MSIM devices. Please use 1098 * {@link #isWfcRoamingEnabledByUser()} instead. 1099 */ isWfcRoamingEnabledByUser(Context context)1100 public static boolean isWfcRoamingEnabledByUser(Context context) { 1101 ImsManager mgr = ImsManager.getInstance(context, 1102 SubscriptionManager.getDefaultVoicePhoneId()); 1103 if (mgr != null) { 1104 return mgr.isWfcRoamingEnabledByUser(); 1105 } 1106 Rlog.e(TAG, "isWfcRoamingEnabledByUser: ImsManager null, returning default value."); 1107 return false; 1108 } 1109 1110 /** 1111 * Returns the user configuration of WFC roaming setting for slot. If not set, it 1112 * queries CarrierConfig value as default. 1113 */ isWfcRoamingEnabledByUser()1114 public boolean isWfcRoamingEnabledByUser() { 1115 int setting = SubscriptionManager.getIntegerSubscriptionProperty( 1116 getSubId(), SubscriptionManager.WFC_IMS_ROAMING_ENABLED, 1117 SUB_PROPERTY_NOT_INITIALIZED, mContext); 1118 if (setting == SUB_PROPERTY_NOT_INITIALIZED) { 1119 return getBooleanCarrierConfig( 1120 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL); 1121 } else { 1122 return setting == ProvisioningManager.PROVISIONING_VALUE_ENABLED; 1123 } 1124 } 1125 1126 /** 1127 * Change persistent WFC roaming enabled setting 1128 */ setWfcRoamingSetting(Context context, boolean enabled)1129 public static void setWfcRoamingSetting(Context context, boolean enabled) { 1130 ImsManager mgr = ImsManager.getInstance(context, 1131 SubscriptionManager.getDefaultVoicePhoneId()); 1132 if (mgr != null) { 1133 mgr.setWfcRoamingSetting(enabled); 1134 } 1135 Rlog.e(TAG, "setWfcRoamingSetting: ImsManager null, value not set."); 1136 } 1137 1138 /** 1139 * Change persistent WFC roaming enabled setting 1140 */ setWfcRoamingSetting(boolean enabled)1141 public void setWfcRoamingSetting(boolean enabled) { 1142 SubscriptionManager.setSubscriptionProperty(getSubId(), 1143 SubscriptionManager.WFC_IMS_ROAMING_ENABLED, booleanToPropertyString(enabled) 1144 ); 1145 1146 setWfcRoamingSettingInternal(enabled); 1147 } 1148 setWfcRoamingSettingInternal(boolean enabled)1149 private void setWfcRoamingSettingInternal(boolean enabled) { 1150 final int value = enabled 1151 ? ProvisioningManager.PROVISIONING_VALUE_ENABLED 1152 : ProvisioningManager.PROVISIONING_VALUE_DISABLED; 1153 mExecutorFactory.executeRunnable(() -> { 1154 try { 1155 getConfigInterface().setConfig( 1156 ProvisioningManager.KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE, value); 1157 } catch (ImsException e) { 1158 // do nothing 1159 } 1160 }); 1161 } 1162 1163 /** 1164 * Returns a platform configuration for WFC which may override the user 1165 * setting. Note: WFC presumes that VoLTE is enabled (these are 1166 * configuration settings which must be done correctly). 1167 * 1168 * @deprecated Doesn't work for MSIM devices. Use {@link #isWfcEnabledByPlatform()} 1169 * instead. 1170 */ isWfcEnabledByPlatform(Context context)1171 public static boolean isWfcEnabledByPlatform(Context context) { 1172 ImsManager mgr = ImsManager.getInstance(context, 1173 SubscriptionManager.getDefaultVoicePhoneId()); 1174 if (mgr != null) { 1175 return mgr.isWfcEnabledByPlatform(); 1176 } 1177 Rlog.e(TAG, "isWfcEnabledByPlatform: ImsManager null, returning default value."); 1178 return false; 1179 } 1180 1181 /** 1182 * Returns a platform configuration for WFC which may override the user 1183 * setting per slot. Note: WFC presumes that VoLTE is enabled (these are 1184 * configuration settings which must be done correctly). 1185 */ isWfcEnabledByPlatform()1186 public boolean isWfcEnabledByPlatform() { 1187 // We first read the per slot value. If doesn't exist, we read the general value. If still 1188 // doesn't exist, we use the hardcoded default value. 1189 if (SystemProperties.getInt(PROPERTY_DBG_WFC_AVAIL_OVERRIDE + 1190 Integer.toString(mPhoneId), SYSTEM_PROPERTY_NOT_SET) == 1 || 1191 SystemProperties.getInt( 1192 PROPERTY_DBG_WFC_AVAIL_OVERRIDE, SYSTEM_PROPERTY_NOT_SET) == 1) { 1193 return true; 1194 } 1195 1196 return mContext.getResources().getBoolean( 1197 com.android.internal.R.bool.config_device_wfc_ims_available) && 1198 getBooleanCarrierConfig( 1199 CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL) && 1200 isGbaValid(); 1201 } 1202 isSuppServicesOverUtEnabledByPlatform()1203 public boolean isSuppServicesOverUtEnabledByPlatform() { 1204 TelephonyManager manager = (TelephonyManager) mContext.getSystemService( 1205 Context.TELEPHONY_SERVICE); 1206 int cardState = manager.getSimState(mPhoneId); 1207 if (cardState != TelephonyManager.SIM_STATE_READY) { 1208 // Do not report enabled until we actually have an active subscription. 1209 return false; 1210 } 1211 return getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL) && 1212 isGbaValid(); 1213 } 1214 1215 /** 1216 * If carrier requires that IMS is only available if GBA capable SIM is used, 1217 * then this function checks GBA bit in EF IST. 1218 * 1219 * Format of EF IST is defined in 3GPP TS 31.103 (Section 4.2.7). 1220 */ isGbaValid()1221 private boolean isGbaValid() { 1222 if (getBooleanCarrierConfig( 1223 CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) { 1224 final TelephonyManager telephonyManager = new TelephonyManager(mContext, getSubId()); 1225 String efIst = telephonyManager.getIsimIst(); 1226 if (efIst == null) { 1227 loge("isGbaValid - ISF is NULL"); 1228 return true; 1229 } 1230 boolean result = efIst != null && efIst.length() > 1 && 1231 (0x02 & (byte)efIst.charAt(1)) != 0; 1232 if (DBG) log("isGbaValid - GBA capable=" + result + ", ISF=" + efIst); 1233 return result; 1234 } 1235 return true; 1236 } 1237 1238 /** 1239 * Will return with config value or throw an ImsException if we receive an error from 1240 * ImsConfig for that value. 1241 */ getProvisionedBool(ImsConfig config, int item)1242 private boolean getProvisionedBool(ImsConfig config, int item) throws ImsException { 1243 int value = config.getProvisionedValue(item); 1244 if (value == ImsConfigImplBase.CONFIG_RESULT_UNKNOWN) { 1245 throw new ImsException("getProvisionedBool failed with error for item: " + item, 1246 ImsReasonInfo.CODE_LOCAL_INTERNAL_ERROR); 1247 } 1248 return value == ProvisioningManager.PROVISIONING_VALUE_ENABLED; 1249 } 1250 1251 /** 1252 * Will set config value or throw an ImsException if we receive an error from ImsConfig for that 1253 * value. 1254 */ setProvisionedBool(ImsConfig config, int item, int value)1255 private void setProvisionedBool(ImsConfig config, int item, int value) throws ImsException { 1256 int result = config.setConfig(item, value); 1257 if (result != ImsConfigImplBase.CONFIG_RESULT_SUCCESS) { 1258 throw new ImsException("setProvisionedBool failed with error for item: " + item, 1259 ImsReasonInfo.CODE_LOCAL_INTERNAL_ERROR); 1260 } 1261 } 1262 1263 /** 1264 * Will return with config value or return false if we receive an error from 1265 * ImsConfigImplBase implementation for that value. 1266 */ getProvisionedBoolNoException(int item)1267 private boolean getProvisionedBoolNoException(int item) { 1268 try { 1269 ImsConfig config = getConfigInterface(); 1270 return getProvisionedBool(config, item); 1271 } catch (ImsException ex) { 1272 logw("getProvisionedBoolNoException: operation failed for item=" + item 1273 + ". Exception:" + ex.getMessage() + ". Returning false."); 1274 return false; 1275 } 1276 } 1277 1278 /** 1279 * Will return with config value or return false if we receive an error from 1280 * ImsConfigImplBase implementation for that value. 1281 */ setProvisionedBoolNoException(int item, int value)1282 private boolean setProvisionedBoolNoException(int item, int value) { 1283 try { 1284 ImsConfig config = getConfigInterface(); 1285 setProvisionedBool(config, item, value); 1286 } catch (ImsException ex) { 1287 logw("setProvisionedBoolNoException: operation failed for item=" + item 1288 + ", value=" + value + ". Exception:" + ex.getMessage()); 1289 return false; 1290 } 1291 return true; 1292 } 1293 1294 /** 1295 * Sync carrier config and user settings with ImsConfigImplBase implementation. 1296 * 1297 * @param context for the manager object 1298 * @param phoneId phone id 1299 * @param force update 1300 * 1301 * @deprecated Doesn't support MSIM devices. Use {@link #updateImsServiceConfig(boolean)} 1302 * instead. 1303 */ updateImsServiceConfig(Context context, int phoneId, boolean force)1304 public static void updateImsServiceConfig(Context context, int phoneId, boolean force) { 1305 ImsManager mgr = ImsManager.getInstance(context, phoneId); 1306 if (mgr != null) { 1307 mgr.updateImsServiceConfig(force); 1308 } 1309 Rlog.e(TAG, "updateImsServiceConfig: ImsManager null, returning without update."); 1310 } 1311 1312 /** 1313 * Sync carrier config and user settings with ImsConfigImplBase implementation. 1314 * 1315 * @param force update 1316 */ updateImsServiceConfig(boolean force)1317 public void updateImsServiceConfig(boolean force) { 1318 if (!force) { 1319 TelephonyManager tm = new TelephonyManager(mContext, getSubId()); 1320 if (tm.getSimState() != TelephonyManager.SIM_STATE_READY) { 1321 log("updateImsServiceConfig: SIM not ready"); 1322 // Don't disable IMS if SIM is not ready 1323 return; 1324 } 1325 } 1326 1327 if (!mConfigUpdated || force) { 1328 try { 1329 PersistableBundle imsCarrierConfigs = 1330 mConfigManager.getConfigByComponentForSubId( 1331 CarrierConfigManager.Ims.KEY_PREFIX, getSubId()); 1332 1333 updateImsCarrierConfigs(imsCarrierConfigs); 1334 1335 // Note: currently the order of updates is set to produce different order of 1336 // changeEnabledCapabilities() function calls from setAdvanced4GMode(). This is done 1337 // to differentiate this code path from vendor code perspective. 1338 CapabilityChangeRequest request = new CapabilityChangeRequest(); 1339 updateVolteFeatureValue(request); 1340 updateWfcFeatureAndProvisionedValues(request); 1341 updateVideoCallFeatureValue(request); 1342 // Only turn on IMS for RTT if there's an active subscription present. If not, the 1343 // modem will be in emergency-call-only mode and will use separate signaling to 1344 // establish an RTT emergency call. 1345 boolean isImsNeededForRtt = updateRttConfigValue() && isActiveSubscriptionPresent(); 1346 // Supplementary services over UT do not require IMS registration. Do not alter IMS 1347 // registration based on UT. 1348 updateUtFeatureValue(request); 1349 1350 // Send the batched request to the modem. 1351 changeMmTelCapability(request); 1352 1353 if (isImsNeededForRtt || !isTurnOffImsAllowedByPlatform() || isImsNeeded(request)) { 1354 // Turn on IMS if it is used. 1355 // Also, if turning off is not allowed for current carrier, 1356 // we need to turn IMS on because it might be turned off before 1357 // phone switched to current carrier. 1358 log("updateImsServiceConfig: turnOnIms"); 1359 turnOnIms(); 1360 } else { 1361 // Turn off IMS if it is not used AND turning off is allowed for carrier. 1362 log("updateImsServiceConfig: turnOffIms"); 1363 turnOffIms(); 1364 } 1365 1366 mConfigUpdated = true; 1367 } catch (ImsException e) { 1368 loge("updateImsServiceConfig: ", e); 1369 mConfigUpdated = false; 1370 } 1371 } 1372 } 1373 isImsNeeded(CapabilityChangeRequest r)1374 private boolean isImsNeeded(CapabilityChangeRequest r) { 1375 // IMS is not needed for UT, so only enabled IMS if any other capability is enabled. 1376 return r.getCapabilitiesToEnable().stream() 1377 .anyMatch((c) -> 1378 (c.getCapability() != MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT)); 1379 } 1380 1381 /** 1382 * Update VoLTE config 1383 */ updateVolteFeatureValue(CapabilityChangeRequest request)1384 private void updateVolteFeatureValue(CapabilityChangeRequest request) { 1385 boolean available = isVolteEnabledByPlatform(); 1386 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(); 1387 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(); 1388 boolean isProvisioned = isVolteProvisionedOnDevice(); 1389 boolean isFeatureOn = available && enabled && isNonTty && isProvisioned; 1390 1391 log("updateVolteFeatureValue: available = " + available 1392 + ", enabled = " + enabled 1393 + ", nonTTY = " + isNonTty 1394 + ", provisioned = " + isProvisioned 1395 + ", isFeatureOn = " + isFeatureOn); 1396 1397 if (isFeatureOn) { 1398 request.addCapabilitiesToEnableForTech( 1399 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1400 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1401 } else { 1402 request.addCapabilitiesToDisableForTech( 1403 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1404 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1405 } 1406 } 1407 1408 /** 1409 * Update video call over LTE config 1410 */ updateVideoCallFeatureValue(CapabilityChangeRequest request)1411 private void updateVideoCallFeatureValue(CapabilityChangeRequest request) { 1412 boolean available = isVtEnabledByPlatform(); 1413 boolean vtEnabled = isVtEnabledByUser(); 1414 boolean advancedEnabled = isEnhanced4gLteModeSettingEnabledByUser(); 1415 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(); 1416 boolean isDataEnabled = isDataEnabled(); 1417 boolean ignoreDataEnabledChanged = getBooleanCarrierConfig( 1418 CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS); 1419 boolean isProvisioned = isVtProvisionedOnDevice(); 1420 // TODO: Support carrier config setting about if VT settings should be associated with 1421 // advanced calling settings. 1422 boolean isFeatureOn = available && vtEnabled && isNonTty && isProvisioned 1423 && advancedEnabled && (ignoreDataEnabledChanged || isDataEnabled); 1424 1425 log("updateVideoCallFeatureValue: available = " + available 1426 + ", vtenabled = " + vtEnabled 1427 + ", advancedCallEnabled = " + advancedEnabled 1428 + ", nonTTY = " + isNonTty 1429 + ", data enabled = " + isDataEnabled 1430 + ", provisioned = " + isProvisioned 1431 + ", isFeatureOn = " + isFeatureOn); 1432 1433 if (isFeatureOn) { 1434 request.addCapabilitiesToEnableForTech( 1435 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 1436 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1437 } else { 1438 request.addCapabilitiesToDisableForTech( 1439 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 1440 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1441 } 1442 } 1443 1444 /** 1445 * Update WFC config 1446 */ updateWfcFeatureAndProvisionedValues(CapabilityChangeRequest request)1447 private void updateWfcFeatureAndProvisionedValues(CapabilityChangeRequest request) { 1448 TelephonyManager tm = new TelephonyManager(mContext, getSubId()); 1449 boolean isNetworkRoaming = tm.isNetworkRoaming(); 1450 boolean available = isWfcEnabledByPlatform(); 1451 boolean enabled = isWfcEnabledByUser(); 1452 boolean isProvisioned = isWfcProvisionedOnDevice(); 1453 int mode = getWfcMode(isNetworkRoaming); 1454 boolean roaming = isWfcRoamingEnabledByUser(); 1455 boolean isFeatureOn = available && enabled && isProvisioned; 1456 1457 log("updateWfcFeatureAndProvisionedValues: available = " + available 1458 + ", enabled = " + enabled 1459 + ", mode = " + mode 1460 + ", provisioned = " + isProvisioned 1461 + ", roaming = " + roaming 1462 + ", isFeatureOn = " + isFeatureOn); 1463 1464 if (isFeatureOn) { 1465 request.addCapabilitiesToEnableForTech( 1466 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1467 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); 1468 } else { 1469 request.addCapabilitiesToDisableForTech( 1470 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 1471 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); 1472 } 1473 1474 if (!isFeatureOn) { 1475 mode = ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED; 1476 roaming = false; 1477 } 1478 setWfcModeInternal(mode); 1479 setWfcRoamingSettingInternal(roaming); 1480 } 1481 1482 updateUtFeatureValue(CapabilityChangeRequest request)1483 private void updateUtFeatureValue(CapabilityChangeRequest request) { 1484 boolean isCarrierSupported = isSuppServicesOverUtEnabledByPlatform(); 1485 boolean requiresProvisioning = getBooleanCarrierConfig( 1486 CarrierConfigManager.KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL); 1487 // Count as "provisioned" if we do not require provisioning. 1488 boolean isProvisioned = true; 1489 if (requiresProvisioning) { 1490 ITelephony telephony = ITelephony.Stub.asInterface( 1491 ServiceManager.getService(Context.TELEPHONY_SERVICE)); 1492 // Only track UT over LTE, since we do not differentiate between UT over LTE and IWLAN 1493 // currently. 1494 try { 1495 if (telephony != null) { 1496 isProvisioned = telephony.isMmTelCapabilityProvisionedInCache(getSubId(), 1497 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, 1498 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1499 } 1500 } catch (RemoteException e) { 1501 loge("updateUtFeatureValue: couldn't reach telephony! returning provisioned"); 1502 } 1503 } 1504 boolean isFeatureOn = isCarrierSupported && isProvisioned; 1505 1506 log("updateUtFeatureValue: available = " + isCarrierSupported 1507 + ", isProvisioned = " + isProvisioned 1508 + ", enabled = " + isFeatureOn); 1509 1510 if (isFeatureOn) { 1511 request.addCapabilitiesToEnableForTech( 1512 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, 1513 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1514 } else { 1515 request.addCapabilitiesToDisableForTech( 1516 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, 1517 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 1518 } 1519 } 1520 1521 /** 1522 * Do NOT use this directly, instead use {@link #getInstance(Context, int)}. 1523 */ 1524 @VisibleForTesting ImsManager(Context context, int phoneId)1525 public ImsManager(Context context, int phoneId) { 1526 mContext = context; 1527 mPhoneId = phoneId; 1528 mConfigManager = (CarrierConfigManager) context.getSystemService( 1529 Context.CARRIER_CONFIG_SERVICE); 1530 createImsService(); 1531 } 1532 1533 /* 1534 * Returns a flag indicating whether the IMS service is available. If it is not available or 1535 * busy, it will try to connect before reporting failure. 1536 */ isServiceAvailable()1537 public boolean isServiceAvailable() { 1538 connectIfServiceIsAvailable(); 1539 // mImsServiceProxy will always create an ImsServiceProxy. 1540 return mMmTelFeatureConnection.isBinderAlive(); 1541 } 1542 1543 /* 1544 * Returns a flag indicating whether the IMS service is ready to send requests to lower layers. 1545 */ isServiceReady()1546 public boolean isServiceReady() { 1547 connectIfServiceIsAvailable(); 1548 return mMmTelFeatureConnection.isBinderReady(); 1549 } 1550 1551 /** 1552 * If the service is available, try to reconnect. 1553 */ connectIfServiceIsAvailable()1554 public void connectIfServiceIsAvailable() { 1555 if (mMmTelFeatureConnection == null || !mMmTelFeatureConnection.isBinderAlive()) { 1556 createImsService(); 1557 } 1558 } 1559 setConfigListener(ImsConfigListener listener)1560 public void setConfigListener(ImsConfigListener listener) { 1561 mImsConfigListener = listener; 1562 } 1563 1564 1565 /** 1566 * Adds a callback for status changed events if the binder is already available. If it is not, 1567 * this method will throw an ImsException. 1568 */ 1569 @Override 1570 @VisibleForTesting addNotifyStatusChangedCallbackIfAvailable(FeatureConnection.IFeatureUpdate c)1571 public void addNotifyStatusChangedCallbackIfAvailable(FeatureConnection.IFeatureUpdate c) 1572 throws android.telephony.ims.ImsException { 1573 if (!mMmTelFeatureConnection.isBinderAlive()) { 1574 throw new android.telephony.ims.ImsException("Can not connect to ImsService", 1575 android.telephony.ims.ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); 1576 } 1577 if (c != null) { 1578 mStatusCallbacks.add(c); 1579 } 1580 } 1581 1582 @Override removeNotifyStatusChangedCallback(FeatureConnection.IFeatureUpdate c)1583 public void removeNotifyStatusChangedCallback(FeatureConnection.IFeatureUpdate c) { 1584 if (c != null) { 1585 mStatusCallbacks.remove(c); 1586 } else { 1587 logw("removeNotifyStatusChangedCallback: callback is null!"); 1588 } 1589 } 1590 1591 /** 1592 * Opens the IMS service for making calls and/or receiving generic IMS calls. 1593 * The caller may make subsequent calls through {@link #makeCall}. 1594 * The IMS service will register the device to the operator's network with the credentials 1595 * (from ISIM) periodically in order to receive calls from the operator's network. 1596 * When the IMS service receives a new call, it will call 1597 * {@link MmTelFeature.Listener#onIncomingCall} 1598 * @param listener A {@link MmTelFeature.Listener}, which is the interface the 1599 * {@link MmTelFeature} uses to notify the framework of updates 1600 * @throws NullPointerException if {@code listener} is null 1601 * @throws ImsException if calling the IMS service results in an error 1602 */ open(MmTelFeature.Listener listener)1603 public void open(MmTelFeature.Listener listener) throws ImsException { 1604 checkAndThrowExceptionIfServiceUnavailable(); 1605 1606 if (listener == null) { 1607 throw new NullPointerException("listener can't be null"); 1608 } 1609 1610 try { 1611 mMmTelFeatureConnection.openConnection(listener); 1612 } catch (RemoteException e) { 1613 throw new ImsException("open()", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1614 } 1615 } 1616 1617 /** 1618 * Adds registration listener to the IMS service. 1619 * 1620 * @param serviceClass a service class specified in {@link ImsServiceClass} 1621 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}. 1622 * @param listener To listen to IMS registration events; It cannot be null 1623 * @throws NullPointerException if {@code listener} is null 1624 * @throws ImsException if calling the IMS service results in an error 1625 * 1626 * @deprecated Use {@link #addRegistrationListener(ImsConnectionStateListener)} instead. 1627 */ addRegistrationListener(int serviceClass, ImsConnectionStateListener listener)1628 public void addRegistrationListener(int serviceClass, ImsConnectionStateListener listener) 1629 throws ImsException { 1630 addRegistrationListener(listener); 1631 } 1632 1633 /** 1634 * Adds registration listener to the IMS service. 1635 * 1636 * @param listener To listen to IMS registration events; It cannot be null 1637 * @throws NullPointerException if {@code listener} is null 1638 * @throws ImsException if calling the IMS service results in an error 1639 * @deprecated use {@link #addRegistrationCallback(RegistrationManager.RegistrationCallback)} 1640 * instead. 1641 */ addRegistrationListener(ImsConnectionStateListener listener)1642 public void addRegistrationListener(ImsConnectionStateListener listener) throws ImsException { 1643 if (listener == null) { 1644 throw new NullPointerException("listener can't be null"); 1645 } 1646 addRegistrationCallback(listener); 1647 // connect the ImsConnectionStateListener to the new CapabilityCallback. 1648 addCapabilitiesCallback(new ImsMmTelManager.CapabilityCallback() { 1649 @Override 1650 public void onCapabilitiesStatusChanged( 1651 MmTelFeature.MmTelCapabilities capabilities) { 1652 listener.onFeatureCapabilityChangedAdapter(getRegistrationTech(), capabilities); 1653 } 1654 }); 1655 log("Registration Callback registered."); 1656 } 1657 1658 /** 1659 * Adds a callback that gets called when IMS registration has changed for the slot ID 1660 * associated with this ImsManager. 1661 * @param callback A {@link RegistrationManager.RegistrationCallback} that will notify the 1662 * caller when IMS registration status has changed. 1663 * @throws ImsException when the ImsService connection is not available. 1664 */ addRegistrationCallback(RegistrationManager.RegistrationCallback callback)1665 public void addRegistrationCallback(RegistrationManager.RegistrationCallback callback) 1666 throws ImsException { 1667 if (callback == null) { 1668 throw new NullPointerException("registration callback can't be null"); 1669 } 1670 1671 try { 1672 callback.setExecutor(getThreadExecutor()); 1673 mMmTelFeatureConnection.addRegistrationCallback(callback.getBinder()); 1674 log("Registration Callback registered."); 1675 // Only record if there isn't a RemoteException. 1676 } catch (IllegalStateException e) { 1677 throw new ImsException("addRegistrationCallback(IRIB)", e, 1678 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1679 } 1680 } 1681 1682 /** 1683 * Removes a previously added registration callback that was added via 1684 * {@link #addRegistrationCallback(RegistrationManager.RegistrationCallback)} . 1685 * @param callback A {@link RegistrationManager.RegistrationCallback} that was previously added. 1686 */ removeRegistrationListener(RegistrationManager.RegistrationCallback callback)1687 public void removeRegistrationListener(RegistrationManager.RegistrationCallback callback) { 1688 if (callback == null) { 1689 throw new NullPointerException("registration callback can't be null"); 1690 } 1691 1692 mMmTelFeatureConnection.removeRegistrationCallback(callback.getBinder()); 1693 log("Registration callback removed."); 1694 } 1695 1696 /** 1697 * Adds a callback that gets called when IMS registration has changed for a specific 1698 * subscription. 1699 * 1700 * @param callback A {@link RegistrationManager.RegistrationCallback} that will notify the 1701 * caller when IMS registration status has changed. 1702 * @param subId The subscription ID to register this registration callback for. 1703 * @throws RemoteException when the ImsService connection is not available. 1704 */ addRegistrationCallbackForSubscription(IImsRegistrationCallback callback, int subId)1705 public void addRegistrationCallbackForSubscription(IImsRegistrationCallback callback, int subId) 1706 throws RemoteException { 1707 if (callback == null) { 1708 throw new IllegalArgumentException("registration callback can't be null"); 1709 } 1710 mMmTelFeatureConnection.addRegistrationCallbackForSubscription(callback, subId); 1711 log("Registration Callback registered."); 1712 // Only record if there isn't a RemoteException. 1713 } 1714 1715 /** 1716 * Removes a previously registered {@link RegistrationManager.RegistrationCallback} callback 1717 * that is associated with a specific subscription. 1718 */ removeRegistrationCallbackForSubscription(IImsRegistrationCallback callback, int subId)1719 public void removeRegistrationCallbackForSubscription(IImsRegistrationCallback callback, 1720 int subId) { 1721 if (callback == null) { 1722 throw new IllegalArgumentException("registration callback can't be null"); 1723 } 1724 1725 mMmTelFeatureConnection.removeRegistrationCallbackForSubscription(callback, subId); 1726 } 1727 1728 /** 1729 * Adds a callback that gets called when MMTel capability status has changed, for example when 1730 * Voice over IMS or VT over IMS is not available currently. 1731 * @param callback A {@link ImsMmTelManager.CapabilityCallback} that will notify the caller when 1732 * MMTel capability status has changed. 1733 * @throws ImsException when the ImsService connection is not available. 1734 */ addCapabilitiesCallback(ImsMmTelManager.CapabilityCallback callback)1735 public void addCapabilitiesCallback(ImsMmTelManager.CapabilityCallback callback) 1736 throws ImsException { 1737 if (callback == null) { 1738 throw new NullPointerException("capabilities callback can't be null"); 1739 } 1740 1741 checkAndThrowExceptionIfServiceUnavailable(); 1742 try { 1743 callback.setExecutor(getThreadExecutor()); 1744 mMmTelFeatureConnection.addCapabilityCallback(callback.getBinder()); 1745 log("Capability Callback registered."); 1746 // Only record if there isn't a RemoteException. 1747 } catch (IllegalStateException e) { 1748 throw new ImsException("addCapabilitiesCallback(IF)", e, 1749 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1750 } 1751 } 1752 1753 /** 1754 * Removes a previously registered {@link ImsMmTelManager.CapabilityCallback} callback. 1755 * @throws ImsException when the ImsService connection is not available. 1756 */ removeCapabilitiesCallback(ImsMmTelManager.CapabilityCallback callback)1757 public void removeCapabilitiesCallback(ImsMmTelManager.CapabilityCallback callback) 1758 throws ImsException { 1759 if (callback == null) { 1760 throw new NullPointerException("capabilities callback can't be null"); 1761 } 1762 1763 checkAndThrowExceptionIfServiceUnavailable(); 1764 mMmTelFeatureConnection.removeCapabilityCallback(callback.getBinder()); 1765 } 1766 1767 /** 1768 * Adds a callback that gets called when IMS capabilities have changed for a specified 1769 * subscription. 1770 * @param callback A {@link ImsMmTelManager.CapabilityCallback} that will notify the caller 1771 * when the IMS Capabilities have changed. 1772 * @param subId The subscription that is associated with the callback. 1773 * @throws RemoteException when the ImsService connection is not available. 1774 */ addCapabilitiesCallbackForSubscription(IImsCapabilityCallback callback, int subId)1775 public void addCapabilitiesCallbackForSubscription(IImsCapabilityCallback callback, int subId) 1776 throws RemoteException { 1777 if (callback == null) { 1778 throw new IllegalArgumentException("registration callback can't be null"); 1779 } 1780 1781 mMmTelFeatureConnection.addCapabilityCallbackForSubscription(callback, subId); 1782 log("Capability Callback registered for subscription."); 1783 } 1784 1785 /** 1786 * Removes a previously registered {@link ImsMmTelManager.CapabilityCallback} that was 1787 * associated with a specific subscription. 1788 */ removeCapabilitiesCallbackForSubscription(IImsCapabilityCallback callback, int subId)1789 public void removeCapabilitiesCallbackForSubscription(IImsCapabilityCallback callback, 1790 int subId) { 1791 if (callback == null) { 1792 throw new IllegalArgumentException("capabilities callback can't be null"); 1793 } 1794 1795 mMmTelFeatureConnection.removeCapabilityCallbackForSubscription(callback, subId); 1796 } 1797 1798 /** 1799 * Removes the registration listener from the IMS service. 1800 * 1801 * @param listener Previously registered listener that will be removed. Can not be null. 1802 * @throws NullPointerException if {@code listener} is null 1803 * @throws ImsException if calling the IMS service results in an error 1804 * instead. 1805 */ removeRegistrationListener(ImsConnectionStateListener listener)1806 public void removeRegistrationListener(ImsConnectionStateListener listener) 1807 throws ImsException { 1808 if (listener == null) { 1809 throw new NullPointerException("listener can't be null"); 1810 } 1811 1812 checkAndThrowExceptionIfServiceUnavailable(); 1813 mMmTelFeatureConnection.removeRegistrationCallback(listener.getBinder()); 1814 log("Registration Callback/Listener registered."); 1815 // Only record if there isn't a RemoteException. 1816 } 1817 1818 /** 1819 * Adds a callback that gets called when Provisioning has changed for a specified subscription. 1820 * @param callback A {@link ProvisioningManager.Callback} that will notify the caller when 1821 * provisioning has changed. 1822 * @param subId The subscription that is associated with the callback. 1823 * @throws IllegalStateException when the {@link ImsService} connection is not available. 1824 * @throws IllegalArgumentException when the {@link IImsConfigCallback} argument is null. 1825 */ addProvisioningCallbackForSubscription(IImsConfigCallback callback, int subId)1826 public void addProvisioningCallbackForSubscription(IImsConfigCallback callback, int subId) { 1827 if (callback == null) { 1828 throw new IllegalArgumentException("provisioning callback can't be null"); 1829 } 1830 1831 mMmTelFeatureConnection.addProvisioningCallbackForSubscription(callback, subId); 1832 log("Capability Callback registered for subscription."); 1833 } 1834 1835 /** 1836 * Removes a previously registered {@link ProvisioningManager.Callback} that was associated with 1837 * a specific subscription. 1838 * @throws IllegalStateException when the {@link ImsService} connection is not available. 1839 * @throws IllegalArgumentException when the {@link IImsConfigCallback} argument is null. 1840 */ removeProvisioningCallbackForSubscription(IImsConfigCallback callback, int subId)1841 public void removeProvisioningCallbackForSubscription(IImsConfigCallback callback, int subId) { 1842 if (callback == null) { 1843 throw new IllegalArgumentException("provisioning callback can't be null"); 1844 } 1845 1846 mMmTelFeatureConnection.removeProvisioningCallbackForSubscription(callback, subId); 1847 } 1848 getRegistrationTech()1849 public @ImsRegistrationImplBase.ImsRegistrationTech int getRegistrationTech() { 1850 try { 1851 return mMmTelFeatureConnection.getRegistrationTech(); 1852 } catch (RemoteException e) { 1853 logw("getRegistrationTech: no connection to ImsService."); 1854 return ImsRegistrationImplBase.REGISTRATION_TECH_NONE; 1855 } 1856 } 1857 getRegistrationTech(Consumer<Integer> callback)1858 public void getRegistrationTech(Consumer<Integer> callback) { 1859 mExecutorFactory.executeRunnable(() -> { 1860 try { 1861 int tech = mMmTelFeatureConnection.getRegistrationTech(); 1862 callback.accept(tech); 1863 } catch (RemoteException e) { 1864 logw("getRegistrationTech(C): no connection to ImsService."); 1865 callback.accept(ImsRegistrationImplBase.REGISTRATION_TECH_NONE); 1866 } 1867 }); 1868 } 1869 1870 /** 1871 * Closes the connection and removes all active callbacks. 1872 * All the resources that were allocated to the service are also released. 1873 */ close()1874 public void close() { 1875 if (mMmTelFeatureConnection != null) { 1876 mMmTelFeatureConnection.closeConnection(); 1877 } 1878 mUt = null; 1879 mEcbm = null; 1880 mMultiEndpoint = null; 1881 } 1882 1883 /** 1884 * Gets the configuration interface to provision / withdraw the supplementary service settings. 1885 * 1886 * @return the Ut interface instance 1887 * @throws ImsException if getting the Ut interface results in an error 1888 */ getSupplementaryServiceConfiguration()1889 public ImsUtInterface getSupplementaryServiceConfiguration() throws ImsException { 1890 // FIXME: manage the multiple Ut interfaces based on the session id 1891 if (mUt != null && mUt.isBinderAlive()) { 1892 return mUt; 1893 } 1894 1895 checkAndThrowExceptionIfServiceUnavailable(); 1896 try { 1897 IImsUt iUt = mMmTelFeatureConnection.getUtInterface(); 1898 1899 if (iUt == null) { 1900 throw new ImsException("getSupplementaryServiceConfiguration()", 1901 ImsReasonInfo.CODE_UT_NOT_SUPPORTED); 1902 } 1903 1904 mUt = new ImsUt(iUt); 1905 } catch (RemoteException e) { 1906 throw new ImsException("getSupplementaryServiceConfiguration()", e, 1907 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1908 } 1909 return mUt; 1910 } 1911 1912 /** 1913 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state. 1914 * 1915 * @param serviceType a service type that is specified in {@link ImsCallProfile} 1916 * {@link ImsCallProfile#SERVICE_TYPE_NONE} 1917 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 1918 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 1919 * @param callType a call type that is specified in {@link ImsCallProfile} 1920 * {@link ImsCallProfile#CALL_TYPE_VOICE} 1921 * {@link ImsCallProfile#CALL_TYPE_VT} 1922 * {@link ImsCallProfile#CALL_TYPE_VT_TX} 1923 * {@link ImsCallProfile#CALL_TYPE_VT_RX} 1924 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR} 1925 * {@link ImsCallProfile#CALL_TYPE_VS} 1926 * {@link ImsCallProfile#CALL_TYPE_VS_TX} 1927 * {@link ImsCallProfile#CALL_TYPE_VS_RX} 1928 * @return a {@link ImsCallProfile} object 1929 * @throws ImsException if calling the IMS service results in an error 1930 */ createCallProfile(int serviceType, int callType)1931 public ImsCallProfile createCallProfile(int serviceType, int callType) throws ImsException { 1932 checkAndThrowExceptionIfServiceUnavailable(); 1933 1934 try { 1935 return mMmTelFeatureConnection.createCallProfile(serviceType, callType); 1936 } catch (RemoteException e) { 1937 throw new ImsException("createCallProfile()", e, 1938 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1939 } 1940 } 1941 1942 /** 1943 * Creates a {@link ImsCall} to make a call. 1944 * 1945 * @param profile a call profile to make the call 1946 * (it contains service type, call type, media information, etc.) 1947 * @param callees participants to invite the conference call 1948 * @param listener listen to the call events from {@link ImsCall} 1949 * @return a {@link ImsCall} object 1950 * @throws ImsException if calling the IMS service results in an error 1951 */ makeCall(ImsCallProfile profile, String[] callees, ImsCall.Listener listener)1952 public ImsCall makeCall(ImsCallProfile profile, String[] callees, 1953 ImsCall.Listener listener) throws ImsException { 1954 if (DBG) { 1955 log("makeCall :: profile=" + profile); 1956 } 1957 1958 checkAndThrowExceptionIfServiceUnavailable(); 1959 1960 ImsCall call = new ImsCall(mContext, profile); 1961 1962 call.setListener(listener); 1963 ImsCallSession session = createCallSession(profile); 1964 1965 if ((callees != null) && (callees.length == 1) && !(session.isMultiparty())) { 1966 call.start(session, callees[0]); 1967 } else { 1968 call.start(session, callees); 1969 } 1970 1971 return call; 1972 } 1973 1974 /** 1975 * Creates a {@link ImsCall} to take an incoming call. 1976 * 1977 * @param listener to listen to the call events from {@link ImsCall} 1978 * @return a {@link ImsCall} object 1979 * @throws ImsException if calling the IMS service results in an error 1980 */ takeCall(IImsCallSession session, ImsCall.Listener listener)1981 public ImsCall takeCall(IImsCallSession session, ImsCall.Listener listener) 1982 throws ImsException { 1983 checkAndThrowExceptionIfServiceUnavailable(); 1984 try { 1985 if (session == null) { 1986 throw new ImsException("No pending session for the call", 1987 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL); 1988 } 1989 1990 ImsCall call = new ImsCall(mContext, session.getCallProfile()); 1991 1992 call.attachSession(new ImsCallSession(session)); 1993 call.setListener(listener); 1994 1995 return call; 1996 } catch (Throwable t) { 1997 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED); 1998 } 1999 } 2000 2001 /** 2002 * Gets the config interface to get/set service/capability parameters. 2003 * 2004 * @return the ImsConfig instance. 2005 * @throws ImsException if getting the setting interface results in an error. 2006 */ 2007 @UnsupportedAppUsage getConfigInterface()2008 public ImsConfig getConfigInterface() throws ImsException { 2009 checkAndThrowExceptionIfServiceUnavailable(); 2010 2011 IImsConfig config = mMmTelFeatureConnection.getConfigInterface(); 2012 if (config == null) { 2013 throw new ImsException("getConfigInterface()", 2014 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE); 2015 } 2016 return new ImsConfig(config); 2017 } 2018 changeMmTelCapability( @mTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech, boolean isEnabled)2019 public void changeMmTelCapability( 2020 @MmTelFeature.MmTelCapabilities.MmTelCapability int capability, 2021 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech, 2022 boolean isEnabled) throws ImsException { 2023 2024 CapabilityChangeRequest request = new CapabilityChangeRequest(); 2025 if (isEnabled) { 2026 request.addCapabilitiesToEnableForTech(capability, radioTech); 2027 } else { 2028 request.addCapabilitiesToDisableForTech(capability, radioTech); 2029 } 2030 changeMmTelCapability(request); 2031 } 2032 changeMmTelCapability(CapabilityChangeRequest r)2033 public void changeMmTelCapability(CapabilityChangeRequest r) throws ImsException { 2034 checkAndThrowExceptionIfServiceUnavailable(); 2035 try { 2036 logi("changeMmTelCapability: changing capabilities for sub: " + getSubId() 2037 + ", request: " + r); 2038 mMmTelFeatureConnection.changeEnabledCapabilities(r, null); 2039 if (mImsConfigListener == null) { 2040 return; 2041 } 2042 for (CapabilityChangeRequest.CapabilityPair enabledCaps : r.getCapabilitiesToEnable()) { 2043 mImsConfigListener.onSetFeatureResponse(enabledCaps.getCapability(), 2044 enabledCaps.getRadioTech(), 2045 ProvisioningManager.PROVISIONING_VALUE_ENABLED, -1); 2046 } 2047 for (CapabilityChangeRequest.CapabilityPair disabledCaps : 2048 r.getCapabilitiesToDisable()) { 2049 mImsConfigListener.onSetFeatureResponse(disabledCaps.getCapability(), 2050 disabledCaps.getRadioTech(), 2051 ProvisioningManager.PROVISIONING_VALUE_DISABLED, -1); 2052 } 2053 } catch (RemoteException e) { 2054 throw new ImsException("changeMmTelCapability(CCR)", e, 2055 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2056 } 2057 } 2058 updateRttConfigValue()2059 public boolean updateRttConfigValue() { 2060 // If there's no active sub anywhere on the device, enable RTT on the modem so that 2061 // the device can make an emergency call. 2062 2063 boolean isActiveSubscriptionPresent = isActiveSubscriptionPresent(); 2064 boolean isCarrierSupported = 2065 getBooleanCarrierConfig(CarrierConfigManager.KEY_RTT_SUPPORTED_BOOL) 2066 || !isActiveSubscriptionPresent; 2067 2068 boolean isRttUiSettingEnabled = Settings.Secure.getInt(mContext.getContentResolver(), 2069 Settings.Secure.RTT_CALLING_MODE, 0) != 0; 2070 boolean isRttAlwaysOnCarrierConfig = getBooleanCarrierConfig( 2071 CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL); 2072 2073 boolean shouldImsRttBeOn = isRttUiSettingEnabled || isRttAlwaysOnCarrierConfig; 2074 logi("update RTT: settings value: " + isRttUiSettingEnabled + " always-on carrierconfig: " 2075 + isRttAlwaysOnCarrierConfig 2076 + "isActiveSubscriptionPresent: " + isActiveSubscriptionPresent); 2077 2078 if (isCarrierSupported) { 2079 setRttConfig(shouldImsRttBeOn); 2080 } else { 2081 setRttConfig(false); 2082 } 2083 return isCarrierSupported && shouldImsRttBeOn; 2084 } 2085 setRttConfig(boolean enabled)2086 private void setRttConfig(boolean enabled) { 2087 final int value = enabled ? ProvisioningManager.PROVISIONING_VALUE_ENABLED : 2088 ProvisioningManager.PROVISIONING_VALUE_DISABLED; 2089 mExecutorFactory.executeRunnable(() -> { 2090 try { 2091 logi("Setting RTT enabled to " + enabled); 2092 getConfigInterface().setProvisionedValue( 2093 ImsConfig.ConfigConstants.RTT_SETTING_ENABLED, value); 2094 } catch (ImsException e) { 2095 loge("Unable to set RTT value enabled to " + enabled + ": " + e); 2096 } 2097 }); 2098 } 2099 queryMmTelCapability( @mTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)2100 public boolean queryMmTelCapability( 2101 @MmTelFeature.MmTelCapabilities.MmTelCapability int capability, 2102 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) throws ImsException { 2103 checkAndThrowExceptionIfServiceUnavailable(); 2104 2105 BlockingQueue<Boolean> result = new LinkedBlockingDeque<>(1); 2106 2107 try { 2108 mMmTelFeatureConnection.queryEnabledCapabilities(capability, radioTech, 2109 new IImsCapabilityCallback.Stub() { 2110 @Override 2111 public void onQueryCapabilityConfiguration(int resCap, int resTech, 2112 boolean enabled) { 2113 if (resCap == capability && resTech == radioTech) { 2114 result.offer(enabled); 2115 } 2116 } 2117 2118 @Override 2119 public void onChangeCapabilityConfigurationError(int capability, 2120 int radioTech, int reason) { 2121 2122 } 2123 2124 @Override 2125 public void onCapabilitiesStatusChanged(int config) { 2126 2127 } 2128 }); 2129 } catch (RemoteException e) { 2130 throw new ImsException("queryMmTelCapability()", e, 2131 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2132 } 2133 2134 try { 2135 return result.poll(RESPONSE_WAIT_TIME_MS, TimeUnit.MILLISECONDS); 2136 } catch (InterruptedException e) { 2137 logw("queryMmTelCapability: interrupted while waiting for response"); 2138 } 2139 return false; 2140 } 2141 queryMmTelCapabilityStatus( @mTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)2142 public boolean queryMmTelCapabilityStatus( 2143 @MmTelFeature.MmTelCapabilities.MmTelCapability int capability, 2144 @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) throws ImsException { 2145 checkAndThrowExceptionIfServiceUnavailable(); 2146 2147 if (getRegistrationTech() != radioTech) 2148 return false; 2149 2150 try { 2151 2152 MmTelFeature.MmTelCapabilities capabilities = 2153 mMmTelFeatureConnection.queryCapabilityStatus(); 2154 2155 return capabilities.isCapable(capability); 2156 } catch (RemoteException e) { 2157 throw new ImsException("queryMmTelCapabilityStatus()", e, 2158 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2159 } 2160 } 2161 setRttEnabled(boolean enabled)2162 public void setRttEnabled(boolean enabled) { 2163 try { 2164 if (enabled) { 2165 setEnhanced4gLteModeSetting(enabled); 2166 } else { 2167 setAdvanced4GMode(enabled || isEnhanced4gLteModeSettingEnabledByUser()); 2168 } 2169 setRttConfig(enabled); 2170 } catch (ImsException e) { 2171 loge("Unable to set RTT enabled to " + enabled + ": " + e); 2172 } 2173 } 2174 2175 /** 2176 * Set the TTY mode. This is the actual tty mode (varies depending on peripheral status) 2177 */ setTtyMode(int ttyMode)2178 public void setTtyMode(int ttyMode) throws ImsException { 2179 if (!getBooleanCarrierConfig( 2180 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) { 2181 setAdvanced4GMode((ttyMode == TelecomManager.TTY_MODE_OFF) && 2182 isEnhanced4gLteModeSettingEnabledByUser()); 2183 } 2184 } 2185 2186 /** 2187 * Sets the UI TTY mode. This is the preferred TTY mode that the user sets in the call 2188 * settings screen. 2189 * @param uiTtyMode TTY Mode, valid options are: 2190 * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF} 2191 * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL} 2192 * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO} 2193 * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO} 2194 * @param onComplete A Message that will be called by the ImsService when it has completed this 2195 * operation or null if not waiting for an async response. The Message must contain a 2196 * valid {@link Message#replyTo} {@link android.os.Messenger}, since it will be passed 2197 * through Binder to another process. 2198 */ setUiTTYMode(Context context, int uiTtyMode, Message onComplete)2199 public void setUiTTYMode(Context context, int uiTtyMode, Message onComplete) 2200 throws ImsException { 2201 2202 checkAndThrowExceptionIfServiceUnavailable(); 2203 2204 try { 2205 mMmTelFeatureConnection.setUiTTYMode(uiTtyMode, onComplete); 2206 } catch (RemoteException e) { 2207 throw new ImsException("setTTYMode()", e, 2208 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2209 } 2210 } 2211 makeACopy(ImsReasonInfo imsReasonInfo)2212 private ImsReasonInfo makeACopy(ImsReasonInfo imsReasonInfo) { 2213 Parcel p = Parcel.obtain(); 2214 imsReasonInfo.writeToParcel(p, 0); 2215 p.setDataPosition(0); 2216 ImsReasonInfo clonedReasonInfo = ImsReasonInfo.CREATOR.createFromParcel(p); 2217 p.recycle(); 2218 return clonedReasonInfo; 2219 } 2220 2221 /** 2222 * Get Recent IMS Disconnect Reasons. 2223 * 2224 * @return ArrayList of ImsReasonInfo objects. MAX size of the arraylist 2225 * is MAX_RECENT_DISCONNECT_REASONS. The objects are in the 2226 * chronological order. 2227 */ getRecentImsDisconnectReasons()2228 public ArrayList<ImsReasonInfo> getRecentImsDisconnectReasons() { 2229 ArrayList<ImsReasonInfo> disconnectReasons = new ArrayList<>(); 2230 2231 for (ImsReasonInfo reason : mRecentDisconnectReasons) { 2232 disconnectReasons.add(makeACopy(reason)); 2233 } 2234 return disconnectReasons; 2235 } 2236 2237 @Override getImsServiceState()2238 public int getImsServiceState() throws ImsException { 2239 return mMmTelFeatureConnection.getFeatureState(); 2240 } 2241 getImsServiceState(Consumer<Integer> result)2242 public void getImsServiceState(Consumer<Integer> result) { 2243 mExecutorFactory.executeRunnable(() -> { 2244 try { 2245 result.accept(getImsServiceState()); 2246 } catch (ImsException e) { 2247 // In the case that the ImsService is not available, report unavailable. 2248 result.accept(ImsFeature.STATE_UNAVAILABLE); 2249 } 2250 }); 2251 } 2252 getThreadExecutor()2253 private Executor getThreadExecutor() { 2254 if (Looper.myLooper() == null) { 2255 Looper.prepare(); 2256 } 2257 return new HandlerExecutor(new Handler(Looper.myLooper())); 2258 } 2259 2260 /** 2261 * Get the boolean config from carrier config manager. 2262 * 2263 * @param key config key defined in CarrierConfigManager 2264 * @return boolean value of corresponding key. 2265 */ getBooleanCarrierConfig(String key)2266 private boolean getBooleanCarrierConfig(String key) { 2267 PersistableBundle b = null; 2268 if (mConfigManager != null) { 2269 // If an invalid subId is used, this bundle will contain default values. 2270 b = mConfigManager.getConfigForSubId(getSubId()); 2271 } 2272 if (b != null) { 2273 return b.getBoolean(key); 2274 } else { 2275 // Return static default defined in CarrierConfigManager. 2276 return CarrierConfigManager.getDefaultConfig().getBoolean(key); 2277 } 2278 } 2279 2280 /** 2281 * Get the int config from carrier config manager. 2282 * 2283 * @param key config key defined in CarrierConfigManager 2284 * @return integer value of corresponding key. 2285 */ getIntCarrierConfig(String key)2286 private int getIntCarrierConfig(String key) { 2287 PersistableBundle b = null; 2288 if (mConfigManager != null) { 2289 // If an invalid subId is used, this bundle will contain default values. 2290 b = mConfigManager.getConfigForSubId(getSubId()); 2291 } 2292 if (b != null) { 2293 return b.getInt(key); 2294 } else { 2295 // Return static default defined in CarrierConfigManager. 2296 return CarrierConfigManager.getDefaultConfig().getInt(key); 2297 } 2298 } 2299 2300 /** 2301 * Checks to see if the ImsService Binder is connected. If it is not, we try to create the 2302 * connection again. 2303 */ checkAndThrowExceptionIfServiceUnavailable()2304 private void checkAndThrowExceptionIfServiceUnavailable() 2305 throws ImsException { 2306 if (!isImsSupportedOnDevice(mContext)) { 2307 throw new ImsException("IMS not supported on device.", 2308 ImsReasonInfo.CODE_LOCAL_IMS_NOT_SUPPORTED_ON_DEVICE); 2309 } 2310 if (mMmTelFeatureConnection == null || !mMmTelFeatureConnection.isBinderAlive()) { 2311 createImsService(); 2312 2313 if (mMmTelFeatureConnection == null) { 2314 throw new ImsException("Service is unavailable", 2315 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2316 } 2317 } 2318 } 2319 2320 /** 2321 * Creates a connection to the ImsService associated with this slot. 2322 */ createImsService()2323 private void createImsService() { 2324 mMmTelFeatureConnection = MmTelFeatureConnection.create(mContext, mPhoneId); 2325 2326 // Forwarding interface to tell mStatusCallbacks that the Proxy is unavailable. 2327 mMmTelFeatureConnection.setStatusCallback(new FeatureConnection.IFeatureUpdate() { 2328 @Override 2329 public void notifyStateChanged() { 2330 mStatusCallbacks.forEach(FeatureConnection.IFeatureUpdate::notifyStateChanged); 2331 } 2332 2333 @Override 2334 public void notifyUnavailable() { 2335 mStatusCallbacks.forEach(FeatureConnection.IFeatureUpdate::notifyUnavailable); 2336 } 2337 }); 2338 } 2339 2340 /** 2341 * Creates a {@link ImsCallSession} with the specified call profile. 2342 * Use other methods, if applicable, instead of interacting with 2343 * {@link ImsCallSession} directly. 2344 * 2345 * @param profile a call profile to make the call 2346 */ createCallSession(ImsCallProfile profile)2347 private ImsCallSession createCallSession(ImsCallProfile profile) throws ImsException { 2348 try { 2349 // Throws an exception if the ImsService Feature is not ready to accept commands. 2350 return new ImsCallSession(mMmTelFeatureConnection.createCallSession(profile)); 2351 } catch (RemoteException e) { 2352 logw("CreateCallSession: Error, remote exception: " + e.getMessage()); 2353 throw new ImsException("createCallSession()", e, 2354 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2355 2356 } 2357 } 2358 log(String s)2359 private void log(String s) { 2360 Rlog.d(TAG + " [" + mPhoneId + "]", s); 2361 } 2362 logi(String s)2363 private void logi(String s) { 2364 Rlog.i(TAG + " [" + mPhoneId + "]", s); 2365 } 2366 logw(String s)2367 private void logw(String s) { 2368 Rlog.w(TAG + " [" + mPhoneId + "]", s); 2369 } 2370 loge(String s)2371 private void loge(String s) { 2372 Rlog.e(TAG + " [" + mPhoneId + "]", s); 2373 } 2374 loge(String s, Throwable t)2375 private void loge(String s, Throwable t) { 2376 Rlog.e(TAG + " [" + mPhoneId + "]", s, t); 2377 } 2378 2379 /** 2380 * Used for turning on IMS.if its off already 2381 */ turnOnIms()2382 private void turnOnIms() throws ImsException { 2383 TelephonyManager tm = (TelephonyManager) 2384 mContext.getSystemService(Context.TELEPHONY_SERVICE); 2385 tm.enableIms(mPhoneId); 2386 } 2387 isImsTurnOffAllowed()2388 private boolean isImsTurnOffAllowed() { 2389 return isTurnOffImsAllowedByPlatform() 2390 && (!isWfcEnabledByPlatform() 2391 || !isWfcEnabledByUser()); 2392 } 2393 setLteFeatureValues(boolean turnOn)2394 private void setLteFeatureValues(boolean turnOn) { 2395 log("setLteFeatureValues: " + turnOn); 2396 CapabilityChangeRequest request = new CapabilityChangeRequest(); 2397 if (turnOn) { 2398 request.addCapabilitiesToEnableForTech( 2399 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 2400 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 2401 } else { 2402 request.addCapabilitiesToDisableForTech( 2403 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 2404 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 2405 } 2406 2407 if (isVtEnabledByPlatform()) { 2408 boolean ignoreDataEnabledChanged = getBooleanCarrierConfig( 2409 CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS); 2410 boolean enableViLte = turnOn && isVtEnabledByUser() && 2411 (ignoreDataEnabledChanged || isDataEnabled()); 2412 if (enableViLte) { 2413 request.addCapabilitiesToEnableForTech( 2414 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 2415 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 2416 } else { 2417 request.addCapabilitiesToDisableForTech( 2418 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 2419 ImsRegistrationImplBase.REGISTRATION_TECH_LTE); 2420 } 2421 } 2422 try { 2423 mMmTelFeatureConnection.changeEnabledCapabilities(request, null); 2424 } catch (RemoteException e) { 2425 loge("setLteFeatureValues: Exception: " + e.getMessage()); 2426 } 2427 } 2428 setAdvanced4GMode(boolean turnOn)2429 private void setAdvanced4GMode(boolean turnOn) throws ImsException { 2430 checkAndThrowExceptionIfServiceUnavailable(); 2431 2432 // if turnOn: first set feature values then call turnOnIms() 2433 // if turnOff: only set feature values if IMS turn off is not allowed. If turn off is 2434 // allowed, first call turnOffIms() then set feature values 2435 if (turnOn) { 2436 setLteFeatureValues(turnOn); 2437 log("setAdvanced4GMode: turnOnIms"); 2438 turnOnIms(); 2439 } else { 2440 if (isImsTurnOffAllowed()) { 2441 log("setAdvanced4GMode: turnOffIms"); 2442 turnOffIms(); 2443 } 2444 setLteFeatureValues(turnOn); 2445 } 2446 } 2447 2448 /** 2449 * Used for turning off IMS completely in order to make the device CSFB'ed. 2450 * Once turned off, all calls will be over CS. 2451 */ turnOffIms()2452 private void turnOffIms() throws ImsException { 2453 TelephonyManager tm = (TelephonyManager) 2454 mContext.getSystemService(Context.TELEPHONY_SERVICE); 2455 tm.disableIms(mPhoneId); 2456 } 2457 addToRecentDisconnectReasons(ImsReasonInfo reason)2458 private void addToRecentDisconnectReasons(ImsReasonInfo reason) { 2459 if (reason == null) return; 2460 while (mRecentDisconnectReasons.size() >= MAX_RECENT_DISCONNECT_REASONS) { 2461 mRecentDisconnectReasons.removeFirst(); 2462 } 2463 mRecentDisconnectReasons.addLast(reason); 2464 } 2465 2466 /** 2467 * Gets the ECBM interface to request ECBM exit. 2468 * 2469 * @return the ECBM interface instance 2470 * @throws ImsException if getting the ECBM interface results in an error 2471 */ getEcbmInterface()2472 public ImsEcbm getEcbmInterface() throws ImsException { 2473 if (mEcbm != null && mEcbm.isBinderAlive()) { 2474 return mEcbm; 2475 } 2476 2477 checkAndThrowExceptionIfServiceUnavailable(); 2478 try { 2479 IImsEcbm iEcbm = mMmTelFeatureConnection.getEcbmInterface(); 2480 2481 if (iEcbm == null) { 2482 throw new ImsException("getEcbmInterface()", 2483 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED); 2484 } 2485 mEcbm = new ImsEcbm(iEcbm); 2486 } catch (RemoteException e) { 2487 throw new ImsException("getEcbmInterface()", e, 2488 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2489 } 2490 return mEcbm; 2491 } 2492 sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, byte[] pdu)2493 public void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, 2494 byte[] pdu) throws ImsException { 2495 try { 2496 mMmTelFeatureConnection.sendSms(token, messageRef, format, smsc, isRetry, pdu); 2497 } catch (RemoteException e) { 2498 throw new ImsException("sendSms()", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2499 } 2500 } 2501 acknowledgeSms(int token, int messageRef, int result)2502 public void acknowledgeSms(int token, int messageRef, int result) throws ImsException { 2503 try { 2504 mMmTelFeatureConnection.acknowledgeSms(token, messageRef, result); 2505 } catch (RemoteException e) { 2506 throw new ImsException("acknowledgeSms()", e, 2507 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2508 } 2509 } 2510 acknowledgeSmsReport(int token, int messageRef, int result)2511 public void acknowledgeSmsReport(int token, int messageRef, int result) throws ImsException{ 2512 try { 2513 mMmTelFeatureConnection.acknowledgeSmsReport(token, messageRef, result); 2514 } catch (RemoteException e) { 2515 throw new ImsException("acknowledgeSmsReport()", e, 2516 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2517 } 2518 } 2519 getSmsFormat()2520 public String getSmsFormat() throws ImsException{ 2521 try { 2522 return mMmTelFeatureConnection.getSmsFormat(); 2523 } catch (RemoteException e) { 2524 throw new ImsException("getSmsFormat()", e, 2525 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2526 } 2527 } 2528 setSmsListener(IImsSmsListener listener)2529 public void setSmsListener(IImsSmsListener listener) throws ImsException { 2530 try { 2531 mMmTelFeatureConnection.setSmsListener(listener); 2532 } catch (RemoteException e) { 2533 throw new ImsException("setSmsListener()", e, 2534 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2535 } 2536 } 2537 onSmsReady()2538 public void onSmsReady() throws ImsException { 2539 try { 2540 mMmTelFeatureConnection.onSmsReady(); 2541 } catch (RemoteException e) { 2542 throw new ImsException("onSmsReady()", e, 2543 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2544 } 2545 } 2546 2547 /** 2548 * Determines whether or not a call with the specified numbers should be placed over IMS or over 2549 * CSFB. 2550 * @param isEmergency is at least one call an emergency number. 2551 * @param numbers A {@link String} array containing the numbers in the call being placed. Can 2552 * be multiple numbers in the case of dialing out a conference. 2553 * @return The result of the query, one of the following values: 2554 * - {@link MmTelFeature#PROCESS_CALL_IMS} 2555 * - {@link MmTelFeature#PROCESS_CALL_CSFB} 2556 * @throws ImsException if the ImsService is not available. In this case, we should fall back 2557 * to CSFB anyway. 2558 */ shouldProcessCall(boolean isEmergency, String[] numbers)2559 public @MmTelFeature.ProcessCallResult int shouldProcessCall(boolean isEmergency, 2560 String[] numbers) throws ImsException { 2561 try { 2562 return mMmTelFeatureConnection.shouldProcessCall(isEmergency, numbers); 2563 } catch (RemoteException e) { 2564 throw new ImsException("shouldProcessCall()", e, 2565 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2566 } 2567 } 2568 2569 /** 2570 * Gets the Multi-Endpoint interface to subscribe to multi-enpoint notifications.. 2571 * 2572 * @return the multi-endpoint interface instance 2573 * @throws ImsException if getting the multi-endpoint interface results in an error 2574 */ getMultiEndpointInterface()2575 public ImsMultiEndpoint getMultiEndpointInterface() throws ImsException { 2576 if (mMultiEndpoint != null && mMultiEndpoint.isBinderAlive()) { 2577 return mMultiEndpoint; 2578 } 2579 2580 checkAndThrowExceptionIfServiceUnavailable(); 2581 try { 2582 IImsMultiEndpoint iImsMultiEndpoint = mMmTelFeatureConnection.getMultiEndpointInterface(); 2583 2584 if (iImsMultiEndpoint == null) { 2585 throw new ImsException("getMultiEndpointInterface()", 2586 ImsReasonInfo.CODE_MULTIENDPOINT_NOT_SUPPORTED); 2587 } 2588 mMultiEndpoint = new ImsMultiEndpoint(iImsMultiEndpoint); 2589 } catch (RemoteException e) { 2590 throw new ImsException("getMultiEndpointInterface()", e, 2591 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2592 } 2593 2594 return mMultiEndpoint; 2595 } 2596 2597 /** 2598 * Resets ImsManager settings back to factory defaults. 2599 * 2600 * @deprecated Doesn't support MSIM devices. Use {@link #factoryReset()} instead. 2601 * 2602 * @hide 2603 */ factoryReset(Context context)2604 public static void factoryReset(Context context) { 2605 ImsManager mgr = ImsManager.getInstance(context, 2606 SubscriptionManager.getDefaultVoicePhoneId()); 2607 if (mgr != null) { 2608 mgr.factoryReset(); 2609 } 2610 Rlog.e(TAG, "factoryReset: ImsManager null."); 2611 } 2612 2613 /** 2614 * Resets ImsManager settings back to factory defaults. 2615 * 2616 * @hide 2617 */ factoryReset()2618 public void factoryReset() { 2619 int subId = getSubId(); 2620 if (isSubIdValid(subId)) { 2621 // Set VoLTE to default 2622 SubscriptionManager.setSubscriptionProperty(subId, 2623 SubscriptionManager.ENHANCED_4G_MODE_ENABLED, 2624 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 2625 2626 // Set VoWiFi to default 2627 SubscriptionManager.setSubscriptionProperty(subId, 2628 SubscriptionManager.WFC_IMS_ENABLED, 2629 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 2630 2631 // Set VoWiFi mode to default 2632 SubscriptionManager.setSubscriptionProperty(subId, 2633 SubscriptionManager.WFC_IMS_MODE, 2634 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 2635 2636 // Set VoWiFi roaming to default 2637 SubscriptionManager.setSubscriptionProperty(subId, 2638 SubscriptionManager.WFC_IMS_ROAMING_ENABLED, 2639 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 2640 2641 // Set VoWiFi roaming mode to default 2642 SubscriptionManager.setSubscriptionProperty(subId, 2643 SubscriptionManager.WFC_IMS_ROAMING_MODE, 2644 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 2645 2646 2647 // Set VT to default 2648 SubscriptionManager.setSubscriptionProperty(subId, 2649 SubscriptionManager.VT_IMS_ENABLED, 2650 Integer.toString(SUB_PROPERTY_NOT_INITIALIZED)); 2651 2652 // Set RCS UCE to default 2653 SubscriptionManager.setSubscriptionProperty(subId, 2654 SubscriptionManager.IMS_RCS_UCE_ENABLED, Integer.toString( 2655 SUBINFO_PROPERTY_FALSE)); 2656 } else { 2657 loge("factoryReset: invalid sub id, can not reset siminfo db settings; subId=" + subId); 2658 } 2659 2660 // Push settings to ImsConfig 2661 updateImsServiceConfig(true); 2662 } 2663 setVolteProvisioned(boolean isProvisioned)2664 public void setVolteProvisioned(boolean isProvisioned) { 2665 int provisionStatus = isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED : 2666 ProvisioningManager.PROVISIONING_VALUE_DISABLED; 2667 setProvisionedBoolNoException(ImsConfig.ConfigConstants.VLT_SETTING_ENABLED, 2668 provisionStatus); 2669 } 2670 setWfcProvisioned(boolean isProvisioned)2671 public void setWfcProvisioned(boolean isProvisioned) { 2672 int provisionStatus = isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED : 2673 ProvisioningManager.PROVISIONING_VALUE_DISABLED; 2674 setProvisionedBoolNoException( 2675 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED, provisionStatus); 2676 } 2677 setVtProvisioned(boolean isProvisioned)2678 public void setVtProvisioned(boolean isProvisioned) { 2679 int provisionStatus = isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED : 2680 ProvisioningManager.PROVISIONING_VALUE_DISABLED; 2681 setProvisionedBoolNoException(ImsConfig.ConfigConstants.LVC_SETTING_ENABLED, 2682 provisionStatus); 2683 } 2684 setEabProvisioned(boolean isProvisioned)2685 public void setEabProvisioned(boolean isProvisioned) { 2686 int provisionStatus = isProvisioned ? ProvisioningManager.PROVISIONING_VALUE_ENABLED : 2687 ProvisioningManager.PROVISIONING_VALUE_DISABLED; 2688 setProvisionedBoolNoException(ImsConfig.ConfigConstants.EAB_SETTING_ENABLED, 2689 provisionStatus); 2690 } 2691 isDataEnabled()2692 private boolean isDataEnabled() { 2693 return new TelephonyManager(mContext, getSubId()).isDataConnectionAllowed(); 2694 } 2695 isVolteProvisioned()2696 private boolean isVolteProvisioned() { 2697 return getProvisionedBoolNoException( 2698 ImsConfig.ConfigConstants.VLT_SETTING_ENABLED); 2699 } 2700 isEabProvisioned()2701 private boolean isEabProvisioned() { 2702 return getProvisionedBoolNoException( 2703 ImsConfig.ConfigConstants.EAB_SETTING_ENABLED); 2704 } 2705 isWfcProvisioned()2706 private boolean isWfcProvisioned() { 2707 return getProvisionedBoolNoException( 2708 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED); 2709 } 2710 isVtProvisioned()2711 private boolean isVtProvisioned() { 2712 return getProvisionedBoolNoException( 2713 ImsConfig.ConfigConstants.LVC_SETTING_ENABLED); 2714 } 2715 booleanToPropertyString(boolean bool)2716 private static String booleanToPropertyString(boolean bool) { 2717 return bool ? "1" : "0"; 2718 } 2719 2720 dump(FileDescriptor fd, PrintWriter pw, String[] args)2721 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2722 pw.println("ImsManager:"); 2723 pw.println(" device supports IMS = " + isImsSupportedOnDevice(mContext)); 2724 pw.println(" mPhoneId = " + mPhoneId); 2725 pw.println(" mConfigUpdated = " + mConfigUpdated); 2726 pw.println(" mImsServiceProxy = " + mMmTelFeatureConnection); 2727 pw.println(" mDataEnabled = " + isDataEnabled()); 2728 pw.println(" ignoreDataEnabledChanged = " + getBooleanCarrierConfig( 2729 CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS)); 2730 2731 pw.println(" isGbaValid = " + isGbaValid()); 2732 pw.println(" isImsTurnOffAllowed = " + isImsTurnOffAllowed()); 2733 pw.println(" isNonTtyOrTtyOnVolteEnabled = " + isNonTtyOrTtyOnVolteEnabled()); 2734 2735 pw.println(" isVolteEnabledByPlatform = " + isVolteEnabledByPlatform()); 2736 pw.println(" isVolteProvisionedOnDevice = " + isVolteProvisionedOnDevice()); 2737 pw.println(" isEnhanced4gLteModeSettingEnabledByUser = " + 2738 isEnhanced4gLteModeSettingEnabledByUser()); 2739 pw.println(" isVtEnabledByPlatform = " + isVtEnabledByPlatform()); 2740 pw.println(" isVtEnabledByUser = " + isVtEnabledByUser()); 2741 2742 pw.println(" isWfcEnabledByPlatform = " + isWfcEnabledByPlatform()); 2743 pw.println(" isWfcEnabledByUser = " + isWfcEnabledByUser()); 2744 pw.println(" getWfcMode(non-roaming) = " + getWfcMode(false)); 2745 pw.println(" getWfcMode(roaming) = " + getWfcMode(true)); 2746 pw.println(" isWfcRoamingEnabledByUser = " + isWfcRoamingEnabledByUser()); 2747 2748 pw.println(" isVtProvisionedOnDevice = " + isVtProvisionedOnDevice()); 2749 pw.println(" isWfcProvisionedOnDevice = " + isWfcProvisionedOnDevice()); 2750 pw.flush(); 2751 } 2752 2753 /** 2754 * Determines if a sub id is valid. 2755 * Mimics the logic in SubscriptionController.validateSubId. 2756 * @param subId The sub id to check. 2757 * @return {@code true} if valid, {@code false} otherwise. 2758 */ isSubIdValid(int subId)2759 private boolean isSubIdValid(int subId) { 2760 return SubscriptionManager.isValidSubscriptionId(subId) && 2761 subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; 2762 } 2763 isActiveSubscriptionPresent()2764 private boolean isActiveSubscriptionPresent() { 2765 SubscriptionManager sm = (SubscriptionManager) mContext.getSystemService( 2766 Context.TELEPHONY_SUBSCRIPTION_SERVICE); 2767 return sm.getActiveSubscriptionIdList().length > 0; 2768 } 2769 updateImsCarrierConfigs(PersistableBundle configs)2770 private void updateImsCarrierConfigs(PersistableBundle configs) throws ImsException { 2771 checkAndThrowExceptionIfServiceUnavailable(); 2772 2773 IImsConfig config = mMmTelFeatureConnection.getConfigInterface(); 2774 if (config == null) { 2775 throw new ImsException("getConfigInterface()", 2776 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE); 2777 } 2778 try { 2779 config.updateImsCarrierConfigs(configs); 2780 } catch (RemoteException e) { 2781 throw new ImsException("updateImsCarrierConfigs()", e, 2782 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 2783 } 2784 } 2785 } 2786