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 modem 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 * Returns the user configuration of WFC modem 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 private static void setWfcModeInternal(Context context, int wfcMode) { 481 final ImsManager imsManager = ImsManager.getInstance(context, 482 SubscriptionManager.getDefaultVoicePhoneId()); 483 if (imsManager != null) { 484 final int value = wfcMode; 485 Thread thread = new Thread(new Runnable() { 486 public void run() { 487 try { 488 imsManager.getConfigInterface().setProvisionedValue( 489 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE, 490 value); 491 } catch (ImsException e) { 492 // do nothing 493 } 494 } 495 }); 496 thread.start(); 497 } 498 } 499 500 /** 501 * Returns the user configuration of WFC roaming setting 502 */ 503 public static boolean isWfcRoamingEnabledByUser(Context context) { 504 int enabled = android.provider.Settings.Global.getInt(context.getContentResolver(), 505 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED, 506 getBooleanCarrierConfig(context, 507 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL) ? 508 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF); 509 return (enabled == 1) ? true : false; 510 } 511 512 /** 513 * Change persistent WFC roaming enabled setting 514 */ 515 public static void setWfcRoamingSetting(Context context, boolean enabled) { 516 android.provider.Settings.Global.putInt(context.getContentResolver(), 517 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED, 518 enabled ? ImsConfig.FeatureValueConstants.ON 519 : ImsConfig.FeatureValueConstants.OFF); 520 521 setWfcRoamingSettingInternal(context, enabled); 522 } 523 524 private static void setWfcRoamingSettingInternal(Context context, boolean enabled) { 525 final ImsManager imsManager = ImsManager.getInstance(context, 526 SubscriptionManager.getDefaultVoicePhoneId()); 527 if (imsManager != null) { 528 final int value = enabled 529 ? ImsConfig.FeatureValueConstants.ON 530 : ImsConfig.FeatureValueConstants.OFF; 531 Thread thread = new Thread(new Runnable() { 532 public void run() { 533 try { 534 imsManager.getConfigInterface().setProvisionedValue( 535 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_ROAMING, 536 value); 537 } catch (ImsException e) { 538 // do nothing 539 } 540 } 541 }); 542 thread.start(); 543 } 544 } 545 546 /** 547 * Returns a platform configuration for WFC which may override the user 548 * setting. Note: WFC presumes that VoLTE is enabled (these are 549 * configuration settings which must be done correctly). 550 */ 551 public static boolean isWfcEnabledByPlatform(Context context) { 552 if (SystemProperties.getInt(PROPERTY_DBG_WFC_AVAIL_OVERRIDE, 553 PROPERTY_DBG_WFC_AVAIL_OVERRIDE_DEFAULT) == 1) { 554 return true; 555 } 556 557 return 558 context.getResources().getBoolean( 559 com.android.internal.R.bool.config_device_wfc_ims_available) && 560 getBooleanCarrierConfig(context, 561 CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL) && 562 isGbaValid(context); 563 } 564 565 /** 566 * If carrier requires that IMS is only available if GBA capable SIM is used, 567 * then this function checks GBA bit in EF IST. 568 * 569 * Format of EF IST is defined in 3GPP TS 31.103 (Section 4.2.7). 570 */ 571 private static boolean isGbaValid(Context context) { 572 if (getBooleanCarrierConfig(context, 573 CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) { 574 final TelephonyManager telephonyManager = TelephonyManager.getDefault(); 575 String efIst = telephonyManager.getIsimIst(); 576 if (efIst == null) { 577 loge("ISF is NULL"); 578 return true; 579 } 580 boolean result = efIst != null && efIst.length() > 1 && 581 (0x02 & (byte)efIst.charAt(1)) != 0; 582 if (DBG) log("GBA capable=" + result + ", ISF=" + efIst); 583 return result; 584 } 585 return true; 586 } 587 588 /** 589 * This function should be called when ImsConfig.ACTION_IMS_CONFIG_CHANGED is received. 590 * 591 * We cannot register receiver in ImsManager because this would lead to resource leak. 592 * ImsManager can be created in different processes and it is not notified when that process 593 * is about to be terminated. 594 * 595 * @hide 596 * */ 597 public static void onProvisionedValueChanged(Context context, int item, String value) { 598 if (DBG) Rlog.d(TAG, "onProvisionedValueChanged: item=" + item + " val=" + value); 599 ImsManager mgr = ImsManager.getInstance(context, 600 SubscriptionManager.getDefaultVoicePhoneId()); 601 602 switch (item) { 603 case ImsConfig.ConfigConstants.VLT_SETTING_ENABLED: 604 mgr.setVolteProvisionedProperty(value.equals("1")); 605 if (DBG) Rlog.d(TAG,"isVoLteProvisioned = " + mgr.isVolteProvisioned()); 606 break; 607 608 case ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED: 609 mgr.setWfcProvisionedProperty(value.equals("1")); 610 if (DBG) Rlog.d(TAG,"isWfcProvisioned = " + mgr.isWfcProvisioned()); 611 break; 612 613 case ImsConfig.ConfigConstants.LVC_SETTING_ENABLED: 614 mgr.setVtProvisionedProperty(value.equals("1")); 615 if (DBG) Rlog.d(TAG,"isVtProvisioned = " + mgr.isVtProvisioned()); 616 break; 617 618 } 619 } 620 621 private class AsyncUpdateProvisionedValues extends AsyncTask<Void, Void, Void> { 622 @Override 623 protected Void doInBackground(Void... params) { 624 // disable on any error 625 setVolteProvisionedProperty(false); 626 setWfcProvisionedProperty(false); 627 setVtProvisionedProperty(false); 628 629 try { 630 ImsConfig config = getConfigInterface(); 631 if (config != null) { 632 setVolteProvisionedProperty(getProvisionedBool(config, 633 ImsConfig.ConfigConstants.VLT_SETTING_ENABLED)); 634 if (DBG) Rlog.d(TAG, "isVoLteProvisioned = " + isVolteProvisioned()); 635 636 setWfcProvisionedProperty(getProvisionedBool(config, 637 ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED)); 638 if (DBG) Rlog.d(TAG, "isWfcProvisioned = " + isWfcProvisioned()); 639 640 setVtProvisionedProperty(getProvisionedBool(config, 641 ImsConfig.ConfigConstants.LVC_SETTING_ENABLED)); 642 if (DBG) Rlog.d(TAG, "isVtProvisioned = " + isVtProvisioned()); 643 644 } 645 } catch (ImsException ie) { 646 Rlog.e(TAG, "AsyncUpdateProvisionedValues error: ", ie); 647 } 648 649 return null; 650 } 651 652 private boolean getProvisionedBool(ImsConfig config, int item) throws ImsException { 653 return config.getProvisionedValue(item) == ImsConfig.FeatureValueConstants.ON; 654 } 655 } 656 657 /** Asynchronously get VoLTE, WFC, VT provisioning statuses */ 658 private void updateProvisionedValues() { 659 if (getBooleanCarrierConfig(mContext, 660 CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL)) { 661 662 new AsyncUpdateProvisionedValues().execute(); 663 } 664 } 665 666 /** 667 * Sync carrier config and user settings with ImsConfig. 668 * 669 * @param context for the manager object 670 * @param phoneId phone id 671 * @param force update 672 */ 673 public static void updateImsServiceConfig(Context context, int phoneId, boolean force) { 674 if (!force) { 675 if (TelephonyManager.getDefault().getSimState() != TelephonyManager.SIM_STATE_READY) { 676 log("updateImsServiceConfig: SIM not ready"); 677 // Don't disable IMS if SIM is not ready 678 return; 679 } 680 } 681 682 final ImsManager imsManager = ImsManager.getInstance(context, phoneId); 683 if (imsManager != null && (!imsManager.mConfigUpdated || force)) { 684 try { 685 imsManager.updateProvisionedValues(); 686 687 // TODO: Extend ImsConfig API and set all feature values in single function call. 688 689 // Note: currently the order of updates is set to produce different order of 690 // setFeatureValue() function calls from setAdvanced4GMode(). This is done to 691 // differentiate this code path from vendor code perspective. 692 boolean isImsUsed = imsManager.updateVolteFeatureValue(); 693 isImsUsed |= imsManager.updateWfcFeatureAndProvisionedValues(); 694 isImsUsed |= imsManager.updateVideoCallFeatureValue(); 695 696 if (isImsUsed || !isTurnOffImsAllowedByPlatform(context)) { 697 // Turn on IMS if it is used. 698 // Also, if turning off is not allowed for current carrier, 699 // we need to turn IMS on because it might be turned off before 700 // phone switched to current carrier. 701 log("updateImsServiceConfig: turnOnIms"); 702 imsManager.turnOnIms(); 703 } else { 704 // Turn off IMS if it is not used AND turning off is allowed for carrier. 705 log("updateImsServiceConfig: turnOffIms"); 706 imsManager.turnOffIms(); 707 } 708 709 imsManager.mConfigUpdated = true; 710 } catch (ImsException e) { 711 loge("updateImsServiceConfig: ", e); 712 imsManager.mConfigUpdated = false; 713 } 714 } 715 } 716 717 /** 718 * Update VoLTE config 719 * @return whether feature is On 720 * @throws ImsException 721 */ 722 private boolean updateVolteFeatureValue() throws ImsException { 723 boolean available = isVolteEnabledByPlatform(mContext); 724 boolean enabled = isEnhanced4gLteModeSettingEnabledByUser(mContext); 725 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext); 726 boolean isFeatureOn = available && enabled && isNonTty; 727 728 log("updateVolteFeatureValue: available = " + available 729 + ", enabled = " + enabled 730 + ", nonTTY = " + isNonTty); 731 732 getConfigInterface().setFeatureValue( 733 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, 734 TelephonyManager.NETWORK_TYPE_LTE, 735 isFeatureOn ? 736 ImsConfig.FeatureValueConstants.ON : 737 ImsConfig.FeatureValueConstants.OFF, 738 mImsConfigListener); 739 740 return isFeatureOn; 741 } 742 743 /** 744 * Update video call over LTE config 745 * @return whether feature is On 746 * @throws ImsException 747 */ 748 private boolean updateVideoCallFeatureValue() throws ImsException { 749 boolean available = isVtEnabledByPlatform(mContext); 750 boolean enabled = isVtEnabledByUser(mContext); 751 boolean isNonTty = isNonTtyOrTtyOnVolteEnabled(mContext); 752 boolean isDataEnabled = isDataEnabled(); 753 754 boolean isFeatureOn = available && enabled && isNonTty && isDataEnabled; 755 756 log("updateVideoCallFeatureValue: available = " + available 757 + ", enabled = " + enabled 758 + ", nonTTY = " + isNonTty 759 + ", data enabled = " + isDataEnabled); 760 761 getConfigInterface().setFeatureValue( 762 ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE, 763 TelephonyManager.NETWORK_TYPE_LTE, 764 isFeatureOn ? 765 ImsConfig.FeatureValueConstants.ON : 766 ImsConfig.FeatureValueConstants.OFF, 767 mImsConfigListener); 768 769 return isFeatureOn; 770 } 771 772 /** 773 * Update WFC config 774 * @return whether feature is On 775 * @throws ImsException 776 */ 777 private boolean updateWfcFeatureAndProvisionedValues() throws ImsException { 778 boolean available = isWfcEnabledByPlatform(mContext); 779 boolean enabled = isWfcEnabledByUser(mContext); 780 int mode = getWfcMode(mContext); 781 boolean roaming = isWfcRoamingEnabledByUser(mContext); 782 boolean isFeatureOn = available && enabled; 783 784 log("updateWfcFeatureAndProvisionedValues: available = " + available 785 + ", enabled = " + enabled 786 + ", mode = " + mode 787 + ", roaming = " + roaming); 788 789 getConfigInterface().setFeatureValue( 790 ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI, 791 TelephonyManager.NETWORK_TYPE_IWLAN, 792 isFeatureOn ? 793 ImsConfig.FeatureValueConstants.ON : 794 ImsConfig.FeatureValueConstants.OFF, 795 mImsConfigListener); 796 797 if (!isFeatureOn) { 798 mode = ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED; 799 roaming = false; 800 } 801 setWfcModeInternal(mContext, mode); 802 setWfcRoamingSettingInternal(mContext, roaming); 803 804 return isFeatureOn; 805 } 806 807 private ImsManager(Context context, int phoneId) { 808 mContext = context; 809 mPhoneId = phoneId; 810 createImsService(true); 811 } 812 813 /* 814 * Returns a flag indicating whether the IMS service is available. 815 */ 816 public boolean isServiceAvailable() { 817 if (mImsService != null) { 818 return true; 819 } 820 821 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId)); 822 if (binder != null) { 823 return true; 824 } 825 826 return false; 827 } 828 829 public void setImsConfigListener(ImsConfigListener listener) { 830 mImsConfigListener = listener; 831 } 832 833 /** 834 * Opens the IMS service for making calls and/or receiving generic IMS calls. 835 * The caller may make subsquent calls through {@link #makeCall}. 836 * The IMS service will register the device to the operator's network with the credentials 837 * (from ISIM) periodically in order to receive calls from the operator's network. 838 * When the IMS service receives a new call, it will send out an intent with 839 * the provided action string. 840 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call. 841 * 842 * @param serviceClass a service class specified in {@link ImsServiceClass} 843 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}. 844 * @param incomingCallPendingIntent When an incoming call is received, 845 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to 846 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE} 847 * as the result code and the intent to fill in the call ID; It cannot be null 848 * @param listener To listen to IMS registration events; It cannot be null 849 * @return identifier (greater than 0) for the specified service 850 * @throws NullPointerException if {@code incomingCallPendingIntent} 851 * or {@code listener} is null 852 * @throws ImsException if calling the IMS service results in an error 853 * @see #getCallId 854 * @see #getServiceId 855 */ 856 public int open(int serviceClass, PendingIntent incomingCallPendingIntent, 857 ImsConnectionStateListener listener) throws ImsException { 858 checkAndThrowExceptionIfServiceUnavailable(); 859 860 if (incomingCallPendingIntent == null) { 861 throw new NullPointerException("incomingCallPendingIntent can't be null"); 862 } 863 864 if (listener == null) { 865 throw new NullPointerException("listener can't be null"); 866 } 867 868 int result = 0; 869 870 try { 871 result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent, 872 createRegistrationListenerProxy(serviceClass, listener)); 873 } catch (RemoteException e) { 874 throw new ImsException("open()", e, 875 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 876 } 877 878 if (result <= 0) { 879 // If the return value is a minus value, 880 // it means that an error occurred in the service. 881 // So, it needs to convert to the reason code specified in ImsReasonInfo. 882 throw new ImsException("open()", (result * (-1))); 883 } 884 885 return result; 886 } 887 888 /** 889 * Adds registration listener to the IMS service. 890 * 891 * @param serviceClass a service class specified in {@link ImsServiceClass} 892 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}. 893 * @param listener To listen to IMS registration events; It cannot be null 894 * @throws NullPointerException if {@code listener} is null 895 * @throws ImsException if calling the IMS service results in an error 896 */ 897 public void addRegistrationListener(int serviceClass, ImsConnectionStateListener listener) 898 throws ImsException { 899 checkAndThrowExceptionIfServiceUnavailable(); 900 901 if (listener == null) { 902 throw new NullPointerException("listener can't be null"); 903 } 904 905 try { 906 mImsService.addRegistrationListener(mPhoneId, serviceClass, 907 createRegistrationListenerProxy(serviceClass, listener)); 908 } catch (RemoteException e) { 909 throw new ImsException("addRegistrationListener()", e, 910 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 911 } 912 } 913 914 /** 915 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls. 916 * All the resources that were allocated to the service are also released. 917 * 918 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open} 919 * @throws ImsException if calling the IMS service results in an error 920 */ 921 public void close(int serviceId) throws ImsException { 922 checkAndThrowExceptionIfServiceUnavailable(); 923 924 try { 925 mImsService.close(serviceId); 926 } catch (RemoteException e) { 927 throw new ImsException("close()", e, 928 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 929 } finally { 930 mUt = null; 931 mConfig = null; 932 mEcbm = null; 933 mMultiEndpoint = null; 934 } 935 } 936 937 /** 938 * Gets the configuration interface to provision / withdraw the supplementary service settings. 939 * 940 * @param serviceId a service id which is obtained from {@link ImsManager#open} 941 * @return the Ut interface instance 942 * @throws ImsException if getting the Ut interface results in an error 943 */ 944 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId) 945 throws ImsException { 946 // FIXME: manage the multiple Ut interfaces based on the service id 947 if (mUt == null) { 948 checkAndThrowExceptionIfServiceUnavailable(); 949 950 try { 951 IImsUt iUt = mImsService.getUtInterface(serviceId); 952 953 if (iUt == null) { 954 throw new ImsException("getSupplementaryServiceConfiguration()", 955 ImsReasonInfo.CODE_UT_NOT_SUPPORTED); 956 } 957 958 mUt = new ImsUt(iUt); 959 } catch (RemoteException e) { 960 throw new ImsException("getSupplementaryServiceConfiguration()", e, 961 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 962 } 963 } 964 965 return mUt; 966 } 967 968 /** 969 * Checks if the IMS service has successfully registered to the IMS network 970 * with the specified service & call type. 971 * 972 * @param serviceId a service id which is obtained from {@link ImsManager#open} 973 * @param serviceType a service type that is specified in {@link ImsCallProfile} 974 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 975 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 976 * @param callType a call type that is specified in {@link ImsCallProfile} 977 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO} 978 * {@link ImsCallProfile#CALL_TYPE_VOICE} 979 * {@link ImsCallProfile#CALL_TYPE_VT} 980 * {@link ImsCallProfile#CALL_TYPE_VS} 981 * @return true if the specified service id is connected to the IMS network; 982 * false otherwise 983 * @throws ImsException if calling the IMS service results in an error 984 */ 985 public boolean isConnected(int serviceId, int serviceType, int callType) 986 throws ImsException { 987 checkAndThrowExceptionIfServiceUnavailable(); 988 989 try { 990 return mImsService.isConnected(serviceId, serviceType, callType); 991 } catch (RemoteException e) { 992 throw new ImsException("isServiceConnected()", e, 993 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 994 } 995 } 996 997 /** 998 * Checks if the specified IMS service is opend. 999 * 1000 * @param serviceId a service id which is obtained from {@link ImsManager#open} 1001 * @return true if the specified service id is opened; false otherwise 1002 * @throws ImsException if calling the IMS service results in an error 1003 */ 1004 public boolean isOpened(int serviceId) throws ImsException { 1005 checkAndThrowExceptionIfServiceUnavailable(); 1006 1007 try { 1008 return mImsService.isOpened(serviceId); 1009 } catch (RemoteException e) { 1010 throw new ImsException("isOpened()", e, 1011 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1012 } 1013 } 1014 1015 /** 1016 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state. 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_NONE} 1021 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 1022 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 1023 * @param callType a call type that is specified in {@link ImsCallProfile} 1024 * {@link ImsCallProfile#CALL_TYPE_VOICE} 1025 * {@link ImsCallProfile#CALL_TYPE_VT} 1026 * {@link ImsCallProfile#CALL_TYPE_VT_TX} 1027 * {@link ImsCallProfile#CALL_TYPE_VT_RX} 1028 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR} 1029 * {@link ImsCallProfile#CALL_TYPE_VS} 1030 * {@link ImsCallProfile#CALL_TYPE_VS_TX} 1031 * {@link ImsCallProfile#CALL_TYPE_VS_RX} 1032 * @return a {@link ImsCallProfile} object 1033 * @throws ImsException if calling the IMS service results in an error 1034 */ 1035 public ImsCallProfile createCallProfile(int serviceId, 1036 int serviceType, int callType) throws ImsException { 1037 checkAndThrowExceptionIfServiceUnavailable(); 1038 1039 try { 1040 return mImsService.createCallProfile(serviceId, serviceType, callType); 1041 } catch (RemoteException e) { 1042 throw new ImsException("createCallProfile()", e, 1043 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1044 } 1045 } 1046 1047 /** 1048 * Creates a {@link ImsCall} to make a call. 1049 * 1050 * @param serviceId a service id which is obtained from {@link ImsManager#open} 1051 * @param profile a call profile to make the call 1052 * (it contains service type, call type, media information, etc.) 1053 * @param participants participants to invite the conference call 1054 * @param listener listen to the call events from {@link ImsCall} 1055 * @return a {@link ImsCall} object 1056 * @throws ImsException if calling the IMS service results in an error 1057 */ 1058 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees, 1059 ImsCall.Listener listener) throws ImsException { 1060 if (DBG) { 1061 log("makeCall :: serviceId=" + serviceId 1062 + ", profile=" + profile); 1063 } 1064 1065 checkAndThrowExceptionIfServiceUnavailable(); 1066 1067 ImsCall call = new ImsCall(mContext, profile); 1068 1069 call.setListener(listener); 1070 ImsCallSession session = createCallSession(serviceId, profile); 1071 1072 if ((callees != null) && (callees.length == 1)) { 1073 call.start(session, callees[0]); 1074 } else { 1075 call.start(session, callees); 1076 } 1077 1078 return call; 1079 } 1080 1081 /** 1082 * Creates a {@link ImsCall} to take an incoming call. 1083 * 1084 * @param serviceId a service id which is obtained from {@link ImsManager#open} 1085 * @param incomingCallIntent the incoming call broadcast intent 1086 * @param listener to listen to the call events from {@link ImsCall} 1087 * @return a {@link ImsCall} object 1088 * @throws ImsException if calling the IMS service results in an error 1089 */ 1090 public ImsCall takeCall(int serviceId, Intent incomingCallIntent, 1091 ImsCall.Listener listener) throws ImsException { 1092 if (DBG) { 1093 log("takeCall :: serviceId=" + serviceId 1094 + ", incomingCall=" + incomingCallIntent); 1095 } 1096 1097 checkAndThrowExceptionIfServiceUnavailable(); 1098 1099 if (incomingCallIntent == null) { 1100 throw new ImsException("Can't retrieve session with null intent", 1101 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 1102 } 1103 1104 int incomingServiceId = getServiceId(incomingCallIntent); 1105 1106 if (serviceId != incomingServiceId) { 1107 throw new ImsException("Service id is mismatched in the incoming call intent", 1108 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 1109 } 1110 1111 String callId = getCallId(incomingCallIntent); 1112 1113 if (callId == null) { 1114 throw new ImsException("Call ID missing in the incoming call intent", 1115 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 1116 } 1117 1118 try { 1119 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId); 1120 1121 if (session == null) { 1122 throw new ImsException("No pending session for the call", 1123 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL); 1124 } 1125 1126 ImsCall call = new ImsCall(mContext, session.getCallProfile()); 1127 1128 call.attachSession(new ImsCallSession(session)); 1129 call.setListener(listener); 1130 1131 return call; 1132 } catch (Throwable t) { 1133 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED); 1134 } 1135 } 1136 1137 /** 1138 * Gets the config interface to get/set service/capability parameters. 1139 * 1140 * @return the ImsConfig instance. 1141 * @throws ImsException if getting the setting interface results in an error. 1142 */ 1143 public ImsConfig getConfigInterface() throws ImsException { 1144 1145 if (mConfig == null) { 1146 checkAndThrowExceptionIfServiceUnavailable(); 1147 1148 try { 1149 IImsConfig config = mImsService.getConfigInterface(mPhoneId); 1150 if (config == null) { 1151 throw new ImsException("getConfigInterface()", 1152 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE); 1153 } 1154 mConfig = new ImsConfig(config, mContext); 1155 } catch (RemoteException e) { 1156 throw new ImsException("getConfigInterface()", e, 1157 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1158 } 1159 } 1160 if (DBG) log("getConfigInterface(), mConfig= " + mConfig); 1161 return mConfig; 1162 } 1163 1164 public void setUiTTYMode(Context context, int serviceId, int uiTtyMode, Message onComplete) 1165 throws ImsException { 1166 1167 checkAndThrowExceptionIfServiceUnavailable(); 1168 1169 try { 1170 mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete); 1171 } catch (RemoteException e) { 1172 throw new ImsException("setTTYMode()", e, 1173 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1174 } 1175 1176 if (!getBooleanCarrierConfig(context, 1177 CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) { 1178 setAdvanced4GMode((uiTtyMode == TelecomManager.TTY_MODE_OFF) && 1179 isEnhanced4gLteModeSettingEnabledByUser(context)); 1180 } 1181 } 1182 1183 /** 1184 * Get the boolean config from carrier config manager. 1185 * 1186 * @param context the context to get carrier service 1187 * @param key config key defined in CarrierConfigManager 1188 * @return boolean value of corresponding key. 1189 */ 1190 private static boolean getBooleanCarrierConfig(Context context, String key) { 1191 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService( 1192 Context.CARRIER_CONFIG_SERVICE); 1193 PersistableBundle b = null; 1194 if (configManager != null) { 1195 b = configManager.getConfig(); 1196 } 1197 if (b != null) { 1198 return b.getBoolean(key); 1199 } else { 1200 // Return static default defined in CarrierConfigManager. 1201 return CarrierConfigManager.getDefaultConfig().getBoolean(key); 1202 } 1203 } 1204 1205 /** 1206 * Get the int config from carrier config manager. 1207 * 1208 * @param context the context to get carrier service 1209 * @param key config key defined in CarrierConfigManager 1210 * @return integer value of corresponding key. 1211 */ 1212 private static int getIntCarrierConfig(Context context, String key) { 1213 CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService( 1214 Context.CARRIER_CONFIG_SERVICE); 1215 PersistableBundle b = null; 1216 if (configManager != null) { 1217 b = configManager.getConfig(); 1218 } 1219 if (b != null) { 1220 return b.getInt(key); 1221 } else { 1222 // Return static default defined in CarrierConfigManager. 1223 return CarrierConfigManager.getDefaultConfig().getInt(key); 1224 } 1225 } 1226 1227 /** 1228 * Gets the call ID from the specified incoming call broadcast intent. 1229 * 1230 * @param incomingCallIntent the incoming call broadcast intent 1231 * @return the call ID or null if the intent does not contain it 1232 */ 1233 private static String getCallId(Intent incomingCallIntent) { 1234 if (incomingCallIntent == null) { 1235 return null; 1236 } 1237 1238 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID); 1239 } 1240 1241 /** 1242 * Gets the service type from the specified incoming call broadcast intent. 1243 * 1244 * @param incomingCallIntent the incoming call broadcast intent 1245 * @return the service identifier or -1 if the intent does not contain it 1246 */ 1247 private static int getServiceId(Intent incomingCallIntent) { 1248 if (incomingCallIntent == null) { 1249 return (-1); 1250 } 1251 1252 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1); 1253 } 1254 1255 /** 1256 * Binds the IMS service only if the service is not created. 1257 */ 1258 private void checkAndThrowExceptionIfServiceUnavailable() 1259 throws ImsException { 1260 if (mImsService == null) { 1261 createImsService(true); 1262 1263 if (mImsService == null) { 1264 throw new ImsException("Service is unavailable", 1265 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1266 } 1267 } 1268 } 1269 1270 private static String getImsServiceName(int phoneId) { 1271 // TODO: MSIM implementation needs to decide on service name as a function of phoneId 1272 return IMS_SERVICE; 1273 } 1274 1275 /** 1276 * Binds the IMS service to make/receive the call. 1277 */ 1278 private void createImsService(boolean checkService) { 1279 if (checkService) { 1280 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId)); 1281 1282 if (binder == null) { 1283 return; 1284 } 1285 } 1286 1287 IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId)); 1288 1289 if (b != null) { 1290 try { 1291 b.linkToDeath(mDeathRecipient, 0); 1292 } catch (RemoteException e) { 1293 } 1294 } 1295 1296 mImsService = IImsService.Stub.asInterface(b); 1297 } 1298 1299 /** 1300 * Creates a {@link ImsCallSession} with the specified call profile. 1301 * Use other methods, if applicable, instead of interacting with 1302 * {@link ImsCallSession} directly. 1303 * 1304 * @param serviceId a service id which is obtained from {@link ImsManager#open} 1305 * @param profile a call profile to make the call 1306 */ 1307 private ImsCallSession createCallSession(int serviceId, 1308 ImsCallProfile profile) throws ImsException { 1309 try { 1310 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null)); 1311 } catch (RemoteException e) { 1312 return null; 1313 } 1314 } 1315 1316 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass, 1317 ImsConnectionStateListener listener) { 1318 ImsRegistrationListenerProxy proxy = 1319 new ImsRegistrationListenerProxy(serviceClass, listener); 1320 return proxy; 1321 } 1322 1323 private static void log(String s) { 1324 Rlog.d(TAG, s); 1325 } 1326 1327 private static void loge(String s) { 1328 Rlog.e(TAG, s); 1329 } 1330 1331 private static void loge(String s, Throwable t) { 1332 Rlog.e(TAG, s, t); 1333 } 1334 1335 /** 1336 * Used for turning on IMS.if its off already 1337 */ 1338 private void turnOnIms() throws ImsException { 1339 checkAndThrowExceptionIfServiceUnavailable(); 1340 1341 try { 1342 mImsService.turnOnIms(mPhoneId); 1343 } catch (RemoteException e) { 1344 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1345 } 1346 } 1347 1348 private boolean isImsTurnOffAllowed() { 1349 return isTurnOffImsAllowedByPlatform(mContext) 1350 && (!isWfcEnabledByPlatform(mContext) 1351 || !isWfcEnabledByUser(mContext)); 1352 } 1353 1354 private void setLteFeatureValues(boolean turnOn) { 1355 log("setLteFeatureValues: " + turnOn); 1356 try { 1357 ImsConfig config = getConfigInterface(); 1358 if (config != null) { 1359 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, 1360 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, mImsConfigListener); 1361 1362 if (isVtEnabledByPlatform(mContext)) { 1363 boolean enableViLte = turnOn && isVtEnabledByUser(mContext) && 1364 isDataEnabled(); 1365 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE, 1366 TelephonyManager.NETWORK_TYPE_LTE, 1367 enableViLte ? 1 : 0, 1368 mImsConfigListener); 1369 } 1370 } 1371 } catch (ImsException e) { 1372 loge("setLteFeatureValues: exception ", e); 1373 } 1374 } 1375 1376 private void setAdvanced4GMode(boolean turnOn) throws ImsException { 1377 checkAndThrowExceptionIfServiceUnavailable(); 1378 1379 // if turnOn: first set feature values then call turnOnIms() 1380 // if turnOff: only set feature values if IMS turn off is not allowed. If turn off is 1381 // allowed, first call turnOffIms() then set feature values 1382 if (turnOn) { 1383 setLteFeatureValues(turnOn); 1384 log("setAdvanced4GMode: turnOnIms"); 1385 turnOnIms(); 1386 } else { 1387 if (isImsTurnOffAllowed()) { 1388 log("setAdvanced4GMode: turnOffIms"); 1389 turnOffIms(); 1390 } 1391 setLteFeatureValues(turnOn); 1392 } 1393 } 1394 1395 /** 1396 * Used for turning off IMS completely in order to make the device CSFB'ed. 1397 * Once turned off, all calls will be over CS. 1398 */ 1399 private void turnOffIms() throws ImsException { 1400 checkAndThrowExceptionIfServiceUnavailable(); 1401 1402 try { 1403 mImsService.turnOffIms(mPhoneId); 1404 } catch (RemoteException e) { 1405 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1406 } 1407 } 1408 1409 /** 1410 * Death recipient class for monitoring IMS service. 1411 */ 1412 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient { 1413 @Override 1414 public void binderDied() { 1415 mImsService = null; 1416 mUt = null; 1417 mConfig = null; 1418 mEcbm = null; 1419 mMultiEndpoint = null; 1420 1421 if (mContext != null) { 1422 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN); 1423 intent.putExtra(EXTRA_PHONE_ID, mPhoneId); 1424 mContext.sendBroadcast(new Intent(intent)); 1425 } 1426 } 1427 } 1428 1429 /** 1430 * Adapter class for {@link IImsRegistrationListener}. 1431 */ 1432 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub { 1433 private int mServiceClass; 1434 private ImsConnectionStateListener mListener; 1435 1436 public ImsRegistrationListenerProxy(int serviceClass, 1437 ImsConnectionStateListener listener) { 1438 mServiceClass = serviceClass; 1439 mListener = listener; 1440 } 1441 1442 public boolean isSameProxy(int serviceClass) { 1443 return (mServiceClass == serviceClass); 1444 } 1445 1446 @Deprecated 1447 public void registrationConnected() { 1448 if (DBG) { 1449 log("registrationConnected ::"); 1450 } 1451 1452 if (mListener != null) { 1453 mListener.onImsConnected(); 1454 } 1455 } 1456 1457 @Deprecated 1458 public void registrationProgressing() { 1459 if (DBG) { 1460 log("registrationProgressing ::"); 1461 } 1462 1463 if (mListener != null) { 1464 mListener.onImsProgressing(); 1465 } 1466 } 1467 1468 @Override 1469 public void registrationConnectedWithRadioTech(int imsRadioTech) { 1470 // Note: imsRadioTech value maps to RIL_RADIO_TECHNOLOGY 1471 // values in ServiceState.java. 1472 if (DBG) { 1473 log("registrationConnectedWithRadioTech :: imsRadioTech=" + imsRadioTech); 1474 } 1475 1476 if (mListener != null) { 1477 mListener.onImsConnected(); 1478 } 1479 } 1480 1481 @Override 1482 public void registrationProgressingWithRadioTech(int imsRadioTech) { 1483 // Note: imsRadioTech value maps to RIL_RADIO_TECHNOLOGY 1484 // values in ServiceState.java. 1485 if (DBG) { 1486 log("registrationProgressingWithRadioTech :: imsRadioTech=" + imsRadioTech); 1487 } 1488 1489 if (mListener != null) { 1490 mListener.onImsProgressing(); 1491 } 1492 } 1493 1494 @Override 1495 public void registrationDisconnected(ImsReasonInfo imsReasonInfo) { 1496 if (DBG) { 1497 log("registrationDisconnected :: imsReasonInfo" + imsReasonInfo); 1498 } 1499 1500 if (mListener != null) { 1501 mListener.onImsDisconnected(imsReasonInfo); 1502 } 1503 } 1504 1505 @Override 1506 public void registrationResumed() { 1507 if (DBG) { 1508 log("registrationResumed ::"); 1509 } 1510 1511 if (mListener != null) { 1512 mListener.onImsResumed(); 1513 } 1514 } 1515 1516 @Override 1517 public void registrationSuspended() { 1518 if (DBG) { 1519 log("registrationSuspended ::"); 1520 } 1521 1522 if (mListener != null) { 1523 mListener.onImsSuspended(); 1524 } 1525 } 1526 1527 @Override 1528 public void registrationServiceCapabilityChanged(int serviceClass, int event) { 1529 log("registrationServiceCapabilityChanged :: serviceClass=" + 1530 serviceClass + ", event=" + event); 1531 1532 if (mListener != null) { 1533 mListener.onImsConnected(); 1534 } 1535 } 1536 1537 @Override 1538 public void registrationFeatureCapabilityChanged(int serviceClass, 1539 int[] enabledFeatures, int[] disabledFeatures) { 1540 log("registrationFeatureCapabilityChanged :: serviceClass=" + 1541 serviceClass); 1542 if (mListener != null) { 1543 mListener.onFeatureCapabilityChanged(serviceClass, 1544 enabledFeatures, disabledFeatures); 1545 } 1546 } 1547 1548 @Override 1549 public void voiceMessageCountUpdate(int count) { 1550 log("voiceMessageCountUpdate :: count=" + count); 1551 1552 if (mListener != null) { 1553 mListener.onVoiceMessageCountChanged(count); 1554 } 1555 } 1556 1557 @Override 1558 public void registrationAssociatedUriChanged(Uri[] uris) { 1559 if (DBG) log("registrationAssociatedUriChanged ::"); 1560 1561 if (mListener != null) { 1562 mListener.registrationAssociatedUriChanged(uris); 1563 } 1564 } 1565 } 1566 1567 /** 1568 * Gets the ECBM interface to request ECBM exit. 1569 * 1570 * @param serviceId a service id which is obtained from {@link ImsManager#open} 1571 * @return the ECBM interface instance 1572 * @throws ImsException if getting the ECBM interface results in an error 1573 */ 1574 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException { 1575 if (mEcbm == null) { 1576 checkAndThrowExceptionIfServiceUnavailable(); 1577 1578 try { 1579 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId); 1580 1581 if (iEcbm == null) { 1582 throw new ImsException("getEcbmInterface()", 1583 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED); 1584 } 1585 mEcbm = new ImsEcbm(iEcbm); 1586 } catch (RemoteException e) { 1587 throw new ImsException("getEcbmInterface()", e, 1588 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1589 } 1590 } 1591 return mEcbm; 1592 } 1593 1594 /** 1595 * Gets the Multi-Endpoint interface to subscribe to multi-enpoint notifications.. 1596 * 1597 * @param serviceId a service id which is obtained from {@link ImsManager#open} 1598 * @return the multi-endpoint interface instance 1599 * @throws ImsException if getting the multi-endpoint interface results in an error 1600 */ 1601 public ImsMultiEndpoint getMultiEndpointInterface(int serviceId) throws ImsException { 1602 if (mMultiEndpoint == null) { 1603 checkAndThrowExceptionIfServiceUnavailable(); 1604 1605 try { 1606 IImsMultiEndpoint iImsMultiEndpoint = mImsService.getMultiEndpointInterface( 1607 serviceId); 1608 1609 if (iImsMultiEndpoint == null) { 1610 throw new ImsException("getMultiEndpointInterface()", 1611 ImsReasonInfo.CODE_MULTIENDPOINT_NOT_SUPPORTED); 1612 } 1613 mMultiEndpoint = new ImsMultiEndpoint(iImsMultiEndpoint); 1614 } catch (RemoteException e) { 1615 throw new ImsException("getMultiEndpointInterface()", e, 1616 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 1617 } 1618 } 1619 return mMultiEndpoint; 1620 } 1621 1622 /** 1623 * Resets ImsManager settings back to factory defaults. 1624 * 1625 * @hide 1626 */ 1627 public static void factoryReset(Context context) { 1628 // Set VoLTE to default 1629 android.provider.Settings.Global.putInt(context.getContentResolver(), 1630 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, 1631 ImsConfig.FeatureValueConstants.ON); 1632 1633 // Set VoWiFi to default 1634 android.provider.Settings.Global.putInt(context.getContentResolver(), 1635 android.provider.Settings.Global.WFC_IMS_ENABLED, 1636 getBooleanCarrierConfig(context, 1637 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL) ? 1638 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF); 1639 1640 // Set VoWiFi mode to default 1641 android.provider.Settings.Global.putInt(context.getContentResolver(), 1642 android.provider.Settings.Global.WFC_IMS_MODE, 1643 getIntCarrierConfig(context, 1644 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT)); 1645 1646 // Set VoWiFi roaming to default 1647 android.provider.Settings.Global.putInt(context.getContentResolver(), 1648 android.provider.Settings.Global.WFC_IMS_ROAMING_ENABLED, 1649 getBooleanCarrierConfig(context, 1650 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL) ? 1651 ImsConfig.FeatureValueConstants.ON : ImsConfig.FeatureValueConstants.OFF); 1652 1653 // Set VT to default 1654 android.provider.Settings.Global.putInt(context.getContentResolver(), 1655 android.provider.Settings.Global.VT_IMS_ENABLED, 1656 ImsConfig.FeatureValueConstants.ON); 1657 1658 // Push settings to ImsConfig 1659 ImsManager.updateImsServiceConfig(context, 1660 SubscriptionManager.getDefaultVoicePhoneId(), true); 1661 } 1662 1663 private boolean isDataEnabled() { 1664 return SystemProperties.getBoolean(DATA_ENABLED_PROP, true); 1665 } 1666 1667 /** 1668 * Set data enabled/disabled flag. 1669 * @param enabled True if data is enabled, otherwise disabled. 1670 */ 1671 public void setDataEnabled(boolean enabled) { 1672 log("setDataEnabled: " + enabled); 1673 SystemProperties.set(DATA_ENABLED_PROP, enabled ? TRUE : FALSE); 1674 } 1675 1676 private boolean isVolteProvisioned() { 1677 return SystemProperties.getBoolean(VOLTE_PROVISIONED_PROP, true); 1678 } 1679 1680 private void setVolteProvisionedProperty(boolean provisioned) { 1681 SystemProperties.set(VOLTE_PROVISIONED_PROP, provisioned ? TRUE : FALSE); 1682 } 1683 1684 private boolean isWfcProvisioned() { 1685 return SystemProperties.getBoolean(WFC_PROVISIONED_PROP, true); 1686 } 1687 1688 private void setWfcProvisionedProperty(boolean provisioned) { 1689 SystemProperties.set(WFC_PROVISIONED_PROP, provisioned ? TRUE : FALSE); 1690 } 1691 1692 private boolean isVtProvisioned() { 1693 return SystemProperties.getBoolean(VT_PROVISIONED_PROP, true); 1694 } 1695 1696 private void setVtProvisionedProperty(boolean provisioned) { 1697 SystemProperties.set(VT_PROVISIONED_PROP, provisioned ? TRUE : FALSE); 1698 } 1699 1700 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1701 pw.println("ImsManager:"); 1702 pw.println(" mPhoneId = " + mPhoneId); 1703 pw.println(" mConfigUpdated = " + mConfigUpdated); 1704 pw.println(" mImsService = " + mImsService); 1705 pw.println(" mDataEnabled = " + isDataEnabled()); 1706 1707 pw.println(" isGbaValid = " + isGbaValid(mContext)); 1708 pw.println(" isImsTurnOffAllowed = " + isImsTurnOffAllowed()); 1709 pw.println(" isNonTtyOrTtyOnVolteEnabled = " + isNonTtyOrTtyOnVolteEnabled(mContext)); 1710 1711 pw.println(" isVolteEnabledByPlatform = " + isVolteEnabledByPlatform(mContext)); 1712 pw.println(" isVolteProvisionedOnDevice = " + isVolteProvisionedOnDevice(mContext)); 1713 pw.println(" isEnhanced4gLteModeSettingEnabledByUser = " + 1714 isEnhanced4gLteModeSettingEnabledByUser(mContext)); 1715 pw.println(" isVtEnabledByPlatform = " + isVtEnabledByPlatform(mContext)); 1716 pw.println(" isVtEnabledByUser = " + isVtEnabledByUser(mContext)); 1717 1718 pw.println(" isWfcEnabledByPlatform = " + isWfcEnabledByPlatform(mContext)); 1719 pw.println(" isWfcEnabledByUser = " + isWfcEnabledByUser(mContext)); 1720 pw.println(" getWfcMode = " + getWfcMode(mContext)); 1721 pw.println(" isWfcRoamingEnabledByUser = " + isWfcRoamingEnabledByUser(mContext)); 1722 1723 pw.println(" isVtProvisionedOnDevice = " + isVtProvisionedOnDevice(mContext)); 1724 pw.println(" isWfcProvisionedOnDevice = " + isWfcProvisionedOnDevice(mContext)); 1725 pw.flush(); 1726 } 1727 } 1728