summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java7
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java73
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java117
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java247
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java15
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java30
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java2
7 files changed, 471 insertions, 20 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index a0869189a5bd..21afde186a32 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothHearingAid;
@@ -351,8 +352,10 @@ public class BluetoothEventManager {
cachedDevice.onBondingStateChanged(bondState);
if (bondState == BluetoothDevice.BOND_NONE) {
- /* Check if we need to remove other Hearing Aid devices */
- if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
+ // Check if we need to remove other Coordinated set member devices / Hearing Aid
+ // devices
+ if (cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
+ || cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
mDeviceManager.onDeviceUnpaired(cachedDevice);
}
int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 6a590c2ff382..78fc139894d1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
@@ -41,7 +42,9 @@ import com.android.settingslib.Utils;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
/**
@@ -66,6 +69,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
private final Object mProfileLock = new Object();
BluetoothDevice mDevice;
private long mHiSyncId;
+ private int mGroupId;
// Need this since there is no method for getting RSSI
short mRssi;
// mProfiles and mRemovedProfiles does not do swap() between main and sub device. It is
@@ -100,6 +104,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
private boolean mIsA2dpProfileConnectedFail = false;
private boolean mIsHeadsetProfileConnectedFail = false;
private boolean mIsHearingAidProfileConnectedFail = false;
+ // Group member devices for the coordinated set
+ private Set<CachedBluetoothDevice> mMemberDevices = new HashSet<CachedBluetoothDevice>();
// Group second device for Hearing Aid
private CachedBluetoothDevice mSubDevice;
@@ -133,6 +139,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
mDevice = device;
fillData();
mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
+ mGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
}
/**
@@ -317,6 +324,24 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
return mIsCoordinatedSetMember;
}
+ /**
+ * Get the coordinated set group id.
+ *
+ * @return the group id.
+ */
+ public int getGroupId() {
+ return mGroupId;
+ }
+
+ /**
+ * Set the coordinated set group id.
+ *
+ * @param id the group id from the CSIP.
+ */
+ public void setGroupId(int id) {
+ mGroupId = id;
+ }
+
void onBondingDockConnect() {
// Attempt to connect if UUIDs are available. Otherwise,
// we will connect when the ACTION_UUID intent arrives.
@@ -1191,4 +1216,52 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
mSubDevice.mJustDiscovered = tmpJustDiscovered;
fetchActiveDevices();
}
+
+ /**
+ * @return a set of member devices that are in the same coordinated set with this device.
+ */
+ public Set<CachedBluetoothDevice> getMemberDevice() {
+ return mMemberDevices;
+ }
+
+ /**
+ * Store the member devices that are in the same coordinated set.
+ */
+ public void setMemberDevice(CachedBluetoothDevice memberDevice) {
+ mMemberDevices.add(memberDevice);
+ }
+
+ /**
+ * Remove a device from the member device sets.
+ */
+ public void removeMemberDevice(CachedBluetoothDevice memberDevice) {
+ mMemberDevices.remove(memberDevice);
+ }
+
+ /**
+ * In order to show the preference for the whole group, we always set the main device as the
+ * first connected device in the coordinated set, and then switch the content of the main
+ * device and member devices.
+ *
+ * @param prevMainDevice the previous Main device, it will be added into the member device set.
+ * @param newMainDevie the new Main device, it will be removed from the member device set.
+ */
+ public void switchMemberDeviceContent(CachedBluetoothDevice prevMainDevice,
+ CachedBluetoothDevice newMainDevie) {
+ // Backup from main device
+ final BluetoothDevice tmpDevice = mDevice;
+ final short tmpRssi = mRssi;
+ final boolean tmpJustDiscovered = mJustDiscovered;
+ // Set main device from sub device
+ mDevice = newMainDevie.mDevice;
+ mRssi = newMainDevie.mRssi;
+ mJustDiscovered = newMainDevie.mJustDiscovered;
+ setMemberDevice(prevMainDevice);
+ mMemberDevices.remove(newMainDevie);
+ // Set sub device from backup
+ newMainDevie.mDevice = tmpDevice;
+ newMainDevie.mRssi = tmpRssi;
+ newMainDevie.mJustDiscovered = tmpJustDiscovered;
+ fetchActiveDevices();
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index cca9cfac2d22..19c5a74280eb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;
@@ -26,6 +27,7 @@ import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
/**
* CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
@@ -41,11 +43,14 @@ public class CachedBluetoothDeviceManager {
final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
@VisibleForTesting
HearingAidDeviceManager mHearingAidDeviceManager;
+ @VisibleForTesting
+ CsipDeviceManager mCsipDeviceManager;
CachedBluetoothDeviceManager(Context context, LocalBluetoothManager localBtManager) {
mContext = context;
mBtManager = localBtManager;
mHearingAidDeviceManager = new HearingAidDeviceManager(localBtManager, mCachedDevices);
+ mCsipDeviceManager = new CsipDeviceManager(localBtManager, mCachedDevices);
}
public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
@@ -79,7 +84,16 @@ public class CachedBluetoothDeviceManager {
if (cachedDevice.getDevice().equals(device)) {
return cachedDevice;
}
- // Check sub devices if it exists
+ // Check the member devices for the coordinated set if it exists
+ final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ if (memberDevice.getDevice().equals(device)) {
+ return memberDevice;
+ }
+ }
+ }
+ // Check sub devices for hearing aid if it exists
CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
if (subDevice != null && subDevice.getDevice().equals(device)) {
return subDevice;
@@ -102,8 +116,10 @@ public class CachedBluetoothDeviceManager {
newDevice = findDevice(device);
if (newDevice == null) {
newDevice = new CachedBluetoothDevice(mContext, profileManager, device);
+ mCsipDeviceManager.initCsipDeviceIfNeeded(newDevice);
mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(newDevice);
- if (!mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
+ if (!mCsipDeviceManager.setMemberDeviceIfNeeded(newDevice)
+ && !mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
mCachedDevices.add(newDevice);
mBtManager.getEventManager().dispatchDeviceAdded(newDevice);
}
@@ -114,13 +130,23 @@ public class CachedBluetoothDeviceManager {
}
/**
- * Returns device summary of the pair of the hearing aid passed as the parameter.
+ * Returns device summary of the pair of the hearing aid / CSIP passed as the parameter.
*
* @param CachedBluetoothDevice device
- * @return Device summary, or if the pair does not exist or if it is not a hearing aid,
- * then {@code null}.
+ * @return Device summary, or if the pair does not exist or if it is not a hearing aid or
+ * a CSIP set member, then {@code null}.
*/
public synchronized String getSubDeviceSummary(CachedBluetoothDevice device) {
+ final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ if (!memberDevice.isConnected()) {
+ return null;
+ }
+ }
+
+ return device.getConnectionSummary();
+ }
CachedBluetoothDevice subDevice = device.getSubDevice();
if (subDevice != null && subDevice.isConnected()) {
return subDevice.getConnectionSummary();
@@ -132,12 +158,22 @@ public class CachedBluetoothDeviceManager {
* Search for existing sub device {@link CachedBluetoothDevice}.
*
* @param device the address of the Bluetooth device
- * @return true for found sub device or false.
+ * @return true for found sub / member device or false.
*/
public synchronized boolean isSubDevice(BluetoothDevice device) {
for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
if (!cachedDevice.getDevice().equals(device)) {
- // Check sub devices if it exists
+ // Check the member devices of the coordinated set if it exists
+ Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ if (memberDevice.getDevice().equals(device)) {
+ return true;
+ }
+ }
+ continue;
+ }
+ // Check sub devices of hearing aid if it exists
CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
if (subDevice != null && subDevice.getDevice().equals(device)) {
return true;
@@ -157,6 +193,14 @@ public class CachedBluetoothDeviceManager {
}
/**
+ * Updates the Csip devices; specifically the GroupId's. This routine is called when the
+ * CSIS is connected and the GroupId's are now available.
+ */
+ public synchronized void updateCsipDevices() {
+ mCsipDeviceManager.updateCsipDevices();
+ }
+
+ /**
* Attempts to get the name of a remote device, otherwise returns the address.
*
* @param device The remote device.
@@ -185,6 +229,16 @@ public class CachedBluetoothDeviceManager {
private void clearNonBondedSubDevices() {
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+ final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ // Member device exists and it is not bonded
+ if (memberDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
+ cachedDevice.removeMemberDevice(memberDevice);
+ }
+ }
+ return;
+ }
CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
if (subDevice != null
&& subDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
@@ -201,6 +255,13 @@ public class CachedBluetoothDeviceManager {
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
cachedDevice.setJustDiscovered(false);
+ final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ memberDevice.setJustDiscovered(false);
+ }
+ return;
+ }
final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
if (subDevice != null) {
subDevice.setJustDiscovered(false);
@@ -214,10 +275,19 @@ public class CachedBluetoothDeviceManager {
if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
- CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
- if (subDevice != null) {
- if (subDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
- cachedDevice.setSubDevice(null);
+ final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
+ if (memberDevices != null) {
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ if (memberDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+ cachedDevice.removeMemberDevice(memberDevice);
+ }
+ }
+ } else {
+ CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
+ if (subDevice != null) {
+ if (subDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+ cachedDevice.setSubDevice(null);
+ }
}
}
if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
@@ -229,13 +299,32 @@ public class CachedBluetoothDeviceManager {
}
public synchronized boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice
- cachedDevice, int state) {
- return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
+ cachedDevice, int state, int profileId) {
+ if (profileId == BluetoothProfile.HEARING_AID) {
+ return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
+ state);
+ }
+ if (profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
+ return mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
state);
+ }
+ return false;
}
public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) {
- CachedBluetoothDevice mainDevice = mHearingAidDeviceManager.findMainDevice(device);
+ CachedBluetoothDevice mainDevice = mCsipDeviceManager.findMainDevice(device);
+ final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
+ if (memberDevices != null) {
+ // Main device is unpaired, to unpair the member device
+ for (CachedBluetoothDevice memberDevice : memberDevices) {
+ memberDevice.unpair();
+ device.removeMemberDevice(memberDevice);
+ }
+ } else if (mainDevice != null) {
+ // the member device unpaired, to unpair main device
+ mainDevice.unpair();
+ }
+ mainDevice = mHearingAidDeviceManager.findMainDevice(device);
CachedBluetoothDevice subDevice = device.getSubDevice();
if (subDevice != null) {
// Main device is unpaired, to unpair sub device
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
new file mode 100644
index 000000000000..ebfe0d336a0a
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * CsipDeviceManager manages the set of remote CSIP Bluetooth devices.
+ */
+public class CsipDeviceManager {
+ private static final String TAG = "CsipDeviceManager";
+ private static final boolean DEBUG = BluetoothUtils.D;
+
+ private final LocalBluetoothManager mBtManager;
+ private final List<CachedBluetoothDevice> mCachedDevices;
+
+ CsipDeviceManager(LocalBluetoothManager localBtManager,
+ List<CachedBluetoothDevice> cachedDevices) {
+ mBtManager = localBtManager;
+ mCachedDevices = cachedDevices;
+ };
+
+ void initCsipDeviceIfNeeded(CachedBluetoothDevice newDevice) {
+ // Current it only supports the base uuid for CSIP and group this set in UI.
+ final int groupId = getBaseGroupId(newDevice.getDevice());
+ if (isValidGroupId(groupId)) {
+ log("initCsipDeviceIfNeeded: " + newDevice + " (group: " + groupId + ")");
+ // Once groupId is valid, assign groupId
+ newDevice.setGroupId(groupId);
+ }
+ }
+
+ private int getBaseGroupId(BluetoothDevice device) {
+ final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager();
+ final CsipSetCoordinatorProfile profileProxy = profileManager
+ .getCsipSetCoordinatorProfile();
+ if (profileProxy != null) {
+ final Map<Integer, ParcelUuid> groupIdMap = profileProxy
+ .getGroupUuidMapByDevice(device);
+ if (groupIdMap == null) {
+ return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+ }
+
+ for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
+ if (entry.getValue().equals(BluetoothUuid.BASE_UUID)) {
+ return entry.getKey();
+ }
+ }
+ }
+ return BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+ }
+
+ boolean setMemberDeviceIfNeeded(CachedBluetoothDevice newDevice) {
+ final int groupId = newDevice.getGroupId();
+ if (isValidGroupId(groupId)) {
+ final CachedBluetoothDevice CsipDevice = getCachedDevice(groupId);
+ log("setMemberDeviceIfNeeded, main: " + CsipDevice + ", member: " + newDevice);
+ // Just add one of the coordinated set from a pair in the list that is shown in the UI.
+ // Once there is other devices with the same groupId, to add new device as member
+ // devices.
+ if (CsipDevice != null) {
+ CsipDevice.setMemberDevice(newDevice);
+ newDevice.setName(CsipDevice.getName());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isValidGroupId(int groupId) {
+ return groupId != BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
+ }
+
+ private CachedBluetoothDevice getCachedDevice(int groupId) {
+ for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+ CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+ if (cachedDevice.getGroupId() == groupId) {
+ return cachedDevice;
+ }
+ }
+ return null;
+ }
+
+ // To collect all set member devices and call #onGroupIdChanged to group device by GroupId
+ void updateCsipDevices() {
+ final Set<Integer> newGroupIdSet = new HashSet<Integer>();
+ for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
+ // Do nothing if GroupId has been assigned
+ if (!isValidGroupId(cachedDevice.getGroupId())) {
+ final int newGroupId = getBaseGroupId(cachedDevice.getDevice());
+ // Do nothing if there is no GroupId on Bluetooth device
+ if (isValidGroupId(newGroupId)) {
+ cachedDevice.setGroupId(newGroupId);
+ newGroupIdSet.add(newGroupId);
+ }
+ }
+ }
+ for (int groupId : newGroupIdSet) {
+ onGroupIdChanged(groupId);
+ }
+ }
+
+ // Group devices by groupId
+ @VisibleForTesting
+ void onGroupIdChanged(int groupId) {
+ int firstMatchedIndex = -1;
+ CachedBluetoothDevice mainDevice = null;
+
+ for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+ final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+ if (cachedDevice.getGroupId() != groupId) {
+ continue;
+ }
+
+ if (firstMatchedIndex == -1) {
+ // Found the first one
+ firstMatchedIndex = i;
+ mainDevice = cachedDevice;
+ continue;
+ }
+
+ log("onGroupIdChanged: removed from UI device =" + cachedDevice
+ + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex);
+
+ mainDevice.setMemberDevice(cachedDevice);
+ mCachedDevices.remove(i);
+ mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
+ break;
+ }
+ }
+
+ // @return {@code true}, the event is processed inside the method. It is for updating
+ // le audio device on group relationship when receiving connected or disconnected.
+ // @return {@code false}, it is not le audio device or to process it same as other profiles
+ boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice cachedDevice,
+ int state) {
+ log("onProfileConnectionStateChangedIfProcessed: " + cachedDevice + ", state: " + state);
+ switch (state) {
+ case BluetoothProfile.STATE_CONNECTED:
+ onGroupIdChanged(cachedDevice.getGroupId());
+ CachedBluetoothDevice mainDevice = findMainDevice(cachedDevice);
+ if (mainDevice != null) {
+ if (mainDevice.isConnected()) {
+ // When main device exists and in connected state, receiving member device
+ // connection. To refresh main device UI
+ mainDevice.refresh();
+ return true;
+ } else {
+ // When both LE Audio devices are disconnected, receiving member device
+ // connection. To switch content and dispatch to notify UI change
+ mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice);
+ mainDevice.switchMemberDeviceContent(mainDevice, cachedDevice);
+ mainDevice.refresh();
+ // It is necessary to do remove and add for updating the mapping on
+ // preference and device
+ mBtManager.getEventManager().dispatchDeviceAdded(mainDevice);
+ return true;
+ }
+ }
+ break;
+ case BluetoothProfile.STATE_DISCONNECTED:
+ mainDevice = findMainDevice(cachedDevice);
+ if (mainDevice != null) {
+ // When main device exists, receiving sub device disconnection
+ // To update main device UI
+ mainDevice.refresh();
+ return true;
+ }
+ final Set<CachedBluetoothDevice> memberSet = cachedDevice.getMemberDevice();
+ if (memberSet == null) {
+ break;
+ }
+
+ for (CachedBluetoothDevice device: memberSet) {
+ if (device.isConnected()) {
+ // Main device is disconnected and sub device is connected
+ // To copy data from sub device to main device
+ mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
+ cachedDevice.switchMemberDeviceContent(device, cachedDevice);
+ cachedDevice.refresh();
+ // It is necessary to do remove and add for updating the mapping on
+ // preference and device
+ mBtManager.getEventManager().dispatchDeviceAdded(cachedDevice);
+ return true;
+ }
+ }
+ break;
+ default:
+ // Do not handle this state.
+ }
+ return false;
+ }
+
+ CachedBluetoothDevice findMainDevice(CachedBluetoothDevice device) {
+ if (device == null || mCachedDevices == null) {
+ return null;
+ }
+
+ for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
+ if (isValidGroupId(cachedDevice.getGroupId())) {
+ Set<CachedBluetoothDevice> memberSet = cachedDevice.getMemberDevice();
+ if (memberSet == null) {
+ continue;
+ }
+
+ for (CachedBluetoothDevice memberDevice: memberSet) {
+ if (memberDevice != null && memberDevice.equals(device)) {
+ return cachedDevice;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private void log(String msg) {
+ if (DEBUG) {
+ Log.d(TAG, msg);
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java
index 754914ff794f..6da249c2980e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipSetCoordinatorProfile.java
@@ -26,6 +26,7 @@ import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.os.ParcelUuid;
import android.util.Log;
import androidx.annotation.RequiresApi;
@@ -34,6 +35,7 @@ import com.android.settingslib.R;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
/**
* CSIP Set Coordinator handles Bluetooth CSIP Set Coordinator role profile.
@@ -80,6 +82,7 @@ public class CsipSetCoordinatorProfile implements LocalBluetoothProfile {
device.refresh();
}
+ mDeviceManager.updateCsipDevices();
mProfileManager.callServiceConnectedListeners();
mIsProfileReady = true;
}
@@ -212,6 +215,18 @@ public class CsipSetCoordinatorProfile implements LocalBluetoothProfile {
}
/**
+ * Get the device's groups and correspondsing uuids map.
+ * @param device the bluetooth device
+ * @return Map of groups ids and related UUIDs
+ */
+ public Map<Integer, ParcelUuid> getGroupUuidMapByDevice(BluetoothDevice device) {
+ if (mService == null || device == null) {
+ return null;
+ }
+ return mService.getGroupUuidMapByDevice(device);
+ }
+
+ /**
* Return the profile name as a string.
*/
public String toString() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 25fd430372f2..24113c5a0261 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -318,11 +318,35 @@ public class LocalBluetoothProfileManager {
}
}
}
+
+ if (getCsipSetCoordinatorProfile() != null
+ && mProfile instanceof CsipSetCoordinatorProfile
+ && newState == BluetoothProfile.STATE_CONNECTED) {
+ // Check if the GroupID has being initialized
+ if (cachedDevice.getGroupId() == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ final Map<Integer, ParcelUuid> groupIdMap = getCsipSetCoordinatorProfile()
+ .getGroupUuidMapByDevice(cachedDevice.getDevice());
+ if (groupIdMap != null) {
+ for (Map.Entry<Integer, ParcelUuid> entry: groupIdMap.entrySet()) {
+ if (entry.getValue().equals(BluetoothUuid.BASE_UUID)) {
+ cachedDevice.setGroupId(entry.getKey());
+ break;
+ }
+ }
+ }
+ }
+ }
+
cachedDevice.onProfileStateChanged(mProfile, newState);
// Dispatch profile changed after device update
- if (!(cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
- && mDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
- newState))) {
+ boolean needDispatchProfileConnectionState = true;
+ if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
+ || cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ needDispatchProfileConnectionState = !mDeviceManager
+ .onProfileConnectionStateChangedIfProcessed(cachedDevice, newState,
+ mProfile.getProfileId());
+ }
+ if (needDispatchProfileConnectionState) {
cachedDevice.refresh();
mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
mProfile.getProfileId());
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
index fd5b05311247..4f8fa2fdb96e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java
@@ -206,7 +206,7 @@ public class LocalBluetoothProfileManagerTest {
mContext.sendBroadcast(mIntent);
verify(mDeviceManager).onProfileConnectionStateChangedIfProcessed(mCachedBluetoothDevice,
- BluetoothProfile.STATE_CONNECTED);
+ BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
}
/**