Merge "Update CSIP base uuid devie set into a single device detail preference"
This commit is contained in:
@@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth;
|
|||||||
|
|
||||||
import android.bluetooth.BluetoothA2dp;
|
import android.bluetooth.BluetoothA2dp;
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.bluetooth.BluetoothCsipSetCoordinator;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothHeadset;
|
import android.bluetooth.BluetoothHeadset;
|
||||||
import android.bluetooth.BluetoothHearingAid;
|
import android.bluetooth.BluetoothHearingAid;
|
||||||
@@ -351,8 +352,10 @@ public class BluetoothEventManager {
|
|||||||
cachedDevice.onBondingStateChanged(bondState);
|
cachedDevice.onBondingStateChanged(bondState);
|
||||||
|
|
||||||
if (bondState == BluetoothDevice.BOND_NONE) {
|
if (bondState == BluetoothDevice.BOND_NONE) {
|
||||||
/* Check if we need to remove other Hearing Aid devices */
|
// Check if we need to remove other Coordinated set member devices / Hearing Aid
|
||||||
if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
|
// devices
|
||||||
|
if (cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
|
||||||
|
|| cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
|
||||||
mDeviceManager.onDeviceUnpaired(cachedDevice);
|
mDeviceManager.onDeviceUnpaired(cachedDevice);
|
||||||
}
|
}
|
||||||
int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
|
int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth;
|
|||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothClass;
|
import android.bluetooth.BluetoothClass;
|
||||||
|
import android.bluetooth.BluetoothCsipSetCoordinator;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothHearingAid;
|
import android.bluetooth.BluetoothHearingAid;
|
||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
@@ -41,7 +42,9 @@ import com.android.settingslib.Utils;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,6 +69,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
|||||||
private final Object mProfileLock = new Object();
|
private final Object mProfileLock = new Object();
|
||||||
BluetoothDevice mDevice;
|
BluetoothDevice mDevice;
|
||||||
private long mHiSyncId;
|
private long mHiSyncId;
|
||||||
|
private int mGroupId;
|
||||||
// Need this since there is no method for getting RSSI
|
// Need this since there is no method for getting RSSI
|
||||||
short mRssi;
|
short mRssi;
|
||||||
// mProfiles and mRemovedProfiles does not do swap() between main and sub device. It is
|
// 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 mIsA2dpProfileConnectedFail = false;
|
||||||
private boolean mIsHeadsetProfileConnectedFail = false;
|
private boolean mIsHeadsetProfileConnectedFail = false;
|
||||||
private boolean mIsHearingAidProfileConnectedFail = 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
|
// Group second device for Hearing Aid
|
||||||
private CachedBluetoothDevice mSubDevice;
|
private CachedBluetoothDevice mSubDevice;
|
||||||
|
|
||||||
@@ -133,6 +139,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
|||||||
mDevice = device;
|
mDevice = device;
|
||||||
fillData();
|
fillData();
|
||||||
mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
|
mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
|
||||||
|
mGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -317,6 +324,24 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
|||||||
return mIsCoordinatedSetMember;
|
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() {
|
void onBondingDockConnect() {
|
||||||
// Attempt to connect if UUIDs are available. Otherwise,
|
// Attempt to connect if UUIDs are available. Otherwise,
|
||||||
// we will connect when the ACTION_UUID intent arrives.
|
// we will connect when the ACTION_UUID intent arrives.
|
||||||
@@ -1191,4 +1216,52 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
|
|||||||
mSubDevice.mJustDiscovered = tmpJustDiscovered;
|
mSubDevice.mJustDiscovered = tmpJustDiscovered;
|
||||||
fetchActiveDevices();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.settingslib.bluetooth;
|
|||||||
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
|
* CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
|
||||||
@@ -41,11 +43,14 @@ public class CachedBluetoothDeviceManager {
|
|||||||
final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
|
final List<CachedBluetoothDevice> mCachedDevices = new ArrayList<CachedBluetoothDevice>();
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
HearingAidDeviceManager mHearingAidDeviceManager;
|
HearingAidDeviceManager mHearingAidDeviceManager;
|
||||||
|
@VisibleForTesting
|
||||||
|
CsipDeviceManager mCsipDeviceManager;
|
||||||
|
|
||||||
CachedBluetoothDeviceManager(Context context, LocalBluetoothManager localBtManager) {
|
CachedBluetoothDeviceManager(Context context, LocalBluetoothManager localBtManager) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mBtManager = localBtManager;
|
mBtManager = localBtManager;
|
||||||
mHearingAidDeviceManager = new HearingAidDeviceManager(localBtManager, mCachedDevices);
|
mHearingAidDeviceManager = new HearingAidDeviceManager(localBtManager, mCachedDevices);
|
||||||
|
mCsipDeviceManager = new CsipDeviceManager(localBtManager, mCachedDevices);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
|
public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
|
||||||
@@ -79,7 +84,16 @@ public class CachedBluetoothDeviceManager {
|
|||||||
if (cachedDevice.getDevice().equals(device)) {
|
if (cachedDevice.getDevice().equals(device)) {
|
||||||
return cachedDevice;
|
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();
|
CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
|
||||||
if (subDevice != null && subDevice.getDevice().equals(device)) {
|
if (subDevice != null && subDevice.getDevice().equals(device)) {
|
||||||
return subDevice;
|
return subDevice;
|
||||||
@@ -102,8 +116,10 @@ public class CachedBluetoothDeviceManager {
|
|||||||
newDevice = findDevice(device);
|
newDevice = findDevice(device);
|
||||||
if (newDevice == null) {
|
if (newDevice == null) {
|
||||||
newDevice = new CachedBluetoothDevice(mContext, profileManager, device);
|
newDevice = new CachedBluetoothDevice(mContext, profileManager, device);
|
||||||
|
mCsipDeviceManager.initCsipDeviceIfNeeded(newDevice);
|
||||||
mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(newDevice);
|
mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(newDevice);
|
||||||
if (!mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
|
if (!mCsipDeviceManager.setMemberDeviceIfNeeded(newDevice)
|
||||||
|
&& !mHearingAidDeviceManager.setSubDeviceIfNeeded(newDevice)) {
|
||||||
mCachedDevices.add(newDevice);
|
mCachedDevices.add(newDevice);
|
||||||
mBtManager.getEventManager().dispatchDeviceAdded(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
|
* @param CachedBluetoothDevice device
|
||||||
* @return Device summary, or if the pair does not exist or if it is not a hearing aid,
|
* @return Device summary, or if the pair does not exist or if it is not a hearing aid or
|
||||||
* then {@code null}.
|
* a CSIP set member, then {@code null}.
|
||||||
*/
|
*/
|
||||||
public synchronized String getSubDeviceSummary(CachedBluetoothDevice device) {
|
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();
|
CachedBluetoothDevice subDevice = device.getSubDevice();
|
||||||
if (subDevice != null && subDevice.isConnected()) {
|
if (subDevice != null && subDevice.isConnected()) {
|
||||||
return subDevice.getConnectionSummary();
|
return subDevice.getConnectionSummary();
|
||||||
@@ -132,12 +158,22 @@ public class CachedBluetoothDeviceManager {
|
|||||||
* Search for existing sub device {@link CachedBluetoothDevice}.
|
* Search for existing sub device {@link CachedBluetoothDevice}.
|
||||||
*
|
*
|
||||||
* @param device the address of the Bluetooth device
|
* @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) {
|
public synchronized boolean isSubDevice(BluetoothDevice device) {
|
||||||
for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
|
for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
|
||||||
if (!cachedDevice.getDevice().equals(device)) {
|
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();
|
CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
|
||||||
if (subDevice != null && subDevice.getDevice().equals(device)) {
|
if (subDevice != null && subDevice.getDevice().equals(device)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -156,6 +192,14 @@ public class CachedBluetoothDeviceManager {
|
|||||||
mHearingAidDeviceManager.updateHearingAidsDevices();
|
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.
|
* Attempts to get the name of a remote device, otherwise returns the address.
|
||||||
*
|
*
|
||||||
@@ -185,6 +229,16 @@ public class CachedBluetoothDeviceManager {
|
|||||||
private void clearNonBondedSubDevices() {
|
private void clearNonBondedSubDevices() {
|
||||||
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
|
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
|
||||||
CachedBluetoothDevice cachedDevice = mCachedDevices.get(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();
|
CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
|
||||||
if (subDevice != null
|
if (subDevice != null
|
||||||
&& subDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
|
&& subDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
|
||||||
@@ -201,6 +255,13 @@ public class CachedBluetoothDeviceManager {
|
|||||||
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
|
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
|
||||||
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
|
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
|
||||||
cachedDevice.setJustDiscovered(false);
|
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();
|
final CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
|
||||||
if (subDevice != null) {
|
if (subDevice != null) {
|
||||||
subDevice.setJustDiscovered(false);
|
subDevice.setJustDiscovered(false);
|
||||||
@@ -214,10 +275,19 @@ public class CachedBluetoothDeviceManager {
|
|||||||
if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
|
if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
|
||||||
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
|
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
|
||||||
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
|
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
|
||||||
CachedBluetoothDevice subDevice = cachedDevice.getSubDevice();
|
final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
|
||||||
if (subDevice != null) {
|
if (memberDevices != null) {
|
||||||
if (subDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
|
for (CachedBluetoothDevice memberDevice : memberDevices) {
|
||||||
cachedDevice.setSubDevice(null);
|
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) {
|
if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
|
||||||
@@ -229,13 +299,32 @@ public class CachedBluetoothDeviceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice
|
public synchronized boolean onProfileConnectionStateChangedIfProcessed(CachedBluetoothDevice
|
||||||
cachedDevice, int state) {
|
cachedDevice, int state, int profileId) {
|
||||||
return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
|
if (profileId == BluetoothProfile.HEARING_AID) {
|
||||||
|
return mHearingAidDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
|
||||||
state);
|
state);
|
||||||
|
}
|
||||||
|
if (profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
|
||||||
|
return mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
|
||||||
|
state);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) {
|
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();
|
CachedBluetoothDevice subDevice = device.getSubDevice();
|
||||||
if (subDevice != null) {
|
if (subDevice != null) {
|
||||||
// Main device is unpaired, to unpair sub device
|
// 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.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.ParcelUuid;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
@@ -34,6 +35,7 @@ import com.android.settingslib.R;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CSIP Set Coordinator handles Bluetooth CSIP Set Coordinator role profile.
|
* CSIP Set Coordinator handles Bluetooth CSIP Set Coordinator role profile.
|
||||||
@@ -80,6 +82,7 @@ public class CsipSetCoordinatorProfile implements LocalBluetoothProfile {
|
|||||||
device.refresh();
|
device.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDeviceManager.updateCsipDevices();
|
||||||
mProfileManager.callServiceConnectedListeners();
|
mProfileManager.callServiceConnectedListeners();
|
||||||
mIsProfileReady = true;
|
mIsProfileReady = true;
|
||||||
}
|
}
|
||||||
@@ -211,6 +214,18 @@ public class CsipSetCoordinatorProfile implements LocalBluetoothProfile {
|
|||||||
return 0;
|
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.
|
* 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);
|
cachedDevice.onProfileStateChanged(mProfile, newState);
|
||||||
// Dispatch profile changed after device update
|
// Dispatch profile changed after device update
|
||||||
if (!(cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
|
boolean needDispatchProfileConnectionState = true;
|
||||||
&& mDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
|
if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID
|
||||||
newState))) {
|
|| cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
|
||||||
|
needDispatchProfileConnectionState = !mDeviceManager
|
||||||
|
.onProfileConnectionStateChangedIfProcessed(cachedDevice, newState,
|
||||||
|
mProfile.getProfileId());
|
||||||
|
}
|
||||||
|
if (needDispatchProfileConnectionState) {
|
||||||
cachedDevice.refresh();
|
cachedDevice.refresh();
|
||||||
mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
|
mEventManager.dispatchProfileConnectionStateChanged(cachedDevice, newState,
|
||||||
mProfile.getProfileId());
|
mProfile.getProfileId());
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ public class LocalBluetoothProfileManagerTest {
|
|||||||
mContext.sendBroadcast(mIntent);
|
mContext.sendBroadcast(mIntent);
|
||||||
|
|
||||||
verify(mDeviceManager).onProfileConnectionStateChangedIfProcessed(mCachedBluetoothDevice,
|
verify(mDeviceManager).onProfileConnectionStateChangedIfProcessed(mCachedBluetoothDevice,
|
||||||
BluetoothProfile.STATE_CONNECTED);
|
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.HEARING_AID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user