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