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

Commit 3da4132c authored by Tyler Gunn's avatar Tyler Gunn
Browse files

Implement extra key filtering for non-system dialers.

Add ability to filter some extra keys from calls which are destined for
a dialer other than the OEM/system dialer.

Test: Added unit tests.
Bug: 124232210
Change-Id: I8055d1428a31ff03c96221d1d65adfcc305f23c3
parent d52fc29e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2065,7 +2065,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
     * @param source The source of the extras addition.
     * @param extras The extras.
     */
    void putExtras(int source, Bundle extras) {
    public void putExtras(int source, Bundle extras) {
        if (extras == null) {
            return;
        }
+19 −13
Original line number Diff line number Diff line
@@ -797,7 +797,8 @@ public class InCallController extends CallsManagerListenerBase {

                ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
                        true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
                        info.isExternalCallsSupported(), includeRttCall);
                        info.isExternalCallsSupported(), includeRttCall,
                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
                try {
                    inCallService.addCall(parcelableCall);
                } catch (RemoteException ignored) {
@@ -861,7 +862,8 @@ public class InCallController extends CallsManagerListenerBase {

                ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
                        true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
                        info.isExternalCallsSupported(), includeRttCall);
                        info.isExternalCallsSupported(), includeRttCall,
                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
                try {
                    inCallService.addCall(parcelableCall);
                } catch (RemoteException ignored) {
@@ -872,15 +874,7 @@ public class InCallController extends CallsManagerListenerBase {
            // The call was regular but it is now external.  We must now remove it from any
            // InCallServices which do not support external calls.
            // Remove the call by sending a call update indicating the call was disconnected.
            ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(
                    call,
                    false /* includeVideoProvider */,
                    mCallsManager.getPhoneAccountRegistrar(),
                    false /* supportsExternalCalls */,
                    android.telecom.Call.STATE_DISCONNECTED /* overrideState */,
                    false /* includeRttCall */);

            Log.i(this, "Removing external call %s ==> %s", call, parcelableCall);
            Log.i(this, "Removing external call %", call);
            for (Map.Entry<InCallServiceInfo, IInCallService> entry : mInCallServices.entrySet()) {
                InCallServiceInfo info = entry.getKey();
                if (info.isExternalCallsSupported()) {
@@ -892,6 +886,16 @@ public class InCallController extends CallsManagerListenerBase {
                componentsUpdated.add(info.getComponentName());
                IInCallService inCallService = entry.getValue();

                ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(
                        call,
                        false /* includeVideoProvider */,
                        mCallsManager.getPhoneAccountRegistrar(),
                        false /* supportsExternalCalls */,
                        android.telecom.Call.STATE_DISCONNECTED /* overrideState */,
                        false /* includeRttCall */,
                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI
                        );

                try {
                    inCallService.updateCall(parcelableCall);
                } catch (RemoteException ignored) {
@@ -1360,7 +1364,8 @@ public class InCallController extends CallsManagerListenerBase {
                        true /* includeVideoProvider */,
                        mCallsManager.getPhoneAccountRegistrar(),
                        info.isExternalCallsSupported(),
                        includeRttCall));
                        includeRttCall,
                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI));
            } catch (RemoteException ignored) {
            }
        }
@@ -1422,7 +1427,8 @@ public class InCallController extends CallsManagerListenerBase {
                        videoProviderChanged /* includeVideoProvider */,
                        mCallsManager.getPhoneAccountRegistrar(),
                        info.isExternalCallsSupported(),
                        rttInfoChanged && info.equals(mInCallServiceConnection.getInfo()));
                        rttInfoChanged && info.equals(mInCallServiceConnection.getInfo()),
                        info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI);
                ComponentName componentName = info.getComponentName();
                IInCallService inCallService = entry.getValue();
                componentsUpdated.add(componentName);
+65 −5
Original line number Diff line number Diff line
@@ -21,14 +21,17 @@ import static android.telecom.Call.Details.DIRECTION_OUTGOING;
import static android.telecom.Call.Details.DIRECTION_UNKNOWN;

import android.net.Uri;
import android.os.Bundle;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
import android.telecom.ParcelableCall;
import android.telecom.ParcelableRttCall;
import android.telecom.TelecomManager;
import android.text.TextUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
@@ -37,11 +40,23 @@ import java.util.List;
public class ParcelableCallUtils {
    private static final int CALL_STATE_OVERRIDE_NONE = -1;

    /**
     * A list of extra keys which should be removed from a {@link ParcelableCall} when it is being
     * generated for the purpose of sending to a dialer other than the system dialer.
     * By convention we only pass keys namespaced with android.*, however there are some keys which
     * should not be passed to non-system dialer apps either.
     */
    private static List<String> EXTRA_KEYS_TO_SANITIZE;
    static {
        EXTRA_KEYS_TO_SANITIZE = new ArrayList<>();
        EXTRA_KEYS_TO_SANITIZE.add(android.telecom.Connection.EXTRA_SIP_INVITE);
    }

    public static class Converter {
        public ParcelableCall toParcelableCall(Call call, boolean includeVideoProvider,
                PhoneAccountRegistrar phoneAccountRegistrar) {
            return ParcelableCallUtils.toParcelableCall(
                    call, includeVideoProvider, phoneAccountRegistrar, false, false);
                    call, includeVideoProvider, phoneAccountRegistrar, false, false, false);
        }

        public ParcelableCall toParcelableCallForScreening(Call call) {
@@ -60,16 +75,23 @@ public class ParcelableCallUtils {
     * @param phoneAccountRegistrar The {@link PhoneAccountRegistrar}.
     * @param supportsExternalCalls Indicates whether the call should be parcelled for an
     *      {@link InCallService} which supports external calls or not.
     * @param includeRttCall {@code true} if the RTT call should be included, {@code false}
     *      otherwise.
     * @param isForSystemDialer {@code true} if this call is being parcelled for the system dialer,
     *      {@code false} otherwise.  When parceling for the system dialer, the entire call extras
     *      is included.  When parceling for anything other than the system dialer, some extra key
     *      values will be stripped for privacy sake.
     */
    public static ParcelableCall toParcelableCall(
            Call call,
            boolean includeVideoProvider,
            PhoneAccountRegistrar phoneAccountRegistrar,
            boolean supportsExternalCalls,
            boolean includeRttCall) {
            boolean includeRttCall,
            boolean isForSystemDialer) {
        return toParcelableCall(call, includeVideoProvider, phoneAccountRegistrar,
                supportsExternalCalls, CALL_STATE_OVERRIDE_NONE /* overrideState */,
                includeRttCall);
                includeRttCall, isForSystemDialer);
    }

    /**
@@ -85,6 +107,10 @@ public class ParcelableCallUtils {
     *      {@link InCallService} which supports external calls or not.
     * @param overrideState When not {@link #CALL_STATE_OVERRIDE_NONE}, use the provided state as an
     *      override to whatever is defined in the call.
     * @param isForSystemDialer {@code true} if this call is being parcelled for the system dialer,
     *      {@code false} otherwise.  When parceling for the system dialer, the entire call extras
     *      is included.  When parceling for anything other than the system dialer, some extra key
     *      values will be stripped for privacy sake.
     * @return The {@link ParcelableCall} containing all call information from the {@link Call}.
     */
    public static ParcelableCall toParcelableCall(
@@ -93,7 +119,8 @@ public class ParcelableCallUtils {
            PhoneAccountRegistrar phoneAccountRegistrar,
            boolean supportsExternalCalls,
            int overrideState,
            boolean includeRttCall) {
            boolean includeRttCall,
            boolean isForSystemDialer) {
        int state;
        if (overrideState == CALL_STATE_OVERRIDE_NONE) {
            state = getParcelableState(call, supportsExternalCalls);
@@ -180,6 +207,13 @@ public class ParcelableCallUtils {
            callDirection = DIRECTION_OUTGOING;
        }

        Bundle extras;
        if (isForSystemDialer) {
            extras = call.getExtras();
        } else {
            extras = sanitizeExtras(call.getExtras());
        }

        return new ParcelableCall(
                call.getId(),
                state,
@@ -205,7 +239,7 @@ public class ParcelableCallUtils {
                call.getVideoState(),
                conferenceableCallIds,
                call.getIntentExtras(),
                call.getExtras(),
                extras,
                call.getCreationTimeMillis(),
                call.getCallIdentification(),
                callDirection);
@@ -268,6 +302,32 @@ public class ParcelableCallUtils {
                callDirection);
    }

    /**
     * Sanitize the extras bundle passed in, removing keys which should not be sent to non-system
     * dialer apps.
     * @param extras Extras bundle to sanitize.
     * @return The sanitized extras bundle.
     */
    private static Bundle sanitizeExtras(Bundle oldExtras) {
        if (oldExtras == null) {
            return new Bundle();
        }
        Bundle extras = new Bundle(oldExtras);
        for (String key : EXTRA_KEYS_TO_SANITIZE) {
            extras.remove(key);
        }

        // As a catch-all remove any that don't start with android namespace.
        Iterator<String> toCheck = extras.keySet().iterator();
        while (toCheck.hasNext()) {
            String extraKey = toCheck.next();
            if (TextUtils.isEmpty(extraKey) || !extraKey.startsWith("android.")) {
                toCheck.remove();
            }
        }
        return extras;
    }

    private static int getParcelableState(Call call, boolean supportsExternalCalls) {
        int state = CallState.NEW;
        switch (call.getState()) {
+122 −0
Original line number Diff line number Diff line
package com.android.server.telecom.tests;

import static com.android.server.telecom.TelecomSystem.*;

import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;

import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
import android.telecom.Connection;
import android.telecom.GatewayInfo;
import android.telecom.ParcelableCall;
import android.telecom.PhoneAccountHandle;
import android.test.suitebuilder.annotation.SmallTest;

import com.android.server.telecom.Call;
import com.android.server.telecom.CallerInfoLookupHelper;
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.ClockProxy;
import com.android.server.telecom.ConnectionServiceRepository;
import com.android.server.telecom.ParcelableCallUtils;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.PhoneNumberUtilsAdapter;
import com.android.server.telecom.TelecomSystem;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@RunWith(JUnit4.class)
public class ParcelableCallUtilsTest extends TelecomTestCase {

    private SyncRoot mLock = new SyncRoot() {};
    @Mock private ClockProxy mClockProxy;
    @Mock private CallsManager mCallsManager;
    @Mock private CallerInfoLookupHelper mCallerInfoLookupHelper;
    @Mock private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter;
    @Mock private PhoneAccountRegistrar mPhoneAccountRegistrar;
    private Call mCall;

    @Override
    @Before
    public void setUp() throws Exception {
        super.setUp();
        MockitoAnnotations.initMocks(this);
        when(mClockProxy.currentTimeMillis()).thenReturn(System.currentTimeMillis());
        when(mClockProxy.elapsedRealtime()).thenReturn(SystemClock.elapsedRealtime());
        when(mCallsManager.getCallerInfoLookupHelper()).thenReturn(mCallerInfoLookupHelper);
        when(mCallsManager.getPhoneAccountRegistrar()).thenReturn(mPhoneAccountRegistrar);
        when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(any())).thenReturn(null);
        when(mPhoneNumberUtilsAdapter.isLocalEmergencyNumber(any(), any())).thenReturn(false);
        mCall = new Call("1",
                null /* context */,
                mCallsManager,
                mLock,
                null /* ConnectionServiceRepository */,
                mPhoneNumberUtilsAdapter,
                Uri.fromParts("tel", "6505551212", null),
                null /* GatewayInfo */,
                null /* connectionMgr */,
                new PhoneAccountHandle(
                        ComponentName.unflattenFromString("com.test/Class"), "test"),
                Call.CALL_DIRECTION_INCOMING,
                false /* shouldAttachToExistingConnection */,
                false /* isConference */,
                mClockProxy /* ClockProxy */);
    }

    @SmallTest
    @Test
    public void testParcelForNonSystemDialer() {
        mCall.putExtras(Call.SOURCE_CONNECTION_SERVICE, getSomeExtras());
        ParcelableCall call = ParcelableCallUtils.toParcelableCall(mCall,
                false /* includevideoProvider */,
                null /* phoneAccountRegistrar */,
                false /* supportsExternalCalls */,
                false /* includeRttCall */,
                false /* isForSystemDialer */);

        Bundle parceledExtras = call.getExtras();
        assertFalse(parceledExtras.containsKey(Connection.EXTRA_SIP_INVITE));
        assertFalse(parceledExtras.containsKey("SomeExtra"));
        assertTrue(parceledExtras.containsKey(Connection.EXTRA_CALL_SUBJECT));
    }

    @SmallTest
    @Test
    public void testParcelForSystemDialer() {
        mCall.putExtras(Call.SOURCE_CONNECTION_SERVICE, getSomeExtras());
        ParcelableCall call = ParcelableCallUtils.toParcelableCall(mCall,
                false /* includevideoProvider */,
                null /* phoneAccountRegistrar */,
                false /* supportsExternalCalls */,
                false /* includeRttCall */,
                true /* isForSystemDialer */);

        Bundle parceledExtras = call.getExtras();
        assertTrue(parceledExtras.containsKey(Connection.EXTRA_SIP_INVITE));
        assertTrue(parceledExtras.containsKey("SomeExtra"));
        assertTrue(parceledExtras.containsKey(Connection.EXTRA_CALL_SUBJECT));
    }

    private Bundle getSomeExtras() {
        Bundle extras = new Bundle();
        extras.putString(Connection.EXTRA_SIP_INVITE, "scary data");
        extras.putString("SomeExtra", "Extra Extra");
        extras.putString(Connection.EXTRA_CALL_SUBJECT, "Blah");
        return extras;
    }
}