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

Commit 2cc89e4a authored by Tyler Gunn's avatar Tyler Gunn
Browse files

Ensure calls are not unheld between apps automatically.

When locally disconnecting a call, we have the behavior of automatically
unholding the held background call.  This was originally intended for use
with PSTN calls.  However, when using different apps it makes for a bad
user experience if a call terminated in the dialer auto-unholds a call in
a VOIP app, for example.

As part of this refactored the performRemoval code into a new method in
CAllsManager.  The use of a future made it hard to test this in unit tests.
The only delta is the addition of "areFromSameSource" in the auto-unhold
code.

Test: Manual using test app.
Test: Add new unit test to verify auto-unhold on local disconnect in same app
Test: Add new unit test to verify no auto-unhold on local disconnect in different app
Fixes: 253311155
Change-Id: I4eed793d57a16af64040aaa39c9f68884273858c
parent 7b6c9ba0
Loading
Loading
Loading
Loading
+49 −32
Original line number Diff line number Diff line
@@ -3648,7 +3648,27 @@ public class CallsManager extends Call.ListenerBase
     * @param call The call.
     */
    private void performRemoval(Call call) {
        if (mInCallController.getBindingFuture() != null) {
            mInCallController.getBindingFuture().thenRunAsync(() -> {
                        doRemoval(call);
                    }, new LoggedHandlerExecutor(mHandler, "CM.pR", mLock))
                    .exceptionally((throwable) -> {
                        Log.e(TAG, throwable, "Error while executing call removal");
                        mAnomalyReporter.reportAnomaly(CALL_REMOVAL_EXECUTION_ERROR_UUID,
                                CALL_REMOVAL_EXECUTION_ERROR_MSG);
                        return null;
                    });
        } else {
            doRemoval(call);
        }
    }

    /**
     * Code to perform removal of a call.  Called above from {@link #performRemoval(Call)} either
     * async (in live code) or sync (in testing).
     * @param call the call to remove.
     */
    private void doRemoval(Call call) {
        call.maybeCleanupHandover();
        removeCall(call);
        Call foregroundCall = mCallAudioManager.getPossiblyHeldForegroundCall();
@@ -3660,8 +3680,12 @@ public class CallsManager extends Call.ListenerBase
            // Auto-unhold the foreground call due to a locally disconnected call, except if the
            // call which was disconnected is a member of a conference (don't want to auto
            // un-hold the conference if we remove a member of the conference).
            // Also, ensure that the call we're removing is from the same ConnectionService as
            // the one we're removing.  We don't want to auto-unhold between ConnectionService
            // implementations, especially if one is managed and the other is a VoIP CS.
            if (!isDisconnectingChildCall && foregroundCall != null
                        && foregroundCall.getState() == CallState.ON_HOLD) {
                    && foregroundCall.getState() == CallState.ON_HOLD
                    && areFromSameSource(foregroundCall, call)) {
                foregroundCall.unhold();
            }
        } else if (foregroundCall != null &&
@@ -3675,13 +3699,6 @@ public class CallsManager extends Call.ListenerBase
                    + "support hold)");
            foregroundCall.unhold();
        }
        }, new LoggedHandlerExecutor(mHandler, "CM.pR", mLock))
                .exceptionally((throwable) -> {
                    Log.e(TAG, throwable, "Error while executing call removal");
                    mAnomalyReporter.reportAnomaly(CALL_REMOVAL_EXECUTION_ERROR_UUID,
                            CALL_REMOVAL_EXECUTION_ERROR_MSG);
                    return null;
                });
    }

    /**
+48 −0
Original line number Diff line number Diff line
@@ -688,6 +688,54 @@ public class CallsManagerTest extends TelecomTestCase {
        verify(heldCall).unhold(any());
    }

    /**
     * Ensures we don't auto-unhold a call from a different app when we locally disconnect a call.
     */
    @SmallTest
    @Test
    public void testDontUnholdCallsBetweenConnectionServices() {
        // GIVEN a CallsManager with ongoing call
        Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
        when(ongoingCall.isDisconnectHandledViaFuture()).thenReturn(false);
        doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
        doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
        when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);

        // and a held call which has different ConnectionService
        Call heldCall = addSpyCall(VOIP_1_HANDLE, CallState.ON_HOLD);

        // Disconnect and cleanup the active ongoing call.
        mCallsManager.disconnectCall(ongoingCall);
        mCallsManager.markCallAsRemoved(ongoingCall);

        // Should not unhold the held call since its in another app.
        verify(heldCall, never()).unhold();
    }

    /**
     * Ensures we do auto-unhold a call from the same app when we locally disconnect a call.
     */
    @SmallTest
    @Test
    public void testUnholdCallWhenDisconnectingInSameApp() {
        // GIVEN a CallsManager with ongoing call
        Call ongoingCall = addSpyCall(SIM_1_HANDLE, CallState.ACTIVE);
        when(ongoingCall.isDisconnectHandledViaFuture()).thenReturn(false);
        doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
        doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
        when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);

        // and a held call which has same ConnectionService
        Call heldCall = addSpyCall(SIM_1_HANDLE, CallState.ON_HOLD);

        // Disconnect and cleanup the active ongoing call.
        mCallsManager.disconnectCall(ongoingCall);
        mCallsManager.markCallAsRemoved(ongoingCall);

        // Should auto-unhold the held call since its in the same app.
        verify(heldCall).unhold();
    }

    @SmallTest
    @Test
    public void testUnholdCallWhenOngoingEmergCallCanNotBeHeldAndFromDifferentConnectionService() {