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