Automatic sources dropoff on 2020-06-10 18:32:38.095721
The change is generated with prebuilt drop tool.
Change-Id: I24cbf6ba6db262a1ae1445db1427a08fee35b3b4
diff --git a/android/telephony/ims/feature/ImsFeature.java b/android/telephony/ims/feature/ImsFeature.java
new file mode 100644
index 0000000..e5779b3
--- /dev/null
+++ b/android/telephony/ims/feature/ImsFeature.java
@@ -0,0 +1,552 @@
+/*
+ * Copyright (C) 2018 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.feature;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.content.Context;
+import android.os.IInterface;
+import android.os.RemoteException;
+import android.telephony.SubscriptionManager;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+
+import com.android.ims.internal.IImsFeatureStatusCallback;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.util.RemoteCallbackListExt;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Base class for all IMS features that are supported by the framework. Use a concrete subclass
+ * of {@link ImsFeature}, such as {@link MmTelFeature} or {@link RcsFeature}.
+ *
+ * @hide
+ */
+@SystemApi
+@TestApi
+public abstract class ImsFeature {
+
+ private static final String LOG_TAG = "ImsFeature";
+
+ /**
+ * Invalid feature value
+ * @hide
+ */
+ 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.
+ /**
+ * This feature supports emergency calling over MMTEL. If defined, the framework will try to
+ * place an emergency call over IMS first. If it is not defined, the framework will only use
+ * CSFB for emergency calling.
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final int FEATURE_EMERGENCY_MMTEL = 0;
+ /**
+ * This feature supports the MMTEL feature.
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final int FEATURE_MMTEL = 1;
+ /**
+ * This feature supports the RCS feature.
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final int FEATURE_RCS = 2;
+ /**
+ * Total number of features defined
+ * @hide
+ */
+ public static final int FEATURE_MAX = 3;
+
+ /**
+ * Used for logging purposes.
+ * @hide
+ */
+ public static final Map<Integer, String> FEATURE_LOG_MAP = new HashMap<Integer, String>() {{
+ put(FEATURE_EMERGENCY_MMTEL, "EMERGENCY_MMTEL");
+ put(FEATURE_MMTEL, "MMTEL");
+ put(FEATURE_RCS, "RCS");
+ }};
+
+ /**
+ * Integer values defining IMS features that are supported in ImsFeature.
+ * @hide
+ */
+ @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.
+ * @hide
+ */
+ @IntDef(flag = true,
+ value = {
+ STATE_UNAVAILABLE,
+ STATE_INITIALIZING,
+ STATE_READY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ImsState {}
+
+ /**
+ * This {@link ImsFeature}'s state is unavailable and should not be communicated with. This will
+ * remove all bindings back to the framework. Any attempt to communicate with the framework
+ * during this time will result in an {@link IllegalStateException}.
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final int STATE_UNAVAILABLE = 0;
+ /**
+ * This {@link ImsFeature} state is initializing and should not be communicated with. This will
+ * remove all bindings back to the framework. Any attempt to communicate with the framework
+ * during this time will result in an {@link IllegalStateException}.
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final int STATE_INITIALIZING = 1;
+ /**
+ * This {@link ImsFeature} is ready for communication. Do not attempt to call framework methods
+ * until {@see #onFeatureReady()} is called.
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final int STATE_READY = 2;
+
+ /**
+ * Used for logging purposes.
+ * @hide
+ */
+ public static final Map<Integer, String> STATE_LOG_MAP = new HashMap<Integer, String>() {{
+ put(STATE_UNAVAILABLE, "UNAVAILABLE");
+ put(STATE_INITIALIZING, "INITIALIZING");
+ put(STATE_READY, "READY");
+ }};
+
+ /**
+ * Integer values defining the result codes that should be returned from
+ * {@link #changeEnabledCapabilities} when the framework tries to set a feature's capability.
+ * @hide
+ */
+ @IntDef(flag = true,
+ value = {
+ CAPABILITY_ERROR_GENERIC,
+ CAPABILITY_SUCCESS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ImsCapabilityError {}
+
+ /**
+ * The capability was unable to be changed.
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final int CAPABILITY_ERROR_GENERIC = -1;
+ /**
+ * The capability was able to be changed.
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final int CAPABILITY_SUCCESS = 0;
+
+ /**
+ * Used by the ImsFeature to call back to the CapabilityCallback that the framework has
+ * provided.
+ */
+ protected static class CapabilityCallbackProxy {
+ private final IImsCapabilityCallback mCallback;
+
+ /** @hide */
+ 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, defined as
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, or
+ * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}.
+ * @param radioTech The radio tech that this capability failed for, defined as
+ * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} or
+ * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}.
+ * @param reason The reason this capability was unable to be changed, defined as
+ * {@link #CAPABILITY_ERROR_GENERIC} or {@link #CAPABILITY_SUCCESS}.
+ */
+ public void onChangeCapabilityConfigurationError(int capability, int radioTech,
+ @ImsCapabilityError int reason) {
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ mCallback.onChangeCapabilityConfigurationError(capability, radioTech, reason);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "onChangeCapabilityConfigurationError called on dead binder.");
+ }
+ }
+ }
+
+ /**
+ * Contains the IMS capabilities defined and supported by an ImsFeature in the form of a
+ * bit-mask.
+ *
+ * @deprecated This class is not used directly, but rather extended in subclasses of
+ * {@link ImsFeature} to provide service specific capabilities.
+ * @see MmTelFeature.MmTelCapabilities
+ * @hide
+ */
+ // Not Actually deprecated, but we need to remove it from the @SystemApi surface.
+ @Deprecated
+ @SystemApi // SystemApi only because it was leaked through type usage in a previous release.
+ @TestApi
+ public static class Capabilities {
+ /** @deprecated Use getters and accessors instead. */
+ // Not actually deprecated, but we need to remove it from the @SystemApi surface eventually.
+ protected int mCapabilities = 0;
+
+ /**
+ * @hide
+ */
+ public Capabilities() {
+ }
+
+ /**
+ * @hide
+ */
+ protected Capabilities(int capabilities) {
+ mCapabilities = capabilities;
+ }
+
+ /**
+ * @param capabilities Capabilities to be added to the configuration in the form of a
+ * bit mask.
+ * @hide
+ */
+ public void addCapabilities(int capabilities) {
+ mCapabilities |= capabilities;
+ }
+
+ /**
+ * @param capabilities Capabilities to be removed to the configuration in the form of a
+ * bit mask.
+ * @hide
+ */
+ public void removeCapabilities(int capabilities) {
+ mCapabilities &= ~capabilities;
+ }
+
+ /**
+ * @return true if all of the capabilities specified are capable.
+ * @hide
+ */
+ public boolean isCapable(int capabilities) {
+ return (mCapabilities & capabilities) == capabilities;
+ }
+
+ /**
+ * @return a deep copy of the Capabilites.
+ * @hide
+ */
+ public Capabilities copy() {
+ return new Capabilities(mCapabilities);
+ }
+
+ /**
+ * @return a bitmask containing the capability flags directly.
+ * @hide
+ */
+ public int getMask() {
+ return mCapabilities;
+ }
+
+ /**
+ * @hide
+ */
+ @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;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public int hashCode() {
+ return mCapabilities;
+ }
+
+ /**
+ * @hide
+ */
+ @Override
+ public String toString() {
+ return "Capabilities: " + Integer.toBinaryString(mCapabilities);
+ }
+ }
+
+ /** @hide */
+ protected Context mContext;
+ /** @hide */
+ protected final Object mLock = new Object();
+
+ private final RemoteCallbackListExt<IImsFeatureStatusCallback> mStatusCallbacks =
+ new RemoteCallbackListExt<>();
+ private @ImsState int mState = STATE_UNAVAILABLE;
+ private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+ private final RemoteCallbackListExt<IImsCapabilityCallback> mCapabilityCallbacks =
+ new RemoteCallbackListExt<>();
+ private Capabilities mCapabilityStatus = new Capabilities();
+
+ /**
+ * @hide
+ */
+ public final void initialize(Context context, int slotId) {
+ mContext = context;
+ mSlotId = slotId;
+ }
+
+ /**
+ * @return The SIM slot index associated with this ImsFeature.
+ *
+ * @see SubscriptionManager#getSubscriptionIds(int) for more information on getting the
+ * subscription IDs associated with this slot.
+ * @hide
+ */
+ @SystemApi @TestApi
+ public final int getSlotIndex() {
+ return mSlotId;
+ }
+
+ /**
+ * @return The current state of the ImsFeature, set previously by {@link #setFeatureState(int)}
+ * or {@link #STATE_UNAVAILABLE} if it has not been updated yet.
+ * @hide
+ */
+ @SystemApi @TestApi
+ public @ImsState int getFeatureState() {
+ synchronized (mLock) {
+ return mState;
+ }
+ }
+
+ /**
+ * Set the state of the ImsFeature. The state is used as a signal to the framework to start or
+ * stop communication, depending on the state sent.
+ * @param state The ImsFeature's state, defined as {@link #STATE_UNAVAILABLE},
+ * {@link #STATE_INITIALIZING}, or {@link #STATE_READY}.
+ * @hide
+ */
+ @SystemApi @TestApi
+ public final void setFeatureState(@ImsState int state) {
+ synchronized (mLock) {
+ if (mState != state) {
+ mState = state;
+ notifyFeatureState(state);
+ }
+ }
+ }
+
+ /**
+ * Not final for testing, but shouldn't be extended!
+ * @hide
+ */
+ @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.
+ mStatusCallbacks.register(c);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Not final for testing, but shouldn't be extended!
+ * @hide
+ */
+ @VisibleForTesting
+ public void removeImsFeatureStatusCallback(@NonNull IImsFeatureStatusCallback c) {
+ mStatusCallbacks.unregister(c);
+ }
+
+ /**
+ * Internal method called by ImsFeature when setFeatureState has changed.
+ */
+ private void notifyFeatureState(@ImsState int state) {
+ mStatusCallbacks.broadcastAction((c) -> {
+ try {
+ c.notifyImsFeatureStatus(state);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, e + " notifyFeatureState() - Skipping "
+ + "callback.");
+ }
+ });
+ }
+
+ /**
+ * @hide
+ */
+ public final void addCapabilityCallback(IImsCapabilityCallback c) {
+ mCapabilityCallbacks.register(c);
+ try {
+ // Notify the Capability callback that was just registered of the current capabilities.
+ c.onCapabilitiesStatusChanged(queryCapabilityStatus().mCapabilities);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "addCapabilityCallback: error accessing callback: " + e.getMessage());
+ }
+ }
+
+ /**
+ * @hide
+ */
+ final void removeCapabilityCallback(IImsCapabilityCallback c) {
+ mCapabilityCallbacks.unregister(c);
+ }
+
+ /**@hide*/
+ final 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!");
+ }
+ }
+
+ /**
+ * @return the cached capabilities status for this feature.
+ * @hide
+ */
+ @VisibleForTesting
+ public Capabilities queryCapabilityStatus() {
+ synchronized (mLock) {
+ return mCapabilityStatus.copy();
+ }
+ }
+
+ /**
+ * Called internally to request the change of enabled capabilities.
+ * @hide
+ */
+ @VisibleForTesting
+ public final void requestChangeEnabledCapabilities(CapabilityChangeRequest request,
+ IImsCapabilityCallback c) {
+ 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 caps the new {@link Capabilities} status of the {@link ImsFeature}.
+ *
+ * @hide
+ */
+ protected final void notifyCapabilitiesStatusChanged(Capabilities caps) {
+ synchronized (mLock) {
+ mCapabilityStatus = caps.copy();
+ }
+ mCapabilityCallbacks.broadcastAction((callback) -> {
+ try {
+ callback.onCapabilitiesStatusChanged(caps.mCapabilities);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, e + " notifyCapabilitiesStatusChanged() - Skipping "
+ + "callback.");
+ }
+ });
+ }
+
+ /**
+ * Provides the ImsFeature 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.
+ * @hide
+ */
+ public abstract boolean queryCapabilityConfiguration(int capability, int radioTech);
+
+ /**
+ * 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 after this ImsFeature has been initialized and has been set to the
+ * {@link ImsState#STATE_READY} state.
+ * <p>
+ * 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.
+ * @hide
+ */
+ protected abstract IInterface getBinder();
+}