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