diff options
author | 2017-12-15 17:53:16 +0000 | |
---|---|---|
committer | 2017-12-15 17:53:16 +0000 | |
commit | 4e54d6092bbcb2ac7ff895a7955acdd1e26e838c (patch) | |
tree | cbdef69b1f182af1d0c993d37266ce077490bcc6 | |
parent | f5e37d18deba6fc2b5b8b083288fa1f0b632d7c3 (diff) | |
parent | ea8fd1bd0a13feddd53f6c7cb202ac32a1a74c28 (diff) |
Merge "Adds MMTel APIs in temporary namespace"
23 files changed, 2965 insertions, 0 deletions
diff --git a/Android.bp b/Android.bp index 2185e0571b6f..2c1fce3fc725 100644 --- a/Android.bp +++ b/Android.bp @@ -453,6 +453,17 @@ java_library { "telecomm/java/com/android/internal/telecom/IInCallService.aidl", "telecomm/java/com/android/internal/telecom/ITelecomService.aidl", "telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl", + "telephony/java/android/telephony/ims/internal/aidl/IImsCallSessionListener.aidl", + "telephony/java/android/telephony/ims/internal/aidl/IImsCapabilityCallback.aidl", + "telephony/java/android/telephony/ims/internal/aidl/IImsConfig.aidl", + "telephony/java/android/telephony/ims/internal/aidl/IImsConfigCallback.aidl", + "telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl", + "telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl", + "telephony/java/android/telephony/ims/internal/aidl/IImsRcsFeature.aidl", + "telephony/java/android/telephony/ims/internal/aidl/IImsRegistration.aidl", + "telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl", + "telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl", + "telephony/java/android/telephony/ims/internal/aidl/IImsServiceControllerListener.aidl", "telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl", "telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl", "telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl", diff --git a/telephony/java/android/telephony/ims/internal/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/internal/ImsCallSessionListener.java new file mode 100644 index 000000000000..5d16dd5b30ee --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/ImsCallSessionListener.java @@ -0,0 +1,364 @@ +/* + * 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 android.telephony.ims.internal; + +import android.os.RemoteException; +import android.telephony.ims.internal.aidl.IImsCallSessionListener; + +import com.android.ims.ImsCallProfile; +import com.android.ims.ImsConferenceState; +import com.android.ims.ImsReasonInfo; +import com.android.ims.ImsStreamMediaProfile; +import com.android.ims.ImsSuppServiceNotification; +import com.android.ims.internal.ImsCallSession; + +/** + * Proxy class for interfacing with the framework's Call session for an ongoing IMS call. + * + * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you + * will break other implementations of ImsCallSessionListener maintained by other ImsServices. + * + * @hide + */ +public class ImsCallSessionListener { + + private final IImsCallSessionListener mListener; + + public ImsCallSessionListener(IImsCallSessionListener l) { + mListener = l; + } + + /** + * Called when a request is sent out to initiate a new session + * and 1xx response is received from the network. + */ + public void callSessionProgressing(ImsStreamMediaProfile profile) + throws RemoteException { + mListener.callSessionProgressing(profile); + } + + /** + * Called when the session is initiated. + * + * @param profile the associated {@link ImsCallSession}. + */ + public void callSessionInitiated(ImsCallProfile profile) throws RemoteException { + mListener.callSessionInitiated(profile); + } + + /** + * Called when the session establishment has failed. + * + * @param reasonInfo detailed reason of the session establishment failure + */ + public void callSessionInitiatedFailed(ImsReasonInfo reasonInfo) throws RemoteException { + mListener.callSessionInitiatedFailed(reasonInfo); + } + + /** + * Called when the session is terminated. + * + * @param reasonInfo detailed reason of the session termination + */ + public void callSessionTerminated(ImsReasonInfo reasonInfo) throws RemoteException { + mListener.callSessionTerminated(reasonInfo); + } + + /** + * Called when the session is on hold. + */ + public void callSessionHeld(ImsCallProfile profile) throws RemoteException { + mListener.callSessionHeld(profile); + } + + /** + * Called when the session hold has failed. + * + * @param reasonInfo detailed reason of the session hold failure + */ + public void callSessionHoldFailed(ImsReasonInfo reasonInfo) throws RemoteException { + mListener.callSessionHoldFailed(reasonInfo); + } + + /** + * Called when the session hold is received from the remote user. + */ + public void callSessionHoldReceived(ImsCallProfile profile) throws RemoteException { + mListener.callSessionHoldReceived(profile); + } + + /** + * Called when the session resume is done. + */ + public void callSessionResumed(ImsCallProfile profile) throws RemoteException { + mListener.callSessionResumed(profile); + } + + /** + * Called when the session resume has failed. + * + * @param reasonInfo detailed reason of the session resume failure + */ + public void callSessionResumeFailed(ImsReasonInfo reasonInfo) throws RemoteException { + mListener.callSessionResumeFailed(reasonInfo); + } + + /** + * Called when the session resume is received from the remote user. + */ + public void callSessionResumeReceived(ImsCallProfile profile) throws RemoteException { + mListener.callSessionResumeReceived(profile); + } + + /** + * Called when the session merge has been started. At this point, the {@code newSession} + * represents the session which has been initiated to the IMS conference server for the + * new merged conference. + * + * @param newSession the session object that is merged with an active & hold session + */ + public void callSessionMergeStarted(ImsCallSession newSession, ImsCallProfile profile) + throws RemoteException { + mListener.callSessionMergeStarted(newSession != null ? newSession.getSession() : null, + profile); + } + + /** + * Called when the session merge is successful and the merged session is active. + * + * @param newSession the new session object that is used for the conference + */ + public void callSessionMergeComplete(ImsCallSession newSession) throws RemoteException { + mListener.callSessionMergeComplete(newSession != null ? newSession.getSession() : null); + } + + /** + * Called when the session merge has failed. + * + * @param reasonInfo detailed reason of the call merge failure + */ + public void callSessionMergeFailed(ImsReasonInfo reasonInfo) throws RemoteException { + mListener.callSessionMergeFailed(reasonInfo); + } + + /** + * Called when the session is updated (except for hold/unhold). + */ + public void callSessionUpdated(ImsCallProfile profile) throws RemoteException { + mListener.callSessionUpdated(profile); + } + + /** + * Called when the session update has failed. + * + * @param reasonInfo detailed reason of the session update failure + */ + public void callSessionUpdateFailed(ImsReasonInfo reasonInfo) throws RemoteException { + mListener.callSessionUpdateFailed(reasonInfo); + } + + /** + * Called when the session update is received from the remote user. + */ + public void callSessionUpdateReceived(ImsCallProfile profile) throws RemoteException { + mListener.callSessionUpdateReceived(profile); + } + + /** + * Called when the session has been extended to a conference session. + * + * @param newSession the session object that is extended to the conference + * from the active session + */ + public void callSessionConferenceExtended(ImsCallSession newSession, ImsCallProfile profile) + throws RemoteException { + mListener.callSessionConferenceExtended(newSession != null ? newSession.getSession() : null, + profile); + } + + /** + * Called when the conference extension has failed. + * + * @param reasonInfo detailed reason of the conference extension failure + */ + public void callSessionConferenceExtendFailed(ImsReasonInfo reasonInfo) throws RemoteException { + mListener.callSessionConferenceExtendFailed(reasonInfo); + } + + /** + * Called when the conference extension is received from the remote user. + */ + public void callSessionConferenceExtendReceived(ImsCallSession newSession, + ImsCallProfile profile) throws RemoteException { + mListener.callSessionConferenceExtendReceived(newSession != null + ? newSession.getSession() : null, profile); + } + + /** + * Called when the invitation request of the participants is delivered to the conference + * server. + */ + public void callSessionInviteParticipantsRequestDelivered() throws RemoteException { + mListener.callSessionInviteParticipantsRequestDelivered(); + } + + /** + * Called when the invitation request of the participants has failed. + * + * @param reasonInfo detailed reason of the conference invitation failure + */ + public void callSessionInviteParticipantsRequestFailed(ImsReasonInfo reasonInfo) + throws RemoteException { + mListener.callSessionInviteParticipantsRequestFailed(reasonInfo); + } + + /** + * Called when the removal request of the participants is delivered to the conference + * server. + */ + public void callSessionRemoveParticipantsRequestDelivered() throws RemoteException { + mListener.callSessionRemoveParticipantsRequestDelivered(); + } + + /** + * Called when the removal request of the participants has failed. + * + * @param reasonInfo detailed reason of the conference removal failure + */ + public void callSessionRemoveParticipantsRequestFailed(ImsReasonInfo reasonInfo) + throws RemoteException { + mListener.callSessionInviteParticipantsRequestFailed(reasonInfo); + } + + /** + * Notifies the framework of the updated Call session conference state. + * + * @param state the new {@link ImsConferenceState} associated with the conference. + */ + public void callSessionConferenceStateUpdated(ImsConferenceState state) throws RemoteException { + mListener.callSessionConferenceStateUpdated(state); + } + + /** + * Notifies the incoming USSD message. + */ + public void callSessionUssdMessageReceived(int mode, String ussdMessage) + throws RemoteException { + mListener.callSessionUssdMessageReceived(mode, ussdMessage); + } + + /** + * Notifies of a case where a {@link com.android.ims.internal.ImsCallSession} may potentially + * handover from one radio technology to another. + * + * @param srcAccessTech The source radio access technology; one of the access technology + * constants defined in {@link android.telephony.ServiceState}. For + * example + * {@link android.telephony.ServiceState#RIL_RADIO_TECHNOLOGY_LTE}. + * @param targetAccessTech The target radio access technology; one of the access technology + * constants defined in {@link android.telephony.ServiceState}. For + * example + * {@link android.telephony.ServiceState#RIL_RADIO_TECHNOLOGY_LTE}. + */ + public void callSessionMayHandover(int srcAccessTech, int targetAccessTech) + throws RemoteException { + mListener.callSessionMayHandover(srcAccessTech, targetAccessTech); + } + + /** + * Called when session access technology changes. + * + * @param srcAccessTech original access technology + * @param targetAccessTech new access technology + * @param reasonInfo + */ + public void callSessionHandover(int srcAccessTech, int targetAccessTech, + ImsReasonInfo reasonInfo) throws RemoteException { + mListener.callSessionHandover(srcAccessTech, targetAccessTech, reasonInfo); + } + + /** + * Called when session access technology change fails. + * + * @param srcAccessTech original access technology + * @param targetAccessTech new access technology + * @param reasonInfo handover failure reason + */ + public void callSessionHandoverFailed(int srcAccessTech, int targetAccessTech, + ImsReasonInfo reasonInfo) throws RemoteException { + mListener.callSessionHandoverFailed(srcAccessTech, targetAccessTech, reasonInfo); + } + + /** + * Called when the TTY mode is changed by the remote party. + * + * @param mode one of the following: - + * {@link com.android.internal.telephony.Phone#TTY_MODE_OFF} - + * {@link com.android.internal.telephony.Phone#TTY_MODE_FULL} - + * {@link com.android.internal.telephony.Phone#TTY_MODE_HCO} - + * {@link com.android.internal.telephony.Phone#TTY_MODE_VCO} + */ + public void callSessionTtyModeReceived(int mode) throws RemoteException { + mListener.callSessionTtyModeReceived(mode); + } + + /** + * Called when the multiparty state is changed for this {@code ImsCallSession}. + * + * @param isMultiParty {@code true} if the session became multiparty, + * {@code false} otherwise. + */ + + public void callSessionMultipartyStateChanged(boolean isMultiParty) throws RemoteException { + mListener.callSessionMultipartyStateChanged(isMultiParty); + } + + /** + * Called when the supplementary service information is received for the current session. + */ + public void callSessionSuppServiceReceived(ImsSuppServiceNotification suppSrvNotification) + throws RemoteException { + mListener.callSessionSuppServiceReceived(suppSrvNotification); + } + + /** + * Received RTT modify request from the remote party. + * + * @param callProfile ImsCallProfile with updated attributes + */ + public void callSessionRttModifyRequestReceived(ImsCallProfile callProfile) + throws RemoteException { + mListener.callSessionRttModifyRequestReceived(callProfile); + } + + /** + * @param status the received response for RTT modify request. + */ + public void callSessionRttModifyResponseReceived(int status) throws RemoteException { + mListener.callSessionRttModifyResponseReceived(status); + } + + /** + * Device received RTT message from Remote UE. + * + * @param rttMessage RTT message received + */ + public void callSessionRttMessageReceived(String rttMessage) throws RemoteException { + mListener.callSessionRttMessageReceived(rttMessage); + } +} + diff --git a/telephony/java/android/telephony/ims/internal/ImsService.java b/telephony/java/android/telephony/ims/internal/ImsService.java new file mode 100644 index 000000000000..b7c8ca0f9799 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/ImsService.java @@ -0,0 +1,339 @@ +/* + * 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 android.telephony.ims.internal; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.os.RemoteException; +import android.telephony.CarrierConfigManager; +import android.telephony.ims.internal.aidl.IImsConfig; +import android.telephony.ims.internal.aidl.IImsMmTelFeature; +import android.telephony.ims.internal.aidl.IImsRcsFeature; +import android.telephony.ims.internal.aidl.IImsRegistration; +import android.telephony.ims.internal.aidl.IImsServiceController; +import android.telephony.ims.internal.aidl.IImsServiceControllerListener; +import android.telephony.ims.internal.feature.ImsFeature; +import android.telephony.ims.internal.feature.MmTelFeature; +import android.telephony.ims.internal.feature.RcsFeature; +import android.telephony.ims.internal.stub.ImsConfigImplBase; +import android.telephony.ims.internal.stub.ImsFeatureConfiguration; +import android.telephony.ims.internal.stub.ImsRegistrationImplBase; +import android.util.Log; +import android.util.SparseArray; + +import com.android.ims.internal.IImsFeatureStatusCallback; +import com.android.internal.annotations.VisibleForTesting; + +/** + * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend + * ImsService must register the service in their AndroidManifest to be detected by the framework. + * First, the application must declare that they use the "android.permission.BIND_IMS_SERVICE" + * permission. Then, the ImsService definition in the manifest must follow the following format: + * + * ... + * <service android:name=".EgImsService" + * android:permission="android.permission.BIND_IMS_SERVICE" > + * <!-- Apps must declare which features they support as metadata. The different categories are + * defined below. In this example, the RCS_FEATURE feature is supported. --> + * <meta-data android:name="android.telephony.ims.RCS_FEATURE" android:value="true" /> + * <intent-filter> + * <action android:name="android.telephony.ims.ImsService" /> + * </intent-filter> + * </service> + * ... + * + * The telephony framework will then bind to the ImsService you have defined in your manifest + * if you are either: + * 1) Defined as the default ImsService for the device in the device overlay using + * "config_ims_package". + * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using + * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}. + * + * The features that are currently supported in an ImsService are: + * - RCS_FEATURE: This ImsService implements the RcsFeature class. + * - MMTEL_FEATURE: This ImsService implements the MmTelFeature class. + * @hide + */ +public class ImsService extends Service { + + private static final String LOG_TAG = "ImsService"; + + /** + * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService. + * @hide + */ + public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService"; + + // A map of slot Id -> map of features (indexed by ImsFeature feature id) corresponding to that + // slot. + // We keep track of this to facilitate cleanup of the IImsFeatureStatusCallback and + // call ImsFeature#onFeatureRemoved. + private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>(); + + private IImsServiceControllerListener mListener; + + + /** + * Listener that notifies the framework of ImsService changes. + */ + public static class Listener extends IImsServiceControllerListener.Stub { + /** + * The IMS features that this ImsService supports has changed. + * @param c a new {@link ImsFeatureConfiguration} containing {@link ImsFeature.FeatureType}s + * that this ImsService supports. This may trigger the addition/removal of feature + * in this service. + */ + public void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) { + } + } + + /** + * @hide + */ + protected final IBinder mImsServiceController = new IImsServiceController.Stub() { + @Override + public void setListener(IImsServiceControllerListener l) { + mListener = l; + } + + @Override + public IImsMmTelFeature createMmTelFeature(int slotId, IImsFeatureStatusCallback c) { + return createMmTelFeatureInternal(slotId, c); + } + + @Override + public IImsRcsFeature createRcsFeature(int slotId, IImsFeatureStatusCallback c) { + return createRcsFeatureInternal(slotId, c); + } + + @Override + public void removeImsFeature(int slotId, int featureType, IImsFeatureStatusCallback c) + throws RemoteException { + ImsService.this.removeImsFeature(slotId, featureType, c); + } + + @Override + public ImsFeatureConfiguration querySupportedImsFeatures() { + return ImsService.this.querySupportedImsFeatures(); + } + + @Override + public void notifyImsServiceReadyForFeatureCreation() { + ImsService.this.readyForFeatureCreation(); + } + + @Override + public void notifyImsFeatureReady(int slotId, int featureType) + throws RemoteException { + ImsService.this.notifyImsFeatureReady(slotId, featureType); + } + + @Override + public IImsConfig getConfig(int slotId) throws RemoteException { + ImsConfigImplBase c = ImsService.this.getConfig(slotId); + return c != null ? c.getBinder() : null; + } + + @Override + public IImsRegistration getRegistration(int slotId) throws RemoteException { + ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId); + return r != null ? r.getBinder() : null; + } + }; + + /** + * @hide + */ + @Override + public IBinder onBind(Intent intent) { + if(SERVICE_INTERFACE.equals(intent.getAction())) { + Log.i(LOG_TAG, "ImsService Bound."); + return mImsServiceController; + } + return null; + } + + /** + * @hide + */ + @VisibleForTesting + public SparseArray<ImsFeature> getFeatures(int slotId) { + return mFeaturesBySlot.get(slotId); + } + + private IImsMmTelFeature createMmTelFeatureInternal(int slotId, + IImsFeatureStatusCallback c) { + MmTelFeature f = createMmTelFeature(slotId); + if (f != null) { + setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL, c); + return f.getBinder(); + } else { + Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned."); + return null; + } + } + + private IImsRcsFeature createRcsFeatureInternal(int slotId, + IImsFeatureStatusCallback c) { + RcsFeature f = createRcsFeature(slotId); + if (f != null) { + setupFeature(f, slotId, ImsFeature.FEATURE_RCS, c); + return f.getBinder(); + } else { + Log.e(LOG_TAG, "createRcsFeatureInternal: null feature returned."); + return null; + } + } + + private void setupFeature(ImsFeature f, int slotId, int featureType, + IImsFeatureStatusCallback c) { + f.addImsFeatureStatusCallback(c); + f.initialize(this, slotId); + addImsFeature(slotId, featureType, f); + } + + private void addImsFeature(int slotId, int featureType, ImsFeature f) { + synchronized (mFeaturesBySlot) { + // Get SparseArray for Features, by querying slot Id + SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); + if (features == null) { + // Populate new SparseArray of features if it doesn't exist for this slot yet. + features = new SparseArray<>(); + mFeaturesBySlot.put(slotId, features); + } + features.put(featureType, f); + } + } + + private void removeImsFeature(int slotId, int featureType, + IImsFeatureStatusCallback c) { + synchronized (mFeaturesBySlot) { + // get ImsFeature associated with the slot/feature + SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); + if (features == null) { + Log.w(LOG_TAG, "Can not remove ImsFeature. No ImsFeatures exist on slot " + + slotId); + return; + } + ImsFeature f = features.get(featureType); + if (f == null) { + Log.w(LOG_TAG, "Can not remove ImsFeature. No feature with type " + + featureType + " exists on slot " + slotId); + return; + } + f.removeImsFeatureStatusCallback(c); + f.onFeatureRemoved(); + features.remove(featureType); + } + } + + private void notifyImsFeatureReady(int slotId, int featureType) { + synchronized (mFeaturesBySlot) { + // get ImsFeature associated with the slot/feature + SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId); + if (features == null) { + Log.w(LOG_TAG, "Can not notify ImsFeature ready. No ImsFeatures exist on " + + "slot " + slotId); + return; + } + ImsFeature f = features.get(featureType); + if (f == null) { + Log.w(LOG_TAG, "Can not notify ImsFeature ready. No feature with type " + + featureType + " exists on slot " + slotId); + return; + } + f.onFeatureReady(); + } + } + + /** + * When called, provide the {@link ImsFeatureConfiguration} that this ImsService currently + * supports. This will trigger the framework to set up the {@link ImsFeature}s that correspond + * to the {@link ImsFeature.FeatureType}s configured here. + * @return an {@link ImsFeatureConfiguration} containing Features this ImsService supports, + * defined in {@link ImsFeature.FeatureType}. + */ + public ImsFeatureConfiguration querySupportedImsFeatures() { + // Return empty for base implementation + return new ImsFeatureConfiguration(); + } + + /** + * Updates the framework with a new {@link ImsFeatureConfiguration} containing the updated + * features, defined in {@link ImsFeature.FeatureType} that this ImsService supports. This may + * trigger the framework to add/remove new ImsFeatures, depending on the configuration. + */ + public final void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) + throws RemoteException { + if (mListener == null) { + throw new IllegalStateException("Framework is not ready"); + } + mListener.onUpdateSupportedImsFeatures(c); + } + + /** + * The ImsService has been bound and is ready for ImsFeature creation based on the Features that + * the ImsService has registered for with the framework, either in the manifest or via + * The ImsService should use this signal instead of onCreate/onBind or similar to perform + * feature initialization because the framework may bind to this service multiple times to + * query the ImsService's {@link ImsFeatureConfiguration} via + * {@link #querySupportedImsFeatures()}before creating features. + */ + public void readyForFeatureCreation() { + } + + /** + * When called, the framework is requesting that a new MmTelFeature is created for the specified + * slot. + * + * @param slotId The slot ID that the MMTel Feature is being created for. + * @return The newly created MmTelFeature associated with the slot or null if the feature is not + * supported. + */ + public MmTelFeature createMmTelFeature(int slotId) { + return null; + } + + /** + * When called, the framework is requesting that a new RcsFeature is created for the specified + * slot + * + * @param slotId The slot ID that the RCS Feature is being created for. + * @return The newly created RcsFeature associated with the slot or null if the feature is not + * supported. + */ + public RcsFeature createRcsFeature(int slotId) { + return null; + } + + /** + * @param slotId The slot that the IMS configuration is associated with. + * @return ImsConfig implementation that is associated with the specified slot. + */ + public ImsConfigImplBase getConfig(int slotId) { + return new ImsConfigImplBase(); + } + + /** + * @param slotId The slot that is associated with the IMS Registration. + * @return the ImsRegistration implementation associated with the slot. + */ + public ImsRegistrationImplBase getRegistration(int slotId) { + return new ImsRegistrationImplBase(); + } +} diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsCallSessionListener.aidl new file mode 100644 index 000000000000..2fb67442fa34 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsCallSessionListener.aidl @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2013 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 android.telephony.ims.internal.aidl; + +import com.android.ims.ImsStreamMediaProfile; +import com.android.ims.ImsCallProfile; +import com.android.ims.ImsReasonInfo; +import com.android.ims.ImsConferenceState; +import com.android.ims.internal.IImsCallSession; +import com.android.ims.ImsSuppServiceNotification; + +/** + * A listener type for receiving notification on IMS call session events. + * When an event is generated for an {@link IImsCallSession}, the application is notified + * by having one of the methods called on the {@link IImsCallSessionListener}. + * {@hide} + */ +oneway interface IImsCallSessionListener { + /** + * Notifies the result of the basic session operation (setup / terminate). + */ + void callSessionProgressing(in ImsStreamMediaProfile profile); + void callSessionInitiated(in ImsCallProfile profile); + void callSessionInitiatedFailed(in ImsReasonInfo reasonInfo); + void callSessionTerminated(in ImsReasonInfo reasonInfo); + + /** + * Notifies the result of the call hold/resume operation. + */ + void callSessionHeld(in ImsCallProfile profile); + void callSessionHoldFailed(in ImsReasonInfo reasonInfo); + void callSessionHoldReceived(in ImsCallProfile profile); + void callSessionResumed(in ImsCallProfile profile); + void callSessionResumeFailed(in ImsReasonInfo reasonInfo); + void callSessionResumeReceived(in ImsCallProfile profile); + + /** + * Notifies the result of call merge operation. + */ + void callSessionMergeStarted(IImsCallSession newSession, in ImsCallProfile profile); + void callSessionMergeComplete(IImsCallSession session); + void callSessionMergeFailed(in ImsReasonInfo reasonInfo); + + /** + * Notifies the result of call upgrade / downgrade or any other call updates. + */ + void callSessionUpdated(in ImsCallProfile profile); + void callSessionUpdateFailed(in ImsReasonInfo reasonInfo); + void callSessionUpdateReceived(in ImsCallProfile profile); + + /** + * Notifies the result of conference extension. + */ + void callSessionConferenceExtended(IImsCallSession newSession, in ImsCallProfile profile); + void callSessionConferenceExtendFailed(in ImsReasonInfo reasonInfo); + void callSessionConferenceExtendReceived(IImsCallSession newSession, + in ImsCallProfile profile); + + /** + * Notifies the result of the participant invitation / removal to/from the conference session. + */ + void callSessionInviteParticipantsRequestDelivered(); + void callSessionInviteParticipantsRequestFailed(in ImsReasonInfo reasonInfo); + void callSessionRemoveParticipantsRequestDelivered(); + void callSessionRemoveParticipantsRequestFailed(in ImsReasonInfo reasonInfo); + + /** + * Notifies the changes of the conference info. in the conference session. + */ + void callSessionConferenceStateUpdated(in ImsConferenceState state); + + /** + * Notifies the incoming USSD message. + */ + void callSessionUssdMessageReceived(int mode, String ussdMessage); + + /** + * Notifies of handover information for this call + */ + void callSessionHandover(int srcAccessTech, int targetAccessTech, + in ImsReasonInfo reasonInfo); + void callSessionHandoverFailed(int srcAccessTech, int targetAccessTech, + in ImsReasonInfo reasonInfo); + void callSessionMayHandover(int srcAccessTech, int targetAccessTech); + + /** + * Notifies the TTY mode change by remote party. + * @param mode one of the following: + * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF} + * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL} + * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO} + * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO} + */ + void callSessionTtyModeReceived(int mode); + + /** + * Notifies of a change to the multiparty state for this {@code ImsCallSession}. + * + * @param session The call session. + * @param isMultiParty {@code true} if the session became multiparty, {@code false} otherwise. + */ + void callSessionMultipartyStateChanged(boolean isMultiParty); + + /** + * Notifies the supplementary service information for the current session. + */ + void callSessionSuppServiceReceived(in ImsSuppServiceNotification suppSrvNotification); + + /** + * Device received RTT modify request from Remote UE + * @param session ImsCallProfile with updated attribute + */ + void callSessionRttModifyRequestReceived(in ImsCallProfile callProfile); + + /* Device issued RTT modify request and inturn received response + * from Remote UE + * @param status Will be one of the following values from: + * - {@link Connection.RttModifyStatus} + */ + void callSessionRttModifyResponseReceived(int status); + + /* + * While in call, device received RTT message from Remote UE + * @param rttMessage Received RTT message + */ + void callSessionRttMessageReceived(in String rttMessage); +} diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsCapabilityCallback.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsCapabilityCallback.aidl new file mode 100644 index 000000000000..fd2eb24610ec --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsCapabilityCallback.aidl @@ -0,0 +1,27 @@ +/* + * 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 android.telephony.ims.internal.aidl; + +/** + * See ImsFeature#CapabilityCallback for more information. + * {@hide} + */ +oneway interface IImsCapabilityCallback { + void onQueryCapabilityConfiguration(int capability, int radioTech, boolean enabled); + void onChangeCapabilityConfigurationError(int capability, int radioTech, int reason); + void onCapabilitiesStatusChanged(int config); +} diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsConfig.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsConfig.aidl new file mode 100644 index 000000000000..3d424a33012d --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsConfig.aidl @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013 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 android.telephony.ims.internal.aidl; + +import android.telephony.ims.internal.aidl.IImsConfigCallback; + +import com.android.ims.ImsConfigListener; + +/** + * Provides APIs to get/set the IMS service feature/capability/parameters. + * The config items include items provisioned by the operator. + * + * {@hide} + */ +interface IImsConfig { + + void addImsConfigCallback(IImsConfigCallback c); + void removeImsConfigCallback(IImsConfigCallback c); + int getConfigInt(int item); + String getConfigString(int item); + // Return result code defined in ImsConfig#OperationStatusConstants + int setConfigInt(int item, int value); + // Return result code defined in ImsConfig#OperationStatusConstants + int setConfigString(int item, String value); +} diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsConfigCallback.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsConfigCallback.aidl new file mode 100644 index 000000000000..52efd2322c17 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsConfigCallback.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013 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 android.telephony.ims.internal.aidl; + +/** + * Provides callback interface for ImsConfig when a value has changed. + * + * {@hide} + */ +oneway interface IImsConfigCallback { + void onIntConfigChanged(int item, int value); + void onStringConfigChanged(int item, String value); +} diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl new file mode 100644 index 000000000000..712578117e44 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelFeature.aidl @@ -0,0 +1,52 @@ +/* + * 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 android.telephony.ims.internal.aidl; + +import android.os.Message; +import android.telephony.ims.internal.aidl.IImsMmTelListener; +import android.telephony.ims.internal.aidl.IImsCapabilityCallback; +import android.telephony.ims.internal.aidl.IImsCallSessionListener; +import android.telephony.ims.internal.feature.CapabilityChangeRequest; + +import com.android.ims.ImsCallProfile; +import com.android.ims.internal.IImsCallSession; +import com.android.ims.internal.IImsEcbm; +import com.android.ims.internal.IImsMultiEndpoint; +import com.android.ims.internal.IImsRegistrationListener; +import com.android.ims.internal.IImsUt; + +/** + * See MmTelFeature for more information. + * {@hide} + */ +interface IImsMmTelFeature { + void setListener(IImsMmTelListener l); + int getFeatureState(); + ImsCallProfile createCallProfile(int callSessionType, int callType); + IImsCallSession createCallSession(in ImsCallProfile profile, IImsCallSessionListener listener); + IImsUt getUtInterface(); + IImsEcbm getEcbmInterface(); + void setUiTtyMode(int uiTtyMode, in Message onCompleteMessage); + IImsMultiEndpoint getMultiEndpointInterface(); + int queryCapabilityStatus(); + oneway void addCapabilityCallback(IImsCapabilityCallback c); + oneway void removeCapabilityCallback(IImsCapabilityCallback c); + oneway void changeCapabilitiesConfiguration(in CapabilityChangeRequest request, + IImsCapabilityCallback c); + oneway void queryCapabilityConfiguration(int capability, int radioTech, + IImsCapabilityCallback c); +} diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl new file mode 100644 index 000000000000..8332bc024e37 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsMmTelListener.aidl @@ -0,0 +1,27 @@ +/* + * 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 android.telephony.ims.internal.aidl; + +import com.android.ims.internal.IImsCallSession; + +/** + * See MmTelFeature#Listener for more information. + * {@hide} + */ +oneway interface IImsMmTelListener { + void onIncomingCall(IImsCallSession c); +}
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsRcsFeature.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsRcsFeature.aidl new file mode 100644 index 000000000000..f6005b66bd3c --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsRcsFeature.aidl @@ -0,0 +1,25 @@ +/* + * 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 android.telephony.ims.internal.aidl; + +/** + * See RcsFeature for more information. + * {@hide} + */ +interface IImsRcsFeature { + //Empty Default Implementation +}
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsRegistration.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsRegistration.aidl new file mode 100644 index 000000000000..687b7ca408d5 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsRegistration.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 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 android.telephony.ims.internal.aidl; + +import android.telephony.ims.internal.aidl.IImsRegistrationCallback; +import android.telephony.ims.internal.stub.ImsFeatureConfiguration; + +/** + * See ImsRegistration for more information. + * + * {@hide} + */ +interface IImsRegistration { + int getRegistrationTechnology(); + oneway void addRegistrationCallback(IImsRegistrationCallback c); + oneway void removeRegistrationCallback(IImsRegistrationCallback c); +}
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl new file mode 100644 index 000000000000..a50575b96865 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsRegistrationCallback.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013 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 android.telephony.ims.internal.aidl; + +import android.telephony.ims.internal.stub.ImsFeatureConfiguration; + +import com.android.ims.ImsReasonInfo; + +/** + * See ImsRegistrationImplBase.Callback for more information. + * + * {@hide} + */ +oneway interface IImsRegistrationCallback { + void onRegistered(int imsRadioTech); + void onRegistering(int imsRadioTech); + void onDeregistered(in ImsReasonInfo info); + void onTechnologyChangeFailed(int imsRadioTech, in ImsReasonInfo info); +}
\ No newline at end of file diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl new file mode 100644 index 000000000000..8afb95588b01 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsServiceController.aidl @@ -0,0 +1,44 @@ +/* + * 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 android.telephony.ims.internal.aidl; + +import android.telephony.ims.internal.aidl.IImsMmTelFeature; +import android.telephony.ims.internal.aidl.IImsRcsFeature; +import android.telephony.ims.internal.aidl.IImsRegistration; +import android.telephony.ims.internal.aidl.IImsConfig; +import android.telephony.ims.internal.aidl.IImsServiceControllerListener; +import android.telephony.ims.internal.stub.ImsFeatureConfiguration; + +import com.android.ims.internal.IImsFeatureStatusCallback; + +/** + * See ImsService and MmTelFeature for more information. + * {@hide} + */ +interface IImsServiceController { + void setListener(IImsServiceControllerListener l); + IImsMmTelFeature createMmTelFeature(int slotId, in IImsFeatureStatusCallback c); + IImsRcsFeature createRcsFeature(int slotId, in IImsFeatureStatusCallback c); + ImsFeatureConfiguration querySupportedImsFeatures(); + // Synchronous call to ensure the ImsService is ready before continuing with feature creation. + void notifyImsServiceReadyForFeatureCreation(); + // Synchronous call to ensure the new ImsFeature is ready before using the Feature. + void notifyImsFeatureReady(int slotId, int featureType); + void removeImsFeature(int slotId, int featureType, in IImsFeatureStatusCallback c); + IImsConfig getConfig(int slotId); + IImsRegistration getRegistration(int slotId); +} diff --git a/telephony/java/android/telephony/ims/internal/aidl/IImsServiceControllerListener.aidl b/telephony/java/android/telephony/ims/internal/aidl/IImsServiceControllerListener.aidl new file mode 100644 index 000000000000..01cca2db0978 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/aidl/IImsServiceControllerListener.aidl @@ -0,0 +1,27 @@ +/* + * 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 android.telephony.ims.internal.aidl; + +import android.telephony.ims.internal.stub.ImsFeatureConfiguration; + +/** + * See ImsService#Listener for more information. + * {@hide} + */ +oneway interface IImsServiceControllerListener { + void onUpdateSupportedImsFeatures(in ImsFeatureConfiguration c); +} diff --git a/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.aidl b/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.aidl new file mode 100644 index 000000000000..f4ec0eb38f34 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.telephony.ims.internal.feature; + +parcelable CapabilityChangeRequest; diff --git a/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.java b/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.java new file mode 100644 index 000000000000..4d188734c10e --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/feature/CapabilityChangeRequest.java @@ -0,0 +1,197 @@ +/* + * 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 android.telephony.ims.internal.feature; + +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.ims.internal.stub.ImsRegistrationImplBase; +import android.util.ArraySet; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Request to send to IMS provider, which will try to enable/disable capabilities that are added to + * the request. + * {@hide} + */ +public class CapabilityChangeRequest implements Parcelable { + + public static class CapabilityPair { + private final int mCapability; + private final int radioTech; + + public CapabilityPair(int capability, int radioTech) { + this.mCapability = capability; + this.radioTech = radioTech; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CapabilityPair)) return false; + + CapabilityPair that = (CapabilityPair) o; + + if (getCapability() != that.getCapability()) return false; + return getRadioTech() == that.getRadioTech(); + } + + @Override + public int hashCode() { + int result = getCapability(); + result = 31 * result + getRadioTech(); + return result; + } + + public @MmTelFeature.MmTelCapabilities.MmTelCapability int getCapability() { + return mCapability; + } + + public @ImsRegistrationImplBase.ImsRegistrationTech int getRadioTech() { + return radioTech; + } + } + + // Pair contains <radio tech, mCapability> + private final Set<CapabilityPair> mCapabilitiesToEnable; + // Pair contains <radio tech, mCapability> + private final Set<CapabilityPair> mCapabilitiesToDisable; + + public CapabilityChangeRequest() { + mCapabilitiesToEnable = new ArraySet<>(); + mCapabilitiesToDisable = new ArraySet<>(); + } + + /** + * Add one or many capabilities to the request to be enabled. + * + * @param capabilities A bitfield of capabilities to enable, valid values are defined in + * {@link MmTelFeature.MmTelCapabilities.MmTelCapability}. + * @param radioTech the radio tech that these capabilities should be enabled for, valid + * values are in {@link ImsRegistrationImplBase.ImsRegistrationTech}. + */ + public void addCapabilitiesToEnableForTech( + @MmTelFeature.MmTelCapabilities.MmTelCapability int capabilities, + @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { + addAllCapabilities(mCapabilitiesToEnable, capabilities, radioTech); + } + + /** + * Add one or many capabilities to the request to be disabled. + * @param capabilities A bitfield of capabilities to diable, valid values are defined in + * {@link MmTelFeature.MmTelCapabilities.MmTelCapability}. + * @param radioTech the radio tech that these capabilities should be disabled for, valid + * values are in {@link ImsRegistrationImplBase.ImsRegistrationTech}. + */ + public void addCapabilitiesToDisableForTech( + @MmTelFeature.MmTelCapabilities.MmTelCapability int capabilities, + @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { + addAllCapabilities(mCapabilitiesToDisable, capabilities, radioTech); + } + + /** + * @return a {@link List} of {@link CapabilityPair}s that are requesting to be enabled. + */ + public List<CapabilityPair> getCapabilitiesToEnable() { + return new ArrayList<>(mCapabilitiesToEnable); + } + + /** + * @return a {@link List} of {@link CapabilityPair}s that are requesting to be disabled. + */ + public List<CapabilityPair> getCapabilitiesToDisable() { + return new ArrayList<>(mCapabilitiesToDisable); + } + + // Iterate through capabilities bitfield and add each one as a pair associated with the radio + // technology + private void addAllCapabilities(Set<CapabilityPair> set, int capabilities, int tech) { + long highestCapability = Long.highestOneBit(capabilities); + for (int i = 1; i <= highestCapability; i *= 2) { + if ((i & capabilities) > 0) { + set.add(new CapabilityPair(/*capability*/ i, /*radioTech*/ tech)); + } + } + } + + protected CapabilityChangeRequest(Parcel in) { + int enableSize = in.readInt(); + mCapabilitiesToEnable = new ArraySet<>(enableSize); + for (int i = 0; i < enableSize; i++) { + mCapabilitiesToEnable.add(new CapabilityPair(/*capability*/ in.readInt(), + /*radioTech*/ in.readInt())); + } + int disableSize = in.readInt(); + mCapabilitiesToDisable = new ArraySet<>(disableSize); + for (int i = 0; i < disableSize; i++) { + mCapabilitiesToDisable.add(new CapabilityPair(/*capability*/ in.readInt(), + /*radioTech*/ in.readInt())); + } + } + + public static final Creator<CapabilityChangeRequest> CREATOR = + new Creator<CapabilityChangeRequest>() { + @Override + public CapabilityChangeRequest createFromParcel(Parcel in) { + return new CapabilityChangeRequest(in); + } + + @Override + public CapabilityChangeRequest[] newArray(int size) { + return new CapabilityChangeRequest[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mCapabilitiesToEnable.size()); + for (CapabilityPair pair : mCapabilitiesToEnable) { + dest.writeInt(pair.getCapability()); + dest.writeInt(pair.getRadioTech()); + } + dest.writeInt(mCapabilitiesToDisable.size()); + for (CapabilityPair pair : mCapabilitiesToDisable) { + dest.writeInt(pair.getCapability()); + dest.writeInt(pair.getRadioTech()); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof CapabilityChangeRequest)) return false; + + CapabilityChangeRequest that = (CapabilityChangeRequest) o; + + if (!mCapabilitiesToEnable.equals(that.mCapabilitiesToEnable)) return false; + return mCapabilitiesToDisable.equals(that.mCapabilitiesToDisable); + } + + @Override + public int hashCode() { + int result = mCapabilitiesToEnable.hashCode(); + result = 31 * result + mCapabilitiesToDisable.hashCode(); + return result; + } +} diff --git a/telephony/java/android/telephony/ims/internal/feature/ImsFeature.java b/telephony/java/android/telephony/ims/internal/feature/ImsFeature.java new file mode 100644 index 000000000000..9f82ad241eaf --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/feature/ImsFeature.java @@ -0,0 +1,462 @@ +/* + * 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 android.telephony.ims.internal.feature; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.content.Context; +import android.content.Intent; +import android.os.IInterface; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.telephony.SubscriptionManager; +import android.telephony.ims.internal.aidl.IImsCapabilityCallback; +import android.util.Log; + +import com.android.ims.internal.IImsFeatureStatusCallback; +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Collections; +import java.util.Iterator; +import java.util.Set; +import java.util.WeakHashMap; + +/** + * Base class for all IMS features that are supported by the framework. + * + * @hide + */ +public abstract class ImsFeature { + + private static final String LOG_TAG = "ImsFeature"; + + /** + * Action to broadcast when ImsService is up. + * Internal use only. + * Only defined here separately for compatibility purposes with the old ImsService. + * + * @hide + */ + public static final String ACTION_IMS_SERVICE_UP = + "com.android.ims.IMS_SERVICE_UP"; + + /** + * Action to broadcast when ImsService is down. + * Internal use only. + * Only defined here separately for compatibility purposes with the old ImsService. + * + * @hide + */ + public static final String ACTION_IMS_SERVICE_DOWN = + "com.android.ims.IMS_SERVICE_DOWN"; + + /** + * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents. + * A long value; the phone ID corresponding to the IMS service coming up or down. + * Only defined here separately for compatibility purposes with the old ImsService. + * + * @hide + */ + public static final String EXTRA_PHONE_ID = "android:phone_id"; + + // Invalid feature value + public static final int FEATURE_INVALID = -1; + // ImsFeatures that are defined in the Manifests. Ensure that these values match the previously + // defined values in ImsServiceClass for compatibility purposes. + public static final int FEATURE_EMERGENCY_MMTEL = 0; + public static final int FEATURE_MMTEL = 1; + public static final int FEATURE_RCS = 2; + // Total number of features defined + public static final int FEATURE_MAX = 3; + + // Integer values defining IMS features that are supported in ImsFeature. + @IntDef(flag = true, + value = { + FEATURE_EMERGENCY_MMTEL, + FEATURE_MMTEL, + FEATURE_RCS + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FeatureType {} + + // Integer values defining the state of the ImsFeature at any time. + @IntDef(flag = true, + value = { + STATE_UNAVAILABLE, + STATE_INITIALIZING, + STATE_READY, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ImsState {} + + public static final int STATE_UNAVAILABLE = 0; + public static final int STATE_INITIALIZING = 1; + public static final int STATE_READY = 2; + + // Integer values defining the result codes that should be returned from + // {@link changeEnabledCapabilities} when the framework tries to set a feature's capability. + @IntDef(flag = true, + value = { + CAPABILITY_ERROR_GENERIC, + CAPABILITY_SUCCESS + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ImsCapabilityError {} + + public static final int CAPABILITY_ERROR_GENERIC = -1; + public static final int CAPABILITY_SUCCESS = 0; + + + /** + * The framework implements this callback in order to register for Feature Capability status + * updates, via {@link #onCapabilitiesStatusChanged(Capabilities)}, query Capability + * configurations, via {@link #onQueryCapabilityConfiguration}, as well as to receive error + * callbacks when the ImsService can not change the capability as requested, via + * {@link #onChangeCapabilityConfigurationError}. + */ + public static class CapabilityCallback extends IImsCapabilityCallback.Stub { + + @Override + public final void onCapabilitiesStatusChanged(int config) throws RemoteException { + onCapabilitiesStatusChanged(new Capabilities(config)); + } + + /** + * Returns the result of a query for the capability configuration of a requested capability. + * + * @param capability The capability that was requested. + * @param radioTech The IMS radio technology associated with the capability. + * @param isEnabled true if the capability is enabled, false otherwise. + */ + @Override + public void onQueryCapabilityConfiguration(int capability, int radioTech, + boolean isEnabled) { + + } + + /** + * Called when a change to the capability configuration has returned an error. + * + * @param capability The capability that was requested to be changed. + * @param radioTech The IMS radio technology associated with the capability. + * @param reason error associated with the failure to change configuration. + */ + @Override + public void onChangeCapabilityConfigurationError(int capability, int radioTech, + int reason) { + } + + /** + * The status of the feature's capabilities has changed to either available or unavailable. + * If unavailable, the feature is not able to support the unavailable capability at this + * time. + * + * @param config The new availability of the capabilities. + */ + public void onCapabilitiesStatusChanged(Capabilities config) { + } + } + + /** + * Used by the ImsFeature to call back to the CapabilityCallback that the framework has + * provided. + */ + protected static class CapabilityCallbackProxy { + private final IImsCapabilityCallback mCallback; + + public CapabilityCallbackProxy(IImsCapabilityCallback c) { + mCallback = c; + } + + /** + * This method notifies the provided framework callback that the request to change the + * indicated capability has failed and has not changed. + * + * @param capability The Capability that will be notified to the framework. + * @param radioTech The radio tech that this capability failed for. + * @param reason The reason this capability was unable to be changed. + */ + public void onChangeCapabilityConfigurationError(int capability, int radioTech, + @ImsCapabilityError int reason) { + try { + mCallback.onChangeCapabilityConfigurationError(capability, radioTech, reason); + } catch (RemoteException e) { + Log.e(LOG_TAG, "onChangeCapabilityConfigurationError called on dead binder."); + } + } + + public void onQueryCapabilityConfiguration(int capability, int radioTech, + boolean isEnabled) { + try { + mCallback.onQueryCapabilityConfiguration(capability, radioTech, isEnabled); + } catch (RemoteException e) { + Log.e(LOG_TAG, "onQueryCapabilityConfiguration called on dead binder."); + } + } + } + + /** + * Contains the capabilities defined and supported by an ImsFeature in the form of a bit mask. + */ + public static class Capabilities { + protected int mCapabilities = 0; + + public Capabilities() { + } + + protected Capabilities(int capabilities) { + mCapabilities = capabilities; + } + + /** + * @param capabilities Capabilities to be added to the configuration in the form of a + * bit mask. + */ + public void addCapabilities(int capabilities) { + mCapabilities |= capabilities; + } + + /** + * @param capabilities Capabilities to be removed to the configuration in the form of a + * bit mask. + */ + public void removeCapabilities(int capabilities) { + mCapabilities &= ~capabilities; + } + + /** + * @return true if all of the capabilities specified are capable. + */ + public boolean isCapable(int capabilities) { + return (mCapabilities & capabilities) == capabilities; + } + + public Capabilities copy() { + return new Capabilities(mCapabilities); + } + + /** + * @return a bitmask containing the capability flags directly. + */ + public int getMask() { + return mCapabilities; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Capabilities)) return false; + + Capabilities that = (Capabilities) o; + + return mCapabilities == that.mCapabilities; + } + + @Override + public int hashCode() { + return mCapabilities; + } + } + + private final Set<IImsFeatureStatusCallback> mStatusCallbacks = Collections.newSetFromMap( + new WeakHashMap<IImsFeatureStatusCallback, Boolean>()); + private @ImsState int mState = STATE_UNAVAILABLE; + private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; + private Context mContext; + private final Object mLock = new Object(); + private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks + = new RemoteCallbackList<>(); + private Capabilities mCapabilityStatus = new Capabilities(); + + public final void initialize(Context context, int slotId) { + mContext = context; + mSlotId = slotId; + } + + public final int getFeatureState() { + synchronized (mLock) { + return mState; + } + } + + protected final void setFeatureState(@ImsState int state) { + synchronized (mLock) { + if (mState != state) { + mState = state; + notifyFeatureState(state); + } + } + } + + // Not final for testing, but shouldn't be extended! + @VisibleForTesting + public void addImsFeatureStatusCallback(@NonNull IImsFeatureStatusCallback c) { + try { + // If we have just connected, send queued status. + c.notifyImsFeatureStatus(getFeatureState()); + // Add the callback if the callback completes successfully without a RemoteException. + synchronized (mLock) { + mStatusCallbacks.add(c); + } + } catch (RemoteException e) { + Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage()); + } + } + + @VisibleForTesting + // Not final for testing, but should not be extended! + public void removeImsFeatureStatusCallback(@NonNull IImsFeatureStatusCallback c) { + synchronized (mLock) { + mStatusCallbacks.remove(c); + } + } + + /** + * Internal method called by ImsFeature when setFeatureState has changed. + */ + private void notifyFeatureState(@ImsState int state) { + synchronized (mLock) { + for (Iterator<IImsFeatureStatusCallback> iter = mStatusCallbacks.iterator(); + iter.hasNext(); ) { + IImsFeatureStatusCallback callback = iter.next(); + try { + Log.i(LOG_TAG, "notifying ImsFeatureState=" + state); + callback.notifyImsFeatureStatus(state); + } catch (RemoteException e) { + // remove if the callback is no longer alive. + iter.remove(); + Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage()); + } + } + } + sendImsServiceIntent(state); + } + + /** + * Provide backwards compatibility using deprecated service UP/DOWN intents. + */ + private void sendImsServiceIntent(@ImsState int state) { + if (mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) { + return; + } + Intent intent; + switch (state) { + case ImsFeature.STATE_UNAVAILABLE: + case ImsFeature.STATE_INITIALIZING: + intent = new Intent(ACTION_IMS_SERVICE_DOWN); + break; + case ImsFeature.STATE_READY: + intent = new Intent(ACTION_IMS_SERVICE_UP); + break; + default: + intent = new Intent(ACTION_IMS_SERVICE_DOWN); + } + intent.putExtra(EXTRA_PHONE_ID, mSlotId); + mContext.sendBroadcast(intent); + } + + public final void addCapabilityCallback(IImsCapabilityCallback c) { + mCapabilityCallbacks.register(c); + } + + public final void removeCapabilityCallback(IImsCapabilityCallback c) { + mCapabilityCallbacks.unregister(c); + } + + /** + * @return the cached capabilities status for this feature. + */ + @VisibleForTesting + public Capabilities queryCapabilityStatus() { + synchronized (mLock) { + return mCapabilityStatus.copy(); + } + } + + // Called internally to request the change of enabled capabilities. + @VisibleForTesting + public final void requestChangeEnabledCapabilities(CapabilityChangeRequest request, + IImsCapabilityCallback c) throws RemoteException { + if (request == null) { + throw new IllegalArgumentException( + "ImsFeature#requestChangeEnabledCapabilities called with invalid params."); + } + changeEnabledCapabilities(request, new CapabilityCallbackProxy(c)); + } + + /** + * Called by the ImsFeature when the capabilities status has changed. + * + * @param c A {@link Capabilities} containing the new Capabilities status. + */ + protected final void notifyCapabilitiesStatusChanged(Capabilities c) { + synchronized (mLock) { + mCapabilityStatus = c.copy(); + } + int count = mCapabilityCallbacks.beginBroadcast(); + try { + for (int i = 0; i < count; i++) { + try { + mCapabilityCallbacks.getBroadcastItem(i).onCapabilitiesStatusChanged( + c.mCapabilities); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + " " + "notifyCapabilitiesStatusChanged() - Skipping " + + "callback."); + } + } + } finally { + mCapabilityCallbacks.finishBroadcast(); + } + } + + /** + * Features should override this method to receive Capability preference change requests from + * the framework using the provided {@link CapabilityChangeRequest}. If any of the capabilities + * in the {@link CapabilityChangeRequest} are not able to be completed due to an error, + * {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError} should be called for + * each failed capability. + * + * @param request A {@link CapabilityChangeRequest} containing requested capabilities to + * enable/disable. + * @param c A {@link CapabilityCallbackProxy}, which will be used to call back to the framework + * setting a subset of these capabilities fail, using + * {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError}. + */ + public abstract void changeEnabledCapabilities(CapabilityChangeRequest request, + CapabilityCallbackProxy c); + + /** + * Called when the framework is removing this feature and it needs to be cleaned up. + */ + public abstract void onFeatureRemoved(); + + /** + * Called when the feature has been initialized and communication with the framework is set up. + * Any attempt by this feature to access the framework before this method is called will return + * with an {@link IllegalStateException}. + * The IMS provider should use this method to trigger registration for this feature on the IMS + * network, if needed. + */ + public abstract void onFeatureReady(); + + /** + * @return Binder instance that the framework will use to communicate with this feature. + */ + protected abstract IInterface getBinder(); +} diff --git a/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java new file mode 100644 index 000000000000..f183a57e77fc --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/feature/MmTelFeature.java @@ -0,0 +1,422 @@ +/* + * 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 android.telephony.ims.internal.feature; + +import android.annotation.IntDef; +import android.os.Message; +import android.os.RemoteException; +import android.telecom.TelecomManager; +import android.telephony.ims.internal.ImsCallSessionListener; +import android.telephony.ims.internal.aidl.IImsCallSessionListener; +import android.telephony.ims.internal.aidl.IImsCapabilityCallback; +import android.telephony.ims.internal.aidl.IImsMmTelFeature; +import android.telephony.ims.internal.aidl.IImsMmTelListener; +import android.telephony.ims.internal.stub.ImsRegistrationImplBase; +import android.telephony.ims.stub.ImsEcbmImplBase; +import android.telephony.ims.stub.ImsMultiEndpointImplBase; +import android.telephony.ims.stub.ImsUtImplBase; +import android.util.Log; + +import com.android.ims.ImsCallProfile; +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 com.android.ims.internal.ImsCallSession; +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Base implementation for Voice and SMS (IR-92) and Video (IR-94) IMS support. + * + * Any class wishing to use MmTelFeature should extend this class and implement all methods that the + * service supports. + * @hide + */ + +public class MmTelFeature extends ImsFeature { + + private static final String LOG_TAG = "MmTelFeature"; + + private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() { + + @Override + public void setListener(IImsMmTelListener l) throws RemoteException { + synchronized (mLock) { + MmTelFeature.this.setListener(l); + } + } + + @Override + public int getFeatureState() throws RemoteException { + synchronized (mLock) { + return MmTelFeature.this.getFeatureState(); + } + } + + + @Override + public ImsCallProfile createCallProfile(int callSessionType, int callType) + throws RemoteException { + synchronized (mLock) { + return MmTelFeature.this.createCallProfile(callSessionType, callType); + } + } + + @Override + public IImsCallSession createCallSession(ImsCallProfile profile, + IImsCallSessionListener listener) throws RemoteException { + synchronized (mLock) { + ImsCallSession s = MmTelFeature.this.createCallSession(profile, + new ImsCallSessionListener(listener)); + return s != null ? s.getSession() : null; + } + } + + @Override + public IImsUt getUtInterface() throws RemoteException { + synchronized (mLock) { + return MmTelFeature.this.getUt(); + } + } + + @Override + public IImsEcbm getEcbmInterface() throws RemoteException { + synchronized (mLock) { + return MmTelFeature.this.getEcbm(); + } + } + + @Override + public void setUiTtyMode(int uiTtyMode, Message onCompleteMessage) throws RemoteException { + synchronized (mLock) { + MmTelFeature.this.setUiTtyMode(uiTtyMode, onCompleteMessage); + } + } + + @Override + public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException { + synchronized (mLock) { + return MmTelFeature.this.getMultiEndpoint(); + } + } + + @Override + public int queryCapabilityStatus() throws RemoteException { + return MmTelFeature.this.queryCapabilityStatus().mCapabilities; + } + + @Override + public void addCapabilityCallback(IImsCapabilityCallback c) { + MmTelFeature.this.addCapabilityCallback(c); + } + + @Override + public void removeCapabilityCallback(IImsCapabilityCallback c) { + MmTelFeature.this.removeCapabilityCallback(c); + } + + @Override + public void changeCapabilitiesConfiguration(CapabilityChangeRequest request, + IImsCapabilityCallback c) throws RemoteException { + MmTelFeature.this.requestChangeEnabledCapabilities(request, c); + } + + @Override + public void queryCapabilityConfiguration(int capability, int radioTech, + IImsCapabilityCallback c) { + queryCapabilityConfigurationInternal(capability, radioTech, c); + } + }; + + /** + * Contains the capabilities defined and supported by a MmTelFeature in the form of a Bitmask. + * The capabilities that are used in MmTelFeature are defined by {@link MmTelCapability}. + * + * The capabilities of this MmTelFeature will be set by the framework and can be queried with + * {@link #queryCapabilityStatus()}. + * + * This MmTelFeature can then return the status of each of these capabilities (enabled or not) + * by sending a {@link #notifyCapabilitiesStatusChanged} callback to the framework. The current + * status can also be queried using {@link #queryCapabilityStatus()}. + */ + public static class MmTelCapabilities extends Capabilities { + + @VisibleForTesting + public MmTelCapabilities() { + super(); + } + + public MmTelCapabilities(Capabilities c) { + mCapabilities = c.mCapabilities; + } + + @IntDef(flag = true, + value = { + CAPABILITY_TYPE_VOICE, + CAPABILITY_TYPE_VIDEO, + CAPABILITY_TYPE_UT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MmTelCapability {} + + /** + * This MmTelFeature supports Voice calling (IR.92) + */ + public static final int CAPABILITY_TYPE_VOICE = 1 << 0; + + /** + * This MmTelFeature supports Video (IR.94) + */ + public static final int CAPABILITY_TYPE_VIDEO = 1 << 1; + + /** + * This MmTelFeature supports XCAP over Ut for supplementary services. (IR.92) + */ + public static final int CAPABILITY_TYPE_UT = 1 << 2; + + @Override + public final void addCapabilities(@MmTelCapability int capabilities) { + super.addCapabilities(capabilities); + } + + @Override + public final void removeCapabilities(@MmTelCapability int capability) { + super.removeCapabilities(capability); + } + + @Override + public final boolean isCapable(@MmTelCapability int capabilities) { + return super.isCapable(capabilities); + } + } + + /** + * Listener that the framework implements for communication from the MmTelFeature. + */ + public static class Listener extends IImsMmTelListener.Stub { + + @Override + public final void onIncomingCall(IImsCallSession c) { + onIncomingCall(new ImsCallSession(c)); + } + + /** + * Called when the IMS provider receives an incoming call. + * @param c The {@link ImsCallSession} associated with the new call. + */ + public void onIncomingCall(ImsCallSession c) { + } + } + + // Lock for feature synchronization + private final Object mLock = new Object(); + private IImsMmTelListener mListener; + + /** + * @param listener A {@link Listener} used when the MmTelFeature receives an incoming call and + * notifies the framework. + */ + private void setListener(IImsMmTelListener listener) { + synchronized (mLock) { + mListener = listener; + } + } + + private void queryCapabilityConfigurationInternal(int capability, int radioTech, + IImsCapabilityCallback c) { + boolean enabled = queryCapabilityConfiguration(capability, radioTech); + try { + if (c != null) { + c.onQueryCapabilityConfiguration(capability, radioTech, enabled); + } + } catch (RemoteException e) { + Log.e(LOG_TAG, "queryCapabilityConfigurationInternal called on dead binder!"); + } + } + + /** + * The current capability status that this MmTelFeature has defined is available. This + * configuration will be used by the platform to figure out which capabilities are CURRENTLY + * available to be used. + * + * Should be a subset of the capabilities that are enabled by the framework in + * {@link #changeEnabledCapabilities}. + * @return A copy of the current MmTelFeature capability status. + */ + @Override + public final MmTelCapabilities queryCapabilityStatus() { + return new MmTelCapabilities(super.queryCapabilityStatus()); + } + + /** + * Notify the framework that the status of the Capabilities has changed. Even though the + * MmTelFeature capability may be enabled by the framework, the status may be disabled due to + * the feature being unavailable from the network. + * @param c The current capability status of the MmTelFeature. If a capability is disabled, then + * the status of that capability is disabled. This can happen if the network does not currently + * support the capability that is enabled. A capability that is disabled by the framework (via + * {@link #changeEnabledCapabilities}) should also show the status as disabled. + */ + protected final void notifyCapabilitiesStatusChanged(MmTelCapabilities c) { + super.notifyCapabilitiesStatusChanged(c); + } + + /** + * Notify the framework of an incoming call. + * @param c The {@link ImsCallSession} of the new incoming call. + * + * @throws RemoteException if the connection to the framework is not available. If this happens, + * the call should be no longer considered active and should be cleaned up. + * */ + protected final void notifyIncomingCall(ImsCallSession c) throws RemoteException { + synchronized (mLock) { + if (mListener == null) { + throw new IllegalStateException("Session is not available."); + } + mListener.onIncomingCall(c.getSession()); + } + } + + /** + * Provides the MmTelFeature with the ability to return the framework Capability Configuration + * for a provided Capability. If the framework calls {@link #changeEnabledCapabilities} and + * includes a capability A to enable or disable, this method should return the correct enabled + * status for capability A. + * @param capability The capability that we are querying the configuration for. + * @return true if the capability is enabled, false otherwise. + */ + public boolean queryCapabilityConfiguration(@MmTelCapabilities.MmTelCapability int capability, + @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { + // Base implementation - Override to provide functionality + return false; + } + + /** + * The MmTelFeature should override this method to handle the enabling/disabling of + * MmTel Features, defined in {@link MmTelCapabilities.MmTelCapability}. The framework assumes + * the {@link CapabilityChangeRequest} was processed successfully. If a subset of capabilities + * could not be set to their new values, + * {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError} must be called + * individually for each capability whose processing resulted in an error. + * + * Enabling/Disabling a capability here indicates that the capability should be registered or + * deregistered (depending on the capability change) and become available or unavailable to + * the framework. + */ + @Override + public void changeEnabledCapabilities(CapabilityChangeRequest request, + CapabilityCallbackProxy c) { + // Base implementation, no-op + } + + /** + * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state. + * + * @param callSessionType a service type that is specified in {@link ImsCallProfile} + * {@link ImsCallProfile#SERVICE_TYPE_NONE} + * {@link ImsCallProfile#SERVICE_TYPE_NORMAL} + * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY} + * @param callType a call type that is specified in {@link ImsCallProfile} + * {@link ImsCallProfile#CALL_TYPE_VOICE} + * {@link ImsCallProfile#CALL_TYPE_VT} + * {@link ImsCallProfile#CALL_TYPE_VT_TX} + * {@link ImsCallProfile#CALL_TYPE_VT_RX} + * {@link ImsCallProfile#CALL_TYPE_VT_NODIR} + * {@link ImsCallProfile#CALL_TYPE_VS} + * {@link ImsCallProfile#CALL_TYPE_VS_TX} + * {@link ImsCallProfile#CALL_TYPE_VS_RX} + * @return a {@link ImsCallProfile} object + */ + public ImsCallProfile createCallProfile(int callSessionType, int callType) { + // Base Implementation - Should be overridden + return null; + } + + /** + * Creates an {@link ImsCallSession} with the specified call profile. + * Use other methods, if applicable, instead of interacting with + * {@link ImsCallSession} directly. + * + * @param profile a call profile to make the call + * @param listener An implementation of IImsCallSessionListener. + */ + public ImsCallSession createCallSession(ImsCallProfile profile, + ImsCallSessionListener listener) { + // Base Implementation - Should be overridden + return null; + } + + /** + * @return The Ut interface for the supplementary service configuration. + */ + public ImsUtImplBase getUt() { + // Base Implementation - Should be overridden + return null; + } + + /** + * @return The Emergency call-back mode interface for emergency VoLTE calls that support it. + */ + public ImsEcbmImplBase getEcbm() { + // Base Implementation - Should be overridden + return null; + } + + /** + * @return The Emergency call-back mode interface for emergency VoLTE calls that support it. + */ + public ImsMultiEndpointImplBase getMultiEndpoint() { + // Base Implementation - Should be overridden + return null; + } + + /** + * Sets the current UI TTY mode for the MmTelFeature. + * @param mode An integer containing the new UI TTY Mode, can consist of + * {@link TelecomManager#TTY_MODE_OFF}, + * {@link TelecomManager#TTY_MODE_FULL}, + * {@link TelecomManager#TTY_MODE_HCO}, + * {@link TelecomManager#TTY_MODE_VCO} + * @param onCompleteMessage A {@link Message} to be used when the mode has been set. + */ + void setUiTtyMode(int mode, Message onCompleteMessage) { + // Base Implementation - Should be overridden + } + + /**{@inheritDoc}*/ + @Override + public void onFeatureRemoved() { + // Base Implementation - Should be overridden + } + + /**{@inheritDoc}*/ + @Override + public void onFeatureReady() { + // Base Implementation - Should be overridden + } + + /** + * @hide + */ + @Override + public final IImsMmTelFeature getBinder() { + return mImsMMTelBinder; + } +} diff --git a/telephony/java/android/telephony/ims/internal/feature/RcsFeature.java b/telephony/java/android/telephony/ims/internal/feature/RcsFeature.java new file mode 100644 index 000000000000..8d1bd9d27f7c --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/feature/RcsFeature.java @@ -0,0 +1,59 @@ +/* + * 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 android.telephony.ims.internal.feature; + +import android.telephony.ims.internal.aidl.IImsRcsFeature; + +/** + * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend + * this class and provide implementations of the RcsFeature methods that they support. + * @hide + */ + +public class RcsFeature extends ImsFeature { + + private final IImsRcsFeature mImsRcsBinder = new IImsRcsFeature.Stub() { + // Empty Default Implementation. + }; + + + public RcsFeature() { + super(); + } + + @Override + public void changeEnabledCapabilities(CapabilityChangeRequest request, + CapabilityCallbackProxy c) { + // Do nothing for base implementation. + } + + @Override + public void onFeatureRemoved() { + + } + + /**{@inheritDoc}*/ + @Override + public void onFeatureReady() { + + } + + @Override + public final IImsRcsFeature getBinder() { + return mImsRcsBinder; + } +} diff --git a/telephony/java/android/telephony/ims/internal/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/internal/stub/ImsConfigImplBase.java new file mode 100644 index 000000000000..33aec5dfb8af --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/stub/ImsConfigImplBase.java @@ -0,0 +1,173 @@ +/* + * 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 android.telephony.ims.internal.stub; + +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.telephony.ims.internal.aidl.IImsConfig; +import android.telephony.ims.internal.aidl.IImsConfigCallback; + +import com.android.ims.ImsConfig; + +/** + * Controls the modification of IMS specific configurations. For more information on the supported + * IMS configuration constants, see {@link ImsConfig}. + * + * @hide + */ + +public class ImsConfigImplBase { + + //TODO: Implement the Binder logic to call base APIs. Need to finish other ImsService Config + // work first. + private final IImsConfig mBinder = new IImsConfig.Stub() { + + @Override + public void addImsConfigCallback(IImsConfigCallback c) throws RemoteException { + ImsConfigImplBase.this.addImsConfigCallback(c); + } + + @Override + public void removeImsConfigCallback(IImsConfigCallback c) throws RemoteException { + ImsConfigImplBase.this.removeImsConfigCallback(c); + } + + @Override + public int getConfigInt(int item) throws RemoteException { + return Integer.MIN_VALUE; + } + + @Override + public String getConfigString(int item) throws RemoteException { + return null; + } + + @Override + public int setConfigInt(int item, int value) throws RemoteException { + return Integer.MIN_VALUE; + } + + @Override + public int setConfigString(int item, String value) throws RemoteException { + return Integer.MIN_VALUE; + } + }; + + public class Callback extends IImsConfigCallback.Stub { + + @Override + public final void onIntConfigChanged(int item, int value) throws RemoteException { + onConfigChanged(item, value); + } + + @Override + public final void onStringConfigChanged(int item, String value) throws RemoteException { + onConfigChanged(item, value); + } + + /** + * Called when the IMS configuration has changed. + * @param item the IMS configuration key constant, as defined in ImsConfig. + * @param value the new integer value of the IMS configuration constant. + */ + public void onConfigChanged(int item, int value) { + // Base Implementation + } + + /** + * Called when the IMS configuration has changed. + * @param item the IMS configuration key constant, as defined in ImsConfig. + * @param value the new String value of the IMS configuration constant. + */ + public void onConfigChanged(int item, String value) { + // Base Implementation + } + } + + private final RemoteCallbackList<IImsConfigCallback> mCallbacks = new RemoteCallbackList<>(); + + /** + * Adds a {@link Callback} to the list of callbacks notified when a value in the configuration + * changes. + * @param c callback to add. + */ + private void addImsConfigCallback(IImsConfigCallback c) { + mCallbacks.register(c); + } + /** + * Removes a {@link Callback} to the list of callbacks notified when a value in the + * configuration changes. + * + * @param c callback to remove. + */ + private void removeImsConfigCallback(IImsConfigCallback c) { + mCallbacks.unregister(c); + } + + public final IImsConfig getBinder() { + return mBinder; + } + + /** + * Sets the value for IMS service/capabilities parameters by the operator device + * management entity. It sets the config item value in the provisioned storage + * from which the master value is derived. + * + * @param item as defined in com.android.ims.ImsConfig#ConfigConstants. + * @param value in Integer format. + * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants. + */ + public int setConfig(int item, int value) { + // Base Implementation - To be overridden. + return ImsConfig.OperationStatusConstants.FAILED; + } + + /** + * Sets the value for IMS service/capabilities parameters by the operator device + * management entity. It sets the config item value in the provisioned storage + * from which the master value is derived. + * + * @param item as defined in com.android.ims.ImsConfig#ConfigConstants. + * @param value in String format. + * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants. + */ + public int setConfig(int item, String value) { + return ImsConfig.OperationStatusConstants.FAILED; + } + + /** + * Gets the value for ims service/capabilities parameters from the provisioned + * value storage. + * + * @param item as defined in com.android.ims.ImsConfig#ConfigConstants. + * @return value in Integer format. + */ + public int getConfigInt(int item) { + return ImsConfig.OperationStatusConstants.FAILED; + } + + /** + * Gets the value for ims service/capabilities parameters from the provisioned + * value storage. + * + * @param item as defined in com.android.ims.ImsConfig#ConfigConstants. + * @return value in String format. + */ + public String getConfigString(int item) { + return null; + } +} diff --git a/telephony/java/android/telephony/ims/internal/stub/ImsFeatureConfiguration.aidl b/telephony/java/android/telephony/ims/internal/stub/ImsFeatureConfiguration.aidl new file mode 100644 index 000000000000..e890cf8756f3 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/stub/ImsFeatureConfiguration.aidl @@ -0,0 +1,19 @@ +/* + * 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 android.telephony.ims.internal.stub; + +parcelable ImsFeatureConfiguration; diff --git a/telephony/java/android/telephony/ims/internal/stub/ImsFeatureConfiguration.java b/telephony/java/android/telephony/ims/internal/stub/ImsFeatureConfiguration.java new file mode 100644 index 000000000000..244c9578f6b4 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/stub/ImsFeatureConfiguration.java @@ -0,0 +1,147 @@ +/* + * 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 android.telephony.ims.internal.stub; + +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.ims.internal.feature.ImsFeature; +import android.util.ArraySet; + +import java.util.Arrays; +import java.util.Set; + +/** + * Container class for IMS Feature configuration. This class contains the features that the + * ImsService supports, which are defined in {@link ImsFeature.FeatureType}. + * @hide + */ +public class ImsFeatureConfiguration implements Parcelable { + /** + * Features that this ImsService supports. + */ + private final Set<Integer> mFeatures; + + /** + * Creates an ImsFeatureConfiguration with the features + */ + public static class Builder { + ImsFeatureConfiguration mConfig; + public Builder() { + mConfig = new ImsFeatureConfiguration(); + } + + /** + * @param feature A feature defined in {@link ImsFeature.FeatureType} that this service + * supports. + * @return a {@link Builder} to continue constructing the ImsFeatureConfiguration. + */ + public Builder addFeature(@ImsFeature.FeatureType int feature) { + mConfig.addFeature(feature); + return this; + } + + public ImsFeatureConfiguration build() { + return mConfig; + } + } + + /** + * Creates with all registration features empty. + * + * Consider using the provided {@link Builder} to create this configuration instead. + */ + public ImsFeatureConfiguration() { + mFeatures = new ArraySet<>(); + } + + /** + * Configuration of the ImsService, which describes which features the ImsService supports + * (for registration). + * @param features an array of feature integers defined in {@link ImsFeature} that describe + * which features this ImsService supports. + */ + public ImsFeatureConfiguration(int[] features) { + mFeatures = new ArraySet<>(); + + if (features != null) { + for (int i : features) { + mFeatures.add(i); + } + } + } + + /** + * @return an int[] containing the features that this ImsService supports. + */ + public int[] getServiceFeatures() { + return mFeatures.stream().mapToInt(i->i).toArray(); + } + + void addFeature(int feature) { + mFeatures.add(feature); + } + + protected ImsFeatureConfiguration(Parcel in) { + int[] features = in.createIntArray(); + if (features != null) { + mFeatures = new ArraySet<>(features.length); + for(Integer i : features) { + mFeatures.add(i); + } + } else { + mFeatures = new ArraySet<>(); + } + } + + public static final Creator<ImsFeatureConfiguration> CREATOR + = new Creator<ImsFeatureConfiguration>() { + @Override + public ImsFeatureConfiguration createFromParcel(Parcel in) { + return new ImsFeatureConfiguration(in); + } + + @Override + public ImsFeatureConfiguration[] newArray(int size) { + return new ImsFeatureConfiguration[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeIntArray(mFeatures.stream().mapToInt(i->i).toArray()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ImsFeatureConfiguration)) return false; + + ImsFeatureConfiguration that = (ImsFeatureConfiguration) o; + + return mFeatures.equals(that.mFeatures); + } + + @Override + public int hashCode() { + return mFeatures.hashCode(); + } +} diff --git a/telephony/java/android/telephony/ims/internal/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/internal/stub/ImsRegistrationImplBase.java new file mode 100644 index 000000000000..558b009ab4c2 --- /dev/null +++ b/telephony/java/android/telephony/ims/internal/stub/ImsRegistrationImplBase.java @@ -0,0 +1,276 @@ +/* + * 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 android.telephony.ims.internal.stub; + +import android.annotation.IntDef; +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.telephony.ims.internal.aidl.IImsRegistration; +import android.telephony.ims.internal.aidl.IImsRegistrationCallback; +import android.util.Log; + +import com.android.ims.ImsReasonInfo; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Controls IMS registration for this ImsService and notifies the framework when the IMS + * registration for this ImsService has changed status. + * @hide + */ + +public class ImsRegistrationImplBase { + + private static final String LOG_TAG = "ImsRegistrationImplBase"; + + // Defines the underlying radio technology type that we have registered for IMS over. + @IntDef(flag = true, + value = { + REGISTRATION_TECH_NONE, + REGISTRATION_TECH_LTE, + REGISTRATION_TECH_IWLAN + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ImsRegistrationTech {} + /** + * No registration technology specified, used when we are not registered. + */ + public static final int REGISTRATION_TECH_NONE = -1; + /** + * IMS is registered to IMS via LTE. + */ + public static final int REGISTRATION_TECH_LTE = 0; + /** + * IMS is registered to IMS via IWLAN. + */ + public static final int REGISTRATION_TECH_IWLAN = 1; + + // Registration states, used to notify new ImsRegistrationImplBase#Callbacks of the current + // state. + private static final int REGISTRATION_STATE_NOT_REGISTERED = 0; + private static final int REGISTRATION_STATE_REGISTERING = 1; + private static final int REGISTRATION_STATE_REGISTERED = 2; + + + /** + * Callback class for receiving Registration callback events. + */ + public static class Callback extends IImsRegistrationCallback.Stub { + + /** + * Notifies the framework when the IMS Provider is connected to the IMS network. + * + * @param imsRadioTech the radio access technology. Valid values are defined in + * {@link ImsRegistrationTech}. + */ + @Override + public void onRegistered(@ImsRegistrationTech int imsRadioTech) { + } + + /** + * Notifies the framework when the IMS Provider is trying to connect the IMS network. + * + * @param imsRadioTech the radio access technology. Valid values are defined in + * {@link ImsRegistrationTech}. + */ + @Override + public void onRegistering(@ImsRegistrationTech int imsRadioTech) { + } + + /** + * Notifies the framework when the IMS Provider is disconnected from the IMS network. + * + * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. + */ + @Override + public void onDeregistered(ImsReasonInfo info) { + } + + /** + * A failure has occurred when trying to handover registration to another technology type, + * defined in {@link ImsRegistrationTech} + * + * @param imsRadioTech The {@link ImsRegistrationTech} type that has failed + * @param info A {@link ImsReasonInfo} that identifies the reason for failure. + */ + @Override + public void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech, + ImsReasonInfo info) { + } + } + + private final IImsRegistration mBinder = new IImsRegistration.Stub() { + + @Override + public @ImsRegistrationTech int getRegistrationTechnology() throws RemoteException { + return getConnectionType(); + } + + @Override + public void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException { + ImsRegistrationImplBase.this.addRegistrationCallback(c); + } + + @Override + public void removeRegistrationCallback(IImsRegistrationCallback c) throws RemoteException { + ImsRegistrationImplBase.this.removeRegistrationCallback(c); + } + }; + + private final RemoteCallbackList<IImsRegistrationCallback> mCallbacks + = new RemoteCallbackList<>(); + private final Object mLock = new Object(); + // Locked on mLock + private @ImsRegistrationTech + int mConnectionType = REGISTRATION_TECH_NONE; + // Locked on mLock + private int mRegistrationState = REGISTRATION_STATE_NOT_REGISTERED; + // Locked on mLock + private ImsReasonInfo mLastDisconnectCause; + + public final IImsRegistration getBinder() { + return mBinder; + } + + private void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException { + mCallbacks.register(c); + updateNewCallbackWithState(c); + } + + private void removeRegistrationCallback(IImsRegistrationCallback c) { + mCallbacks.unregister(c); + } + + /** + * Notify the framework that the device is connected to the IMS network. + * + * @param imsRadioTech the radio access technology. Valid values are defined in + * {@link ImsRegistrationTech}. + */ + public final void onRegistered(@ImsRegistrationTech int imsRadioTech) { + updateToState(imsRadioTech, REGISTRATION_STATE_REGISTERED); + mCallbacks.broadcast((c) -> { + try { + c.onRegistered(imsRadioTech); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + " " + "onRegistrationConnected() - Skipping " + + "callback."); + } + }); + } + + /** + * Notify the framework that the device is trying to connect the IMS network. + * + * @param imsRadioTech the radio access technology. Valid values are defined in + * {@link ImsRegistrationTech}. + */ + public final void onRegistering(@ImsRegistrationTech int imsRadioTech) { + updateToState(imsRadioTech, REGISTRATION_STATE_REGISTERING); + mCallbacks.broadcast((c) -> { + try { + c.onRegistering(imsRadioTech); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + " " + "onRegistrationProcessing() - Skipping " + + "callback."); + } + }); + } + + /** + * Notify the framework that the device is disconnected from the IMS network. + * + * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. + */ + public final void onDeregistered(ImsReasonInfo info) { + updateToDisconnectedState(info); + mCallbacks.broadcast((c) -> { + try { + c.onDeregistered(info); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + " " + "onRegistrationDisconnected() - Skipping " + + "callback."); + } + }); + } + + public final void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech, + ImsReasonInfo info) { + mCallbacks.broadcast((c) -> { + try { + c.onTechnologyChangeFailed(imsRadioTech, info); + } catch (RemoteException e) { + Log.w(LOG_TAG, e + " " + "onRegistrationChangeFailed() - Skipping " + + "callback."); + } + }); + } + + private void updateToState(@ImsRegistrationTech int connType, int newState) { + synchronized (mLock) { + mConnectionType = connType; + mRegistrationState = newState; + mLastDisconnectCause = null; + } + } + + private void updateToDisconnectedState(ImsReasonInfo info) { + synchronized (mLock) { + updateToState(REGISTRATION_TECH_NONE, REGISTRATION_STATE_NOT_REGISTERED); + if (info != null) { + mLastDisconnectCause = info; + } else { + Log.w(LOG_TAG, "updateToDisconnectedState: no ImsReasonInfo provided."); + mLastDisconnectCause = new ImsReasonInfo(); + } + } + } + + private @ImsRegistrationTech int getConnectionType() { + synchronized (mLock) { + return mConnectionType; + } + } + + /** + * @param c the newly registered callback that will be updated with the current registration + * state. + */ + private void updateNewCallbackWithState(IImsRegistrationCallback c) throws RemoteException { + int state; + ImsReasonInfo disconnectInfo; + synchronized (mLock) { + state = mRegistrationState; + disconnectInfo = mLastDisconnectCause; + } + switch (state) { + case REGISTRATION_STATE_NOT_REGISTERED: { + c.onDeregistered(disconnectInfo); + break; + } + case REGISTRATION_STATE_REGISTERING: { + c.onRegistering(getConnectionType()); + break; + } + case REGISTRATION_STATE_REGISTERED: { + c.onRegistered(getConnectionType()); + break; + } + } + } +} |