Enhance TelephonyRcsService to only create needed features
1) When determining the features that should be added to an
RcsFeatureContainer, take into account that subscriptions
CarrierConfig. This will stop unnecessary polling for the
RcsFeature for subscriptions that are not configured to support
RCS in the first place.
2) Fix some of the logging
Bug: 149100088
Test: atest TeleServiceTests
Change-Id: Ieaa23ba002528c75b87af961f5af534b6589a130
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index 6b1b5e3..3ea8df2 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -361,8 +361,8 @@
int slotId = phone.getPhoneId();
RcsFeatureController c = mRcsService.getFeatureController(slotId);
if (c == null) {
- throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
- "Cannot find RcsFeatureController instance for sub: " + subId);
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "The requested operation is not supported for subId " + subId);
}
return c;
}
diff --git a/src/com/android/services/telephony/rcs/RcsFeatureController.java b/src/com/android/services/telephony/rcs/RcsFeatureController.java
index f451e9b..5094c57 100644
--- a/src/com/android/services/telephony/rcs/RcsFeatureController.java
+++ b/src/com/android/services/telephony/rcs/RcsFeatureController.java
@@ -125,7 +125,7 @@
public void connectionReady(RcsFeatureManager manager)
throws com.android.ims.ImsException {
if (manager == null) {
- Log.w(LOG_TAG, "connectionReady returned null RcsFeatureManager");
+ logw("connectionReady returned null RcsFeatureManager");
return;
}
try {
@@ -192,6 +192,7 @@
*/
public void connect() {
synchronized (mLock) {
+ if (mFeatureConnector != null) return;
mFeatureConnector = mFeatureFactory.create(mContext, mSlotId, mFeatureConnectorListener,
mContext.getMainExecutor(), LOG_TAG);
mFeatureConnector.connect();
@@ -224,6 +225,25 @@
}
/**
+ * Removes the feature associated with this class.
+ */
+ public <T> void removeFeature(Class<T> clazz) {
+ synchronized (mLock) {
+ RcsFeatureController.Feature feature = mFeatures.remove(clazz);
+ feature.onDestroy();
+ }
+ }
+
+ /**
+ * @return true if this controller has features it is actively tracking.
+ */
+ public boolean hasActiveFeatures() {
+ synchronized (mLock) {
+ return mFeatures.size() > 0;
+ }
+ }
+
+ /**
* Update the subscription associated with this controller.
*/
public void updateAssociatedSubscription(int newSubId) {
@@ -247,7 +267,10 @@
*/
public void destroy() {
synchronized (mLock) {
- mFeatureConnector.disconnect();
+ Log.i(LOG_TAG, "destroy: slotId=" + mSlotId);
+ if (mFeatureConnector != null) {
+ mFeatureConnector.disconnect();
+ }
for (Feature c : mFeatures.values()) {
c.onRcsDisconnected();
c.onDestroy();
@@ -406,4 +429,15 @@
pw.println(mFeatureManager != null);
}
}
+
+ private void logw(String log) {
+ Log.w(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ private StringBuilder getLogPrefix() {
+ StringBuilder sb = new StringBuilder("[");
+ sb.append(mSlotId);
+ sb.append("] ");
+ return sb;
+ }
}
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
index b4223d3..c85e9a9 100644
--- a/src/com/android/services/telephony/rcs/TelephonyRcsService.java
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -28,6 +28,7 @@
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.util.Log;
+import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.PhoneConfigurationManager;
@@ -35,8 +36,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
/**
* Singleton service setup to manage RCS related services that the platform provides such as User
@@ -85,8 +84,8 @@
private final Object mLock = new Object();
private int mNumSlots;
- // Index corresponds to the slot ID.
- private List<RcsFeatureController> mFeatureControllers;
+ // Maps slot ID -> RcsFeatureController.
+ private SparseArray<RcsFeatureController> mFeatureControllers;
private BroadcastReceiver mCarrierConfigChangedReceiver = new BroadcastReceiver() {
@Override
@@ -99,8 +98,10 @@
if (bundle == null) {
return;
}
- int slotId = bundle.getInt(CarrierConfigManager.EXTRA_SLOT_INDEX);
- int subId = bundle.getInt(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX);
+ int slotId = bundle.getInt(CarrierConfigManager.EXTRA_SLOT_INDEX,
+ SubscriptionManager.INVALID_PHONE_INDEX);
+ int subId = bundle.getInt(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
updateFeatureControllerSubscription(slotId, subId);
}
}
@@ -125,10 +126,9 @@
});
public TelephonyRcsService(Context context, int numSlots) {
- Log.i(LOG_TAG, "initialize");
mContext = context;
mNumSlots = numSlots;
- mFeatureControllers = new ArrayList<>(numSlots);
+ mFeatureControllers = new SparseArray<>(numSlots);
}
/**
@@ -145,11 +145,7 @@
* system callbacks.
*/
public void initialize() {
- synchronized (mLock) {
- for (int i = 0; i < mNumSlots; i++) {
- mFeatureControllers.add(constructFeatureController(i));
- }
- }
+ updateFeatureControllerSize(mNumSlots);
PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler,
HANDLER_MSIM_CONFIGURATION_CHANGE, null);
@@ -173,15 +169,24 @@
if (oldNumSlots == newNumSlots) {
return;
}
+ Log.i(LOG_TAG, "updateFeatureControllers: oldSlots=" + oldNumSlots + ", newNumSlots="
+ + newNumSlots);
mNumSlots = newNumSlots;
if (oldNumSlots < newNumSlots) {
for (int i = oldNumSlots; i < newNumSlots; i++) {
- mFeatureControllers.add(constructFeatureController(i));
+ RcsFeatureController c = constructFeatureController(i);
+ // Do not add feature controllers for inactive subscriptions
+ if (c.hasActiveFeatures()) {
+ mFeatureControllers.put(i, c);
+ }
}
} else {
for (int i = (oldNumSlots - 1); i > (newNumSlots - 1); i--) {
- RcsFeatureController controller = mFeatureControllers.remove(i);
- controller.destroy();
+ RcsFeatureController c = mFeatureControllers.get(i);
+ if (c != null) {
+ mFeatureControllers.remove(i);
+ c.destroy();
+ }
}
}
}
@@ -190,24 +195,62 @@
private void updateFeatureControllerSubscription(int slotId, int newSubId) {
synchronized (mLock) {
RcsFeatureController f = mFeatureControllers.get(slotId);
- if (f == null) {
- Log.w(LOG_TAG, "unexpected null FeatureContainer for slot " + slotId);
- return;
+ Log.i(LOG_TAG, "updateFeatureControllerSubscription: slotId=" + slotId + " newSubId="
+ + newSubId + ", existing feature=" + (f != null));
+ if (SubscriptionManager.isValidSubscriptionId(newSubId)) {
+ if (f == null) {
+ // A controller doesn't exist for this slot yet.
+ f = mFeatureFactory.createController(mContext, slotId);
+ updateSupportedFeatures(f, slotId, newSubId);
+ if (f.hasActiveFeatures()) mFeatureControllers.put(slotId, f);
+ } else {
+ updateSupportedFeatures(f, slotId, newSubId);
+ // Do not keep an empty container around.
+ if (!f.hasActiveFeatures()) {
+ f.destroy();
+ mFeatureControllers.remove(slotId);
+ }
+ }
}
- f.updateAssociatedSubscription(newSubId);
+ if (f != null) f.updateAssociatedSubscription(newSubId);
}
}
private RcsFeatureController constructFeatureController(int slotId) {
RcsFeatureController c = mFeatureFactory.createController(mContext, slotId);
- // TODO: integrate user setting into whether or not this feature is added as well as logic
- // to listen for changes in user setting.
- c.addFeature(mFeatureFactory.createUserCapabilityExchange(mContext, slotId,
- getSubscriptionFromSlot(slotId)), UserCapabilityExchangeImpl.class);
- c.connect();
+ int subId = getSubscriptionFromSlot(slotId);
+ updateSupportedFeatures(c, slotId, subId);
return c;
}
+ private void updateSupportedFeatures(RcsFeatureController c, int slotId, int subId) {
+ if (doesSubscriptionSupportPresence(subId)) {
+ if (c.getFeature(UserCapabilityExchangeImpl.class) == null) {
+ c.addFeature(mFeatureFactory.createUserCapabilityExchange(mContext, slotId, subId),
+ UserCapabilityExchangeImpl.class);
+ }
+ } else {
+ if (c.getFeature(UserCapabilityExchangeImpl.class) != null) {
+ c.removeFeature(UserCapabilityExchangeImpl.class);
+ }
+ }
+ // Only start the connection procedure if we have active features.
+ if (c.hasActiveFeatures()) c.connect();
+ }
+
+ private boolean doesSubscriptionSupportPresence(int subId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return false;
+ CarrierConfigManager carrierConfigManager =
+ mContext.getSystemService(CarrierConfigManager.class);
+ if (carrierConfigManager == null) return false;
+ boolean supportsUce = carrierConfigManager.getConfigForSubId(subId).getBoolean(
+ CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL);
+ supportsUce |= carrierConfigManager.getConfigForSubId(subId).getBoolean(
+ CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL);
+ return supportsUce;
+ }
+
+
private int getSubscriptionFromSlot(int slotId) {
SubscriptionManager manager = mContext.getSystemService(SubscriptionManager.class);
if (manager == null) {
@@ -229,7 +272,8 @@
pw.println("RcsFeatureControllers:");
pw.increaseIndent();
synchronized (mLock) {
- for (RcsFeatureController f : mFeatureControllers) {
+ for (int i = 0; i < mNumSlots; i++) {
+ RcsFeatureController f = mFeatureControllers.get(i);
pw.increaseIndent();
f.dump(fd, printWriter, args);
pw.decreaseIndent();
diff --git a/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java b/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
index 7521205..d488dff 100644
--- a/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
+++ b/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
@@ -44,7 +44,7 @@
public class UserCapabilityExchangeImpl implements RcsFeatureController.Feature, SubscribePublisher,
PresencePublisher {
- private static final String LOG_TAG = "UserCapabilityExchangeImpl";
+ private static final String LOG_TAG = "RcsUceImpl";
private int mSlotId;
private int mSubId;
@@ -58,6 +58,7 @@
UserCapabilityExchangeImpl(Context context, int slotId, int subId) {
mSlotId = slotId;
mSubId = subId;
+ logi("created");
String[] volteError = context.getResources().getStringArray(
R.array.config_volte_provision_error_on_publish_response);
@@ -78,7 +79,7 @@
// Runs on main thread.
@Override
public void onRcsConnected(RcsFeatureManager rcsFeatureManager) {
- Log.i(LOG_TAG, "onRcsConnected: slotId=" + mSlotId + ", subId=" + mSubId);
+ logi("onRcsConnected");
mPresencePublication.updatePresencePublisher(this);
mPresenceSubscriber.updatePresenceSubscriber(this);
}
@@ -86,7 +87,7 @@
// Runs on main thread.
@Override
public void onRcsDisconnected() {
- Log.i(LOG_TAG, "onRcsDisconnected: phoneId=" + mSlotId + ", subId=" + mSubId);
+ logi("onRcsDisconnected");
mPresencePublication.removePresencePublisher();
mPresenceSubscriber.removePresenceSubscriber();
}
@@ -127,7 +128,7 @@
new ContactCapabilityResponse() {
@Override
public void onSuccess(int reqId) {
- Log.i(LOG_TAG, "onSuccess called for reqId:" + reqId);
+ logi("onSuccess called for reqId:" + reqId);
}
@Override
@@ -137,16 +138,16 @@
if (c != null) {
c.onError(toUceError(resultCode));
} else {
- Log.w(LOG_TAG, "onError called for unknown reqId:" + reqId);
+ logw("onError called for unknown reqId:" + reqId);
}
} catch (RemoteException e) {
- Log.i(LOG_TAG, "Calling back to dead service");
+ logi("Calling back to dead service");
}
}
@Override
public void onFinish(int reqId) {
- Log.i(LOG_TAG, "onFinish called for reqId:" + reqId);
+ logi("onFinish called for reqId:" + reqId);
}
@Override
@@ -156,10 +157,10 @@
if (c != null) {
c.onError(RcsUceAdapter.ERROR_REQUEST_TIMEOUT);
} else {
- Log.w(LOG_TAG, "onTimeout called for unknown reqId:" + reqId);
+ logw("onTimeout called for unknown reqId:" + reqId);
}
} catch (RemoteException e) {
- Log.i(LOG_TAG, "Calling back to dead service");
+ logi("Calling back to dead service");
}
}
@@ -172,10 +173,10 @@
if (c != null) {
c.onCapabilitiesReceived(contactCapabilities);
} else {
- Log.w(LOG_TAG, "onCapabilitiesUpdated, unknown reqId:" + reqId);
+ logw("onCapabilitiesUpdated, unknown reqId:" + reqId);
}
} catch (RemoteException e) {
- Log.w(LOG_TAG, "onCapabilitiesUpdated on dead service");
+ logw("onCapabilitiesUpdated on dead service");
}
}
});
@@ -184,7 +185,7 @@
c.onError(toUceError(taskId));
return;
} catch (RemoteException e) {
- Log.i(LOG_TAG, "Calling back to dead service");
+ logi("Calling back to dead service");
}
}
mPendingCapabilityRequests.put(taskId, c);
@@ -272,4 +273,21 @@
return RcsUceAdapter.ERROR_GENERIC_FAILURE;
}
}
+
+ private void logi(String log) {
+ Log.i(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ private void logw(String log) {
+ Log.w(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ private StringBuilder getLogPrefix() {
+ StringBuilder builder = new StringBuilder("[");
+ builder.append(mSlotId);
+ builder.append("->");
+ builder.append(mSubId);
+ builder.append("] ");
+ return builder;
+ }
}
diff --git a/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
index cfede94..fbb270d 100644
--- a/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
+++ b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
@@ -107,7 +107,7 @@
}
@Test
- public void testFeatureManagerConnectedAddFeature() throws Exception {
+ public void testFeatureManagerConnectedAddRemoveFeature() throws Exception {
RcsFeatureController controller = createFeatureController();
// Connect the RcsFeatureManager
mConnectorListener.getValue().connectionReady(mFeatureManager);
@@ -115,6 +115,10 @@
verify(mMockFeature).onRcsConnected(mFeatureManager);
assertEquals(mMockFeature, controller.getFeature(RcsFeatureController.Feature.class));
+
+ controller.removeFeature(RcsFeatureController.Feature.class);
+ verify(mMockFeature).onDestroy();
+ assertNull(controller.getFeature(RcsFeatureController.Feature.class));
}
@Test
diff --git a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
index 68b08a7..cfb68b7 100644
--- a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
+++ b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
@@ -21,16 +21,21 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.BroadcastReceiver;
import android.content.Intent;
+import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
import androidx.test.runner.AndroidJUnit4;
import com.android.TelephonyTestBase;
+import com.android.ims.FeatureConnector;
+import com.android.ims.RcsFeatureManager;
import org.junit.After;
import org.junit.Before;
@@ -45,20 +50,31 @@
@Captor ArgumentCaptor<BroadcastReceiver> mReceiverCaptor;
@Mock TelephonyRcsService.FeatureFactory mFeatureFactory;
- @Mock RcsFeatureController mFeatureControllerSlot0;
- @Mock RcsFeatureController mFeatureControllerSlot1;
@Mock UserCapabilityExchangeImpl mMockUceSlot0;
@Mock UserCapabilityExchangeImpl mMockUceSlot1;
+ @Mock RcsFeatureController.RegistrationHelperFactory mRegistrationFactory;
+ @Mock RcsFeatureController.FeatureConnectorFactory<RcsFeatureManager> mFeatureConnectorFactory;
+ @Mock FeatureConnector<RcsFeatureManager> mFeatureConnector;
+
+ private RcsFeatureController mFeatureControllerSlot0;
+ private RcsFeatureController mFeatureControllerSlot1;
@Before
public void setUp() throws Exception {
super.setUp();
+ doReturn(mFeatureConnector).when(mFeatureConnectorFactory).create(any(), anyInt(),
+ any(), any(), any());
+ mFeatureControllerSlot0 = createFeatureController(0 /*slotId*/);
+ mFeatureControllerSlot1 = createFeatureController(1 /*slotId*/);
doReturn(mFeatureControllerSlot0).when(mFeatureFactory).createController(any(), eq(0));
doReturn(mFeatureControllerSlot1).when(mFeatureFactory).createController(any(), eq(1));
doReturn(mMockUceSlot0).when(mFeatureFactory).createUserCapabilityExchange(any(), eq(0),
anyInt());
doReturn(mMockUceSlot1).when(mFeatureFactory).createUserCapabilityExchange(any(), eq(1),
anyInt());
+ //set up default slot-> sub ID mappings.
+ setSlotToSubIdMapping(0 /*slotId*/, 1/*subId*/);
+ setSlotToSubIdMapping(1 /*slotId*/, 2/*subId*/);
}
@After
@@ -67,14 +83,46 @@
}
@Test
- public void testUserCapabilityExchangeConnected() {
+ public void testUserCapabilityExchangePresenceConnected() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
createRcsService(1 /*numSlots*/);
verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
verify(mFeatureControllerSlot0).connect();
}
@Test
+ public void testUserCapabilityExchangeOptionsConnected() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL, true /*isEnabled*/);
+ createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+ }
+
+ @Test
+ public void testNoFeaturesEnabled() {
+ createRcsService(1 /*numSlots*/);
+ // No carrier config set for UCE.
+ verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, never()).connect();
+ }
+
+ @Test
+ public void testNoFeaturesEnabledCarrierConfigChanged() {
+ createRcsService(1 /*numSlots*/);
+ // No carrier config set for UCE.
+
+ sendCarrierConfigChanged(0, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, never()).connect();
+ verify(mFeatureControllerSlot0, never()).updateAssociatedSubscription(anyInt());
+ }
+
+
+ @Test
public void testSlotUpdates() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
TelephonyRcsService service = createRcsService(1 /*numSlots*/);
verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
verify(mFeatureControllerSlot0).connect();
@@ -94,8 +142,7 @@
verify(mFeatureControllerSlot0, times(1)).addFeature(mMockUceSlot0,
UserCapabilityExchangeImpl.class);
verify(mFeatureControllerSlot0, times(1)).connect();
- verify(mFeatureControllerSlot1, times(1)).addFeature(mMockUceSlot1,
- UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot1).addFeature(mMockUceSlot1, UserCapabilityExchangeImpl.class);
verify(mFeatureControllerSlot1, times(1)).connect();
// Remove a slot.
@@ -116,6 +163,7 @@
@Test
public void testCarrierConfigUpdate() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
createRcsService(2 /*numSlots*/);
verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
verify(mFeatureControllerSlot1).addFeature(mMockUceSlot1, UserCapabilityExchangeImpl.class);
@@ -132,6 +180,37 @@
verify(mFeatureControllerSlot1, times(1)).updateAssociatedSubscription(2);
}
+ @Test
+ public void testCarrierConfigUpdateUceToNoUce() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+ createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+
+
+ // Send carrier config update for each slot.
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, false /*isEnabled*/);
+ sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+ verify(mFeatureControllerSlot0).removeFeature(UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).updateAssociatedSubscription(1);
+ }
+
+ @Test
+ public void testCarrierConfigUpdateNoUceToUce() {
+ createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, never()).connect();
+
+
+ // Send carrier config update for each slot.
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+ sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+ verify(mFeatureControllerSlot0).updateAssociatedSubscription(1);
+ }
+
private void sendCarrierConfigChanged(int slotId, int subId) {
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, slotId);
@@ -139,6 +218,18 @@
mReceiverCaptor.getValue().onReceive(mContext, intent);
}
+ private void setCarrierConfig(String key, boolean value) {
+ PersistableBundle bundle = mContext.getCarrierConfig();
+ bundle.putBoolean(key, value);
+ }
+
+ private void setSlotToSubIdMapping(int slotId, int loadedSubId) {
+ SubscriptionManager m = mContext.getSystemService(SubscriptionManager.class);
+ int [] subIds = new int[1];
+ subIds[0] = loadedSubId;
+ doReturn(subIds).when(m).getSubscriptionIds(eq(slotId));
+ }
+
private TelephonyRcsService createRcsService(int numSlots) {
TelephonyRcsService service = new TelephonyRcsService(mContext, numSlots);
service.setFeatureFactory(mFeatureFactory);
@@ -146,4 +237,13 @@
verify(mContext).registerReceiver(mReceiverCaptor.capture(), any());
return service;
}
+
+ private RcsFeatureController createFeatureController(int slotId) {
+ // Create a spy instead of a mock because TelephonyRcsService relies on state provided by
+ // RcsFeatureController.
+ RcsFeatureController controller = spy(new RcsFeatureController(mContext, slotId,
+ mRegistrationFactory));
+ controller.setFeatureConnectorFactory(mFeatureConnectorFactory);
+ return controller;
+ }
}