diff options
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); } /** |