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) {