1 /* 2 * Copyright (C) 2017 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.content.Context; 20 import android.os.Binder; 21 import android.os.IBinder; 22 import android.os.IInterface; 23 import android.os.Message; 24 import android.os.RemoteException; 25 import android.telephony.ims.ImsCallProfile; 26 import android.telephony.ims.ImsService; 27 import android.telephony.ims.RtpHeaderExtensionType; 28 import android.telephony.ims.aidl.IImsCapabilityCallback; 29 import android.telephony.ims.aidl.IImsConfig; 30 import android.telephony.ims.aidl.IImsConfigCallback; 31 import android.telephony.ims.aidl.IImsMmTelFeature; 32 import android.telephony.ims.aidl.IImsRegistration; 33 import android.telephony.ims.aidl.IImsRegistrationCallback; 34 import android.telephony.ims.aidl.IImsSmsListener; 35 import android.telephony.ims.aidl.ISipTransport; 36 import android.telephony.ims.feature.CapabilityChangeRequest; 37 import android.telephony.ims.feature.MmTelFeature; 38 import android.telephony.ims.stub.ImsEcbmImplBase; 39 import android.telephony.ims.stub.ImsSmsImplBase; 40 import android.util.Log; 41 42 import com.android.ims.internal.IImsCallSession; 43 import com.android.ims.internal.IImsEcbm; 44 import com.android.ims.internal.IImsMultiEndpoint; 45 import com.android.ims.internal.IImsUt; 46 47 import java.util.ArrayList; 48 import java.util.Optional; 49 import java.util.Set; 50 51 /** 52 * A container of the IImsServiceController binder, which implements all of the ImsFeatures that 53 * the platform currently supports: MMTel 54 */ 55 56 public class MmTelFeatureConnection extends FeatureConnection { 57 protected static final String TAG = "MmTelFeatureConn"; 58 59 private class ImsRegistrationCallbackAdapter extends 60 ImsCallbackAdapterManager<IImsRegistrationCallback> { 61 ImsRegistrationCallbackAdapter(Context context, Object lock)62 public ImsRegistrationCallbackAdapter(Context context, Object lock) { 63 super(context, lock, mSlotId); 64 } 65 66 @Override registerCallback(IImsRegistrationCallback localCallback)67 public void registerCallback(IImsRegistrationCallback localCallback) { 68 IImsRegistration imsRegistration = getRegistration(); 69 if (imsRegistration != null) { 70 try { 71 imsRegistration.addRegistrationCallback(localCallback); 72 } catch (RemoteException e) { 73 throw new IllegalStateException("ImsRegistrationCallbackAdapter: MmTelFeature" 74 + " binder is dead."); 75 } 76 } else { 77 Log.e(TAG + " [" + mSlotId + "]", "ImsRegistrationCallbackAdapter: ImsRegistration" 78 + " is null"); 79 throw new IllegalStateException("ImsRegistrationCallbackAdapter: MmTelFeature is" 80 + "not available!"); 81 } 82 } 83 84 @Override unregisterCallback(IImsRegistrationCallback localCallback)85 public void unregisterCallback(IImsRegistrationCallback localCallback) { 86 IImsRegistration imsRegistration = getRegistration(); 87 if (imsRegistration != null) { 88 try { 89 imsRegistration.removeRegistrationCallback(localCallback); 90 } catch (RemoteException e) { 91 Log.w(TAG + " [" + mSlotId + "]", "ImsRegistrationCallbackAdapter -" 92 + " unregisterCallback: couldn't remove registration callback"); 93 } 94 } else { 95 Log.e(TAG + " [" + mSlotId + "]", "ImsRegistrationCallbackAdapter: ImsRegistration" 96 + " is null"); 97 } 98 } 99 } 100 101 private class CapabilityCallbackManager extends ImsCallbackAdapterManager<IImsCapabilityCallback> { 102 CapabilityCallbackManager(Context context, Object lock)103 public CapabilityCallbackManager(Context context, Object lock) { 104 super(context, lock, mSlotId); 105 } 106 107 @Override registerCallback(IImsCapabilityCallback localCallback)108 public void registerCallback(IImsCapabilityCallback localCallback) { 109 IImsMmTelFeature binder; 110 synchronized (mLock) { 111 try { 112 checkServiceIsReady(); 113 binder = getServiceInterface(mBinder); 114 } catch (RemoteException e) { 115 throw new IllegalStateException("CapabilityCallbackManager - MmTelFeature" 116 + " binder is dead."); 117 } 118 } 119 if (binder != null) { 120 try { 121 binder.addCapabilityCallback(localCallback); 122 } catch (RemoteException e) { 123 throw new IllegalStateException(" CapabilityCallbackManager - MmTelFeature" 124 + " binder is null."); 125 } 126 } else { 127 Log.w(TAG + " [" + mSlotId + "]", "CapabilityCallbackManager, register: Couldn't" 128 + " get binder"); 129 throw new IllegalStateException("CapabilityCallbackManager: MmTelFeature is" 130 + " not available!"); 131 } 132 } 133 134 @Override unregisterCallback(IImsCapabilityCallback localCallback)135 public void unregisterCallback(IImsCapabilityCallback localCallback) { 136 IImsMmTelFeature binder; 137 synchronized (mLock) { 138 try { 139 checkServiceIsReady(); 140 binder = getServiceInterface(mBinder); 141 } catch (RemoteException e) { 142 // binder is null 143 Log.w(TAG + " [" + mSlotId + "]", "CapabilityCallbackManager, unregister:" 144 + " couldn't get binder."); 145 return; 146 } 147 } 148 if (binder != null) { 149 try { 150 binder.removeCapabilityCallback(localCallback); 151 } catch (RemoteException e) { 152 Log.w(TAG + " [" + mSlotId + "]", "CapabilityCallbackManager, unregister:" 153 + " Binder is dead."); 154 } 155 } else { 156 Log.w(TAG + " [" + mSlotId + "]", "CapabilityCallbackManager, unregister:" 157 + " binder is null."); 158 } 159 } 160 } 161 162 private class ProvisioningCallbackManager extends ImsCallbackAdapterManager<IImsConfigCallback> { ProvisioningCallbackManager(Context context, Object lock)163 public ProvisioningCallbackManager (Context context, Object lock) { 164 super(context, lock, mSlotId); 165 } 166 167 @Override registerCallback(IImsConfigCallback localCallback)168 public void registerCallback(IImsConfigCallback localCallback) { 169 IImsConfig binder = getConfig(); 170 if (binder == null) { 171 // Config interface is not currently available. 172 Log.w(TAG + " [" + mSlotId + "]", "ProvisioningCallbackManager - couldn't register," 173 + " binder is null."); 174 throw new IllegalStateException("ImsConfig is not available!"); 175 } 176 try { 177 binder.addImsConfigCallback(localCallback); 178 }catch (RemoteException e) { 179 throw new IllegalStateException("ImsService is not available!"); 180 } 181 } 182 183 @Override unregisterCallback(IImsConfigCallback localCallback)184 public void unregisterCallback(IImsConfigCallback localCallback) { 185 IImsConfig binder = getConfig(); 186 if (binder == null) { 187 Log.w(TAG + " [" + mSlotId + "]", "ProvisioningCallbackManager - couldn't" 188 + " unregister, binder is null."); 189 return; 190 } 191 try { 192 binder.removeImsConfigCallback(localCallback); 193 } catch (RemoteException e) { 194 Log.w(TAG + " [" + mSlotId + "]", "ProvisioningCallbackManager - couldn't" 195 + " unregister, binder is dead."); 196 } 197 } 198 } 199 200 private static final class BinderAccessState<T> { 201 /** 202 * We have not tried to get the interface yet. 203 */ 204 static final int STATE_NOT_SET = 0; 205 /** 206 * We have tried to get the interface, but it is not supported. 207 */ 208 static final int STATE_NOT_SUPPORTED = 1; 209 /** 210 * The interface is available from the service. 211 */ 212 static final int STATE_AVAILABLE = 2; 213 of(T value)214 public static <T> BinderAccessState<T> of(T value) { 215 return new BinderAccessState<>(value); 216 } 217 218 private final int mState; 219 private final T mInterface; 220 BinderAccessState(int state)221 public BinderAccessState(int state) { 222 mState = state; 223 mInterface = null; 224 } 225 BinderAccessState(T binderInterface)226 public BinderAccessState(T binderInterface) { 227 mState = STATE_AVAILABLE; 228 mInterface = binderInterface; 229 } 230 getState()231 public int getState() { 232 return mState; 233 } 234 getInterface()235 public T getInterface() { 236 return mInterface; 237 } 238 } 239 240 // Updated by IImsServiceFeatureCallback when FEATURE_EMERGENCY_MMTEL is sent. 241 private boolean mSupportsEmergencyCalling = false; 242 private BinderAccessState<ImsEcbm> mEcbm = 243 new BinderAccessState<>(BinderAccessState.STATE_NOT_SET); 244 private BinderAccessState<ImsMultiEndpoint> mMultiEndpoint = 245 new BinderAccessState<>(BinderAccessState.STATE_NOT_SET); 246 private MmTelFeature.Listener mMmTelFeatureListener; 247 private ImsUt mUt; 248 249 private final ImsRegistrationCallbackAdapter mRegistrationCallbackManager; 250 private final CapabilityCallbackManager mCapabilityCallbackManager; 251 private final ProvisioningCallbackManager mProvisioningCallbackManager; 252 MmTelFeatureConnection(Context context, int slotId, IImsMmTelFeature f, IImsConfig c, IImsRegistration r, ISipTransport s)253 public MmTelFeatureConnection(Context context, int slotId, IImsMmTelFeature f, 254 IImsConfig c, IImsRegistration r, ISipTransport s) { 255 super(context, slotId, c, r, s); 256 257 setBinder((f != null) ? f.asBinder() : null); 258 mRegistrationCallbackManager = new ImsRegistrationCallbackAdapter(context, mLock); 259 mCapabilityCallbackManager = new CapabilityCallbackManager(context, mLock); 260 mProvisioningCallbackManager = new ProvisioningCallbackManager(context, mLock); 261 } 262 263 @Override onRemovedOrDied()264 protected void onRemovedOrDied() { 265 // Release all callbacks being tracked and unregister them from the connected MmTelFeature. 266 mRegistrationCallbackManager.close(); 267 mCapabilityCallbackManager.close(); 268 mProvisioningCallbackManager.close(); 269 // Close mUt interface separately from other listeners, as it is not tied directly to 270 // calling. There is still a limitation currently that only one UT listener can be set 271 // (through ImsPhoneCallTracker), but this could be relaxed in the future via the ability 272 // to register multiple callbacks. 273 synchronized (mLock) { 274 if (mUt != null) { 275 mUt.close(); 276 mUt = null; 277 } 278 closeConnection(); 279 super.onRemovedOrDied(); 280 } 281 } 282 isEmergencyMmTelAvailable()283 public boolean isEmergencyMmTelAvailable() { 284 return mSupportsEmergencyCalling; 285 } 286 287 /** 288 * Opens the connection to the {@link MmTelFeature} and establishes a listener back to the 289 * framework. Calling this method multiple times will reset the listener attached to the 290 * {@link MmTelFeature}. 291 * @param mmTelListener A {@link MmTelFeature.Listener} that will be used by the 292 * {@link MmTelFeature} to notify the framework of mmtel calling updates. 293 * @param ecbmListener Listener used to listen for ECBM updates from {@link ImsEcbmImplBase} 294 * implementation. 295 */ openConnection(MmTelFeature.Listener mmTelListener, ImsEcbmStateListener ecbmListener, ImsExternalCallStateListener multiEndpointListener)296 public void openConnection(MmTelFeature.Listener mmTelListener, 297 ImsEcbmStateListener ecbmListener, 298 ImsExternalCallStateListener multiEndpointListener) throws RemoteException { 299 synchronized (mLock) { 300 checkServiceIsReady(); 301 mMmTelFeatureListener = mmTelListener; 302 getServiceInterface(mBinder).setListener(mmTelListener); 303 setEcbmInterface(ecbmListener); 304 setMultiEndpointInterface(multiEndpointListener); 305 } 306 } 307 308 /** 309 * Closes the connection to the {@link MmTelFeature} if it was previously opened via 310 * {@link #openConnection} by removing all listeners. 311 */ closeConnection()312 public void closeConnection() { 313 synchronized (mLock) { 314 if (!isBinderAlive()) return; 315 try { 316 if (mMmTelFeatureListener != null) { 317 mMmTelFeatureListener = null; 318 getServiceInterface(mBinder).setListener(null); 319 } 320 if (mEcbm.getState() == BinderAccessState.STATE_AVAILABLE) { 321 mEcbm.getInterface().setEcbmStateListener(null); 322 mEcbm = new BinderAccessState<>(BinderAccessState.STATE_NOT_SET); 323 } 324 if (mMultiEndpoint.getState() == BinderAccessState.STATE_AVAILABLE) { 325 mMultiEndpoint.getInterface().setExternalCallStateListener(null); 326 mMultiEndpoint = new BinderAccessState<>(BinderAccessState.STATE_NOT_SET); 327 } 328 } catch (RemoteException e) { 329 Log.w(TAG + " [" + mSlotId + "]", "closeConnection: couldn't remove listeners!"); 330 } 331 } 332 } 333 addRegistrationCallback(IImsRegistrationCallback callback)334 public void addRegistrationCallback(IImsRegistrationCallback callback) { 335 mRegistrationCallbackManager.addCallback(callback); 336 } 337 addRegistrationCallbackForSubscription(IImsRegistrationCallback callback, int subId)338 public void addRegistrationCallbackForSubscription(IImsRegistrationCallback callback, 339 int subId) { 340 mRegistrationCallbackManager.addCallbackForSubscription(callback , subId); 341 } 342 removeRegistrationCallback(IImsRegistrationCallback callback)343 public void removeRegistrationCallback(IImsRegistrationCallback callback) { 344 mRegistrationCallbackManager.removeCallback(callback); 345 } 346 removeRegistrationCallbackForSubscription(IImsRegistrationCallback callback, int subId)347 public void removeRegistrationCallbackForSubscription(IImsRegistrationCallback callback, 348 int subId) { 349 mRegistrationCallbackManager.removeCallbackForSubscription(callback, subId); 350 } 351 addCapabilityCallback(IImsCapabilityCallback callback)352 public void addCapabilityCallback(IImsCapabilityCallback callback) { 353 mCapabilityCallbackManager.addCallback(callback); 354 } 355 addCapabilityCallbackForSubscription(IImsCapabilityCallback callback, int subId)356 public void addCapabilityCallbackForSubscription(IImsCapabilityCallback callback, 357 int subId) { 358 mCapabilityCallbackManager.addCallbackForSubscription(callback, subId); 359 } 360 removeCapabilityCallback(IImsCapabilityCallback callback)361 public void removeCapabilityCallback(IImsCapabilityCallback callback) { 362 mCapabilityCallbackManager.removeCallback(callback); 363 } 364 removeCapabilityCallbackForSubscription(IImsCapabilityCallback callback, int subId)365 public void removeCapabilityCallbackForSubscription(IImsCapabilityCallback callback, 366 int subId) { 367 mCapabilityCallbackManager.removeCallbackForSubscription(callback , subId); 368 } 369 addProvisioningCallbackForSubscription(IImsConfigCallback callback, int subId)370 public void addProvisioningCallbackForSubscription(IImsConfigCallback callback, 371 int subId) { 372 mProvisioningCallbackManager.addCallbackForSubscription(callback, subId); 373 } 374 removeProvisioningCallbackForSubscription(IImsConfigCallback callback, int subId)375 public void removeProvisioningCallbackForSubscription(IImsConfigCallback callback, 376 int subId) { 377 mProvisioningCallbackManager.removeCallbackForSubscription(callback , subId); 378 } 379 changeEnabledCapabilities(CapabilityChangeRequest request, IImsCapabilityCallback callback)380 public void changeEnabledCapabilities(CapabilityChangeRequest request, 381 IImsCapabilityCallback callback) throws RemoteException { 382 synchronized (mLock) { 383 checkServiceIsReady(); 384 getServiceInterface(mBinder).changeCapabilitiesConfiguration(request, callback); 385 } 386 } 387 queryEnabledCapabilities(int capability, int radioTech, IImsCapabilityCallback callback)388 public void queryEnabledCapabilities(int capability, int radioTech, 389 IImsCapabilityCallback callback) throws RemoteException { 390 synchronized (mLock) { 391 checkServiceIsReady(); 392 getServiceInterface(mBinder).queryCapabilityConfiguration(capability, radioTech, 393 callback); 394 } 395 } 396 queryCapabilityStatus()397 public MmTelFeature.MmTelCapabilities queryCapabilityStatus() throws RemoteException { 398 synchronized (mLock) { 399 checkServiceIsReady(); 400 return new MmTelFeature.MmTelCapabilities( 401 getServiceInterface(mBinder).queryCapabilityStatus()); 402 } 403 } 404 createCallProfile(int callServiceType, int callType)405 public ImsCallProfile createCallProfile(int callServiceType, int callType) 406 throws RemoteException { 407 synchronized (mLock) { 408 checkServiceIsReady(); 409 return getServiceInterface(mBinder).createCallProfile(callServiceType, callType); 410 } 411 } 412 changeOfferedRtpHeaderExtensionTypes(Set<RtpHeaderExtensionType> types)413 public void changeOfferedRtpHeaderExtensionTypes(Set<RtpHeaderExtensionType> types) 414 throws RemoteException { 415 synchronized (mLock) { 416 checkServiceIsReady(); 417 getServiceInterface(mBinder).changeOfferedRtpHeaderExtensionTypes( 418 new ArrayList<>(types)); 419 } 420 } 421 createCallSession(ImsCallProfile profile)422 public IImsCallSession createCallSession(ImsCallProfile profile) 423 throws RemoteException { 424 synchronized (mLock) { 425 checkServiceIsReady(); 426 return getServiceInterface(mBinder).createCallSession(profile); 427 } 428 } 429 createOrGetUtInterface()430 public ImsUt createOrGetUtInterface() throws RemoteException { 431 synchronized (mLock) { 432 if (mUt != null) return mUt; 433 434 checkServiceIsReady(); 435 IImsUt imsUt = getServiceInterface(mBinder).getUtInterface(); 436 // This will internally set up a listener on the ImsUtImplBase interface, and there is 437 // a limitation that there can only be one. If multiple connections try to create this 438 // UT interface, it will throw an IllegalStateException. 439 mUt = (imsUt != null) ? new ImsUt(imsUt) : null; 440 return mUt; 441 } 442 } 443 setEcbmInterface(ImsEcbmStateListener ecbmListener)444 private void setEcbmInterface(ImsEcbmStateListener ecbmListener) throws RemoteException { 445 synchronized (mLock) { 446 if (mEcbm.getState() != BinderAccessState.STATE_NOT_SET) { 447 throw new IllegalStateException("ECBM interface already open"); 448 } 449 450 checkServiceIsReady(); 451 IImsEcbm imsEcbm = getServiceInterface(mBinder).getEcbmInterface(); 452 mEcbm = (imsEcbm != null) ? BinderAccessState.of(new ImsEcbm(imsEcbm)) : 453 new BinderAccessState<>(BinderAccessState.STATE_NOT_SUPPORTED); 454 if (mEcbm.getState() == BinderAccessState.STATE_AVAILABLE) { 455 // May throw an IllegalStateException if a listener already exists. 456 mEcbm.getInterface().setEcbmStateListener(ecbmListener); 457 } 458 } 459 } 460 getEcbmInterface()461 public ImsEcbm getEcbmInterface() { 462 synchronized (mLock) { 463 if (mEcbm.getState() == BinderAccessState.STATE_NOT_SET) { 464 throw new IllegalStateException("ECBM interface has not been opened"); 465 } 466 467 return mEcbm.getState() == BinderAccessState.STATE_AVAILABLE ? 468 mEcbm.getInterface() : null; 469 } 470 } 471 setUiTTYMode(int uiTtyMode, Message onComplete)472 public void setUiTTYMode(int uiTtyMode, Message onComplete) 473 throws RemoteException { 474 synchronized (mLock) { 475 checkServiceIsReady(); 476 getServiceInterface(mBinder).setUiTtyMode(uiTtyMode, onComplete); 477 } 478 } 479 setMultiEndpointInterface(ImsExternalCallStateListener listener)480 private void setMultiEndpointInterface(ImsExternalCallStateListener listener) 481 throws RemoteException { 482 synchronized (mLock) { 483 if (mMultiEndpoint.getState() != BinderAccessState.STATE_NOT_SET) { 484 throw new IllegalStateException("multiendpoint interface is already open"); 485 } 486 487 checkServiceIsReady(); 488 IImsMultiEndpoint imEndpoint = getServiceInterface(mBinder).getMultiEndpointInterface(); 489 mMultiEndpoint = (imEndpoint != null) 490 ? BinderAccessState.of(new ImsMultiEndpoint(imEndpoint)) : 491 new BinderAccessState<>(BinderAccessState.STATE_NOT_SUPPORTED); 492 if (mMultiEndpoint.getState() == BinderAccessState.STATE_AVAILABLE) { 493 // May throw an IllegalStateException if a listener already exists. 494 mMultiEndpoint.getInterface().setExternalCallStateListener(listener); 495 } 496 } 497 } 498 sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, byte[] pdu)499 public void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, 500 byte[] pdu) throws RemoteException { 501 synchronized (mLock) { 502 checkServiceIsReady(); 503 getServiceInterface(mBinder).sendSms(token, messageRef, format, smsc, isRetry, 504 pdu); 505 } 506 } 507 acknowledgeSms(int token, int messageRef, @ImsSmsImplBase.SendStatusResult int result)508 public void acknowledgeSms(int token, int messageRef, 509 @ImsSmsImplBase.SendStatusResult int result) throws RemoteException { 510 synchronized (mLock) { 511 checkServiceIsReady(); 512 getServiceInterface(mBinder).acknowledgeSms(token, messageRef, result); 513 } 514 } 515 acknowledgeSmsReport(int token, int messageRef, @ImsSmsImplBase.StatusReportResult int result)516 public void acknowledgeSmsReport(int token, int messageRef, 517 @ImsSmsImplBase.StatusReportResult int result) throws RemoteException { 518 synchronized (mLock) { 519 checkServiceIsReady(); 520 getServiceInterface(mBinder).acknowledgeSmsReport(token, messageRef, result); 521 } 522 } 523 getSmsFormat()524 public String getSmsFormat() throws RemoteException { 525 synchronized (mLock) { 526 checkServiceIsReady(); 527 return getServiceInterface(mBinder).getSmsFormat(); 528 } 529 } 530 onSmsReady()531 public void onSmsReady() throws RemoteException { 532 synchronized (mLock) { 533 checkServiceIsReady(); 534 getServiceInterface(mBinder).onSmsReady(); 535 } 536 } 537 setSmsListener(IImsSmsListener listener)538 public void setSmsListener(IImsSmsListener listener) throws RemoteException { 539 synchronized (mLock) { 540 checkServiceIsReady(); 541 getServiceInterface(mBinder).setSmsListener(listener); 542 } 543 } 544 shouldProcessCall(boolean isEmergency, String[] numbers)545 public @MmTelFeature.ProcessCallResult int shouldProcessCall(boolean isEmergency, 546 String[] numbers) throws RemoteException { 547 if (isEmergency && !isEmergencyMmTelAvailable()) { 548 // Don't query the ImsService if emergency calling is not available on the ImsService. 549 Log.i(TAG + " [" + mSlotId + "]", "MmTel does not support emergency over IMS, fallback" 550 + " to CS."); 551 return MmTelFeature.PROCESS_CALL_CSFB; 552 } 553 synchronized (mLock) { 554 checkServiceIsReady(); 555 return getServiceInterface(mBinder).shouldProcessCall(numbers); 556 } 557 } 558 559 @Override retrieveFeatureState()560 protected Integer retrieveFeatureState() { 561 if (mBinder != null) { 562 try { 563 return getServiceInterface(mBinder).getFeatureState(); 564 } catch (RemoteException e) { 565 // Status check failed, don't update cache 566 } 567 } 568 return null; 569 } 570 571 @Override onFeatureCapabilitiesUpdated(long capabilities)572 public void onFeatureCapabilitiesUpdated(long capabilities) 573 { 574 synchronized (mLock) { 575 mSupportsEmergencyCalling = 576 ((capabilities | ImsService.CAPABILITY_EMERGENCY_OVER_MMTEL) > 0); 577 } 578 } 579 getServiceInterface(IBinder b)580 private IImsMmTelFeature getServiceInterface(IBinder b) { 581 return IImsMmTelFeature.Stub.asInterface(b); 582 } 583 } 584