Merge "[Audiosharing] Handle add source from notif in receiver" into main
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java
index c070e6c..a7c7984 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java
@@ -25,6 +25,7 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.settings.SettingsEnums;
+import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -45,6 +46,11 @@
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Map;
+
public class AudioSharingReceiver extends BroadcastReceiver {
private static final String TAG = "AudioSharingReceiver";
private static final String ACTION_LE_AUDIO_SHARING_SETTINGS =
@@ -141,6 +147,52 @@
showAddSourceNotification(context, device);
}
break;
+ case ACTION_LE_AUDIO_SHARING_ADD_SOURCE:
+ if (!BluetoothUtils.isAudioSharingUIAvailable(context)) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, feature disabled.");
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ return;
+ }
+ BluetoothDevice sink = intent.getParcelableExtra(EXTRA_BLUETOOTH_DEVICE,
+ BluetoothDevice.class);
+ if (sink == null) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, null device");
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ return;
+ }
+ LocalBluetoothManager manager = Utils.getLocalBtManager(context);
+ boolean isBroadcasting = BluetoothUtils.isBroadcasting(manager);
+ if (!isBroadcasting) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, not broadcasting");
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ return;
+ }
+ Map<Integer, List<BluetoothDevice>> groupedDevices =
+ AudioSharingUtils.fetchConnectedDevicesByGroupId(manager);
+ int groupId = groupedDevices.entrySet().stream().filter(
+ entry -> entry.getValue().contains(sink)).findFirst().map(
+ Map.Entry::getKey).orElse(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, no valid group id");
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ return;
+ }
+ List<BluetoothDevice> sinksToAdd = groupedDevices.getOrDefault(groupId,
+ ImmutableList.of()).stream().filter(
+ d -> !BluetoothUtils.hasConnectedBroadcastSourceForBtDevice(d,
+ manager)).toList();
+ if (sinksToAdd.isEmpty()) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, already has source");
+ } else if (groupedDevices.entrySet().stream().filter(
+ entry -> entry.getKey() != groupId && entry.getValue().stream().anyMatch(
+ d -> BluetoothUtils.hasConnectedBroadcastSourceForBtDevice(d,
+ manager))).toList().size() >= 2) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, already 2 sinks");
+ } else {
+ AudioSharingUtils.addSourceToTargetSinks(sinksToAdd, manager);
+ }
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ break;
case ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF:
int notifId = intent.getIntExtra(EXTRA_NOTIF_ID, -1);
if (notifId != -1) {
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java
index 6b8ec72..dfe5171 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java
@@ -26,6 +26,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -41,6 +42,8 @@
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothStatusCodes;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -55,11 +58,16 @@
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.R;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.flags.Flags;
+import com.google.common.collect.ImmutableList;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -82,6 +90,8 @@
public class AudioSharingReceiverTest {
private static final String ACTION_LE_AUDIO_SHARING_STOP =
"com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STOP";
+ private static final String ACTION_LE_AUDIO_SHARING_ADD_SOURCE =
+ "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_ADD_SOURCE";
private static final String ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF =
"com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_CANCEL_NOTIF";
private static final String EXTRA_NOTIF_ID = "NOTIF_ID";
@@ -97,7 +107,9 @@
private FakeFeatureFactory mFeatureFactory;
@Mock private LocalBluetoothProfileManager mLocalBtProfileManager;
@Mock private LocalBluetoothLeBroadcast mBroadcast;
+ @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
@Mock private LocalBluetoothManager mLocalBtManager;
+ @Mock private BluetoothDevice mDevice;
@Mock private NotificationManager mNm;
@Before
@@ -115,6 +127,8 @@
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBtProfileManager);
when(mLocalBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
+ when(mLocalBtProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
+ when(mDevice.getAlias()).thenReturn(TEST_DEVICE_NAME);
mFeatureFactory = FakeFeatureFactory.setupForTest();
}
@@ -297,12 +311,10 @@
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
- BluetoothDevice device = mock(BluetoothDevice.class);
- when(device.getAlias()).thenReturn(TEST_DEVICE_NAME);
setAppInForeground(false);
Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED);
intent.setPackage(mContext.getPackageName());
- intent.putExtra(EXTRA_BLUETOOTH_DEVICE, device);
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
audioSharingReceiver.onReceive(mContext, intent);
@@ -314,12 +326,10 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void broadcastReceiver_receiveAudioSharingDeviceConnected_showDialog() {
- BluetoothDevice device = mock(BluetoothDevice.class);
- when(device.getAlias()).thenReturn(TEST_DEVICE_NAME);
setAppInForeground(true);
Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED);
intent.setPackage(mContext.getPackageName());
- intent.putExtra(EXTRA_BLUETOOTH_DEVICE, device);
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
audioSharingReceiver.onReceive(mContext, intent);
@@ -332,12 +342,10 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void broadcastReceiver_receiveAudioSharingDeviceConnected_showNotification() {
- BluetoothDevice device = mock(BluetoothDevice.class);
- when(device.getAlias()).thenReturn(TEST_DEVICE_NAME);
setAppInForeground(false);
Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED);
intent.setPackage(mContext.getPackageName());
- intent.putExtra(EXTRA_BLUETOOTH_DEVICE, device);
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
audioSharingReceiver.onReceive(mContext, intent);
@@ -348,6 +356,185 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingAddSource_broadcastDisabled_cancelNotif() {
+ mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
+ BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingAddSource_nullArg_cancelNotif() {
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(any(BluetoothDevice.class),
+ any(BluetoothLeBroadcastMetadata.class), anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingAddSource_notInBroadcast_cancelNotif() {
+ when(mBroadcast.isEnabled(null)).thenReturn(false);
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingAddSource_notConnected_cancelNotif() {
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of());
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingAddSource_invalidGroupId_cancelNotif() {
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+ CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice);
+ when(cachedDevice.getDevice()).thenReturn(mDevice);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice));
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX})
+ public void broadcastReceiver_receiveAudioSharingAddSource_alreadyTwoSinks_cancelNotif() {
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
+ CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+ CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice1);
+ BluetoothDevice device2 = mock(BluetoothDevice.class);
+ CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(device2)).thenReturn(cachedDevice2);
+ when(cachedDevice1.getGroupId()).thenReturn(1);
+ when(cachedDevice1.getDevice()).thenReturn(mDevice);
+ when(cachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME);
+ when(cachedDevice2.getGroupId()).thenReturn(2);
+ when(cachedDevice2.getDevice()).thenReturn(device2);
+ when(cachedDevice2.getName()).thenReturn(TEST_DEVICE_NAME);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice, device2));
+ BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+ when(state.getBroadcastId()).thenReturn(1);
+ when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(state));
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX})
+ public void broadcastReceiver_receiveAudioSharingAddSource_alreadyHasSource_cancelNotif() {
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
+ CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+ CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice);
+ when(cachedDevice.getGroupId()).thenReturn(1);
+ when(cachedDevice.getDevice()).thenReturn(mDevice);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice));
+ BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+ when(state.getBroadcastId()).thenReturn(1);
+ when(mAssistant.getAllSources(mDevice)).thenReturn(ImmutableList.of(state));
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX})
+ public void broadcastReceiver_receiveAudioSharingAddSource_addSource() {
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
+ BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class);
+ when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
+ CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+ CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice1);
+ BluetoothDevice device2 = mock(BluetoothDevice.class);
+ CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(device2)).thenReturn(cachedDevice2);
+ when(cachedDevice1.getGroupId()).thenReturn(1);
+ when(cachedDevice1.getDevice()).thenReturn(mDevice);
+ when(cachedDevice2.getGroupId()).thenReturn(2);
+ when(cachedDevice2.getDevice()).thenReturn(device2);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice, device2));
+ BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+ when(state.getBroadcastId()).thenReturn(1);
+ when(mAssistant.getAllSources(device2)).thenReturn(ImmutableList.of(state));
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant).addSource(mDevice, metadata, /* isGroupOp= */ false);
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void broadcastReceiver_receiveAudioSharingCancelNotif_cancel() {
Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF);
intent.setPackage(mContext.getPackageName());