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