Loading src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java +23 −11 Original line number Diff line number Diff line Loading @@ -450,6 +450,7 @@ public class BluetoothRouteManager extends StateMachine { // Tracks the active devices in the BT stack (HFP or hearing aid). private BluetoothDevice mHfpActiveDeviceCache = null; private BluetoothDevice mHearingAidActiveDeviceCache = null; private BluetoothDevice mMostRecentlyReportedActiveDevice = null; public BluetoothRouteManager(Context context, TelecomSystem.SyncRoot lock, BluetoothDeviceManager deviceManager, Timeouts.Adapter timeoutsAdapter) { Loading Loading @@ -588,6 +589,9 @@ public class BluetoothRouteManager extends StateMachine { } else { mHfpActiveDeviceCache = device; } if (device != null) mMostRecentlyReportedActiveDevice = device; boolean isActiveDevicePresent = mHearingAidActiveDeviceCache != null || mHfpActiveDeviceCache != null; Loading Loading @@ -690,30 +694,38 @@ public class BluetoothRouteManager extends StateMachine { BluetoothHeadsetProxy bluetoothHeadset = mDeviceManager.getHeadsetService(); BluetoothHearingAid bluetoothHearingAid = mDeviceManager.getHearingAidService(); BluetoothDevice hfpActiveDevice = null; BluetoothDevice hearingAidActiveDevice = null; if (bluetoothHeadset == null && bluetoothHearingAid == null) { Log.i(this, "getBluetoothAudioConnectedDevice: no service available."); return null; } if (bluetoothHeadset != null) { for (BluetoothDevice device : bluetoothHeadset.getConnectedDevices()) { boolean isAudioOn = bluetoothHeadset.getAudioState(device) != BluetoothHeadset.STATE_AUDIO_DISCONNECTED; Log.v(this, "isBluetoothAudioConnected: ==> isAudioOn = " + isAudioOn + "for headset: " + device); if (isAudioOn) { return device; } } hfpActiveDevice = bluetoothHeadset.getActiveDevice(); } if (bluetoothHearingAid != null) { for (BluetoothDevice device : bluetoothHearingAid.getActiveDevices()) { if (device != null) { return device; hearingAidActiveDevice = device; break; } } } return null; // Return the active device reported by either HFP or hearing aid. If both are reporting // active devices, go with the most recent one as reported by the receiver. if (hfpActiveDevice != null) { if (hearingAidActiveDevice != null) { Log.i(this, "Both HFP and hearing aid are reporting active devices. Going with" + " the most recently reported active device: %s"); return mMostRecentlyReportedActiveDevice; } return hfpActiveDevice; } return hearingAidActiveDevice; } /** Loading src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java +1 −1 Original line number Diff line number Diff line Loading @@ -136,7 +136,7 @@ public class BluetoothStateReceiver extends BroadcastReceiver { boolean isHearingAid = BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED.equals(intent.getAction()); Log.i(LOG_TAG, "Device %s is now the preferred BT device for %s", device, isHearingAid ? "heading aid" : "HFP"); isHearingAid ? "hearing aid" : "HFP"); mBluetoothRouteManager.onActiveDeviceChanged(device, isHearingAid); if (isHearingAid) { Loading tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java +45 −15 Original line number Diff line number Diff line Loading @@ -38,7 +38,9 @@ import org.junit.runners.JUnit4; import org.mockito.Mock; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; Loading @@ -55,6 +57,7 @@ public class BluetoothRouteManagerTest extends TelecomTestCase { static final BluetoothDevice DEVICE1 = makeBluetoothDevice("00:00:00:00:00:01"); static final BluetoothDevice DEVICE2 = makeBluetoothDevice("00:00:00:00:00:02"); static final BluetoothDevice DEVICE3 = makeBluetoothDevice("00:00:00:00:00:03"); static final BluetoothDevice HEARING_AID_DEVICE = makeBluetoothDevice("00:00:00:00:00:04"); @Mock private BluetoothDeviceManager mDeviceManager; @Mock private BluetoothHeadsetProxy mHeadsetProxy; Loading @@ -73,7 +76,7 @@ public class BluetoothRouteManagerTest extends TelecomTestCase { public void testConnectHfpRetryWhileNotConnected() { BluetoothRouteManager sm = setupStateMachine( BluetoothRouteManager.AUDIO_OFF_STATE_NAME, null); setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null); setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null, null, null); when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis( nullable(ContentResolver.class))).thenReturn(0L); when(mHeadsetProxy.connectAudio()).thenReturn(false); Loading @@ -90,12 +93,31 @@ public class BluetoothRouteManagerTest extends TelecomTestCase { sm.quitNow(); } @SmallTest @Test public void testAmbiguousActiveDevice() { BluetoothRouteManager sm = setupStateMachine( BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1); setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, new BluetoothDevice[]{HEARING_AID_DEVICE}, DEVICE1, HEARING_AID_DEVICE); sm.onActiveDeviceChanged(DEVICE1, false); sm.onActiveDeviceChanged(HEARING_AID_DEVICE, true); executeRoutingAction(sm, BluetoothRouteManager.BT_AUDIO_LOST, DEVICE1.getAddress()); verifyConnectionAttempt(HEARING_AID_DEVICE, 0); verifyConnectionAttempt(DEVICE1, 0); assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX + ":" + HEARING_AID_DEVICE.getAddress(), sm.getCurrentState().getName()); sm.quitNow(); } @SmallTest @Test public void testConnectHfpRetryWhileConnectedToAnotherDevice() { BluetoothRouteManager sm = setupStateMachine( BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1); setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null); setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null, null, null); when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis( nullable(ContentResolver.class))).thenReturn(0L); when(mHeadsetProxy.connectAudio()).thenReturn(false); Loading Loading @@ -127,18 +149,26 @@ public class BluetoothRouteManagerTest extends TelecomTestCase { return sm; } private void setupConnectedDevices(BluetoothDevice[] devices, BluetoothDevice activeDevice) { when(mDeviceManager.getNumConnectedDevices()).thenReturn(devices.length); when(mDeviceManager.getConnectedDevices()).thenReturn(Arrays.asList(devices)); when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices)); when(mHeadsetProxy.getAudioState(any(BluetoothDevice.class))) .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); when(mBluetoothHearingAid.getConnectedDevices()).thenReturn(Collections.emptyList()); when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(null, null)); if (activeDevice != null) { when(mHeadsetProxy.getAudioState(eq(activeDevice))) .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED); } private void setupConnectedDevices(BluetoothDevice[] hfpDevices, BluetoothDevice[] hearingAidDevices, BluetoothDevice hfpActiveDevice, BluetoothDevice hearingAidActiveDevice) { if (hfpDevices == null) hfpDevices = new BluetoothDevice[]{}; if (hearingAidDevices == null) hearingAidDevices = new BluetoothDevice[]{}; when(mDeviceManager.getNumConnectedDevices()).thenReturn( hfpDevices.length + hearingAidDevices.length); List<BluetoothDevice> allDevices = Stream.concat( Arrays.stream(hfpDevices), Arrays.stream(hearingAidDevices)) .collect(Collectors.toList()); when(mDeviceManager.getConnectedDevices()).thenReturn(allDevices); when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(hfpDevices)); when(mHeadsetProxy.getActiveDevice()).thenReturn(hfpActiveDevice); when(mBluetoothHearingAid.getConnectedDevices()) .thenReturn(Arrays.asList(hearingAidDevices)); when(mBluetoothHearingAid.getActiveDevices()) .thenReturn(Arrays.asList(hearingAidActiveDevice, null)); } static void executeRoutingAction(BluetoothRouteManager brm, int message, String Loading tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java +8 −7 Original line number Diff line number Diff line Loading @@ -265,9 +265,8 @@ public class BluetoothRouteTransitionTests extends TelecomTestCase { SomeArgs args = SomeArgs.obtain(); args.arg1 = Log.createSubsession(); args.arg2 = mParams.initialDevice.getAddress(); when(mHeadsetProxy.getActiveDevice()).thenReturn(null); sm.sendMessage(BluetoothRouteManager.BT_AUDIO_LOST, args); when(mHeadsetProxy.getAudioState(eq(mParams.initialDevice))) .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); return true; }).when(mDeviceManager).disconnectAudio(); } Loading @@ -278,9 +277,14 @@ public class BluetoothRouteTransitionTests extends TelecomTestCase { sm.onActiveDeviceChanged(mParams.messageDevice, mParams.hearingAidBtDevices.contains(mParams.messageDevice)); } else if (mParams.messageType == BluetoothRouteManager.LOST_DEVICE) { sm.onDeviceLost(mParams.messageDevice.getAddress()); sm.onActiveDeviceChanged(null, mParams.hearingAidBtDevices.contains(mParams.messageDevice)); if (mParams.hearingAidBtDevices.contains(mParams.messageDevice)) { when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(null, null)); } else { when(mHeadsetProxy.getActiveDevice()).thenReturn(null); } sm.onDeviceLost(mParams.messageDevice.getAddress()); } else { executeRoutingAction(sm, mParams.messageType, mParams.messageDevice == null ? null : mParams.messageDevice.getAddress()); Loading Loading @@ -335,11 +339,8 @@ public class BluetoothRouteTransitionTests extends TelecomTestCase { when(mDeviceManager.getConnectedDevices()).thenReturn(Arrays.asList(devices)); when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices)); when(mHeadsetProxy.getActiveDevice()).thenReturn(activeDevice); when(mHeadsetProxy.getAudioState(any(BluetoothDevice.class))) .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); if (audioOnDevice != null) { when(mHeadsetProxy.getAudioState(eq(audioOnDevice))) .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED); when(mHeadsetProxy.getActiveDevice()).thenReturn(audioOnDevice); } } Loading Loading
src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java +23 −11 Original line number Diff line number Diff line Loading @@ -450,6 +450,7 @@ public class BluetoothRouteManager extends StateMachine { // Tracks the active devices in the BT stack (HFP or hearing aid). private BluetoothDevice mHfpActiveDeviceCache = null; private BluetoothDevice mHearingAidActiveDeviceCache = null; private BluetoothDevice mMostRecentlyReportedActiveDevice = null; public BluetoothRouteManager(Context context, TelecomSystem.SyncRoot lock, BluetoothDeviceManager deviceManager, Timeouts.Adapter timeoutsAdapter) { Loading Loading @@ -588,6 +589,9 @@ public class BluetoothRouteManager extends StateMachine { } else { mHfpActiveDeviceCache = device; } if (device != null) mMostRecentlyReportedActiveDevice = device; boolean isActiveDevicePresent = mHearingAidActiveDeviceCache != null || mHfpActiveDeviceCache != null; Loading Loading @@ -690,30 +694,38 @@ public class BluetoothRouteManager extends StateMachine { BluetoothHeadsetProxy bluetoothHeadset = mDeviceManager.getHeadsetService(); BluetoothHearingAid bluetoothHearingAid = mDeviceManager.getHearingAidService(); BluetoothDevice hfpActiveDevice = null; BluetoothDevice hearingAidActiveDevice = null; if (bluetoothHeadset == null && bluetoothHearingAid == null) { Log.i(this, "getBluetoothAudioConnectedDevice: no service available."); return null; } if (bluetoothHeadset != null) { for (BluetoothDevice device : bluetoothHeadset.getConnectedDevices()) { boolean isAudioOn = bluetoothHeadset.getAudioState(device) != BluetoothHeadset.STATE_AUDIO_DISCONNECTED; Log.v(this, "isBluetoothAudioConnected: ==> isAudioOn = " + isAudioOn + "for headset: " + device); if (isAudioOn) { return device; } } hfpActiveDevice = bluetoothHeadset.getActiveDevice(); } if (bluetoothHearingAid != null) { for (BluetoothDevice device : bluetoothHearingAid.getActiveDevices()) { if (device != null) { return device; hearingAidActiveDevice = device; break; } } } return null; // Return the active device reported by either HFP or hearing aid. If both are reporting // active devices, go with the most recent one as reported by the receiver. if (hfpActiveDevice != null) { if (hearingAidActiveDevice != null) { Log.i(this, "Both HFP and hearing aid are reporting active devices. Going with" + " the most recently reported active device: %s"); return mMostRecentlyReportedActiveDevice; } return hfpActiveDevice; } return hearingAidActiveDevice; } /** Loading
src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java +1 −1 Original line number Diff line number Diff line Loading @@ -136,7 +136,7 @@ public class BluetoothStateReceiver extends BroadcastReceiver { boolean isHearingAid = BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED.equals(intent.getAction()); Log.i(LOG_TAG, "Device %s is now the preferred BT device for %s", device, isHearingAid ? "heading aid" : "HFP"); isHearingAid ? "hearing aid" : "HFP"); mBluetoothRouteManager.onActiveDeviceChanged(device, isHearingAid); if (isHearingAid) { Loading
tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java +45 −15 Original line number Diff line number Diff line Loading @@ -38,7 +38,9 @@ import org.junit.runners.JUnit4; import org.mockito.Mock; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; Loading @@ -55,6 +57,7 @@ public class BluetoothRouteManagerTest extends TelecomTestCase { static final BluetoothDevice DEVICE1 = makeBluetoothDevice("00:00:00:00:00:01"); static final BluetoothDevice DEVICE2 = makeBluetoothDevice("00:00:00:00:00:02"); static final BluetoothDevice DEVICE3 = makeBluetoothDevice("00:00:00:00:00:03"); static final BluetoothDevice HEARING_AID_DEVICE = makeBluetoothDevice("00:00:00:00:00:04"); @Mock private BluetoothDeviceManager mDeviceManager; @Mock private BluetoothHeadsetProxy mHeadsetProxy; Loading @@ -73,7 +76,7 @@ public class BluetoothRouteManagerTest extends TelecomTestCase { public void testConnectHfpRetryWhileNotConnected() { BluetoothRouteManager sm = setupStateMachine( BluetoothRouteManager.AUDIO_OFF_STATE_NAME, null); setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null); setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null, null, null); when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis( nullable(ContentResolver.class))).thenReturn(0L); when(mHeadsetProxy.connectAudio()).thenReturn(false); Loading @@ -90,12 +93,31 @@ public class BluetoothRouteManagerTest extends TelecomTestCase { sm.quitNow(); } @SmallTest @Test public void testAmbiguousActiveDevice() { BluetoothRouteManager sm = setupStateMachine( BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1); setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, new BluetoothDevice[]{HEARING_AID_DEVICE}, DEVICE1, HEARING_AID_DEVICE); sm.onActiveDeviceChanged(DEVICE1, false); sm.onActiveDeviceChanged(HEARING_AID_DEVICE, true); executeRoutingAction(sm, BluetoothRouteManager.BT_AUDIO_LOST, DEVICE1.getAddress()); verifyConnectionAttempt(HEARING_AID_DEVICE, 0); verifyConnectionAttempt(DEVICE1, 0); assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX + ":" + HEARING_AID_DEVICE.getAddress(), sm.getCurrentState().getName()); sm.quitNow(); } @SmallTest @Test public void testConnectHfpRetryWhileConnectedToAnotherDevice() { BluetoothRouteManager sm = setupStateMachine( BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1); setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null); setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null, null, null); when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis( nullable(ContentResolver.class))).thenReturn(0L); when(mHeadsetProxy.connectAudio()).thenReturn(false); Loading Loading @@ -127,18 +149,26 @@ public class BluetoothRouteManagerTest extends TelecomTestCase { return sm; } private void setupConnectedDevices(BluetoothDevice[] devices, BluetoothDevice activeDevice) { when(mDeviceManager.getNumConnectedDevices()).thenReturn(devices.length); when(mDeviceManager.getConnectedDevices()).thenReturn(Arrays.asList(devices)); when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices)); when(mHeadsetProxy.getAudioState(any(BluetoothDevice.class))) .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); when(mBluetoothHearingAid.getConnectedDevices()).thenReturn(Collections.emptyList()); when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(null, null)); if (activeDevice != null) { when(mHeadsetProxy.getAudioState(eq(activeDevice))) .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED); } private void setupConnectedDevices(BluetoothDevice[] hfpDevices, BluetoothDevice[] hearingAidDevices, BluetoothDevice hfpActiveDevice, BluetoothDevice hearingAidActiveDevice) { if (hfpDevices == null) hfpDevices = new BluetoothDevice[]{}; if (hearingAidDevices == null) hearingAidDevices = new BluetoothDevice[]{}; when(mDeviceManager.getNumConnectedDevices()).thenReturn( hfpDevices.length + hearingAidDevices.length); List<BluetoothDevice> allDevices = Stream.concat( Arrays.stream(hfpDevices), Arrays.stream(hearingAidDevices)) .collect(Collectors.toList()); when(mDeviceManager.getConnectedDevices()).thenReturn(allDevices); when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(hfpDevices)); when(mHeadsetProxy.getActiveDevice()).thenReturn(hfpActiveDevice); when(mBluetoothHearingAid.getConnectedDevices()) .thenReturn(Arrays.asList(hearingAidDevices)); when(mBluetoothHearingAid.getActiveDevices()) .thenReturn(Arrays.asList(hearingAidActiveDevice, null)); } static void executeRoutingAction(BluetoothRouteManager brm, int message, String Loading
tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java +8 −7 Original line number Diff line number Diff line Loading @@ -265,9 +265,8 @@ public class BluetoothRouteTransitionTests extends TelecomTestCase { SomeArgs args = SomeArgs.obtain(); args.arg1 = Log.createSubsession(); args.arg2 = mParams.initialDevice.getAddress(); when(mHeadsetProxy.getActiveDevice()).thenReturn(null); sm.sendMessage(BluetoothRouteManager.BT_AUDIO_LOST, args); when(mHeadsetProxy.getAudioState(eq(mParams.initialDevice))) .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); return true; }).when(mDeviceManager).disconnectAudio(); } Loading @@ -278,9 +277,14 @@ public class BluetoothRouteTransitionTests extends TelecomTestCase { sm.onActiveDeviceChanged(mParams.messageDevice, mParams.hearingAidBtDevices.contains(mParams.messageDevice)); } else if (mParams.messageType == BluetoothRouteManager.LOST_DEVICE) { sm.onDeviceLost(mParams.messageDevice.getAddress()); sm.onActiveDeviceChanged(null, mParams.hearingAidBtDevices.contains(mParams.messageDevice)); if (mParams.hearingAidBtDevices.contains(mParams.messageDevice)) { when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(null, null)); } else { when(mHeadsetProxy.getActiveDevice()).thenReturn(null); } sm.onDeviceLost(mParams.messageDevice.getAddress()); } else { executeRoutingAction(sm, mParams.messageType, mParams.messageDevice == null ? null : mParams.messageDevice.getAddress()); Loading Loading @@ -335,11 +339,8 @@ public class BluetoothRouteTransitionTests extends TelecomTestCase { when(mDeviceManager.getConnectedDevices()).thenReturn(Arrays.asList(devices)); when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices)); when(mHeadsetProxy.getActiveDevice()).thenReturn(activeDevice); when(mHeadsetProxy.getAudioState(any(BluetoothDevice.class))) .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); if (audioOnDevice != null) { when(mHeadsetProxy.getAudioState(eq(audioOnDevice))) .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED); when(mHeadsetProxy.getActiveDevice()).thenReturn(audioOnDevice); } } Loading