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