Loading src/java/com/android/internal/telephony/ims/ImsServiceController.java +73 −22 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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<>(); Loading Loading @@ -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 Loading @@ -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); } } } } Loading Loading @@ -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. */ Loading @@ -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; } Loading Loading @@ -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 Loading Loading @@ -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() { Loading src/java/com/android/internal/telephony/ims/ImsServiceControllerCompat.java +16 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"); Loading tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java +19 −0 Original line number Diff line number Diff line Loading @@ -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()); } } tests/telephonytests/src/android/telephony/ims/TestImsService.java +7 −0 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -58,4 +60,9 @@ public class TestImsService extends android.telephony.ims.ImsService { public ImsFeatureConfiguration querySupportedImsFeatures() { return testFeatureConfig; } @Override public long getImsServiceCapabilities() { return testCaps; } } tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java +61 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); Loading Loading
src/java/com/android/internal/telephony/ims/ImsServiceController.java +73 −22 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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<>(); Loading Loading @@ -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 Loading @@ -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); } } } } Loading Loading @@ -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. */ Loading @@ -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; } Loading Loading @@ -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 Loading Loading @@ -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() { Loading
src/java/com/android/internal/telephony/ims/ImsServiceControllerCompat.java +16 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"); Loading
tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java +19 −0 Original line number Diff line number Diff line Loading @@ -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()); } }
tests/telephonytests/src/android/telephony/ims/TestImsService.java +7 −0 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -58,4 +60,9 @@ public class TestImsService extends android.telephony.ims.ImsService { public ImsFeatureConfiguration querySupportedImsFeatures() { return testFeatureConfig; } @Override public long getImsServiceCapabilities() { return testCaps; } }
tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java +61 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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); Loading