Loading src/java/com/android/internal/telephony/ims/ImsResolver.java +53 −7 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.os.Message; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; Loading Loading @@ -405,6 +406,8 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal // Persistent Logging private final LocalLog mEventLog = new LocalLog(50); private boolean mBootCompletedHandlerRan = false; // Synchronize all events on a handler to ensure that the cache includes the most recent // version of the installed ImsServices. private Handler mHandler = new Handler(Looper.getMainLooper(), (msg) -> { Loading @@ -420,9 +423,12 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal break; } case HANDLER_BOOT_COMPLETE: { if (!mBootCompletedHandlerRan) { mBootCompletedHandlerRan = true; mEventLog.log("handling BOOT_COMPLETE"); // Re-evaluate bound services for all slots after requerying packagemanager maybeAddedImsService(null /*packageName*/); } break; } case HANDLER_CONFIG_CHANGED: { Loading Loading @@ -539,8 +545,17 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal mReceiverContext.registerReceiver(mAppChangedReceiver, appChangedFilter); mReceiverContext.registerReceiver(mConfigChangedReceiver, new IntentFilter( CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); if (userManager.isUserUnlocked()) { mHandler.obtainMessage(HANDLER_BOOT_COMPLETE, null).sendToTarget(); } else { mReceiverContext.registerReceiver(mBootCompleted, new IntentFilter( Intent.ACTION_BOOT_COMPLETED)); if (userManager.isUserUnlocked()) { mHandler.obtainMessage(HANDLER_BOOT_COMPLETE, null).sendToTarget(); } } } @VisibleForTesting Loading Loading @@ -1179,6 +1194,8 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal // Called from handler ONLY. private void carrierConfigChanged(int slotId) { updateBoundDeviceServices(); if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) { // not specified, update carrier override cache and possibly rebind on all slots. for (int i = 0; i < mNumSlots; i++) { Loading @@ -1188,11 +1205,28 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal updateBoundServices(slotId, getImsPackageOverrideConfig(slotId)); } private void updateBoundDeviceServices() { Log.d(TAG, "updateBoundDeviceServices: called"); ArrayMap<String, ImsServiceInfo> featureDynamicImsPackages = new ArrayMap<>(); for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) { String packageName = getDeviceConfiguration(f); ImsServiceInfo serviceInfo = getImsServiceInfoFromCache(packageName); if (serviceInfo != null && !serviceInfo.featureFromMetadata && !featureDynamicImsPackages.containsKey(packageName)) { featureDynamicImsPackages.put(packageName, serviceInfo); Log.d(TAG, "updateBoundDeviceServices: Schedule query for package=" + packageName); scheduleQueryForFeatures(featureDynamicImsPackages.get(packageName)); } } } private void updateBoundServices(int slotId, Map<Integer, String> featureMap) { if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlots) { return; } boolean hasConfigChanged = false; boolean didQuerySchedule = false; for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) { String overridePackageName = getOverridePackageName(slotId, f); String oldPackageName = getCarrierConfiguredPackageName(slotId, f); Loading @@ -1207,20 +1241,28 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal ImsFeature.FEATURE_LOG_MAP.getOrDefault(f, "invalid"), slotId)); newPackageName = overridePackageName; } mEventLog.log("updateBoundServices - carrier package changed: " + oldPackageName + " -> " + newPackageName + " on slot " + slotId); setCarrierConfiguredPackageName(newPackageName, slotId, f); // Carrier config may have not changed, but we still want to kick off a recalculation // in case there has been a change to the supported device features. ImsServiceInfo info = getImsServiceInfoFromCache(newPackageName); mEventLog.log("updateBoundServices - carrier package changed: " + oldPackageName + " -> " + newPackageName + " on slot " + slotId + ", hasConfigChanged=" + hasConfigChanged); if (info == null || info.featureFromMetadata) { hasConfigChanged = true; } else { // Config will change when this query completes scheduleQueryForFeatures(info); didQuerySchedule = true; } } if (hasConfigChanged) calculateFeatureConfigurationChange(); if (hasConfigChanged && didQuerySchedule) { mEventLog.log("[warning] updateBoundServices - both hasConfigChange and query " + "scheduled on slot " + slotId); } } private @NonNull Map<Integer, String> getImsPackageOverrideConfig(int slotId) { Loading Loading @@ -1384,6 +1426,10 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal service.replaceFeatures(features); // Wait until all queries have completed before changing the configuration to reduce churn. if (!mFeatureQueryManager.isQueryInProgress()) { if (mHandler.hasMessages(HANDLER_DYNAMIC_FEATURE_CHANGE)) { mEventLog.log("[warning] dynamicQueryComplete - HANDLER_DYNAMIC_FEATURE_CHANGE " + "pending with calculateFeatureConfigurationChange()"); } calculateFeatureConfigurationChange(); } } Loading tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java +88 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.UserManager; import android.telephony.CarrierConfigManager; import android.telephony.TelephonyManager; import android.telephony.ims.ImsService; Loading @@ -54,6 +55,7 @@ import android.telephony.ims.stub.ImsFeatureConfiguration; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.ArrayMap; import android.util.ArraySet; import com.android.internal.telephony.PhoneConfigurationManager; Loading @@ -68,6 +70,7 @@ import org.mockito.Mock; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; Loading @@ -89,6 +92,7 @@ public class ImsResolverTest extends ImsTestBase { "TestCarrier2Pkg", "Carrier2ImsService"); private static final int NUM_MAX_SLOTS = 2; private static final String TAG = ImsResolverTest.class.getSimpleName(); @Mock Context mMockContext; Loading @@ -101,6 +105,8 @@ public class ImsResolverTest extends ImsTestBase { @Mock CarrierConfigManager mMockCarrierConfigManager; @Mock UserManager mMockUserManager; @Mock ImsResolver.ImsDynamicQueryManagerFactory mMockQueryManagerFactory; @Mock ImsServiceFeatureQueryManager mMockQueryManager; Loading Loading @@ -549,6 +555,61 @@ public class ImsResolverTest extends ImsTestBase { verify(controller, never()).unbind(); } /** * Test that the dynamic ims services are bound in the event that the user is not yet unlocked * but the carrier config changed event is fired. * @throws RemoteException */ @Test @SmallTest public void testDeviceDynamicQueryBindsOnCarrierConfigChanged() throws RemoteException { //Set package names with no features set in metadata List<ResolveInfo> info = new ArrayList<>(); info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, new HashSet<>(), true)); info.add(getResolveInfo(TEST_DEVICE2_DEFAULT_NAME, new HashSet<>(), true)); info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true)); setupPackageQuery(info); //setupResolver setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(), TEST_DEVICE2_DEFAULT_NAME.getPackageName()); //Set controllers ImsServiceController deviceController = mock(ImsServiceController.class); ImsServiceController deviceController2 = mock(ImsServiceController.class); ImsServiceController carrierController = mock(ImsServiceController.class); Map<String, ImsServiceController> controllerMap = new ArrayMap<>(); controllerMap.put(TEST_DEVICE_DEFAULT_NAME.getPackageName(), deviceController); controllerMap.put(TEST_DEVICE2_DEFAULT_NAME.getPackageName(), deviceController2); controllerMap.put(TEST_CARRIER_DEFAULT_NAME.getPackageName(), carrierController); setImsServiceControllerFactory(controllerMap); //Set features to device ims services Set<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatures1 = convertToFeatureSlotPairs(0, ImsResolver.METADATA_EMERGENCY_MMTEL_FEATURE, ImsResolver.METADATA_MMTEL_FEATURE); Set<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatures2 = convertToFeatureSlotPairs(0, ImsResolver.METADATA_RCS_FEATURE); startBindNoCarrierConfig(1); mLooper.processAllMessages(); // ensure that startQuery was called verify(mMockQueryManager, times(1)).startQuery(eq(TEST_DEVICE_DEFAULT_NAME), any(String.class)); verify(mMockQueryManager, times(1)).startQuery(eq(TEST_DEVICE2_DEFAULT_NAME), any(String.class)); mDynamicQueryListener.onComplete(TEST_DEVICE_DEFAULT_NAME, deviceFeatures1); mDynamicQueryListener.onComplete(TEST_DEVICE2_DEFAULT_NAME, deviceFeatures2); mLooper.processAllMessages(); verify(deviceController, times(2)).bind(eq(deviceFeatures1)); verify(deviceController2, times(1)).bind(eq(deviceFeatures2)); } /** * Test that when a device and carrier override package are set, both ImsServices are bound. * Verify that the carrier ImsService features are created and the device default features Loading Loading @@ -1581,6 +1642,12 @@ public class ImsResolverTest extends ImsTestBase { when(mMockContext.createContextAsUser(any(), eq(0))).thenReturn(mMockContext); when(mMockContext.getSystemService(eq(Context.CARRIER_CONFIG_SERVICE))).thenReturn( mMockCarrierConfigManager); when(mMockContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mMockUserManager); //If this is not false, then HANDLER_BOOT_COMPLETE is fired now but the controller factories //used in the test methods aren't created in time. when(mMockUserManager.isUserUnlocked()).thenReturn(false); // Support configs for MSIM always in case we are testing dynamic sim slot config changes. mCarrierConfigs = new PersistableBundle[NUM_MAX_SLOTS]; for (int i = 0; i < NUM_MAX_SLOTS; i++) { Loading Loading @@ -1719,6 +1786,22 @@ public class ImsResolverTest extends ImsTestBase { mLooper.processAllMessages(); } private void setImsServiceControllerFactory(Map<String, ImsServiceController> controllerMap) { mTestImsResolver.setImsServiceControllerFactory( new ImsResolver.ImsServiceControllerFactory() { @Override public String getServiceInterface() { return ImsService.SERVICE_INTERFACE; } @Override public ImsServiceController create(Context context, ComponentName componentName, ImsServiceController.ImsServiceControllerCallbacks callbacks) { return controllerMap.get(componentName.getPackageName()); } }); } private void setImsServiceControllerFactory(ImsServiceController deviceController, ImsServiceController carrierController) { mTestImsResolver.setImsServiceControllerFactory( Loading Loading @@ -1844,6 +1927,11 @@ public class ImsResolverTest extends ImsTestBase { .collect(Collectors.toCollection(HashSet::new)); } private HashSet<ImsFeatureConfiguration.FeatureSlotPair> convertToFeatureSlotPairs( int slotId, String... features) { return convertToHashSet(new ArraySet<>(features), slotId); } private int metadataStringToFeature(String f) { switch (f) { case ImsResolver.METADATA_MMTEL_FEATURE: Loading Loading
src/java/com/android/internal/telephony/ims/ImsResolver.java +53 −7 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.os.Message; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; Loading Loading @@ -405,6 +406,8 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal // Persistent Logging private final LocalLog mEventLog = new LocalLog(50); private boolean mBootCompletedHandlerRan = false; // Synchronize all events on a handler to ensure that the cache includes the most recent // version of the installed ImsServices. private Handler mHandler = new Handler(Looper.getMainLooper(), (msg) -> { Loading @@ -420,9 +423,12 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal break; } case HANDLER_BOOT_COMPLETE: { if (!mBootCompletedHandlerRan) { mBootCompletedHandlerRan = true; mEventLog.log("handling BOOT_COMPLETE"); // Re-evaluate bound services for all slots after requerying packagemanager maybeAddedImsService(null /*packageName*/); } break; } case HANDLER_CONFIG_CHANGED: { Loading Loading @@ -539,8 +545,17 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal mReceiverContext.registerReceiver(mAppChangedReceiver, appChangedFilter); mReceiverContext.registerReceiver(mConfigChangedReceiver, new IntentFilter( CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); if (userManager.isUserUnlocked()) { mHandler.obtainMessage(HANDLER_BOOT_COMPLETE, null).sendToTarget(); } else { mReceiverContext.registerReceiver(mBootCompleted, new IntentFilter( Intent.ACTION_BOOT_COMPLETED)); if (userManager.isUserUnlocked()) { mHandler.obtainMessage(HANDLER_BOOT_COMPLETE, null).sendToTarget(); } } } @VisibleForTesting Loading Loading @@ -1179,6 +1194,8 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal // Called from handler ONLY. private void carrierConfigChanged(int slotId) { updateBoundDeviceServices(); if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) { // not specified, update carrier override cache and possibly rebind on all slots. for (int i = 0; i < mNumSlots; i++) { Loading @@ -1188,11 +1205,28 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal updateBoundServices(slotId, getImsPackageOverrideConfig(slotId)); } private void updateBoundDeviceServices() { Log.d(TAG, "updateBoundDeviceServices: called"); ArrayMap<String, ImsServiceInfo> featureDynamicImsPackages = new ArrayMap<>(); for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) { String packageName = getDeviceConfiguration(f); ImsServiceInfo serviceInfo = getImsServiceInfoFromCache(packageName); if (serviceInfo != null && !serviceInfo.featureFromMetadata && !featureDynamicImsPackages.containsKey(packageName)) { featureDynamicImsPackages.put(packageName, serviceInfo); Log.d(TAG, "updateBoundDeviceServices: Schedule query for package=" + packageName); scheduleQueryForFeatures(featureDynamicImsPackages.get(packageName)); } } } private void updateBoundServices(int slotId, Map<Integer, String> featureMap) { if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX || slotId >= mNumSlots) { return; } boolean hasConfigChanged = false; boolean didQuerySchedule = false; for (int f = ImsFeature.FEATURE_EMERGENCY_MMTEL; f < ImsFeature.FEATURE_MAX; f++) { String overridePackageName = getOverridePackageName(slotId, f); String oldPackageName = getCarrierConfiguredPackageName(slotId, f); Loading @@ -1207,20 +1241,28 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal ImsFeature.FEATURE_LOG_MAP.getOrDefault(f, "invalid"), slotId)); newPackageName = overridePackageName; } mEventLog.log("updateBoundServices - carrier package changed: " + oldPackageName + " -> " + newPackageName + " on slot " + slotId); setCarrierConfiguredPackageName(newPackageName, slotId, f); // Carrier config may have not changed, but we still want to kick off a recalculation // in case there has been a change to the supported device features. ImsServiceInfo info = getImsServiceInfoFromCache(newPackageName); mEventLog.log("updateBoundServices - carrier package changed: " + oldPackageName + " -> " + newPackageName + " on slot " + slotId + ", hasConfigChanged=" + hasConfigChanged); if (info == null || info.featureFromMetadata) { hasConfigChanged = true; } else { // Config will change when this query completes scheduleQueryForFeatures(info); didQuerySchedule = true; } } if (hasConfigChanged) calculateFeatureConfigurationChange(); if (hasConfigChanged && didQuerySchedule) { mEventLog.log("[warning] updateBoundServices - both hasConfigChange and query " + "scheduled on slot " + slotId); } } private @NonNull Map<Integer, String> getImsPackageOverrideConfig(int slotId) { Loading Loading @@ -1384,6 +1426,10 @@ public class ImsResolver implements ImsServiceController.ImsServiceControllerCal service.replaceFeatures(features); // Wait until all queries have completed before changing the configuration to reduce churn. if (!mFeatureQueryManager.isQueryInProgress()) { if (mHandler.hasMessages(HANDLER_DYNAMIC_FEATURE_CHANGE)) { mEventLog.log("[warning] dynamicQueryComplete - HANDLER_DYNAMIC_FEATURE_CHANGE " + "pending with calculateFeatureConfigurationChange()"); } calculateFeatureConfigurationChange(); } } Loading
tests/telephonytests/src/com/android/internal/telephony/ims/ImsResolverTest.java +88 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.UserManager; import android.telephony.CarrierConfigManager; import android.telephony.TelephonyManager; import android.telephony.ims.ImsService; Loading @@ -54,6 +55,7 @@ import android.telephony.ims.stub.ImsFeatureConfiguration; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.ArrayMap; import android.util.ArraySet; import com.android.internal.telephony.PhoneConfigurationManager; Loading @@ -68,6 +70,7 @@ import org.mockito.Mock; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; Loading @@ -89,6 +92,7 @@ public class ImsResolverTest extends ImsTestBase { "TestCarrier2Pkg", "Carrier2ImsService"); private static final int NUM_MAX_SLOTS = 2; private static final String TAG = ImsResolverTest.class.getSimpleName(); @Mock Context mMockContext; Loading @@ -101,6 +105,8 @@ public class ImsResolverTest extends ImsTestBase { @Mock CarrierConfigManager mMockCarrierConfigManager; @Mock UserManager mMockUserManager; @Mock ImsResolver.ImsDynamicQueryManagerFactory mMockQueryManagerFactory; @Mock ImsServiceFeatureQueryManager mMockQueryManager; Loading Loading @@ -549,6 +555,61 @@ public class ImsResolverTest extends ImsTestBase { verify(controller, never()).unbind(); } /** * Test that the dynamic ims services are bound in the event that the user is not yet unlocked * but the carrier config changed event is fired. * @throws RemoteException */ @Test @SmallTest public void testDeviceDynamicQueryBindsOnCarrierConfigChanged() throws RemoteException { //Set package names with no features set in metadata List<ResolveInfo> info = new ArrayList<>(); info.add(getResolveInfo(TEST_DEVICE_DEFAULT_NAME, new HashSet<>(), true)); info.add(getResolveInfo(TEST_DEVICE2_DEFAULT_NAME, new HashSet<>(), true)); info.add(getResolveInfo(TEST_CARRIER_DEFAULT_NAME, new HashSet<>(), true)); setupPackageQuery(info); //setupResolver setupResolver(1 /*numSlots*/, TEST_DEVICE_DEFAULT_NAME.getPackageName(), TEST_DEVICE2_DEFAULT_NAME.getPackageName()); //Set controllers ImsServiceController deviceController = mock(ImsServiceController.class); ImsServiceController deviceController2 = mock(ImsServiceController.class); ImsServiceController carrierController = mock(ImsServiceController.class); Map<String, ImsServiceController> controllerMap = new ArrayMap<>(); controllerMap.put(TEST_DEVICE_DEFAULT_NAME.getPackageName(), deviceController); controllerMap.put(TEST_DEVICE2_DEFAULT_NAME.getPackageName(), deviceController2); controllerMap.put(TEST_CARRIER_DEFAULT_NAME.getPackageName(), carrierController); setImsServiceControllerFactory(controllerMap); //Set features to device ims services Set<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatures1 = convertToFeatureSlotPairs(0, ImsResolver.METADATA_EMERGENCY_MMTEL_FEATURE, ImsResolver.METADATA_MMTEL_FEATURE); Set<ImsFeatureConfiguration.FeatureSlotPair> deviceFeatures2 = convertToFeatureSlotPairs(0, ImsResolver.METADATA_RCS_FEATURE); startBindNoCarrierConfig(1); mLooper.processAllMessages(); // ensure that startQuery was called verify(mMockQueryManager, times(1)).startQuery(eq(TEST_DEVICE_DEFAULT_NAME), any(String.class)); verify(mMockQueryManager, times(1)).startQuery(eq(TEST_DEVICE2_DEFAULT_NAME), any(String.class)); mDynamicQueryListener.onComplete(TEST_DEVICE_DEFAULT_NAME, deviceFeatures1); mDynamicQueryListener.onComplete(TEST_DEVICE2_DEFAULT_NAME, deviceFeatures2); mLooper.processAllMessages(); verify(deviceController, times(2)).bind(eq(deviceFeatures1)); verify(deviceController2, times(1)).bind(eq(deviceFeatures2)); } /** * Test that when a device and carrier override package are set, both ImsServices are bound. * Verify that the carrier ImsService features are created and the device default features Loading Loading @@ -1581,6 +1642,12 @@ public class ImsResolverTest extends ImsTestBase { when(mMockContext.createContextAsUser(any(), eq(0))).thenReturn(mMockContext); when(mMockContext.getSystemService(eq(Context.CARRIER_CONFIG_SERVICE))).thenReturn( mMockCarrierConfigManager); when(mMockContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mMockUserManager); //If this is not false, then HANDLER_BOOT_COMPLETE is fired now but the controller factories //used in the test methods aren't created in time. when(mMockUserManager.isUserUnlocked()).thenReturn(false); // Support configs for MSIM always in case we are testing dynamic sim slot config changes. mCarrierConfigs = new PersistableBundle[NUM_MAX_SLOTS]; for (int i = 0; i < NUM_MAX_SLOTS; i++) { Loading Loading @@ -1719,6 +1786,22 @@ public class ImsResolverTest extends ImsTestBase { mLooper.processAllMessages(); } private void setImsServiceControllerFactory(Map<String, ImsServiceController> controllerMap) { mTestImsResolver.setImsServiceControllerFactory( new ImsResolver.ImsServiceControllerFactory() { @Override public String getServiceInterface() { return ImsService.SERVICE_INTERFACE; } @Override public ImsServiceController create(Context context, ComponentName componentName, ImsServiceController.ImsServiceControllerCallbacks callbacks) { return controllerMap.get(componentName.getPackageName()); } }); } private void setImsServiceControllerFactory(ImsServiceController deviceController, ImsServiceController carrierController) { mTestImsResolver.setImsServiceControllerFactory( Loading Loading @@ -1844,6 +1927,11 @@ public class ImsResolverTest extends ImsTestBase { .collect(Collectors.toCollection(HashSet::new)); } private HashSet<ImsFeatureConfiguration.FeatureSlotPair> convertToFeatureSlotPairs( int slotId, String... features) { return convertToHashSet(new ArraySet<>(features), slotId); } private int metadataStringToFeature(String f) { switch (f) { case ImsResolver.METADATA_MMTEL_FEATURE: Loading