Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +11 −7 Original line number Diff line number Diff line Loading @@ -305,10 +305,11 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> synchronized (mProfileLock) { if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) { for (CachedBluetoothDevice member : getMemberDevice()) { Log.d(TAG, "Disconnect the member(" + member.getAddress() + ")"); Log.d(TAG, "Disconnect the member:" + member); member.disconnect(); } } Log.d(TAG, "Disconnect " + this); mDevice.disconnect(); } // Disconnect PBAP server in case its connected Loading Loading @@ -440,11 +441,11 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> Log.d(TAG, "No profiles. Maybe we will connect later for device " + mDevice); return; } Log.d(TAG, "connect " + this); mDevice.connect(); if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) { for (CachedBluetoothDevice member : getMemberDevice()) { Log.d(TAG, "connect the member(" + member.getAddress() + ")"); Log.d(TAG, "connect the member:" + member); member.connect(); } } Loading Loading @@ -530,7 +531,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } // TODO: do any of these need to run async on a background thread? private void fillData() { void fillData() { updateProfiles(); fetchActiveDevices(); migratePhonebookPermissionChoice(); Loading Loading @@ -933,14 +934,15 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> @Override public String toString() { return "CachedBluetoothDevice (" return "CachedBluetoothDevice{" + "anonymizedAddress=" + mDevice.getAnonymizedAddress() + ", name=" + getName() + ", groupId=" + mGroupId + ")"; + ", member=" + mMemberDevices + "}"; } @Override Loading Loading @@ -1482,6 +1484,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> * Store the member devices that are in the same coordinated set. */ public void addMemberDevice(CachedBluetoothDevice memberDevice) { Log.d(TAG, this + " addMemberDevice = " + memberDevice); mMemberDevices.add(memberDevice); } Loading Loading @@ -1511,13 +1514,14 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> mDevice = newMainDevice.mDevice; mRssi = newMainDevice.mRssi; mJustDiscovered = newMainDevice.mJustDiscovered; fillData(); // Set sub device from backup newMainDevice.release(); newMainDevice.mDevice = tmpDevice; newMainDevice.mRssi = tmpRssi; newMainDevice.mJustDiscovered = tmpJustDiscovered; fetchActiveDevices(); newMainDevice.fillData(); } /** Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java +118 −68 Original line number Diff line number Diff line Loading @@ -153,72 +153,13 @@ public class CsipDeviceManager { return; } log("onGroupIdChanged: mCachedDevices list =" + mCachedDevices.toString()); final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager(); final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager(); final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile(); final BluetoothDevice mainBluetoothDevice = (leAudioProfile != null && isAtLeastT()) ? leAudioProfile.getConnectedGroupLeadDevice(groupId) : null; List<CachedBluetoothDevice> memberDevicesList = getMemberDevicesList(groupId); CachedBluetoothDevice newMainDevice = mainBluetoothDevice != null ? deviceManager.findDevice(mainBluetoothDevice) : null; if (newMainDevice != null) { final CachedBluetoothDevice finalNewMainDevice = newMainDevice; final List<CachedBluetoothDevice> memberDevices = mCachedDevices.stream() .filter(cachedDevice -> !cachedDevice.equals(finalNewMainDevice) && cachedDevice.getGroupId() == groupId) .collect(Collectors.toList()); if (memberDevices == null || memberDevices.isEmpty()) { log("onGroupIdChanged: There is no member device in list."); return; } log("onGroupIdChanged: removed from UI device =" + memberDevices + ", with groupId=" + groupId + " mainDevice= " + newMainDevice); for (CachedBluetoothDevice memberDeviceItem : memberDevices) { Set<CachedBluetoothDevice> memberSet = memberDeviceItem.getMemberDevice(); if (!memberSet.isEmpty()) { log("onGroupIdChanged: Transfer the member list into new main device."); for (CachedBluetoothDevice memberListItem : memberSet) { if (!memberListItem.equals(newMainDevice)) { newMainDevice.addMemberDevice(memberListItem); } } memberSet.clear(); } newMainDevice.addMemberDevice(memberDeviceItem); mCachedDevices.remove(memberDeviceItem); mBtManager.getEventManager().dispatchDeviceRemoved(memberDeviceItem); } if (!mCachedDevices.contains(newMainDevice)) { mCachedDevices.add(newMainDevice); mBtManager.getEventManager().dispatchDeviceAdded(newMainDevice); } } else { log("onGroupIdChanged: There is no main device from the LE profile."); int firstMatchedIndex = -1; for (int i = mCachedDevices.size() - 1; i >= 0; i--) { final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i); if (cachedDevice.getGroupId() != groupId) { continue; } getPreferredMainDeviceWithoutConectionState(groupId, memberDevicesList); if (firstMatchedIndex == -1) { // Found the first one firstMatchedIndex = i; newMainDevice = cachedDevice; continue; } log("onGroupIdChanged: removed from UI device =" + cachedDevice + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex); newMainDevice.addMemberDevice(cachedDevice); mCachedDevices.remove(i); mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice); break; } } log("onGroupIdChanged: The mainDevice= " + newMainDevice + " and the memberDevicesList of groupId= " + groupId + " =" + memberDevicesList); addMemberDevicesIntoMainDevice(memberDevicesList, newMainDevice); } // @return {@code true}, the event is processed inside the method. It is for updating Loading Loading @@ -310,7 +251,6 @@ public class CsipDeviceManager { * Check if the {@code groupId} is existed. * * @param groupId The group id * * @return {@code true}, if we could find a device with this {@code groupId}; Otherwise, * return {@code false}. */ Loading @@ -322,6 +262,116 @@ public class CsipDeviceManager { return false; } private List<CachedBluetoothDevice> getMemberDevicesList(int groupId) { return mCachedDevices.stream() .filter(cacheDevice -> cacheDevice.getGroupId() == groupId) .collect(Collectors.toList()); } private CachedBluetoothDevice getPreferredMainDeviceWithoutConectionState(int groupId, List<CachedBluetoothDevice> memberDevicesList) { // First, priority connected lead device from LE profile // Second, the DUAL mode device which has A2DP/HFP and LE audio // Last, any one of LE device in the list. if (memberDevicesList == null || memberDevicesList.isEmpty()) { return null; } final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager(); final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager(); final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile(); final BluetoothDevice mainBluetoothDevice = (leAudioProfile != null && isAtLeastT()) ? leAudioProfile.getConnectedGroupLeadDevice(groupId) : null; if (mainBluetoothDevice != null) { log("getPreferredMainDevice: The LeadDevice from LE profile is " + mainBluetoothDevice.getAnonymizedAddress()); } // 1st CachedBluetoothDevice newMainDevice = mainBluetoothDevice != null ? deviceManager.findDevice(mainBluetoothDevice) : null; if (newMainDevice != null) { if (newMainDevice.isConnected()) { log("getPreferredMainDevice: The connected LeadDevice from LE profile"); return newMainDevice; } else { log("getPreferredMainDevice: The LeadDevice is not connect."); } } else { log("getPreferredMainDevice: The LeadDevice is not in the all of devices list"); } // 2nd newMainDevice = memberDevicesList.stream() .filter(cachedDevice -> cachedDevice.getConnectableProfiles().stream() .anyMatch(profile -> profile instanceof A2dpProfile || profile instanceof HeadsetProfile)) .findFirst().orElse(null); if (newMainDevice != null) { log("getPreferredMainDevice: The DUAL mode device"); return newMainDevice; } // last if (!memberDevicesList.isEmpty()) { newMainDevice = memberDevicesList.get(0); } return newMainDevice; } private void addMemberDevicesIntoMainDevice(List<CachedBluetoothDevice> memberDevicesList, CachedBluetoothDevice newMainDevice) { if (newMainDevice == null) { log("addMemberDevicesIntoMainDevice: No main device. Do nothing."); return; } if (memberDevicesList.isEmpty()) { log("addMemberDevicesIntoMainDevice: No member device in list. Do nothing."); return; } CachedBluetoothDevice mainDeviceOfNewMainDevice = findMainDevice(newMainDevice); boolean isMemberInOtherMainDevice = mainDeviceOfNewMainDevice != null; if (!memberDevicesList.contains(newMainDevice) && isMemberInOtherMainDevice) { log("addMemberDevicesIntoMainDevice: The 'new main device' is not in list, and it is " + "the member at other device. Do switch main and member."); // To switch content and dispatch to notify UI change mBtManager.getEventManager().dispatchDeviceRemoved(mainDeviceOfNewMainDevice); mainDeviceOfNewMainDevice.switchMemberDeviceContent(newMainDevice); mainDeviceOfNewMainDevice.refresh(); // It is necessary to do remove and add for updating the mapping on // preference and device mBtManager.getEventManager().dispatchDeviceAdded(mainDeviceOfNewMainDevice); } else { log("addMemberDevicesIntoMainDevice: Set new main device"); for (CachedBluetoothDevice memberDeviceItem : memberDevicesList) { if (memberDeviceItem.equals(newMainDevice)) { continue; } Set<CachedBluetoothDevice> memberSet = memberDeviceItem.getMemberDevice(); if (!memberSet.isEmpty()) { for (CachedBluetoothDevice memberSetItem : memberSet) { if (!memberSetItem.equals(newMainDevice)) { newMainDevice.addMemberDevice(memberSetItem); } } memberSet.clear(); } newMainDevice.addMemberDevice(memberDeviceItem); mCachedDevices.remove(memberDeviceItem); mBtManager.getEventManager().dispatchDeviceRemoved(memberDeviceItem); } if (!mCachedDevices.contains(newMainDevice)) { mCachedDevices.add(newMainDevice); mBtManager.getEventManager().dispatchDeviceAdded(newMainDevice); } } log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: " + mCachedDevices); } private void log(String msg) { if (DEBUG) { Log.d(TAG, msg); Loading packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +2 −0 Original line number Diff line number Diff line Loading @@ -1150,9 +1150,11 @@ public class CachedBluetoothDeviceTest { assertThat(mCachedDevice.mRssi).isEqualTo(RSSI_2); assertThat(mCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_2); assertThat(mCachedDevice.mDevice).isEqualTo(mSubDevice); verify(mCachedDevice).fillData(); assertThat(mSubCachedDevice.mRssi).isEqualTo(RSSI_1); assertThat(mSubCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1); assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice); verify(mSubCachedDevice).fillData(); assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue(); } Loading Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +11 −7 Original line number Diff line number Diff line Loading @@ -305,10 +305,11 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> synchronized (mProfileLock) { if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) { for (CachedBluetoothDevice member : getMemberDevice()) { Log.d(TAG, "Disconnect the member(" + member.getAddress() + ")"); Log.d(TAG, "Disconnect the member:" + member); member.disconnect(); } } Log.d(TAG, "Disconnect " + this); mDevice.disconnect(); } // Disconnect PBAP server in case its connected Loading Loading @@ -440,11 +441,11 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> Log.d(TAG, "No profiles. Maybe we will connect later for device " + mDevice); return; } Log.d(TAG, "connect " + this); mDevice.connect(); if (getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) { for (CachedBluetoothDevice member : getMemberDevice()) { Log.d(TAG, "connect the member(" + member.getAddress() + ")"); Log.d(TAG, "connect the member:" + member); member.connect(); } } Loading Loading @@ -530,7 +531,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } // TODO: do any of these need to run async on a background thread? private void fillData() { void fillData() { updateProfiles(); fetchActiveDevices(); migratePhonebookPermissionChoice(); Loading Loading @@ -933,14 +934,15 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> @Override public String toString() { return "CachedBluetoothDevice (" return "CachedBluetoothDevice{" + "anonymizedAddress=" + mDevice.getAnonymizedAddress() + ", name=" + getName() + ", groupId=" + mGroupId + ")"; + ", member=" + mMemberDevices + "}"; } @Override Loading Loading @@ -1482,6 +1484,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> * Store the member devices that are in the same coordinated set. */ public void addMemberDevice(CachedBluetoothDevice memberDevice) { Log.d(TAG, this + " addMemberDevice = " + memberDevice); mMemberDevices.add(memberDevice); } Loading Loading @@ -1511,13 +1514,14 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> mDevice = newMainDevice.mDevice; mRssi = newMainDevice.mRssi; mJustDiscovered = newMainDevice.mJustDiscovered; fillData(); // Set sub device from backup newMainDevice.release(); newMainDevice.mDevice = tmpDevice; newMainDevice.mRssi = tmpRssi; newMainDevice.mJustDiscovered = tmpJustDiscovered; fetchActiveDevices(); newMainDevice.fillData(); } /** Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java +118 −68 Original line number Diff line number Diff line Loading @@ -153,72 +153,13 @@ public class CsipDeviceManager { return; } log("onGroupIdChanged: mCachedDevices list =" + mCachedDevices.toString()); final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager(); final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager(); final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile(); final BluetoothDevice mainBluetoothDevice = (leAudioProfile != null && isAtLeastT()) ? leAudioProfile.getConnectedGroupLeadDevice(groupId) : null; List<CachedBluetoothDevice> memberDevicesList = getMemberDevicesList(groupId); CachedBluetoothDevice newMainDevice = mainBluetoothDevice != null ? deviceManager.findDevice(mainBluetoothDevice) : null; if (newMainDevice != null) { final CachedBluetoothDevice finalNewMainDevice = newMainDevice; final List<CachedBluetoothDevice> memberDevices = mCachedDevices.stream() .filter(cachedDevice -> !cachedDevice.equals(finalNewMainDevice) && cachedDevice.getGroupId() == groupId) .collect(Collectors.toList()); if (memberDevices == null || memberDevices.isEmpty()) { log("onGroupIdChanged: There is no member device in list."); return; } log("onGroupIdChanged: removed from UI device =" + memberDevices + ", with groupId=" + groupId + " mainDevice= " + newMainDevice); for (CachedBluetoothDevice memberDeviceItem : memberDevices) { Set<CachedBluetoothDevice> memberSet = memberDeviceItem.getMemberDevice(); if (!memberSet.isEmpty()) { log("onGroupIdChanged: Transfer the member list into new main device."); for (CachedBluetoothDevice memberListItem : memberSet) { if (!memberListItem.equals(newMainDevice)) { newMainDevice.addMemberDevice(memberListItem); } } memberSet.clear(); } newMainDevice.addMemberDevice(memberDeviceItem); mCachedDevices.remove(memberDeviceItem); mBtManager.getEventManager().dispatchDeviceRemoved(memberDeviceItem); } if (!mCachedDevices.contains(newMainDevice)) { mCachedDevices.add(newMainDevice); mBtManager.getEventManager().dispatchDeviceAdded(newMainDevice); } } else { log("onGroupIdChanged: There is no main device from the LE profile."); int firstMatchedIndex = -1; for (int i = mCachedDevices.size() - 1; i >= 0; i--) { final CachedBluetoothDevice cachedDevice = mCachedDevices.get(i); if (cachedDevice.getGroupId() != groupId) { continue; } getPreferredMainDeviceWithoutConectionState(groupId, memberDevicesList); if (firstMatchedIndex == -1) { // Found the first one firstMatchedIndex = i; newMainDevice = cachedDevice; continue; } log("onGroupIdChanged: removed from UI device =" + cachedDevice + ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex); newMainDevice.addMemberDevice(cachedDevice); mCachedDevices.remove(i); mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice); break; } } log("onGroupIdChanged: The mainDevice= " + newMainDevice + " and the memberDevicesList of groupId= " + groupId + " =" + memberDevicesList); addMemberDevicesIntoMainDevice(memberDevicesList, newMainDevice); } // @return {@code true}, the event is processed inside the method. It is for updating Loading Loading @@ -310,7 +251,6 @@ public class CsipDeviceManager { * Check if the {@code groupId} is existed. * * @param groupId The group id * * @return {@code true}, if we could find a device with this {@code groupId}; Otherwise, * return {@code false}. */ Loading @@ -322,6 +262,116 @@ public class CsipDeviceManager { return false; } private List<CachedBluetoothDevice> getMemberDevicesList(int groupId) { return mCachedDevices.stream() .filter(cacheDevice -> cacheDevice.getGroupId() == groupId) .collect(Collectors.toList()); } private CachedBluetoothDevice getPreferredMainDeviceWithoutConectionState(int groupId, List<CachedBluetoothDevice> memberDevicesList) { // First, priority connected lead device from LE profile // Second, the DUAL mode device which has A2DP/HFP and LE audio // Last, any one of LE device in the list. if (memberDevicesList == null || memberDevicesList.isEmpty()) { return null; } final LocalBluetoothProfileManager profileManager = mBtManager.getProfileManager(); final CachedBluetoothDeviceManager deviceManager = mBtManager.getCachedDeviceManager(); final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile(); final BluetoothDevice mainBluetoothDevice = (leAudioProfile != null && isAtLeastT()) ? leAudioProfile.getConnectedGroupLeadDevice(groupId) : null; if (mainBluetoothDevice != null) { log("getPreferredMainDevice: The LeadDevice from LE profile is " + mainBluetoothDevice.getAnonymizedAddress()); } // 1st CachedBluetoothDevice newMainDevice = mainBluetoothDevice != null ? deviceManager.findDevice(mainBluetoothDevice) : null; if (newMainDevice != null) { if (newMainDevice.isConnected()) { log("getPreferredMainDevice: The connected LeadDevice from LE profile"); return newMainDevice; } else { log("getPreferredMainDevice: The LeadDevice is not connect."); } } else { log("getPreferredMainDevice: The LeadDevice is not in the all of devices list"); } // 2nd newMainDevice = memberDevicesList.stream() .filter(cachedDevice -> cachedDevice.getConnectableProfiles().stream() .anyMatch(profile -> profile instanceof A2dpProfile || profile instanceof HeadsetProfile)) .findFirst().orElse(null); if (newMainDevice != null) { log("getPreferredMainDevice: The DUAL mode device"); return newMainDevice; } // last if (!memberDevicesList.isEmpty()) { newMainDevice = memberDevicesList.get(0); } return newMainDevice; } private void addMemberDevicesIntoMainDevice(List<CachedBluetoothDevice> memberDevicesList, CachedBluetoothDevice newMainDevice) { if (newMainDevice == null) { log("addMemberDevicesIntoMainDevice: No main device. Do nothing."); return; } if (memberDevicesList.isEmpty()) { log("addMemberDevicesIntoMainDevice: No member device in list. Do nothing."); return; } CachedBluetoothDevice mainDeviceOfNewMainDevice = findMainDevice(newMainDevice); boolean isMemberInOtherMainDevice = mainDeviceOfNewMainDevice != null; if (!memberDevicesList.contains(newMainDevice) && isMemberInOtherMainDevice) { log("addMemberDevicesIntoMainDevice: The 'new main device' is not in list, and it is " + "the member at other device. Do switch main and member."); // To switch content and dispatch to notify UI change mBtManager.getEventManager().dispatchDeviceRemoved(mainDeviceOfNewMainDevice); mainDeviceOfNewMainDevice.switchMemberDeviceContent(newMainDevice); mainDeviceOfNewMainDevice.refresh(); // It is necessary to do remove and add for updating the mapping on // preference and device mBtManager.getEventManager().dispatchDeviceAdded(mainDeviceOfNewMainDevice); } else { log("addMemberDevicesIntoMainDevice: Set new main device"); for (CachedBluetoothDevice memberDeviceItem : memberDevicesList) { if (memberDeviceItem.equals(newMainDevice)) { continue; } Set<CachedBluetoothDevice> memberSet = memberDeviceItem.getMemberDevice(); if (!memberSet.isEmpty()) { for (CachedBluetoothDevice memberSetItem : memberSet) { if (!memberSetItem.equals(newMainDevice)) { newMainDevice.addMemberDevice(memberSetItem); } } memberSet.clear(); } newMainDevice.addMemberDevice(memberDeviceItem); mCachedDevices.remove(memberDeviceItem); mBtManager.getEventManager().dispatchDeviceRemoved(memberDeviceItem); } if (!mCachedDevices.contains(newMainDevice)) { mCachedDevices.add(newMainDevice); mBtManager.getEventManager().dispatchDeviceAdded(newMainDevice); } } log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: " + mCachedDevices); } private void log(String msg) { if (DEBUG) { Log.d(TAG, msg); Loading
packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +2 −0 Original line number Diff line number Diff line Loading @@ -1150,9 +1150,11 @@ public class CachedBluetoothDeviceTest { assertThat(mCachedDevice.mRssi).isEqualTo(RSSI_2); assertThat(mCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_2); assertThat(mCachedDevice.mDevice).isEqualTo(mSubDevice); verify(mCachedDevice).fillData(); assertThat(mSubCachedDevice.mRssi).isEqualTo(RSSI_1); assertThat(mSubCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1); assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice); verify(mSubCachedDevice).fillData(); assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue(); } Loading