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