ImsManager.java revision abbd7880cf8e29274dfc0508568fbffe9f49cad7
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 return 186 context.getResources().getBoolean( 187 com.android.internal.R.bool.config_device_volte_available) && 188 context.getResources().getBoolean( 189 com.android.internal.R.bool.config_carrier_volte_available); 190 } 191 192 /** 193 * Returns a platform configuration for VT which may override the user setting. 194 * 195 * Note: VT presumes that VoLTE is enabled (these are configuration settings 196 * which must be done correctly). 197 */ 198 public static boolean isVtEnabledByPlatform(Context context) { 199 if (SystemProperties.getInt(PROPERTY_DBG_VT_AVAIL_OVERRIDE, 200 PROPERTY_DBG_VT_AVAIL_OVERRIDE_DEFAULT) == 1) { 201 return true; 202 } 203 204 return 205 context.getResources().getBoolean( 206 com.android.internal.R.bool.config_device_vt_available) && 207 context.getResources().getBoolean( 208 com.android.internal.R.bool.config_carrier_vt_available); 209 } 210 211 private ImsManager(Context context, int phoneId) { 212 mContext = context; 213 mPhoneId = phoneId; 214 createImsService(true); 215 } 216 217 /** 218 * Opens the IMS service for making calls and/or receiving generic IMS calls. 219 * The caller may make subsquent calls through {@link #makeCall}. 220 * The IMS service will register the device to the operator's network with the credentials 221 * (from ISIM) periodically in order to receive calls from the operator's network. 222 * When the IMS service receives a new call, it will send out an intent with 223 * the provided action string. 224 * The intent contains a call ID extra {@link getCallId} and it can be used to take a call. 225 * 226 * @param serviceClass a service class specified in {@link ImsServiceClass} 227 * For VoLTE service, it MUST be a {@link ImsServiceClass#MMTEL}. 228 * @param incomingCallPendingIntent When an incoming call is received, 229 * the IMS service will call {@link PendingIntent#send(Context, int, Intent)} to 230 * send back the intent to the caller with {@link #INCOMING_CALL_RESULT_CODE} 231 * as the result code and the intent to fill in the call ID; It cannot be null 232 * @param listener To listen to IMS registration events; It cannot be null 233 * @return identifier (greater than 0) for the specified service 234 * @throws NullPointerException if {@code incomingCallPendingIntent} 235 * or {@code listener} is null 236 * @throws ImsException if calling the IMS service results in an error 237 * @see #getCallId 238 * @see #getServiceId 239 */ 240 public int open(int serviceClass, PendingIntent incomingCallPendingIntent, 241 ImsConnectionStateListener listener) throws ImsException { 242 checkAndThrowExceptionIfServiceUnavailable(); 243 244 if (incomingCallPendingIntent == null) { 245 throw new NullPointerException("incomingCallPendingIntent can't be null"); 246 } 247 248 if (listener == null) { 249 throw new NullPointerException("listener can't be null"); 250 } 251 252 int result = 0; 253 254 try { 255 result = mImsService.open(mPhoneId, serviceClass, incomingCallPendingIntent, 256 createRegistrationListenerProxy(serviceClass, listener)); 257 } catch (RemoteException e) { 258 throw new ImsException("open()", e, 259 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 260 } 261 262 if (result <= 0) { 263 // If the return value is a minus value, 264 // it means that an error occurred in the service. 265 // So, it needs to convert to the reason code specified in ImsReasonInfo. 266 throw new ImsException("open()", (result * (-1))); 267 } 268 269 return result; 270 } 271 272 /** 273 * Closes the specified service ({@link ImsServiceClass}) not to make/receive calls. 274 * All the resources that were allocated to the service are also released. 275 * 276 * @param serviceId a service id to be closed which is obtained from {@link ImsManager#open} 277 * @throws ImsException if calling the IMS service results in an error 278 */ 279 public void close(int serviceId) throws ImsException { 280 checkAndThrowExceptionIfServiceUnavailable(); 281 282 try { 283 mImsService.close(serviceId); 284 } catch (RemoteException e) { 285 throw new ImsException("close()", e, 286 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 287 } finally { 288 mUt = null; 289 mConfig = null; 290 mEcbm = null; 291 } 292 } 293 294 /** 295 * Gets the configuration interface to provision / withdraw the supplementary service settings. 296 * 297 * @param serviceId a service id which is obtained from {@link ImsManager#open} 298 * @return the Ut interface instance 299 * @throws ImsException if getting the Ut interface results in an error 300 */ 301 public ImsUtInterface getSupplementaryServiceConfiguration(int serviceId) 302 throws ImsException { 303 // FIXME: manage the multiple Ut interfaces based on the service id 304 if (mUt == null) { 305 checkAndThrowExceptionIfServiceUnavailable(); 306 307 try { 308 IImsUt iUt = mImsService.getUtInterface(serviceId); 309 310 if (iUt == null) { 311 throw new ImsException("getSupplementaryServiceConfiguration()", 312 ImsReasonInfo.CODE_UT_NOT_SUPPORTED); 313 } 314 315 mUt = new ImsUt(iUt); 316 } catch (RemoteException e) { 317 throw new ImsException("getSupplementaryServiceConfiguration()", e, 318 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 319 } 320 } 321 322 return mUt; 323 } 324 325 /** 326 * Checks if the IMS service has successfully registered to the IMS network 327 * with the specified service & call type. 328 * 329 * @param serviceId a service id which is obtained from {@link ImsManager#open} 330 * @param serviceType a service type that is specified in {@link ImsCallProfile} 331 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 332 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 333 * @param callType a call type that is specified in {@link ImsCallProfile} 334 * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO} 335 * {@link ImsCallProfile#CALL_TYPE_VOICE} 336 * {@link ImsCallProfile#CALL_TYPE_VT} 337 * {@link ImsCallProfile#CALL_TYPE_VS} 338 * @return true if the specified service id is connected to the IMS network; 339 * false otherwise 340 * @throws ImsException if calling the IMS service results in an error 341 */ 342 public boolean isConnected(int serviceId, int serviceType, int callType) 343 throws ImsException { 344 checkAndThrowExceptionIfServiceUnavailable(); 345 346 try { 347 return mImsService.isConnected(serviceId, serviceType, callType); 348 } catch (RemoteException e) { 349 throw new ImsException("isServiceConnected()", e, 350 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 351 } 352 } 353 354 /** 355 * Checks if the specified IMS service is opend. 356 * 357 * @param serviceId a service id which is obtained from {@link ImsManager#open} 358 * @return true if the specified service id is opened; false otherwise 359 * @throws ImsException if calling the IMS service results in an error 360 */ 361 public boolean isOpened(int serviceId) throws ImsException { 362 checkAndThrowExceptionIfServiceUnavailable(); 363 364 try { 365 return mImsService.isOpened(serviceId); 366 } catch (RemoteException e) { 367 throw new ImsException("isOpened()", e, 368 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 369 } 370 } 371 372 /** 373 * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state. 374 * 375 * @param serviceId a service id which is obtained from {@link ImsManager#open} 376 * @param serviceType a service type that is specified in {@link ImsCallProfile} 377 * {@link ImsCallProfile#SERVICE_TYPE_NONE} 378 * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} 379 * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} 380 * @param callType a call type that is specified in {@link ImsCallProfile} 381 * {@link ImsCallProfile#CALL_TYPE_VOICE} 382 * {@link ImsCallProfile#CALL_TYPE_VT} 383 * {@link ImsCallProfile#CALL_TYPE_VT_TX} 384 * {@link ImsCallProfile#CALL_TYPE_VT_RX} 385 * {@link ImsCallProfile#CALL_TYPE_VT_NODIR} 386 * {@link ImsCallProfile#CALL_TYPE_VS} 387 * {@link ImsCallProfile#CALL_TYPE_VS_TX} 388 * {@link ImsCallProfile#CALL_TYPE_VS_RX} 389 * @return a {@link ImsCallProfile} object 390 * @throws ImsException if calling the IMS service results in an error 391 */ 392 public ImsCallProfile createCallProfile(int serviceId, 393 int serviceType, int callType) throws ImsException { 394 checkAndThrowExceptionIfServiceUnavailable(); 395 396 try { 397 return mImsService.createCallProfile(serviceId, serviceType, callType); 398 } catch (RemoteException e) { 399 throw new ImsException("createCallProfile()", e, 400 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 401 } 402 } 403 404 /** 405 * Creates a {@link ImsCall} to make a call. 406 * 407 * @param serviceId a service id which is obtained from {@link ImsManager#open} 408 * @param profile a call profile to make the call 409 * (it contains service type, call type, media information, etc.) 410 * @param participants participants to invite the conference call 411 * @param listener listen to the call events from {@link ImsCall} 412 * @return a {@link ImsCall} object 413 * @throws ImsException if calling the IMS service results in an error 414 */ 415 public ImsCall makeCall(int serviceId, ImsCallProfile profile, String[] callees, 416 ImsCall.Listener listener) throws ImsException { 417 if (DBG) { 418 log("makeCall :: serviceId=" + serviceId 419 + ", profile=" + profile + ", callees=" + callees); 420 } 421 422 checkAndThrowExceptionIfServiceUnavailable(); 423 424 ImsCall call = new ImsCall(mContext, profile); 425 426 call.setListener(listener); 427 ImsCallSession session = createCallSession(serviceId, profile); 428 429 if ((callees != null) && (callees.length == 1)) { 430 call.start(session, callees[0]); 431 } else { 432 call.start(session, callees); 433 } 434 435 return call; 436 } 437 438 /** 439 * Creates a {@link ImsCall} to take an incoming call. 440 * 441 * @param serviceId a service id which is obtained from {@link ImsManager#open} 442 * @param incomingCallIntent the incoming call broadcast intent 443 * @param listener to listen to the call events from {@link ImsCall} 444 * @return a {@link ImsCall} object 445 * @throws ImsException if calling the IMS service results in an error 446 */ 447 public ImsCall takeCall(int serviceId, Intent incomingCallIntent, 448 ImsCall.Listener listener) throws ImsException { 449 if (DBG) { 450 log("takeCall :: serviceId=" + serviceId 451 + ", incomingCall=" + incomingCallIntent); 452 } 453 454 checkAndThrowExceptionIfServiceUnavailable(); 455 456 if (incomingCallIntent == null) { 457 throw new ImsException("Can't retrieve session with null intent", 458 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 459 } 460 461 int incomingServiceId = getServiceId(incomingCallIntent); 462 463 if (serviceId != incomingServiceId) { 464 throw new ImsException("Service id is mismatched in the incoming call intent", 465 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 466 } 467 468 String callId = getCallId(incomingCallIntent); 469 470 if (callId == null) { 471 throw new ImsException("Call ID missing in the incoming call intent", 472 ImsReasonInfo.CODE_LOCAL_ILLEGAL_ARGUMENT); 473 } 474 475 try { 476 IImsCallSession session = mImsService.getPendingCallSession(serviceId, callId); 477 478 if (session == null) { 479 throw new ImsException("No pending session for the call", 480 ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL); 481 } 482 483 ImsCall call = new ImsCall(mContext, session.getCallProfile()); 484 485 call.attachSession(new ImsCallSession(session)); 486 call.setListener(listener); 487 488 return call; 489 } catch (Throwable t) { 490 throw new ImsException("takeCall()", t, ImsReasonInfo.CODE_UNSPECIFIED); 491 } 492 } 493 494 /** 495 * Gets the config interface to get/set service/capability parameters. 496 * 497 * @return the ImsConfig instance. 498 * @throws ImsException if getting the setting interface results in an error. 499 */ 500 public ImsConfig getConfigInterface() throws ImsException { 501 502 if (mConfig == null) { 503 checkAndThrowExceptionIfServiceUnavailable(); 504 505 try { 506 IImsConfig config = mImsService.getConfigInterface(mPhoneId); 507 if (config == null) { 508 throw new ImsException("getConfigInterface()", 509 ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE); 510 } 511 mConfig = new ImsConfig(config, mContext); 512 } catch (RemoteException e) { 513 throw new ImsException("getConfigInterface()", e, 514 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 515 } 516 } 517 if (DBG) log("getConfigInterface(), mConfig= " + mConfig); 518 return mConfig; 519 } 520 521 public void setUiTTYMode(int serviceId, int uiTtyMode, Message onComplete) 522 throws ImsException { 523 524 checkAndThrowExceptionIfServiceUnavailable(); 525 526 try { 527 mImsService.setUiTTYMode(serviceId, uiTtyMode, onComplete); 528 } catch (RemoteException e) { 529 throw new ImsException("setTTYMode()", e, 530 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 531 } 532 } 533 534 /** 535 * Gets the call ID from the specified incoming call broadcast intent. 536 * 537 * @param incomingCallIntent the incoming call broadcast intent 538 * @return the call ID or null if the intent does not contain it 539 */ 540 private static String getCallId(Intent incomingCallIntent) { 541 if (incomingCallIntent == null) { 542 return null; 543 } 544 545 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID); 546 } 547 548 /** 549 * Gets the service type from the specified incoming call broadcast intent. 550 * 551 * @param incomingCallIntent the incoming call broadcast intent 552 * @return the service identifier or -1 if the intent does not contain it 553 */ 554 private static int getServiceId(Intent incomingCallIntent) { 555 if (incomingCallIntent == null) { 556 return (-1); 557 } 558 559 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1); 560 } 561 562 /** 563 * Binds the IMS service only if the service is not created. 564 */ 565 private void checkAndThrowExceptionIfServiceUnavailable() 566 throws ImsException { 567 if (mImsService == null) { 568 createImsService(true); 569 570 if (mImsService == null) { 571 throw new ImsException("Service is unavailable", 572 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 573 } 574 } 575 } 576 577 private static String getImsServiceName(int phoneId) { 578 // TODO: MSIM implementation needs to decide on service name as a function of phoneId 579 return IMS_SERVICE; 580 } 581 582 /** 583 * Binds the IMS service to make/receive the call. 584 */ 585 private void createImsService(boolean checkService) { 586 if (checkService) { 587 IBinder binder = ServiceManager.checkService(getImsServiceName(mPhoneId)); 588 589 if (binder == null) { 590 return; 591 } 592 } 593 594 IBinder b = ServiceManager.getService(getImsServiceName(mPhoneId)); 595 596 if (b != null) { 597 try { 598 b.linkToDeath(mDeathRecipient, 0); 599 } catch (RemoteException e) { 600 } 601 } 602 603 mImsService = IImsService.Stub.asInterface(b); 604 } 605 606 /** 607 * Creates a {@link ImsCallSession} with the specified call profile. 608 * Use other methods, if applicable, instead of interacting with 609 * {@link ImsCallSession} directly. 610 * 611 * @param serviceId a service id which is obtained from {@link ImsManager#open} 612 * @param profile a call profile to make the call 613 */ 614 private ImsCallSession createCallSession(int serviceId, 615 ImsCallProfile profile) throws ImsException { 616 try { 617 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null)); 618 } catch (RemoteException e) { 619 return null; 620 } 621 } 622 623 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass, 624 ImsConnectionStateListener listener) { 625 ImsRegistrationListenerProxy proxy = 626 new ImsRegistrationListenerProxy(serviceClass, listener); 627 return proxy; 628 } 629 630 private void log(String s) { 631 Rlog.d(TAG, s); 632 } 633 634 private void loge(String s) { 635 Rlog.e(TAG, s); 636 } 637 638 private void loge(String s, Throwable t) { 639 Rlog.e(TAG, s, t); 640 } 641 642 /** 643 * Used for turning on IMS.if its off already 644 */ 645 public void turnOnIms() throws ImsException { 646 checkAndThrowExceptionIfServiceUnavailable(); 647 648 try { 649 mImsService.turnOnIms(mPhoneId); 650 } catch (RemoteException e) { 651 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 652 } 653 } 654 655 public void setAdvanced4GMode(boolean turnOn) throws ImsException { 656 checkAndThrowExceptionIfServiceUnavailable(); 657 658 ImsConfig config = getConfigInterface(); 659 if (config != null) { 660 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, 661 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null); 662 if (isVtEnabledByPlatform(mContext)) { 663 // TODO: once VT is available on platform replace the '1' with the current 664 // user configuration of VT. 665 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE, 666 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null); 667 } 668 } 669 670 if (turnOn) { 671 turnOnIms(); 672 } else if (mContext.getResources().getBoolean( 673 com.android.internal.R.bool.imsServiceAllowTurnOff)) { 674 log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms"); 675 turnOffIms(); 676 } 677 } 678 679 /** 680 * Used for turning off IMS completely in order to make the device CSFB'ed. 681 * Once turned off, all calls will be over CS. 682 */ 683 public void turnOffIms() throws ImsException { 684 checkAndThrowExceptionIfServiceUnavailable(); 685 686 try { 687 mImsService.turnOffIms(mPhoneId); 688 } catch (RemoteException e) { 689 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 690 } 691 } 692 693 /** 694 * Death recipient class for monitoring IMS service. 695 */ 696 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient { 697 @Override 698 public void binderDied() { 699 mImsService = null; 700 mUt = null; 701 mConfig = null; 702 mEcbm = null; 703 704 if (mContext != null) { 705 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN); 706 intent.putExtra(EXTRA_PHONE_ID, mPhoneId); 707 mContext.sendBroadcast(new Intent(intent)); 708 } 709 } 710 } 711 712 /** 713 * Adapter class for {@link IImsRegistrationListener}. 714 */ 715 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub { 716 private int mServiceClass; 717 private ImsConnectionStateListener mListener; 718 719 public ImsRegistrationListenerProxy(int serviceClass, 720 ImsConnectionStateListener listener) { 721 mServiceClass = serviceClass; 722 mListener = listener; 723 } 724 725 public boolean isSameProxy(int serviceClass) { 726 return (mServiceClass == serviceClass); 727 } 728 729 @Override 730 public void registrationConnected() { 731 if (DBG) { 732 log("registrationConnected ::"); 733 } 734 735 if (mListener != null) { 736 mListener.onImsConnected(); 737 } 738 } 739 740 @Override 741 public void registrationDisconnected() { 742 if (DBG) { 743 log("registrationDisconnected ::"); 744 } 745 746 if (mListener != null) { 747 mListener.onImsDisconnected(); 748 } 749 } 750 751 @Override 752 public void registrationResumed() { 753 if (DBG) { 754 log("registrationResumed ::"); 755 } 756 757 if (mListener != null) { 758 mListener.onImsResumed(); 759 } 760 } 761 762 @Override 763 public void registrationSuspended() { 764 if (DBG) { 765 log("registrationSuspended ::"); 766 } 767 768 if (mListener != null) { 769 mListener.onImsSuspended(); 770 } 771 } 772 773 @Override 774 public void registrationServiceCapabilityChanged(int serviceClass, int event) { 775 log("registrationServiceCapabilityChanged :: serviceClass=" + 776 serviceClass + ", event=" + event); 777 778 if (mListener != null) { 779 mListener.onImsConnected(); 780 } 781 } 782 783 @Override 784 public void registrationFeatureCapabilityChanged(int serviceClass, 785 int[] enabledFeatures, int[] disabledFeatures) { 786 log("registrationFeatureCapabilityChanged :: serviceClass=" + 787 serviceClass); 788 if (mListener != null) { 789 mListener.onFeatureCapabilityChanged(serviceClass, 790 enabledFeatures, disabledFeatures); 791 } 792 } 793 794 } 795 /** 796 * Gets the ECBM interface to request ECBM exit. 797 * 798 * @param serviceId a service id which is obtained from {@link ImsManager#open} 799 * @return the ECBM interface instance 800 * @throws ImsException if getting the ECBM interface results in an error 801 */ 802 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException { 803 if (mEcbm == null) { 804 checkAndThrowExceptionIfServiceUnavailable(); 805 806 try { 807 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId); 808 809 if (iEcbm == null) { 810 throw new ImsException("getEcbmInterface()", 811 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED); 812 } 813 mEcbm = new ImsEcbm(iEcbm); 814 } catch (RemoteException e) { 815 throw new ImsException("getEcbmInterface()", e, 816 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 817 } 818 } 819 return mEcbm; 820 } 821} 822