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