Loading android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java +72 −6 Original line number Diff line number Diff line Loading @@ -117,7 +117,8 @@ class ActiveDeviceManager { private static final int MESSAGE_A2DP_ACTION_ACTIVE_DEVICE_CHANGED = 3; private static final int MESSAGE_HFP_ACTION_CONNECTION_STATE_CHANGED = 4; private static final int MESSAGE_HFP_ACTION_ACTIVE_DEVICE_CHANGED = 5; private static final int MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED = 6; private static final int MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE_CHANGED = 6; private static final int MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED = 7; private static final int MESSAGE_LE_AUDIO_ACTION_CONNECTION_STATE_CHANGED = 8; private static final int MESSAGE_LE_AUDIO_ACTION_ACTIVE_DEVICE_CHANGED = 9; private static final int MESSAGE_HAP_ACTION_CONNECTION_STATE_CHANGED = 10; Loading @@ -132,6 +133,7 @@ class ActiveDeviceManager { private final List<BluetoothDevice> mA2dpConnectedDevices = new LinkedList<>(); private final List<BluetoothDevice> mHfpConnectedDevices = new LinkedList<>(); private final List<BluetoothDevice> mHearingAidConnectedDevices = new LinkedList<>(); private final List<BluetoothDevice> mLeAudioConnectedDevices = new LinkedList<>(); private final List<BluetoothDevice> mLeHearingAidConnectedDevices = new LinkedList<>(); private BluetoothDevice mA2dpActiveDevice = null; Loading Loading @@ -170,6 +172,10 @@ class ActiveDeviceManager { mHandler.obtainMessage(MESSAGE_HFP_ACTION_ACTIVE_DEVICE_CHANGED, intent).sendToTarget(); break; case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED: mHandler.obtainMessage(MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE_CHANGED, intent).sendToTarget(); break; case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED: mHandler.obtainMessage(MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED, intent).sendToTarget(); Loading Loading @@ -243,7 +249,6 @@ class ActiveDeviceManager { // New connected device: select it as active setA2dpActiveDevice(device); setLeAudioActiveDevice(null); break; } break; } Loading Loading @@ -307,7 +312,6 @@ class ActiveDeviceManager { // New connected device: select it as active setHfpActiveDevice(device); setLeAudioActiveDevice(null); break; } break; } Loading Loading @@ -346,6 +350,50 @@ class ActiveDeviceManager { } break; case MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE_CHANGED: { Intent intent = (Intent) msg.obj; BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); int prevState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1); int nextState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); if (prevState == nextState) { // Nothing has changed break; } if (nextState == BluetoothProfile.STATE_CONNECTED) { // Device connected if (DBG) { Log.d(TAG, "handleMessage(MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE" + "_CHANGED): device " + device + " connected"); } if (mHearingAidConnectedDevices.contains(device)) { break; // The device is already connected } mHearingAidConnectedDevices.add(device); // New connected device: select it as active setHearingAidActiveDevice(device); setA2dpActiveDevice(null); setHfpActiveDevice(null); setLeAudioActiveDevice(null); break; } if (prevState == BluetoothProfile.STATE_CONNECTED) { // Device disconnected if (DBG) { Log.d(TAG, "handleMessage(MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE" + "_CHANGED): device " + device + " disconnected"); } mHearingAidConnectedDevices.remove(device); if (Objects.equals(mHearingAidActiveDevice, device)) { if (mHearingAidConnectedDevices.isEmpty()) { setHearingAidActiveDevice(null); } setFallbackDeviceActive(); } } } break; case MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED: { Intent intent = (Intent) msg.obj; BluetoothDevice device = Loading Loading @@ -474,10 +522,12 @@ class ActiveDeviceManager { // mLeAudioConnectedDevices should contain all of // mLeHearingAidConnectedDevices. Call setLeAudioActiveDevice(null) // only if there are no LE audio devices. if (mLeAudioConnectedDevices.isEmpty() && Objects.equals(mLeHearingAidConnectedDevices, device)) { if (Objects.equals(mLeHearingAidConnectedDevices, device)) { if (mLeAudioConnectedDevices.isEmpty()) { setLeAudioActiveDevice(null); } setFallbackDeviceActive(); } } } break; Loading Loading @@ -569,6 +619,7 @@ class ActiveDeviceManager { filter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED); filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED); filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED); filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED); Loading Loading @@ -676,6 +727,21 @@ class ActiveDeviceManager { return; } if (!mHearingAidConnectedDevices.isEmpty()) { BluetoothDevice device = dbManager.getMostRecentlyConnectedDevicesInList(mHearingAidConnectedDevices); if (device != null) { if (DBG) { Log.d(TAG, "set hearing aid device active: " + device); } setHearingAidActiveDevice(device); setA2dpActiveDevice(null); setHfpActiveDevice(null); setLeAudioActiveDevice(null); return; } } A2dpService a2dpService = mFactory.getA2dpService(); BluetoothDevice a2dpFallbackDevice = null; if (a2dpService != null) { Loading android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java +0 −1 Original line number Diff line number Diff line Loading @@ -818,7 +818,6 @@ public class HearingAidService extends ProfileService { BluetoothMetricsProto.ProfileId.HEARING_AID); } if (!mHiSyncIdConnectedMap.getOrDefault(myHiSyncId, false)) { setActiveDevice(device); mHiSyncIdConnectedMap.put(myHiSyncId, true); } } Loading android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java +80 −0 Original line number Diff line number Diff line Loading @@ -525,6 +525,64 @@ public class ActiveDeviceManagerTest { verify(mA2dpService, timeout(TIMEOUT_MS).times(2)).setActiveDevice(mA2dpDevice); } /** * Two Hearing Aid are connected and the current active is then disconnected. * Should then set active device to fallback device. */ @Test public void hearingAidSecondDeviceDisconnected_fallbackDeviceActive() { hearingAidConnected(mSecondaryAudioDevice); verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice); hearingAidConnected(mHearingAidDevice); verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice); leAudioDisconnected(mHearingAidDevice); verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice); } /** * Hearing aid is connected, but active device is different BT. * When the active device is disconnected, the hearing aid should be the active one. */ @Test public void activeDeviceDisconnected_fallbackToHearingAid() { hearingAidConnected(mHearingAidDevice); verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice); leAudioConnected(mLeAudioDevice); a2dpConnected(mA2dpDevice); a2dpActiveDeviceChanged(mA2dpDevice); TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper()); verify(mHearingAidService).setActiveDevice(isNull()); verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice); verify(mA2dpService, never()).setActiveDevice(mA2dpDevice); when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL); when(mDatabaseManager.getMostRecentlyConnectedDevicesInList(any())).thenAnswer( invocation -> { List<BluetoothDevice> devices = invocation.getArgument(0); if (devices == null) { return null; } else if (devices.contains(mA2dpDevice)) { return mA2dpDevice; } else if (devices.contains(mLeAudioDevice)) { return mLeAudioDevice; } else if (devices.contains(mHearingAidDevice)) { return mHearingAidDevice; } else { return devices.get(0); } } ); a2dpDisconnected(mA2dpDevice); verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(isNull()); verify(mHearingAidService, timeout(TIMEOUT_MS).times(2)) .setActiveDevice(mHearingAidDevice); } /** * One LE Hearing Aid is connected. */ Loading Loading @@ -626,6 +684,28 @@ public class ActiveDeviceManagerTest { mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent); } /** * Helper to indicate Hearing Aid connected for a device. */ private void hearingAidConnected(BluetoothDevice device) { Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_DISCONNECTED); intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED); mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent); } /** * Helper to indicate Hearing Aid disconnected for a device. */ private void hearingAidDisconnected(BluetoothDevice device) { Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTED); intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED); mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent); } /** * Helper to indicate Hearing Aid active device changed for a device. */ Loading Loading
android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java +72 −6 Original line number Diff line number Diff line Loading @@ -117,7 +117,8 @@ class ActiveDeviceManager { private static final int MESSAGE_A2DP_ACTION_ACTIVE_DEVICE_CHANGED = 3; private static final int MESSAGE_HFP_ACTION_CONNECTION_STATE_CHANGED = 4; private static final int MESSAGE_HFP_ACTION_ACTIVE_DEVICE_CHANGED = 5; private static final int MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED = 6; private static final int MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE_CHANGED = 6; private static final int MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED = 7; private static final int MESSAGE_LE_AUDIO_ACTION_CONNECTION_STATE_CHANGED = 8; private static final int MESSAGE_LE_AUDIO_ACTION_ACTIVE_DEVICE_CHANGED = 9; private static final int MESSAGE_HAP_ACTION_CONNECTION_STATE_CHANGED = 10; Loading @@ -132,6 +133,7 @@ class ActiveDeviceManager { private final List<BluetoothDevice> mA2dpConnectedDevices = new LinkedList<>(); private final List<BluetoothDevice> mHfpConnectedDevices = new LinkedList<>(); private final List<BluetoothDevice> mHearingAidConnectedDevices = new LinkedList<>(); private final List<BluetoothDevice> mLeAudioConnectedDevices = new LinkedList<>(); private final List<BluetoothDevice> mLeHearingAidConnectedDevices = new LinkedList<>(); private BluetoothDevice mA2dpActiveDevice = null; Loading Loading @@ -170,6 +172,10 @@ class ActiveDeviceManager { mHandler.obtainMessage(MESSAGE_HFP_ACTION_ACTIVE_DEVICE_CHANGED, intent).sendToTarget(); break; case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED: mHandler.obtainMessage(MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE_CHANGED, intent).sendToTarget(); break; case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED: mHandler.obtainMessage(MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED, intent).sendToTarget(); Loading Loading @@ -243,7 +249,6 @@ class ActiveDeviceManager { // New connected device: select it as active setA2dpActiveDevice(device); setLeAudioActiveDevice(null); break; } break; } Loading Loading @@ -307,7 +312,6 @@ class ActiveDeviceManager { // New connected device: select it as active setHfpActiveDevice(device); setLeAudioActiveDevice(null); break; } break; } Loading Loading @@ -346,6 +350,50 @@ class ActiveDeviceManager { } break; case MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE_CHANGED: { Intent intent = (Intent) msg.obj; BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); int prevState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, -1); int nextState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); if (prevState == nextState) { // Nothing has changed break; } if (nextState == BluetoothProfile.STATE_CONNECTED) { // Device connected if (DBG) { Log.d(TAG, "handleMessage(MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE" + "_CHANGED): device " + device + " connected"); } if (mHearingAidConnectedDevices.contains(device)) { break; // The device is already connected } mHearingAidConnectedDevices.add(device); // New connected device: select it as active setHearingAidActiveDevice(device); setA2dpActiveDevice(null); setHfpActiveDevice(null); setLeAudioActiveDevice(null); break; } if (prevState == BluetoothProfile.STATE_CONNECTED) { // Device disconnected if (DBG) { Log.d(TAG, "handleMessage(MESSAGE_HEARING_AID_ACTION_CONNECTION_STATE" + "_CHANGED): device " + device + " disconnected"); } mHearingAidConnectedDevices.remove(device); if (Objects.equals(mHearingAidActiveDevice, device)) { if (mHearingAidConnectedDevices.isEmpty()) { setHearingAidActiveDevice(null); } setFallbackDeviceActive(); } } } break; case MESSAGE_HEARING_AID_ACTION_ACTIVE_DEVICE_CHANGED: { Intent intent = (Intent) msg.obj; BluetoothDevice device = Loading Loading @@ -474,10 +522,12 @@ class ActiveDeviceManager { // mLeAudioConnectedDevices should contain all of // mLeHearingAidConnectedDevices. Call setLeAudioActiveDevice(null) // only if there are no LE audio devices. if (mLeAudioConnectedDevices.isEmpty() && Objects.equals(mLeHearingAidConnectedDevices, device)) { if (Objects.equals(mLeHearingAidConnectedDevices, device)) { if (mLeAudioConnectedDevices.isEmpty()) { setLeAudioActiveDevice(null); } setFallbackDeviceActive(); } } } break; Loading Loading @@ -569,6 +619,7 @@ class ActiveDeviceManager { filter.addAction(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED); filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED); filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED); filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED); Loading Loading @@ -676,6 +727,21 @@ class ActiveDeviceManager { return; } if (!mHearingAidConnectedDevices.isEmpty()) { BluetoothDevice device = dbManager.getMostRecentlyConnectedDevicesInList(mHearingAidConnectedDevices); if (device != null) { if (DBG) { Log.d(TAG, "set hearing aid device active: " + device); } setHearingAidActiveDevice(device); setA2dpActiveDevice(null); setHfpActiveDevice(null); setLeAudioActiveDevice(null); return; } } A2dpService a2dpService = mFactory.getA2dpService(); BluetoothDevice a2dpFallbackDevice = null; if (a2dpService != null) { Loading
android/app/src/com/android/bluetooth/hearingaid/HearingAidService.java +0 −1 Original line number Diff line number Diff line Loading @@ -818,7 +818,6 @@ public class HearingAidService extends ProfileService { BluetoothMetricsProto.ProfileId.HEARING_AID); } if (!mHiSyncIdConnectedMap.getOrDefault(myHiSyncId, false)) { setActiveDevice(device); mHiSyncIdConnectedMap.put(myHiSyncId, true); } } Loading
android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java +80 −0 Original line number Diff line number Diff line Loading @@ -525,6 +525,64 @@ public class ActiveDeviceManagerTest { verify(mA2dpService, timeout(TIMEOUT_MS).times(2)).setActiveDevice(mA2dpDevice); } /** * Two Hearing Aid are connected and the current active is then disconnected. * Should then set active device to fallback device. */ @Test public void hearingAidSecondDeviceDisconnected_fallbackDeviceActive() { hearingAidConnected(mSecondaryAudioDevice); verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice); hearingAidConnected(mHearingAidDevice); verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice); leAudioDisconnected(mHearingAidDevice); verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mSecondaryAudioDevice); } /** * Hearing aid is connected, but active device is different BT. * When the active device is disconnected, the hearing aid should be the active one. */ @Test public void activeDeviceDisconnected_fallbackToHearingAid() { hearingAidConnected(mHearingAidDevice); verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(mHearingAidDevice); leAudioConnected(mLeAudioDevice); a2dpConnected(mA2dpDevice); a2dpActiveDeviceChanged(mA2dpDevice); TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper()); verify(mHearingAidService).setActiveDevice(isNull()); verify(mLeAudioService, never()).setActiveDevice(mLeAudioDevice); verify(mA2dpService, never()).setActiveDevice(mA2dpDevice); when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL); when(mDatabaseManager.getMostRecentlyConnectedDevicesInList(any())).thenAnswer( invocation -> { List<BluetoothDevice> devices = invocation.getArgument(0); if (devices == null) { return null; } else if (devices.contains(mA2dpDevice)) { return mA2dpDevice; } else if (devices.contains(mLeAudioDevice)) { return mLeAudioDevice; } else if (devices.contains(mHearingAidDevice)) { return mHearingAidDevice; } else { return devices.get(0); } } ); a2dpDisconnected(mA2dpDevice); verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(isNull()); verify(mHearingAidService, timeout(TIMEOUT_MS).times(2)) .setActiveDevice(mHearingAidDevice); } /** * One LE Hearing Aid is connected. */ Loading Loading @@ -626,6 +684,28 @@ public class ActiveDeviceManagerTest { mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent); } /** * Helper to indicate Hearing Aid connected for a device. */ private void hearingAidConnected(BluetoothDevice device) { Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_DISCONNECTED); intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED); mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent); } /** * Helper to indicate Hearing Aid disconnected for a device. */ private void hearingAidDisconnected(BluetoothDevice device) { Intent intent = new Intent(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTED); intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED); mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent); } /** * Helper to indicate Hearing Aid active device changed for a device. */ Loading