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