Merge "Use carrier config to determine which D2D transports are initialized." into sc-dev
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 7000733..44fc531 100755
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -73,6 +73,7 @@
import com.android.internal.telephony.d2d.RtpAdapter;
import com.android.internal.telephony.d2d.RtpTransport;
import com.android.internal.telephony.d2d.Timeouts;
+import com.android.internal.telephony.d2d.TransportProtocol;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
@@ -3325,53 +3326,57 @@
return;
}
- // Implement abstracted out RTP functionality the RTP transport depends on.
- RtpAdapter rtpAdapter = new RtpAdapter() {
- @Override
- public Set<RtpHeaderExtensionType> getAcceptedRtpHeaderExtensions() {
- if (!isImsConnection()) {
- return Collections.EMPTY_SET;
- }
- ImsPhoneConnection originalConnection =
- (ImsPhoneConnection) mOriginalConnection;
- return originalConnection.getAcceptedRtpHeaderExtensions();
- }
+ ArrayList<TransportProtocol> supportedTransports = new ArrayList<>(2);
- @Override
- public void sendRtpHeaderExtensions(
- @NonNull Set<RtpHeaderExtension> rtpHeaderExtensions) {
- if (!isImsConnection()) {
- Log.w(TelephonyConnection.this, "sendRtpHeaderExtensions: not an ims conn.");
+ if (supportsD2DUsingRtp()) {
+ Log.i(this, "maybeConfigureDeviceToDeviceCommunication: carrier supports RTP.");
+ // Implement abstracted out RTP functionality the RTP transport depends on.
+ RtpAdapter rtpAdapter = new RtpAdapter() {
+ @Override
+ public Set<RtpHeaderExtensionType> getAcceptedRtpHeaderExtensions() {
+ ImsPhoneConnection originalConnection =
+ (ImsPhoneConnection) mOriginalConnection;
+ return originalConnection.getAcceptedRtpHeaderExtensions();
}
- Log.i(TelephonyConnection.this, "sendRtpHeaderExtensions: sending: %s",
- rtpHeaderExtensions.stream()
- .map(r -> r.toString())
- .collect(Collectors.joining(",")));
+ @Override
+ public void sendRtpHeaderExtensions(
+ @NonNull Set<RtpHeaderExtension> rtpHeaderExtensions) {
+ Log.i(TelephonyConnection.this, "sendRtpHeaderExtensions: sending: %s",
+ rtpHeaderExtensions.stream()
+ .map(r -> r.toString())
+ .collect(Collectors.joining(",")));
+ ImsPhoneConnection originalConnection =
+ (ImsPhoneConnection) mOriginalConnection;
+ originalConnection.sendRtpHeaderExtensions(rtpHeaderExtensions);
+ }
+ };
+ mRtpTransport = new RtpTransport(rtpAdapter, null /* TODO: not needed yet */, mHandler,
+ supportsSdpNegotiationOfRtpHeaderExtensions());
+ supportedTransports.add(mRtpTransport);
+ }
+ if (supportsD2DUsingDtmf()) {
+ Log.i(this, "maybeConfigureDeviceToDeviceCommunication: carrier supports DTMF.");
+ DtmfAdapter dtmfAdapter = digit -> {
+ Log.i(TelephonyConnection.this, "sendDtmf: send digit %c", digit);
ImsPhoneConnection originalConnection =
(ImsPhoneConnection) mOriginalConnection;
- originalConnection.sendRtpHeaderExtensions(rtpHeaderExtensions);
- }
- };
- mRtpTransport = new RtpTransport(rtpAdapter, null /* TODO: not needed yet */, mHandler);
-
- DtmfAdapter dtmfAdapter = digit -> {
- if (!isImsConnection()) {
- Log.w(TelephonyConnection.this, "sendDtmf: not an ims conn.");
- }
- Log.i(TelephonyConnection.this, "sendDtmf: send digit %c", digit);
- ImsPhoneConnection originalConnection =
- (ImsPhoneConnection) mOriginalConnection;
- Message dtmfComplete = mHandler.obtainMessage(MSG_DTMF_DONE);
- dtmfComplete.replyTo = mHandlerMessenger;
- originalConnection.getImsCall().sendDtmf(digit, dtmfComplete);
- };
- ContentResolver cr = getPhone().getContext().getContentResolver();
- mDtmfTransport = new DtmfTransport(dtmfAdapter, new Timeouts.Adapter(cr),
- Executors.newSingleThreadScheduledExecutor());
- mCommunicator = new Communicator(List.of(mRtpTransport, mDtmfTransport), this);
- mD2DCallStateAdapter = new D2DCallStateAdapter(mCommunicator);
- addTelephonyConnectionListener(mD2DCallStateAdapter);
+ Message dtmfComplete = mHandler.obtainMessage(MSG_DTMF_DONE);
+ dtmfComplete.replyTo = mHandlerMessenger;
+ originalConnection.getImsCall().sendDtmf(digit, dtmfComplete);
+ };
+ ContentResolver cr = getPhone().getContext().getContentResolver();
+ mDtmfTransport = new DtmfTransport(dtmfAdapter, new Timeouts.Adapter(cr),
+ Executors.newSingleThreadScheduledExecutor());
+ supportedTransports.add(mDtmfTransport);
+ }
+ if (supportedTransports.size() > 0) {
+ mCommunicator = new Communicator(supportedTransports, this);
+ mD2DCallStateAdapter = new D2DCallStateAdapter(mCommunicator);
+ addTelephonyConnectionListener(mD2DCallStateAdapter);
+ } else {
+ Log.i(this, "maybeConfigureDeviceToDeviceCommunication: no transports; disabled.");
+ }
}
/**
@@ -3575,4 +3580,34 @@
public TelecomAccountRegistry getTelecomAccountRegistry(Context context) {
return TelecomAccountRegistry.getInstance(context);
}
+
+ /**
+ * @return {@code true} if the carrier supports D2D using RTP header extensions, {@code false}
+ * otherwise.
+ */
+ private boolean supportsD2DUsingRtp() {
+ PersistableBundle b = getCarrierConfig();
+ return b != null && b.getBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL);
+ }
+
+ /**
+ * @return {@code true} if the carrier supports D2D using DTMF digits, {@code false} otherwise.
+ */
+ private boolean supportsD2DUsingDtmf() {
+ PersistableBundle b = getCarrierConfig();
+ return b != null && b.getBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL);
+ }
+
+ /**
+ * @return {@code true} if the carrier supports using SDP negotiation for the RTP header
+ * extensions used in D2D comms, {@code false} otherwise.
+ */
+ private boolean supportsSdpNegotiationOfRtpHeaderExtensions() {
+ PersistableBundle b = getCarrierConfig();
+ return b != null && b.getBoolean(
+ CarrierConfigManager
+ .KEY_SUPPORTS_SDP_NEGOTIATION_OF_D2D_RTP_HEADER_EXTENSIONS_BOOL);
+ }
}
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
index 94c9063..c55dee7 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionTest.java
@@ -1,20 +1,156 @@
package com.android.services.telephony;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static junit.framework.TestCase.assertFalse;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
import android.os.Bundle;
import android.telecom.Connection;
+import android.telephony.CarrierConfigManager;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.d2d.DtmfTransport;
+import com.android.internal.telephony.d2d.RtpTransport;
+import com.android.internal.telephony.imsphone.ImsPhoneConnection;
+import com.android.phone.R;
+
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class TelephonyConnectionTest {
+ @Mock
+ private ImsPhoneConnection mImsPhoneConnection;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mImsPhoneConnection.getState()).thenReturn(Call.State.ACTIVE);
+ when(mImsPhoneConnection.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_IMS);
+ }
+
+ /**
+ * Ensures an Ims connection uses the D2D communicator when it is enabled.
+ */
+ @Test
+ public void testSetupCommunicator() {
+ TestTelephonyConnection c = new TestTelephonyConnection();
+ c.setIsImsConnection(true);
+ // Enable D2D comms.
+ when(c.mMockResources.getBoolean(eq(
+ R.bool.config_use_device_to_device_communication))).thenReturn(true);
+ c.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL,
+ true);
+
+ c.setOriginalConnection(mImsPhoneConnection);
+ assertNotNull(c.getCommunicator());
+ }
+
+ /**
+ * Ensures an Ims connection does not use the D2D communicator when it is disabled.
+ */
+ @Test
+ public void testDoNotSetupCommunicatorWhenDisabled() {
+ TestTelephonyConnection c = new TestTelephonyConnection();
+ c.setIsImsConnection(true);
+ // Disable D2D comms.
+ when(c.mMockResources.getBoolean(eq(
+ R.bool.config_use_device_to_device_communication))).thenReturn(false);
+
+ c.setOriginalConnection(mImsPhoneConnection);
+ assertNull(c.getCommunicator());
+ }
+
+ /**
+ * Ensures an Ims connection does not use the D2D communicator for a non-IMS call.
+ */
+ @Test
+ public void testDoNotSetupCommunicatorForNonIms() {
+ TestTelephonyConnection c = new TestTelephonyConnection();
+ c.setIsImsConnection(false);
+ // Disable D2D comms.
+ when(c.mMockResources.getBoolean(eq(
+ R.bool.config_use_device_to_device_communication))).thenReturn(true);
+
+ c.setOriginalConnection(mImsPhoneConnection);
+ assertNull(c.getCommunicator());
+ }
+
+ /**
+ * Ensures an Ims connection does not use the D2D communicator when it is disabled.
+ */
+ @Test
+ public void testDoNotSetupCommunicatorNoTransports() {
+ TestTelephonyConnection c = new TestTelephonyConnection();
+ c.setIsImsConnection(true);
+ // Enable D2D comms.
+ when(c.mMockResources.getBoolean(eq(
+ R.bool.config_use_device_to_device_communication))).thenReturn(true);
+ // But carrier disables transports. Womp.
+ c.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL,
+ false);
+ c.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL,
+ false);
+ c.setOriginalConnection(mImsPhoneConnection);
+ assertNull(c.getCommunicator());
+ }
+
+ @Test
+ public void testSetupRtpOnly() {
+ TestTelephonyConnection c = new TestTelephonyConnection();
+ c.setIsImsConnection(true);
+ // Enable D2D comms.
+ when(c.mMockResources.getBoolean(eq(
+ R.bool.config_use_device_to_device_communication))).thenReturn(true);
+ // But carrier disables transports. Womp.
+ c.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL,
+ false);
+ c.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL,
+ true);
+ c.setOriginalConnection(mImsPhoneConnection);
+ assertNotNull(c.getCommunicator());
+ assertEquals(1, c.getCommunicator().getTransportProtocols().size());
+ assertTrue(c.getCommunicator().getTransportProtocols()
+ .stream().anyMatch(p -> p instanceof RtpTransport));
+ }
+
+ @Test
+ public void testSetupDtmfOnly() {
+ TestTelephonyConnection c = new TestTelephonyConnection();
+ c.setIsImsConnection(true);
+ // Enable D2D comms.
+ when(c.mMockResources.getBoolean(eq(
+ R.bool.config_use_device_to_device_communication))).thenReturn(true);
+ // But carrier disables transports. Womp.
+ c.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_DTMF_BOOL,
+ true);
+ c.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL,
+ false);
+ c.setOriginalConnection(mImsPhoneConnection);
+ assertNotNull(c.getCommunicator());
+ assertEquals(1, c.getCommunicator().getTransportProtocols().size());
+ assertTrue(c.getCommunicator().getTransportProtocols()
+ .stream().anyMatch(p -> p instanceof DtmfTransport));
+ }
@Test
public void testCodecInIms() {
diff --git a/tests/src/com/android/services/telephony/TestTelephonyConnection.java b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
index 596393c..940d8bb 100644
--- a/tests/src/com/android/services/telephony/TestTelephonyConnection.java
+++ b/tests/src/com/android/services/telephony/TestTelephonyConnection.java
@@ -16,6 +16,8 @@
package com.android.services.telephony;
+import android.content.ContentResolver;
+import android.os.UserHandle;
import android.telephony.TelephonyManager;
import static org.mockito.ArgumentMatchers.any;
@@ -66,6 +68,9 @@
Context mMockContext;
@Mock
+ ContentResolver mMockContentResolver;
+
+ @Mock
Resources mMockResources;
@Mock
@@ -97,6 +102,7 @@
private List<String> mLastConnectionEvents = new ArrayList<>();
private List<Bundle> mLastConnectionEventExtras = new ArrayList<>();
private Object mLock = new Object();
+ private PersistableBundle mCarrierConfig = new PersistableBundle();
@Override
public com.android.internal.telephony.Connection getOriginalConnection() {
@@ -143,8 +149,10 @@
when(mMockPhone.getContext()).thenReturn(mMockContext);
when(mMockPhone.getCurrentSubscriberUris()).thenReturn(null);
when(mMockContext.getResources()).thenReturn(mMockResources);
+ when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
when(mMockContext.getSystemService(Context.TELEPHONY_SERVICE))
.thenReturn(mMockTelephonyManager);
+ when(mMockContentResolver.getUserId()).thenReturn(UserHandle.USER_CURRENT);
when(mMockResources.getBoolean(anyInt())).thenReturn(false);
when(mMockPhone.getDefaultPhone()).thenReturn(mMockPhone);
when(mMockPhone.getPhoneType()).thenReturn(PhoneConstants.PHONE_TYPE_IMS);
@@ -201,7 +209,7 @@
public PersistableBundle getCarrierConfig() {
// Depends on PhoneGlobals for context in TelephonyConnection, do not implement during
// testing.
- return new PersistableBundle();
+ return mCarrierConfig;
}
@Override
@@ -284,4 +292,8 @@
.thenReturn(mCarrierConfigManager);
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(bundle);
}
+
+ public PersistableBundle getCarrierConfigBundle() {
+ return mCarrierConfig;
+ }
}