1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.sound;
18 
19 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
20 import static android.media.AudioSystem.STREAM_MUSIC;
21 
22 import static com.android.settings.core.BasePreferenceController.AVAILABLE;
23 import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
24 import static com.android.settingslib.media.flags.Flags.FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING;
25 
26 import static com.google.common.truth.Truth.assertThat;
27 
28 import static org.mockito.ArgumentMatchers.any;
29 import static org.mockito.ArgumentMatchers.eq;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.spy;
32 import static org.mockito.Mockito.verify;
33 import static org.mockito.Mockito.when;
34 
35 import android.bluetooth.BluetoothAdapter;
36 import android.bluetooth.BluetoothDevice;
37 import android.bluetooth.BluetoothManager;
38 import android.content.BroadcastReceiver;
39 import android.content.Context;
40 import android.content.IntentFilter;
41 import android.content.pm.PackageManager;
42 import android.media.AudioManager;
43 import android.media.session.MediaSessionManager;
44 import android.platform.test.flag.junit.SetFlagsRule;
45 import android.util.FeatureFlagUtils;
46 
47 import androidx.preference.ListPreference;
48 import androidx.preference.PreferenceManager;
49 import androidx.preference.PreferenceScreen;
50 
51 import com.android.settings.bluetooth.Utils;
52 import com.android.settings.core.FeatureFlags;
53 import com.android.settings.testutils.shadow.ShadowAudioManager;
54 import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
55 import com.android.settingslib.bluetooth.A2dpProfile;
56 import com.android.settingslib.bluetooth.BluetoothCallback;
57 import com.android.settingslib.bluetooth.BluetoothEventManager;
58 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
59 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
60 import com.android.settingslib.bluetooth.HeadsetProfile;
61 import com.android.settingslib.bluetooth.HearingAidProfile;
62 import com.android.settingslib.bluetooth.LeAudioProfile;
63 import com.android.settingslib.bluetooth.LocalBluetoothManager;
64 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
65 
66 import org.junit.After;
67 import org.junit.Before;
68 import org.junit.Rule;
69 import org.junit.Test;
70 import org.junit.runner.RunWith;
71 import org.mockito.Mock;
72 import org.mockito.MockitoAnnotations;
73 import org.robolectric.RobolectricTestRunner;
74 import org.robolectric.RuntimeEnvironment;
75 import org.robolectric.annotation.Config;
76 import org.robolectric.shadow.api.Shadow;
77 import org.robolectric.shadows.ShadowBluetoothDevice;
78 import org.robolectric.shadows.ShadowPackageManager;
79 
80 import java.util.ArrayList;
81 import java.util.Collection;
82 import java.util.List;
83 
84 @RunWith(RobolectricTestRunner.class)
85 @Config(shadows = {
86         ShadowAudioManager.class,
87         ShadowBluetoothUtils.class,
88         ShadowBluetoothDevice.class}
89 )
90 public class AudioOutputSwitchPreferenceControllerTest {
91     private static final String TEST_KEY = "Test_Key";
92     private static final String TEST_DEVICE_NAME_1 = "Test_A2DP_BT_Device_NAME_1";
93     private static final String TEST_DEVICE_NAME_2 = "Test_A2DP_BT_Device_NAME_2";
94     private static final String TEST_DEVICE_ADDRESS_1 = "00:A1:A1:A1:A1:A1";
95     private static final String TEST_DEVICE_ADDRESS_2 = "00:B2:B2:B2:B2:B2";
96     private static final String TEST_DEVICE_ADDRESS_3 = "00:C3:C3:C3:C3:C3";
97     private final static long HISYNCID1 = 10;
98     private final static long HISYNCID2 = 11;
99 
100     @Mock
101     private LocalBluetoothManager mLocalManager;
102     @Mock
103     private BluetoothEventManager mBluetoothEventManager;
104     @Mock
105     private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
106     @Mock
107     private A2dpProfile mA2dpProfile;
108     @Mock
109     private HeadsetProfile mHeadsetProfile;
110     @Mock
111     private HearingAidProfile mHearingAidProfile;
112     @Mock
113     private LeAudioProfile mLeAudioProfile;
114     @Mock
115     private CachedBluetoothDeviceManager mCachedDeviceManager;
116     @Mock
117     private CachedBluetoothDevice mCachedBluetoothDeviceL;
118     @Mock
119     private CachedBluetoothDevice mCachedBluetoothDeviceR;
120 
121     @Rule
122     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
123 
124     private Context mContext;
125     private PreferenceScreen mScreen;
126     private ListPreference mPreference;
127     private AudioManager mAudioManager;
128     private ShadowAudioManager mShadowAudioManager;
129     private BluetoothManager mBluetoothManager;
130     private BluetoothAdapter mBluetoothAdapter;
131     private BluetoothDevice mBluetoothDevice;
132     private BluetoothDevice mLeftBluetoothHapDevice;
133     private BluetoothDevice mRightBluetoothHapDevice;
134     private LocalBluetoothManager mLocalBluetoothManager;
135     private AudioSwitchPreferenceController mController;
136     private List<BluetoothDevice> mProfileConnectedDevices;
137     private List<BluetoothDevice> mHearingAidActiveDevices;
138     private List<BluetoothDevice> mLeAudioActiveDevices;
139     private List<BluetoothDevice> mEmptyDevices;
140     private ShadowPackageManager mPackageManager;
141     private Collection<CachedBluetoothDevice> mCachedDevices;
142 
143     @Before
setUp()144     public void setUp() {
145         MockitoAnnotations.initMocks(this);
146         mContext = spy(RuntimeEnvironment.application);
147 
148         mAudioManager = mContext.getSystemService(AudioManager.class);
149         mShadowAudioManager = ShadowAudioManager.getShadow();
150 
151         ShadowBluetoothUtils.sLocalBluetoothManager = mLocalManager;
152         mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
153 
154         when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
155         when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
156         when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
157         when(mLocalBluetoothProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
158         when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
159         when(mLocalBluetoothProfileManager.getHeadsetProfile()).thenReturn(mHeadsetProfile);
160         when(mLocalBluetoothProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
161         mPackageManager = Shadow.extract(mContext.getPackageManager());
162         mPackageManager.setSystemFeature(PackageManager.FEATURE_BLUETOOTH, true);
163 
164         mBluetoothManager = mContext.getSystemService(BluetoothManager.class);
165         mBluetoothAdapter = mBluetoothManager.getAdapter();
166 
167         mCachedDevices = new ArrayList<>();
168         mCachedDevices.add(mCachedBluetoothDeviceL);
169         mCachedDevices.add(mCachedBluetoothDeviceR);
170         when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices);
171 
172         mBluetoothDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_1));
173         when(mBluetoothDevice.getName()).thenReturn(TEST_DEVICE_NAME_1);
174         when(mBluetoothDevice.isConnected()).thenReturn(true);
175 
176         mLeftBluetoothHapDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2));
177         when(mLeftBluetoothHapDevice.isConnected()).thenReturn(true);
178         mRightBluetoothHapDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_3));
179         when(mRightBluetoothHapDevice.isConnected()).thenReturn(true);
180 
181         mController = new AudioSwitchPreferenceControllerTestable(mContext, TEST_KEY);
182         mScreen = spy(new PreferenceScreen(mContext, null));
183         mPreference = new ListPreference(mContext);
184         mProfileConnectedDevices = new ArrayList<>();
185         mHearingAidActiveDevices = new ArrayList<>(2);
186         mLeAudioActiveDevices = new ArrayList<>();
187         mEmptyDevices = new ArrayList<>(2);
188 
189         when(mScreen.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
190         when(mScreen.getContext()).thenReturn(mContext);
191         when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
192         mScreen.addPreference(mPreference);
193         mController.displayPreference(mScreen);
194     }
195 
196     @After
tearDown()197     public void tearDown() {
198         ShadowBluetoothUtils.reset();
199     }
200 
201     @Test
constructor_notSupportBluetooth_shouldReturnBeforeUsingLocalBluetoothManager()202     public void constructor_notSupportBluetooth_shouldReturnBeforeUsingLocalBluetoothManager() {
203         ShadowBluetoothUtils.reset();
204         mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
205 
206         AudioSwitchPreferenceController controller = new AudioSwitchPreferenceControllerTestable(
207                 mContext, TEST_KEY);
208         controller.onStart();
209         controller.onStop();
210 
211         assertThat(mLocalBluetoothManager).isNull();
212     }
213 
214     @Test
getAvailabilityStatus_disableFlagNoBluetoothFeature_returnUnavailable()215     public void getAvailabilityStatus_disableFlagNoBluetoothFeature_returnUnavailable() {
216         FeatureFlagUtils.setEnabled(mContext, FeatureFlags.AUDIO_SWITCHER_SETTINGS, false);
217         mPackageManager.setSystemFeature(PackageManager.FEATURE_BLUETOOTH, false);
218 
219         assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
220     }
221 
222     @Test
getAvailabilityStatus_disableFlagWithBluetoothFeature_returnUnavailable()223     public void getAvailabilityStatus_disableFlagWithBluetoothFeature_returnUnavailable() {
224         FeatureFlagUtils.setEnabled(mContext, FeatureFlags.AUDIO_SWITCHER_SETTINGS, false);
225         mPackageManager.setSystemFeature(PackageManager.FEATURE_BLUETOOTH, true);
226 
227 
228         assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
229     }
230 
231     @Test
getAvailabilityStatus_enableFlagWithBluetoothFeature_returnAvailable()232     public void getAvailabilityStatus_enableFlagWithBluetoothFeature_returnAvailable() {
233         FeatureFlagUtils.setEnabled(mContext, FeatureFlags.AUDIO_SWITCHER_SETTINGS, true);
234         mPackageManager.setSystemFeature(PackageManager.FEATURE_BLUETOOTH, true);
235 
236         assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
237     }
238 
239     @Test
getAvailabilityStatus_enableFlagNoBluetoothFeature_returnUnavailable()240     public void getAvailabilityStatus_enableFlagNoBluetoothFeature_returnUnavailable() {
241         FeatureFlagUtils.setEnabled(mContext, FeatureFlags.AUDIO_SWITCHER_SETTINGS, true);
242         mPackageManager.setSystemFeature(PackageManager.FEATURE_BLUETOOTH, false);
243 
244         assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
245     }
246 
247     @Test
onStart_shouldRegisterCallbackAndRegisterReceiver()248     public void onStart_shouldRegisterCallbackAndRegisterReceiver() {
249         mSetFlagsRule.disableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING);
250         mController.onStart();
251 
252         verify(mLocalBluetoothManager.getEventManager()).registerCallback(
253                 any(BluetoothCallback.class));
254         verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
255         verify(mLocalBluetoothManager).setForegroundActivity(mContext);
256     }
257 
258     @Test
onStop_shouldUnregisterCallbackAndUnregisterReceiver()259     public void onStop_shouldUnregisterCallbackAndUnregisterReceiver() {
260         mSetFlagsRule.disableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING);
261         mController.onStart();
262         mController.onStop();
263 
264         verify(mLocalBluetoothManager.getEventManager()).unregisterCallback(
265                 any(BluetoothCallback.class));
266         verify(mContext).unregisterReceiver(any(BroadcastReceiver.class));
267         verify(mLocalBluetoothManager).setForegroundActivity(null);
268     }
269 
270     @Test
onStart_shouldRegisterCallbackAndRegisterReceiverWithDefaultMediaOutput()271     public void onStart_shouldRegisterCallbackAndRegisterReceiverWithDefaultMediaOutput() {
272         MediaSessionManager mediaSessionManager =
273                 spy(mContext.getSystemService(MediaSessionManager.class));
274         mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING);
275         when(mContext.getSystemService(MediaSessionManager.class)).thenReturn(mediaSessionManager);
276         mController = new AudioSwitchPreferenceControllerTestable(mContext, TEST_KEY);
277 
278         mController.onStart();
279 
280         verify(mLocalBluetoothManager.getEventManager()).registerCallback(
281                 any(BluetoothCallback.class));
282         verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class),
283                 eq(Context.RECEIVER_NOT_EXPORTED));
284         verify(mLocalBluetoothManager).setForegroundActivity(mContext);
285         verify(mediaSessionManager).addOnActiveSessionsChangedListener(
286                 any(MediaSessionManager.OnActiveSessionsChangedListener.class), any(), any());
287     }
288 
289 
290     @Test
onStop_shouldUnregisterCallbackAndUnregisterReceiverWithDefaultMediaOutput()291     public void onStop_shouldUnregisterCallbackAndUnregisterReceiverWithDefaultMediaOutput() {
292         MediaSessionManager mediaSessionManager =
293                 spy(mContext.getSystemService(MediaSessionManager.class));
294         mSetFlagsRule.enableFlags(FLAG_ENABLE_OUTPUT_SWITCHER_FOR_SYSTEM_ROUTING);
295         when(mContext.getSystemService(MediaSessionManager.class)).thenReturn(mediaSessionManager);
296         mController = new AudioSwitchPreferenceControllerTestable(mContext, TEST_KEY);
297         mController.onStart();
298 
299         mController.onStop();
300 
301         verify(mLocalBluetoothManager.getEventManager()).unregisterCallback(
302                 any(BluetoothCallback.class));
303         verify(mContext).unregisterReceiver(any(BroadcastReceiver.class));
304         verify(mLocalBluetoothManager).setForegroundActivity(null);
305         verify(mediaSessionManager).removeOnActiveSessionsChangedListener(
306                 any(MediaSessionManager.OnActiveSessionsChangedListener.class));
307     }
308 
309     /**
310      * Audio stream output to bluetooth sco headset which is the subset of all sco device.
311      * isStreamFromOutputDevice should return true.
312      */
313     @Test
isStreamFromOutputDevice_outputDeviceIsBtScoHeadset_shouldReturnTrue()314     public void isStreamFromOutputDevice_outputDeviceIsBtScoHeadset_shouldReturnTrue() {
315         mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_SCO_HEADSET);
316 
317         assertThat(mController.isStreamFromOutputDevice(
318                 STREAM_MUSIC, DEVICE_OUT_BLUETOOTH_SCO_HEADSET)).isTrue();
319     }
320 
321     /**
322      * Left side of HAP device is active.
323      * findActiveHearingAidDevice should return hearing aid device active device.
324      */
325     @Test
findActiveHearingAidDevice_leftActiveDevice_returnLeftDeviceAsActiveHapDevice()326     public void findActiveHearingAidDevice_leftActiveDevice_returnLeftDeviceAsActiveHapDevice() {
327         mController.mConnectedDevices.clear();
328         mController.mConnectedDevices.add(mBluetoothDevice);
329         mController.mConnectedDevices.add(mLeftBluetoothHapDevice);
330         mHearingAidActiveDevices.clear();
331         mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
332         mHearingAidActiveDevices.add(null);
333         when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
334         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
335 
336         assertThat(mController.findActiveHearingAidDevice()).isEqualTo(mLeftBluetoothHapDevice);
337     }
338 
339     /**
340      * Right side of HAP device is active.
341      * findActiveHearingAidDevice should return hearing aid device active device.
342      */
343     @Test
findActiveHearingAidDevice_rightActiveDevice_returnRightDeviceAsActiveHapDevice()344     public void findActiveHearingAidDevice_rightActiveDevice_returnRightDeviceAsActiveHapDevice() {
345         mController.mConnectedDevices.clear();
346         mController.mConnectedDevices.add(mBluetoothDevice);
347         mController.mConnectedDevices.add(mRightBluetoothHapDevice);
348         mHearingAidActiveDevices.clear();
349         mHearingAidActiveDevices.add(null);
350         mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
351         when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
352         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
353 
354         assertThat(mController.findActiveHearingAidDevice()).isEqualTo(mRightBluetoothHapDevice);
355     }
356 
357     /**
358      * Both are active device.
359      * findActiveHearingAidDevice only return the active device in mConnectedDevices.
360      */
361     @Test
findActiveHearingAidDevice_twoActiveDevice_returnActiveDeviceInConnectedDevices()362     public void findActiveHearingAidDevice_twoActiveDevice_returnActiveDeviceInConnectedDevices() {
363         mController.mConnectedDevices.clear();
364         mController.mConnectedDevices.add(mBluetoothDevice);
365         mController.mConnectedDevices.add(mRightBluetoothHapDevice);
366         mHearingAidActiveDevices.clear();
367         mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
368         mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
369         when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
370         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
371 
372         assertThat(mController.findActiveHearingAidDevice()).isEqualTo(mRightBluetoothHapDevice);
373     }
374 
375     /**
376      * None of them are active.
377      * findActiveHearingAidDevice should return null.
378      */
379     @Test
findActiveHearingAidDevice_noActiveDevice_returnNull()380     public void findActiveHearingAidDevice_noActiveDevice_returnNull() {
381         mController.mConnectedDevices.clear();
382         mController.mConnectedDevices.add(mBluetoothDevice);
383         mController.mConnectedDevices.add(mLeftBluetoothHapDevice);
384         mHearingAidActiveDevices.clear();
385         when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
386         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
387 
388         assertThat(mController.findActiveHearingAidDevice()).isNull();
389     }
390 
391     /**
392      * Two hearing aid devices with different HisyncId
393      * getConnectedHearingAidDevices should add both device to list.
394      */
395     @Test
getConnectedHearingAidDevices_deviceHisyncIdIsDifferent_shouldAddBothToList()396     public void getConnectedHearingAidDevices_deviceHisyncIdIsDifferent_shouldAddBothToList() {
397         mEmptyDevices.clear();
398         mProfileConnectedDevices.clear();
399         mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
400         mProfileConnectedDevices.add(mRightBluetoothHapDevice);
401         when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
402         when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
403         when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID2);
404 
405         mEmptyDevices.addAll(mController.getConnectedHearingAidDevices());
406 
407         assertThat(mEmptyDevices).containsExactly(mLeftBluetoothHapDevice,
408                 mRightBluetoothHapDevice);
409     }
410 
411     /**
412      * Two hearing aid devices with same HisyncId
413      * getConnectedHearingAidDevices should only add first device to list.
414      */
415     @Test
getConnectedHearingAidDevices_deviceHisyncIdIsSame_shouldAddOneToList()416     public void getConnectedHearingAidDevices_deviceHisyncIdIsSame_shouldAddOneToList() {
417         mEmptyDevices.clear();
418         mProfileConnectedDevices.clear();
419         mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
420         mProfileConnectedDevices.add(mRightBluetoothHapDevice);
421         when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
422         when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
423         when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID1);
424 
425         mEmptyDevices.addAll(mController.getConnectedHearingAidDevices());
426 
427         assertThat(mEmptyDevices).containsExactly(mLeftBluetoothHapDevice);
428     }
429 
430     /**
431      * One hands free profile device is connected.
432      * getConnectedA2dpDevices should add this device to list.
433      */
434     @Test
getConnectedHfpDevices_oneConnectedHfpDevice_shouldAddDeviceToList()435     public void getConnectedHfpDevices_oneConnectedHfpDevice_shouldAddDeviceToList() {
436         mEmptyDevices.clear();
437         mProfileConnectedDevices.clear();
438         mProfileConnectedDevices.add(mBluetoothDevice);
439         when(mHeadsetProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
440 
441         mEmptyDevices.addAll(mController.getConnectedHfpDevices());
442 
443         assertThat(mEmptyDevices).containsExactly(mBluetoothDevice);
444     }
445 
446     /**
447      * More than one hands free profile devices are connected.
448      * getConnectedA2dpDevices should add all devices to list.
449      */
450     @Test
getConnectedHfpDevices_moreThanOneConnectedHfpDevice_shouldAddDeviceToList()451     public void getConnectedHfpDevices_moreThanOneConnectedHfpDevice_shouldAddDeviceToList() {
452         mEmptyDevices.clear();
453         mProfileConnectedDevices.clear();
454         mProfileConnectedDevices.add(mBluetoothDevice);
455         mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
456         when(mHeadsetProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
457 
458         mEmptyDevices.addAll(mController.getConnectedHfpDevices());
459 
460         assertThat(mEmptyDevices).containsExactly(mBluetoothDevice, mLeftBluetoothHapDevice);
461     }
462 
463     @Test
getConnectedLeAudioDevices_connectedLeAudioDevice_shouldAddDeviceToList()464     public void getConnectedLeAudioDevices_connectedLeAudioDevice_shouldAddDeviceToList() {
465         when(mCachedBluetoothDeviceL.getDevice()).thenReturn(mBluetoothDevice);
466         mEmptyDevices.clear();
467         mProfileConnectedDevices.clear();
468         mProfileConnectedDevices.add(mBluetoothDevice);
469         when(mLeAudioProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
470 
471         mEmptyDevices.addAll(mController.getConnectedLeAudioDevices());
472 
473         assertThat(mEmptyDevices).containsExactly(mBluetoothDevice);
474     }
475 
476     @Test
getConnectedLeAudioDevices_disconnectedLeAudioDevice_shouldNotAddDeviceToList()477     public void getConnectedLeAudioDevices_disconnectedLeAudioDevice_shouldNotAddDeviceToList() {
478         BluetoothDevice connectedBtLeAduioDevice =
479                 spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2));
480         when(connectedBtLeAduioDevice.isConnected()).thenReturn(true);
481         BluetoothDevice disconnectedBtLeAduioDevice =
482                 spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_3));
483         when(disconnectedBtLeAduioDevice.isConnected()).thenReturn(false);
484         when(mCachedBluetoothDeviceL.getDevice()).thenReturn(mBluetoothDevice);
485         when(mCachedBluetoothDeviceR.getDevice()).thenReturn(connectedBtLeAduioDevice);
486         mEmptyDevices.clear();
487         mProfileConnectedDevices.clear();
488         mProfileConnectedDevices.add(mBluetoothDevice);
489         mProfileConnectedDevices.add(connectedBtLeAduioDevice);
490         mProfileConnectedDevices.add(disconnectedBtLeAduioDevice);
491         when(mLeAudioProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
492 
493         mEmptyDevices.addAll(mController.getConnectedLeAudioDevices());
494 
495         assertThat(mEmptyDevices).containsExactly(mBluetoothDevice, connectedBtLeAduioDevice);
496     }
497 
498     @Test
getConnectedLeAudioDevices_notInCachedDeviceList_shouldNotAddDeviceToList()499     public void getConnectedLeAudioDevices_notInCachedDeviceList_shouldNotAddDeviceToList() {
500         BluetoothDevice connectedBtLeAduioDevice1 =
501                 spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2));
502         when(connectedBtLeAduioDevice1.isConnected()).thenReturn(true);
503         BluetoothDevice connectedBtLeAduioDevice2 =
504                 spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_3));
505         when(connectedBtLeAduioDevice2.isConnected()).thenReturn(true);
506         when(mCachedBluetoothDeviceL.getDevice()).thenReturn(mBluetoothDevice);
507         when(mCachedBluetoothDeviceR.getDevice()).thenReturn(connectedBtLeAduioDevice1);
508         mEmptyDevices.clear();
509         mProfileConnectedDevices.clear();
510         mProfileConnectedDevices.add(connectedBtLeAduioDevice1);
511         mProfileConnectedDevices.add(connectedBtLeAduioDevice2);
512         when(mLeAudioProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
513 
514         mEmptyDevices.addAll(mController.getConnectedLeAudioDevices());
515 
516         assertThat(mEmptyDevices).containsExactly(connectedBtLeAduioDevice1);
517     }
518 
519     @Test
getConnectedLeAudioDevices_nullConnectedDevices_returnEmptyList()520     public void getConnectedLeAudioDevices_nullConnectedDevices_returnEmptyList() {
521       when(mLeAudioProfile.getConnectedDevices()).thenReturn(null);
522 
523       List<BluetoothDevice> connectedDevices = mController.getConnectedLeAudioDevices();
524 
525       assertThat(connectedDevices.isEmpty()).isTrue();
526     }
527 
528     @Test
findActiveLeAudioDevice_noActiveDevice_returnNull()529     public void findActiveLeAudioDevice_noActiveDevice_returnNull() {
530         mLeAudioActiveDevices.clear();
531         when(mLeAudioProfile.getActiveDevices()).thenReturn(mLeAudioActiveDevices);
532 
533         assertThat(mController.findActiveLeAudioDevice()).isNull();
534     }
535 
536     @Test
findActiveLeAudioDevice_withActiveDevice_returnActiveDevice()537     public void findActiveLeAudioDevice_withActiveDevice_returnActiveDevice() {
538         mLeAudioActiveDevices.clear();
539         mLeAudioActiveDevices.add(mBluetoothDevice);
540         when(mLeAudioProfile.getActiveDevices()).thenReturn(mLeAudioActiveDevices);
541 
542         assertThat(mController.findActiveLeAudioDevice()).isEqualTo(mBluetoothDevice);
543     }
544 
545     private class AudioSwitchPreferenceControllerTestable extends
546             AudioSwitchPreferenceController {
AudioSwitchPreferenceControllerTestable(Context context, String key)547         AudioSwitchPreferenceControllerTestable(Context context, String key) {
548             super(context, key);
549         }
550 
551         @Override
findActiveDevice()552         public BluetoothDevice findActiveDevice() {
553             return null;
554         }
555 
556         @Override
getPreferenceKey()557         public String getPreferenceKey() {
558             return TEST_KEY;
559         }
560     }
561 }
562