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
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 514e5f3..e110be8 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -2065,7 +2065,7 @@
* @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;
}
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 142cf3a..7d4ee13 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -797,7 +797,8 @@
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 @@
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 @@
// 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 @@
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 @@
true /* includeVideoProvider */,
mCallsManager.getPhoneAccountRegistrar(),
info.isExternalCallsSupported(),
- includeRttCall));
+ includeRttCall,
+ info.getType() == IN_CALL_SERVICE_TYPE_SYSTEM_UI));
} catch (RemoteException ignored) {
}
}
@@ -1422,7 +1427,8 @@
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);
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index 8dab6a6..3e3ce3d 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -21,14 +21,17 @@
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 @@
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 @@
* @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 @@
* {@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 @@
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 @@
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 @@
call.getVideoState(),
conferenceableCallIds,
call.getIntentExtras(),
- call.getExtras(),
+ extras,
call.getCreationTimeMillis(),
call.getCallIdentification(),
callDirection);
@@ -268,6 +302,32 @@
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()) {
diff --git a/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java b/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
new file mode 100644
index 0000000..753b635
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/ParcelableCallUtilsTest.java
@@ -0,0 +1,122 @@
+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;
+ }
+}