Loading flags/telecom_calls_manager_flags.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -8,3 +8,14 @@ flag { description: "Enables simultaneous call sequencing for SIM PhoneAccounts" bug: "327038818" } # OWNER=pmadapurmath TARGET=25Q3 flag { name: "allow_call_on_same_connection_mgr" namespace: "telecom" description: "If two incoming calls are received at the same time from the same connection service, allow the CS to handle the second call." bug: "414261900" metadata { purpose: PURPOSE_BUGFIX } } src/com/android/server/telecom/CallsManager.java +20 −1 Original line number Diff line number Diff line Loading @@ -1784,6 +1784,24 @@ public class CallsManager extends Call.ListenerBase : mUserManager.isQuietModeEnabled(call.getAssociatedUser()); } boolean ignoreIncomingCallFailureOnSameNumber = false; if (hasMaximumManagedRingingCalls(call)) { Call ringingCall = getRingingOrSimulatedRingingCall(); PhoneAccountHandle connectionMgr = mPhoneAccountRegistrar.getSimCallManagerFromCall( call); // Check if the new incoming call is using the same connection mgr with the already // tracked ringing call. This can happen in a scenario where two incoming calls are // received on Fi: one from Tycho (over WiFi) and from Telephony via the mobile network. // In this case, we should allow the new call to go through instead of failing it and // logging it. We are refraining from doing a phone number check as it's possible that // Fi is using shadow numbers. if (mFeatureFlags.allowCallOnSameConnectionMgr() && ringingCall != null && connectionMgr != null && Objects.equals(connectionMgr, ringingCall.getConnectionManagerPhoneAccount())) { ignoreIncomingCallFailureOnSameNumber = true; } } // We should always allow emergency calls and also allow non-emergency calls when ECBM // is active for the phone account. if (isCallHiddenFromProfile && !call.isEmergencyCall() && !call.isInECBM()) { Loading Loading @@ -1825,7 +1843,8 @@ public class CallsManager extends Call.ListenerBase } else { notifyCreateConnectionFailed(phoneAccountHandle, call); } } else if (mFeatureFlags.enableCallSequencing() && (hasMaximumManagedRingingCalls(call) } else if (mFeatureFlags.enableCallSequencing() && ((hasMaximumManagedRingingCalls(call) && !ignoreIncomingCallFailureOnSameNumber) || hasMaximumManagedDialingCalls(call))) { // Fail incoming call if there's already a ringing or dialing call present. boolean maxRinging = hasMaximumManagedRingingCalls(call); Loading tests/src/com/android/server/telecom/tests/CallsManagerTest.java +37 −5 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.telecom.tests; import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED; import static android.provider.CallLog.Calls.USER_MISSED_NOT_RUNNING; import static junit.framework.Assert.assertNotNull; Loading Loading @@ -51,7 +52,6 @@ import static java.lang.Thread.sleep; import android.Manifest; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; Loading Loading @@ -83,7 +83,6 @@ import android.telephony.PhoneCapability; import android.telephony.TelephonyManager; import android.util.ArraySet; import android.util.Pair; import android.widget.Toast; import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; Loading Loading @@ -146,8 +145,6 @@ import com.android.server.telecom.ui.DisconnectedCallNotifier; import com.android.server.telecom.ui.ToastFactory; import com.android.server.telecom.callsequencing.TransactionManager; import com.google.common.base.Objects; import org.junit.After; import org.junit.Before; import org.junit.Test; Loading @@ -170,7 +167,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @RunWith(JUnit4.class) public class CallsManagerTest extends TelecomTestCase { Loading Loading @@ -262,6 +258,8 @@ public class CallsManagerTest extends TelecomTestCase { private static final Uri TEST_ADDRESS = Uri.parse("tel:555-1212"); private static final Uri TEST_ADDRESS2 = Uri.parse("tel:555-1213"); private static final Uri TEST_ADDRESS3 = Uri.parse("tel:555-1214"); private static final String TEST_NUMBER = "1234567890"; private static final Map<Uri, PhoneAccountHandle> CONTACT_PREFERRED_ACCOUNT = Map.of( TEST_ADDRESS2, SIM_1_HANDLE, TEST_ADDRESS3, SIM_2_HANDLE); Loading Loading @@ -773,6 +771,7 @@ public class CallsManagerTest extends TelecomTestCase { Uri handle = invocation.getArgument(0); CallerInfoLookupHelper.OnQueryCompleteListener listener = invocation.getArgument(1); CallerInfo info = new CallerInfo(); info.setPhoneNumber(TEST_NUMBER); if (CONTACT_PREFERRED_ACCOUNT.get(handle) != null) { PhoneAccountHandle pah = CONTACT_PREFERRED_ACCOUNT.get(handle); info.preferredPhoneAccountComponent = pah.getComponentName(); Loading Loading @@ -3855,6 +3854,39 @@ public class CallsManagerTest extends TelecomTestCase { assertTrue(mCallsManager.getPendingAccountSelection().containsKey(pendingCall.getId())); } @SmallTest @Test public void testIgnoreMaxRingingCallOnSameNumber() { when(mFeatureFlags.enableCallSequencing()).thenReturn(true); when(mFeatureFlags.allowCallOnSameConnectionMgr()).thenReturn(true); setupCallerInfoLookupHelper(); ConnectionServiceWrapper service = mock(ConnectionServiceWrapper.class); doReturn(SIM_1_HANDLE.getComponentName()).when(service).getComponentName(); mCallsManager.addConnectionServiceRepositoryCache(SIM_1_HANDLE.getComponentName(), SIM_1_HANDLE.getUserHandle(), service); when(mPhoneAccountRegistrar.phoneAccountRequiresBindPermission( any(PhoneAccountHandle.class))).thenReturn(true); // WHEN Call existingIncomingCall = createCall(SIM_2_HANDLE, CallState.RINGING); mCallsManager.addCall(existingIncomingCall); PhoneAccountHandle connectionMgr = mock(PhoneAccountHandle.class); existingIncomingCall.setConnectionManagerPhoneAccount(connectionMgr); when(mPhoneAccountRegistrar.getSimCallManagerFromCall(any(Call.class))) .thenReturn(connectionMgr); when(mMockCurrentUserManager.isAdminUser()).thenReturn(true); // THEN, add a new incoming call with the same number as the 1st call Bundle extras = new Bundle(); extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, TEST_ADDRESS); Call newCall = mCallsManager.processIncomingCallIntent(SIM_2_HANDLE, extras, false); // Verify we don't mark the call as auto missed and that the connection doesn't fail // locally. assertEquals(existingIncomingCall, mCallsManager.getRingingOrSimulatedRingingCall()); assertEquals(newCall.getMissedReason(), MISSED_REASON_NOT_MISSED); verify(service, never()).createConnectionFailed(any()); } private Call addSpyCall() { return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE); } Loading Loading
flags/telecom_calls_manager_flags.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -8,3 +8,14 @@ flag { description: "Enables simultaneous call sequencing for SIM PhoneAccounts" bug: "327038818" } # OWNER=pmadapurmath TARGET=25Q3 flag { name: "allow_call_on_same_connection_mgr" namespace: "telecom" description: "If two incoming calls are received at the same time from the same connection service, allow the CS to handle the second call." bug: "414261900" metadata { purpose: PURPOSE_BUGFIX } }
src/com/android/server/telecom/CallsManager.java +20 −1 Original line number Diff line number Diff line Loading @@ -1784,6 +1784,24 @@ public class CallsManager extends Call.ListenerBase : mUserManager.isQuietModeEnabled(call.getAssociatedUser()); } boolean ignoreIncomingCallFailureOnSameNumber = false; if (hasMaximumManagedRingingCalls(call)) { Call ringingCall = getRingingOrSimulatedRingingCall(); PhoneAccountHandle connectionMgr = mPhoneAccountRegistrar.getSimCallManagerFromCall( call); // Check if the new incoming call is using the same connection mgr with the already // tracked ringing call. This can happen in a scenario where two incoming calls are // received on Fi: one from Tycho (over WiFi) and from Telephony via the mobile network. // In this case, we should allow the new call to go through instead of failing it and // logging it. We are refraining from doing a phone number check as it's possible that // Fi is using shadow numbers. if (mFeatureFlags.allowCallOnSameConnectionMgr() && ringingCall != null && connectionMgr != null && Objects.equals(connectionMgr, ringingCall.getConnectionManagerPhoneAccount())) { ignoreIncomingCallFailureOnSameNumber = true; } } // We should always allow emergency calls and also allow non-emergency calls when ECBM // is active for the phone account. if (isCallHiddenFromProfile && !call.isEmergencyCall() && !call.isInECBM()) { Loading Loading @@ -1825,7 +1843,8 @@ public class CallsManager extends Call.ListenerBase } else { notifyCreateConnectionFailed(phoneAccountHandle, call); } } else if (mFeatureFlags.enableCallSequencing() && (hasMaximumManagedRingingCalls(call) } else if (mFeatureFlags.enableCallSequencing() && ((hasMaximumManagedRingingCalls(call) && !ignoreIncomingCallFailureOnSameNumber) || hasMaximumManagedDialingCalls(call))) { // Fail incoming call if there's already a ringing or dialing call present. boolean maxRinging = hasMaximumManagedRingingCalls(call); Loading
tests/src/com/android/server/telecom/tests/CallsManagerTest.java +37 −5 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.telecom.tests; import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED; import static android.provider.CallLog.Calls.USER_MISSED_NOT_RUNNING; import static junit.framework.Assert.assertNotNull; Loading Loading @@ -51,7 +52,6 @@ import static java.lang.Thread.sleep; import android.Manifest; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; Loading Loading @@ -83,7 +83,6 @@ import android.telephony.PhoneCapability; import android.telephony.TelephonyManager; import android.util.ArraySet; import android.util.Pair; import android.widget.Toast; import androidx.test.filters.MediumTest; import androidx.test.filters.SmallTest; Loading Loading @@ -146,8 +145,6 @@ import com.android.server.telecom.ui.DisconnectedCallNotifier; import com.android.server.telecom.ui.ToastFactory; import com.android.server.telecom.callsequencing.TransactionManager; import com.google.common.base.Objects; import org.junit.After; import org.junit.Before; import org.junit.Test; Loading @@ -170,7 +167,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @RunWith(JUnit4.class) public class CallsManagerTest extends TelecomTestCase { Loading Loading @@ -262,6 +258,8 @@ public class CallsManagerTest extends TelecomTestCase { private static final Uri TEST_ADDRESS = Uri.parse("tel:555-1212"); private static final Uri TEST_ADDRESS2 = Uri.parse("tel:555-1213"); private static final Uri TEST_ADDRESS3 = Uri.parse("tel:555-1214"); private static final String TEST_NUMBER = "1234567890"; private static final Map<Uri, PhoneAccountHandle> CONTACT_PREFERRED_ACCOUNT = Map.of( TEST_ADDRESS2, SIM_1_HANDLE, TEST_ADDRESS3, SIM_2_HANDLE); Loading Loading @@ -773,6 +771,7 @@ public class CallsManagerTest extends TelecomTestCase { Uri handle = invocation.getArgument(0); CallerInfoLookupHelper.OnQueryCompleteListener listener = invocation.getArgument(1); CallerInfo info = new CallerInfo(); info.setPhoneNumber(TEST_NUMBER); if (CONTACT_PREFERRED_ACCOUNT.get(handle) != null) { PhoneAccountHandle pah = CONTACT_PREFERRED_ACCOUNT.get(handle); info.preferredPhoneAccountComponent = pah.getComponentName(); Loading Loading @@ -3855,6 +3854,39 @@ public class CallsManagerTest extends TelecomTestCase { assertTrue(mCallsManager.getPendingAccountSelection().containsKey(pendingCall.getId())); } @SmallTest @Test public void testIgnoreMaxRingingCallOnSameNumber() { when(mFeatureFlags.enableCallSequencing()).thenReturn(true); when(mFeatureFlags.allowCallOnSameConnectionMgr()).thenReturn(true); setupCallerInfoLookupHelper(); ConnectionServiceWrapper service = mock(ConnectionServiceWrapper.class); doReturn(SIM_1_HANDLE.getComponentName()).when(service).getComponentName(); mCallsManager.addConnectionServiceRepositoryCache(SIM_1_HANDLE.getComponentName(), SIM_1_HANDLE.getUserHandle(), service); when(mPhoneAccountRegistrar.phoneAccountRequiresBindPermission( any(PhoneAccountHandle.class))).thenReturn(true); // WHEN Call existingIncomingCall = createCall(SIM_2_HANDLE, CallState.RINGING); mCallsManager.addCall(existingIncomingCall); PhoneAccountHandle connectionMgr = mock(PhoneAccountHandle.class); existingIncomingCall.setConnectionManagerPhoneAccount(connectionMgr); when(mPhoneAccountRegistrar.getSimCallManagerFromCall(any(Call.class))) .thenReturn(connectionMgr); when(mMockCurrentUserManager.isAdminUser()).thenReturn(true); // THEN, add a new incoming call with the same number as the 1st call Bundle extras = new Bundle(); extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, TEST_ADDRESS); Call newCall = mCallsManager.processIncomingCallIntent(SIM_2_HANDLE, extras, false); // Verify we don't mark the call as auto missed and that the connection doesn't fail // locally. assertEquals(existingIncomingCall, mCallsManager.getRingingOrSimulatedRingingCall()); assertEquals(newCall.getMissedReason(), MISSED_REASON_NOT_MISSED); verify(service, never()).createConnectionFailed(any()); } private Call addSpyCall() { return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE); } Loading