Loading src/com/android/server/telecom/Call.java +13 −3 Original line number Diff line number Diff line Loading @@ -131,10 +131,20 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, private static final char NO_DTMF_TONE = '\0'; /** * The following simultaneous call types will be set on each call on creation and may be updated * according to priority level. CALL_DIRECTION_DUAL_DIFF_ACCOUNT holds the highest priority. * So if for example, a call is created with CALL_DIRECTION_DUAL_SAME_ACCOUNT, it can be * upgraded to CALL_DIRECTION_DUAL_DIFF_ACCOUNT if another call is added with a different phone * account. */ public static final int CALL_SIMULTANEOUS_UNKNOWN = 0; public static final int CALL_SIMULTANEOUS_SINGLE = 1; public static final int CALL_DIRECTION_DUAL_SAME_ACCOUNT = 2; public static final int CALL_DIRECTION_DUAL_DIFF_ACCOUNT = 3; // Only used if simultaneous calling is not available public static final int CALL_SIMULTANEOUS_DISABLED_SAME_ACCOUNT = 1; // Only used if simultaneous calling is not available public static final int CALL_SIMULTANEOUS_DISABLED_DIFF_ACCOUNT = 2; public static final int CALL_DIRECTION_DUAL_SAME_ACCOUNT = 3; public static final int CALL_DIRECTION_DUAL_DIFF_ACCOUNT = 4; /** * Listener for CallState changes which can be leveraged by a Transaction. Loading src/com/android/server/telecom/CallsManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -511,7 +511,7 @@ public class CallsManager extends Call.ListenerBase private final UserManager mUserManager; private final CallStreamingNotification mCallStreamingNotification; private final BlockedNumbersManager mBlockedNumbersManager; private final CallsManagerCallSequencingAdapter mCallSequencingAdapter; private CallsManagerCallSequencingAdapter mCallSequencingAdapter; private final FeatureFlags mFeatureFlags; private final com.android.internal.telephony.flags.FeatureFlags mTelephonyFeatureFlags; Loading Loading @@ -4864,6 +4864,9 @@ public class CallsManager extends Call.ListenerBase Log.i(this, "addCall(%s)", call); call.addListener(this); mCalls.add(call); // Reprocess the simultaneous call types for all the tracked calls after having added a new // call. mCallSequencingAdapter.processSimultaneousCallTypes(mCalls); mSelfManagedCallsBeingSetup.remove(call); // Specifies the time telecom finished routing the call. This is used by the dialer for Loading Loading @@ -7172,6 +7175,11 @@ public class CallsManager extends Call.ListenerBase return mCallSequencingAdapter; } @VisibleForTesting public void setCallSequencingAdapter(CallsManagerCallSequencingAdapter adapter) { mCallSequencingAdapter = adapter; } public void waitForAudioToUpdate(boolean expectActive) { Log.i(this, "waitForAudioToUpdate"); if (mFeatureFlags.useRefactoredAudioRouteSwitching()) { Loading src/com/android/server/telecom/callsequencing/CallsManagerCallSequencingAdapter.java +50 −4 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ package com.android.server.telecom.callsequencing; import static com.android.server.telecom.CallsManager.CALL_FILTER_ALL; import static com.android.server.telecom.CallsManager.ONGOING_CALL_STATES; import android.content.Context; import android.os.Bundle; import android.os.Handler; Loading @@ -26,8 +23,8 @@ import android.os.OutcomeReceiver; import android.telecom.CallAttributes; import android.telecom.CallException; import android.telecom.Connection; import android.telecom.DisconnectCause; import android.telecom.Log; import android.telecom.PhoneAccountHandle; import com.android.server.telecom.Call; import com.android.server.telecom.CallAudioManager; Loading @@ -37,6 +34,9 @@ import com.android.server.telecom.callsequencing.voip.OutgoingCallTransaction; import com.android.server.telecom.flags.FeatureFlags; import com.android.server.telecom.R; import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CompletableFuture; /** Loading Loading @@ -309,6 +309,52 @@ public class CallsManagerCallSequencingAdapter { return !mIsCallSequencingEnabled || !mSequencingController.hasMmiCodeRestriction(call); } /** * Processes the simultaneous call type for the ongoing calls that are being tracked in * {@link CallsManager}. The current call's simultaneous call type will be overridden only if * it's current type priority is lower than the one being set. * @param calls The list of the currently tracked calls. */ public void processSimultaneousCallTypes(Collection<Call> calls) { // Metrics should only be tracked when call sequencing flag is enabled. if (!mIsCallSequencingEnabled) { return; } // Device should have simultaneous calling supported. boolean isSimultaneousCallingSupported = mCallsManager.isDsdaCallingPossible(); int type; // Go through the available calls' phone accounts to determine how many different ones // are being used. Set<PhoneAccountHandle> handles = new HashSet<>(); for (Call call : calls) { if (call.getTargetPhoneAccount() != null) { handles.add(call.getTargetPhoneAccount()); } // No need to proceed further given that we already know there is more than 1 phone // account being used. if (handles.size() > 1) { break; } } type = handles.size() > 1 ? (isSimultaneousCallingSupported ? Call.CALL_DIRECTION_DUAL_DIFF_ACCOUNT : Call.CALL_SIMULTANEOUS_DISABLED_DIFF_ACCOUNT) : (isSimultaneousCallingSupported ? Call.CALL_DIRECTION_DUAL_SAME_ACCOUNT : Call.CALL_SIMULTANEOUS_DISABLED_SAME_ACCOUNT); Log.i(this, "processSimultaneousCallTypes: the calculated simultaneous call type for " + "the tracked calls is [%d]", type); calls.forEach(c -> { // If the current call's simultaneous call type priority is lower than the one being // set, then let the override occur. Otherwise, ignore it. if (c.getSimultaneousType() < type) { Log.i(this, "processSimultaneousCallTypes: overriding simultaneous call type for " + "call (%s). Previous value: %d", c.getId(), c.getSimultaneousType()); c.setSimultaneousType(type); } }); } public Handler getHandler() { return mHandler; } Loading tests/src/com/android/server/telecom/tests/CallsManagerTest.java +48 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ import com.android.server.telecom.CallEndpointControllerFactory; import com.android.server.telecom.CallState; import com.android.server.telecom.CallerInfoLookupHelper; import com.android.server.telecom.CallsManager; import com.android.server.telecom.callsequencing.CallSequencingController; import com.android.server.telecom.callsequencing.CallsManagerCallSequencingAdapter; import com.android.server.telecom.ClockProxy; import com.android.server.telecom.ConnectionServiceFocusManager; Loading Loading @@ -3777,6 +3778,53 @@ public class CallsManagerTest extends TelecomTestCase { inOrder.verify(call).setState(eq(CallState.RINGING), anyString()); } @SmallTest @Test public void testSimultaneousCallType() { when(mFeatureFlags.enableCallSequencing()).thenReturn(true); // Setup CallsManagerCallSequencingAdapter CallSequencingController sequencingController = mock(CallSequencingController.class); CallAudioManager callAudioManager = mock(CallAudioManager.class); CallsManagerCallSequencingAdapter adapter = new CallsManagerCallSequencingAdapter( mCallsManager, mContext, sequencingController, callAudioManager, mFeatureFlags); mCallsManager.setCallSequencingAdapter(adapter); // Explicitly disable simultaneous calling TelephonyManager mockTelephonyManager = mComponentContextFixture.getTelephonyManager(); when(mockTelephonyManager.getMaxNumberOfSimultaneouslyActiveSims()).thenReturn(1); Call call1 = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE); assertEquals(call1.getSimultaneousType(), Call.CALL_SIMULTANEOUS_DISABLED_SAME_ACCOUNT); // Emulate adding another concurrent call on a different call when simultaneous calling // isn't supported by the device. Call call2 = addSpyCall(SIM_2_HANDLE, CallState.ON_HOLD); assertEquals(call1.getSimultaneousType(), Call.CALL_SIMULTANEOUS_DISABLED_DIFF_ACCOUNT); assertEquals(call2.getSimultaneousType(), Call.CALL_SIMULTANEOUS_DISABLED_DIFF_ACCOUNT); mCallsManager.removeCall(call2); // Now enable simultaneous calling and verify the updated call simultaneous types when // adding another call. when(mockTelephonyManager.getMaxNumberOfSimultaneouslyActiveSims()).thenReturn(2); call2 = addSpyCall(SIM_1_HANDLE, CallState.ON_HOLD); assertEquals(call1.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_SAME_ACCOUNT); assertEquals(call2.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_SAME_ACCOUNT); // Add a new call and remove the held one (emulation). mCallsManager.removeCall(call2); // Verify that the simultaneous call type priority of the 1st call has been upgraded. Call call3 = addSpyCall(SIM_2_HANDLE, CallState.ACTIVE); assertEquals(call1.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_DIFF_ACCOUNT); assertEquals(call3.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_DIFF_ACCOUNT); // Remove the first call and add another call with the same handle as the third call. mCallsManager.removeCall(call1); Call call4 = addSpyCall(SIM_2_HANDLE, CallState.ON_HOLD); // Verify that call3's priority remains unchanged but call4's priority is // Call.CALL_DIRECTION_DUAL_SAME_ACCOUNT. assertEquals(call3.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_DIFF_ACCOUNT); assertEquals(call4.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_SAME_ACCOUNT); } @SmallTest @Test public void testPendingAccountSelectionNotClearedWithNewCall() { Loading Loading
src/com/android/server/telecom/Call.java +13 −3 Original line number Diff line number Diff line Loading @@ -131,10 +131,20 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, private static final char NO_DTMF_TONE = '\0'; /** * The following simultaneous call types will be set on each call on creation and may be updated * according to priority level. CALL_DIRECTION_DUAL_DIFF_ACCOUNT holds the highest priority. * So if for example, a call is created with CALL_DIRECTION_DUAL_SAME_ACCOUNT, it can be * upgraded to CALL_DIRECTION_DUAL_DIFF_ACCOUNT if another call is added with a different phone * account. */ public static final int CALL_SIMULTANEOUS_UNKNOWN = 0; public static final int CALL_SIMULTANEOUS_SINGLE = 1; public static final int CALL_DIRECTION_DUAL_SAME_ACCOUNT = 2; public static final int CALL_DIRECTION_DUAL_DIFF_ACCOUNT = 3; // Only used if simultaneous calling is not available public static final int CALL_SIMULTANEOUS_DISABLED_SAME_ACCOUNT = 1; // Only used if simultaneous calling is not available public static final int CALL_SIMULTANEOUS_DISABLED_DIFF_ACCOUNT = 2; public static final int CALL_DIRECTION_DUAL_SAME_ACCOUNT = 3; public static final int CALL_DIRECTION_DUAL_DIFF_ACCOUNT = 4; /** * Listener for CallState changes which can be leveraged by a Transaction. Loading
src/com/android/server/telecom/CallsManager.java +9 −1 Original line number Diff line number Diff line Loading @@ -511,7 +511,7 @@ public class CallsManager extends Call.ListenerBase private final UserManager mUserManager; private final CallStreamingNotification mCallStreamingNotification; private final BlockedNumbersManager mBlockedNumbersManager; private final CallsManagerCallSequencingAdapter mCallSequencingAdapter; private CallsManagerCallSequencingAdapter mCallSequencingAdapter; private final FeatureFlags mFeatureFlags; private final com.android.internal.telephony.flags.FeatureFlags mTelephonyFeatureFlags; Loading Loading @@ -4864,6 +4864,9 @@ public class CallsManager extends Call.ListenerBase Log.i(this, "addCall(%s)", call); call.addListener(this); mCalls.add(call); // Reprocess the simultaneous call types for all the tracked calls after having added a new // call. mCallSequencingAdapter.processSimultaneousCallTypes(mCalls); mSelfManagedCallsBeingSetup.remove(call); // Specifies the time telecom finished routing the call. This is used by the dialer for Loading Loading @@ -7172,6 +7175,11 @@ public class CallsManager extends Call.ListenerBase return mCallSequencingAdapter; } @VisibleForTesting public void setCallSequencingAdapter(CallsManagerCallSequencingAdapter adapter) { mCallSequencingAdapter = adapter; } public void waitForAudioToUpdate(boolean expectActive) { Log.i(this, "waitForAudioToUpdate"); if (mFeatureFlags.useRefactoredAudioRouteSwitching()) { Loading
src/com/android/server/telecom/callsequencing/CallsManagerCallSequencingAdapter.java +50 −4 Original line number Diff line number Diff line Loading @@ -16,9 +16,6 @@ package com.android.server.telecom.callsequencing; import static com.android.server.telecom.CallsManager.CALL_FILTER_ALL; import static com.android.server.telecom.CallsManager.ONGOING_CALL_STATES; import android.content.Context; import android.os.Bundle; import android.os.Handler; Loading @@ -26,8 +23,8 @@ import android.os.OutcomeReceiver; import android.telecom.CallAttributes; import android.telecom.CallException; import android.telecom.Connection; import android.telecom.DisconnectCause; import android.telecom.Log; import android.telecom.PhoneAccountHandle; import com.android.server.telecom.Call; import com.android.server.telecom.CallAudioManager; Loading @@ -37,6 +34,9 @@ import com.android.server.telecom.callsequencing.voip.OutgoingCallTransaction; import com.android.server.telecom.flags.FeatureFlags; import com.android.server.telecom.R; import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CompletableFuture; /** Loading Loading @@ -309,6 +309,52 @@ public class CallsManagerCallSequencingAdapter { return !mIsCallSequencingEnabled || !mSequencingController.hasMmiCodeRestriction(call); } /** * Processes the simultaneous call type for the ongoing calls that are being tracked in * {@link CallsManager}. The current call's simultaneous call type will be overridden only if * it's current type priority is lower than the one being set. * @param calls The list of the currently tracked calls. */ public void processSimultaneousCallTypes(Collection<Call> calls) { // Metrics should only be tracked when call sequencing flag is enabled. if (!mIsCallSequencingEnabled) { return; } // Device should have simultaneous calling supported. boolean isSimultaneousCallingSupported = mCallsManager.isDsdaCallingPossible(); int type; // Go through the available calls' phone accounts to determine how many different ones // are being used. Set<PhoneAccountHandle> handles = new HashSet<>(); for (Call call : calls) { if (call.getTargetPhoneAccount() != null) { handles.add(call.getTargetPhoneAccount()); } // No need to proceed further given that we already know there is more than 1 phone // account being used. if (handles.size() > 1) { break; } } type = handles.size() > 1 ? (isSimultaneousCallingSupported ? Call.CALL_DIRECTION_DUAL_DIFF_ACCOUNT : Call.CALL_SIMULTANEOUS_DISABLED_DIFF_ACCOUNT) : (isSimultaneousCallingSupported ? Call.CALL_DIRECTION_DUAL_SAME_ACCOUNT : Call.CALL_SIMULTANEOUS_DISABLED_SAME_ACCOUNT); Log.i(this, "processSimultaneousCallTypes: the calculated simultaneous call type for " + "the tracked calls is [%d]", type); calls.forEach(c -> { // If the current call's simultaneous call type priority is lower than the one being // set, then let the override occur. Otherwise, ignore it. if (c.getSimultaneousType() < type) { Log.i(this, "processSimultaneousCallTypes: overriding simultaneous call type for " + "call (%s). Previous value: %d", c.getId(), c.getSimultaneousType()); c.setSimultaneousType(type); } }); } public Handler getHandler() { return mHandler; } Loading
tests/src/com/android/server/telecom/tests/CallsManagerTest.java +48 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ import com.android.server.telecom.CallEndpointControllerFactory; import com.android.server.telecom.CallState; import com.android.server.telecom.CallerInfoLookupHelper; import com.android.server.telecom.CallsManager; import com.android.server.telecom.callsequencing.CallSequencingController; import com.android.server.telecom.callsequencing.CallsManagerCallSequencingAdapter; import com.android.server.telecom.ClockProxy; import com.android.server.telecom.ConnectionServiceFocusManager; Loading Loading @@ -3777,6 +3778,53 @@ public class CallsManagerTest extends TelecomTestCase { inOrder.verify(call).setState(eq(CallState.RINGING), anyString()); } @SmallTest @Test public void testSimultaneousCallType() { when(mFeatureFlags.enableCallSequencing()).thenReturn(true); // Setup CallsManagerCallSequencingAdapter CallSequencingController sequencingController = mock(CallSequencingController.class); CallAudioManager callAudioManager = mock(CallAudioManager.class); CallsManagerCallSequencingAdapter adapter = new CallsManagerCallSequencingAdapter( mCallsManager, mContext, sequencingController, callAudioManager, mFeatureFlags); mCallsManager.setCallSequencingAdapter(adapter); // Explicitly disable simultaneous calling TelephonyManager mockTelephonyManager = mComponentContextFixture.getTelephonyManager(); when(mockTelephonyManager.getMaxNumberOfSimultaneouslyActiveSims()).thenReturn(1); Call call1 = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE); assertEquals(call1.getSimultaneousType(), Call.CALL_SIMULTANEOUS_DISABLED_SAME_ACCOUNT); // Emulate adding another concurrent call on a different call when simultaneous calling // isn't supported by the device. Call call2 = addSpyCall(SIM_2_HANDLE, CallState.ON_HOLD); assertEquals(call1.getSimultaneousType(), Call.CALL_SIMULTANEOUS_DISABLED_DIFF_ACCOUNT); assertEquals(call2.getSimultaneousType(), Call.CALL_SIMULTANEOUS_DISABLED_DIFF_ACCOUNT); mCallsManager.removeCall(call2); // Now enable simultaneous calling and verify the updated call simultaneous types when // adding another call. when(mockTelephonyManager.getMaxNumberOfSimultaneouslyActiveSims()).thenReturn(2); call2 = addSpyCall(SIM_1_HANDLE, CallState.ON_HOLD); assertEquals(call1.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_SAME_ACCOUNT); assertEquals(call2.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_SAME_ACCOUNT); // Add a new call and remove the held one (emulation). mCallsManager.removeCall(call2); // Verify that the simultaneous call type priority of the 1st call has been upgraded. Call call3 = addSpyCall(SIM_2_HANDLE, CallState.ACTIVE); assertEquals(call1.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_DIFF_ACCOUNT); assertEquals(call3.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_DIFF_ACCOUNT); // Remove the first call and add another call with the same handle as the third call. mCallsManager.removeCall(call1); Call call4 = addSpyCall(SIM_2_HANDLE, CallState.ON_HOLD); // Verify that call3's priority remains unchanged but call4's priority is // Call.CALL_DIRECTION_DUAL_SAME_ACCOUNT. assertEquals(call3.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_DIFF_ACCOUNT); assertEquals(call4.getSimultaneousType(), Call.CALL_DIRECTION_DUAL_SAME_ACCOUNT); } @SmallTest @Test public void testPendingAccountSelectionNotClearedWithNewCall() { Loading