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