ImsManager.java revision 9510b1cb97fd77cb6a595b91405cbf0a8a4c426e
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 isImsUsed = imsManager.updateVolteFeatureValue(); 491 isImsUsed |= imsManager.updateVideoCallFeatureValue(); 492 isImsUsed |= imsManager.updateWfcFeatureAndProvisionedValues(); 493 494 if (isImsUsed || !getBooleanCarrierConfig(context, 495 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL)) { 496 // Turn on IMS if it is used. 497 // Also, if turning off is not allowed for current carrier, 498 // we need to turn IMS on because it might be turned off before 499 // phone switched to current carrier. 500 imsManager.turnOnIms(); 501 } else { 502 // Turn off IMS if it is not used AND turning off is allowed for carrier. 503 imsManager.turnOffIms(); 504 } 505 506 imsManager.mConfigUpdated = true; 507 } catch (ImsException e) { 508 loge("updateImsServiceConfig: " + e); 509 imsManager.mConfigUpdated = false; 510 } 511 } 512 } 513 514 /** 515 * Update VoLTE config 516 * @return whether feature is On 517 * @throws ImsException 518 */ 519 private boolean updateVolteFeatureValue() throws ImsException { 520 boolean available = isVolteEnabledByPlatform(mContext); 521 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext); 522 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext); 523 boolean isFeatureOn = available && enabled && isNonTty; 524 525 log("updateVolteFeatureValue: available = " + available 526 + ", enabled = " + enabled 527 + ", nonTTY = " + isNonTty); 528 529 getConfigInterface().setFeatureValue( 530 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, 531 TelephonyManager.NETWORK_TYPE_LTE, 532 isFeatureOn ? 533 ImsConfig.FeatureValueConstants.ON : 534 ImsConfig.FeatureValueConstants.OFF, 535 null); 536 537 return isFeatureOn; 538 } 539 540 /** 541 * Update VC config 542 * @return whether feature is On 543 * @throws ImsException 544 */ 545 private boolean updateVideoCallFeatureValue() throws ImsException { 546 boolean available = isVtEnabledByPlatform(mContext); 547 SharedPreferences sharedPrefs = 548 PreferenceManager.getDefaultSharedPreferences(mContext); 549 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext) && 550 sharedPrefs.getBoolean(PREF_ENABLE_VIDEO_CALLING_KEY, true); 551 boolean isNonTty = Settings.Secure.getInt(mContext.getContentResolver(), 552 Settings.Secure.PREFERRED_TTY_MODE, TelecomManager.TTY_MODE_OFF) 553 == TelecomManager.TTY_MODE_OFF; 554 boolean isFeatureOn = available && enabled && isNonTty; 555 556 log("updateVideoCallFeatureValue: available = " + available 557 + ", enabled = " + enabled 558 + ", nonTTY = " + isNonTty); 559 560 getConfigInterface().setFeatureValue( 561 ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE, 562 TelephonyManager.NETWORK_TYPE_LTE, 563 isFeatureOn ? 564 ImsConfig.FeatureValueConstants.ON : 565 ImsConfig.FeatureValueConstants.OFF, 566 null); 567 568 return isFeatureOn; 569 } 570 571 /** 572 * Update WFC config 573 * @return whether feature is On 574 * @throws ImsException 575 */ 576 private boolean updateWfcFeatureAndProvisionedValues() throws ImsException { 577 boolean available = isWfcEnabledByPlatform(mContext); 578 boolean enabled = isWfcEnabledByUser(mContext); 579 int mode = getWfcMode(mContext); 580 boolean roaming = isWfcRoamingEnabledByUser(mContext); 581 boolean isFeatureOn = available && enabled; 582 583 log("updateWfcFeatureAndProvisionedValues: available = " + available 584 + ", enabled = " + enabled 585 + ", mode = " + mode 586 + ", roaming = " + roaming); 587 588 getConfigInterface().setFeatureValue( 589 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI, 590 TelephonyManager.NETWORK_TYPE_IWLAN, 591 isFeatureOn ? 592 ImsConfig.FeatureValueConstants.ON : 593 ImsConfig.FeatureValueConstants.OFF, 594 null); 595 596 if (!isFeatureOn) { 597 mode = ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED; 598 roaming = false; 599 } 600 setWfcModeInternal(mContext, mode); 601 setWfcRoamingSettingInternal(mContext, roaming); 602 603 return isFeatureOn; 604 } 605 606 private ImsManager(Context context, int phoneId) { 607 mContext = context; 608 mPhoneId = phoneId; 609 createImsService(true); 610 } 611 612 /* 613 * Returns a flag indicating whether the IMS service is available. 614 */ 615 public boolean isServiceAvailable() { 616 if (mImsService != null) { 617 return true; 618 } 619 620 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId)); 621 if (binder != null) { 622 return true; 623 } 624 625 return false; 626 } 627 628 /** 629 * Opens the IMS service for making calls and/or receiving generic IMS calls. 630 * The caller may make subsquent calls through {@link #makeCall}. 631 * The IMS service will register the device to the operator's network with the credentials 632 * (from ISIM) periodically in order to receive calls from the operator's network. 633 * When the IMS service receives a new call, it will send out an intent with 634 * the provided action string. 635 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call. 636 * 637 * @param serviceClass a service class specified in {@link ImsServiceClass} 638 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}. 639 * @param incomingCallPendingIntent When an incoming call is received, 640 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to 641 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE} 642 * as the result code and the intent to fill in the call ID; It cannot be null 643 * @param listener To listen to IMS registration events; It cannot be null 644 * @return identifier (greater than 0) for the specified service 645 * @throws NullPointerException if {@code incomingCallPendingIntent} 646 * or {@code listener} is null 647 * @throws ImsException if calling the IMS service results in an error 648 * @see #getCallId 649 * @see #getServiceId 650 */ 651 public int open(int serviceClass, PendingIntent incomingCallPendingIntent, 652 ImsConnectionStateListener listener) throws ImsException { 653 checkAndThrowExceptionIfServiceUnavailable(); 654 655 if (incomingCallPendingIntent == null) { 656 throw new NullPointerException("incomingCallPendingIntent can't be null"); 657 } 658 659 if (listener == null) { 660 throw new NullPointerException("listener can't be null"); 661 } 662 663 int result = 0; 664 665 try { 666 result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent, 667 createRegistrationListenerProxy(serviceClass, listener)); 668 } catch (RemoteException e) { 669 throw new ImsException("open()", e, 670 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 671 } 672 673 if (result <= 0) { 674 // If the return value is a minus value, 675 // it means that an error occurred in the service. 676 // So, it needs to convert to the reason code specified in ImsReasonInfo. 677 throw new ImsException("open()", (result * (-1))); 678 } 679 680 return result; 681 } 682 683 /** 684 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls. 685 * All the resources that were allocated to the service are also released. 686 * 687 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open} 688 * @throws ImsException if calling the IMS service results in an error 689 */ 690 public void close(int serviceId) throws ImsException { 691 checkAndThrowExceptionIfServiceUnavailable(); 692 693 try { 694 mImsService.close(serviceId); 695 } catch (RemoteException e) { 696 throw new ImsException("close()", e, 697 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 698 } finally { 699 mUt = null; 700 mConfig = null; 701 mEcbm = null; 702 } 703 } 704 705 /** 706 * Gets the configuration interface to provision / withdraw the supplementary service settings. 707 * 708 * @param serviceId a service id which is obtained from {@link ImsManager#open} 709 * @return the Ut interface instance 710 * @throws ImsException if getting the Ut interface results in an error 711 */ 712 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId) 713 throws ImsException { 714 // FIXME: manage the multiple Ut interfaces based on the service id 715 if (mUt == null) { 716 checkAndThrowExceptionIfServiceUnavailable(); 717 718 try { 719 IImsUt iUt = mImsService.getUtInterface(serviceId); 720 721 if (iUt == null) { 722 throw new ImsException("getSupplementaryServiceConfiguration()", 723 ImsReasonInfo.CODE_UT_NOT_SUPPORTED); 724 } 725 726 mUt = new ImsUt(iUt); 727 } catch (RemoteException e) { 728 throw new ImsException("getSupplementaryServiceConfiguration()", e, 729 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 730 } 731 } 732 733 return mUt; 734 } 735 736 /** 737 * Checks if the IMS service has successfully registered to the IMS network 738 * with the specified service & call type. 739 * 740 * @param serviceId a service id which is obtained from {@link ImsManager#open} 741 * @param serviceType a service type that is specified in {@link ImsCallProfile} 742 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 743 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 744 * @param callType a call type that is specified in {@link ImsCallProfile} 745 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO} 746 * {@link ImsCallProfile#CALL_TYPE_VOICE} 747 * {@link ImsCallProfile#CALL_TYPE_VT} 748 * {@link ImsCallProfile#CALL_TYPE_VS} 749 * @return true if the specified service id is connected to the IMS network; 750 * false otherwise 751 * @throws ImsException if calling the IMS service results in an error 752 */ 753 public boolean isConnected(int serviceId, int serviceType, int callType) 754 throws ImsException { 755 checkAndThrowExceptionIfServiceUnavailable(); 756 757 try { 758 return mImsService.isConnected(serviceId, serviceType, callType); 759 } catch (RemoteException e) { 760 throw new ImsException("isServiceConnected()", e, 761 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 762 } 763 } 764 765 /** 766 * Checks if the specified IMS service is opend. 767 * 768 * @param serviceId a service id which is obtained from {@link ImsManager#open} 769 * @return true if the specified service id is opened; false otherwise 770 * @throws ImsException if calling the IMS service results in an error 771 */ 772 public boolean isOpened(int serviceId) throws ImsException { 773 checkAndThrowExceptionIfServiceUnavailable(); 774 775 try { 776 return mImsService.isOpened(serviceId); 777 } catch (RemoteException e) { 778 throw new ImsException("isOpened()", e, 779 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 780 } 781 } 782 783 /** 784 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state. 785 * 786 * @param serviceId a service id which is obtained from {@link ImsManager#open} 787 * @param serviceType a service type that is specified in {@link ImsCallProfile} 788 * {@link ImsCallProfile#SERVICE_TYPE_NONE} 789 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 790 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 791 * @param callType a call type that is specified in {@link ImsCallProfile} 792 * {@link ImsCallProfile#CALL_TYPE_VOICE} 793 * {@link ImsCallProfile#CALL_TYPE_VT} 794 * {@link ImsCallProfile#CALL_TYPE_VT_TX} 795 * {@link ImsCallProfile#CALL_TYPE_VT_RX} 796 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR} 797 * {@link ImsCallProfile#CALL_TYPE_VS} 798 * {@link ImsCallProfile#CALL_TYPE_VS_TX} 799 * {@link ImsCallProfile#CALL_TYPE_VS_RX} 800 * @return a {@link ImsCallProfile} object 801 * @throws ImsException if calling the IMS service results in an error 802 */ 803 public ImsCallProfile createCallProfile(int serviceId, 804 int serviceType, int callType) throws ImsException { 805 checkAndThrowExceptionIfServiceUnavailable(); 806 807 try { 808 return mImsService.createCallProfile(serviceId, serviceType, callType); 809 } catch (RemoteException e) { 810 throw new ImsException("createCallProfile()", e, 811 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 812 } 813 } 814 815 /** 816 * Creates a {@link ImsCall} to make a call. 817 * 818 * @param serviceId a service id which is obtained from {@link ImsManager#open} 819 * @param profile a call profile to make the call 820 * (it contains service type, call type, media information, etc.) 821 * @param participants participants to invite the conference call 822 * @param listener listen to the call events from {@link ImsCall} 823 * @return a {@link ImsCall} object 824 * @throws ImsException if calling the IMS service results in an error 825 */ 826 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees, 827 ImsCall.Listener listener) throws ImsException { 828 if (DBG) { 829 log("makeCall :: serviceId=" + serviceId 830 + ", profile=" + profile + ", callees=" + callees); 831 } 832 833 checkAndThrowExceptionIfServiceUnavailable(); 834 835 ImsCall call = new ImsCall(mContext, profile); 836 837 call.setListener(listener); 838 ImsCallSession session = createCallSession(serviceId, profile); 839 840 if ((callees != null) && (callees.length == 1)) { 841 call.start(session, callees[0]); 842 } else { 843 call.start(session, callees); 844 } 845 846 return call; 847 } 848 849 /** 850 * Creates a {@link ImsCall} to take an incoming call. 851 * 852 * @param serviceId a service id which is obtained from {@link ImsManager#open} 853 * @param incomingCallIntent the incoming call broadcast intent 854 * @param listener to listen to the call events from {@link ImsCall} 855 * @return a {@link ImsCall} object 856 * @throws ImsException if calling the IMS service results in an error 857 */ 858 public ImsCall takeCall(int serviceId, Intent incomingCallIntent, 859 ImsCall.Listener listener) throws ImsException { 860 if (DBG) { 861 log("takeCall :: serviceId=" + serviceId 862 + ", incomingCall=" + incomingCallIntent); 863 } 864 865 checkAndThrowExceptionIfServiceUnavailable(); 866 867 if (incomingCallIntent == null) { 868 throw new ImsException("Can't retrieve session with null intent", 869 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 870 } 871 872 int incomingServiceId = getServiceId(incomingCallIntent); 873 874 if (serviceId != incomingServiceId) { 875 throw new ImsException("Service id is mismatched in the incoming call intent", 876 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 877 } 878 879 String callId = getCallId(incomingCallIntent); 880 881 if (callId == null) { 882 throw new ImsException("Call ID missing in the incoming call intent", 883 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 884 } 885 886 try { 887 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId); 888 889 if (session == null) { 890 throw new ImsException("No pending session for the call", 891 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL); 892 } 893 894 ImsCall call = new ImsCall(mContext, session.getCallProfile()); 895 896 call.attachSession(new ImsCallSession(session)); 897 call.setListener(listener); 898 899 return call; 900 } catch (Throwable t) { 901 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED); 902 } 903 } 904 905 /** 906 * Gets the config interface to get/set service/capability parameters. 907 * 908 * @return the ImsConfig instance. 909 * @throws ImsException if getting the setting interface results in an error. 910 */ 911 public ImsConfig getConfigInterface() throws ImsException { 912 913 if (mConfig == null) { 914 checkAndThrowExceptionIfServiceUnavailable(); 915 916 try { 917 IImsConfig config = mImsService.getConfigInterface(mPhoneId); 918 if (config == null) { 919 throw new ImsException("getConfigInterface()", 920 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE); 921 } 922 mConfig = new ImsConfig(config, mContext); 923 } catch (RemoteException e) { 924 throw new ImsException("getConfigInterface()", e, 925 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 926 } 927 } 928 if (DBG) log("getConfigInterface(), mConfig= " + mConfig); 929 return mConfig; 930 } 931 932 public void setUiTTYMode(Context context, int serviceId, int uiTtyMode, Message onComplete) 933 throws ImsException { 934 935 checkAndThrowExceptionIfServiceUnavailable(); 936 937 try { 938 mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete); 939 } catch (RemoteException e) { 940 throw new ImsException("setTTYMode()", e, 941 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 942 } 943 944 if (!getBooleanCarrierConfig(context, 945 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) { 946 setAdvanced4GMode((uiTtyMode == TelecomManager.TTY_MODE_OFF) && 947 isEnhanced4gLteModeSettingEnabledByUser(context)); 948 } 949 } 950 951 /** 952 * Get the boolean config from carrier config manager. 953 * 954 * @param context the context to get carrier service 955 * @param key config key defined in CarrierConfigManager 956 * @return boolean value of corresponding key. 957 */ 958 private static boolean getBooleanCarrierConfig(Context context, String key) { 959 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService( 960 Context.CARRIER_CONFIG_SERVICE); 961 PersistableBundle b = null; 962 if (configManager != null) { 963 b = configManager.getConfig(); 964 } 965 if (b != null) { 966 return b.getBoolean(key); 967 } else { 968 // Return static default defined in CarrierConfigManager. 969 return CarrierConfigManager.getDefaultConfig().getBoolean(key); 970 } 971 } 972 973 /** 974 * Gets the call ID from the specified incoming call broadcast intent. 975 * 976 * @param incomingCallIntent the incoming call broadcast intent 977 * @return the call ID or null if the intent does not contain it 978 */ 979 private static String getCallId(Intent incomingCallIntent) { 980 if (incomingCallIntent == null) { 981 return null; 982 } 983 984 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID); 985 } 986 987 /** 988 * Gets the service type from the specified incoming call broadcast intent. 989 * 990 * @param incomingCallIntent the incoming call broadcast intent 991 * @return the service identifier or -1 if the intent does not contain it 992 */ 993 private static int getServiceId(Intent incomingCallIntent) { 994 if (incomingCallIntent == null) { 995 return (-1); 996 } 997 998 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1); 999 } 1000 1001 /** 1002 * Binds the IMS service only if the service is not created. 1003 */ 1004 private void checkAndThrowExceptionIfServiceUnavailable() 1005 throws ImsException { 1006 if (mImsService == null) { 1007 createImsService(true); 1008 1009 if (mImsService == null) { 1010 throw new ImsException("Service is unavailable", 1011 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1012 } 1013 } 1014 } 1015 1016 private static String getImsServiceName(int phoneId) { 1017 // TODO: MSIM implementation needs to decide on service name as a function of phoneId 1018 return IMS_SERVICE; 1019 } 1020 1021 /** 1022 * Binds the IMS service to make/receive the call. 1023 */ 1024 private void createImsService(boolean checkService) { 1025 if (checkService) { 1026 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId)); 1027 1028 if (binder == null) { 1029 return; 1030 } 1031 } 1032 1033 IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId)); 1034 1035 if (b != null) { 1036 try { 1037 b.linkToDeath(mDeathRecipient, 0); 1038 } catch (RemoteException e) { 1039 } 1040 } 1041 1042 mImsService = IImsService.Stub.asInterface(b); 1043 } 1044 1045 /** 1046 * Creates a {@link ImsCallSession} with the specified call profile. 1047 * Use other methods, if applicable, instead of interacting with 1048 * {@link ImsCallSession} directly. 1049 * 1050 * @param serviceId a service id which is obtained from {@link ImsManager#open} 1051 * @param profile a call profile to make the call 1052 */ 1053 private ImsCallSession createCallSession(int serviceId, 1054 ImsCallProfile profile) throws ImsException { 1055 try { 1056 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null)); 1057 } catch (RemoteException e) { 1058 return null; 1059 } 1060 } 1061 1062 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass, 1063 ImsConnectionStateListener listener) { 1064 ImsRegistrationListenerProxy proxy = 1065 new ImsRegistrationListenerProxy(serviceClass, listener); 1066 return proxy; 1067 } 1068 1069 private static void log(String s) { 1070 Rlog.d(TAG, s); 1071 } 1072 1073 private static void loge(String s) { 1074 Rlog.e(TAG, s); 1075 } 1076 1077 private static void loge(String s, Throwable t) { 1078 Rlog.e(TAG, s, t); 1079 } 1080 1081 /** 1082 * Used for turning on IMS.if its off already 1083 */ 1084 private void turnOnIms() throws ImsException { 1085 checkAndThrowExceptionIfServiceUnavailable(); 1086 1087 try { 1088 mImsService.turnOnIms(mPhoneId); 1089 } catch (RemoteException e) { 1090 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1091 } 1092 } 1093 1094 private boolean isImsTurnOffAllowed() { 1095 return getBooleanCarrierConfig(mContext, 1096 CarrierConfigManager.KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL) 1097 && (!isWfcEnabledByPlatform(mContext) 1098 || !isWfcEnabledByUser(mContext)); 1099 } 1100 1101 private void setAdvanced4GMode(boolean turnOn) throws ImsException { 1102 checkAndThrowExceptionIfServiceUnavailable(); 1103 1104 try { 1105 ImsConfig config = getConfigInterface(); 1106 if (config != null && (turnOn || !isImsTurnOffAllowed())) { 1107 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, 1108 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null); 1109 if (isVtEnabledByPlatform(mContext)) { 1110 // TODO: once VT is available on platform: 1111 // - replace the '1' with the current user configuration of VT. 1112 // - separate exception checks for setFeatureValue() failures for VoLTE and VT. 1113 // I.e. if VoLTE fails still try to configure VT. 1114 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE, 1115 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null); 1116 } 1117 } 1118 } catch (ImsException e) { 1119 log("setAdvanced4GMode() : " + e); 1120 } 1121 if (turnOn) { 1122 turnOnIms(); 1123 } else if (isImsTurnOffAllowed()) { 1124 log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms"); 1125 turnOffIms(); 1126 } 1127 } 1128 1129 /** 1130 * Used for turning off IMS completely in order to make the device CSFB'ed. 1131 * Once turned off, all calls will be over CS. 1132 */ 1133 private void turnOffIms() throws ImsException { 1134 checkAndThrowExceptionIfServiceUnavailable(); 1135 1136 try { 1137 mImsService.turnOffIms(mPhoneId); 1138 } catch (RemoteException e) { 1139 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1140 } 1141 } 1142 1143 /** 1144 * Death recipient class for monitoring IMS service. 1145 */ 1146 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient { 1147 @Override 1148 public void binderDied() { 1149 mImsService = null; 1150 mUt = null; 1151 mConfig = null; 1152 mEcbm = null; 1153 1154 if (mContext != null) { 1155 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN); 1156 intent.putExtra(EXTRA_PHONE_ID, mPhoneId); 1157 mContext.sendBroadcast(new Intent(intent)); 1158 } 1159 } 1160 } 1161 1162 /** 1163 * Adapter class for {@link IImsRegistrationListener}. 1164 */ 1165 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub { 1166 private int mServiceClass; 1167 private ImsConnectionStateListener mListener; 1168 1169 public ImsRegistrationListenerProxy(int serviceClass, 1170 ImsConnectionStateListener listener) { 1171 mServiceClass = serviceClass; 1172 mListener = listener; 1173 } 1174 1175 public boolean isSameProxy(int serviceClass) { 1176 return (mServiceClass == serviceClass); 1177 } 1178 1179 @Override 1180 public void registrationConnected() { 1181 if (DBG) { 1182 log("registrationConnected ::"); 1183 } 1184 1185 if (mListener != null) { 1186 mListener.onImsConnected(); 1187 } 1188 } 1189 1190 @Override 1191 public void registrationProgressing() { 1192 if (DBG) { 1193 log("registrationProgressing ::"); 1194 } 1195 1196 if (mListener != null) { 1197 mListener.onImsProgressing(); 1198 } 1199 } 1200 1201 @Override 1202 public void registrationDisconnected(ImsReasonInfo imsReasonInfo) { 1203 if (DBG) { 1204 log("registrationDisconnected :: imsReasonInfo" + imsReasonInfo); 1205 } 1206 1207 if (mListener != null) { 1208 mListener.onImsDisconnected(imsReasonInfo); 1209 } 1210 } 1211 1212 @Override 1213 public void registrationResumed() { 1214 if (DBG) { 1215 log("registrationResumed ::"); 1216 } 1217 1218 if (mListener != null) { 1219 mListener.onImsResumed(); 1220 } 1221 } 1222 1223 @Override 1224 public void registrationSuspended() { 1225 if (DBG) { 1226 log("registrationSuspended ::"); 1227 } 1228 1229 if (mListener != null) { 1230 mListener.onImsSuspended(); 1231 } 1232 } 1233 1234 @Override 1235 public void registrationServiceCapabilityChanged(int serviceClass, int event) { 1236 log("registrationServiceCapabilityChanged :: serviceClass=" + 1237 serviceClass + ", event=" + event); 1238 1239 if (mListener != null) { 1240 mListener.onImsConnected(); 1241 } 1242 } 1243 1244 @Override 1245 public void registrationFeatureCapabilityChanged(int serviceClass, 1246 int[] enabledFeatures, int[] disabledFeatures) { 1247 log("registrationFeatureCapabilityChanged :: serviceClass=" + 1248 serviceClass); 1249 if (mListener != null) { 1250 mListener.onFeatureCapabilityChanged(serviceClass, 1251 enabledFeatures, disabledFeatures); 1252 } 1253 } 1254 1255 @Override 1256 public void voiceMessageCountUpdate(int count) { 1257 log("voiceMessageCountUpdate :: count=" + count); 1258 1259 if (mListener != null) { 1260 mListener.onVoiceMessageCountChanged(count); 1261 } 1262 } 1263 1264 } 1265 /** 1266 * Gets the ECBM interface to request ECBM exit. 1267 * 1268 * @param serviceId a service id which is obtained from {@link ImsManager#open} 1269 * @return the ECBM interface instance 1270 * @throws ImsException if getting the ECBM interface results in an error 1271 */ 1272 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException { 1273 if (mEcbm == null) { 1274 checkAndThrowExceptionIfServiceUnavailable(); 1275 1276 try { 1277 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId); 1278 1279 if (iEcbm == null) { 1280 throw new ImsException("getEcbmInterface()", 1281 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED); 1282 } 1283 mEcbm = new ImsEcbm(iEcbm); 1284 } catch (RemoteException e) { 1285 throw new ImsException("getEcbmInterface()", e, 1286 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1287 } 1288 } 1289 return mEcbm; 1290 } 1291 1292 /** 1293 * Resets ImsManager settings back to factory defaults. 1294 * 1295 * @hide 1296 */ 1297 public static void factoryReset(Context context) { 1298 // Set VoLTE to default 1299 android.provider.Settings.Global.putInt(context.getContentResolver(), 1300 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, 1301 ImsConfig.FeatureValueConstants.ON); 1302 1303 // Set VoWiFi to default 1304 android.provider.Settings.Global.putInt(context.getContentResolver(), 1305 android.provider.Settings.Global.WFC_IMS_ENABLED, 1306 ImsConfig.FeatureValueConstants.OFF); 1307 1308 // Set VoWiFi mode to default 1309 android.provider.Settings.Global.putInt(context.getContentResolver(), 1310 android.provider.Settings.Global.WFC_IMS_MODE, 1311 ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED); 1312 1313 // Set VoWiFi roaming to default 1314 android.provider.Settings.Global.putInt(context.getContentResolver(), 1315 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED, 1316 ImsConfig.FeatureValueConstants.OFF); 1317 1318 // Set VT to default 1319 SharedPreferences sharedPrefs = 1320 PreferenceManager.getDefaultSharedPreferences(context); 1321 SharedPreferences.Editor editor = sharedPrefs.edit(); 1322 editor.putBoolean(PREF_ENABLE_VIDEO_CALLING_KEY, true); 1323 editor.commit(); 1324 1325 // Push settings to ImsConfig 1326 ImsManager.updateImsServiceConfig(context, 1327 SubscriptionManager.getDefaultVoicePhoneId(), true); 1328 } 1329} 1330