From f3d300b042c923351ac69ca7928926e154718887 Mon Sep 17 00:00:00 2001 From: SongFerngWang Date: Wed, 15 Jun 2022 22:18:25 +0800 Subject: [PATCH] [LE Unicast] Using the active device as main device after grouping After onGroupIdChanged, the CsipDeviceManager assigns the first device with the same groupId as main device. It is not correct since the main device shouble be the active device. This issue causes the summary can't shows 'Active' at the Settings. Bug: 232892046 Test: Build pass Change-Id: I00e5471b9315c896b8c16723ad37d66a922c27e4 Merged-In: I00e5471b9315c896b8c16723ad37d66a922c27e4 --- .../bluetooth/CsipDeviceManager.java | 90 +++++++++++++++---- .../settingslib/bluetooth/LeAudioProfile.java | 32 +++++++ 2 files changed, 105 insertions(+), 17 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java index 89e10c4b5e113..fc70ba40fb476 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java @@ -20,15 +20,19 @@ import android.bluetooth.BluetoothCsipSetCoordinator; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; +import android.os.Build; import android.os.ParcelUuid; import android.util.Log; +import androidx.annotation.ChecksSdkIntAtLeast; + import com.android.internal.annotations.VisibleForTesting; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * CsipDeviceManager manages the set of remote CSIP Bluetooth devices. @@ -126,32 +130,84 @@ public class CsipDeviceManager { } } + @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.TIRAMISU) + private static boolean isAtLeastT() { + return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU; + } + // Group devices by groupId @VisibleForTesting void onGroupIdChanged(int groupId) { - int firstMatchedIndex = -1; - CachedBluetoothDevice mainDevice = null; + if (!isValidGroupId(groupId)) { + log("onGroupIdChanged: groupId is invalid"); + return; + } + log("onGroupIdChanged: mCachedDevices list =" + mCachedDevices.toString()); + final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager(); + final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager(); + final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile(); + final BluetoothDevice mainBluetoothDevice = (leAudioProfile != null && isAtLeastT()) ? + leAudioProfile.getConnectedGroupLeadDevice(groupId) : null; + CachedBluetoothDevice newMainDevice = + mainBluetoothDevice != null ? deviceManager.findDevice(mainBluetoothDevice) : null; + if (newMainDevice != null) { + final CachedBluetoothDevice finalNewMainDevice = newMainDevice; + final List memberDevices = mCachedDevices.stream() + .filter(cachedDevice -> !cachedDevice.equals(finalNewMainDevice) + && cachedDevice.getGroupId() == groupId) + .collect(Collectors.toList()); + if (memberDevices == null || memberDevices.isEmpty()) { + log("onGroupIdChanged: There is no member device in list."); + return; + } + log("onGroupIdChanged: removed from UI device =" + memberDevices + + ", with groupId=" + groupId + " mainDevice= " + newMainDevice); + for (CachedBluetoothDevice memberDeviceItem : memberDevices) { + Set memberSet = memberDeviceItem.getMemberDevice(); + if (!memberSet.isEmpty()) { + log("onGroupIdChanged: Transfer the member list into new main device."); + for (CachedBluetoothDevice memberListItem : memberSet) { + if (!memberListItem.equals(newMainDevice)) { + newMainDevice.addMemberDevice(memberListItem); + } + } + memberSet.clear(); + } - for (int i = mCachedDevices.size() - 1; i >= 0; i--) { - final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i); - if (cachedDevice.getGroupId() != groupId) { - continue; + newMainDevice.addMemberDevice(memberDeviceItem); + mCachedDevices.remove(memberDeviceItem); + mBtManager.getEventManager().dispatchDeviceRemoved(memberDeviceItem); } - if (firstMatchedIndex == -1) { - // Found the first one - firstMatchedIndex = i; - mainDevice = cachedDevice; - continue; + if (!mCachedDevices.contains(newMainDevice)) { + mCachedDevices.add(newMainDevice); + mBtManager.getEventManager().dispatchDeviceAdded(newMainDevice); } + } else { + log("onGroupIdChanged: There is no main device from the LE profile."); + int firstMatchedIndex = -1; - log("onGroupIdChanged: removed from UI device =" + cachedDevice - + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex); + for (int i = mCachedDevices.size() - 1; i >= 0; i--) { + final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i); + if (cachedDevice.getGroupId() != groupId) { + continue; + } - mainDevice.addMemberDevice(cachedDevice); - mCachedDevices.remove(i); - mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice); - break; + if (firstMatchedIndex == -1) { + // Found the first one + firstMatchedIndex = i; + newMainDevice = cachedDevice; + continue; + } + + log("onGroupIdChanged: removed from UI device =" + cachedDevice + + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex); + + newMainDevice.addMemberDevice(cachedDevice); + mCachedDevices.remove(i); + mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice); + break; + } } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java index c323c4ef99373..b6dcdc3b1759a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java @@ -21,6 +21,7 @@ import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_ALL; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED; import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN; +import android.annotation.Nullable; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothCodecConfig; @@ -183,6 +184,37 @@ public class LeAudioProfile implements LocalBluetoothProfile { return mBluetoothAdapter.getActiveDevices(BluetoothProfile.LE_AUDIO); } + /** + * Get Lead device for the group. + * + * Lead device is the device that can be used as an active device in the system. + * Active devices points to the Audio Device for the Le Audio group. + * This method returns the Lead devices for the connected LE Audio + * group and this device should be used in the setActiveDevice() method by other parts + * of the system, which wants to set to active a particular Le Audio group. + * + * Note: getActiveDevice() returns the Lead device for the currently active LE Audio group. + * Note: When Lead device gets disconnected while Le Audio group is active and has more devices + * in the group, then Lead device will not change. If Lead device gets disconnected, for the + * Le Audio group which is not active, a new Lead device will be chosen + * + * @param groupId The group id. + * @return group lead device. + * + * @hide + */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + public @Nullable BluetoothDevice getConnectedGroupLeadDevice(int groupId) { + if (DEBUG) { + Log.d(TAG,"getConnectedGroupLeadDevice"); + } + if (mService == null) { + Log.e(TAG,"No service."); + return null; + } + return mService.getConnectedGroupLeadDevice(groupId); + } + @Override public boolean isEnabled(BluetoothDevice device) { if (mService == null || device == null) {