Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 235d7a46 authored by Jonggeon Kim's avatar Jonggeon Kim
Browse files

ImsService Subscription Notifications

Provide a new API in ImsService that creates a new version of each ImsFeature and dependencies when a new subId is loaded.
The ImsService handles ImsFeature setup and teardown procedures to happen on a per-subscription basis instead of on a per-slot basis.
Provide the compatibility behavior for older devices that are not upgrading to using the new API.

Bug: 197991451
Test: atest FrameworksTelephonyTests:ImsServiceTest, atest CtsTelephonyTestCases:ImsServiceTest

Change-Id: I231da2f4479d4a4fb272edbf27e49f46833a082a
parent 967a70e5
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -14037,14 +14037,21 @@ package android.telephony.ims {
  public class ImsService extends android.app.Service {
    ctor public ImsService();
    method public android.telephony.ims.feature.MmTelFeature createMmTelFeature(int);
    method public android.telephony.ims.feature.RcsFeature createRcsFeature(int);
    method public void disableIms(int);
    method public void enableIms(int);
    method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int);
    method @Nullable public android.telephony.ims.feature.MmTelFeature createEmergencyOnlyMmTelFeature(int);
    method @Deprecated public android.telephony.ims.feature.MmTelFeature createMmTelFeature(int);
    method @Nullable public android.telephony.ims.feature.MmTelFeature createMmTelFeatureForSubscription(int, int);
    method @Deprecated public android.telephony.ims.feature.RcsFeature createRcsFeature(int);
    method @Nullable public android.telephony.ims.feature.RcsFeature createRcsFeatureForSubscription(int, int);
    method @Deprecated public void disableIms(int);
    method public void disableImsForSubscription(int, int);
    method @Deprecated public void enableIms(int);
    method public void enableImsForSubscription(int, int);
    method @Deprecated public android.telephony.ims.stub.ImsConfigImplBase getConfig(int);
    method @NonNull public android.telephony.ims.stub.ImsConfigImplBase getConfigForSubscription(int, int);
    method @NonNull public java.util.concurrent.Executor getExecutor();
    method public long getImsServiceCapabilities();
    method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int);
    method @Deprecated public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int);
    method @NonNull public android.telephony.ims.stub.ImsRegistrationImplBase getRegistrationForSubscription(int, int);
    method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int);
    method public final void onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) throws android.os.RemoteException;
    method public android.telephony.ims.stub.ImsFeatureConfiguration querySupportedImsFeatures();
+208 −26
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.telephony.ims.stub.SipTransportImplBase;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;

import com.android.ims.internal.IImsFeatureStatusCallback;
import com.android.internal.annotations.VisibleForTesting;
@@ -180,6 +181,12 @@ public class ImsService extends Service {
    // call ImsFeature#onFeatureRemoved.
    private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>();

    // A map of slot id -> boolean array, where each entry in the boolean array corresponds to an
    // ImsFeature that was created for a slot id and not a sub id for backwards compatibility
    // purposes.
    private final SparseArray<SparseBooleanArray> mCreateImsFeatureWithSlotIdFlagMap =
            new SparseArray<>();

    private IImsServiceControllerListener mListener;
    private Executor mExecutor;

@@ -222,15 +229,36 @@ public class ImsService extends Service {
        }

        @Override
        public IImsMmTelFeature createMmTelFeature(int slotId) {
            return executeMethodAsyncForResult(() -> createMmTelFeatureInternal(slotId),
        public IImsMmTelFeature createMmTelFeature(int slotId, int subId) {
            MmTelFeature f  = (MmTelFeature) getImsFeature(slotId, ImsFeature.FEATURE_MMTEL);
            if (f == null) {
                return executeMethodAsyncForResult(() -> createMmTelFeatureInternal(slotId, subId),
                        "createMmTelFeature");
            } else {
                return f.getBinder();
            }
        }

        @Override
        public IImsRcsFeature createRcsFeature(int slotId) {
            return executeMethodAsyncForResult(() -> createRcsFeatureInternal(slotId),
                "createRcsFeature");
        public IImsMmTelFeature createEmergencyOnlyMmTelFeature(int slotId) {
            MmTelFeature f  = (MmTelFeature) getImsFeature(slotId, ImsFeature.FEATURE_MMTEL);
            if (f == null) {
                return executeMethodAsyncForResult(() -> createEmergencyOnlyMmTelFeatureInternal(
                        slotId), "createEmergencyOnlyMmTelFeature");
            } else {
                return f.getBinder();
            }
        }

        @Override
        public IImsRcsFeature createRcsFeature(int slotId, int subId) {
            RcsFeature f  = (RcsFeature) getImsFeature(slotId, ImsFeature.FEATURE_RCS);
            if (f == null) {
                return executeMethodAsyncForResult(() ->
                        createRcsFeatureInternal(slotId, subId), "createRcsFeature");
            } else {
                return f.getBinder();
            }
        }

        @Override
@@ -248,9 +276,14 @@ public class ImsService extends Service {
        }

        @Override
        public void removeImsFeature(int slotId, int featureType) {
        public void removeImsFeature(int slotId, int featureType, boolean changeSubId) {
            if (changeSubId && isImsFeatureCreatedForSlot(slotId, featureType)) {
                Log.w(LOG_TAG, "Do not remove Ims feature for compatibility");
                return;
            }
            executeMethodAsync(() -> ImsService.this.removeImsFeature(slotId, featureType),
                    "removeImsFeature");
            setImsFeatureCreatedForSlot(slotId, featureType, false);
        }

        @Override
@@ -279,9 +312,10 @@ public class ImsService extends Service {
        }

        @Override
        public IImsConfig getConfig(int slotId) {
        public IImsConfig getConfig(int slotId, int subId) {
            return executeMethodAsyncForResult(() -> {
                ImsConfigImplBase c = ImsService.this.getConfig(slotId);
                ImsConfigImplBase c =
                        ImsService.this.getConfigForSubscription(slotId, subId);
                if (c != null) {
                    c.setDefaultExecutor(mExecutor);
                    return c.getIImsConfig();
@@ -292,9 +326,10 @@ public class ImsService extends Service {
        }

        @Override
        public IImsRegistration getRegistration(int slotId) {
        public IImsRegistration getRegistration(int slotId, int subId) {
            return executeMethodAsyncForResult(() -> {
                ImsRegistrationImplBase r =  ImsService.this.getRegistration(slotId);
                ImsRegistrationImplBase r =
                        ImsService.this.getRegistrationForSubscription(slotId, subId);
                if (r != null) {
                    r.setDefaultExecutor(mExecutor);
                    return r.getBinder();
@@ -318,13 +353,15 @@ public class ImsService extends Service {
        }

        @Override
        public void enableIms(int slotId) {
            executeMethodAsync(() -> ImsService.this.enableIms(slotId), "enableIms");
        public void enableIms(int slotId, int subId) {
            executeMethodAsync(() ->
                    ImsService.this.enableImsForSubscription(slotId, subId), "enableIms");
        }

        @Override
        public void disableIms(int slotId) {
            executeMethodAsync(() -> ImsService.this.disableIms(slotId), "disableIms");
        public void disableIms(int slotId, int subId) {
            executeMethodAsync(() ->
                    ImsService.this.disableImsForSubscription(slotId, subId), "disableIms");
        }

        // Call the methods with a clean calling identity on the executor and wait indefinitely for
@@ -364,28 +401,32 @@ public class ImsService extends Service {
        return null;
    }

    /**
     * @hide
     */
    @VisibleForTesting
    public SparseArray<ImsFeature> getFeatures(int slotId) {
        return mFeaturesBySlot.get(slotId);
    private IImsMmTelFeature createMmTelFeatureInternal(int slotId, int subscriptionId) {
        MmTelFeature f = createMmTelFeatureForSubscription(slotId, subscriptionId);
        if (f != null) {
            setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL);
            f.setDefaultExecutor(mExecutor);
            return f.getBinder();
        } else {
            Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned.");
            return null;
        }
    }

    private IImsMmTelFeature createMmTelFeatureInternal(int slotId) {
        MmTelFeature f = createMmTelFeature(slotId);
    private IImsMmTelFeature createEmergencyOnlyMmTelFeatureInternal(int slotId) {
        MmTelFeature f = createEmergencyOnlyMmTelFeature(slotId);
        if (f != null) {
            setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL);
            f.setDefaultExecutor(mExecutor);
            return f.getBinder();
        } else {
            Log.e(LOG_TAG, "createMmTelFeatureInternal: null feature returned.");
            Log.e(LOG_TAG, "createEmergencyOnlyMmTelFeatureInternal: null feature returned.");
            return null;
        }
    }

    private IImsRcsFeature createRcsFeatureInternal(int slotId) {
        RcsFeature f = createRcsFeature(slotId);
    private IImsRcsFeature createRcsFeatureInternal(int slotId, int subI) {
        RcsFeature f = createRcsFeatureForSubscription(slotId, subI);
        if (f != null) {
            f.setDefaultExecutor(mExecutor);
            setupFeature(f, slotId, ImsFeature.FEATURE_RCS);
@@ -466,6 +507,49 @@ public class ImsService extends Service {
            f.onFeatureRemoved();
            features.remove(featureType);
        }

    }

    /**
     * @hide
     */
    @VisibleForTesting
    public ImsFeature getImsFeature(int slotId, int featureType) {
        synchronized (mFeaturesBySlot) {
            // Get SparseArray for Features, by querying slot Id
            SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
            if (features == null) {
                return null;
            }
            return features.get(featureType);
        }
    }

    private void setImsFeatureCreatedForSlot(int slotId,
            @ImsFeature.FeatureType int featureType, boolean createdForSlot) {
        synchronized (mCreateImsFeatureWithSlotIdFlagMap) {
            getImsFeatureCreatedForSlot(slotId).put(featureType, createdForSlot);
        }
    }

    /**
     * @hide
     */
    @VisibleForTesting
    public boolean isImsFeatureCreatedForSlot(int slotId,
            @ImsFeature.FeatureType int featureType) {
        synchronized (mCreateImsFeatureWithSlotIdFlagMap) {
            return getImsFeatureCreatedForSlot(slotId).get(featureType);
        }
    }

    private SparseBooleanArray getImsFeatureCreatedForSlot(int slotId) {
        SparseBooleanArray createFlag = mCreateImsFeatureWithSlotIdFlagMap.get(slotId);
        if (createFlag == null) {
            createFlag = new SparseBooleanArray();
            mCreateImsFeatureWithSlotIdFlagMap.put(slotId, createFlag);
        }
        return createFlag;
    }

    /**
@@ -523,28 +607,96 @@ public class ImsService extends Service {
    public void readyForFeatureCreation() {
    }

    /**
     * The framework has enabled IMS for the subscription specified, the ImsService should register
     * for IMS and perform all appropriate initialization to bring up all ImsFeatures.
     *
     * @param slotId The slot ID that IMS will be enabled for.
     * @param subscriptionId The subscription ID that IMS will be enabled for.
     */
    public void enableImsForSubscription(int slotId, int subscriptionId) {
        enableIms(slotId);
    }

    /**
     * The framework has disabled IMS for the subscription specified. The ImsService must deregister
     * for IMS and set capability status to false for all ImsFeatures.
     * @param slotId The slot ID that IMS will be disabled for.
     * @param subscriptionId The subscription ID that IMS will be disabled for.
     */
    public void disableImsForSubscription(int slotId, int subscriptionId) {
        disableIms(slotId);
    }

    /**
     * The framework has enabled IMS for the slot specified, the ImsService should register for IMS
     * and perform all appropriate initialization to bring up all ImsFeatures.
     * @deprecated Use {@link #enableImsForSubscription} instead.
     */
    @Deprecated
    public void enableIms(int slotId) {
    }

    /**
     * The framework has disabled IMS for the slot specified. The ImsService must deregister for IMS
     * and set capability status to false for all ImsFeatures.
     * @deprecated Use {@link #disableImsForSubscription} instead.
     */
    @Deprecated
    public void disableIms(int slotId) {
    }

    /**
     * When called, the framework is requesting that a new {@link MmTelFeature} is created for the
     * specified subscription.
     *
     * @param subscriptionId The subscription ID that the MMTEL Feature is being created for.
     * @return The newly created {@link MmTelFeature} associated with the subscription or null if
     * the feature is not supported.
     */
    public @Nullable MmTelFeature createMmTelFeatureForSubscription(int slotId,
            int subscriptionId) {
        setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_MMTEL, true);
        return createMmTelFeature(slotId);
    }

    /**
     * When called, the framework is requesting that a new {@link RcsFeature} is created for the
     * specified subscription.
     *
     * @param subscriptionId The subscription ID that the RCS Feature is being created for.
     * @return The newly created {@link RcsFeature} associated with the subscription or null if the
     * feature is not supported.
     */
    public @Nullable RcsFeature createRcsFeatureForSubscription(int slotId, int subscriptionId) {
        setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_RCS, true);
        return createRcsFeature(slotId);
    }

    /**
     * When called, the framework is requesting that a new emergency-only {@link MmTelFeature} is
     * created for the specified slot. For emergency calls, there is no known Subscription Id.
     *
     * @param slotId The slot ID that the MMTEL Feature is being created for.
     * @return An MmTelFeature instance to be used for the slot ID when there is not
     * subscription inserted. Only requested when there is no subscription active on
     * the specified slot.
     */
    public @Nullable MmTelFeature createEmergencyOnlyMmTelFeature(int slotId) {
        setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_MMTEL, true);
        return createMmTelFeature(slotId);
    }

    /**
     * When called, the framework is requesting that a new {@link MmTelFeature} is created for the
     * specified slot.
     * @deprecated Use {@link #createMmTelFeatureForSubscription} instead
     *
     * @param slotId The slot ID that the MMTEL Feature is being created for.
     * @return The newly created {@link MmTelFeature} associated with the slot or null if the
     * feature is not supported.
     */
    @Deprecated
    public MmTelFeature createMmTelFeature(int slotId) {
        return null;
    }
@@ -552,32 +704,62 @@ public class ImsService extends Service {
    /**
     * When called, the framework is requesting that a new {@link RcsFeature} is created for the
     * specified slot.
     * @deprecated Use {@link #createRcsFeatureForSubscription} instead
     *
     * @param slotId The slot ID that the RCS Feature is being created for.
     * @return The newly created {@link RcsFeature} associated with the slot or null if the feature
     * is not supported.
     */
    @Deprecated
    public RcsFeature createRcsFeature(int slotId) {
        return null;
    }

    /**
     * Return the {@link ImsConfigImplBase} implementation associated with the provided
     * subscription. This will be used by the platform to get/set specific IMS related
     * configurations.
     *
     * @param subscriptionId The subscription ID that the IMS configuration is associated with.
     * @return ImsConfig implementation that is associated with the specified subscription.
     */
    public @NonNull ImsConfigImplBase getConfigForSubscription(int slotId, int subscriptionId) {
        return getConfig(slotId);
    }

    /**
     * Return the {@link ImsRegistrationImplBase} implementation associated with the provided
     * subscription.
     *
     * @param subscriptionId The subscription ID that is associated with the IMS Registration.
     * @return the ImsRegistration implementation associated with the subscription.
     */
    public @NonNull ImsRegistrationImplBase getRegistrationForSubscription(int slotId,
            int subscriptionId) {
        return getRegistration(slotId);
    }

    /**
     * Return the {@link ImsConfigImplBase} implementation associated with the provided slot. This
     * will be used by the platform to get/set specific IMS related configurations.
     * @deprecated use {@link #getConfigForSubscription} instead.
     *
     * @param slotId The slot that the IMS configuration is associated with.
     * @return ImsConfig implementation that is associated with the specified slot.
     */
    @Deprecated
    public ImsConfigImplBase getConfig(int slotId) {
        return new ImsConfigImplBase();
    }

    /**
     * Return the {@link ImsRegistrationImplBase} implementation associated with the provided slot.
     * @deprecated use  {@link #getRegistrationForSubscription} instead.
     *
     * @param slotId The slot that is associated with the IMS Registration.
     * @return the ImsRegistration implementation associated with the slot.
     */
    @Deprecated
    public ImsRegistrationImplBase getRegistration(int slotId) {
        return new ImsRegistrationImplBase();
    }
+8 −7
Original line number Diff line number Diff line
@@ -32,18 +32,19 @@ import com.android.ims.internal.IImsFeatureStatusCallback;
 */
interface IImsServiceController {
    void setListener(IImsServiceControllerListener l);
    IImsMmTelFeature createMmTelFeature(int slotId);
    IImsRcsFeature createRcsFeature(int slotId);
    IImsMmTelFeature createMmTelFeature(int slotId, int subId);
    IImsMmTelFeature createEmergencyOnlyMmTelFeature(int slotId);
    IImsRcsFeature createRcsFeature(int slotId, int subId);
    ImsFeatureConfiguration querySupportedImsFeatures();
    long getImsServiceCapabilities();
    void addFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
    void removeFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
    // Synchronous call to ensure the ImsService is ready before continuing with feature creation.
    void notifyImsServiceReadyForFeatureCreation();
    void removeImsFeature(int slotId, int featureType);
    IImsConfig getConfig(int slotId);
    IImsRegistration getRegistration(int slotId);
    void removeImsFeature(int slotId, int featureType, boolean changeSubId);
    IImsConfig getConfig(int slotId, int subId);
    IImsRegistration getRegistration(int slotId, int subId);
    ISipTransport getSipTransport(int slotId);
    oneway void enableIms(int slotId);
    oneway void disableIms(int slotId);
    oneway void enableIms(int slotId, int subId);
    oneway void disableIms(int slotId, int subId);
}
+2 −2
Original line number Diff line number Diff line
@@ -23,11 +23,11 @@ import com.android.ims.ImsFeatureContainer;
 * {@hide}
 */
oneway interface IImsServiceFeatureCallback {
    void imsFeatureCreated(in ImsFeatureContainer feature);
    void imsFeatureCreated(in ImsFeatureContainer feature, int subId);
    // Reason defined in FeatureConnector.UnavailableReason
    void imsFeatureRemoved(int reason);
    // Status defined in ImsFeature.ImsState.
    void imsStatusChanged(int status);
    void imsStatusChanged(int status, int subId);
    //Capabilities defined in ImsService.ImsServiceCapability
    void updateCapabilities(long capabilities);
}
 No newline at end of file