summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-03-13 21:15:32 -0700
committer Android (Google) Code Review <android-gerrit@google.com> 2025-03-13 21:15:32 -0700
commit15717f41d0b11a9a26b0e5288336a060d1854221 (patch)
tree308a02adc4bb79649b0294f35dad3f2d8fef9a27
parent2353e035d49b5965ce987ed9a8e6354549f46c51 (diff)
parentf022c09b3f5a150a2a1b365cad132b9bdb81f463 (diff)
Merge "LE Audio: do not hardcode TMAP role mask" into main
-rw-r--r--android/app/src/com/android/bluetooth/le_audio/LeAudioService.java69
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java100
2 files changed, 142 insertions, 27 deletions
diff --git a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
index cebf4270e5..de152f0ae1 100644
--- a/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
+++ b/android/app/src/com/android/bluetooth/le_audio/LeAudioService.java
@@ -27,6 +27,7 @@ import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
import static android.bluetooth.IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
import static com.android.bluetooth.bass_client.BassConstants.INVALID_BROADCAST_ID;
+import static com.android.bluetooth.flags.Flags.doNotHardcodeTmapRoleMask;
import static com.android.bluetooth.flags.Flags.leaudioBigDependsOnAudioState;
import static com.android.bluetooth.flags.Flags.leaudioBroadcastApiManagePrimaryGroup;
import static com.android.bluetooth.flags.Flags.leaudioMonitorUnicastSourceWhenManagedByBroadcastDelegator;
@@ -261,24 +262,49 @@ public class LeAudioService extends ProfileService {
mStateMachinesThread.start();
// Initialize Broadcast native interface
- if ((mAdapterService.getSupportedProfilesBitMask()
- & (1 << BluetoothProfile.LE_AUDIO_BROADCAST))
- != 0) {
- Log.i(TAG, "Init Le Audio broadcaster");
- LeAudioBroadcasterNativeInterface broadcastNativeInterface =
- requireNonNull(LeAudioBroadcasterNativeInterface.getInstance());
- broadcastNativeInterface.init();
- mLeAudioBroadcasterNativeInterface = Optional.of(broadcastNativeInterface);
- mTmapRoleMask =
- LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG
- | LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS
- | LeAudioTmapGattServer.TMAP_ROLE_FLAG_BMS;
+ if (doNotHardcodeTmapRoleMask()) {
+ int mask = 0;
+ if (isProfileSupported(BluetoothProfile.LE_CALL_CONTROL)) {
+ // Table 3.5 of TMAP v1.0: CCP Server is mandatory for the TMAP CG role.
+ mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG;
+ }
+ if (isProfileSupported(BluetoothProfile.MCP_SERVER)) {
+ // Table 3.5 of TMAP v1.0: MCP Server is mandatory for the TMAP UMS role.
+ mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS;
+ }
+ if (isProfileSupported(BluetoothProfile.LE_AUDIO_BROADCAST)) {
+ Log.i(TAG, "Init Le Audio broadcaster");
+ LeAudioBroadcasterNativeInterface broadcastNativeInterface =
+ requireNonNull(LeAudioBroadcasterNativeInterface.getInstance());
+ broadcastNativeInterface.init();
+ mLeAudioBroadcasterNativeInterface = Optional.of(broadcastNativeInterface);
+
+ mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_BMS;
+ } else {
+ mLeAudioBroadcasterNativeInterface = Optional.empty();
+ Log.w(TAG, "Le Audio Broadcasts not supported.");
+ }
+ mTmapRoleMask = mask;
} else {
- mTmapRoleMask =
- LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG
- | LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS;
- mLeAudioBroadcasterNativeInterface = Optional.empty();
- Log.w(TAG, "Le Audio Broadcasts not supported.");
+ if ((mAdapterService.getSupportedProfilesBitMask()
+ & (1 << BluetoothProfile.LE_AUDIO_BROADCAST))
+ != 0) {
+ Log.i(TAG, "Init Le Audio broadcaster");
+ LeAudioBroadcasterNativeInterface broadcastNativeInterface =
+ requireNonNull(LeAudioBroadcasterNativeInterface.getInstance());
+ broadcastNativeInterface.init();
+ mLeAudioBroadcasterNativeInterface = Optional.of(broadcastNativeInterface);
+ mTmapRoleMask =
+ LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG
+ | LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS
+ | LeAudioTmapGattServer.TMAP_ROLE_FLAG_BMS;
+ } else {
+ mTmapRoleMask =
+ LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG
+ | LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS;
+ mLeAudioBroadcasterNativeInterface = Optional.empty();
+ Log.w(TAG, "Le Audio Broadcasts not supported.");
+ }
}
mTmapStarted = registerTmap();
@@ -302,6 +328,15 @@ public class LeAudioService extends ProfileService {
}
}
+ private boolean isProfileSupported(int profile) {
+ return (mAdapterService.getSupportedProfilesBitMask() & (1 << profile)) != 0;
+ }
+
+ @VisibleForTesting
+ int getTmapRoleMask() {
+ return mTmapRoleMask;
+ }
+
private class LeAudioGroupDescriptor {
LeAudioGroupDescriptor(int groupId, boolean isInbandRingtoneEnabled) {
mGroupId = groupId;
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
index f0f2037358..cf836ddc3c 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_audio/LeAudioServiceTest.java
@@ -76,12 +76,12 @@ import android.os.ParcelUuid;
import android.os.RemoteException;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.FlagsParameterization;
import android.platform.test.flag.junit.SetFlagsRule;
import android.sysprop.BluetoothProperties;
import androidx.test.filters.MediumTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.bass_client.BassClientService;
@@ -113,15 +113,20 @@ import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.hamcrest.MockitoHamcrest;
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4;
+import platform.test.runner.parameterized.Parameters;
+
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
@MediumTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(ParameterizedAndroidJunit4.class)
public class LeAudioServiceTest {
- @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule public final SetFlagsRule mSetFlagsRule;
@Rule public final MockitoRule mMockitoRule = new MockitoRule();
@Mock private AdapterService mAdapterService;
@@ -201,6 +206,20 @@ public class LeAudioServiceTest {
private InOrder mInOrder;
+ @Parameters(name = "{0}")
+ public static List<FlagsParameterization> getParams() {
+ return FlagsParameterization.progressionOf(
+ Flags.FLAG_LEAUDIO_BROADCAST_PRIMARY_GROUP_SELECTION,
+ Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX,
+ Flags.FLAG_LEAUDIO_UNICAST_NO_AVAILABLE_CONTEXTS,
+ Flags.FLAG_LEAUDIO_BROADCAST_API_MANAGE_PRIMARY_GROUP,
+ Flags.FLAG_DO_NOT_HARDCODE_TMAP_ROLE_MASK);
+ }
+
+ public LeAudioServiceTest(FlagsParameterization flags) {
+ mSetFlagsRule = new SetFlagsRule(flags);
+ }
+
@Before
public void setUp() throws Exception {
mInOrder = inOrder(mAdapterService);
@@ -211,11 +230,9 @@ public class LeAudioServiceTest {
doReturn(mTargetContext.getContentResolver()).when(mAdapterService).getContentResolver();
doReturn(MAX_LE_AUDIO_CONNECTIONS).when(mAdapterService).getMaxConnectedAudioDevices();
- doReturn(
- (long) (1 << BluetoothProfile.LE_AUDIO_BROADCAST)
- | (1 << BluetoothProfile.LE_AUDIO))
- .when(mAdapterService)
- .getSupportedProfilesBitMask();
+ injectSupportedProfilesBitMask(
+ Set.of(BluetoothProfile.LE_AUDIO_BROADCAST, BluetoothProfile.LE_AUDIO));
+
doReturn(new ParcelUuid[] {BluetoothUuid.LE_AUDIO})
.when(mAdapterService)
.getRemoteUuids(any(BluetoothDevice.class));
@@ -280,6 +297,43 @@ public class LeAudioServiceTest {
assertThat(LeAudioService.getLeAudioService()).isNull();
}
+ @Test
+ @EnableFlags(Flags.FLAG_DO_NOT_HARDCODE_TMAP_ROLE_MASK)
+ public void testTmapRoleMask() {
+ List<Set<Integer>> powerSet =
+ List.of(
+ Set.of(BluetoothProfile.LE_CALL_CONTROL),
+ Set.of(BluetoothProfile.MCP_SERVER),
+ Set.of(BluetoothProfile.LE_CALL_CONTROL, BluetoothProfile.MCP_SERVER),
+ Set.of(BluetoothProfile.LE_AUDIO_BROADCAST),
+ Set.of(
+ BluetoothProfile.LE_AUDIO_BROADCAST,
+ BluetoothProfile.LE_CALL_CONTROL),
+ Set.of(BluetoothProfile.LE_AUDIO_BROADCAST, BluetoothProfile.MCP_SERVER),
+ Set.of(
+ BluetoothProfile.LE_AUDIO_BROADCAST,
+ BluetoothProfile.LE_CALL_CONTROL,
+ BluetoothProfile.MCP_SERVER));
+
+ List<Integer> tmapMasks =
+ powerSet.stream()
+ .map(
+ set -> {
+ injectSupportedProfilesBitMask(set);
+ LeAudioService service =
+ new LeAudioService(mAdapterService, mNativeInterface);
+ return service.getTmapRoleMask();
+ })
+ .collect(Collectors.toList());
+
+ List<Integer> expectedMasks =
+ powerSet.stream()
+ .map(LeAudioServiceTest::constructTmapRoleMask)
+ .collect(Collectors.toList());
+
+ assertThat(tmapMasks).containsExactly(expectedMasks.toArray()).inOrder();
+ }
+
/** Test getting LeAudio Service: getLeAudioService() */
@Test
public void testGetLeAudioService() {
@@ -1788,8 +1842,8 @@ public class LeAudioServiceTest {
/** Test native interface group status message handling */
@Test
+ @EnableFlags(Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX)
public void testMessageFromNativeGroupCodecConfigChangedNonActiveDevice() {
- mSetFlagsRule.enableFlags(Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX);
onGroupCodecConfChangedCallbackCalled = false;
injectLocalCodecConfigCapaChanged(INPUT_CAPABILITIES_CONFIG, OUTPUT_CAPABILITIES_CONFIG);
@@ -1874,8 +1928,8 @@ public class LeAudioServiceTest {
/** Test native interface group status message handling */
@Test
+ @EnableFlags(Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX)
public void testMessageFromNativeGroupCodecConfigChangedActiveDevice_DifferentConfiguration() {
- mSetFlagsRule.enableFlags(Flags.FLAG_LEAUDIO_CODEC_CONFIG_CALLBACK_ORDER_FIX);
onGroupCodecConfChangedCallbackCalled = false;
injectLocalCodecConfigCapaChanged(INPUT_CAPABILITIES_CONFIG, OUTPUT_CAPABILITIES_CONFIG);
@@ -3216,4 +3270,30 @@ public class LeAudioServiceTest {
.sendBroadcastAsUser(
MockitoHamcrest.argThat(AllOf.allOf(matchers)), any(), any(), any());
}
+
+ private void injectSupportedProfilesBitMask(Set<Integer> profiles) {
+ long mask = 0;
+ for (int profile : profiles) {
+ mask |= (long) (1 << profile);
+ }
+ doReturn(mask).when(mAdapterService).getSupportedProfilesBitMask();
+ }
+
+ private static int constructTmapRoleMask(Set<Integer> profiles) {
+ int mask = 0;
+ for (int profile : profiles) {
+ switch (profile) {
+ case BluetoothProfile.LE_CALL_CONTROL:
+ mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_CG;
+ break;
+ case BluetoothProfile.MCP_SERVER:
+ mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_UMS;
+ break;
+ case BluetoothProfile.LE_AUDIO_BROADCAST:
+ mask |= LeAudioTmapGattServer.TMAP_ROLE_FLAG_BMS;
+ break;
+ }
+ }
+ return mask;
+ }
}