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