Loading android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java +42 −7 Original line number Diff line number Diff line Loading @@ -100,6 +100,7 @@ public class CsipSetCoordinatorService extends ProfileService { private final Map<Integer, Integer> mGroupIdToGroupSize = new HashMap<>(); // Tracks the number of available devices mapped to the group id private final Map<Integer, Set<BluetoothDevice>> mGroupIdToConnectedDevices = new HashMap<>(); private final Map<BluetoothDevice, Integer> mFoundSetMemberToGroupId = new HashMap<>(); private final Map<ParcelUuid, Map<Executor, IBluetoothCsipSetCoordinatorCallback>> mCallbacks = new HashMap<>(); private final Map<Integer, Pair<UUID, IBluetoothCsipSetCoordinatorLockCallback>> mLocks = Loading Loading @@ -221,6 +222,7 @@ public class CsipSetCoordinatorService extends ProfileService { mDeviceGroupIdRankMap.clear(); mCallbacks.clear(); mFoundSetMemberToGroupId.clear(); mGroupIdToGroupSize.clear(); mGroupIdToConnectedDevices.clear(); mGroupIdToUuidMap.clear(); Loading Loading @@ -832,6 +834,25 @@ public class CsipSetCoordinatorService extends ProfileService { } } void notifySetMemberAvailable(BluetoothDevice device, int groupId) { if (DBG) { Log.d(TAG, "notifySetMemberAvailable: " + device + ", " + groupId); } /* Sent intent as well */ Intent intent = new Intent(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, groupId); intent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); sendBroadcast(intent, BLUETOOTH_PRIVILEGED); /* Notify registered parties */ handleSetMemberAvailable(device, groupId); } void messageFromNative(CsipSetCoordinatorStackEvent stackEvent) { BluetoothDevice device = stackEvent.device; Log.d(TAG, "Message from native: " + stackEvent); Loading @@ -854,13 +875,12 @@ public class CsipSetCoordinatorService extends ProfileService { } else if (stackEvent.type == CsipSetCoordinatorStackEvent.EVENT_TYPE_SET_MEMBER_AVAILABLE) { Objects.requireNonNull(device, "Device should never be null, event: " + stackEvent); /* Notify registered parties */ handleSetMemberAvailable(device, stackEvent.valueInt1); /* Sent intent as well */ intent = new Intent(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, groupId); if (!mFoundSetMemberToGroupId.containsKey(device)) { mFoundSetMemberToGroupId.put(device, groupId); } if (mGroupIdToConnectedDevices.containsKey(groupId)) { notifySetMemberAvailable(device, groupId); } } else if (stackEvent.type == CsipSetCoordinatorStackEvent.EVENT_TYPE_GROUP_LOCK_CHANGED) { int lock_status = stackEvent.valueInt2; boolean lock_state = stackEvent.valueBool1; Loading Loading @@ -953,6 +973,10 @@ public class CsipSetCoordinatorService extends ProfileService { if (DBG) { Log.d(TAG, "Bond state changed for device: " + device + " state: " + bondState); } if (bondState == BluetoothDevice.BOND_BONDING && mFoundSetMemberToGroupId.containsKey(device)) { mFoundSetMemberToGroupId.remove(device); } // Remove state machine if the bonding for a device is removed if (bondState != BluetoothDevice.BOND_NONE) { Loading Loading @@ -1017,6 +1041,11 @@ public class CsipSetCoordinatorService extends ProfileService { if (!mGroupIdToConnectedDevices.containsKey(groupId)) { mGroupIdToConnectedDevices.put(groupId, new HashSet<>()); } for (Map.Entry<BluetoothDevice, Integer> entry : mFoundSetMemberToGroupId.entrySet()) { if (entry.getValue() == groupId) { notifySetMemberAvailable(entry.getKey(), groupId); } } mGroupIdToConnectedDevices.get(groupId).add(device); disableCsipIfNeeded(groupId); } Loading Loading @@ -1337,5 +1366,11 @@ public class CsipSetCoordinatorService extends ProfileService { for (CsipSetCoordinatorStateMachine sm : mStateMachines.values()) { sm.dump(sb); } ProfileService.println(sb, "mFoundSetMemberToGroupId: "); for (Map.Entry<BluetoothDevice, Integer> entry : mFoundSetMemberToGroupId.entrySet()) { ProfileService.println( sb, " member device: " + entry.getKey() + ", group ID: " + entry.getValue()); } } } android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java +75 −5 Original line number Diff line number Diff line Loading @@ -521,23 +521,93 @@ public class CsipSetCoordinatorServiceTest { } /** * Test that native callback generates proper intent. * Test that native callback generates proper intent after group connected. */ @Test public void testStackEventSetMemberAvailable() { public void testStackEventSetMemberAvailableAfterGroupConnected() { int group_id = 0x01; int group_size = 0x02; long uuidLsb = BluetoothUuid.CAP.getUuid().getLeastSignificantBits(); long uuidMsb = BluetoothUuid.CAP.getUuid().getMostSignificantBits(); // Make sure to use real methods when needed below doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onDeviceAvailable(any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()); doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onConnectionStateChanged(any(byte[].class), anyInt()); doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onSetMemberAvailable(any(byte[].class), anyInt()); mCsipSetCoordinatorNativeInterface.onDeviceAvailable( getByteAddress(mTestDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb); mCsipSetCoordinatorNativeInterface.onConnectionStateChanged( getByteAddress(mTestDevice), BluetoothProfile.STATE_CONNECTED); // Comes from state machine mService.connectionStateChanged(mTestDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED); mCsipSetCoordinatorNativeInterface.onSetMemberAvailable( getByteAddress(mTestDevice), group_id); getByteAddress(mTestDevice2), group_id); Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice)); Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2)); Assert.assertNotNull(intent); Assert.assertEquals( BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE, intent.getAction()); Assert.assertEquals(mTestDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)); Assert.assertEquals(mTestDevice2, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)); Assert.assertEquals( group_id, intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, -1)); } /** * Test that native callback generates proper intent before group connected. */ @Test public void testStackEventSetMemberAvailableBeforeGroupConnected() { int group_id = 0x01; int group_size = 0x02; long uuidLsb = BluetoothUuid.CAP.getUuid().getLeastSignificantBits(); long uuidMsb = BluetoothUuid.CAP.getUuid().getMostSignificantBits(); // Make sure to use real methods when needed below doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onDeviceAvailable(any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()); doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onSetMemberAvailable(any(byte[].class), anyInt()); doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onConnectionStateChanged(any(byte[].class), anyInt()); mCsipSetCoordinatorNativeInterface.onDeviceAvailable( getByteAddress(mTestDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb); mCsipSetCoordinatorNativeInterface.onConnectionStateChanged( getByteAddress(mTestDevice), BluetoothProfile.STATE_CONNECTED); mCsipSetCoordinatorNativeInterface.onSetMemberAvailable( getByteAddress(mTestDevice2), group_id); Intent intent = TestUtils.waitForNoIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2)); Assert.assertNull(intent); // Comes from state machine mService.connectionStateChanged(mTestDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED); intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2)); Assert.assertNotNull(intent); Assert.assertEquals( BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE, intent.getAction()); Assert.assertEquals(mTestDevice2, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)); Assert.assertEquals( group_id, intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, -1)); } Loading Loading
android/app/src/com/android/bluetooth/csip/CsipSetCoordinatorService.java +42 −7 Original line number Diff line number Diff line Loading @@ -100,6 +100,7 @@ public class CsipSetCoordinatorService extends ProfileService { private final Map<Integer, Integer> mGroupIdToGroupSize = new HashMap<>(); // Tracks the number of available devices mapped to the group id private final Map<Integer, Set<BluetoothDevice>> mGroupIdToConnectedDevices = new HashMap<>(); private final Map<BluetoothDevice, Integer> mFoundSetMemberToGroupId = new HashMap<>(); private final Map<ParcelUuid, Map<Executor, IBluetoothCsipSetCoordinatorCallback>> mCallbacks = new HashMap<>(); private final Map<Integer, Pair<UUID, IBluetoothCsipSetCoordinatorLockCallback>> mLocks = Loading Loading @@ -221,6 +222,7 @@ public class CsipSetCoordinatorService extends ProfileService { mDeviceGroupIdRankMap.clear(); mCallbacks.clear(); mFoundSetMemberToGroupId.clear(); mGroupIdToGroupSize.clear(); mGroupIdToConnectedDevices.clear(); mGroupIdToUuidMap.clear(); Loading Loading @@ -832,6 +834,25 @@ public class CsipSetCoordinatorService extends ProfileService { } } void notifySetMemberAvailable(BluetoothDevice device, int groupId) { if (DBG) { Log.d(TAG, "notifySetMemberAvailable: " + device + ", " + groupId); } /* Sent intent as well */ Intent intent = new Intent(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, groupId); intent.addFlags( Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); sendBroadcast(intent, BLUETOOTH_PRIVILEGED); /* Notify registered parties */ handleSetMemberAvailable(device, groupId); } void messageFromNative(CsipSetCoordinatorStackEvent stackEvent) { BluetoothDevice device = stackEvent.device; Log.d(TAG, "Message from native: " + stackEvent); Loading @@ -854,13 +875,12 @@ public class CsipSetCoordinatorService extends ProfileService { } else if (stackEvent.type == CsipSetCoordinatorStackEvent.EVENT_TYPE_SET_MEMBER_AVAILABLE) { Objects.requireNonNull(device, "Device should never be null, event: " + stackEvent); /* Notify registered parties */ handleSetMemberAvailable(device, stackEvent.valueInt1); /* Sent intent as well */ intent = new Intent(BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, groupId); if (!mFoundSetMemberToGroupId.containsKey(device)) { mFoundSetMemberToGroupId.put(device, groupId); } if (mGroupIdToConnectedDevices.containsKey(groupId)) { notifySetMemberAvailable(device, groupId); } } else if (stackEvent.type == CsipSetCoordinatorStackEvent.EVENT_TYPE_GROUP_LOCK_CHANGED) { int lock_status = stackEvent.valueInt2; boolean lock_state = stackEvent.valueBool1; Loading Loading @@ -953,6 +973,10 @@ public class CsipSetCoordinatorService extends ProfileService { if (DBG) { Log.d(TAG, "Bond state changed for device: " + device + " state: " + bondState); } if (bondState == BluetoothDevice.BOND_BONDING && mFoundSetMemberToGroupId.containsKey(device)) { mFoundSetMemberToGroupId.remove(device); } // Remove state machine if the bonding for a device is removed if (bondState != BluetoothDevice.BOND_NONE) { Loading Loading @@ -1017,6 +1041,11 @@ public class CsipSetCoordinatorService extends ProfileService { if (!mGroupIdToConnectedDevices.containsKey(groupId)) { mGroupIdToConnectedDevices.put(groupId, new HashSet<>()); } for (Map.Entry<BluetoothDevice, Integer> entry : mFoundSetMemberToGroupId.entrySet()) { if (entry.getValue() == groupId) { notifySetMemberAvailable(entry.getKey(), groupId); } } mGroupIdToConnectedDevices.get(groupId).add(device); disableCsipIfNeeded(groupId); } Loading Loading @@ -1337,5 +1366,11 @@ public class CsipSetCoordinatorService extends ProfileService { for (CsipSetCoordinatorStateMachine sm : mStateMachines.values()) { sm.dump(sb); } ProfileService.println(sb, "mFoundSetMemberToGroupId: "); for (Map.Entry<BluetoothDevice, Integer> entry : mFoundSetMemberToGroupId.entrySet()) { ProfileService.println( sb, " member device: " + entry.getKey() + ", group ID: " + entry.getValue()); } } }
android/app/tests/unit/src/com/android/bluetooth/csip/CsipSetCoordinatorServiceTest.java +75 −5 Original line number Diff line number Diff line Loading @@ -521,23 +521,93 @@ public class CsipSetCoordinatorServiceTest { } /** * Test that native callback generates proper intent. * Test that native callback generates proper intent after group connected. */ @Test public void testStackEventSetMemberAvailable() { public void testStackEventSetMemberAvailableAfterGroupConnected() { int group_id = 0x01; int group_size = 0x02; long uuidLsb = BluetoothUuid.CAP.getUuid().getLeastSignificantBits(); long uuidMsb = BluetoothUuid.CAP.getUuid().getMostSignificantBits(); // Make sure to use real methods when needed below doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onDeviceAvailable(any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()); doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onConnectionStateChanged(any(byte[].class), anyInt()); doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onSetMemberAvailable(any(byte[].class), anyInt()); mCsipSetCoordinatorNativeInterface.onDeviceAvailable( getByteAddress(mTestDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb); mCsipSetCoordinatorNativeInterface.onConnectionStateChanged( getByteAddress(mTestDevice), BluetoothProfile.STATE_CONNECTED); // Comes from state machine mService.connectionStateChanged(mTestDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED); mCsipSetCoordinatorNativeInterface.onSetMemberAvailable( getByteAddress(mTestDevice), group_id); getByteAddress(mTestDevice2), group_id); Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice)); Intent intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2)); Assert.assertNotNull(intent); Assert.assertEquals( BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE, intent.getAction()); Assert.assertEquals(mTestDevice, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)); Assert.assertEquals(mTestDevice2, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)); Assert.assertEquals( group_id, intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, -1)); } /** * Test that native callback generates proper intent before group connected. */ @Test public void testStackEventSetMemberAvailableBeforeGroupConnected() { int group_id = 0x01; int group_size = 0x02; long uuidLsb = BluetoothUuid.CAP.getUuid().getLeastSignificantBits(); long uuidMsb = BluetoothUuid.CAP.getUuid().getMostSignificantBits(); // Make sure to use real methods when needed below doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onDeviceAvailable(any(byte[].class), anyInt(), anyInt(), anyInt(), anyLong(), anyLong()); doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onSetMemberAvailable(any(byte[].class), anyInt()); doCallRealMethod() .when(mCsipSetCoordinatorNativeInterface) .onConnectionStateChanged(any(byte[].class), anyInt()); mCsipSetCoordinatorNativeInterface.onDeviceAvailable( getByteAddress(mTestDevice), group_id, group_size, 0x02, uuidLsb, uuidMsb); mCsipSetCoordinatorNativeInterface.onConnectionStateChanged( getByteAddress(mTestDevice), BluetoothProfile.STATE_CONNECTED); mCsipSetCoordinatorNativeInterface.onSetMemberAvailable( getByteAddress(mTestDevice2), group_id); Intent intent = TestUtils.waitForNoIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2)); Assert.assertNull(intent); // Comes from state machine mService.connectionStateChanged(mTestDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED); intent = TestUtils.waitForIntent(TIMEOUT_MS, mIntentQueue.get(mTestDevice2)); Assert.assertNotNull(intent); Assert.assertEquals( BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE, intent.getAction()); Assert.assertEquals(mTestDevice2, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)); Assert.assertEquals( group_id, intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID, -1)); } Loading