Merge "[Audiosharing] Sort sharing candidates in Utils." into main
This commit is contained in:
@@ -49,6 +49,7 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@@ -174,6 +175,13 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
|||||||
+ source
|
+ source
|
||||||
+ ", reason = "
|
+ ", reason = "
|
||||||
+ reason);
|
+ reason);
|
||||||
|
AudioSharingUtils.toastMessage(
|
||||||
|
mContext,
|
||||||
|
String.format(
|
||||||
|
Locale.US,
|
||||||
|
"Fail to add source to %s reason %d",
|
||||||
|
sink.getAddress(),
|
||||||
|
reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -209,6 +217,13 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
|||||||
+ sourceId
|
+ sourceId
|
||||||
+ ", reason = "
|
+ ", reason = "
|
||||||
+ reason);
|
+ reason);
|
||||||
|
AudioSharingUtils.toastMessage(
|
||||||
|
mContext,
|
||||||
|
String.format(
|
||||||
|
Locale.US,
|
||||||
|
"Fail to remove source from %s reason %d",
|
||||||
|
sink.getAddress(),
|
||||||
|
reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -284,7 +299,7 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
|||||||
mPreferenceGroup.setVisible(false);
|
mPreferenceGroup.setVisible(false);
|
||||||
mAudioSharingSettingsPreference.setVisible(false);
|
mAudioSharingSettingsPreference.setVisible(false);
|
||||||
|
|
||||||
if (isAvailable()) {
|
if (isAvailable() && mBluetoothDeviceUpdater != null) {
|
||||||
mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
|
mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
|
||||||
mBluetoothDeviceUpdater.forceUpdate();
|
mBluetoothDeviceUpdater.forceUpdate();
|
||||||
}
|
}
|
||||||
@@ -379,8 +394,8 @@ public class AudioSharingDevicePreferenceController extends BasePreferenceContro
|
|||||||
// Show audio sharing switch or join dialog according to device count in the sharing
|
// Show audio sharing switch or join dialog according to device count in the sharing
|
||||||
// session.
|
// session.
|
||||||
ArrayList<AudioSharingDeviceItem> deviceItemsInSharingSession =
|
ArrayList<AudioSharingDeviceItem> deviceItemsInSharingSession =
|
||||||
AudioSharingUtils.buildOrderedDeviceItemsInSharingSession(
|
AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
|
||||||
groupedDevices, mLocalBtManager);
|
mLocalBtManager, groupedDevices, /* filterByInSharing= */ true);
|
||||||
// Show audio sharing switch dialog when the third eligible (LE audio) remote device
|
// Show audio sharing switch dialog when the third eligible (LE audio) remote device
|
||||||
// connected during a sharing session.
|
// connected during a sharing session.
|
||||||
if (deviceItemsInSharingSession.size() >= 2) {
|
if (deviceItemsInSharingSession.size() >= 2) {
|
||||||
|
|||||||
@@ -19,18 +19,22 @@ package com.android.settings.connecteddevice.audiosharing;
|
|||||||
import android.bluetooth.BluetoothCsipSetCoordinator;
|
import android.bluetooth.BluetoothCsipSetCoordinator;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||||
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.android.settingslib.bluetooth.BluetoothUtils;
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class AudioSharingUtils {
|
public class AudioSharingUtils {
|
||||||
private static final String TAG = "AudioSharingUtils";
|
private static final String TAG = "AudioSharingUtils";
|
||||||
@@ -73,48 +77,102 @@ public class AudioSharingUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch a list of {@link AudioSharingDeviceItem}s in the audio sharing session.
|
* Fetch a list of ordered connected lead {@link CachedBluetoothDevice}s eligible for audio
|
||||||
|
* sharing. The active device is placed in the first place if it exists. The devices can be
|
||||||
|
* filtered by whether it is already in the audio sharing session.
|
||||||
*
|
*
|
||||||
|
* @param localBtManager The BT manager to provide BT functions. *
|
||||||
* @param groupedConnectedDevices devices connected to broadcast assistant grouped by CSIP group
|
* @param groupedConnectedDevices devices connected to broadcast assistant grouped by CSIP group
|
||||||
* id.
|
* id.
|
||||||
* @param localBtManager The BT manager to provide BT functions.
|
* @param filterByInSharing Whether to filter the device by if is already in the sharing
|
||||||
* @return A list of connected devices in the audio sharing session.
|
* session.
|
||||||
|
* @return A list of ordered connected devices eligible for the audio sharing. The active device
|
||||||
|
* is placed in the first place if it exists.
|
||||||
*/
|
*/
|
||||||
public static ArrayList<AudioSharingDeviceItem> buildOrderedDeviceItemsInSharingSession(
|
public static ArrayList<CachedBluetoothDevice> buildOrderedConnectedLeadDevices(
|
||||||
|
LocalBluetoothManager localBtManager,
|
||||||
Map<Integer, List<CachedBluetoothDevice>> groupedConnectedDevices,
|
Map<Integer, List<CachedBluetoothDevice>> groupedConnectedDevices,
|
||||||
LocalBluetoothManager localBtManager) {
|
boolean filterByInSharing) {
|
||||||
ArrayList<AudioSharingDeviceItem> deviceItems = new ArrayList<>();
|
ArrayList<CachedBluetoothDevice> orderedDevices = new ArrayList<>();
|
||||||
LocalBluetoothLeBroadcastAssistant assistant =
|
LocalBluetoothLeBroadcastAssistant assistant =
|
||||||
localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
|
localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
|
||||||
if (assistant == null) return deviceItems;
|
if (assistant == null) return orderedDevices;
|
||||||
CachedBluetoothDevice activeDevice = null;
|
|
||||||
List<CachedBluetoothDevice> inactiveDevices = new ArrayList<>();
|
|
||||||
for (List<CachedBluetoothDevice> devices : groupedConnectedDevices.values()) {
|
for (List<CachedBluetoothDevice> devices : groupedConnectedDevices.values()) {
|
||||||
|
CachedBluetoothDevice leadDevice = null;
|
||||||
for (CachedBluetoothDevice device : devices) {
|
for (CachedBluetoothDevice device : devices) {
|
||||||
List<BluetoothLeBroadcastReceiveState> sourceList =
|
if (!device.getMemberDevice().isEmpty()) {
|
||||||
assistant.getAllSources(device.getDevice());
|
leadDevice = device;
|
||||||
if (!sourceList.isEmpty()) {
|
|
||||||
// Use random device in the group within the sharing session to
|
|
||||||
// represent the group.
|
|
||||||
if (BluetoothUtils.isActiveLeAudioDevice(device)) {
|
|
||||||
activeDevice = device;
|
|
||||||
} else {
|
|
||||||
inactiveDevices.add(device);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (leadDevice == null && !devices.isEmpty()) {
|
||||||
|
leadDevice = devices.get(0);
|
||||||
|
Log.d(
|
||||||
|
TAG,
|
||||||
|
"Empty member device, pick arbitrary device as the lead: "
|
||||||
|
+ leadDevice.getDevice().getAnonymizedAddress());
|
||||||
}
|
}
|
||||||
if (activeDevice != null) {
|
if (leadDevice == null) {
|
||||||
deviceItems.add(buildAudioSharingDeviceItem(activeDevice));
|
Log.d(TAG, "Skip due to no lead device");
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
inactiveDevices.stream()
|
if (filterByInSharing && !hasBroadcastSource(leadDevice, localBtManager)) {
|
||||||
.sorted(CachedBluetoothDevice::compareTo)
|
Log.d(
|
||||||
.forEach(
|
TAG,
|
||||||
device -> {
|
"Filtered the device due to not in sharing session: "
|
||||||
deviceItems.add(buildAudioSharingDeviceItem(device));
|
+ leadDevice.getDevice().getAnonymizedAddress());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
orderedDevices.add(leadDevice);
|
||||||
|
}
|
||||||
|
orderedDevices.sort(
|
||||||
|
(CachedBluetoothDevice d1, CachedBluetoothDevice d2) -> {
|
||||||
|
// Active above not inactive
|
||||||
|
int comparison =
|
||||||
|
(isActiveLeAudioDevice(d2) ? 1 : 0)
|
||||||
|
- (isActiveLeAudioDevice(d1) ? 1 : 0);
|
||||||
|
if (comparison != 0) return comparison;
|
||||||
|
// Bonded above not bonded
|
||||||
|
comparison =
|
||||||
|
(d2.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0)
|
||||||
|
- (d1.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
|
||||||
|
if (comparison != 0) return comparison;
|
||||||
|
// Bond timestamp available above unavailable
|
||||||
|
comparison =
|
||||||
|
(d2.getBondTimestamp() != null ? 1 : 0)
|
||||||
|
- (d1.getBondTimestamp() != null ? 1 : 0);
|
||||||
|
if (comparison != 0) return comparison;
|
||||||
|
// Order by bond timestamp if it is available
|
||||||
|
// Otherwise order by device name
|
||||||
|
return d1.getBondTimestamp() != null
|
||||||
|
? d1.getBondTimestamp().compareTo(d2.getBondTimestamp())
|
||||||
|
: d1.getName().compareTo(d2.getName());
|
||||||
});
|
});
|
||||||
return deviceItems;
|
return orderedDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a list of ordered connected lead {@link AudioSharingDeviceItem}s eligible for audio
|
||||||
|
* sharing. The active device is placed in the first place if it exists. The devices can be
|
||||||
|
* filtered by whether it is already in the audio sharing session.
|
||||||
|
*
|
||||||
|
* @param localBtManager The BT manager to provide BT functions. *
|
||||||
|
* @param groupedConnectedDevices devices connected to broadcast assistant grouped by CSIP group
|
||||||
|
* id.
|
||||||
|
* @param filterByInSharing Whether to filter the device by if is already in the sharing
|
||||||
|
* session.
|
||||||
|
* @return A list of ordered connected devices eligible for the audio sharing. The active device
|
||||||
|
* is placed in the first place if it exists.
|
||||||
|
*/
|
||||||
|
public static ArrayList<AudioSharingDeviceItem> buildOrderedConnectedLeadAudioSharingDeviceItem(
|
||||||
|
LocalBluetoothManager localBtManager,
|
||||||
|
Map<Integer, List<CachedBluetoothDevice>> groupedConnectedDevices,
|
||||||
|
boolean filterByInSharing) {
|
||||||
|
return buildOrderedConnectedLeadDevices(
|
||||||
|
localBtManager, groupedConnectedDevices, filterByInSharing)
|
||||||
|
.stream()
|
||||||
|
.map(device -> buildAudioSharingDeviceItem(device))
|
||||||
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */
|
/** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */
|
||||||
@@ -123,6 +181,57 @@ public class AudioSharingUtils {
|
|||||||
return new AudioSharingDeviceItem(
|
return new AudioSharingDeviceItem(
|
||||||
cachedDevice.getName(),
|
cachedDevice.getName(),
|
||||||
cachedDevice.getGroupId(),
|
cachedDevice.getGroupId(),
|
||||||
BluetoothUtils.isActiveLeAudioDevice(cachedDevice));
|
isActiveLeAudioDevice(cachedDevice));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if {@link CachedBluetoothDevice} is in an audio sharing session.
|
||||||
|
*
|
||||||
|
* @param cachedDevice The cached bluetooth device to check.
|
||||||
|
* @param localBtManager The BT manager to provide BT functions.
|
||||||
|
* @return Whether the device is in an audio sharing session.
|
||||||
|
*/
|
||||||
|
public static boolean hasBroadcastSource(
|
||||||
|
CachedBluetoothDevice cachedDevice, LocalBluetoothManager localBtManager) {
|
||||||
|
LocalBluetoothLeBroadcastAssistant assistant =
|
||||||
|
localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
|
||||||
|
if (assistant == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<BluetoothLeBroadcastReceiveState> sourceList =
|
||||||
|
assistant.getAllSources(cachedDevice.getDevice());
|
||||||
|
if (!sourceList.isEmpty()) return true;
|
||||||
|
// Return true if member device is in broadcast.
|
||||||
|
for (CachedBluetoothDevice device : cachedDevice.getMemberDevice()) {
|
||||||
|
List<BluetoothLeBroadcastReceiveState> list =
|
||||||
|
assistant.getAllSources(device.getDevice());
|
||||||
|
if (!list.isEmpty()) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if {@link CachedBluetoothDevice} is an active le audio device.
|
||||||
|
*
|
||||||
|
* @param cachedDevice The cached bluetooth device to check.
|
||||||
|
* @return Whether the device is an active le audio device.
|
||||||
|
*/
|
||||||
|
public static boolean isActiveLeAudioDevice(CachedBluetoothDevice cachedDevice) {
|
||||||
|
if (BluetoothUtils.isActiveLeAudioDevice(cachedDevice)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Return true if member device is an active le audio device.
|
||||||
|
for (CachedBluetoothDevice device : cachedDevice.getMemberDevice()) {
|
||||||
|
if (BluetoothUtils.isActiveLeAudioDevice(device)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Toast message on main thread. */
|
||||||
|
public static void toastMessage(Context context, String message) {
|
||||||
|
ThreadUtils.postOnMainThread(
|
||||||
|
() -> Toast.makeText(context, message, Toast.LENGTH_LONG).show());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,14 +62,6 @@ public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferen
|
|||||||
@Override
|
@Override
|
||||||
public void displayPreference(PreferenceScreen screen) {
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
super.displayPreference(screen);
|
super.displayPreference(screen);
|
||||||
updateDeviceItemsInSharingSession();
|
|
||||||
// mDeviceItemsInSharingSession is ordered. The active device is the first place if exits.
|
|
||||||
if (!mDeviceItemsInSharingSession.isEmpty()
|
|
||||||
&& mDeviceItemsInSharingSession.get(0).isActive()) {
|
|
||||||
mPreference.setSummary(mDeviceItemsInSharingSession.get(0).getName());
|
|
||||||
} else {
|
|
||||||
mPreference.setSummary("");
|
|
||||||
}
|
|
||||||
mPreference.setOnPreferenceClickListener(
|
mPreference.setOnPreferenceClickListener(
|
||||||
preference -> {
|
preference -> {
|
||||||
if (mFragment == null) {
|
if (mFragment == null) {
|
||||||
@@ -106,6 +98,22 @@ public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateVisibility(boolean isVisible) {
|
||||||
|
super.updateVisibility(isVisible);
|
||||||
|
if (isVisible && mPreference != null) {
|
||||||
|
updateDeviceItemsInSharingSession();
|
||||||
|
// mDeviceItemsInSharingSession is ordered. The active device is the first place if
|
||||||
|
// exits.
|
||||||
|
if (!mDeviceItemsInSharingSession.isEmpty()
|
||||||
|
&& mDeviceItemsInSharingSession.get(0).isActive()) {
|
||||||
|
mPreference.setSummary(mDeviceItemsInSharingSession.get(0).getName());
|
||||||
|
} else {
|
||||||
|
mPreference.setSummary("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActiveDeviceChanged(
|
public void onActiveDeviceChanged(
|
||||||
@Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) {
|
@Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) {
|
||||||
@@ -129,7 +137,7 @@ public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferen
|
|||||||
mGroupedConnectedDevices =
|
mGroupedConnectedDevices =
|
||||||
AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager);
|
AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager);
|
||||||
mDeviceItemsInSharingSession =
|
mDeviceItemsInSharingSession =
|
||||||
AudioSharingUtils.buildOrderedDeviceItemsInSharingSession(
|
AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
|
||||||
mGroupedConnectedDevices, mLocalBtManager);
|
mLocalBtManager, mGroupedConnectedDevices, /* filterByInSharing= */ true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user