Three methods for adding hearing aids device into audio switcher.
- Add three methods for subclass to get connected device list
denpending on different profiles.
- Test case for these methods.
Bug: 78142719
Test: make RunSettingsRoboTests ROBOTEST_FILTER="AudioOutputSwitchPreferenceControllerTest" -j28
Change-Id: Ia1367a53ab6a3432878a514490722871ed878954
diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
index 4e9ee4e..43cd29f 100644
--- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java
+++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java
@@ -16,8 +16,12 @@
package com.android.settings.sound;
-
import static android.media.AudioManager.STREAM_DEVICES_CHANGED_ACTION;
+import static android.media.AudioManager.STREAM_MUSIC;
+import static android.media.AudioManager.STREAM_VOICE_CALL;
+import static android.media.AudioSystem.DEVICE_OUT_ALL_A2DP;
+import static android.media.AudioSystem.DEVICE_OUT_ALL_SCO;
+import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
import android.bluetooth.BluetoothDevice;
@@ -43,14 +47,18 @@
import com.android.settings.bluetooth.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.FeatureFlags;
+import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.HeadsetProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -198,6 +206,72 @@
return mAudioManager.getDevicesForStream(streamType) == device;
}
+ protected boolean isOngoingCallStatus() {
+ final int audioMode = mAudioManager.getMode();
+ return audioMode == AudioManager.MODE_RINGTONE
+ || audioMode == AudioManager.MODE_IN_CALL
+ || audioMode == AudioManager.MODE_IN_COMMUNICATION;
+ }
+
+ /**
+ * get hands free profile(HFP) connected device
+ */
+ protected List<BluetoothDevice> getConnectedHfpDevices() {
+ final List<BluetoothDevice> connectedDevices = new ArrayList<>();
+ final HeadsetProfile hfpProfile = mProfileManager.getHeadsetProfile();
+ if (hfpProfile == null) {
+ return connectedDevices;
+ }
+ final List<BluetoothDevice> devices = hfpProfile.getConnectedDevices();
+ for (BluetoothDevice device : devices) {
+ if (device.isConnected()) {
+ connectedDevices.add(device);
+ }
+ }
+ return connectedDevices;
+ }
+
+ /**
+ * get A2dp connected device
+ */
+ protected List<BluetoothDevice> getConnectedA2dpDevices() {
+ final List<BluetoothDevice> connectedDevices = new ArrayList<>();
+ final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
+ if (a2dpProfile == null) {
+ return connectedDevices;
+ }
+ final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices();
+ for (BluetoothDevice device : devices) {
+ if (device.isConnected()) {
+ connectedDevices.add(device);
+ }
+ }
+ return connectedDevices;
+ }
+
+ /**
+ * get hearing aid profile connected device, exclude other devices with same hiSyncId.
+ */
+ protected List<BluetoothDevice> getConnectedHearingAidDevices() {
+ final List<BluetoothDevice> connectedDevices = new ArrayList<>();
+ final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
+ if (hapProfile == null) {
+ return connectedDevices;
+ }
+ final List<Long> devicesHiSyncIds = new ArrayList<>();
+ final List<BluetoothDevice> devices = hapProfile.getConnectedDevices();
+ for (BluetoothDevice device : devices) {
+ final long hiSyncId = hapProfile.getHiSyncId(device);
+ // device with same hiSyncId should not be shown in the UI.
+ // So do not add it into connectedDevices.
+ if (!devicesHiSyncIds.contains(hiSyncId) && device.isConnected()) {
+ devicesHiSyncIds.add(hiSyncId);
+ connectedDevices.add(device);
+ }
+ }
+ return connectedDevices;
+ }
+
int getDefaultDeviceIndex() {
// Default device is after all connected devices.
return ArrayUtils.size(mConnectedDevices);
@@ -261,7 +335,7 @@
mContext.unregisterReceiver(mReceiver);
}
- /** Callback for headset plugged and unplugged events. */
+ /** Notifications of audio device connection and disconnection events. */
private class AudioManagerAudioDeviceCallback extends AudioDeviceCallback {
@Override
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
diff --git a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java
index cc1785b..df65297 100644
--- a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java
@@ -48,7 +48,8 @@
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.BluetoothEventManager;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.HeadsetProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -77,19 +78,24 @@
private static final String TEST_KEY = "Test_Key";
private static final String TEST_DEVICE_NAME_1 = "Test_A2DP_BT_Device_NAME_1";
private static final String TEST_DEVICE_NAME_2 = "Test_A2DP_BT_Device_NAME_2";
- private static final String TEST_DEVICE_ADDRESS_1 = "00:07:80:78:A4:69";
- private static final String TEST_DEVICE_ADDRESS_2 = "00:00:00:00:00:00";
+ private static final String TEST_DEVICE_ADDRESS_1 = "00:A1:A1:A1:A1:A1";
+ private static final String TEST_DEVICE_ADDRESS_2 = "00:B2:B2:B2:B2:B2";
+ private static final String TEST_DEVICE_ADDRESS_3 = "00:C3:C3:C3:C3:C3";
+ private final static long HISYNCID1 = 10;
+ private final static long HISYNCID2 = 11;
@Mock
private LocalBluetoothManager mLocalManager;
@Mock
private BluetoothEventManager mBluetoothEventManager;
@Mock
- private CachedBluetoothDevice mCachedBluetoothDevice;
- @Mock
private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
@Mock
private A2dpProfile mA2dpProfile;
+ @Mock
+ private HeadsetProfile mHeadsetProfile;
+ @Mock
+ private HearingAidProfile mHearingAidProfile;
private Context mContext;
private PreferenceScreen mScreen;
@@ -99,10 +105,13 @@
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothDevice mBluetoothDevice;
- private ShadowBluetoothDevice mShadowBluetoothDevice;
+ private BluetoothDevice mBluetoothHapDevice;
+ private BluetoothDevice mSecondBluetoothHapDevice;
private LocalBluetoothManager mLocalBluetoothManager;
private AudioSwitchPreferenceController mController;
private List<BluetoothDevice> mConnectedDevices;
+ private List<BluetoothDevice> mHearingAidActiveDevices;
+ private List<BluetoothDevice> mEmptyDevices;
@Before
public void setUp() {
@@ -118,20 +127,27 @@
when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
when(mLocalBluetoothProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
+ when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
+ when(mLocalBluetoothProfileManager.getHeadsetProfile()).thenReturn(mHeadsetProfile);
mBluetoothManager = new BluetoothManager(mContext);
mBluetoothAdapter = mBluetoothManager.getAdapter();
- mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_1);
- mShadowBluetoothDevice = Shadows.shadowOf(mBluetoothDevice);
- mShadowBluetoothDevice.setName(TEST_DEVICE_NAME_1);
- when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
+ mBluetoothDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_1));
+ when(mBluetoothDevice.getName()).thenReturn(TEST_DEVICE_NAME_1);
+ when(mBluetoothDevice.isConnected()).thenReturn(true);
+
+ mBluetoothHapDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2));
+ when(mBluetoothHapDevice.isConnected()).thenReturn(true);
+ mSecondBluetoothHapDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_3));
+ when(mSecondBluetoothHapDevice.isConnected()).thenReturn(true);
mController = new AudioSwitchPreferenceControllerTestable(mContext, TEST_KEY);
mScreen = spy(new PreferenceScreen(mContext, null));
mPreference = new ListPreference(mContext);
- mConnectedDevices = new ArrayList<>(1);
- mConnectedDevices.add(mBluetoothDevice);
+ mConnectedDevices = new ArrayList<>(2);
+ mHearingAidActiveDevices = new ArrayList<>(2);
+ mEmptyDevices = new ArrayList<>(2);
when(mScreen.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
when(mScreen.getContext()).thenReturn(mContext);
@@ -179,6 +195,8 @@
@Test
public void onPreferenceChange_toThisDevice_shouldSetDefaultSummary() {
+ mConnectedDevices.clear();
+ mConnectedDevices.add(mBluetoothDevice);
mController.mConnectedDevices = mConnectedDevices;
mController.onPreferenceChange(mPreference,
@@ -194,6 +212,8 @@
*/
@Test
public void onPreferenceChange_toBtDevice_shouldSetBtDeviceName() {
+ mConnectedDevices.clear();
+ mConnectedDevices.add(mBluetoothDevice);
mController.mConnectedDevices = mConnectedDevices;
mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1);
@@ -212,10 +232,10 @@
secondBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2);
shadowBluetoothDevice = Shadows.shadowOf(secondBluetoothDevice);
shadowBluetoothDevice.setName(TEST_DEVICE_NAME_2);
- List<BluetoothDevice> connectedDevices = new ArrayList<>(2);
- connectedDevices.add(mBluetoothDevice);
- connectedDevices.add(secondBluetoothDevice);
- mController.mConnectedDevices = connectedDevices;
+ mConnectedDevices.clear();
+ mConnectedDevices.add(mBluetoothDevice);
+ mConnectedDevices.add(secondBluetoothDevice);
+ mController.mConnectedDevices = mConnectedDevices;
mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_2);
@@ -233,6 +253,112 @@
assertThat(mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1)).isFalse();
}
+ /**
+ * Two hearing aid devices with different HisyncId
+ * getConnectedHearingAidDevices should add both device to list.
+ */
+ @Test
+ public void getConnectedHearingAidDevices_deviceHisyncIdIsDifferent_shouldAddBothToList() {
+ mEmptyDevices.clear();
+ mConnectedDevices.clear();
+ mConnectedDevices.add(mBluetoothHapDevice);
+ mConnectedDevices.add(mSecondBluetoothHapDevice);
+ when(mHearingAidProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
+ when(mHearingAidProfile.getHiSyncId(mBluetoothHapDevice)).thenReturn(HISYNCID1);
+ when(mHearingAidProfile.getHiSyncId(mSecondBluetoothHapDevice)).thenReturn(
+ HISYNCID2);
+
+ mEmptyDevices.addAll(mController.getConnectedHearingAidDevices());
+
+ assertThat(mEmptyDevices).containsExactly(mBluetoothHapDevice, mSecondBluetoothHapDevice);
+ }
+
+ /**
+ * Two hearing aid devices with same HisyncId
+ * getConnectedHearingAidDevices should only add first device to list.
+ */
+ @Test
+ public void getConnectedHearingAidDevices_deviceHisyncIdIsSame_shouldAddOneToList() {
+ mEmptyDevices.clear();
+ mConnectedDevices.clear();
+ mConnectedDevices.add(mBluetoothHapDevice);
+ mConnectedDevices.add(mSecondBluetoothHapDevice);
+ when(mHearingAidProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
+ when(mHearingAidProfile.getHiSyncId(mBluetoothHapDevice)).thenReturn(HISYNCID1);
+ when(mHearingAidProfile.getHiSyncId(mSecondBluetoothHapDevice)).thenReturn(
+ HISYNCID1);
+
+ mEmptyDevices.addAll(mController.getConnectedHearingAidDevices());
+
+ assertThat(mEmptyDevices).containsExactly(mBluetoothHapDevice);
+ }
+
+ /**
+ * One A2dp device is connected.
+ * getConnectedA2dpDevices should add this device to list.
+ */
+ @Test
+ public void getConnectedA2dpDevices_oneConnectedA2dpDevice_shouldAddDeviceToList() {
+ mEmptyDevices.clear();
+ mConnectedDevices.clear();
+ mConnectedDevices.add(mBluetoothDevice);
+ when(mA2dpProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
+
+ mEmptyDevices.addAll(mController.getConnectedA2dpDevices());
+
+ assertThat(mEmptyDevices).containsExactly(mBluetoothDevice);
+ }
+
+ /**
+ * More than one A2dp devices are connected.
+ * getConnectedA2dpDevices should add all devices to list.
+ */
+ @Test
+ public void getConnectedA2dpDevices_moreThanOneConnectedA2dpDevice_shouldAddDeviceToList() {
+ mEmptyDevices.clear();
+ mConnectedDevices.clear();
+ mConnectedDevices.add(mBluetoothDevice);
+ mConnectedDevices.add(mBluetoothHapDevice);
+ when(mA2dpProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
+
+ mEmptyDevices.addAll(mController.getConnectedA2dpDevices());
+
+ assertThat(mEmptyDevices).containsExactly(mBluetoothDevice, mBluetoothHapDevice);
+ }
+
+ /**
+ * One hands free profile device is connected.
+ * getConnectedA2dpDevices should add this device to list.
+ */
+ @Test
+ public void getConnectedHfpDevices_oneConnectedHfpDevice_shouldAddDeviceToList() {
+ mEmptyDevices.clear();
+ mConnectedDevices.clear();
+ mConnectedDevices.add(mBluetoothDevice);
+ when(mHeadsetProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
+
+ mEmptyDevices.addAll(mController.getConnectedHfpDevices());
+
+ assertThat(mEmptyDevices).containsExactly(mBluetoothDevice);
+ }
+
+ /**
+ * More than one hands free profile devices are connected.
+ * getConnectedA2dpDevices should add all devices to list.
+ */
+ @Test
+ public void getConnectedHfpDevices_moreThanOneConnectedHfpDevice_shouldAddDeviceToList() {
+ mEmptyDevices.clear();
+ mConnectedDevices.clear();
+ mConnectedDevices.add(mBluetoothDevice);
+ mConnectedDevices.add(mBluetoothHapDevice);
+ when(mHeadsetProfile.getConnectedDevices()).thenReturn(mConnectedDevices);
+
+ mEmptyDevices.addAll(mController.getConnectedHfpDevices());
+
+ assertThat(mEmptyDevices).containsExactly(mBluetoothDevice, mBluetoothHapDevice);
+ }
+
private class AudioSwitchPreferenceControllerTestable extends
AudioSwitchPreferenceController {
AudioSwitchPreferenceControllerTestable(Context context, String key) {