1 /* 2 * Copyright (c) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ims; 18 19 import android.app.PendingIntent; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.IBinder; 23 import android.os.IBinder.DeathRecipient; 24 import android.os.Message; 25 import android.os.Process; 26 import android.os.RemoteException; 27 import android.os.ServiceManager; 28 import android.os.SystemProperties; 29 import android.telephony.Rlog; 30 import android.telephony.TelephonyManager; 31 32 import com.android.ims.internal.IImsCallSession; 33 import com.android.ims.internal.IImsEcbm; 34 import com.android.ims.internal.IImsEcbmListener; 35 import com.android.ims.internal.IImsRegistrationListener; 36 import com.android.ims.internal.IImsService; 37 import com.android.ims.internal.IImsUt; 38 import com.android.ims.internal.ImsCallSession; 39 import com.android.ims.internal.IImsConfig; 40 41 import 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 */ 51 public 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 /** 506 * Gets the call ID from the specified incoming call broadcast intent. 507 * 508 * @param incomingCallIntent the incoming call broadcast intent 509 * @return the call ID or null if the intent does not contain it 510 */ 511 private static String getCallId(Intent incomingCallIntent) { 512 if (incomingCallIntent == null) { 513 return null; 514 } 515 516 return incomingCallIntent.getStringExtra(EXTRA_CALL_ID); 517 } 518 519 /** 520 * Gets the service type from the specified incoming call broadcast intent. 521 * 522 * @param incomingCallIntent the incoming call broadcast intent 523 * @return the service identifier or -1 if the intent does not contain it 524 */ 525 private static int getServiceId(Intent incomingCallIntent) { 526 if (incomingCallIntent == null) { 527 return (-1); 528 } 529 530 return incomingCallIntent.getIntExtra(EXTRA_SERVICE_ID, -1); 531 } 532 533 /** 534 * Binds the IMS service only if the service is not created. 535 */ 536 private void checkAndThrowExceptionIfServiceUnavailable() 537 throws ImsException { 538 if (mImsService == null) { 539 createImsService(true); 540 541 if (mImsService == null) { 542 throw new ImsException("Service is unavailable", 543 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 544 } 545 } 546 } 547 548 private static String getImsServiceName(long subId) { 549 // TODO: MSIM implementation needs to decide on service name as a function of subId 550 // or value derived from subId (slot ID?) 551 return IMS_SERVICE; 552 } 553 554 /** 555 * Binds the IMS service to make/receive the call. 556 */ 557 private void createImsService(boolean checkService) { 558 if (checkService) { 559 IBinder binder = ServiceManager.checkService(getImsServiceName(mSubId)); 560 561 if (binder == null) { 562 return; 563 } 564 } 565 566 IBinder b = ServiceManager.getService(getImsServiceName(mSubId)); 567 568 if (b != null) { 569 try { 570 b.linkToDeath(mDeathRecipient, 0); 571 } catch (RemoteException e) { 572 } 573 } 574 575 mImsService = IImsService.Stub.asInterface(b); 576 } 577 578 /** 579 * Creates a {@link ImsCallSession} with the specified call profile. 580 * Use other methods, if applicable, instead of interacting with 581 * {@link ImsCallSession} directly. 582 * 583 * @param serviceId a service id which is obtained from {@link ImsManager#open} 584 * @param profile a call profile to make the call 585 */ 586 private ImsCallSession createCallSession(int serviceId, 587 ImsCallProfile profile) throws ImsException { 588 try { 589 return new ImsCallSession(mImsService.createCallSession(serviceId, profile, null)); 590 } catch (RemoteException e) { 591 return null; 592 } 593 } 594 595 private ImsRegistrationListenerProxy createRegistrationListenerProxy(int serviceClass, 596 ImsConnectionStateListener listener) { 597 ImsRegistrationListenerProxy proxy = 598 new ImsRegistrationListenerProxy(serviceClass, listener); 599 return proxy; 600 } 601 602 private void log(String s) { 603 Rlog.d(TAG, s); 604 } 605 606 private void loge(String s) { 607 Rlog.e(TAG, s); 608 } 609 610 private void loge(String s, Throwable t) { 611 Rlog.e(TAG, s, t); 612 } 613 614 /** 615 * Used for turning on IMS.if its off already 616 */ 617 public void turnOnIms() throws ImsException { 618 checkAndThrowExceptionIfServiceUnavailable(); 619 620 try { 621 mImsService.turnOnIms(); 622 } catch (RemoteException e) { 623 throw new ImsException("turnOnIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 624 } 625 } 626 627 public void setAdvanced4GMode(boolean turnOn) throws ImsException { 628 checkAndThrowExceptionIfServiceUnavailable(); 629 630 ImsConfig config = getConfigInterface(); 631 if (config != null) { 632 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, 633 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null); 634 config.setFeatureValue(ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE, 635 TelephonyManager.NETWORK_TYPE_LTE, turnOn ? 1 : 0, null); 636 } 637 638 if (turnOn) { 639 turnOnIms(); 640 } else if (mContext.getResources().getBoolean( 641 com.android.internal.R.bool.imsServiceAllowTurnOff)) { 642 log("setAdvanced4GMode() : imsServiceAllowTurnOff -> turnOffIms"); 643 turnOffIms(); 644 } 645 } 646 647 /** 648 * Used for turning off IMS completely in order to make the device CSFB'ed. 649 * Once turned off, all calls will be over CS. 650 */ 651 public void turnOffIms() throws ImsException { 652 checkAndThrowExceptionIfServiceUnavailable(); 653 654 try { 655 mImsService.turnOffIms(); 656 } catch (RemoteException e) { 657 throw new ImsException("turnOffIms() ", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 658 } 659 } 660 661 /** 662 * Death recipient class for monitoring IMS service. 663 */ 664 private class ImsServiceDeathRecipient implements IBinder.DeathRecipient { 665 @Override 666 public void binderDied() { 667 mImsService = null; 668 mUt = null; 669 mConfig = null; 670 mEcbm = null; 671 672 if (mContext != null) { 673 Intent intent = new Intent(ACTION_IMS_SERVICE_DOWN); 674 intent.putExtra(EXTRA_SUBID, mSubId); 675 mContext.sendBroadcast(new Intent(intent)); 676 } 677 } 678 } 679 680 /** 681 * Adapter class for {@link IImsRegistrationListener}. 682 */ 683 private class ImsRegistrationListenerProxy extends IImsRegistrationListener.Stub { 684 private int mServiceClass; 685 private ImsConnectionStateListener mListener; 686 687 public ImsRegistrationListenerProxy(int serviceClass, 688 ImsConnectionStateListener listener) { 689 mServiceClass = serviceClass; 690 mListener = listener; 691 } 692 693 public boolean isSameProxy(int serviceClass) { 694 return (mServiceClass == serviceClass); 695 } 696 697 @Override 698 public void registrationConnected() { 699 if (DBG) { 700 log("registrationConnected ::"); 701 } 702 703 if (mListener != null) { 704 mListener.onImsConnected(); 705 } 706 } 707 708 @Override 709 public void registrationDisconnected() { 710 if (DBG) { 711 log("registrationDisconnected ::"); 712 } 713 714 if (mListener != null) { 715 mListener.onImsDisconnected(); 716 } 717 } 718 719 @Override 720 public void registrationResumed() { 721 if (DBG) { 722 log("registrationResumed ::"); 723 } 724 725 if (mListener != null) { 726 mListener.onImsResumed(); 727 } 728 } 729 730 @Override 731 public void registrationSuspended() { 732 if (DBG) { 733 log("registrationSuspended ::"); 734 } 735 736 if (mListener != null) { 737 mListener.onImsSuspended(); 738 } 739 } 740 741 @Override 742 public void registrationServiceCapabilityChanged(int serviceClass, int event) { 743 log("registrationServiceCapabilityChanged :: serviceClass=" + 744 serviceClass + ", event=" + event); 745 746 if (mListener != null) { 747 mListener.onImsConnected(); 748 } 749 } 750 751 @Override 752 public void registrationFeatureCapabilityChanged(int serviceClass, 753 int[] enabledFeatures, int[] disabledFeatures) { 754 log("registrationFeatureCapabilityChanged :: serviceClass=" + 755 serviceClass); 756 if (mListener != null) { 757 mListener.onFeatureCapabilityChanged(serviceClass, 758 enabledFeatures, disabledFeatures); 759 } 760 } 761 762 } 763 /** 764 * Gets the ECBM interface to request ECBM exit. 765 * 766 * @param serviceId a service id which is obtained from {@link ImsManager#open} 767 * @return the ECBM interface instance 768 * @throws ImsException if getting the ECBM interface results in an error 769 */ 770 public ImsEcbm getEcbmInterface(int serviceId) throws ImsException { 771 if (mEcbm == null) { 772 checkAndThrowExceptionIfServiceUnavailable(); 773 774 try { 775 IImsEcbm iEcbm = mImsService.getEcbmInterface(serviceId); 776 777 if (iEcbm == null) { 778 throw new ImsException("getEcbmInterface()", 779 ImsReasonInfo.CODE_ECBM_NOT_SUPPORTED); 780 } 781 mEcbm = new ImsEcbm(iEcbm); 782 } catch (RemoteException e) { 783 throw new ImsException("getEcbmInterface()", e, 784 ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); 785 } 786 } 787 return mEcbm; 788 } 789 } 790