Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af572a44 authored by Tyler Gunn's avatar Tyler Gunn
Browse files

Correct issue where quick succession calls both get canceled.

There is logic in makeRoomForOutgoingCall which is supposed to disconnect
a stuck connecting call in favor of a new outgoing call.  However, if the
user makes two outgoing calls in quick succession, both will get
disconnected (one in Telecom, one in Telephony).

We ultimately want the CallAnomalyWatchDog clean up stuck connecting
calls, but it's unfortunately not able to currently detect calls stuck
in connecting state because that includes the new outgoing call broadcast
which can take long.

For now, we'll just track how long a call has been around since it was
created and use that as a proxy for how long its stuck in connecting state.
This way we'll ONLY disconnect calls stuck for > 5 sec when making room
for an outgoing call.

The consequence is that in the case of 2 quick succession outgoing calls
we'll not allow the second one (it'll fail) but we won't cancel the first
one, so we'll at least get one call to succeed.

Fixes: 275324976
Test: Added new unit tests for this case and adjusted existing tests.
Change-Id: I9f9f72c4b72debc2d560eeea122204c4ab516cf1
parent 94990ef8
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -318,6 +318,12 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
     */
    private long mCreationTimeMillis;

    /**
     * The elapsed realtime millis when this call was created; this can be used to determine how
     * long has elapsed since the call was first created.
     */
    private long mCreationElapsedRealtimeMillis;

    /** The time this call was made active. */
    private long mConnectTimeMillis = 0;

@@ -822,6 +828,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        mClockProxy = clockProxy;
        mToastFactory = toastFactory;
        mCreationTimeMillis = mClockProxy.currentTimeMillis();
        mCreationElapsedRealtimeMillis = mClockProxy.elapsedRealtime();
        mMissedReason = MISSED_REASON_NOT_MISSED;
        mStartRingTime = 0;

@@ -2051,8 +2058,12 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
        return mCreationTimeMillis;
    }

    public void setCreationTimeMillis(long time) {
        mCreationTimeMillis = time;
    /**
     * @return The elapsed realtime millis when the call was created; ONLY useful for determining
     * how long has elapsed since the call was first created.
     */
    public long getCreationElapsedRealtimeMillis() {
        return mCreationElapsedRealtimeMillis;
    }

    public long getConnectTimeMillis() {
+12 −3
Original line number Diff line number Diff line
@@ -4881,9 +4881,18 @@ public class CallsManager extends Call.ListenerBase
            return true;
        }

        // If the live call is stuck in a connecting state, then we should disconnect it in favor
        // of the new outgoing call and prompt the user to generate a bugreport.
        if (liveCall.getState() == CallState.CONNECTING) {
        // If the live call is stuck in a connecting state for longer than the transitory timeout,
        // then we should disconnect it in favor of the new outgoing call and prompt the user to
        // generate a bugreport.
        // TODO: In the future we should let the CallAnomalyWatchDog do this disconnection of the
        // live call stuck in the connecting state.  Unfortunately that code will get tripped up by
        // calls that have a longer than expected new outgoing call broadcast response time.  This
        // mitigation is intended to catch calls stuck in a CONNECTING state for a long time that
        // block outgoing calls.  However, if the user dials two calls in quick succession it will
        // result in both calls getting disconnected, which is not optimal.
        if (liveCall.getState() == CallState.CONNECTING
                && ((mClockProxy.elapsedRealtime() - liveCall.getCreationElapsedRealtimeMillis())
                > mTimeoutsAdapter.getNonVoipCallTransitoryStateTimeoutMillis())) {
            mAnomalyReporter.reportAnomaly(LIVE_CALL_STUCK_CONNECTING_ERROR_UUID,
                    LIVE_CALL_STUCK_CONNECTING_ERROR_MSG);
            liveCall.disconnect("Force disconnect CONNECTING call.");
+28 −1
Original line number Diff line number Diff line
@@ -149,6 +149,7 @@ import java.util.concurrent.TimeUnit;
@RunWith(JUnit4.class)
public class CallsManagerTest extends TelecomTestCase {
    private static final int TEST_TIMEOUT = 5000;  // milliseconds
    private static final long STATE_TIMEOUT = 5000L;
    private static final int SECONDARY_USER_ID = 12;
    private static final PhoneAccountHandle SIM_1_HANDLE = new PhoneAccountHandle(
            ComponentName.unflattenFromString("com.foo/.Blah"), "Sim1");
@@ -275,6 +276,9 @@ public class CallsManagerTest extends TelecomTestCase {
                .thenReturn(mDisconnectedCallNotifier);
        when(mTimeoutsAdapter.getCallDiagnosticServiceTimeoutMillis(any(ContentResolver.class)))
                .thenReturn(2000L);
        when(mTimeoutsAdapter.getNonVoipCallTransitoryStateTimeoutMillis())
                .thenReturn(STATE_TIMEOUT);
        when(mClockProxy.elapsedRealtime()).thenReturn(0L);
        mCallsManager = new CallsManager(
                mComponentContextFixture.getTestDouble().getApplicationContext(),
                mLock,
@@ -1563,6 +1567,8 @@ public class CallsManagerTest extends TelecomTestCase {
                .thenReturn(false);
        newCall.setHandle(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);

        // Make sure enough time has passed that we'd drop the connecting call.
        when(mClockProxy.elapsedRealtime()).thenReturn(STATE_TIMEOUT + 10L);
        assertTrue(mCallsManager.makeRoomForOutgoingCall(newCall));
        verify(mAnomalyReporterAdapter).reportAnomaly(
                CallsManager.LIVE_CALL_STUCK_CONNECTING_ERROR_UUID,
@@ -1570,6 +1576,26 @@ public class CallsManagerTest extends TelecomTestCase {
        verify(ongoingCall).disconnect(anyLong(), anyString());
    }

    /**
     * Verifies that we won't auto-disconnect an outgoing CONNECTING call unless it has timed out.
     */
    @SmallTest
    @Test
    public void testDontDisconnectConnectingCallWhenNotTimedOut() {
        mCallsManager.setAnomalyReporterAdapter(mAnomalyReporterAdapter);
        Call ongoingCall = addSpyCall(SIM_2_HANDLE, CallState.CONNECTING);

        Call newCall = createCall(SIM_1_HANDLE, CallState.NEW);
        when(mComponentContextFixture.getTelephonyManager().isEmergencyNumber(any()))
                .thenReturn(false);
        newCall.setHandle(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);

        // Make sure it has been a short time so we don't try to disconnect the call
        when(mClockProxy.elapsedRealtime()).thenReturn(STATE_TIMEOUT / 2);
        assertFalse(mCallsManager.makeRoomForOutgoingCall(newCall));
        verify(ongoingCall, never()).disconnect(anyLong(), anyString());
    }

    @SmallTest
    @Test
    public void testMakeRoomForEmergencyCallHasOutgoingCall() {
@@ -1643,6 +1669,7 @@ public class CallsManagerTest extends TelecomTestCase {
        Call ongoingCall = addSpyCall(SIM_2_HANDLE, CallState.CONNECTING);
        Call newCall = createCall(SIM_1_HANDLE, CallState.NEW);

        when(mClockProxy.elapsedRealtime()).thenReturn(STATE_TIMEOUT + 10L);
        assertTrue(mCallsManager.makeRoomForOutgoingCall(newCall));
        verify(ongoingCall).disconnect(anyLong(), anyString());
    }
@@ -1652,7 +1679,7 @@ public class CallsManagerTest extends TelecomTestCase {
    public void testMakeRoomForOutgoingCallForSameCall() {
        addSpyCall(SIM_2_HANDLE, CallState.CONNECTING);
        Call ongoingCall2 = addSpyCall();

        when(mClockProxy.elapsedRealtime()).thenReturn(STATE_TIMEOUT + 10L);
        assertTrue(mCallsManager.makeRoomForOutgoingCall(ongoingCall2));
    }