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

Commit 694ea86d authored by Brad Ebinger's avatar Brad Ebinger Committed by Gerrit Code Review
Browse files

Merge "Get ISipTransport + ImsService implementation capabilities"

parents 23d02b01 7bc4b9b9
Loading
Loading
Loading
Loading
+73 −22
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.telephony.ims.ImsService;
import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.aidl.IImsServiceController;
import android.telephony.ims.aidl.ISipTransport;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.ImsFeatureConfiguration;
import android.util.LocalLog;
@@ -45,6 +46,7 @@ import com.android.internal.telephony.util.TelephonyUtils;

import java.io.PrintWriter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
@@ -82,9 +84,11 @@ public class ImsServiceController {
                            + service);
                    setServiceController(service);
                    notifyImsServiceReady();
                    retrieveStaticImsServiceCapabilities();
                    // create all associated features in the ImsService
                    for (ImsFeatureConfiguration.FeatureSlotPair i : mImsFeatures) {
                        long caps = calculateCapabiltiesForSlot(mImsFeatures, i.slotId);
                        long caps = modifyCapabiltiesForSlot(mImsFeatures, i.slotId,
                                mServiceCapabilities);
                        addImsServiceFeature(i, caps);
                    }
                } catch (RemoteException e) {
@@ -221,6 +225,8 @@ public class ImsServiceController {
    // Set of a pair of slotId->feature
    private Set<ImsFeatureConfiguration.FeatureSlotPair> mImsFeatures;
    private IImsServiceController mIImsServiceController;
    // The Capabilities bitmask of the connected ImsService (see ImsService#ImsServiceCapability).
    private long mServiceCapabilities;
    private ImsServiceConnection mImsServiceConnection;
    // Only added or removed, never accessed on purpose.
    private Set<ImsFeatureStatusCallback> mFeatureStatusCallbacks = new HashSet<>();
@@ -435,7 +441,8 @@ public class ImsServiceController {
                        new HashSet<>(mImsFeatures);
                newFeatures.removeAll(oldImsFeatures);
                for (ImsFeatureConfiguration.FeatureSlotPair i : newFeatures) {
                    long caps = calculateCapabiltiesForSlot(newFeatures, i.slotId);
                    long caps = modifyCapabiltiesForSlot(newFeatures, i.slotId,
                            mServiceCapabilities);
                    addImsServiceFeature(i, caps);
                }
                // remove old features
@@ -450,7 +457,11 @@ public class ImsServiceController {
                        new HashSet<>(mImsFeatures);
                unchangedFeatures.removeAll(oldFeatures);
                unchangedFeatures.removeAll(newFeatures);
                updateCapsForUnchangedFeatures(unchangedFeatures);
                for (ImsFeatureConfiguration.FeatureSlotPair p : unchangedFeatures) {
                    long caps = modifyCapabiltiesForSlot(unchangedFeatures, p.slotId,
                            mServiceCapabilities);
                    mRepo.notifyFeatureCapabilitiesChanged(p.slotId, p.featureType, caps);
                }
            }
        }
    }
@@ -517,6 +528,23 @@ public class ImsServiceController {
        }
    }

    /**
     * @return the ISipTransport instance associated with the requested slot ID.
     */
    public ISipTransport getSipTransport(int slotId) throws RemoteException {
        synchronized (mLock) {
            return isServiceControllerAvailable()
                    ? mIImsServiceController.getSipTransport(slotId) : null;
        }
    }

    protected long getStaticServiceCapabilities() throws RemoteException {
        synchronized (mLock) {
            return isServiceControllerAvailable()
                    ? mIImsServiceController.getImsServiceCapabilities() : 0L;
        }
    }

    /**
     * notify the ImsService that the ImsService is ready for feature creation.
     */
@@ -530,6 +558,17 @@ public class ImsServiceController {
        }
    }

    private void retrieveStaticImsServiceCapabilities() throws RemoteException {
        long caps = getStaticServiceCapabilities();
        Log.i(LOG_TAG, "retrieveStaticImsServiceCapabilities: "
                + ImsService.getCapabilitiesString(caps));
        mLocalLog.log("retrieveStaticImsServiceCapabilities: "
                + ImsService.getCapabilitiesString(caps));
        synchronized (mLock) {
            mServiceCapabilities = caps;
        }
    }

    protected String getServiceInterface() {
        return ImsService.SERVICE_INTERFACE;
    }
@@ -571,26 +610,30 @@ public class ImsServiceController {
        }
    }

    private long calculateCapabiltiesForSlot(
            Set<ImsFeatureConfiguration.FeatureSlotPair> features, int slotId) {
        // We only consider MMTEL_EMERGENCY as a capability here, so set the capability if the
        // ImsService has declared it.
        long caps = 0;
        for (ImsFeatureConfiguration.FeatureSlotPair p : features) {
            if (p.featureType == ImsFeature.FEATURE_EMERGENCY_MMTEL && p.slotId == slotId) {
    /**
     * Modify the capabilities returned by the ImsService based on the state of this controller:
     * - CAPABILITY_EMERGENCY_OVER_MMTEL should only be set if features contains
     * FEATURE_EMERGENCY_MMTEL (This is not set by the ImsService itself).
     * - CAPABILITY_SIP_DELEGATE_CREATION should only be set in the case that this ImsService is
     * handling both MMTEL and RCS features for this slot.
     */
    private long modifyCapabiltiesForSlot(
            Set<ImsFeatureConfiguration.FeatureSlotPair> features, int slotId, long serviceCaps) {
        long caps = serviceCaps;
        List<Integer> featureTypes = getFeaturesForSlot(slotId, features);
        if (featureTypes.contains(ImsFeature.FEATURE_EMERGENCY_MMTEL)) {
            // We only consider MMTEL_EMERGENCY as a capability here, so set the capability if
            // the ImsService has declared it.
            caps |= ImsService.CAPABILITY_EMERGENCY_OVER_MMTEL;
        }
        }
        return caps;
    }

    // This method should only be called when synchronized on mLock
    private void updateCapsForUnchangedFeatures(
            Set<ImsFeatureConfiguration.FeatureSlotPair> features) {
        for (ImsFeatureConfiguration.FeatureSlotPair p : features) {
            long caps = calculateCapabiltiesForSlot(features, p.slotId);
            mRepo.notifyFeatureCapabilitiesChanged(p.slotId, p.featureType, caps);
        if (!featureTypes.contains(ImsFeature.FEATURE_MMTEL)
                || !featureTypes.contains(ImsFeature.FEATURE_RCS)) {
            // Only allow SipDelegate creation if this ImsService is providing both MMTEL and RCS
            // features.
            caps &= ~(ImsService.CAPABILITY_SIP_DELEGATE_CREATION);
        }
        return caps;
    }

    // Grant runtime permissions to ImsService. PermissionManager ensures that the ImsService is
@@ -752,7 +795,15 @@ public class ImsServiceController {
                    + "available.");
            return null;
        }
        return new ImsFeatureContainer(b, config, reg, capabilities);
        // SipTransport AIDL may be null for older devices, this is expected.
        ISipTransport transport = getSipTransport(slotId);
        return new ImsFeatureContainer(b, config, reg, transport, capabilities);
    }

    private List<Integer> getFeaturesForSlot(int slotId,
            Set<ImsFeatureConfiguration.FeatureSlotPair> features) {
        return features.stream().filter(f -> f.slotId == slotId).map(f -> f.featureType)
                .collect(Collectors.toList());
    }

    private void cleanupAllFeatures() {
+16 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsMmTelFeature;
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.aidl.ISipTransport;
import android.telephony.ims.compat.ImsService;
import android.telephony.ims.compat.feature.ImsFeature;
import android.telephony.ims.compat.feature.MMTelFeature;
@@ -128,6 +129,21 @@ public class ImsServiceControllerCompat extends ImsServiceController {
        return adapter.getIImsConfig();
    }

    /**
     * Return the SIP transport interface, which is not supported on the compat version of
     * ImsService, so return null.
     */
    @Override
    public ISipTransport getSipTransport(int slotId) {
        return null;
    }

    @Override
    protected long getStaticServiceCapabilities() {
        // Older implementations do not support optional static capabilities
        return 0L;
    }

    @Override
    protected final void notifyImsServiceReady() {
        Log.d(TAG, "notifyImsServiceReady");
+19 −0
Original line number Diff line number Diff line
@@ -150,4 +150,23 @@ public class ImsServiceTest {

        assertEquals(config, result);
    }

    /**
     * Tests that ImsService capability sanitization works correctly.
     */
    @Test
    @SmallTest
    public void testCapsSanitized() throws RemoteException {
        long validCaps =
                ImsService.CAPABILITY_SIP_DELEGATE_CREATION;
        // emergency over MMTEL should not be set here, but rather internally in Telephony.
        long invalidCaps = 0xDEADBEEF00000000L | ImsService.CAPABILITY_EMERGENCY_OVER_MMTEL;
        invalidCaps |= validCaps;

        mTestImsService.testCaps = validCaps;
        assertEquals(validCaps, mTestImsServiceBinder.getImsServiceCapabilities());
        mTestImsService.testCaps = invalidCaps;
        // The extra bits should have been removed, leaving only the valid remaining
        assertEquals(validCaps, mTestImsServiceBinder.getImsServiceCapabilities());
    }
}
+7 −0
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ public class TestImsService extends android.telephony.ims.ImsService {

    public ImsFeatureConfiguration testFeatureConfig;

    public long testCaps;

    public TestImsService(Context context) {
        attachBaseContext(context);
        MockitoAnnotations.initMocks(this);
@@ -58,4 +60,9 @@ public class TestImsService extends android.telephony.ims.ImsService {
    public ImsFeatureConfiguration querySupportedImsFeatures() {
        return testFeatureConfig;
    }

    @Override
    public long getImsServiceCapabilities() {
        return testCaps;
    }
}
+61 −0
Original line number Diff line number Diff line
@@ -228,6 +228,60 @@ public class ImsServiceControllerTest extends ImsTestBase {
        validateRcsFeatureContainerExists(SLOT_0);
    }

    /**
     * Tests ImsServiceController keeps SIP delegate creation flags if MMTEL and RCS are supported.
     */
    @SmallTest
    @Test
    public void testBindServiceSipDelegateCapability() throws RemoteException {
        HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
                ImsFeature.FEATURE_MMTEL));
        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
                ImsFeature.FEATURE_RCS));
        when(mMockServiceControllerBinder.getImsServiceCapabilities()).thenReturn(
                ImsService.CAPABILITY_SIP_DELEGATE_CREATION);

        bindAndConnectService(testFeatures);

        verify(mMockServiceControllerBinder).createMmTelFeature(SLOT_0);
        verify(mMockServiceControllerBinder).addFeatureStatusCallback(eq(SLOT_0),
                eq(ImsFeature.FEATURE_MMTEL), any());
        verify(mMockServiceControllerBinder).createRcsFeature(SLOT_0);
        verify(mMockServiceControllerBinder).addFeatureStatusCallback(eq(SLOT_0),
                eq(ImsFeature.FEATURE_RCS), any());
        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                eq(mTestImsServiceController));
        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_RCS),
                eq(mTestImsServiceController));
        validateFeatureContainerExistsWithSipDelegate(ImsFeature.FEATURE_MMTEL, SLOT_0);
        validateFeatureContainerExistsWithSipDelegate(ImsFeature.FEATURE_RCS, SLOT_0);
    }

    /**
     * Tests ImsServiceController loses SIP delegate creation flag if MMTEL and RCS are not both
     * supported.
     */
    @SmallTest
    @Test
    public void testBindServiceSipDelegateCapabilityLost() throws RemoteException {
        HashSet<ImsFeatureConfiguration.FeatureSlotPair> testFeatures = new HashSet<>();
        testFeatures.add(new ImsFeatureConfiguration.FeatureSlotPair(SLOT_0,
                ImsFeature.FEATURE_MMTEL));
        when(mMockServiceControllerBinder.getImsServiceCapabilities()).thenReturn(
                ImsService.CAPABILITY_SIP_DELEGATE_CREATION);

        bindAndConnectService(testFeatures);

        verify(mMockServiceControllerBinder).createMmTelFeature(SLOT_0);
        verify(mMockServiceControllerBinder).addFeatureStatusCallback(eq(SLOT_0),
                eq(ImsFeature.FEATURE_MMTEL), any());
        verify(mMockCallbacks).imsServiceFeatureCreated(eq(SLOT_0), eq(ImsFeature.FEATURE_MMTEL),
                eq(mTestImsServiceController));
        // verify CAPABILITY_SIP_DELEGATE_CREATION is not set because MMTEL and RCS are not set.
        validateMmTelFeatureContainerExists(SLOT_0);
    }

    /**
     * Tests Emergency MMTEL ImsServiceController callbacks are properly called when an ImsService
     * is bound and connected.
@@ -890,6 +944,13 @@ public class ImsServiceControllerTest extends ImsTestBase {
        assertTrue((ImsService.CAPABILITY_EMERGENCY_OVER_MMTEL | fc.getCapabilities()) > 0);
    }

    private void validateFeatureContainerExistsWithSipDelegate(int featureType, int slotId) {
        ImsFeatureContainer fc =
                mRepo.getIfExists(slotId, featureType).orElse(null);
        assertNotNull("FeatureContainer should not be null", fc);
        assertTrue((ImsService.CAPABILITY_SIP_DELEGATE_CREATION | fc.getCapabilities()) > 0);
    }

    private void validateMmTelFeatureExistsInCallback(int slotId, long expectedCaps) {
        TestCallback cb = new TestCallback();
        mRepo.registerForConnectionUpdates(slotId, ImsFeature.FEATURE_MMTEL, cb, Runnable::run);