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