Loading android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java +29 −11 Original line number Diff line number Diff line Loading @@ -408,12 +408,18 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac } // New connected device: select it as active if (setHearingAidActiveDevice(device)) { final LeAudioService leAudioService = mFactory.getLeAudioService(); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); if (Flags.admVerifyActiveFallbackDevice()) { setLeAudioActiveDevice( null, !leAudioService.getActiveDevices().contains(device)); } else { setLeAudioActiveDevice(null, true); } } } } private void handleLeAudioConnected(BluetoothDevice device) { synchronized (mLock) { Loading Loading @@ -504,7 +510,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac + mA2dpActiveDevice); mA2dpConnectedDevices.remove(device); if (Objects.equals(mA2dpActiveDevice, device)) { if (!setFallbackDeviceActiveLocked()) { if (!setFallbackDeviceActiveLocked(device)) { setA2dpActiveDevice(null, false); } } Loading @@ -521,7 +527,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac if (mHfpConnectedDevices.isEmpty()) { setHfpActiveDevice(null); } setFallbackDeviceActiveLocked(); setFallbackDeviceActiveLocked(device); } } } Loading @@ -536,7 +542,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac + mHearingAidActiveDevices); mHearingAidConnectedDevices.remove(device); if (mHearingAidActiveDevices.remove(device) && mHearingAidActiveDevices.isEmpty()) { if (!setFallbackDeviceActiveLocked()) { if (!setFallbackDeviceActiveLocked(device)) { setHearingAidActiveDevice(null, false); } } Loading @@ -562,7 +568,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac boolean hasFallbackDevice = false; if (Objects.equals(mLeAudioActiveDevice, device)) { hasFallbackDevice = setFallbackDeviceActiveLocked(); hasFallbackDevice = setFallbackDeviceActiveLocked(device); if (!hasFallbackDevice) { setLeAudioActiveDevice(null, false); } Loading Loading @@ -816,7 +822,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac return; } synchronized (mLock) { setFallbackDeviceActiveLocked(); setFallbackDeviceActiveLocked(null); } } } Loading Loading @@ -1043,7 +1049,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac * @return true when the fallback device is activated, false otherwise */ @GuardedBy("mLock") private boolean setFallbackDeviceActiveLocked() { private boolean setFallbackDeviceActiveLocked(BluetoothDevice recentlyRemovedDevice) { Log.d(TAG, "setFallbackDeviceActive"); mDbManager = mAdapterService.getDatabase(); List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>(); Loading @@ -1057,17 +1063,29 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac BluetoothDevice device = mDbManager.getMostRecentlyConnectedDevicesInList(connectedHearingAidDevices); if (device != null) { /* Check if fallback device shall be used. It should be used when a new * device is connected. If the most recently connected device is the same as * recently removed device, it means it just switched profile it is using and is * not new one. */ boolean hasFallbackDevice = true; if (Flags.admVerifyActiveFallbackDevice()) { hasFallbackDevice = !(recentlyRemovedDevice != null && device.equals(recentlyRemovedDevice) && connectedHearingAidDevices.size() == 1); } if (mHearingAidConnectedDevices.contains(device)) { Log.d(TAG, "Found a hearing aid fallback device: " + device); setHearingAidActiveDevice(device); setA2dpActiveDevice(null, true); setA2dpActiveDevice(null, hasFallbackDevice); setHfpActiveDevice(null); setLeAudioActiveDevice(null, true); setLeAudioActiveDevice(null, hasFallbackDevice); } else { Log.d(TAG, "Found a LE hearing aid fallback device: " + device); setLeHearingAidActiveDevice(device); setHearingAidActiveDevice(null, true); setA2dpActiveDevice(null, true); setHearingAidActiveDevice(null, hasFallbackDevice); setA2dpActiveDevice(null, hasFallbackDevice); setHfpActiveDevice(null); } return true; Loading android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java +66 −0 Original line number Diff line number Diff line Loading @@ -1055,6 +1055,72 @@ public class ActiveDeviceManagerTest { verify(mA2dpService).setActiveDevice(mA2dpDevice); } /** * An ASHA device connected and set to active. Same device connected as a LE Audio device. ASHA * disconnects with no fallback and LE Audio is set to active. New LE Audio device is connected * and selected as active. First LE Audio device disconnects with fallback to new one. */ @Test @EnableFlags(Flags.FLAG_ADM_VERIFY_ACTIVE_FALLBACK_DEVICE) public void sameDeviceAsAshaAndLeAudio_noFallbackOnSwitch() { when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL); /* Connect first device as ASHA */ hearingAidConnected(mHearingAidDevice); mTestLooper.dispatchAll(); verify(mHearingAidService).setActiveDevice(mHearingAidDevice); /* Connect first device as LE Audio */ leAudioConnected(mHearingAidDevice); hearingAidDisconnected(mHearingAidDevice); mTestLooper.dispatchAll(); verify(mHearingAidService).removeActiveDevice(false); verify(mLeAudioService).setActiveDevice(mHearingAidDevice); /* Connect second device as LE Audio. First device is disconnected with fallback to * new one. */ leAudioConnected(mLeAudioDevice); leAudioDisconnected(mHearingAidDevice); mTestLooper.dispatchAll(); verify(mLeAudioService).removeActiveDevice(true); verify(mLeAudioService).setActiveDevice(mLeAudioDevice); } /** * A LE Audio device connected and set to active. Same device connected as an ASHA device. LE * Audio disconnects with no fallback and ASHA is set to active. New ASHA device is connected * and selected as active. First ASHA device disconnects with fallback to new one. */ @Test @EnableFlags(Flags.FLAG_ADM_VERIFY_ACTIVE_FALLBACK_DEVICE) public void sameDeviceAsLeAudioAndAsha_noFallbackOnSwitch() { // Turn on the dual mode audio flag so the A2DP won't disconnect LE Audio when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL); List<BluetoothDevice> list = new ArrayList<>(); when(mLeAudioService.getActiveDevices()).thenReturn(list); /* Connect first device as LE Audio */ leAudioConnected(mHearingAidDevice); list.add(mHearingAidDevice); mTestLooper.dispatchAll(); verify(mLeAudioService).setActiveDevice(mHearingAidDevice); /* Connect first device as ASHA */ hearingAidConnected(mHearingAidDevice); leAudioDisconnected(mHearingAidDevice); mTestLooper.dispatchAll(); verify(mHearingAidService).setActiveDevice(mHearingAidDevice); verify(mLeAudioService).removeActiveDevice(false); /* Connect second device as ASHA. It is set as fallback device for LE Audio Service */ hearingAidConnected(mSecondaryAudioDevice); mTestLooper.dispatchAll(); verify(mLeAudioService).removeActiveDevice(true); verify(mHearingAidService).setActiveDevice(mSecondaryAudioDevice); } /** * Two Hearing Aid are connected and the current active is then disconnected. Should then set * active device to fallback device. Loading Loading
android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java +29 −11 Original line number Diff line number Diff line Loading @@ -408,12 +408,18 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac } // New connected device: select it as active if (setHearingAidActiveDevice(device)) { final LeAudioService leAudioService = mFactory.getLeAudioService(); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); if (Flags.admVerifyActiveFallbackDevice()) { setLeAudioActiveDevice( null, !leAudioService.getActiveDevices().contains(device)); } else { setLeAudioActiveDevice(null, true); } } } } private void handleLeAudioConnected(BluetoothDevice device) { synchronized (mLock) { Loading Loading @@ -504,7 +510,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac + mA2dpActiveDevice); mA2dpConnectedDevices.remove(device); if (Objects.equals(mA2dpActiveDevice, device)) { if (!setFallbackDeviceActiveLocked()) { if (!setFallbackDeviceActiveLocked(device)) { setA2dpActiveDevice(null, false); } } Loading @@ -521,7 +527,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac if (mHfpConnectedDevices.isEmpty()) { setHfpActiveDevice(null); } setFallbackDeviceActiveLocked(); setFallbackDeviceActiveLocked(device); } } } Loading @@ -536,7 +542,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac + mHearingAidActiveDevices); mHearingAidConnectedDevices.remove(device); if (mHearingAidActiveDevices.remove(device) && mHearingAidActiveDevices.isEmpty()) { if (!setFallbackDeviceActiveLocked()) { if (!setFallbackDeviceActiveLocked(device)) { setHearingAidActiveDevice(null, false); } } Loading @@ -562,7 +568,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac boolean hasFallbackDevice = false; if (Objects.equals(mLeAudioActiveDevice, device)) { hasFallbackDevice = setFallbackDeviceActiveLocked(); hasFallbackDevice = setFallbackDeviceActiveLocked(device); if (!hasFallbackDevice) { setLeAudioActiveDevice(null, false); } Loading Loading @@ -816,7 +822,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac return; } synchronized (mLock) { setFallbackDeviceActiveLocked(); setFallbackDeviceActiveLocked(null); } } } Loading Loading @@ -1043,7 +1049,7 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac * @return true when the fallback device is activated, false otherwise */ @GuardedBy("mLock") private boolean setFallbackDeviceActiveLocked() { private boolean setFallbackDeviceActiveLocked(BluetoothDevice recentlyRemovedDevice) { Log.d(TAG, "setFallbackDeviceActive"); mDbManager = mAdapterService.getDatabase(); List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>(); Loading @@ -1057,17 +1063,29 @@ public class ActiveDeviceManager implements AdapterService.BluetoothStateCallbac BluetoothDevice device = mDbManager.getMostRecentlyConnectedDevicesInList(connectedHearingAidDevices); if (device != null) { /* Check if fallback device shall be used. It should be used when a new * device is connected. If the most recently connected device is the same as * recently removed device, it means it just switched profile it is using and is * not new one. */ boolean hasFallbackDevice = true; if (Flags.admVerifyActiveFallbackDevice()) { hasFallbackDevice = !(recentlyRemovedDevice != null && device.equals(recentlyRemovedDevice) && connectedHearingAidDevices.size() == 1); } if (mHearingAidConnectedDevices.contains(device)) { Log.d(TAG, "Found a hearing aid fallback device: " + device); setHearingAidActiveDevice(device); setA2dpActiveDevice(null, true); setA2dpActiveDevice(null, hasFallbackDevice); setHfpActiveDevice(null); setLeAudioActiveDevice(null, true); setLeAudioActiveDevice(null, hasFallbackDevice); } else { Log.d(TAG, "Found a LE hearing aid fallback device: " + device); setLeHearingAidActiveDevice(device); setHearingAidActiveDevice(null, true); setA2dpActiveDevice(null, true); setHearingAidActiveDevice(null, hasFallbackDevice); setA2dpActiveDevice(null, hasFallbackDevice); setHfpActiveDevice(null); } return true; Loading
android/app/tests/unit/src/com/android/bluetooth/btservice/ActiveDeviceManagerTest.java +66 −0 Original line number Diff line number Diff line Loading @@ -1055,6 +1055,72 @@ public class ActiveDeviceManagerTest { verify(mA2dpService).setActiveDevice(mA2dpDevice); } /** * An ASHA device connected and set to active. Same device connected as a LE Audio device. ASHA * disconnects with no fallback and LE Audio is set to active. New LE Audio device is connected * and selected as active. First LE Audio device disconnects with fallback to new one. */ @Test @EnableFlags(Flags.FLAG_ADM_VERIFY_ACTIVE_FALLBACK_DEVICE) public void sameDeviceAsAshaAndLeAudio_noFallbackOnSwitch() { when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL); /* Connect first device as ASHA */ hearingAidConnected(mHearingAidDevice); mTestLooper.dispatchAll(); verify(mHearingAidService).setActiveDevice(mHearingAidDevice); /* Connect first device as LE Audio */ leAudioConnected(mHearingAidDevice); hearingAidDisconnected(mHearingAidDevice); mTestLooper.dispatchAll(); verify(mHearingAidService).removeActiveDevice(false); verify(mLeAudioService).setActiveDevice(mHearingAidDevice); /* Connect second device as LE Audio. First device is disconnected with fallback to * new one. */ leAudioConnected(mLeAudioDevice); leAudioDisconnected(mHearingAidDevice); mTestLooper.dispatchAll(); verify(mLeAudioService).removeActiveDevice(true); verify(mLeAudioService).setActiveDevice(mLeAudioDevice); } /** * A LE Audio device connected and set to active. Same device connected as an ASHA device. LE * Audio disconnects with no fallback and ASHA is set to active. New ASHA device is connected * and selected as active. First ASHA device disconnects with fallback to new one. */ @Test @EnableFlags(Flags.FLAG_ADM_VERIFY_ACTIVE_FALLBACK_DEVICE) public void sameDeviceAsLeAudioAndAsha_noFallbackOnSwitch() { // Turn on the dual mode audio flag so the A2DP won't disconnect LE Audio when(mAudioManager.getMode()).thenReturn(AudioManager.MODE_NORMAL); List<BluetoothDevice> list = new ArrayList<>(); when(mLeAudioService.getActiveDevices()).thenReturn(list); /* Connect first device as LE Audio */ leAudioConnected(mHearingAidDevice); list.add(mHearingAidDevice); mTestLooper.dispatchAll(); verify(mLeAudioService).setActiveDevice(mHearingAidDevice); /* Connect first device as ASHA */ hearingAidConnected(mHearingAidDevice); leAudioDisconnected(mHearingAidDevice); mTestLooper.dispatchAll(); verify(mHearingAidService).setActiveDevice(mHearingAidDevice); verify(mLeAudioService).removeActiveDevice(false); /* Connect second device as ASHA. It is set as fallback device for LE Audio Service */ hearingAidConnected(mSecondaryAudioDevice); mTestLooper.dispatchAll(); verify(mLeAudioService).removeActiveDevice(true); verify(mHearingAidService).setActiveDevice(mSecondaryAudioDevice); } /** * Two Hearing Aid are connected and the current active is then disconnected. Should then set * active device to fallback device. Loading