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