ImsManager.java revision 8c065f5f1bc66bec1c12cdd156b90f1cb0e98df8
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 17package com.android.ims; 18 19import android.app.PendingIntent; 20import android.app.QueuedWork; 21import android.content.Context; 22import android.content.Intent; 23import android.content.SharedPreferences; 24import android.os.IBinder; 25import android.os.Message; 26import android.os.PersistableBundle; 27import android.os.RemoteException; 28import android.os.ServiceManager; 29import android.os.SystemProperties; 30import android.preference.PreferenceManager; 31import android.provider.Settings; 32import android.telecom.TelecomManager; 33import android.telephony.CarrierConfigManager; 34import android.telephony.Rlog; 35import android.telephony.SubscriptionManager; 36import android.telephony.TelephonyManager; 37 38import com.android.ims.internal.IImsCallSession; 39import com.android.ims.internal.IImsEcbm; 40import com.android.ims.internal.IImsEcbmListener; 41import com.android.ims.internal.IImsRegistrationListener; 42import com.android.ims.internal.IImsService; 43import com.android.ims.internal.IImsUt; 44import com.android.ims.internal.ImsCallSession; 45import com.android.ims.internal.IImsConfig; 46 47import java.util.HashMap; 48 49/** 50 * Provides APIs for IMS services, such as initiating IMS calls, and provides access to 51 * the operator's IMS network. This class is the starting point for any IMS actions. 52 * You can acquire an instance of it with {@link #getInstance getInstance()}.</p> 53 * <p>The APIs in this class allows you to:</p> 54 * 55 * @hide 56 */ 57public class ImsManager { 58 59 /* 60 * Debug flag to override configuration flag 61 */ 62 public static final String PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr"; 63 public static final int PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT = 0; 64 public static final String PROPERTY_DBG_VT_AVAIL_OVERRIDE = "persist.dbg.vt_avail_ovr"; 65 public static final int PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT = 0; 66 public static final String PROPERTY_DBG_WFC_AVAIL_OVERRIDE = "persist.dbg.wfc_avail_ovr"; 67 public static final int PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT = 0; 68 69 /** 70 * For accessing the IMS related service. 71 * Internal use only. 72 * @hide 73 */ 74 private static final String IMS_SERVICE = "ims"; 75 76 /** 77 * The result code to be sent back with the incoming call {@link PendingIntent}. 78 * @see #open(PendingIntent, ImsConnectionStateListener) 79 */ 80 public static final int INCOMING_CALL_RESULT_CODE = 101; 81 82 /** 83 * Key to retrieve the call ID from an incoming call intent. 84 * @see #open(PendingIntent, ImsConnectionStateListener) 85 */ 86 public static final String EXTRA_CALL_ID = "android:imsCallID"; 87 88 /** 89 * Action to broadcast when ImsService is up. 90 * Internal use only. 91 * @hide 92 */ 93 public static final String ACTION_IMS_SERVICE_UP = 94 "com.android.ims.IMS_SERVICE_UP"; 95 96 /** 97 * Action to broadcast when ImsService is down. 98 * Internal use only. 99 * @hide 100 */ 101 public static final String ACTION_IMS_SERVICE_DOWN = 102 "com.android.ims.IMS_SERVICE_DOWN"; 103 104 /** 105 * Action to broadcast when ImsService registration fails. 106 * Internal use only. 107 * @hide 108 */ 109 public static final String ACTION_IMS_REGISTRATION_ERROR = 110 "com.android.ims.REGISTRATION_ERROR"; 111 112 /** 113 * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents. 114 * A long value; the phone ID corresponding to the IMS service coming up or down. 115 * Internal use only. 116 * @hide 117 */ 118 public static final String EXTRA_PHONE_ID = "android:phone_id"; 119 120 /** 121 * Action for the incoming call intent for the Phone app. 122 * Internal use only. 123 * @hide 124 */ 125 public static final String ACTION_IMS_INCOMING_CALL = 126 "com.android.ims.IMS_INCOMING_CALL"; 127 128 /** 129 * Part of the ACTION_IMS_INCOMING_CALL intents. 130 * An integer value; service identifier obtained from {@link ImsManager#open}. 131 * Internal use only. 132 * @hide 133 */ 134 public static final String EXTRA_SERVICE_ID = "android:imsServiceId"; 135 136 /** 137 * Part of the ACTION_IMS_INCOMING_CALL intents. 138 * An boolean value; Flag to indicate that the incoming call is a normal call or call for USSD. 139 * The value "true" indicates that the incoming call is for USSD. 140 * Internal use only. 141 * @hide 142 */ 143 public static final String EXTRA_USSD = "android:ussd"; 144 145 /** 146 * Part of the ACTION_IMS_INCOMING_CALL intents. 147 * A boolean value; Flag to indicate whether the call is an unknown 148 * dialing call. Such calls are originated by sending commands (like 149 * AT commands) directly to modem without Android involvement. 150 * Even though they are not incoming calls, they are propagated 151 * to Phone app using same ACTION_IMS_INCOMING_CALL intent. 152 * Internal use only. 153 * @hide 154 */ 155 public static final String EXTRA_IS_UNKNOWN_CALL = "android:isUnknown"; 156 157 private static final String TAG = "ImsManager"; 158 private static final boolean DBG = true; 159 160 private static HashMap<Integer, ImsManager> sImsManagerInstances = 161 new HashMap<Integer, ImsManager>(); 162 163 private Context mContext; 164 private int mPhoneId; 165 private IImsService mImsService = null; 166 private ImsServiceDeathRecipient mDeathRecipient = new ImsServiceDeathRecipient(); 167 // Ut interface for the supplementary service configuration 168 private ImsUt mUt = null; 169 // Interface to get/set ims config items 170 private ImsConfig mConfig = null; 171 private boolean mConfigUpdated = false; 172 private static final String PREF_ENABLE_VIDEO_CALLING_KEY = "enable_video_calling"; 173 174 // ECBM interface 175 private ImsEcbm mEcbm = null; 176 177 /** 178 * Gets a manager instance. 179 * 180 * @param context application context for creating the manager object 181 * @param phoneId the phone ID for the IMS Service 182 * @return the manager instance corresponding to the phoneId 183 */ 184 public static ImsManager getInstance(Context context, int phoneId) { 185 synchronized (sImsManagerInstances) { 186 if (sImsManagerInstances.containsKey(phoneId)) 187 return sImsManagerInstances.get(phoneId); 188 189 ImsManager mgr = new ImsManager(context, phoneId); 190 sImsManagerInstances.put(phoneId, mgr); 191 192 return mgr; 193 } 194 } 195 196 /** 197 * Returns the user configuration of Enhanced 4G LTE Mode setting 198 */ 199 public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) { 200 int enabled = android.provider.Settings.Global.getInt( 201 context.getContentResolver(), 202 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON); 203 return (enabled == 1) ? true : false; 204 } 205 206 /** 207 * Change persistent Enhanced 4G LTE Mode setting 208 */ 209 public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) { 210 int value = enabled ? 1 : 0; 211 android.provider.Settings.Global.putInt( 212 context.getContentResolver(), 213 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, value); 214 215 if (isNonTtyOrTtyOnVolteEnabled(context)) { 216 ImsManager imsManager = ImsManager.getInstance(context, 217 SubscriptionManager.getDefaultVoicePhoneId()); 218 if (imsManager != null) { 219 try { 220 imsManager.setAdvanced4GMode(enabled); 221 } catch (ImsException ie) { 222 // do nothing 223 } 224 } 225 } 226 } 227 228 /** 229 * Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is 230 * supported. 231 */ 232 public static boolean isNonTtyOrTtyOnVolteEnabled(Context context) { 233 if (getBooleanCarrierConfig(context, 234 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) { 235 return true; 236 } 237 238 return Settings.Secure.getInt(context.getContentResolver(), 239 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF) 240 == TelecomManager.TTY_MODE_OFF; 241 } 242 243 /** 244 * Returns a platform configuration for VoLTE which may override the user setting. 245 */ 246 public static boolean isVolteEnabledByPlatform(Context context) { 247 if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE, 248 PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT) == 1) { 249 return true; 250 } 251 252 return context.getResources().getBoolean( 253 com.android.internal.R.bool.config_device_volte_available) 254 && getBooleanCarrierConfig(context, 255 CarrierConfigManager.KEY_CARRIER_VOLTE_AVAILABLE_BOOL) 256 && isGbaValid(context); 257 } 258 259 /* 260 * Indicates whether VoLTE is provisioned on device 261 */ 262 public static boolean isVolteProvisionedOnDevice(Context context) { 263 boolean isProvisioned = true; 264 if (getBooleanCarrierConfig(context, 265 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) { 266 isProvisioned = false; // disable on any error 267 ImsManager mgr = ImsManager.getInstance(context, 268 SubscriptionManager.getDefaultVoicePhoneId()); 269 if (mgr != null) { 270 try { 271 ImsConfig config = mgr.getConfigInterface(); 272 if (config != null) { 273 isProvisioned = config.getVolteProvisioned(); 274 } 275 } catch (ImsException ie) { 276 // do nothing 277 } 278 } 279 } 280 281 return isProvisioned; 282 } 283 284 /** 285 * Returns a platform configuration for VT which may override the user setting. 286 * 287 * Note: VT presumes that VoLTE is enabled (these are configuration settings 288 * which must be done correctly). 289 */ 290 public static boolean isVtEnabledByPlatform(Context context) { 291 if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE, 292 PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT) == 1) { 293 return true; 294 } 295 296 return 297 context.getResources().getBoolean( 298 com.android.internal.R.bool.config_device_vt_available) && 299 getBooleanCarrierConfig(context, 300 CarrierConfigManager.KEY_CARRIER_VT_AVAILABLE_BOOL) && 301 isGbaValid(context); 302 } 303 304 /** 305 * Returns the user configuration of WFC setting 306 */ 307 public static boolean isWfcEnabledByUser(Context context) { 308 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(), 309 android.provider.Settings.Global.WFC_IMS_ENABLED, 310 ImsConfig.FeatureValueConstants.OFF); 311 return (enabled == 1) ? true : false; 312 } 313 314 /** 315 * Change persistent WFC enabled setting 316 */ 317 public static void setWfcSetting(Context context, boolean enabled) { 318 int value = enabled ? 1 : 0; 319 android.provider.Settings.Global.putInt(context.getContentResolver(), 320 android.provider.Settings.Global.WFC_IMS_ENABLED, value); 321 322 ImsManager imsManager = ImsManager.getInstance(context, 323 SubscriptionManager.getDefaultVoicePhoneId()); 324 if (imsManager != null) { 325 try { 326 ImsConfig config = imsManager.getConfigInterface(); 327 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI, 328 TelephonyManager.NETWORK_TYPE_IWLAN, 329 enabled ? ImsConfig.FeatureValueConstants.ON 330 : ImsConfig.FeatureValueConstants.OFF, null); 331 332 if (enabled) { 333 imsManager.turnOnIms(); 334 } else if (getBooleanCarrierConfig(context, 335 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL) 336 && (!isVolteEnabledByPlatform(context) 337 || !isEnhanced4gLteModeSettingEnabledByUser(context))) { 338 log("setWfcSetting() : imsServiceAllowTurnOff -> turnOffIms"); 339 imsManager.turnOffIms(); 340 } 341 342 // Force IMS to register over LTE when turning off WFC 343 setWfcModeInternal(context, enabled 344 ? getWfcMode(context) 345 : ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED); 346 } catch (ImsException e) { 347 loge("setWfcSetting(): " + e); 348 } 349 } 350 } 351 352 /** 353 * Returns the user configuration of WFC modem setting 354 */ 355 public static int getWfcMode(Context context) { 356 int setting = android.provider.Settings.Global.getInt(context.getContentResolver(), 357 android.provider.Settings.Global.WFC_IMS_MODE, 358 ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED); 359 if (DBG) log("getWfcMode - setting=" + setting); 360 return setting; 361 } 362 363 /** 364 * Returns the user configuration of WFC modem setting 365 */ 366 public static void setWfcMode(Context context, int wfcMode) { 367 if (DBG) log("setWfcMode - setting=" + wfcMode); 368 android.provider.Settings.Global.putInt(context.getContentResolver(), 369 android.provider.Settings.Global.WFC_IMS_MODE, wfcMode); 370 371 setWfcModeInternal(context, wfcMode); 372 } 373 374 private static void setWfcModeInternal(Context context, int wfcMode) { 375 final ImsManager imsManager = ImsManager.getInstance(context, 376 SubscriptionManager.getDefaultVoicePhoneId()); 377 if (imsManager != null) { 378 final int value = wfcMode; 379 QueuedWork.singleThreadExecutor().submit(new Runnable() { 380 public void run() { 381 try { 382 imsManager.getConfigInterface().setProvisionedValue( 383 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE, 384 value); 385 } catch (ImsException e) { 386 // do nothing 387 } 388 } 389 }); 390 } 391 } 392 393 /** 394 * Returns the user configuration of WFC roaming setting 395 */ 396 public static boolean isWfcRoamingEnabledByUser(Context context) { 397 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(), 398 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED, 399 ImsConfig.FeatureValueConstants.OFF); 400 return (enabled == 1) ? true : false; 401 } 402 403 /** 404 * Change persistent WFC roaming enabled setting 405 */ 406 public static void setWfcRoamingSetting(Context context, boolean enabled) { 407 android.provider.Settings.Global.putInt(context.getContentResolver(), 408 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED, 409 enabled 410 ? ImsConfig.FeatureValueConstants.ON 411 : ImsConfig.FeatureValueConstants.OFF); 412 413 setWfcRoamingSettingInternal(context, enabled); 414 } 415 416 private static void setWfcRoamingSettingInternal(Context context, boolean enabled) { 417 final ImsManager imsManager = ImsManager.getInstance(context, 418 SubscriptionManager.getDefaultVoicePhoneId()); 419 if (imsManager != null) { 420 final int value = enabled 421 ? ImsConfig.FeatureValueConstants.ON 422 : ImsConfig.FeatureValueConstants.OFF; 423 QueuedWork.singleThreadExecutor().submit(new Runnable() { 424 public void run() { 425 try { 426 imsManager.getConfigInterface().setProvisionedValue( 427 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_ROAMING, 428 value); 429 } catch (ImsException e) { 430 // do nothing 431 } 432 } 433 }); 434 } 435 } 436 437 /** 438 * Returns a platform configuration for WFC which may override the user 439 * setting. Note: WFC presumes that VoLTE is enabled (these are 440 * configuration settings which must be done correctly). 441 */ 442 public static boolean isWfcEnabledByPlatform(Context context) { 443 if (SystemProperties.getInt(PROPERTY_DBG_WFC_AVAIL_OVERRIDE, 444 PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT) == 1) { 445 return true; 446 } 447 448 return 449 context.getResources().getBoolean( 450 com.android.internal.R.bool.config_device_wfc_ims_available) && 451 getBooleanCarrierConfig(context, 452 CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL) && 453 isGbaValid(context); 454 } 455 456 /** 457 * If carrier requires that IMS is only available if GBA capable SIM is used, 458 * then this function checks GBA bit in EF IST. 459 * 460 * Format of EF IST is defined in 3GPP TS 31.103 (Section 4.2.7). 461 */ 462 private static boolean isGbaValid(Context context) { 463 if (getBooleanCarrierConfig(context, 464 CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) { 465 final TelephonyManager telephonyManager = TelephonyManager.getDefault(); 466 String efIst = telephonyManager.getIsimIst(); 467 if (efIst == null) { 468 loge("ISF is NULL"); 469 return true; 470 } 471 boolean result = efIst != null && efIst.length() > 1 && 472 (0x02 & (byte)efIst.charAt(1)) != 0; 473 if (DBG) log("GBA capable=" + result + ", ISF=" + efIst); 474 return result; 475 } 476 return true; 477 } 478 479 /** 480 * Sync carrier config and user settings with ImsConfig. 481 * 482 * @param context for the manager object 483 * @param phoneId phone id 484 * @param force update 485 */ 486 public static void updateImsServiceConfig(Context context, int phoneId, boolean force) { 487 final ImsManager imsManager = ImsManager.getInstance(context, phoneId); 488 if (imsManager != null && (!imsManager.mConfigUpdated || force)) { 489 try { 490 boolean turnOn = imsManager.updateVolteFeatureValue(); 491 turnOn |= imsManager.updateVideoCallFeatureValue(); 492 turnOn |= imsManager.updateWfcFeatureAndProvisionedValues(); 493 494 if (turnOn) { 495 imsManager.turnOnIms(); 496 } else if (getBooleanCarrierConfig(context, 497 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL)) { 498 imsManager.turnOffIms(); 499 } 500 501 imsManager.mConfigUpdated = true; 502 } catch (ImsException e) { 503 loge("updateImsServiceConfig: " + e); 504 imsManager.mConfigUpdated = false; 505 } 506 } 507 } 508 509 /** 510 * Update VoLTE config 511 * @return whether feature is On 512 * @throws ImsException 513 */ 514 private boolean updateVolteFeatureValue() throws ImsException { 515 boolean available = isVolteEnabledByPlatform(mContext); 516 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext); 517 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext); 518 boolean turnOn = available && enabled && isNonTty; 519 520 log("updateVolteFeatureValue: available = " + available 521 + ", enabled = " + enabled 522 + ", nonTTY = " + isNonTty); 523 524 getConfigInterface().setFeatureValue( 525 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, 526 TelephonyManager.NETWORK_TYPE_LTE, 527 turnOn ? 528 ImsConfig.FeatureValueConstants.ON : 529 ImsConfig.FeatureValueConstants.OFF, 530 null); 531 532 return turnOn; 533 } 534 535 /** 536 * Update VC config 537 * @return whether feature is On 538 * @throws ImsException 539 */ 540 private boolean updateVideoCallFeatureValue() throws ImsException { 541 boolean available = isVtEnabledByPlatform(mContext); 542 SharedPreferences sharedPrefs = 543 PreferenceManager.getDefaultSharedPreferences(mContext); 544 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext) && 545 sharedPrefs.getBoolean(PREF_ENABLE_VIDEO_CALLING_KEY, true); 546 boolean isNonTty = Settings.Secure.getInt(mContext.getContentResolver(), 547 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF) 548 == TelecomManager.TTY_MODE_OFF; 549 boolean turnOn = available && enabled && isNonTty; 550 551 log("updateVideoCallFeatureValue: available = " + available 552 + ", enabled = " + enabled 553 + ", nonTTY = " + isNonTty); 554 555 getConfigInterface().setFeatureValue( 556 ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE, 557 TelephonyManager.NETWORK_TYPE_LTE, 558 turnOn ? 559 ImsConfig.FeatureValueConstants.ON : 560 ImsConfig.FeatureValueConstants.OFF, 561 null); 562 563 return turnOn; 564 } 565 566 /** 567 * Update WFC config 568 * @return whether feature is On 569 * @throws ImsException 570 */ 571 private boolean updateWfcFeatureAndProvisionedValues() throws ImsException { 572 boolean available = isWfcEnabledByPlatform(mContext); 573 boolean enabled = isWfcEnabledByUser(mContext); 574 int mode = getWfcMode(mContext); 575 boolean roaming = isWfcRoamingEnabledByUser(mContext); 576 boolean turnOn = available && enabled; 577 578 log("updateWfcFeatureAndProvisionedValues: available = " + available 579 + ", enabled = " + enabled 580 + ", mode = " + mode 581 + ", roaming = " + roaming); 582 583 getConfigInterface().setFeatureValue( 584 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI, 585 TelephonyManager.NETWORK_TYPE_IWLAN, 586 turnOn ? 587 ImsConfig.FeatureValueConstants.ON : 588 ImsConfig.FeatureValueConstants.OFF, 589 null); 590 591 if (!turnOn) { 592 mode = ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED; 593 roaming = false; 594 } 595 setWfcModeInternal(mContext, mode); 596 setWfcRoamingSettingInternal(mContext, roaming); 597 598 return turnOn; 599 } 600 601 private ImsManager(Context context, int phoneId) { 602 mContext = context; 603 mPhoneId = phoneId; 604 createImsService(true); 605 } 606 607 /* 608 * Returns a flag indicating whether the IMS service is available. 609 */ 610 public boolean isServiceAvailable() { 611 if (mImsService != null) { 612 return true; 613 } 614 615 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId)); 616 if (binder != null) { 617 return true; 618 } 619 620 return false; 621 } 622 623 /** 624 * Opens the IMS service for making calls and/or receiving generic IMS calls. 625 * The caller may make subsquent calls through {@link #makeCall}. 626 * The IMS service will register the device to the operator's network with the credentials 627 * (from ISIM) periodically in order to receive calls from the operator's network. 628 * When the IMS service receives a new call, it will send out an intent with 629 * the provided action string. 630 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call. 631 * 632 * @param serviceClass a service class specified in {@link ImsServiceClass} 633 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}. 634 * @param incomingCallPendingIntent When an incoming call is received, 635 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to 636 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE} 637 * as the result code and the intent to fill in the call ID; It cannot be null 638 * @param listener To listen to IMS registration events; It cannot be null 639 * @return identifier (greater than 0) for the specified service 640 * @throws NullPointerException if {@code incomingCallPendingIntent} 641 * or {@code listener} is null 642 * @throws ImsException if calling the IMS service results in an error 643 * @see #getCallId 644 * @see #getServiceId 645 */ 646 public int open(int serviceClass, PendingIntent incomingCallPendingIntent, 647 ImsConnectionStateListener listener) throws ImsException { 648 checkAndThrowExceptionIfServiceUnavailable(); 649 650 if (incomingCallPendingIntent == null) { 651 throw new NullPointerException("incomingCallPendingIntent can't be null"); 652 } 653 654 if (listener == null) { 655 throw new NullPointerException("listener can't be null"); 656 } 657 658 int result = 0; 659 660 try { 661 result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent, 662 createRegistrationListenerProxy(serviceClass, listener)); 663 } catch (RemoteException e) { 664 throw new ImsException("open()", e, 665 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 666 } 667 668 if (result <= 0) { 669 // If the return value is a minus value, 670 // it means that an error occurred in the service. 671 // So, it needs to convert to the reason code specified in ImsReasonInfo. 672 throw new ImsException("open()", (result * (-1))); 673 } 674 675 return result; 676 } 677 678 /** 679 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls. 680 * All the resources that were allocated to the service are also released. 681 * 682 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open} 683 * @throws ImsException if calling the IMS service results in an error 684 */ 685 public void close(int serviceId) throws ImsException { 686 checkAndThrowExceptionIfServiceUnavailable(); 687 688 try { 689 mImsService.close(serviceId); 690 } catch (RemoteException e) { 691 throw new ImsException("close()", e, 692 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 693 } finally { 694 mUt = null; 695 mConfig = null; 696 mEcbm = null; 697 } 698 } 699 700 /** 701 * Gets the configuration interface to provision / withdraw the supplementary service settings. 702 * 703 * @param serviceId a service id which is obtained from {@link ImsManager#open} 704 * @return the Ut interface instance 705 * @throws ImsException if getting the Ut interface results in an error 706 */ 707 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId) 708 throws ImsException { 709 // FIXME: manage the multiple Ut interfaces based on the service id 710 if (mUt == null) { 711 checkAndThrowExceptionIfServiceUnavailable(); 712 713 try { 714 IImsUt iUt = mImsService.getUtInterface(serviceId); 715 716 if (iUt == null) { 717 throw new ImsException("getSupplementaryServiceConfiguration()", 718 ImsReasonInfo.CODE_UT_NOT_SUPPORTED); 719 } 720 721 mUt = new ImsUt(iUt); 722 } catch (RemoteException e) { 723 throw new ImsException("getSupplementaryServiceConfiguration()", e, 724 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 725 } 726 } 727 728 return mUt; 729 } 730 731 /** 732 * Checks if the IMS service has successfully registered to the IMS network 733 * with the specified service & call type. 734 * 735 * @param serviceId a service id which is obtained from {@link ImsManager#open} 736 * @param serviceType a service type that is specified in {@link ImsCallProfile} 737 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 738 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 739 * @param callType a call type that is specified in {@link ImsCallProfile} 740 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO} 741 * {@link ImsCallProfile#CALL_TYPE_VOICE} 742 * {@link ImsCallProfile#CALL_TYPE_VT} 743 * {@link ImsCallProfile#CALL_TYPE_VS} 744 * @return true if the specified service id is connected to the IMS network; 745 * false otherwise 746 * @throws ImsException if calling the IMS service results in an error 747 */ 748 public boolean isConnected(int serviceId, int serviceType, int callType) 749 throws ImsException { 750 checkAndThrowExceptionIfServiceUnavailable(); 751 752 try { 753 return mImsService.isConnected(serviceId, serviceType, callType); 754 } catch (RemoteException e) { 755 throw new ImsException("isServiceConnected()", e, 756 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 757 } 758 } 759 760 /** 761 * Checks if the specified IMS service is opend. 762 * 763 * @param serviceId a service id which is obtained from {@link ImsManager#open} 764 * @return true if the specified service id is opened; false otherwise 765 * @throws ImsException if calling the IMS service results in an error 766 */ 767 public boolean isOpened(int serviceId) throws ImsException { 768 checkAndThrowExceptionIfServiceUnavailable(); 769 770 try { 771 return mImsService.isOpened(serviceId); 772 } catch (RemoteException e) { 773 throw new ImsException("isOpened()", e, 774 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 775 } 776 } 777 778 /** 779 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state. 780 * 781 * @param serviceId a service id which is obtained from {@link ImsManager#open} 782 * @param serviceType a service type that is specified in {@link ImsCallProfile} 783 * {@link ImsCallProfile#SERVICE_TYPE_NONE} 784 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 785 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 786 * @param callType a call type that is specified in {@link ImsCallProfile} 787 * {@link ImsCallProfile#CALL_TYPE_VOICE} 788 * {@link ImsCallProfile#CALL_TYPE_VT} 789 * {@link ImsCallProfile#CALL_TYPE_VT_TX} 790 * {@link ImsCallProfile#CALL_TYPE_VT_RX} 791 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR} 792 * {@link ImsCallProfile#CALL_TYPE_VS} 793 * {@link ImsCallProfile#CALL_TYPE_VS_TX} 794 * {@link ImsCallProfile#CALL_TYPE_VS_RX} 795 * @return a {@link ImsCallProfile} object 796 * @throws ImsException if calling the IMS service results in an error 797 */ 798 public ImsCallProfile createCallProfile(int serviceId, 799 int serviceType, int callType) throws ImsException { 800 checkAndThrowExceptionIfServiceUnavailable(); 801 802 try { 803 return mImsService.createCallProfile(serviceId, serviceType, callType); 804 } catch (RemoteException e) { 805 throw new ImsException("createCallProfile()", e, 806 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 807 } 808 } 809 810 /** 811 * Creates a {@link ImsCall} to make a call. 812 * 813 * @param serviceId a service id which is obtained from {@link ImsManager#open} 814 * @param profile a call profile to make the call 815 * (it contains service type, call type, media information, etc.) 816 * @param participants participants to invite the conference call 817 * @param listener listen to the call events from {@link ImsCall} 818 * @return a {@link ImsCall} object 819 * @throws ImsException if calling the IMS service results in an error 820 */ 821 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees, 822 ImsCall.Listener listener) throws ImsException { 823 if (DBG) { 824 log("makeCall :: serviceId=" + serviceId 825 + ", profile=" + profile + ", callees=" + callees); 826 } 827 828 checkAndThrowExceptionIfServiceUnavailable(); 829 830 ImsCall call = new ImsCall(mContext, profile); 831 832 call.setListener(listener); 833 ImsCallSession session = createCallSession(serviceId, profile); 834 835 if ((callees != null) && (callees.length == 1)) { 836 call.start(session, callees[0]); 837 } else { 838 call.start(session, callees); 839 } 840 841 return call; 842 } 843 844 /** 845 * Creates a {@link ImsCall} to take an incoming call. 846 * 847 * @param serviceId a service id which is obtained from {@link ImsManager#open} 848 * @param incomingCallIntent the incoming call broadcast intent 849 * @param listener to listen to the call events from {@link ImsCall} 850 * @return a {@link ImsCall} object 851 * @throws ImsException if calling the IMS service results in an error 852 */ 853 public ImsCall takeCall(int serviceId, Intent incomingCallIntent, 854 ImsCall.Listener listener) throws ImsException { 855 if (DBG) { 856 log("takeCall :: serviceId=" + serviceId 857 + ", incomingCall=" + incomingCallIntent); 858 } 859 860 checkAndThrowExceptionIfServiceUnavailable(); 861 862 if (incomingCallIntent == null) { 863 throw new ImsException("Can't retrieve session with null intent", 864 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 865 } 866 867 int incomingServiceId = getServiceId(incomingCallIntent); 868 869 if (serviceId != incomingServiceId) { 870 throw new ImsException("Service id is mismatched in the incoming call intent", 871 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 872 } 873 874 String callId = getCallId(incomingCallIntent); 875 876 if (callId == null) { 877 throw new ImsException("Call ID missing in the incoming call intent", 878 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 879 } 880 881 try { 882 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId); 883 884 if (session == null) { 885 throw new ImsException("No pending session for the call", 886 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL); 887 } 888 889 ImsCall call = new ImsCall(mContext, session.getCallProfile()); 890 891 call.attachSession(new ImsCallSession(session)); 892 call.setListener(listener); 893 894 return call; 895 } catch (Throwable t) { 896 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED); 897 } 898 } 899 900 /** 901 * Gets the config interface to get/set service/capability parameters. 902 * 903 * @return the ImsConfig instance. 904 * @throws ImsException if getting the setting interface results in an error. 905 */ 906 public ImsConfig getConfigInterface() throws ImsException { 907 908 if (mConfig == null) { 909 checkAndThrowExceptionIfServiceUnavailable(); 910 911 try { 912 IImsConfig config = mImsService.getConfigInterface(mPhoneId); 913 if (config == null) { 914 throw new ImsException("getConfigInterface()", 915 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE); 916 } 917 mConfig = new ImsConfig(config, mContext); 918 } catch (RemoteException e) { 919 throw new ImsException("getConfigInterface()", e, 920 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 921 } 922 } 923 if (DBG) log("getConfigInterface(), mConfig= " + mConfig); 924 return mConfig; 925 } 926 927 public void setUiTTYMode(Context context, int serviceId, int uiTtyMode, Message onComplete) 928 throws ImsException { 929 930 checkAndThrowExceptionIfServiceUnavailable(); 931 932 try { 933 mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete); 934 } catch (RemoteException e) { 935 throw new ImsException("setTTYMode()", e, 936 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 937 } 938 939 if (!getBooleanCarrierConfig(context, 940 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) { 941 setAdvanced4GMode((uiTtyMode == TelecomManager.TTY_MODE_OFF) && 942 isEnhanced4gLteModeSettingEnabledByUser(context)); 943 } 944 } 945 946 /** 947 * Get the boolean config from carrier config manager. 948 * 949 * @param context the context to get carrier service 950 * @param key config key defined in CarrierConfigManager 951 * @return boolean value of corresponding key. 952 */ 953 private static boolean getBooleanCarrierConfig(Context context, String key) { 954 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService( 955 Context.CARRIER_CONFIG_SERVICE); 956 PersistableBundle b = null; 957 if (configManager != null) { 958 b = configManager.getConfig(); 959 } 960 if (b != null) { 961 return b.getBoolean(key); 962 } else { 963 // Return static default defined in CarrierConfigManager. 964 return CarrierConfigManager.getDefaultConfig().getBoolean(key); 965 } 966 } 967 968 /** 969 * Gets the call ID from the specified incoming call broadcast intent. 970 * 971 * @param incomingCallIntent the incoming call broadcast intent 972 * @return the call ID or null if the intent does not contain it 973 */ 974 private static String getCallId(Intent incomingCallIntent) { 975 if (incomingCallIntent == null) { 976 return null; 977 } 978 979 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID); 980 } 981 982 /** 983 * Gets the service type from the specified incoming call broadcast intent. 984 * 985 * @param incomingCallIntent the incoming call broadcast intent 986 * @return the service identifier or -1 if the intent does not contain it 987 */ 988 private static int getServiceId(Intent incomingCallIntent) { 989 if (incomingCallIntent == null) { 990 return (-1); 991 } 992 993 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1); 994 } 995 996 /** 997 * Binds the IMS service only if the service is not created. 998 */ 999 private void checkAndThrowExceptionIfServiceUnavailable() 1000 throws ImsException { 1001 if (mImsService == null) { 1002 createImsService(true); 1003 1004 if (mImsService == null) { 1005 throw new ImsException("Service is unavailable", 1006 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1007 } 1008 } 1009 } 1010 1011 private static String getImsServiceName(int phoneId) { 1012 // TODO: MSIM implementation needs to decide on service name as a function of phoneId 1013 return IMS_SERVICE; 1014 } 1015 1016 /** 1017 * Binds the IMS service to make/receive the call. 1018 */ 1019 private void createImsService(boolean checkService) { 1020 if (checkService) { 1021 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId)); 1022 1023 if (binder == null) { 1024 return; 1025 } 1026 } 1027 1028 IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId)); 1029 1030 if (b != null) { 1031 try { 1032 b.linkToDeath(mDeathRecipient, 0); 1033 } catch (RemoteException e) { 1034 } 1035 } 1036 1037 mImsService = IImsService.Stub.asInterface(b); 1038 } 1039 1040 /** 1041 * Creates a {@link ImsCallSession} with the specified call profile. 1042 * Use other methods, if applicable, instead of interacting with 1043 * {@link ImsCallSession} directly. 1044 * 1045 * @param serviceId a service id which is obtained from {@link ImsManager#open} 1046 * @param profile a call profile to make the call 1047 */ 1048 private ImsCallSession createCallSession(int serviceId, 1049 ImsCallProfile profile) throws ImsException { 1050 try { 1051 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null)); 1052 } catch (RemoteException e) { 1053 return null; 1054 } 1055 } 1056 1057 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass, 1058 ImsConnectionStateListener listener) { 1059 ImsRegistrationListenerProxy proxy = 1060 new ImsRegistrationListenerProxy(serviceClass, listener); 1061 return proxy; 1062 } 1063 1064 private static void log(String s) { 1065 Rlog.d(TAG, s); 1066 } 1067 1068 private static void loge(String s) { 1069 Rlog.e(TAG, s); 1070 } 1071 1072 private static void loge(String s, Throwable t) { 1073 Rlog.e(TAG, s, t); 1074 } 1075 1076 /** 1077 * Used for turning on IMS.if its off already 1078 */ 1079 private void turnOnIms() throws ImsException { 1080 checkAndThrowExceptionIfServiceUnavailable(); 1081 1082 try { 1083 mImsService.turnOnIms(mPhoneId); 1084 } catch (RemoteException e) { 1085 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1086 } 1087 } 1088 1089 private boolean isImsTurnOffAllowed() { 1090 return getBooleanCarrierConfig(mContext, 1091 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL) 1092 && (!isWfcEnabledByPlatform(mContext) 1093 || !isWfcEnabledByUser(mContext)); 1094 } 1095 1096 private void setAdvanced4GMode(boolean turnOn) throws ImsException { 1097 checkAndThrowExceptionIfServiceUnavailable(); 1098 1099 try { 1100 ImsConfig config = getConfigInterface(); 1101 if (config != null && (turnOn || !isImsTurnOffAllowed())) { 1102 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, 1103 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null); 1104 if (isVtEnabledByPlatform(mContext)) { 1105 // TODO: once VT is available on platform: 1106 // - replace the '1' with the current user configuration of VT. 1107 // - separate exception checks for setFeatureValue() failures for VoLTE and VT. 1108 // I.e. if VoLTE fails still try to configure VT. 1109 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE, 1110 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null); 1111 } 1112 } 1113 } catch (ImsException e) { 1114 log("setAdvanced4GMode() : " + e); 1115 } 1116 if (turnOn) { 1117 turnOnIms(); 1118 } else if (isImsTurnOffAllowed()) { 1119 log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms"); 1120 turnOffIms(); 1121 } 1122 } 1123 1124 /** 1125 * Used for turning off IMS completely in order to make the device CSFB'ed. 1126 * Once turned off, all calls will be over CS. 1127 */ 1128 private void turnOffIms() throws ImsException { 1129 checkAndThrowExceptionIfServiceUnavailable(); 1130 1131 try { 1132 mImsService.turnOffIms(mPhoneId); 1133 } catch (RemoteException e) { 1134 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1135 } 1136 } 1137 1138 /** 1139 * Death recipient class for monitoring IMS service. 1140 */ 1141 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient { 1142 @Override 1143 public void binderDied() { 1144 mImsService = null; 1145 mUt = null; 1146 mConfig = null; 1147 mEcbm = null; 1148 1149 if (mContext != null) { 1150 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN); 1151 intent.putExtra(EXTRA_PHONE_ID, mPhoneId); 1152 mContext.sendBroadcast(new Intent(intent)); 1153 } 1154 } 1155 } 1156 1157 /** 1158 * Adapter class for {@link IImsRegistrationListener}. 1159 */ 1160 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub { 1161 private int mServiceClass; 1162 private ImsConnectionStateListener mListener; 1163 1164 public ImsRegistrationListenerProxy(int serviceClass, 1165 ImsConnectionStateListener listener) { 1166 mServiceClass = serviceClass; 1167 mListener = listener; 1168 } 1169 1170 public boolean isSameProxy(int serviceClass) { 1171 return (mServiceClass == serviceClass); 1172 } 1173 1174 @Override 1175 public void registrationConnected() { 1176 if (DBG) { 1177 log("registrationConnected ::"); 1178 } 1179 1180 if (mListener != null) { 1181 mListener.onImsConnected(); 1182 } 1183 } 1184 1185 @Override 1186 public void registrationProgressing() { 1187 if (DBG) { 1188 log("registrationProgressing ::"); 1189 } 1190 1191 if (mListener != null) { 1192 mListener.onImsProgressing(); 1193 } 1194 } 1195 1196 @Override 1197 public void registrationDisconnected(ImsReasonInfo imsReasonInfo) { 1198 if (DBG) { 1199 log("registrationDisconnected :: imsReasonInfo" + imsReasonInfo); 1200 } 1201 1202 if (mListener != null) { 1203 mListener.onImsDisconnected(imsReasonInfo); 1204 } 1205 } 1206 1207 @Override 1208 public void registrationResumed() { 1209 if (DBG) { 1210 log("registrationResumed ::"); 1211 } 1212 1213 if (mListener != null) { 1214 mListener.onImsResumed(); 1215 } 1216 } 1217 1218 @Override 1219 public void registrationSuspended() { 1220 if (DBG) { 1221 log("registrationSuspended ::"); 1222 } 1223 1224 if (mListener != null) { 1225 mListener.onImsSuspended(); 1226 } 1227 } 1228 1229 @Override 1230 public void registrationServiceCapabilityChanged(int serviceClass, int event) { 1231 log("registrationServiceCapabilityChanged :: serviceClass=" + 1232 serviceClass + ", event=" + event); 1233 1234 if (mListener != null) { 1235 mListener.onImsConnected(); 1236 } 1237 } 1238 1239 @Override 1240 public void registrationFeatureCapabilityChanged(int serviceClass, 1241 int[] enabledFeatures, int[] disabledFeatures) { 1242 log("registrationFeatureCapabilityChanged :: serviceClass=" + 1243 serviceClass); 1244 if (mListener != null) { 1245 mListener.onFeatureCapabilityChanged(serviceClass, 1246 enabledFeatures, disabledFeatures); 1247 } 1248 } 1249 1250 @Override 1251 public void voiceMessageCountUpdate(int count) { 1252 log("voiceMessageCountUpdate :: count=" + count); 1253 1254 if (mListener != null) { 1255 mListener.onVoiceMessageCountChanged(count); 1256 } 1257 } 1258 1259 } 1260 /** 1261 * Gets the ECBM interface to request ECBM exit. 1262 * 1263 * @param serviceId a service id which is obtained from {@link ImsManager#open} 1264 * @return the ECBM interface instance 1265 * @throws ImsException if getting the ECBM interface results in an error 1266 */ 1267 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException { 1268 if (mEcbm == null) { 1269 checkAndThrowExceptionIfServiceUnavailable(); 1270 1271 try { 1272 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId); 1273 1274 if (iEcbm == null) { 1275 throw new ImsException("getEcbmInterface()", 1276 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED); 1277 } 1278 mEcbm = new ImsEcbm(iEcbm); 1279 } catch (RemoteException e) { 1280 throw new ImsException("getEcbmInterface()", e, 1281 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1282 } 1283 } 1284 return mEcbm; 1285 } 1286 1287 /** 1288 * Resets ImsManager settings back to factory defaults. 1289 * 1290 * @hide 1291 */ 1292 public static void factoryReset(Context context) { 1293 // Set VoLTE to default 1294 android.provider.Settings.Global.putInt(context.getContentResolver(), 1295 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, 1296 ImsConfig.FeatureValueConstants.ON); 1297 1298 // Set VoWiFi to default 1299 android.provider.Settings.Global.putInt(context.getContentResolver(), 1300 android.provider.Settings.Global.WFC_IMS_ENABLED, 1301 ImsConfig.FeatureValueConstants.OFF); 1302 1303 // Set VoWiFi mode to default 1304 android.provider.Settings.Global.putInt(context.getContentResolver(), 1305 android.provider.Settings.Global.WFC_IMS_MODE, 1306 ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED); 1307 1308 // Set VoWiFi roaming to default 1309 android.provider.Settings.Global.putInt(context.getContentResolver(), 1310 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED, 1311 ImsConfig.FeatureValueConstants.OFF); 1312 1313 // Set VT to default 1314 SharedPreferences sharedPrefs = 1315 PreferenceManager.getDefaultSharedPreferences(context); 1316 SharedPreferences.Editor editor = sharedPrefs.edit(); 1317 editor.putBoolean(PREF_ENABLE_VIDEO_CALLING_KEY, true); 1318 editor.commit(); 1319 1320 // Push settings to ImsConfig 1321 ImsManager.updateImsServiceConfig(context, 1322 SubscriptionManager.getDefaultVoicePhoneId(), true); 1323 } 1324} 1325