| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| |
| package com.android.ims; |
| |
| import android.content.Context; |
| import android.os.Binder; |
| import android.os.IBinder; |
| import android.os.IInterface; |
| import android.os.Message; |
| import android.os.RemoteException; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.ims.ImsCallProfile; |
| import android.telephony.ims.ImsService; |
| import android.telephony.ims.MediaQualityStatus; |
| import android.telephony.ims.MediaThreshold; |
| import android.telephony.ims.RtpHeaderExtensionType; |
| import android.telephony.ims.aidl.IImsCapabilityCallback; |
| import android.telephony.ims.aidl.IImsConfig; |
| import android.telephony.ims.aidl.IImsConfigCallback; |
| import android.telephony.ims.aidl.IImsMmTelFeature; |
| import android.telephony.ims.aidl.IImsRegistration; |
| import android.telephony.ims.aidl.IImsRegistrationCallback; |
| import android.telephony.ims.aidl.IImsSmsListener; |
| import android.telephony.ims.aidl.ISipTransport; |
| import android.telephony.ims.aidl.ISrvccStartedCallback; |
| import android.telephony.ims.feature.CapabilityChangeRequest; |
| import android.telephony.ims.feature.MmTelFeature; |
| import android.telephony.ims.stub.ImsEcbmImplBase; |
| import android.telephony.ims.stub.ImsRegistrationImplBase; |
| import android.telephony.ims.stub.ImsSmsImplBase; |
| import android.util.Log; |
| import android.util.SparseArray; |
| |
| import com.android.ims.internal.IImsCallSession; |
| import com.android.ims.internal.IImsEcbm; |
| import com.android.ims.internal.IImsMultiEndpoint; |
| import com.android.ims.internal.IImsUt; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Set; |
| |
| /** |
| * A container of the IImsServiceController binder, which implements all of the ImsFeatures that |
| * the platform currently supports: MMTel |
| */ |
| |
| public class MmTelFeatureConnection extends FeatureConnection { |
| protected static final String TAG = "MmTelFeatureConn"; |
| |
| private class ImsRegistrationCallbackAdapter extends |
| ImsCallbackAdapterManager<IImsRegistrationCallback> { |
| |
| public ImsRegistrationCallbackAdapter(Context context, Object lock) { |
| super(context, lock, mSlotId, mSubId); |
| } |
| |
| @Override |
| public void registerCallback(IImsRegistrationCallback localCallback) { |
| IImsRegistration imsRegistration = getRegistration(); |
| if (imsRegistration != null) { |
| try { |
| imsRegistration.addRegistrationCallback(localCallback); |
| } catch (RemoteException e) { |
| throw new IllegalStateException("ImsRegistrationCallbackAdapter: MmTelFeature" |
| + " binder is dead."); |
| } |
| } else { |
| Log.e(TAG + " [" + mSlotId + "]", "ImsRegistrationCallbackAdapter: ImsRegistration" |
| + " is null"); |
| throw new IllegalStateException("ImsRegistrationCallbackAdapter: MmTelFeature is" |
| + "not available!"); |
| } |
| } |
| |
| @Override |
| public void unregisterCallback(IImsRegistrationCallback localCallback) { |
| IImsRegistration imsRegistration = getRegistration(); |
| if (imsRegistration != null) { |
| try { |
| imsRegistration.removeRegistrationCallback(localCallback); |
| } catch (RemoteException | IllegalStateException e) { |
| Log.w(TAG + " [" + mSlotId + "]", "ImsRegistrationCallbackAdapter -" |
| + " unregisterCallback: couldn't remove registration callback" |
| + " Exception: " + e.getMessage()); |
| } |
| } else { |
| Log.e(TAG + " [" + mSlotId + "]", "ImsRegistrationCallbackAdapter: ImsRegistration" |
| + " is null"); |
| } |
| } |
| } |
| |
| private class CapabilityCallbackManager extends ImsCallbackAdapterManager<IImsCapabilityCallback> { |
| public CapabilityCallbackManager(Context context, Object lock) { |
| super(context, lock, mSlotId, mSubId); |
| } |
| |
| @Override |
| public void registerCallback(IImsCapabilityCallback localCallback) { |
| IImsMmTelFeature binder; |
| synchronized (mLock) { |
| try { |
| checkServiceIsReady(); |
| binder = getServiceInterface(mBinder); |
| } catch (RemoteException e) { |
| throw new IllegalStateException("CapabilityCallbackManager - MmTelFeature" |
| + " binder is dead."); |
| } |
| } |
| if (binder != null) { |
| try { |
| binder.addCapabilityCallback(localCallback); |
| } catch (RemoteException e) { |
| throw new IllegalStateException(" CapabilityCallbackManager - MmTelFeature" |
| + " binder is null."); |
| } |
| } else { |
| Log.w(TAG + " [" + mSlotId + "]", "CapabilityCallbackManager, register: Couldn't" |
| + " get binder"); |
| throw new IllegalStateException("CapabilityCallbackManager: MmTelFeature is" |
| + " not available!"); |
| } |
| } |
| |
| @Override |
| public void unregisterCallback(IImsCapabilityCallback localCallback) { |
| IImsMmTelFeature binder; |
| synchronized (mLock) { |
| if (!isBinderAlive()) { |
| Log.w(TAG + " [" + mSlotId + "]", "CapabilityCallbackManager, unregister:" |
| + " binder is not alive"); |
| return; |
| } |
| binder = getServiceInterface(mBinder); |
| } |
| if (binder != null) { |
| try { |
| binder.removeCapabilityCallback(localCallback); |
| } catch (RemoteException | IllegalStateException e) { |
| Log.w(TAG + " [" + mSlotId + "]", "CapabilityCallbackManager, unregister:" |
| + " Binder is dead. Exception: " + e.getMessage()); |
| } |
| } else { |
| Log.w(TAG + " [" + mSlotId + "]", "CapabilityCallbackManager, unregister:" |
| + " binder is null."); |
| } |
| } |
| } |
| |
| private class ProvisioningCallbackManager extends ImsCallbackAdapterManager<IImsConfigCallback> { |
| public ProvisioningCallbackManager (Context context, Object lock) { |
| super(context, lock, mSlotId, mSubId); |
| } |
| |
| @Override |
| public void registerCallback(IImsConfigCallback localCallback) { |
| IImsConfig binder = getConfig(); |
| if (binder == null) { |
| // Config interface is not currently available. |
| Log.w(TAG + " [" + mSlotId + "]", "ProvisioningCallbackManager - couldn't register," |
| + " binder is null."); |
| throw new IllegalStateException("ImsConfig is not available!"); |
| } |
| try { |
| binder.addImsConfigCallback(localCallback); |
| }catch (RemoteException e) { |
| throw new IllegalStateException("ImsService is not available!"); |
| } |
| } |
| |
| @Override |
| public void unregisterCallback(IImsConfigCallback localCallback) { |
| IImsConfig binder = getConfig(); |
| if (binder == null) { |
| Log.w(TAG + " [" + mSlotId + "]", "ProvisioningCallbackManager - couldn't" |
| + " unregister, binder is null."); |
| return; |
| } |
| try { |
| binder.removeImsConfigCallback(localCallback); |
| } catch (RemoteException | IllegalStateException e) { |
| Log.w(TAG + " [" + mSlotId + "]", "ProvisioningCallbackManager - couldn't" |
| + " unregister, binder is dead. Exception: " + e.getMessage()); |
| } |
| } |
| } |
| |
| private static final class BinderAccessState<T> { |
| /** |
| * We have not tried to get the interface yet. |
| */ |
| static final int STATE_NOT_SET = 0; |
| /** |
| * We have tried to get the interface, but it is not supported. |
| */ |
| static final int STATE_NOT_SUPPORTED = 1; |
| /** |
| * The interface is available from the service. |
| */ |
| static final int STATE_AVAILABLE = 2; |
| |
| public static <T> BinderAccessState<T> of(T value) { |
| return new BinderAccessState<>(value); |
| } |
| |
| private final int mState; |
| private final T mInterface; |
| |
| public BinderAccessState(int state) { |
| mState = state; |
| mInterface = null; |
| } |
| |
| public BinderAccessState(T binderInterface) { |
| mState = STATE_AVAILABLE; |
| mInterface = binderInterface; |
| } |
| |
| public int getState() { |
| return mState; |
| } |
| |
| public T getInterface() { |
| return mInterface; |
| } |
| } |
| |
| // Updated by IImsServiceFeatureCallback when FEATURE_EMERGENCY_MMTEL is sent. |
| private boolean mSupportsEmergencyCalling = false; |
| private BinderAccessState<ImsEcbm> mEcbm = |
| new BinderAccessState<>(BinderAccessState.STATE_NOT_SET); |
| private BinderAccessState<ImsMultiEndpoint> mMultiEndpoint = |
| new BinderAccessState<>(BinderAccessState.STATE_NOT_SET); |
| private MmTelFeature.Listener mMmTelFeatureListener; |
| private ImsUt mUt; |
| |
| private final ImsRegistrationCallbackAdapter mRegistrationCallbackManager; |
| private final CapabilityCallbackManager mCapabilityCallbackManager; |
| private final ProvisioningCallbackManager mProvisioningCallbackManager; |
| |
| public MmTelFeatureConnection(Context context, int slotId, int subId, IImsMmTelFeature f, |
| IImsConfig c, IImsRegistration r, ISipTransport s) { |
| super(context, slotId, subId, c, r, s); |
| |
| setBinder((f != null) ? f.asBinder() : null); |
| mRegistrationCallbackManager = new ImsRegistrationCallbackAdapter(context, mLock); |
| mCapabilityCallbackManager = new CapabilityCallbackManager(context, mLock); |
| mProvisioningCallbackManager = new ProvisioningCallbackManager(context, mLock); |
| } |
| |
| @Override |
| protected void onRemovedOrDied() { |
| // Release all callbacks being tracked and unregister them from the connected MmTelFeature. |
| mRegistrationCallbackManager.close(); |
| mCapabilityCallbackManager.close(); |
| mProvisioningCallbackManager.close(); |
| // Close mUt interface separately from other listeners, as it is not tied directly to |
| // calling. There is still a limitation currently that only one UT listener can be set |
| // (through ImsPhoneCallTracker), but this could be relaxed in the future via the ability |
| // to register multiple callbacks. |
| synchronized (mLock) { |
| if (mUt != null) { |
| mUt.close(); |
| mUt = null; |
| } |
| closeConnection(); |
| super.onRemovedOrDied(); |
| } |
| } |
| |
| public boolean isEmergencyMmTelAvailable() { |
| return mSupportsEmergencyCalling; |
| } |
| |
| /** |
| * Opens the connection to the {@link MmTelFeature} and establishes a listener back to the |
| * framework. Calling this method multiple times will reset the listener attached to the |
| * {@link MmTelFeature}. |
| * @param mmTelListener A {@link MmTelFeature.Listener} that will be used by the |
| * {@link MmTelFeature} to notify the framework of mmtel calling updates. |
| * @param ecbmListener Listener used to listen for ECBM updates from {@link ImsEcbmImplBase} |
| * implementation. |
| */ |
| public void openConnection(MmTelFeature.Listener mmTelListener, |
| ImsEcbmStateListener ecbmListener, |
| ImsExternalCallStateListener multiEndpointListener) throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| mMmTelFeatureListener = mmTelListener; |
| getServiceInterface(mBinder).setListener(mmTelListener); |
| setEcbmInterface(ecbmListener); |
| setMultiEndpointInterface(multiEndpointListener); |
| } |
| } |
| |
| /** |
| * Closes the connection to the {@link MmTelFeature} if it was previously opened via |
| * {@link #openConnection} by removing all listeners. |
| */ |
| public void closeConnection() { |
| synchronized (mLock) { |
| if (!isBinderAlive()) return; |
| try { |
| if (mMmTelFeatureListener != null) { |
| mMmTelFeatureListener = null; |
| getServiceInterface(mBinder).setListener(null); |
| } |
| if (mEcbm.getState() == BinderAccessState.STATE_AVAILABLE) { |
| mEcbm.getInterface().setEcbmStateListener(null); |
| mEcbm = new BinderAccessState<>(BinderAccessState.STATE_NOT_SET); |
| } |
| if (mMultiEndpoint.getState() == BinderAccessState.STATE_AVAILABLE) { |
| mMultiEndpoint.getInterface().setExternalCallStateListener(null); |
| mMultiEndpoint = new BinderAccessState<>(BinderAccessState.STATE_NOT_SET); |
| } |
| } catch (RemoteException | IllegalStateException e) { |
| Log.w(TAG + " [" + mSlotId + "]", "closeConnection: couldn't remove listeners!" + |
| " Exception: " + e.getMessage()); |
| } |
| } |
| } |
| |
| public void addRegistrationCallback(IImsRegistrationCallback callback) { |
| mRegistrationCallbackManager.addCallback(callback); |
| } |
| |
| public void addRegistrationCallbackForSubscription(IImsRegistrationCallback callback, |
| int subId) { |
| mRegistrationCallbackManager.addCallbackForSubscription(callback , subId); |
| } |
| |
| public void removeRegistrationCallback(IImsRegistrationCallback callback) { |
| mRegistrationCallbackManager.removeCallback(callback); |
| } |
| |
| public void removeRegistrationCallbackForSubscription(IImsRegistrationCallback callback, |
| int subId) { |
| mRegistrationCallbackManager.removeCallback(callback); |
| } |
| |
| public void addCapabilityCallback(IImsCapabilityCallback callback) { |
| mCapabilityCallbackManager.addCallback(callback); |
| } |
| |
| public void addCapabilityCallbackForSubscription(IImsCapabilityCallback callback, |
| int subId) { |
| mCapabilityCallbackManager.addCallbackForSubscription(callback, subId); |
| } |
| |
| public void removeCapabilityCallback(IImsCapabilityCallback callback) { |
| mCapabilityCallbackManager.removeCallback(callback); |
| } |
| |
| public void removeCapabilityCallbackForSubscription(IImsCapabilityCallback callback, |
| int subId) { |
| mCapabilityCallbackManager.removeCallback(callback); |
| } |
| |
| public void addProvisioningCallbackForSubscription(IImsConfigCallback callback, |
| int subId) { |
| mProvisioningCallbackManager.addCallbackForSubscription(callback, subId); |
| } |
| |
| public void removeProvisioningCallbackForSubscription(IImsConfigCallback callback, |
| int subId) { |
| mProvisioningCallbackManager.removeCallback(callback); |
| } |
| |
| public void setMediaThreshold(@MediaQualityStatus.MediaSessionType int sessionType, |
| MediaThreshold threshold) throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).setMediaQualityThreshold(sessionType, threshold); |
| } |
| } |
| |
| public MediaQualityStatus queryMediaQualityStatus( |
| @MediaQualityStatus.MediaSessionType int sessionType) throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| return getServiceInterface(mBinder).queryMediaQualityStatus(sessionType); |
| } |
| } |
| |
| public void changeEnabledCapabilities(CapabilityChangeRequest request, |
| IImsCapabilityCallback callback) throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).changeCapabilitiesConfiguration(request, callback); |
| } |
| } |
| |
| public void queryEnabledCapabilities(int capability, int radioTech, |
| IImsCapabilityCallback callback) throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).queryCapabilityConfiguration(capability, radioTech, |
| callback); |
| } |
| } |
| |
| public MmTelFeature.MmTelCapabilities queryCapabilityStatus() throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| return new MmTelFeature.MmTelCapabilities( |
| getServiceInterface(mBinder).queryCapabilityStatus()); |
| } |
| } |
| |
| public ImsCallProfile createCallProfile(int callServiceType, int callType) |
| throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| return getServiceInterface(mBinder).createCallProfile(callServiceType, callType); |
| } |
| } |
| |
| public void changeOfferedRtpHeaderExtensionTypes(Set<RtpHeaderExtensionType> types) |
| throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).changeOfferedRtpHeaderExtensionTypes( |
| new ArrayList<>(types)); |
| } |
| } |
| |
| public IImsCallSession createCallSession(ImsCallProfile profile) |
| throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| return getServiceInterface(mBinder).createCallSession(profile); |
| } |
| } |
| |
| public ImsUt createOrGetUtInterface() throws RemoteException { |
| synchronized (mLock) { |
| if (mUt != null) return mUt; |
| |
| checkServiceIsReady(); |
| IImsUt imsUt = getServiceInterface(mBinder).getUtInterface(); |
| // This will internally set up a listener on the ImsUtImplBase interface, and there is |
| // a limitation that there can only be one. If multiple connections try to create this |
| // UT interface, it will throw an IllegalStateException. |
| mUt = (imsUt != null) ? new ImsUt(imsUt, mContext.getMainExecutor()) : null; |
| return mUt; |
| } |
| } |
| |
| private void setEcbmInterface(ImsEcbmStateListener ecbmListener) throws RemoteException { |
| synchronized (mLock) { |
| if (mEcbm.getState() != BinderAccessState.STATE_NOT_SET) { |
| throw new IllegalStateException("ECBM interface already open"); |
| } |
| |
| checkServiceIsReady(); |
| IImsEcbm imsEcbm = getServiceInterface(mBinder).getEcbmInterface(); |
| mEcbm = (imsEcbm != null) ? BinderAccessState.of(new ImsEcbm(imsEcbm)) : |
| new BinderAccessState<>(BinderAccessState.STATE_NOT_SUPPORTED); |
| if (mEcbm.getState() == BinderAccessState.STATE_AVAILABLE) { |
| // May throw an IllegalStateException if a listener already exists. |
| mEcbm.getInterface().setEcbmStateListener(ecbmListener); |
| } |
| } |
| } |
| |
| public ImsEcbm getEcbmInterface() { |
| synchronized (mLock) { |
| if (mEcbm.getState() == BinderAccessState.STATE_NOT_SET) { |
| throw new IllegalStateException("ECBM interface has not been opened"); |
| } |
| |
| return mEcbm.getState() == BinderAccessState.STATE_AVAILABLE ? |
| mEcbm.getInterface() : null; |
| } |
| } |
| |
| public void setUiTTYMode(int uiTtyMode, Message onComplete) |
| throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).setUiTtyMode(uiTtyMode, onComplete); |
| } |
| } |
| |
| private void setMultiEndpointInterface(ImsExternalCallStateListener listener) |
| throws RemoteException { |
| synchronized (mLock) { |
| if (mMultiEndpoint.getState() != BinderAccessState.STATE_NOT_SET) { |
| throw new IllegalStateException("multiendpoint interface is already open"); |
| } |
| |
| checkServiceIsReady(); |
| IImsMultiEndpoint imEndpoint = getServiceInterface(mBinder).getMultiEndpointInterface(); |
| mMultiEndpoint = (imEndpoint != null) |
| ? BinderAccessState.of(new ImsMultiEndpoint(imEndpoint)) : |
| new BinderAccessState<>(BinderAccessState.STATE_NOT_SUPPORTED); |
| if (mMultiEndpoint.getState() == BinderAccessState.STATE_AVAILABLE) { |
| // May throw an IllegalStateException if a listener already exists. |
| mMultiEndpoint.getInterface().setExternalCallStateListener(listener); |
| } |
| } |
| } |
| |
| public void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry, |
| byte[] pdu) throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).sendSms(token, messageRef, format, smsc, isRetry, |
| pdu); |
| } |
| } |
| |
| public void onMemoryAvailable(int token) throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).onMemoryAvailable(token); |
| } |
| } |
| |
| public void acknowledgeSms(int token, int messageRef, |
| @ImsSmsImplBase.SendStatusResult int result) throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).acknowledgeSms(token, messageRef, result); |
| } |
| } |
| |
| public void acknowledgeSms(int token, int messageRef, |
| @ImsSmsImplBase.SendStatusResult int result, byte[] pdu) throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).acknowledgeSmsWithPdu(token, messageRef, result, pdu); |
| } |
| } |
| |
| public void acknowledgeSmsReport(int token, int messageRef, |
| @ImsSmsImplBase.StatusReportResult int result) throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).acknowledgeSmsReport(token, messageRef, result); |
| } |
| } |
| |
| public String getSmsFormat() throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| return getServiceInterface(mBinder).getSmsFormat(); |
| } |
| } |
| |
| public void onSmsReady() throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).onSmsReady(); |
| } |
| } |
| |
| public void setSmsListener(IImsSmsListener listener) throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).setSmsListener(listener); |
| } |
| } |
| |
| public void notifySrvccStarted(ISrvccStartedCallback cb) |
| throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).notifySrvccStarted(cb); |
| } |
| } |
| |
| public void notifySrvccCompleted() throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).notifySrvccCompleted(); |
| } |
| } |
| |
| public void notifySrvccFailed() throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).notifySrvccFailed(); |
| } |
| } |
| |
| public void notifySrvccCanceled() throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).notifySrvccCanceled(); |
| } |
| } |
| |
| public void triggerDeregistration(@ImsRegistrationImplBase.ImsDeregistrationReason int reason) |
| throws RemoteException { |
| IImsRegistration registration = getRegistration(); |
| if (registration != null) { |
| registration.triggerDeregistration(reason); |
| } else { |
| Log.e(TAG + " [" + mSlotId + "]", "triggerDeregistration IImsRegistration is null"); |
| } |
| } |
| |
| public @MmTelFeature.ProcessCallResult int shouldProcessCall(boolean isEmergency, |
| String[] numbers) throws RemoteException { |
| if (isEmergency && !isEmergencyMmTelAvailable()) { |
| // Don't query the ImsService if emergency calling is not available on the ImsService. |
| Log.i(TAG + " [" + mSlotId + "]", "MmTel does not support emergency over IMS, fallback" |
| + " to CS."); |
| return MmTelFeature.PROCESS_CALL_CSFB; |
| } |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| return getServiceInterface(mBinder).shouldProcessCall(numbers); |
| } |
| } |
| |
| @Override |
| protected Integer retrieveFeatureState() { |
| if (mBinder != null) { |
| try { |
| return getServiceInterface(mBinder).getFeatureState(); |
| } catch (RemoteException e) { |
| // Status check failed, don't update cache |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public void onFeatureCapabilitiesUpdated(long capabilities) |
| { |
| synchronized (mLock) { |
| mSupportsEmergencyCalling = |
| ((capabilities | ImsService.CAPABILITY_EMERGENCY_OVER_MMTEL) > 0); |
| } |
| } |
| |
| /** |
| * Notifies the MmTelFeature of the enablement status of terminal based call waiting |
| * |
| * @param enabled indicates whether the user setting for call waiting is enabled or not. |
| */ |
| public void setTerminalBasedCallWaitingStatus(boolean enabled) |
| throws RemoteException { |
| synchronized (mLock) { |
| checkServiceIsReady(); |
| getServiceInterface(mBinder).setTerminalBasedCallWaitingStatus(enabled); |
| } |
| } |
| |
| private IImsMmTelFeature getServiceInterface(IBinder b) { |
| return IImsMmTelFeature.Stub.asInterface(b); |
| } |
| } |