Loading android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java +42 −28 Original line number Original line Diff line number Diff line Loading @@ -212,6 +212,9 @@ public class HearingAidService extends ProfileService { if (DBG) { if (DBG) { Log.d(TAG, "connect(): " + device); Log.d(TAG, "connect(): " + device); } } if (device == null) { return false; } if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { return false; return false; Loading @@ -222,16 +225,35 @@ public class HearingAidService extends ProfileService { return false; return false; } } long hiSyncId = mDeviceHiSyncIdMap.getOrDefault(device, BluetoothHearingAid.HI_SYNC_ID_INVALID); if (hiSyncId != mActiveDeviceHiSyncId) { for (BluetoothDevice connectedDevice : getConnectedDevices()) { disconnect(connectedDevice); } } for (BluetoothDevice storedDevice : mDeviceHiSyncIdMap.keySet()) { if (mDeviceHiSyncIdMap.getOrDefault(storedDevice, BluetoothHearingAid.HI_SYNC_ID_INVALID) == hiSyncId) { synchronized (mStateMachines) { synchronized (mStateMachines) { HearingAidStateMachine smConnect = getOrCreateStateMachine(device); HearingAidStateMachine sm = getOrCreateStateMachine(storedDevice); if (smConnect == null) { if (sm == null) { Log.e(TAG, "Cannot connect to " + device + " : no state machine"); Log.e(TAG, "Ignored connect request for " + device + " : no state machine"); return false; continue; } } smConnect.sendMessage(HearingAidStateMachine.CONNECT); sm.sendMessage(HearingAidStateMachine.CONNECT); return true; } if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID && !device.equals(storedDevice)) { break; } } } } } return true; } boolean disconnect(BluetoothDevice device) { boolean disconnect(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); Loading @@ -243,32 +265,24 @@ public class HearingAidService extends ProfileService { } } long hiSyncId = mDeviceHiSyncIdMap.getOrDefault(device, long hiSyncId = mDeviceHiSyncIdMap.getOrDefault(device, BluetoothHearingAid.HI_SYNC_ID_INVALID); BluetoothHearingAid.HI_SYNC_ID_INVALID); synchronized (mStateMachines) { HearingAidStateMachine sm = mStateMachines.get(device); if (sm == null) { Log.e(TAG, "Ignored disconnect request for " + device + " : no state machine"); } else { sm.sendMessage(HearingAidStateMachine.DISCONNECT); } } if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID) { return true; } for (BluetoothDevice storedDevice : mDeviceHiSyncIdMap.keySet()) { for (BluetoothDevice storedDevice : mDeviceHiSyncIdMap.keySet()) { if (mDeviceHiSyncIdMap.getOrDefault(storedDevice, if (mDeviceHiSyncIdMap.getOrDefault(storedDevice, BluetoothHearingAid.HI_SYNC_ID_INVALID) != hiSyncId BluetoothHearingAid.HI_SYNC_ID_INVALID) == hiSyncId) { || storedDevice.equals(device)) { continue; } synchronized (mStateMachines) { synchronized (mStateMachines) { HearingAidStateMachine sm = mStateMachines.get(storedDevice); HearingAidStateMachine sm = mStateMachines.get(storedDevice); if (sm == null) { if (sm == null) { Log.e(TAG, "Ignored disconnect request for " + device + " : no state machine"); Log.e(TAG, "Ignored disconnect request for " + device + " : no state machine"); continue; continue; } } sm.sendMessage(HearingAidStateMachine.DISCONNECT); sm.sendMessage(HearingAidStateMachine.DISCONNECT); } } if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID && !device.equals(storedDevice)) { break; } } } } return true; return true; } } Loading android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java +89 −2 Original line number Original line Diff line number Diff line Loading @@ -106,8 +106,8 @@ public class HearingAidServiceTest { // Get a device for testing // Get a device for testing mLeftDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05"); mLeftDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05"); mRightDevice = mAdapter.getRemoteDevice("00:01:02:03:04:06"); mRightDevice = mAdapter.getRemoteDevice("00:01:02:33:44:55"); mSingleDevice = mAdapter.getRemoteDevice("00:01:02:03:04:00"); mSingleDevice = mAdapter.getRemoteDevice("10:11:12:13:14:15"); mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_UNDEFINED); Loading Loading @@ -337,6 +337,93 @@ public class HearingAidServiceTest { mService.getConnectionState(mLeftDevice)); mService.getConnectionState(mLeftDevice)); } } /** * Test that the Hearing Aid Service connects to left and right device at the same time. */ @Test public void testConnectAPair_connectBothDevices() { HearingAidStackEvent connCompletedEvent; // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); // Send a connect request Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mLeftDevice)); verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mRightDevice)); } /** * Test that the service disconnects the current pair before connecting to another pair. */ @Test public void testConnectAnotherPair_disconnectCurrentPair() { HearingAidStackEvent connCompletedEvent; // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_ON); doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); // Send a connect request Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mLeftDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mRightDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); // Verify the connection state broadcast, and that we are in Connected state for right side verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); // Send a connect request for another pair Assert.assertTrue("Connect failed", mService.connect(mSingleDevice)); // Verify the connection state broadcast, and that the first pair is in Disconnecting state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_CONNECTED); verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_CONNECTED); Assert.assertFalse(mService.getConnectedDevices().contains(mLeftDevice)); Assert.assertFalse(mService.getConnectedDevices().contains(mRightDevice)); // Verify the connection state broadcast, and that the second device is in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mSingleDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mSingleDevice)); } /** /** * Test that the outgoing connect/disconnect and audio switch is successful. * Test that the outgoing connect/disconnect and audio switch is successful. */ */ Loading Loading
android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java +42 −28 Original line number Original line Diff line number Diff line Loading @@ -212,6 +212,9 @@ public class HearingAidService extends ProfileService { if (DBG) { if (DBG) { Log.d(TAG, "connect(): " + device); Log.d(TAG, "connect(): " + device); } } if (device == null) { return false; } if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { return false; return false; Loading @@ -222,16 +225,35 @@ public class HearingAidService extends ProfileService { return false; return false; } } long hiSyncId = mDeviceHiSyncIdMap.getOrDefault(device, BluetoothHearingAid.HI_SYNC_ID_INVALID); if (hiSyncId != mActiveDeviceHiSyncId) { for (BluetoothDevice connectedDevice : getConnectedDevices()) { disconnect(connectedDevice); } } for (BluetoothDevice storedDevice : mDeviceHiSyncIdMap.keySet()) { if (mDeviceHiSyncIdMap.getOrDefault(storedDevice, BluetoothHearingAid.HI_SYNC_ID_INVALID) == hiSyncId) { synchronized (mStateMachines) { synchronized (mStateMachines) { HearingAidStateMachine smConnect = getOrCreateStateMachine(device); HearingAidStateMachine sm = getOrCreateStateMachine(storedDevice); if (smConnect == null) { if (sm == null) { Log.e(TAG, "Cannot connect to " + device + " : no state machine"); Log.e(TAG, "Ignored connect request for " + device + " : no state machine"); return false; continue; } } smConnect.sendMessage(HearingAidStateMachine.CONNECT); sm.sendMessage(HearingAidStateMachine.CONNECT); return true; } if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID && !device.equals(storedDevice)) { break; } } } } } return true; } boolean disconnect(BluetoothDevice device) { boolean disconnect(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission"); Loading @@ -243,32 +265,24 @@ public class HearingAidService extends ProfileService { } } long hiSyncId = mDeviceHiSyncIdMap.getOrDefault(device, long hiSyncId = mDeviceHiSyncIdMap.getOrDefault(device, BluetoothHearingAid.HI_SYNC_ID_INVALID); BluetoothHearingAid.HI_SYNC_ID_INVALID); synchronized (mStateMachines) { HearingAidStateMachine sm = mStateMachines.get(device); if (sm == null) { Log.e(TAG, "Ignored disconnect request for " + device + " : no state machine"); } else { sm.sendMessage(HearingAidStateMachine.DISCONNECT); } } if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID) { return true; } for (BluetoothDevice storedDevice : mDeviceHiSyncIdMap.keySet()) { for (BluetoothDevice storedDevice : mDeviceHiSyncIdMap.keySet()) { if (mDeviceHiSyncIdMap.getOrDefault(storedDevice, if (mDeviceHiSyncIdMap.getOrDefault(storedDevice, BluetoothHearingAid.HI_SYNC_ID_INVALID) != hiSyncId BluetoothHearingAid.HI_SYNC_ID_INVALID) == hiSyncId) { || storedDevice.equals(device)) { continue; } synchronized (mStateMachines) { synchronized (mStateMachines) { HearingAidStateMachine sm = mStateMachines.get(storedDevice); HearingAidStateMachine sm = mStateMachines.get(storedDevice); if (sm == null) { if (sm == null) { Log.e(TAG, "Ignored disconnect request for " + device + " : no state machine"); Log.e(TAG, "Ignored disconnect request for " + device + " : no state machine"); continue; continue; } } sm.sendMessage(HearingAidStateMachine.DISCONNECT); sm.sendMessage(HearingAidStateMachine.DISCONNECT); } } if (hiSyncId == BluetoothHearingAid.HI_SYNC_ID_INVALID && !device.equals(storedDevice)) { break; } } } } return true; return true; } } Loading
android/app/tests/unit/src/com/android/bluetooth/hearingaid/HearingAidServiceTest.java +89 −2 Original line number Original line Diff line number Diff line Loading @@ -106,8 +106,8 @@ public class HearingAidServiceTest { // Get a device for testing // Get a device for testing mLeftDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05"); mLeftDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05"); mRightDevice = mAdapter.getRemoteDevice("00:01:02:03:04:06"); mRightDevice = mAdapter.getRemoteDevice("00:01:02:33:44:55"); mSingleDevice = mAdapter.getRemoteDevice("00:01:02:03:04:00"); mSingleDevice = mAdapter.getRemoteDevice("10:11:12:13:14:15"); mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_UNDEFINED); mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_UNDEFINED); Loading Loading @@ -337,6 +337,93 @@ public class HearingAidServiceTest { mService.getConnectionState(mLeftDevice)); mService.getConnectionState(mLeftDevice)); } } /** * Test that the Hearing Aid Service connects to left and right device at the same time. */ @Test public void testConnectAPair_connectBothDevices() { HearingAidStackEvent connCompletedEvent; // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); // Send a connect request Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mLeftDevice)); verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mRightDevice)); } /** * Test that the service disconnects the current pair before connecting to another pair. */ @Test public void testConnectAnotherPair_disconnectCurrentPair() { HearingAidStackEvent connCompletedEvent; // Update the device priority so okToConnect() returns true mService.setPriority(mLeftDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mRightDevice, BluetoothProfile.PRIORITY_ON); mService.setPriority(mSingleDevice, BluetoothProfile.PRIORITY_ON); doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); // Send a connect request Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); // Verify the connection state broadcast, and that we are in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); // Send a message to trigger connection completed connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mLeftDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); connCompletedEvent = new HearingAidStackEvent( HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); connCompletedEvent.device = mRightDevice; connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; mService.messageFromNative(connCompletedEvent); // Verify the connection state broadcast, and that we are in Connected state for right side verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); // Send a connect request for another pair Assert.assertTrue("Connect failed", mService.connect(mSingleDevice)); // Verify the connection state broadcast, and that the first pair is in Disconnecting state verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_CONNECTED); verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_CONNECTED); Assert.assertFalse(mService.getConnectedDevices().contains(mLeftDevice)); Assert.assertFalse(mService.getConnectedDevices().contains(mRightDevice)); // Verify the connection state broadcast, and that the second device is in Connecting state verifyConnectionStateIntent(TIMEOUT_MS, mSingleDevice, BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, mService.getConnectionState(mSingleDevice)); } /** /** * Test that the outgoing connect/disconnect and audio switch is successful. * Test that the outgoing connect/disconnect and audio switch is successful. */ */ Loading