• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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