ImsManager.java revision d40d4a9ca488e4caa07ed7916ccae4b76c385cae
1/* 2 * Copyright (c) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.ims; 18 19import android.app.PendingIntent; 20import android.content.Context; 21import android.content.Intent; 22import android.os.IBinder; 23import android.os.IBinder.DeathRecipient; 24import android.os.Message; 25import android.os.Process; 26import android.os.RemoteException; 27import android.os.ServiceManager; 28import android.os.SystemProperties; 29import android.telephony.Rlog; 30import android.telephony.TelephonyManager; 31 32import com.android.ims.internal.IImsCallSession; 33import com.android.ims.internal.IImsEcbm; 34import com.android.ims.internal.IImsEcbmListener; 35import com.android.ims.internal.IImsRegistrationListener; 36import com.android.ims.internal.IImsService; 37import com.android.ims.internal.IImsUt; 38import com.android.ims.internal.ImsCallSession; 39import com.android.ims.internal.IImsConfig; 40 41import java.util.HashMap; 42 43/** 44 * Provides APIs for IMS services, such as initiating IMS calls, and provides access to 45 * the operator's IMS network. This class is the starting point for any IMS actions. 46 * You can acquire an instance of it with {@link #getInstance getInstance()}.</p> 47 * <p>The APIs in this class allows you to:</p> 48 * 49 * @hide 50 */ 51public class ImsManager { 52 53 /* 54 * Debug flag to override configuration flag 55 */ 56 public static final String PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE = "persist.dbg.volte_avail_ovr"; 57 public static final int PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT = 0; 58 public static final String PROPERTY_DBG_VT_AVAIL_OVERRIDE = "persist.dbg.vt_avail_ovr"; 59 public static final int PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT = 0; 60 61 /** 62 * For accessing the IMS related service. 63 * Internal use only. 64 * @hide 65 */ 66 private static final String IMS_SERVICE = "ims"; 67 68 /** 69 * The result code to be sent back with the incoming call {@link PendingIntent}. 70 * @see #open(PendingIntent, ImsConnectionStateListener) 71 */ 72 public static final int INCOMING_CALL_RESULT_CODE = 101; 73 74 /** 75 * Key to retrieve the call ID from an incoming call intent. 76 * @see #open(PendingIntent, ImsConnectionStateListener) 77 */ 78 public static final String EXTRA_CALL_ID = "android:imsCallID"; 79 80 /** 81 * Action to broadcast when ImsService is up. 82 * Internal use only. 83 * @hide 84 */ 85 public static final String ACTION_IMS_SERVICE_UP = 86 "com.android.ims.IMS_SERVICE_UP"; 87 88 /** 89 * Action to broadcast when ImsService is down. 90 * Internal use only. 91 * @hide 92 */ 93 public static final String ACTION_IMS_SERVICE_DOWN = 94 "com.android.ims.IMS_SERVICE_DOWN"; 95 96 /** 97 * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents. 98 * A long value; the phone ID corresponding to the IMS service coming up or down. 99 * Internal use only. 100 * @hide 101 */ 102 public static final String EXTRA_PHONE_ID = "android:phone_id"; 103 104 /** 105 * Action for the incoming call intent for the Phone app. 106 * Internal use only. 107 * @hide 108 */ 109 public static final String ACTION_IMS_INCOMING_CALL = 110 "com.android.ims.IMS_INCOMING_CALL"; 111 112 /** 113 * Part of the ACTION_IMS_INCOMING_CALL intents. 114 * An integer value; service identifier obtained from {@link ImsManager#open}. 115 * Internal use only. 116 * @hide 117 */ 118 public static final String EXTRA_SERVICE_ID = "android:imsServiceId"; 119 120 /** 121 * Part of the ACTION_IMS_INCOMING_CALL intents. 122 * An boolean value; Flag to indicate that the incoming call is a normal call or call for USSD. 123 * The value "true" indicates that the incoming call is for USSD. 124 * Internal use only. 125 * @hide 126 */ 127 public static final String EXTRA_USSD = "android:ussd"; 128 129 private static final String TAG = "ImsManager"; 130 private static final boolean DBG = true; 131 132 private static HashMap<Integer, ImsManager> sImsManagerInstances = 133 new HashMap<Integer, ImsManager>(); 134 135 private Context mContext; 136 private int mPhoneId; 137 private IImsService mImsService = null; 138 private ImsServiceDeathRecipient mDeathRecipient = new ImsServiceDeathRecipient(); 139 // Ut interface for the supplementary service configuration 140 private ImsUt mUt = null; 141 // Interface to get/set ims config items 142 private ImsConfig mConfig = null; 143 144 // ECBM interface 145 private ImsEcbm mEcbm = null; 146 147 /** 148 * Gets a manager instance. 149 * 150 * @param context application context for creating the manager object 151 * @param phoneId the phone ID for the IMS Service 152 * @return the manager instance corresponding to the phoneId 153 */ 154 public static ImsManager getInstance(Context context, int phoneId) { 155 synchronized (sImsManagerInstances) { 156 if (sImsManagerInstances.containsKey(phoneId)) 157 return sImsManagerInstances.get(phoneId); 158 159 ImsManager mgr = new ImsManager(context, phoneId); 160 sImsManagerInstances.put(phoneId, mgr); 161 162 return mgr; 163 } 164 } 165 166 /** 167 * Returns the user configuration of Enhanced 4G LTE Mode setting 168 */ 169 public static boolean isEnhanced4gLteModeSettingEnabledByUser(Context context) { 170 int enabled = android.provider.Settings.Global.getInt( 171 context.getContentResolver(), 172 android.provider.Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON); 173 return (enabled == 1)? true:false; 174 } 175 176 /** 177 * Returns a platform configuration for VoLTE which may override the user setting. 178 */ 179 public static boolean isVolteEnabledByPlatform(Context context) { 180 if (SystemProperties.getInt(PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE, 181 PROPERTY_DBG_VOLTE_AVAIL_OVERRIDE_DEFAULT) == 1) { 182 return true; 183 } 184 185 boolean disabledByGlobalSetting = android.provider.Settings.Global.getInt( 186 context.getContentResolver(), 187 android.provider.Settings.Global.VOLTE_FEATURE_DISABLED, 0) == 1; 188 189 return 190 context.getResources().getBoolean( 191 com.android.internal.R.bool.config_device_volte_available) && 192 context.getResources().getBoolean( 193 com.android.internal.R.bool.config_carrier_volte_available) && 194 !disabledByGlobalSetting; 195 } 196 197 /** 198 * Returns a platform configuration for VT which may override the user setting. 199 * 200 * Note: VT presumes that VoLTE is enabled (these are configuration settings 201 * which must be done correctly). 202 */ 203 public static boolean isVtEnabledByPlatform(Context context) { 204 if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE, 205 PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT) == 1) { 206 return true; 207 } 208 209 return 210 context.getResources().getBoolean( 211 com.android.internal.R.bool.config_device_vt_available) && 212 context.getResources().getBoolean( 213 com.android.internal.R.bool.config_carrier_vt_available); 214 } 215 216 private ImsManager(Context context, int phoneId) { 217 mContext = context; 218 mPhoneId = phoneId; 219 createImsService(true); 220 } 221 222 /** 223 * Opens the IMS service for making calls and/or receiving generic IMS calls. 224 * The caller may make subsquent calls through {@link #makeCall}. 225 * The IMS service will register the device to the operator's network with the credentials 226 * (from ISIM) periodically in order to receive calls from the operator's network. 227 * When the IMS service receives a new call, it will send out an intent with 228 * the provided action string. 229 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call. 230 * 231 * @param serviceClass a service class specified in {@link ImsServiceClass} 232 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}. 233 * @param incomingCallPendingIntent When an incoming call is received, 234 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to 235 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE} 236 * as the result code and the intent to fill in the call ID; It cannot be null 237 * @param listener To listen to IMS registration events; It cannot be null 238 * @return identifier (greater than 0) for the specified service 239 * @throws NullPointerException if {@code incomingCallPendingIntent} 240 * or {@code listener} is null 241 * @throws ImsException if calling the IMS service results in an error 242 * @see #getCallId 243 * @see #getServiceId 244 */ 245 public int open(int serviceClass, PendingIntent incomingCallPendingIntent, 246 ImsConnectionStateListener listener) throws ImsException { 247 checkAndThrowExceptionIfServiceUnavailable(); 248 249 if (incomingCallPendingIntent == null) { 250 throw new NullPointerException("incomingCallPendingIntent can't be null"); 251 } 252 253 if (listener == null) { 254 throw new NullPointerException("listener can't be null"); 255 } 256 257 int result = 0; 258 259 try { 260 result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent, 261 createRegistrationListenerProxy(serviceClass, listener)); 262 } catch (RemoteException e) { 263 throw new ImsException("open()", e, 264 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 265 } 266 267 if (result <= 0) { 268 // If the return value is a minus value, 269 // it means that an error occurred in the service. 270 // So, it needs to convert to the reason code specified in ImsReasonInfo. 271 throw new ImsException("open()", (result * (-1))); 272 } 273 274 return result; 275 } 276 277 /** 278 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls. 279 * All the resources that were allocated to the service are also released. 280 * 281 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open} 282 * @throws ImsException if calling the IMS service results in an error 283 */ 284 public void close(int serviceId) throws ImsException { 285 checkAndThrowExceptionIfServiceUnavailable(); 286 287 try { 288 mImsService.close(serviceId); 289 } catch (RemoteException e) { 290 throw new ImsException("close()", e, 291 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 292 } finally { 293 mUt = null; 294 mConfig = null; 295 mEcbm = null; 296 } 297 } 298 299 /** 300 * Gets the configuration interface to provision / withdraw the supplementary service settings. 301 * 302 * @param serviceId a service id which is obtained from {@link ImsManager#open} 303 * @return the Ut interface instance 304 * @throws ImsException if getting the Ut interface results in an error 305 */ 306 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId) 307 throws ImsException { 308 // FIXME: manage the multiple Ut interfaces based on the service id 309 if (mUt == null) { 310 checkAndThrowExceptionIfServiceUnavailable(); 311 312 try { 313 IImsUt iUt = mImsService.getUtInterface(serviceId); 314 315 if (iUt == null) { 316 throw new ImsException("getSupplementaryServiceConfiguration()", 317 ImsReasonInfo.CODE_UT_NOT_SUPPORTED); 318 } 319 320 mUt = new ImsUt(iUt); 321 } catch (RemoteException e) { 322 throw new ImsException("getSupplementaryServiceConfiguration()", e, 323 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 324 } 325 } 326 327 return mUt; 328 } 329 330 /** 331 * Checks if the IMS service has successfully registered to the IMS network 332 * with the specified service & call type. 333 * 334 * @param serviceId a service id which is obtained from {@link ImsManager#open} 335 * @param serviceType a service type that is specified in {@link ImsCallProfile} 336 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 337 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 338 * @param callType a call type that is specified in {@link ImsCallProfile} 339 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO} 340 * {@link ImsCallProfile#CALL_TYPE_VOICE} 341 * {@link ImsCallProfile#CALL_TYPE_VT} 342 * {@link ImsCallProfile#CALL_TYPE_VS} 343 * @return true if the specified service id is connected to the IMS network; 344 * false otherwise 345 * @throws ImsException if calling the IMS service results in an error 346 */ 347 public boolean isConnected(int serviceId, int serviceType, int callType) 348 throws ImsException { 349 checkAndThrowExceptionIfServiceUnavailable(); 350 351 try { 352 return mImsService.isConnected(serviceId, serviceType, callType); 353 } catch (RemoteException e) { 354 throw new ImsException("isServiceConnected()", e, 355 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 356 } 357 } 358 359 /** 360 * Checks if the specified IMS service is opend. 361 * 362 * @param serviceId a service id which is obtained from {@link ImsManager#open} 363 * @return true if the specified service id is opened; false otherwise 364 * @throws ImsException if calling the IMS service results in an error 365 */ 366 public boolean isOpened(int serviceId) throws ImsException { 367 checkAndThrowExceptionIfServiceUnavailable(); 368 369 try { 370 return mImsService.isOpened(serviceId); 371 } catch (RemoteException e) { 372 throw new ImsException("isOpened()", e, 373 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 374 } 375 } 376 377 /** 378 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state. 379 * 380 * @param serviceId a service id which is obtained from {@link ImsManager#open} 381 * @param serviceType a service type that is specified in {@link ImsCallProfile} 382 * {@link ImsCallProfile#SERVICE_TYPE_NONE} 383 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 384 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 385 * @param callType a call type that is specified in {@link ImsCallProfile} 386 * {@link ImsCallProfile#CALL_TYPE_VOICE} 387 * {@link ImsCallProfile#CALL_TYPE_VT} 388 * {@link ImsCallProfile#CALL_TYPE_VT_TX} 389 * {@link ImsCallProfile#CALL_TYPE_VT_RX} 390 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR} 391 * {@link ImsCallProfile#CALL_TYPE_VS} 392 * {@link ImsCallProfile#CALL_TYPE_VS_TX} 393 * {@link ImsCallProfile#CALL_TYPE_VS_RX} 394 * @return a {@link ImsCallProfile} object 395 * @throws ImsException if calling the IMS service results in an error 396 */ 397 public ImsCallProfile createCallProfile(int serviceId, 398 int serviceType, int callType) throws ImsException { 399 checkAndThrowExceptionIfServiceUnavailable(); 400 401 try { 402 return mImsService.createCallProfile(serviceId, serviceType, callType); 403 } catch (RemoteException e) { 404 throw new ImsException("createCallProfile()", e, 405 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 406 } 407 } 408 409 /** 410 * Creates a {@link ImsCall} to make a call. 411 * 412 * @param serviceId a service id which is obtained from {@link ImsManager#open} 413 * @param profile a call profile to make the call 414 * (it contains service type, call type, media information, etc.) 415 * @param participants participants to invite the conference call 416 * @param listener listen to the call events from {@link ImsCall} 417 * @return a {@link ImsCall} object 418 * @throws ImsException if calling the IMS service results in an error 419 */ 420 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees, 421 ImsCall.Listener listener) throws ImsException { 422 if (DBG) { 423 log("makeCall :: serviceId=" + serviceId 424 + ", profile=" + profile + ", callees=" + callees); 425 } 426 427 checkAndThrowExceptionIfServiceUnavailable(); 428 429 ImsCall call = new ImsCall(mContext, profile); 430 431 call.setListener(listener); 432 ImsCallSession session = createCallSession(serviceId, profile); 433 434 if ((callees != null) && (callees.length == 1)) { 435 call.start(session, callees[0]); 436 } else { 437 call.start(session, callees); 438 } 439 440 return call; 441 } 442 443 /** 444 * Creates a {@link ImsCall} to take an incoming call. 445 * 446 * @param serviceId a service id which is obtained from {@link ImsManager#open} 447 * @param incomingCallIntent the incoming call broadcast intent 448 * @param listener to listen to the call events from {@link ImsCall} 449 * @return a {@link ImsCall} object 450 * @throws ImsException if calling the IMS service results in an error 451 */ 452 public ImsCall takeCall(int serviceId, Intent incomingCallIntent, 453 ImsCall.Listener listener) throws ImsException { 454 if (DBG) { 455 log("takeCall :: serviceId=" + serviceId 456 + ", incomingCall=" + incomingCallIntent); 457 } 458 459 checkAndThrowExceptionIfServiceUnavailable(); 460 461 if (incomingCallIntent == null) { 462 throw new ImsException("Can't retrieve session with null intent", 463 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 464 } 465 466 int incomingServiceId = getServiceId(incomingCallIntent); 467 468 if (serviceId != incomingServiceId) { 469 throw new ImsException("Service id is mismatched in the incoming call intent", 470 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 471 } 472 473 String callId = getCallId(incomingCallIntent); 474 475 if (callId == null) { 476 throw new ImsException("Call ID missing in the incoming call intent", 477 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 478 } 479 480 try { 481 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId); 482 483 if (session == null) { 484 throw new ImsException("No pending session for the call", 485 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL); 486 } 487 488 ImsCall call = new ImsCall(mContext, session.getCallProfile()); 489 490 call.attachSession(new ImsCallSession(session)); 491 call.setListener(listener); 492 493 return call; 494 } catch (Throwable t) { 495 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED); 496 } 497 } 498 499 /** 500 * Gets the config interface to get/set service/capability parameters. 501 * 502 * @return the ImsConfig instance. 503 * @throws ImsException if getting the setting interface results in an error. 504 */ 505 public ImsConfig getConfigInterface() throws ImsException { 506 507 if (mConfig == null) { 508 checkAndThrowExceptionIfServiceUnavailable(); 509 510 try { 511 IImsConfig config = mImsService.getConfigInterface(mPhoneId); 512 if (config == null) { 513 throw new ImsException("getConfigInterface()", 514 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE); 515 } 516 mConfig = new ImsConfig(config, mContext); 517 } catch (RemoteException e) { 518 throw new ImsException("getConfigInterface()", e, 519 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 520 } 521 } 522 if (DBG) log("getConfigInterface(), mConfig= " + mConfig); 523 return mConfig; 524 } 525 526 public void setUiTTYMode(int serviceId, int uiTtyMode, Message onComplete) 527 throws ImsException { 528 529 checkAndThrowExceptionIfServiceUnavailable(); 530 531 try { 532 mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete); 533 } catch (RemoteException e) { 534 throw new ImsException("setTTYMode()", e, 535 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 536 } 537 } 538 539 /** 540 * Gets the call ID from the specified incoming call broadcast intent. 541 * 542 * @param incomingCallIntent the incoming call broadcast intent 543 * @return the call ID or null if the intent does not contain it 544 */ 545 private static String getCallId(Intent incomingCallIntent) { 546 if (incomingCallIntent == null) { 547 return null; 548 } 549 550 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID); 551 } 552 553 /** 554 * Gets the service type from the specified incoming call broadcast intent. 555 * 556 * @param incomingCallIntent the incoming call broadcast intent 557 * @return the service identifier or -1 if the intent does not contain it 558 */ 559 private static int getServiceId(Intent incomingCallIntent) { 560 if (incomingCallIntent == null) { 561 return (-1); 562 } 563 564 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1); 565 } 566 567 /** 568 * Binds the IMS service only if the service is not created. 569 */ 570 private void checkAndThrowExceptionIfServiceUnavailable() 571 throws ImsException { 572 if (mImsService == null) { 573 createImsService(true); 574 575 if (mImsService == null) { 576 throw new ImsException("Service is unavailable", 577 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 578 } 579 } 580 } 581 582 private static String getImsServiceName(int phoneId) { 583 // TODO: MSIM implementation needs to decide on service name as a function of phoneId 584 return IMS_SERVICE; 585 } 586 587 /** 588 * Binds the IMS service to make/receive the call. 589 */ 590 private void createImsService(boolean checkService) { 591 if (checkService) { 592 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId)); 593 594 if (binder == null) { 595 return; 596 } 597 } 598 599 IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId)); 600 601 if (b != null) { 602 try { 603 b.linkToDeath(mDeathRecipient, 0); 604 } catch (RemoteException e) { 605 } 606 } 607 608 mImsService = IImsService.Stub.asInterface(b); 609 } 610 611 /** 612 * Creates a {@link ImsCallSession} with the specified call profile. 613 * Use other methods, if applicable, instead of interacting with 614 * {@link ImsCallSession} directly. 615 * 616 * @param serviceId a service id which is obtained from {@link ImsManager#open} 617 * @param profile a call profile to make the call 618 */ 619 private ImsCallSession createCallSession(int serviceId, 620 ImsCallProfile profile) throws ImsException { 621 try { 622 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null)); 623 } catch (RemoteException e) { 624 return null; 625 } 626 } 627 628 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass, 629 ImsConnectionStateListener listener) { 630 ImsRegistrationListenerProxy proxy = 631 new ImsRegistrationListenerProxy(serviceClass, listener); 632 return proxy; 633 } 634 635 private void log(String s) { 636 Rlog.d(TAG, s); 637 } 638 639 private void loge(String s) { 640 Rlog.e(TAG, s); 641 } 642 643 private void loge(String s, Throwable t) { 644 Rlog.e(TAG, s, t); 645 } 646 647 /** 648 * Used for turning on IMS.if its off already 649 */ 650 public void turnOnIms() throws ImsException { 651 checkAndThrowExceptionIfServiceUnavailable(); 652 653 try { 654 mImsService.turnOnIms(mPhoneId); 655 } catch (RemoteException e) { 656 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 657 } 658 } 659 660 public void setAdvanced4GMode(boolean turnOn) throws ImsException { 661 checkAndThrowExceptionIfServiceUnavailable(); 662 663 ImsConfig config = getConfigInterface(); 664 if (config != null) { 665 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, 666 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null); 667 if (isVtEnabledByPlatform(mContext)) { 668 // TODO: once VT is available on platform replace the '1' with the current 669 // user configuration of VT. 670 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE, 671 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null); 672 } 673 } 674 675 if (turnOn) { 676 turnOnIms(); 677 } else if (mContext.getResources().getBoolean( 678 com.android.internal.R.bool.imsServiceAllowTurnOff)) { 679 log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms"); 680 turnOffIms(); 681 } 682 } 683 684 /** 685 * Used for turning off IMS completely in order to make the device CSFB'ed. 686 * Once turned off, all calls will be over CS. 687 */ 688 public void turnOffIms() throws ImsException { 689 checkAndThrowExceptionIfServiceUnavailable(); 690 691 try { 692 mImsService.turnOffIms(mPhoneId); 693 } catch (RemoteException e) { 694 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 695 } 696 } 697 698 /** 699 * Death recipient class for monitoring IMS service. 700 */ 701 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient { 702 @Override 703 public void binderDied() { 704 mImsService = null; 705 mUt = null; 706 mConfig = null; 707 mEcbm = null; 708 709 if (mContext != null) { 710 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN); 711 intent.putExtra(EXTRA_PHONE_ID, mPhoneId); 712 mContext.sendBroadcast(new Intent(intent)); 713 } 714 } 715 } 716 717 /** 718 * Adapter class for {@link IImsRegistrationListener}. 719 */ 720 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub { 721 private int mServiceClass; 722 private ImsConnectionStateListener mListener; 723 724 public ImsRegistrationListenerProxy(int serviceClass, 725 ImsConnectionStateListener listener) { 726 mServiceClass = serviceClass; 727 mListener = listener; 728 } 729 730 public boolean isSameProxy(int serviceClass) { 731 return (mServiceClass == serviceClass); 732 } 733 734 @Override 735 public void registrationConnected() { 736 if (DBG) { 737 log("registrationConnected ::"); 738 } 739 740 if (mListener != null) { 741 mListener.onImsConnected(); 742 } 743 } 744 745 @Override 746 public void registrationDisconnected() { 747 if (DBG) { 748 log("registrationDisconnected ::"); 749 } 750 751 if (mListener != null) { 752 mListener.onImsDisconnected(); 753 } 754 } 755 756 @Override 757 public void registrationResumed() { 758 if (DBG) { 759 log("registrationResumed ::"); 760 } 761 762 if (mListener != null) { 763 mListener.onImsResumed(); 764 } 765 } 766 767 @Override 768 public void registrationSuspended() { 769 if (DBG) { 770 log("registrationSuspended ::"); 771 } 772 773 if (mListener != null) { 774 mListener.onImsSuspended(); 775 } 776 } 777 778 @Override 779 public void registrationServiceCapabilityChanged(int serviceClass, int event) { 780 log("registrationServiceCapabilityChanged :: serviceClass=" + 781 serviceClass + ", event=" + event); 782 783 if (mListener != null) { 784 mListener.onImsConnected(); 785 } 786 } 787 788 @Override 789 public void registrationFeatureCapabilityChanged(int serviceClass, 790 int[] enabledFeatures, int[] disabledFeatures) { 791 log("registrationFeatureCapabilityChanged :: serviceClass=" + 792 serviceClass); 793 if (mListener != null) { 794 mListener.onFeatureCapabilityChanged(serviceClass, 795 enabledFeatures, disabledFeatures); 796 } 797 } 798 799 } 800 /** 801 * Gets the ECBM interface to request ECBM exit. 802 * 803 * @param serviceId a service id which is obtained from {@link ImsManager#open} 804 * @return the ECBM interface instance 805 * @throws ImsException if getting the ECBM interface results in an error 806 */ 807 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException { 808 if (mEcbm == null) { 809 checkAndThrowExceptionIfServiceUnavailable(); 810 811 try { 812 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId); 813 814 if (iEcbm == null) { 815 throw new ImsException("getEcbmInterface()", 816 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED); 817 } 818 mEcbm = new ImsEcbm(iEcbm); 819 } catch (RemoteException e) { 820 throw new ImsException("getEcbmInterface()", e, 821 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 822 } 823 } 824 return mEcbm; 825 } 826} 827