Disable merge capability for DSDA calls
- Do not mark connections from other PhoneAccountHandles as
conferenceable.
Bug:249851262
Test: Update ImsConferenceControllerTest
Live test on Pixel 7 by receiving calls on different subs
Change-Id: I1feb6582c249051c8ac196aea1767aef66706d9b
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 7cf9415..4200904 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -16,6 +16,7 @@
package com.android.services.telephony;
+import android.annotation.NonNull;
import android.content.Context;
import android.os.PersistableBundle;
import android.telecom.Conference;
@@ -26,17 +27,17 @@
import android.telecom.PhoneAccountHandle;
import android.telephony.CarrierConfigManager;
-import com.android.telephony.Rlog;
-
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.phone.PhoneUtils;
+import com.android.telephony.Rlog;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import java.util.stream.Collectors;
/**
@@ -220,14 +221,33 @@
recalculateConference();
}
+ private PhoneAccountHandle getPhoneAccountHandle(@NonNull Conferenceable c) {
+ if (c instanceof Connection) {
+ Connection connection = (Connection) c;
+ return connection.getPhoneAccountHandle();
+ } else if (c instanceof Conference) {
+ Conference conference = (Conference) c;
+ return conference.getPhoneAccountHandle();
+ }
+ throw new IllegalArgumentException("Unrecognized Conferenceable!" + c);
+ }
+
+ private boolean isSamePhoneAccountHandle(
+ @NonNull Conferenceable left, @NonNull Conferenceable right) {
+ PhoneAccountHandle leftHandle = getPhoneAccountHandle(left);
+ PhoneAccountHandle rightHandle = getPhoneAccountHandle(right);
+ return Objects.equals(leftHandle, rightHandle);
+ }
+
/**
* Calculates the conference-capable state of all GSM connections in this connection service.
+ * Connections from different {@link PhoneAccountHandle}s shall not be conferenceable.
*/
private void recalculateConferenceable() {
Log.v(this, "recalculateConferenceable : %d", mTelephonyConnections.size());
HashSet<Conferenceable> conferenceableSet = new HashSet<>(mTelephonyConnections.size() +
mImsConferences.size());
- HashSet<Conferenceable> conferenceParticipantsSet = new HashSet<>();
+ HashSet<Connection> conferenceParticipantsSet = new HashSet<>();
// Loop through and collect all calls which are active or holding
for (TelephonyConnection connection : mTelephonyConnections) {
@@ -300,11 +320,6 @@
for (Conferenceable c : conferenceableSet) {
if (c instanceof Connection) {
- // Remove this connection from the Set and add all others
- List<Conferenceable> conferenceables = conferenceableSet
- .stream()
- .filter(conferenceable -> c != conferenceable)
- .collect(Collectors.toList());
// TODO: Remove this once RemoteConnection#setConferenceableConnections is fixed.
// Add all conference participant connections as conferenceable with a standalone
// Connection. We need to do this to ensure that RemoteConnections work properly.
@@ -313,7 +328,18 @@
// into the conference.
// We should add support for RemoteConnection#setConferenceables, which accepts a
// list of remote conferences and connections in the future.
- conferenceables.addAll(conferenceParticipantsSet);
+ List<Conferenceable> conferenceables = conferenceParticipantsSet
+ .stream()
+ // Removes conference participants from different PhoneAccountHandles.
+ .filter(connection -> isSamePhoneAccountHandle(c, connection))
+ .collect(Collectors.toCollection(ArrayList::new));
+
+ // Removes this connection from the Set and add all others. Removes conferenceables
+ // from different PhoneAccountHandles.
+ conferenceables.addAll(conferenceableSet
+ .stream()
+ .filter(conferenceable -> c != conferenceable
+ && isSamePhoneAccountHandle(c, conferenceable)).toList());
((Connection) c).setConferenceables(conferenceables);
} else if (c instanceof ImsConference) {
@@ -325,10 +351,11 @@
}
// Remove all conferences from the set, since we can not conference a conference
- // to another conference.
+ // to another conference. Removes connections from different PhoneAccountHandles.
List<Connection> connections = conferenceableSet
.stream()
- .filter(conferenceable -> conferenceable instanceof Connection)
+ .filter(conferenceable -> conferenceable instanceof Connection
+ && isSamePhoneAccountHandle(c, conferenceable))
.map(conferenceable -> (Connection) conferenceable)
.collect(Collectors.toList());
// Conference equivalent to setConferenceables that only accepts Connections
diff --git a/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java b/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
index 33c8b8a..a9207e6 100644
--- a/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
+++ b/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
@@ -24,7 +24,9 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.ComponentName;
import android.os.Looper;
+import android.telecom.PhoneAccountHandle;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Before;
@@ -46,6 +48,14 @@
@Mock
private TelecomAccountRegistry mMockTelecomAccountRegistry;
+ private static final ComponentName TEST_COMPONENT_NAME = new ComponentName(
+ "com.android.phone.tests", ImsConferenceControllerTest.class.getName());
+ private static final String TEST_ACCOUNT_ID1 = "id1";
+ private static final String TEST_ACCOUNT_ID2 = "id2";
+ private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_1 = new PhoneAccountHandle(
+ TEST_COMPONENT_NAME, TEST_ACCOUNT_ID1);
+ private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_2 = new PhoneAccountHandle(
+ TEST_COMPONENT_NAME, TEST_ACCOUNT_ID2);
private TestTelephonyConnection mTestTelephonyConnectionA;
private TestTelephonyConnection mTestTelephonyConnectionB;
@@ -61,6 +71,9 @@
mTestTelephonyConnectionA = new TestTelephonyConnection();
mTestTelephonyConnectionB = new TestTelephonyConnection();
+ mTestTelephonyConnectionA.setPhoneAccountHandle(PHONE_ACCOUNT_HANDLE_1);
+ mTestTelephonyConnectionB.setPhoneAccountHandle(PHONE_ACCOUNT_HANDLE_1);
+
mControllerTest = new ImsConferenceController(mTelecomAccountRegistry,
mMockTelephonyConnectionServiceProxy, () -> false);
}
@@ -99,6 +112,27 @@
}
/**
+ * Behavior: add telephony connections A and B to conference controller;
+ * Assumption: Connection A and B have different PhoneAccountHandles, belong to different subs;
+ * Expected: Connection A and Connection B are not conferenceable with each other;
+ */
+ @Test
+ @SmallTest
+ public void testCallsOnDifferentSubsNotConferenceable() {
+ mTestTelephonyConnectionB.setPhoneAccountHandle(PHONE_ACCOUNT_HANDLE_2);
+ mControllerTest.add(mTestTelephonyConnectionA);
+ mControllerTest.add(mTestTelephonyConnectionB);
+
+ mTestTelephonyConnectionA.setActive();
+ mTestTelephonyConnectionB.setTelephonyConnectionOnHold();
+
+ assertFalse(mTestTelephonyConnectionA.getConferenceables()
+ .contains(mTestTelephonyConnectionB));
+ assertFalse(mTestTelephonyConnectionB.getConferenceables()
+ .contains(mTestTelephonyConnectionA));
+ }
+
+ /**
* Behavior: add telephony connection B and A to conference controller,
* set status for merged connections
* Assumption: after performing the behaviors, the status of Connection A is STATE_ACTIVE;