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