Update CSIP base uuid devie set into a single device detail preference
Bug: 178981521 Bug: 150670922 Test: pair with two device which are a coordinated set, and make sure the UI only show one device Change-Id: I1a8d570da1af7fa4c8b3a99f8ce69d23b574e96c
This commit is contained in:
@@ -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;
|
||||
@@ -352,8 +353,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,
|
||||
|
||||
@@ -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;
|
||||
@@ -49,7 +50,9 @@ import com.android.settingslib.widget.AdaptiveOutlineDrawable;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -74,6 +77,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
|
||||
@@ -110,6 +114,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
||||
private boolean mIsHearingAidProfileConnectedFail = false;
|
||||
// Group second device for Hearing Aid
|
||||
private CachedBluetoothDevice mSubDevice;
|
||||
// Group member devices for the coordinated set
|
||||
private Set<CachedBluetoothDevice> mMemberDevices = new HashSet<CachedBluetoothDevice>();
|
||||
@VisibleForTesting
|
||||
LruCache<String, BitmapDrawable> mDrawableCache;
|
||||
|
||||
@@ -143,6 +149,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
||||
mDevice = device;
|
||||
fillData();
|
||||
mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
|
||||
mGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
|
||||
initDrawableCache();
|
||||
}
|
||||
|
||||
@@ -340,6 +347,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.
|
||||
@@ -1237,6 +1262,54 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached bluetooth icon with description
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
@@ -156,6 +192,14 @@ public class CachedBluetoothDeviceManager {
|
||||
mHearingAidDeviceManager.updateHearingAidsDevices();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -211,6 +214,18 @@ public class CsipSetCoordinatorProfile implements LocalBluetoothProfile {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -206,7 +206,7 @@ public class LocalBluetoothProfileManagerTest {
|
||||
mContext.sendBroadcast(mIntent);
|
||||
|
||||
verify(mDeviceManager).onProfileConnectionStateChangedIfProcessed(mCachedBluetoothDevice,
|
||||
BluetoothProfile.STATE_CONNECTED);
|
||||
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user