• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_BLE_HEADSET;
20 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
21 import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.Mockito.mock;
27 import static org.mockito.Mockito.never;
28 import static org.mockito.Mockito.spy;
29 import static org.mockito.Mockito.times;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
32 
33 import android.bluetooth.BluetoothAdapter;
34 import android.bluetooth.BluetoothDevice;
35 import android.bluetooth.BluetoothManager;
36 import android.content.Context;
37 import android.media.AudioManager;
38 
39 import androidx.preference.ListPreference;
40 import androidx.preference.PreferenceManager;
41 import androidx.preference.PreferenceScreen;
42 
43 import com.android.settings.R;
44 import com.android.settings.bluetooth.Utils;
45 import com.android.settings.testutils.shadow.ShadowAudioManager;
46 import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
47 import com.android.settingslib.bluetooth.BluetoothEventManager;
48 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
49 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
50 import com.android.settingslib.bluetooth.HeadsetProfile;
51 import com.android.settingslib.bluetooth.HearingAidProfile;
52 import com.android.settingslib.bluetooth.LeAudioProfile;
53 import com.android.settingslib.bluetooth.LocalBluetoothManager;
54 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
55 
56 import org.junit.After;
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.mockito.Mock;
61 import org.mockito.MockitoAnnotations;
62 import org.robolectric.RobolectricTestRunner;
63 import org.robolectric.RuntimeEnvironment;
64 import org.robolectric.annotation.Config;
65 import org.robolectric.shadows.ShadowBluetoothDevice;
66 
67 import java.util.ArrayList;
68 import java.util.Collection;
69 import java.util.List;
70 
71 @RunWith(RobolectricTestRunner.class)
72 @Config(shadows = {
73         ShadowAudioManager.class,
74         ShadowBluetoothUtils.class,
75         ShadowBluetoothDevice.class}
76 )
77 public class HandsFreeProfileOutputPreferenceControllerTest {
78     private static final String TEST_KEY = "Test_Key";
79     private static final String TEST_DEVICE_NAME_1 = "Test_HFP_BT_Device_NAME_1";
80     private static final String TEST_DEVICE_NAME_2 = "Test_HFP_BT_Device_NAME_2";
81     private static final String TEST_HAP_DEVICE_NAME_1 = "Test_HAP_BT_Device_NAME_1";
82     private static final String TEST_HAP_DEVICE_NAME_2 = "Test_HAP_BT_Device_NAME_2";
83     private static final String TEST_LE_AUDIO_DEVICE_NAME_1 = "Test_LE_AUDIO_Device_NAME_1";
84     private static final String TEST_DEVICE_ADDRESS_1 = "00:A1:A1:A1:A1:A1";
85     private static final String TEST_DEVICE_ADDRESS_2 = "00:B2:B2:B2:B2:B2";
86     private static final String TEST_DEVICE_ADDRESS_3 = "00:C3:C3:C3:C3:C3";
87     private static final String TEST_DEVICE_ADDRESS_4 = "00:D4:D4:D4:D4:D4";
88     private static final String TEST_DEVICE_ADDRESS_5 = "00:E5:E5:E5:E5:E5";
89     private final static long HISYNCID1 = 10;
90     private final static long HISYNCID2 = 11;
91 
92     @Mock
93     private LocalBluetoothManager mLocalManager;
94     @Mock
95     private BluetoothEventManager mBluetoothEventManager;
96     @Mock
97     private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
98     @Mock
99     private HeadsetProfile mHeadsetProfile;
100     @Mock
101     private HearingAidProfile mHearingAidProfile;
102     @Mock
103     private LeAudioProfile mLeAudioProfile;
104     @Mock
105     private AudioSwitchPreferenceController.AudioSwitchCallback mAudioSwitchPreferenceCallback;
106     @Mock
107     private CachedBluetoothDeviceManager mCachedDeviceManager;
108     @Mock
109     private CachedBluetoothDevice mCachedBluetoothDeviceL;
110     @Mock
111     private CachedBluetoothDevice mCachedBluetoothDeviceR;
112 
113     private Context mContext;
114     private PreferenceScreen mScreen;
115     private ListPreference mPreference;
116     private AudioManager mAudioManager;
117     private ShadowAudioManager mShadowAudioManager;
118     private BluetoothManager mBluetoothManager;
119     private BluetoothAdapter mBluetoothAdapter;
120     private BluetoothDevice mBluetoothDevice;
121     private BluetoothDevice mSecondBluetoothDevice;
122     private BluetoothDevice mLeftBluetoothHapDevice;
123     private BluetoothDevice mRightBluetoothHapDevice;
124     private LocalBluetoothManager mLocalBluetoothManager;
125     private HandsFreeProfileOutputPreferenceController mController;
126     private List<BluetoothDevice> mProfileConnectedDevices;
127     private List<BluetoothDevice> mHearingAidActiveDevices;
128     private List<BluetoothDevice> mLeAudioActiveDevices;
129     private Collection<CachedBluetoothDevice> mCachedDevices;
130 
131     @Before
setUp()132     public void setUp() {
133         MockitoAnnotations.initMocks(this);
134         mContext = spy(RuntimeEnvironment.application);
135 
136         mAudioManager = mContext.getSystemService(AudioManager.class);
137         mShadowAudioManager = ShadowAudioManager.getShadow();
138 
139         ShadowBluetoothUtils.sLocalBluetoothManager = mLocalManager;
140         mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
141 
142         when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager);
143         when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
144         when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
145         when(mLocalBluetoothProfileManager.getHeadsetProfile()).thenReturn(mHeadsetProfile);
146         when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
147         when(mLocalBluetoothProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
148 
149         mBluetoothManager = mContext.getSystemService(BluetoothManager.class);
150         mBluetoothAdapter = mBluetoothManager.getAdapter();
151 
152         mCachedDevices = new ArrayList<>();
153         mCachedDevices.add(mCachedBluetoothDeviceL);
154         mCachedDevices.add(mCachedBluetoothDeviceR);
155         when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices);
156 
157         mBluetoothDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_1));
158         when(mBluetoothDevice.getName()).thenReturn(TEST_DEVICE_NAME_1);
159         when(mBluetoothDevice.getAlias()).thenReturn(TEST_DEVICE_NAME_1);
160         when(mBluetoothDevice.isConnected()).thenReturn(true);
161 
162         mSecondBluetoothDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2));
163         when(mSecondBluetoothDevice.getName()).thenReturn(TEST_DEVICE_NAME_2);
164         when(mSecondBluetoothDevice.getAlias()).thenReturn(TEST_DEVICE_NAME_2);
165         when(mSecondBluetoothDevice.isConnected()).thenReturn(true);
166 
167         mLeftBluetoothHapDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_3));
168         when(mLeftBluetoothHapDevice.getName()).thenReturn(TEST_HAP_DEVICE_NAME_1);
169         when(mLeftBluetoothHapDevice.getAlias()).thenReturn(TEST_HAP_DEVICE_NAME_1);
170         when(mLeftBluetoothHapDevice.isConnected()).thenReturn(true);
171 
172         mRightBluetoothHapDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_4));
173         when(mRightBluetoothHapDevice.getName()).thenReturn(TEST_HAP_DEVICE_NAME_2);
174         when(mRightBluetoothHapDevice.getAlias()).thenReturn(TEST_HAP_DEVICE_NAME_2);
175         when(mRightBluetoothHapDevice.isConnected()).thenReturn(true);
176 
177         mController = new HandsFreeProfileOutputPreferenceController(mContext, TEST_KEY);
178         mScreen = spy(new PreferenceScreen(mContext, null));
179         mPreference = new ListPreference(mContext);
180         mProfileConnectedDevices = new ArrayList<>();
181         mHearingAidActiveDevices = new ArrayList<>(2);
182         mLeAudioActiveDevices = new ArrayList<>();
183 
184         when(mScreen.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
185         when(mScreen.getContext()).thenReturn(mContext);
186         when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
187         mScreen.addPreference(mPreference);
188         mController.displayPreference(mScreen);
189         mController.setCallback(mAudioSwitchPreferenceCallback);
190     }
191 
192     @After
tearDown()193     public void tearDown() {
194         ShadowBluetoothUtils.reset();
195     }
196 
197     /**
198      * During a call, bluetooth device with HisyncId.
199      * HearingAidProfile should set active device to this device.
200      */
201     @Test
setActiveBluetoothDevice_btDeviceWithHisyncId_shouldSetBtDeviceActive()202     public void setActiveBluetoothDevice_btDeviceWithHisyncId_shouldSetBtDeviceActive() {
203         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
204         when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
205 
206         mController.setActiveBluetoothDevice(mLeftBluetoothHapDevice);
207 
208         verify(mHearingAidProfile).setActiveDevice(mLeftBluetoothHapDevice);
209         verify(mHeadsetProfile, never()).setActiveDevice(mLeftBluetoothHapDevice);
210     }
211 
212     /**
213      * During a call, Bluetooth device without HisyncId.
214      * HeadsetProfile should set active device to this device.
215      */
216     @Test
setActiveBluetoothDevice_btDeviceWithoutHisyncId_shouldSetBtDeviceActive()217     public void setActiveBluetoothDevice_btDeviceWithoutHisyncId_shouldSetBtDeviceActive() {
218         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
219 
220         mController.setActiveBluetoothDevice(mBluetoothDevice);
221 
222         verify(mHeadsetProfile).setActiveDevice(mBluetoothDevice);
223         verify(mHearingAidProfile, never()).setActiveDevice(mBluetoothDevice);
224     }
225 
226     /**
227      * During a call, set active device to "this device".
228      * HeadsetProfile should set to null.
229      * HearingAidProfile should set to null.
230      */
231     @Test
setActiveBluetoothDevice_setNull_shouldSetNullToBothProfiles()232     public void setActiveBluetoothDevice_setNull_shouldSetNullToBothProfiles() {
233         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
234 
235         mController.setActiveBluetoothDevice(null);
236 
237         verify(mHeadsetProfile).setActiveDevice(null);
238         verify(mHearingAidProfile).setActiveDevice(null);
239     }
240 
241     /**
242      * In normal mode
243      * HeadsetProfile should not set active device.
244      */
245     @Test
setActiveBluetoothDevice_inNormalMode_shouldNotSetActiveDeviceToHeadsetProfile()246     public void setActiveBluetoothDevice_inNormalMode_shouldNotSetActiveDeviceToHeadsetProfile() {
247         mAudioManager.setMode(AudioManager.MODE_NORMAL);
248 
249         mController.setActiveBluetoothDevice(mBluetoothDevice);
250 
251         verify(mHeadsetProfile, times(0)).setActiveDevice(any(BluetoothDevice.class));
252     }
253 
254     /**
255      * Default status
256      * Preference should be invisible
257      * Summary should be default summary
258      */
259     @Test
updateState_shouldSetSummary()260     public void updateState_shouldSetSummary() {
261         mController.updateState(mPreference);
262 
263         assertThat(mPreference.isVisible()).isFalse();
264         assertThat(mPreference.getSummary()).isEqualTo(
265                 mContext.getText(R.string.media_output_default_summary));
266     }
267 
268     /**
269      * One Hands Free Profile Bluetooth device is available and activated
270      * Preference should be visible
271      * Preference summary should be the activated device name
272      */
273     @Test
updateState_oneHeadsetsAvailableAndActivated_shouldSetDeviceName()274     public void updateState_oneHeadsetsAvailableAndActivated_shouldSetDeviceName() {
275         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
276         mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_SCO);
277         mProfileConnectedDevices.clear();
278         mProfileConnectedDevices.add(mBluetoothDevice);
279         when(mHeadsetProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
280         when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
281 
282         mController.updateState(mPreference);
283 
284         assertThat(mPreference.isVisible()).isTrue();
285         assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
286     }
287 
288     /**
289      * More than one Hands Free Profile Bluetooth devices are available, and second
290      * device is active.
291      * Preference should be visible
292      * Preference summary should be the activated device name
293      */
294     @Test
updateState_moreThanOneHfpBtDevicesAreAvailable_shouldSetActivatedDeviceName()295     public void updateState_moreThanOneHfpBtDevicesAreAvailable_shouldSetActivatedDeviceName() {
296         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
297         mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_SCO);
298         List<BluetoothDevice> connectedDevices = new ArrayList<>(2);
299         connectedDevices.add(mBluetoothDevice);
300         connectedDevices.add(mSecondBluetoothDevice);
301         when(mHeadsetProfile.getConnectedDevices()).thenReturn(connectedDevices);
302         when(mHeadsetProfile.getActiveDevice()).thenReturn(mSecondBluetoothDevice);
303 
304         mController.updateState(mPreference);
305 
306         assertThat(mPreference.isVisible()).isTrue();
307         assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2);
308     }
309 
310     /**
311      * Hands Free Profile Bluetooth device(s) are available, but wired headset is plugged in
312      * and activated.
313      * Preference should be visible
314      * Preference summary should be "This device"
315      */
316     @Test
updateState_withAvailableDevicesWiredHeadsetActivated_shouldSetDefaultSummary()317     public void updateState_withAvailableDevicesWiredHeadsetActivated_shouldSetDefaultSummary() {
318         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
319         mProfileConnectedDevices.clear();
320         mProfileConnectedDevices.add(mBluetoothDevice);
321         when(mHeadsetProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
322         when(mHeadsetProfile.getActiveDevice()).thenReturn(null);
323 
324         mController.updateState(mPreference);
325 
326         assertThat(mPreference.isVisible()).isTrue();
327         assertThat(mPreference.getSummary()).isEqualTo(
328                 mContext.getText(R.string.media_output_default_summary));
329     }
330 
331     /**
332      * No available Headset BT devices
333      * Preference should be invisible
334      * Preference summary should be "This device"
335      */
336     @Test
updateState_noAvailableHeadsetBtDevices_shouldSetDefaultSummary()337     public void updateState_noAvailableHeadsetBtDevices_shouldSetDefaultSummary() {
338         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
339         List<BluetoothDevice> emptyDeviceList = new ArrayList<>();
340         when(mHeadsetProfile.getConnectedDevices()).thenReturn(emptyDeviceList);
341 
342         mController.updateState(mPreference);
343 
344         assertThat(mPreference.isVisible()).isFalse();
345         assertThat(mPreference.getSummary()).isEqualTo(
346                 mContext.getText(R.string.media_output_default_summary));
347     }
348 
349     /**
350      * One hearing aid profile Bluetooth device is available and active.
351      * Preference should be visible
352      * Preference summary should be the activated device name
353      */
354     @Test
updateState_oneHapBtDeviceAreAvailable_shouldSetActivatedDeviceName()355     public void updateState_oneHapBtDeviceAreAvailable_shouldSetActivatedDeviceName() {
356         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
357         mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
358         mProfileConnectedDevices.clear();
359         mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
360         mHearingAidActiveDevices.clear();
361         mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
362         when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
363         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
364         when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
365 
366         mController.updateState(mPreference);
367 
368         assertThat(mPreference.isVisible()).isTrue();
369         assertThat(mPreference.getSummary()).isEqualTo(mLeftBluetoothHapDevice.getName());
370     }
371 
372     /**
373      * More than one hearing aid profile Bluetooth devices are available, and second
374      * device is active.
375      * Preference should be visible
376      * Preference summary should be the activated device name
377      */
378     @Test
updateState_moreThanOneHapBtDevicesAreAvailable_shouldSetActivatedDeviceName()379     public void updateState_moreThanOneHapBtDevicesAreAvailable_shouldSetActivatedDeviceName() {
380         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
381         mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
382         mProfileConnectedDevices.clear();
383         mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
384         mProfileConnectedDevices.add(mRightBluetoothHapDevice);
385         mHearingAidActiveDevices.clear();
386         mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
387         when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
388         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
389         when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
390         when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID2);
391 
392         mController.updateState(mPreference);
393 
394         assertThat(mPreference.isVisible()).isTrue();
395         assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
396     }
397 
398     /**
399      * Both hearing aid profile and hands free profile Bluetooth devices are available, and
400      * two hearing aid profile devices with same HisyncId. Both of HAP device are active,
401      * "left" side HAP device is added first.
402      * Preference should be visible
403      * Preference summary should be the activated device name
404      * ConnectedDevice should not contain second HAP device with same HisyncId
405      */
406     @Test
updateState_hapBtDeviceWithSameId_shouldSetActivatedDeviceName()407     public void updateState_hapBtDeviceWithSameId_shouldSetActivatedDeviceName() {
408         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
409         mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
410         mProfileConnectedDevices.clear();
411         mProfileConnectedDevices.add(mBluetoothDevice);
412         //with same HisyncId, only the first one will remain in UI.
413         mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
414         mProfileConnectedDevices.add(mRightBluetoothHapDevice);
415         mHearingAidActiveDevices.clear();
416         mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
417         mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
418         when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
419         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
420         when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
421         when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID1);
422 
423         mController.updateState(mPreference);
424 
425         assertThat(mPreference.isVisible()).isTrue();
426         assertThat(mPreference.getSummary()).isEqualTo(mLeftBluetoothHapDevice.getName());
427         assertThat(mController.mConnectedDevices.contains(mLeftBluetoothHapDevice)).isTrue();
428         assertThat(mController.mConnectedDevices.contains(mRightBluetoothHapDevice)).isFalse();
429     }
430 
431     /**
432      * Both hearing aid profile and hands free profile Bluetooth devices are available, and
433      * two hearing aid profile devices with same HisyncId. Both of HAP device are active,
434      * "right" side HAP device is added first.
435      * Preference should be visible
436      * Preference summary should be the activated device name
437      * ConnectedDevice should not contain second HAP device with same HisyncId
438      */
439     @Test
updateState_hapBtDeviceWithSameIdButDifferentOrder_shouldSetActivatedDeviceName()440     public void updateState_hapBtDeviceWithSameIdButDifferentOrder_shouldSetActivatedDeviceName() {
441         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
442         mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
443         mProfileConnectedDevices.clear();
444         mProfileConnectedDevices.add(mBluetoothDevice);
445         //with same HisyncId, only the first one will remain in UI.
446         mProfileConnectedDevices.add(mRightBluetoothHapDevice);
447         mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
448         mHearingAidActiveDevices.clear();
449         mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
450         mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
451         when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
452         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
453         when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
454         when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID1);
455 
456         mController.updateState(mPreference);
457 
458         assertThat(mPreference.isVisible()).isTrue();
459         assertThat(mController.mConnectedDevices.contains(mRightBluetoothHapDevice)).isTrue();
460         assertThat(mController.mConnectedDevices.contains(mLeftBluetoothHapDevice)).isFalse();
461         assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
462     }
463 
464     /**
465      * Both hearing aid profile and hands free profile  Bluetooth devices are available, and
466      * two hearing aid profile devices with different HisyncId. One of HAP device is active.
467      * Preference should be visible
468      * Preference summary should be the activated device name
469      * ConnectedDevice should contain both HAP device with different HisyncId
470      */
471     @Test
updateState_hapBtDeviceWithDifferentId_shouldSetActivatedDeviceName()472     public void updateState_hapBtDeviceWithDifferentId_shouldSetActivatedDeviceName() {
473         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
474         mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
475         mProfileConnectedDevices.clear();
476         mProfileConnectedDevices.add(mBluetoothDevice);
477         mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
478         mProfileConnectedDevices.add(mRightBluetoothHapDevice);
479         mHearingAidActiveDevices.clear();
480         mHearingAidActiveDevices.add(null);
481         mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
482         when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
483         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
484         when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
485         when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID2);
486 
487         mController.updateState(mPreference);
488 
489         assertThat(mPreference.isVisible()).isTrue();
490         assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
491         assertThat(mController.mConnectedDevices).containsExactly(mBluetoothDevice,
492                 mLeftBluetoothHapDevice, mRightBluetoothHapDevice);
493     }
494 
495     @Test
updateState_leAudioDeviceActive_shouldSetActivatedDeviceName()496     public void updateState_leAudioDeviceActive_shouldSetActivatedDeviceName() {
497         mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
498         mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLE_HEADSET);
499         when(mCachedBluetoothDeviceL.getDevice()).thenReturn(mBluetoothDevice);
500         when(mBluetoothDevice.getName()).thenReturn(TEST_LE_AUDIO_DEVICE_NAME_1);
501         when(mBluetoothDevice.getAlias()).thenReturn(TEST_LE_AUDIO_DEVICE_NAME_1);
502         mProfileConnectedDevices.clear();
503         mProfileConnectedDevices.add(mBluetoothDevice);
504         mLeAudioActiveDevices.clear();
505         mLeAudioActiveDevices.add(mBluetoothDevice);
506         when(mLeAudioProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
507         when(mLeAudioProfile.getActiveDevices()).thenReturn(mLeAudioActiveDevices);
508 
509         mController.updateState(mPreference);
510 
511         assertThat(mPreference.isVisible()).isTrue();
512         assertThat(mPreference.getSummary()).isEqualTo(mBluetoothDevice.getName());
513     }
514 
515     @Test
findActiveDevice_onlyHeadsetDeviceActive_returnHeadsetDevice()516     public void findActiveDevice_onlyHeadsetDeviceActive_returnHeadsetDevice() {
517         when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null);
518         when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
519 
520         assertThat(mController.findActiveDevice()).isEqualTo(mBluetoothDevice);
521     }
522 
523     @Test
findActiveDevice_allDevicesNotActive_returnNull()524     public void findActiveDevice_allDevicesNotActive_returnNull() {
525         when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null);
526         when(mHeadsetProfile.getActiveDevice()).thenReturn(null);
527 
528         assertThat(mController.findActiveDevice()).isNull();
529     }
530 
531     @Test
findActiveDevice_allProfilesWithActiveDevice_returnHADevice()532     public void findActiveDevice_allProfilesWithActiveDevice_returnHADevice() {
533         BluetoothDevice btLeDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_5));
534         when(btLeDevice.getName()).thenReturn(TEST_LE_AUDIO_DEVICE_NAME_1);
535         mController.mConnectedDevices.clear();
536         mController.mConnectedDevices.add(mBluetoothDevice);
537         mController.mConnectedDevices.add(mLeftBluetoothHapDevice);
538         mController.mConnectedDevices.add(btLeDevice);
539         mLeAudioActiveDevices.clear();
540         mLeAudioActiveDevices.add(btLeDevice);
541         mHearingAidActiveDevices.clear();
542         mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
543         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
544         when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
545         when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
546         when(mLeAudioProfile.getActiveDevices()).thenReturn(mLeAudioActiveDevices);
547 
548         assertThat(mController.findActiveDevice()).isEqualTo(mLeftBluetoothHapDevice);
549     }
550 
551     @Test
findActiveDevice_headsetDeviceAndLeAudioDeviceActive_returnLeAudioDevice()552     public void findActiveDevice_headsetDeviceAndLeAudioDeviceActive_returnLeAudioDevice() {
553         BluetoothDevice btLeDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_5));
554         when(btLeDevice.getName()).thenReturn(TEST_LE_AUDIO_DEVICE_NAME_1);
555         mLeAudioActiveDevices.clear();
556         mLeAudioActiveDevices.add(btLeDevice);
557         mHearingAidActiveDevices.clear();
558         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
559         when(mHeadsetProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
560         when(mLeAudioProfile.getActiveDevices()).thenReturn(mLeAudioActiveDevices);
561 
562         assertThat(mController.findActiveDevice()).isEqualTo(btLeDevice);
563     }
564 
565     @Test
findActiveDevice_onlyLeAudioDeviceActive_returnLeAudioDevice()566     public void findActiveDevice_onlyLeAudioDeviceActive_returnLeAudioDevice() {
567         BluetoothDevice btLeDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_5));
568         when(btLeDevice.getName()).thenReturn(TEST_LE_AUDIO_DEVICE_NAME_1);
569         mLeAudioActiveDevices.clear();
570         mLeAudioActiveDevices.add(btLeDevice);
571         mHearingAidActiveDevices.clear();
572         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
573         when(mHeadsetProfile.getActiveDevice()).thenReturn(null);
574         when(mLeAudioProfile.getActiveDevices()).thenReturn(mLeAudioActiveDevices);
575 
576         assertThat(mController.findActiveDevice()).isEqualTo(btLeDevice);
577     }
578 
579 
580     /**
581      * One Bluetooth devices are available, and select the device.
582      * Preference summary should be device name.
583      */
584     @Test
onPreferenceChange_toBtDevice_shouldSetBtDeviceName()585     public void onPreferenceChange_toBtDevice_shouldSetBtDeviceName() {
586         mController.mConnectedDevices.clear();
587         mController.mConnectedDevices.add(mBluetoothDevice);
588 
589         mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1);
590 
591         assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
592     }
593 
594     /**
595      * More than one Bluetooth devices are available, and select second device.
596      * Preference summary should be second device name.
597      */
598     @Test
onPreferenceChange_toBtDevices_shouldSetSecondBtDeviceName()599     public void onPreferenceChange_toBtDevices_shouldSetSecondBtDeviceName() {
600         mController.mConnectedDevices.clear();
601         mController.mConnectedDevices.add(mBluetoothDevice);
602         mController.mConnectedDevices.add(mSecondBluetoothDevice);
603 
604         mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_2);
605 
606         assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2);
607     }
608 
609     /**
610      * mConnectedDevices is empty.
611      * onPreferenceChange should return false.
612      */
613     @Test
onPreferenceChange_connectedDeviceIsNull_shouldReturnFalse()614     public void onPreferenceChange_connectedDeviceIsNull_shouldReturnFalse() {
615         mController.mConnectedDevices.clear();
616 
617         assertThat(mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1)).isFalse();
618     }
619 
620     @Test
onPreferenceChange_toThisDevice_shouldSetDefaultSummary()621     public void onPreferenceChange_toThisDevice_shouldSetDefaultSummary() {
622         mController.mConnectedDevices.clear();
623         mController.mConnectedDevices.add(mBluetoothDevice);
624 
625         mController.onPreferenceChange(mPreference,
626                 mContext.getText(R.string.media_output_default_summary));
627 
628         assertThat(mPreference.getSummary()).isEqualTo(
629                 mContext.getText(R.string.media_output_default_summary));
630     }
631 }
632