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

Commit 302eff83 authored by Grace Jia's avatar Grace Jia
Browse files

Block normal outgoing call when there's an ongoing emergency call.

Block non-emergency call if there's an ongoing emergency call when we
try to make room for outgoing calls. This can make sure that all
non-emergency call will be blocked even if the
NewOutgoingCallIntentBroadcaster wouldn't start the call immediately.

Bug: 186868542
Test: TelecomUnitTest
Change-Id: I9d21e8f23db6b725e978904919198ff9521dd633
parent f8f1b2e7
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -1675,6 +1675,21 @@ public class CallsManager extends Call.ListenerBase
                        }
                    }

                    if (!finalCall.isEmergencyCall() && isInEmergencyCall()) {
                        Log.i(CallsManager.this, "Aborting call since there's an"
                                + " ongoing emergency call");
                        // If the ongoing call is a managed call, we will prevent the outgoing
                        // call from dialing.
                        if (isConference) {
                            notifyCreateConferenceFailed(finalCall.getTargetPhoneAccount(),
                                    finalCall);
                        } else {
                            notifyCreateConnectionFailed(
                                    finalCall.getTargetPhoneAccount(), finalCall);
                        }
                        return CompletableFuture.completedFuture(null);
                    }

                    // If we can not supportany more active calls, our options are to move a call
                    // to hold, disconnect a call, or cancel this call altogether.
                    boolean isRoomForCall = finalCall.isEmergencyCall() ?
@@ -5528,4 +5543,10 @@ public class CallsManager extends Call.ListenerBase
    public void addToPendingCallsToDisconnect(Call call) {
        mPendingCallsToDisconnect.add(call);
    }

    @VisibleForTesting
    public void addConnectionServiceRepositoryCache(ComponentName componentName,
            UserHandle userHandle, ConnectionServiceWrapper service) {
        mConnectionServiceRepository.setService(componentName, userHandle, service);
    }
}
+7 −0
Original line number Diff line number Diff line
@@ -79,6 +79,13 @@ public class ConnectionServiceRepository {
        return service;
    }

    @VisibleForTesting
    public void setService(ComponentName componentName, UserHandle userHandle,
            ConnectionServiceWrapper service) {
        Pair<ComponentName, UserHandle> cacheKey = Pair.create(componentName, userHandle);
        mServiceCache.put(cacheKey, service);
    }

    /**
     * Dumps the state of the {@link ConnectionServiceRepository}.
     *
+2 −1
Original line number Diff line number Diff line
@@ -1362,7 +1362,8 @@ public class ConnectionServiceWrapper extends ServiceBinder implements
     * create a connection has been denied or failed.
     * @param call The call.
     */
    void createConnectionFailed(final Call call) {
    @VisibleForTesting
    public void createConnectionFailed(final Call call) {
        Log.d(this, "createConnectionFailed(%s) via %s.", call, getComponentName());
        BindCallback callback = new BindCallback() {
            @Override
+45 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static junit.framework.TestCase.fail;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -36,6 +37,8 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -54,6 +57,7 @@ import android.os.UserHandle;
import android.telecom.CallerInfo;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
import android.telecom.Log;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -77,6 +81,7 @@ import com.android.server.telecom.CallsManagerListenerBase;
import com.android.server.telecom.ClockProxy;
import com.android.server.telecom.ConnectionServiceFocusManager;
import com.android.server.telecom.ConnectionServiceFocusManager.ConnectionServiceFocusManagerFactory;
import com.android.server.telecom.ConnectionServiceWrapper;
import com.android.server.telecom.DefaultDialerCache;
import com.android.server.telecom.EmergencyCallHelper;
import com.android.server.telecom.HeadsetMediaButton;
@@ -1110,6 +1115,46 @@ public class CallsManagerTest extends TelecomTestCase {
        assertFalse(mCallsManager.isInEmergencyCall());
    }


    @SmallTest
    @Test
    public void testBlockNonEmergencyCallDuringEmergencyCall() throws Exception {
        // Setup a call which the network identified as an emergency call.
        Call ongoingCall = addSpyCall();
        ongoingCall.setConnectionProperties(Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL);
        assertTrue(mCallsManager.isInEmergencyCall());

        Call newCall = addSpyCall(CallState.NEW);
        ConnectionServiceWrapper service = mock(ConnectionServiceWrapper.class);
        doReturn(SIM_2_HANDLE.getComponentName()).when(service).getComponentName();

        // Ensure contact info lookup succeeds
        doAnswer(invocation -> {
            Uri handle = invocation.getArgument(0);
            CallerInfo info = new CallerInfo();
            CompletableFuture<Pair<Uri, CallerInfo>> callerInfoFuture = new CompletableFuture<>();
            callerInfoFuture.complete(new Pair<>(handle, info));
            return callerInfoFuture;
        }).when(mCallerInfoLookupHelper).startLookup(any(Uri.class));

        // Ensure we have candidate phone account handle info.
        when(mPhoneAccountRegistrar.getOutgoingPhoneAccountForScheme(any(), any())).thenReturn(
                SIM_1_HANDLE);
        when(mPhoneAccountRegistrar.getCallCapablePhoneAccounts(any(), anyBoolean(),
                any(), anyInt(), anyInt())).thenReturn(
                new ArrayList<>(Arrays.asList(SIM_1_HANDLE, SIM_2_HANDLE)));
        mCallsManager.addConnectionServiceRepositoryCache(SIM_2_HANDLE.getComponentName(),
                SIM_2_HANDLE.getUserHandle(), service);

        CompletableFuture<Call> callFuture = mCallsManager.startOutgoingCall(
                newCall.getHandle(), newCall.getTargetPhoneAccount(), new Bundle(),
                UserHandle.CURRENT, new Intent(), "com.test.stuff");

        verify(service, timeout(TEST_TIMEOUT)).createConnectionFailed(any());
        Call result = callFuture.get(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
        assertNull(result);
    }

    @SmallTest
    @Test
    public void testHasEmergencyCallIncomingCallPermitted() {