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