• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.server.telecom.tests;
18 
19 import static android.media.AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
20 
21 import static com.android.server.telecom.CallAudioRouteAdapter.SWITCH_BASELINE_ROUTE;
22 import static com.android.server.telecom.CallAudioRouteController.INCLUDE_BLUETOOTH_IN_BASELINE;
23 
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNull;
27 import static org.junit.Assert.assertTrue;
28 import static org.mockito.ArgumentMatchers.isNull;
29 import static org.mockito.ArgumentMatchers.nullable;
30 import static org.mockito.ArgumentMatchers.any;
31 import static org.mockito.ArgumentMatchers.eq;
32 import static org.mockito.Mockito.atLeastOnce;
33 import static org.mockito.Mockito.mock;
34 import static org.mockito.Mockito.never;
35 import static org.mockito.Mockito.times;
36 import static org.mockito.Mockito.verify;
37 import static org.mockito.Mockito.when;
38 
39 import android.bluetooth.BluetoothAdapter;
40 import android.bluetooth.BluetoothDevice;
41 import android.bluetooth.BluetoothHeadset;
42 import android.bluetooth.BluetoothHearingAid;
43 import android.bluetooth.BluetoothLeAudio;
44 import android.bluetooth.BluetoothProfile;
45 import android.content.Intent;
46 import android.media.AudioDeviceInfo;
47 import android.media.AudioManager;
48 import android.os.Bundle;
49 import android.os.Parcel;
50 import android.telecom.CallAudioState;
51 
52 import androidx.test.filters.SmallTest;
53 
54 import com.android.server.telecom.AudioRoute;
55 import com.android.server.telecom.CallAudioCommunicationDeviceTracker;
56 import com.android.server.telecom.CallAudioRouteAdapter;
57 import com.android.server.telecom.CallAudioRouteController;
58 import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
59 import com.android.server.telecom.bluetooth.BluetoothRouteManager;
60 import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
61 
62 import org.junit.After;
63 import org.junit.Before;
64 import org.junit.Test;
65 import org.junit.runner.RunWith;
66 import org.junit.runners.JUnit4;
67 import org.mockito.ArgumentCaptor;
68 import org.mockito.Mock;
69 
70 import static org.mockito.Mockito.reset;
71 import java.util.ArrayList;
72 import java.util.Arrays;
73 import java.util.HashMap;
74 import java.util.List;
75 import java.util.Map;
76 import java.util.concurrent.Executor;
77 
78 @RunWith(JUnit4.class)
79 public class BluetoothDeviceManagerTest extends TelecomTestCase {
80     private static final String DEVICE_ADDRESS_1 = "00:00:00:00:00:01";
81 
82     @Mock BluetoothRouteManager mRouteManager;
83     @Mock BluetoothHeadset mBluetoothHeadset;
84     @Mock BluetoothAdapter mAdapter;
85     @Mock BluetoothHearingAid mBluetoothHearingAid;
86     @Mock BluetoothLeAudio mBluetoothLeAudio;
87     @Mock AudioManager mockAudioManager;
88     @Mock AudioDeviceInfo mSpeakerInfo;
89     @Mock Executor mExecutor;
90     @Mock CallAudioRouteController mCallAudioRouteController;
91     @Mock CallAudioState mCallAudioState;
92 
93     BluetoothDeviceManager mBluetoothDeviceManager;
94     BluetoothProfile.ServiceListener serviceListenerUnderTest;
95     BluetoothStateReceiver receiverUnderTest;
96     CallAudioCommunicationDeviceTracker mCommunicationDeviceTracker;
97     ArgumentCaptor<BluetoothLeAudio.Callback> leAudioCallbacksTest;
98 
99     private BluetoothDevice device1;
100     private BluetoothDevice device2;
101     private BluetoothDevice device3;
102     private BluetoothDevice device4;
103     private BluetoothDevice device5;
104     private BluetoothDevice device6;
105 
106     @Override
107     @Before
setUp()108     public void setUp() throws Exception {
109         super.setUp();
110         device1 = makeBluetoothDevice("00:00:00:00:00:01");
111         // hearing aid
112         device2 = makeBluetoothDevice("00:00:00:00:00:02");
113         device3 = makeBluetoothDevice("00:00:00:00:00:03");
114         // hearing aid
115         device4 = makeBluetoothDevice("00:00:00:00:00:04");
116         // le audio
117         device5 = makeBluetoothDevice("00:00:00:00:00:05");
118         device6 = makeBluetoothDevice("00:00:00:00:00:06");
119 
120         when(mBluetoothHearingAid.getHiSyncId(device2)).thenReturn(100L);
121         when(mBluetoothHearingAid.getHiSyncId(device4)).thenReturn(100L);
122 
123         mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
124         mCommunicationDeviceTracker = new CallAudioCommunicationDeviceTracker(mContext);
125         mBluetoothDeviceManager = new BluetoothDeviceManager(mContext, mAdapter,
126                 mCommunicationDeviceTracker, mFeatureFlags);
127         mBluetoothDeviceManager.setBluetoothRouteManager(mRouteManager);
128         mBluetoothDeviceManager.setCallAudioRouteAdapter(mCallAudioRouteController);
129         mCommunicationDeviceTracker.setBluetoothRouteManager(mRouteManager);
130 
131         mockAudioManager = mContext.getSystemService(AudioManager.class);
132         mExecutor = mContext.getMainExecutor();
133 
134         ArgumentCaptor<BluetoothProfile.ServiceListener> serviceCaptor =
135                 ArgumentCaptor.forClass(BluetoothProfile.ServiceListener.class);
136         verify(mAdapter).getProfileProxy(eq(mContext),
137                 serviceCaptor.capture(), eq(BluetoothProfile.HEADSET));
138         serviceListenerUnderTest = serviceCaptor.getValue();
139 
140         receiverUnderTest = new BluetoothStateReceiver(mBluetoothDeviceManager,
141                 mRouteManager, mCommunicationDeviceTracker, mFeatureFlags);
142 
143         mBluetoothDeviceManager.setHeadsetServiceForTesting(mBluetoothHeadset);
144         mBluetoothDeviceManager.setHearingAidServiceForTesting(mBluetoothHearingAid);
145 
146         leAudioCallbacksTest =
147                          ArgumentCaptor.forClass(BluetoothLeAudio.Callback.class);
148         mBluetoothDeviceManager.setLeAudioServiceForTesting(mBluetoothLeAudio);
149         verify(mBluetoothLeAudio).registerCallback(any(), leAudioCallbacksTest.capture());
150 
151         when(mSpeakerInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
152         when(mFeatureFlags.callAudioCommunicationDeviceRefactor()).thenReturn(false);
153         when(mFeatureFlags.useRefactoredAudioRouteSwitching()).thenReturn(false);
154     }
155 
156     @Override
157     @After
tearDown()158     public void tearDown() throws Exception {
159         super.tearDown();
160     }
161 
162     @SmallTest
163     @Test
testSingleDeviceConnectAndDisconnect()164     public void testSingleDeviceConnectAndDisconnect() {
165         receiverUnderTest.onReceive(mContext,
166                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
167                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
168         assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
169         receiverUnderTest.onReceive(mContext,
170                 buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device1,
171                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
172         assertEquals(0, mBluetoothDeviceManager.getNumConnectedDevices());
173     }
174 
175     @SmallTest
176     @Test
testAddDeviceFailsWhenServicesAreNull()177     public void testAddDeviceFailsWhenServicesAreNull() {
178         mBluetoothDeviceManager.setHeadsetServiceForTesting(null);
179         mBluetoothDeviceManager.setHearingAidServiceForTesting(null);
180 
181         receiverUnderTest.onReceive(mContext,
182                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
183                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
184         receiverUnderTest.onReceive(mContext,
185                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
186                         BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
187         receiverUnderTest.onReceive(mContext,
188                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
189                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
190 
191         assertEquals(0, mBluetoothDeviceManager.getNumConnectedDevices());
192     }
193 
194     @SmallTest
195     @Test
testMultiDeviceConnectAndDisconnect()196     public void testMultiDeviceConnectAndDisconnect() {
197         receiverUnderTest.onReceive(mContext,
198                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
199                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
200         receiverUnderTest.onReceive(mContext,
201                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
202                         BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
203         receiverUnderTest.onReceive(mContext,
204                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
205                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
206         leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
207         when(mBluetoothLeAudio.getGroupId(device5)).thenReturn(1);
208         when(mBluetoothLeAudio.getConnectedGroupLeadDevice(1)).thenReturn(device5);
209 
210         receiverUnderTest.onReceive(mContext,
211                 buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device1,
212                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
213         receiverUnderTest.onReceive(mContext,
214                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device6,
215                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
216         leAudioCallbacksTest.getValue().onGroupNodeAdded(device6, 2);
217         when(mBluetoothLeAudio.getConnectedGroupLeadDevice(2)).thenReturn(device6);
218         when(mBluetoothLeAudio.getGroupId(device6)).thenReturn(1);
219         receiverUnderTest.onReceive(mContext,
220                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3,
221                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
222         receiverUnderTest.onReceive(mContext,
223                 buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device5,
224                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
225         assertEquals(3, mBluetoothDeviceManager.getNumConnectedDevices());
226         receiverUnderTest.onReceive(mContext,
227                 buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device3,
228                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
229         receiverUnderTest.onReceive(mContext,
230                 buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device6,
231                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
232         assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
233     }
234 
235     @SmallTest
236     @Test
testLeAudioMissedGroupCallbackBeforeConnected()237     public void testLeAudioMissedGroupCallbackBeforeConnected() {
238         /* This should be called on connection state changed */
239         when(mBluetoothLeAudio.getGroupId(device5)).thenReturn(1);
240         when(mBluetoothLeAudio.getGroupId(device6)).thenReturn(1);
241 
242         receiverUnderTest.onReceive(mContext,
243                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
244                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
245         receiverUnderTest.onReceive(mContext,
246                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device6,
247                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
248         when(mBluetoothLeAudio.getConnectedGroupLeadDevice(1)).thenReturn(device5);
249         assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
250         assertEquals(1, mBluetoothDeviceManager.getUniqueConnectedDevices().size());
251     }
252 
253     @SmallTest
254     @Test
testLeAudioGroupAvailableBeforeConnect()255     public void testLeAudioGroupAvailableBeforeConnect() {
256         /* Device is known (e.g. from storage) */
257         leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
258         leAudioCallbacksTest.getValue().onGroupNodeAdded(device6, 1);
259         /* Make sure getGroupId is not called for known devices */
260         verify(mBluetoothLeAudio, never()).getGroupId(device5);
261         verify(mBluetoothLeAudio, never()).getGroupId(device6);
262 
263         receiverUnderTest.onReceive(mContext,
264                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
265                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
266         receiverUnderTest.onReceive(mContext,
267                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device6,
268                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
269         when(mBluetoothLeAudio.getConnectedGroupLeadDevice(1)).thenReturn(device5);
270         assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
271         assertEquals(1, mBluetoothDeviceManager.getUniqueConnectedDevices().size());
272     }
273 
274     @SmallTest
275     @Test
testHearingAidDedup()276     public void testHearingAidDedup() {
277         receiverUnderTest.onReceive(mContext,
278                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
279                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
280         receiverUnderTest.onReceive(mContext,
281                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
282                         BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
283         receiverUnderTest.onReceive(mContext,
284                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device4,
285                         BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
286         assertEquals(3, mBluetoothDeviceManager.getNumConnectedDevices());
287         assertEquals(2, mBluetoothDeviceManager.getUniqueConnectedDevices().size());
288     }
289 
290     @SmallTest
291     @Test
testLeAudioDedup()292     public void testLeAudioDedup() {
293         receiverUnderTest.onReceive(mContext,
294                 buildConnectionActionIntent(BluetoothProfile.STATE_CONNECTED, device1,
295                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
296         receiverUnderTest.onReceive(mContext,
297                 buildConnectionActionIntent(BluetoothProfile.STATE_CONNECTED, device5,
298                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
299         leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
300         receiverUnderTest.onReceive(mContext,
301                 buildConnectionActionIntent(BluetoothProfile.STATE_CONNECTED, device6,
302                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
303         leAudioCallbacksTest.getValue().onGroupNodeAdded(device6, 1);
304         when(mBluetoothLeAudio.getConnectedGroupLeadDevice(1)).thenReturn(device5);
305         when(mBluetoothLeAudio.getGroupId(device5)).thenReturn(1);
306         when(mBluetoothLeAudio.getGroupId(device6)).thenReturn(1);
307         assertEquals(2, mBluetoothDeviceManager.getNumConnectedDevices());
308         assertEquals(2, mBluetoothDeviceManager.getUniqueConnectedDevices().size());
309     }
310 
311     @SmallTest
312     @Test
testHandleAudioRefactoringServiceDisconnectedWhileBluetooth()313     public void testHandleAudioRefactoringServiceDisconnectedWhileBluetooth() {
314         when(mFeatureFlags.skipBaselineSwitchWhenRouteNotBluetooth()).thenReturn(true);
315         Map<AudioRoute, BluetoothDevice> btRoutes = new HashMap<>();
316         when(mCallAudioRouteController.getBluetoothRoutes()).thenReturn(btRoutes);
317         when(mCallAudioRouteController.getCurrentCallAudioState()).thenReturn(mCallAudioState);
318         when(mCallAudioState.getRoute()).thenReturn(CallAudioState.ROUTE_BLUETOOTH);
319 
320         mBluetoothDeviceManager
321                 .handleAudioRefactoringServiceDisconnected(BluetoothProfile.LE_AUDIO);
322 
323         verify(mCallAudioRouteController).sendMessageWithSessionInfo(SWITCH_BASELINE_ROUTE,
324                 INCLUDE_BLUETOOTH_IN_BASELINE, (String) null);
325     }
326 
327     @SmallTest
328     @Test
testHandleAudioRefactoringServiceDisconnectedWhileSpeaker()329     public void testHandleAudioRefactoringServiceDisconnectedWhileSpeaker() {
330         when(mFeatureFlags.skipBaselineSwitchWhenRouteNotBluetooth()).thenReturn(true);
331         Map<AudioRoute, BluetoothDevice> btRoutes = new HashMap<>();
332         when(mCallAudioRouteController.getBluetoothRoutes()).thenReturn(btRoutes);
333         when(mCallAudioRouteController.getCurrentCallAudioState()).thenReturn(mCallAudioState);
334         when(mCallAudioState.getRoute()).thenReturn(CallAudioState.ROUTE_SPEAKER);
335 
336         mBluetoothDeviceManager
337                 .handleAudioRefactoringServiceDisconnected(BluetoothProfile.LE_AUDIO);
338 
339         verify(mCallAudioRouteController, never()).sendMessageWithSessionInfo(SWITCH_BASELINE_ROUTE,
340                 INCLUDE_BLUETOOTH_IN_BASELINE, (String) null);
341     }
342 
343     @SmallTest
344     @Test
testHeadsetServiceDisconnect()345     public void testHeadsetServiceDisconnect() {
346         receiverUnderTest.onReceive(mContext,
347                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
348                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
349         receiverUnderTest.onReceive(mContext,
350                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3,
351                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
352         receiverUnderTest.onReceive(mContext,
353                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
354                         BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
355         serviceListenerUnderTest.onServiceDisconnected(BluetoothProfile.HEADSET);
356 
357         verify(mRouteManager).onActiveDeviceChanged(isNull(),
358                 eq(BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
359         verify(mRouteManager).onDeviceLost(device1.getAddress());
360         verify(mRouteManager).onDeviceLost(device3.getAddress());
361         verify(mRouteManager, never()).onDeviceLost(device2.getAddress());
362         assertNull(mBluetoothDeviceManager.getBluetoothHeadset());
363         assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
364     }
365 
366     @SmallTest
367     @Test
testHearingAidServiceDisconnect()368     public void testHearingAidServiceDisconnect() {
369         receiverUnderTest.onReceive(mContext,
370                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
371                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
372         receiverUnderTest.onReceive(mContext,
373                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3,
374                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
375         receiverUnderTest.onReceive(mContext,
376                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
377                         BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
378         serviceListenerUnderTest.onServiceDisconnected(BluetoothProfile.HEARING_AID);
379 
380         verify(mRouteManager).onActiveDeviceChanged(isNull(),
381                 eq(BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
382         verify(mRouteManager).onDeviceLost(device2.getAddress());
383         verify(mRouteManager, never()).onDeviceLost(device1.getAddress());
384         verify(mRouteManager, never()).onDeviceLost(device3.getAddress());
385         assertNull(mBluetoothDeviceManager.getBluetoothHearingAid());
386         assertEquals(2, mBluetoothDeviceManager.getNumConnectedDevices());
387     }
388 
389     @SmallTest
390     @Test
testLeAudioServiceDisconnect()391     public void testLeAudioServiceDisconnect() {
392         receiverUnderTest.onReceive(mContext,
393                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
394                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
395         receiverUnderTest.onReceive(mContext,
396                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3,
397                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
398         receiverUnderTest.onReceive(mContext,
399                 buildConnectionActionIntent(BluetoothLeAudio.STATE_CONNECTED, device5,
400                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
401         serviceListenerUnderTest.onServiceDisconnected(BluetoothProfile.LE_AUDIO);
402 
403         verify(mRouteManager).onActiveDeviceChanged(isNull(),
404                 eq(BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
405         verify(mRouteManager).onDeviceLost(device5.getAddress());
406         verify(mRouteManager, never()).onDeviceLost(device1.getAddress());
407         verify(mRouteManager, never()).onDeviceLost(device3.getAddress());
408         assertNull(mBluetoothDeviceManager.getLeAudioService());
409         assertEquals(2, mBluetoothDeviceManager.getNumConnectedDevices());
410     }
411 
412     @SmallTest
413     @Test
testHearingAidChangesIgnoredWhenNotInCall()414     public void testHearingAidChangesIgnoredWhenNotInCall() {
415         receiverUnderTest.setIsInCall(false);
416         receiverUnderTest.onReceive(mContext,
417                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
418                         BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
419         Intent activeDeviceChangedIntent =
420                 new Intent(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
421         activeDeviceChangedIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device2);
422         receiverUnderTest.onReceive(mContext, activeDeviceChangedIntent);
423 
424         verify(mRouteManager).onActiveDeviceChanged(device2,
425                 BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID);
426         verify(mRouteManager, never()).sendMessage(BluetoothRouteManager.BT_AUDIO_IS_ON);
427     }
428 
429     @SmallTest
430     @Test
testLeAudioGroupChangesIgnoredWhenNotInCall()431     public void testLeAudioGroupChangesIgnoredWhenNotInCall() {
432         receiverUnderTest.setIsInCall(false);
433         receiverUnderTest.onReceive(mContext,
434                 buildConnectionActionIntent(BluetoothLeAudio.STATE_CONNECTED, device5,
435                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
436         Intent activeDeviceChangedIntent =
437                         new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED);
438         activeDeviceChangedIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device5);
439         receiverUnderTest.onReceive(mContext, activeDeviceChangedIntent);
440 
441         verify(mRouteManager).onActiveDeviceChanged(device5,
442                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO);
443         verify(mRouteManager, never()).sendMessage(BluetoothRouteManager.BT_AUDIO_IS_ON);
444     }
445 
446     @SmallTest
447     @Test
testConnectDisconnectAudioHeadset()448     public void testConnectDisconnectAudioHeadset() {
449         receiverUnderTest.onReceive(mContext,
450                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
451                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
452         when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
453                     eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
454         mBluetoothDeviceManager.connectAudio(device1.getAddress(), false);
455         verify(mAdapter).setActiveDevice(eq(device1),
456                 eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
457         verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
458                 eq(BluetoothAdapter.ACTIVE_DEVICE_ALL));
459         mBluetoothDeviceManager.disconnectAudio();
460         verify(mBluetoothHeadset).disconnectAudio();
461     }
462 
463     @SmallTest
464     @Test
testConnectDisconnectAudioHearingAid()465     public void testConnectDisconnectAudioHearingAid() {
466         receiverUnderTest.setIsInCall(true);
467         receiverUnderTest.onReceive(mContext,
468                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
469                         BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
470         leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
471         when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
472                 eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
473 
474         AudioDeviceInfo mockAudioDeviceInfo = createMockAudioDeviceInfo(device5.getAddress(),
475                 AudioDeviceInfo.TYPE_HEARING_AID);
476         List<AudioDeviceInfo> devices = new ArrayList<>();
477         devices.add(mockAudioDeviceInfo);
478 
479         when(mockAudioManager.getAvailableCommunicationDevices())
480                 .thenReturn(devices);
481         when(mockAudioManager.setCommunicationDevice(eq(mockAudioDeviceInfo)))
482                 .thenReturn(true);
483 
484         mBluetoothDeviceManager.connectAudio(device5.getAddress(), false);
485         verify(mAdapter).setActiveDevice(device5, BluetoothAdapter.ACTIVE_DEVICE_ALL);
486         verify(mBluetoothHeadset, never()).connectAudio();
487         verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
488                 eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
489 
490         receiverUnderTest.onReceive(mContext, buildActiveDeviceChangeActionIntent(device5,
491                 BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
492 
493         when(mockAudioManager.getCommunicationDevice()).thenReturn(mockAudioDeviceInfo);
494         mBluetoothDeviceManager.disconnectAudio();
495         verify(mockAudioManager, atLeastOnce()).clearCommunicationDevice();
496     }
497 
498     @SmallTest
499     @Test
testConnectDisconnectAudioLeAudio()500     public void testConnectDisconnectAudioLeAudio() {
501         receiverUnderTest.setIsInCall(true);
502         receiverUnderTest.onReceive(mContext,
503                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
504                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
505         leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
506         when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
507                 eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
508 
509         AudioDeviceInfo mockAudioDeviceInfo = createMockAudioDeviceInfo(device5.getAddress(),
510                 AudioDeviceInfo.TYPE_BLE_HEADSET);
511         List<AudioDeviceInfo> devices = new ArrayList<>();
512         devices.add(mockAudioDeviceInfo);
513 
514         when(mockAudioManager.getAvailableCommunicationDevices())
515                         .thenReturn(devices);
516         when(mockAudioManager.setCommunicationDevice(mockAudioDeviceInfo))
517                        .thenReturn(true);
518 
519         mBluetoothDeviceManager.connectAudio(device5.getAddress(), false);
520         verify(mAdapter).setActiveDevice(device5, BluetoothAdapter.ACTIVE_DEVICE_ALL);
521         verify(mBluetoothHeadset, never()).connectAudio();
522         verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
523                 eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
524         verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
525                 eq(BluetoothAdapter.ACTIVE_DEVICE_AUDIO));
526 
527         receiverUnderTest.onReceive(mContext, buildActiveDeviceChangeActionIntent(device5,
528                 BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
529 
530         mBluetoothDeviceManager.disconnectAudio();
531         verify(mockAudioManager, atLeastOnce()).clearCommunicationDevice();
532     }
533 
534     @SmallTest
535     @Test
testConnectEarbudLeAudio()536     public void testConnectEarbudLeAudio() {
537         receiverUnderTest.setIsInCall(true);
538         receiverUnderTest.onReceive(mContext,
539                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
540                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
541         leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
542         receiverUnderTest.onReceive(mContext,
543                 buildConnectionActionIntent(BluetoothLeAudio.STATE_CONNECTED, device6,
544                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
545         leAudioCallbacksTest.getValue().onGroupNodeAdded(device6, 1);
546         when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
547                 eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
548         mBluetoothDeviceManager.connectAudio(device5.getAddress(), false);
549         verify(mAdapter).setActiveDevice(device5, BluetoothAdapter.ACTIVE_DEVICE_ALL);
550         verify(mBluetoothHeadset, never()).connectAudio();
551         verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
552                 eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
553         verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
554                 eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
555 
556         when(mAdapter.getActiveDevices(eq(BluetoothProfile.LE_AUDIO)))
557                 .thenReturn(Arrays.asList(device5, device6));
558 
559         receiverUnderTest.onReceive(mContext,
560                 buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device5,
561                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
562 
563         mBluetoothDeviceManager.connectAudio(device6.getAddress(), false);
564         verify(mAdapter).setActiveDevice(device6, BluetoothAdapter.ACTIVE_DEVICE_ALL);
565     }
566 
567     @SmallTest
568     @Test
testConnectMultipleLeAudioDevices()569     public void testConnectMultipleLeAudioDevices() {
570         when(mFeatureFlags.callAudioCommunicationDeviceRefactor()).thenReturn(true);
571         receiverUnderTest.setIsInCall(true);
572         receiverUnderTest.onReceive(mContext,
573                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
574                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
575         leAudioCallbacksTest.getValue().onGroupNodeAdded(device1, 1);
576         receiverUnderTest.onReceive(mContext,
577                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
578                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
579         leAudioCallbacksTest.getValue().onGroupNodeAdded(device2, 1);
580         when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
581                 eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
582 
583         List<AudioDeviceInfo> devices = new ArrayList<>();
584         AudioDeviceInfo leAudioDevice1 = createMockAudioDeviceInfo(device1.getAddress(),
585                 AudioDeviceInfo.TYPE_BLE_HEADSET);
586         AudioDeviceInfo leAudioDevice2 = createMockAudioDeviceInfo(device2.getAddress(),
587                 AudioDeviceInfo.TYPE_BLE_HEADSET);
588         devices.add(leAudioDevice1);
589         devices.add(leAudioDevice2);
590 
591         when(mockAudioManager.getAvailableCommunicationDevices())
592                 .thenReturn(devices);
593         when(mockAudioManager.setCommunicationDevice(any(AudioDeviceInfo.class)))
594                 .thenReturn(true);
595 
596         // Connect LE audio device
597         mBluetoothDeviceManager.connectAudio(device1.getAddress(), false);
598         verify(mAdapter).setActiveDevice(device1, BluetoothAdapter.ACTIVE_DEVICE_ALL);
599         verify(mBluetoothHeadset, never()).connectAudio();
600         verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
601                 eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
602         // Verify that we set the communication device for device 1
603         verify(mockAudioManager).setCommunicationDevice(leAudioDevice1);
604 
605         // Change active device to other LE audio device
606         receiverUnderTest.onReceive(mContext, buildActiveDeviceChangeActionIntent(device2,
607                 BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
608 
609         // Verify call to clearLeAudioCommunicationDevice
610         verify(mRouteManager).onAudioLost(eq(DEVICE_ADDRESS_1));
611         // Verify that we set the communication device for device2
612         verify(mockAudioManager).setCommunicationDevice(leAudioDevice2);
613     }
614 
615     @SmallTest
616     @Test
testClearCommunicationDeviceOnActiveDeviceChange()617     public void testClearCommunicationDeviceOnActiveDeviceChange() {
618         when(mFeatureFlags.callAudioCommunicationDeviceRefactor()).thenReturn(true);
619         receiverUnderTest.setIsInCall(true);
620 
621         List<AudioDeviceInfo> devices = new ArrayList<>();
622         AudioDeviceInfo leAudioDevice1 = createMockAudioDeviceInfo(device1.getAddress(),
623                 AudioDeviceInfo.TYPE_BLE_HEADSET);
624         devices.add(leAudioDevice1);
625 
626         when(mockAudioManager.getAvailableCommunicationDevices())
627                 .thenReturn(devices);
628         when(mockAudioManager.setCommunicationDevice(any(AudioDeviceInfo.class)))
629                 .thenReturn(true);
630 
631         // Pretend that the speaker device is currently the requested device set for communication.
632         // This test ensures that the set/clear communication logic for audio switching in/out of BT
633         // is properly working when the receiver processes an active device change intent.
634         mCommunicationDeviceTracker.setTestCommunicationDevice(TYPE_BUILTIN_SPEAKER);
635 
636         // Notify that LE audio device has been turned on
637         receiverUnderTest.onReceive(mContext, buildActiveDeviceChangeActionIntent(device1,
638                 BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
639         // Verify call to clear speaker communication device
640         verify(mockAudioManager).clearCommunicationDevice();
641         // Verify that LE audio communication device was set after clearing the speaker device
642         verify(mockAudioManager).setCommunicationDevice(leAudioDevice1);
643     }
644 
645     @SmallTest
646     @Test
testConnectDualModeEarbud()647     public void testConnectDualModeEarbud() {
648         when(mFeatureFlags.callAudioCommunicationDeviceRefactor()).thenReturn(true);
649         receiverUnderTest.setIsInCall(true);
650 
651         // LE Audio earbuds connected
652         receiverUnderTest.onReceive(mContext,
653                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
654                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
655         leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
656         receiverUnderTest.onReceive(mContext,
657                 buildConnectionActionIntent(BluetoothLeAudio.STATE_CONNECTED, device6,
658                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
659         leAudioCallbacksTest.getValue().onGroupNodeAdded(device6, 1);
660         // HFP device connected
661         receiverUnderTest.onReceive(mContext,
662                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
663                         BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
664         when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
665                 eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
666 
667         AudioDeviceInfo mockAudioDevice5Info = createMockAudioDeviceInfo(device5.getAddress(),
668                 AudioDeviceInfo.TYPE_BLE_HEADSET);
669         AudioDeviceInfo mockAudioDevice6Info = createMockAudioDeviceInfo(device6.getAddress(),
670                 AudioDeviceInfo.TYPE_BLE_HEADSET);
671         when(mockAudioDevice5Info.getType()).thenReturn(AudioDeviceInfo.TYPE_BLE_HEADSET);
672         when(mockAudioDevice6Info.getType()).thenReturn(AudioDeviceInfo.TYPE_BLE_HEADSET);
673         List<AudioDeviceInfo> devices = new ArrayList<>();
674         devices.add(mockAudioDevice5Info);
675         devices.add(mockAudioDevice6Info);
676 
677         when(mockAudioManager.getAvailableCommunicationDevices())
678                 .thenReturn(devices);
679         when(mockAudioManager.setCommunicationDevice(mockAudioDevice5Info))
680                 .thenReturn(true);
681 
682         Bundle hfpPreferred = new Bundle();
683         hfpPreferred.putInt(BluetoothAdapter.AUDIO_MODE_DUPLEX, BluetoothProfile.HEADSET);
684         Bundle leAudioPreferred = new Bundle();
685         leAudioPreferred.putInt(BluetoothAdapter.AUDIO_MODE_DUPLEX, BluetoothProfile.LE_AUDIO);
686 
687         // TEST 1: LE Audio preferred for DUPLEX
688         when(mAdapter.getPreferredAudioProfiles(device5)).thenReturn(leAudioPreferred);
689         when(mAdapter.getPreferredAudioProfiles(device6)).thenReturn(leAudioPreferred);
690         mBluetoothDeviceManager.connectAudio(device5.getAddress(), false);
691         verify(mAdapter, times(1)).setActiveDevice(device5, BluetoothAdapter.ACTIVE_DEVICE_ALL);
692         verify(mBluetoothHeadset, never()).connectAudio();
693         verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
694                 eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
695         verify(mockAudioManager).setCommunicationDevice(mockAudioDevice5Info);
696 
697         when(mAdapter.getActiveDevices(eq(BluetoothProfile.LE_AUDIO)))
698                 .thenReturn(Arrays.asList(device5, device6));
699 
700         // Check disconnect during a call
701         devices.remove(mockAudioDevice5Info);
702         receiverUnderTest.onReceive(mContext,
703                 buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device5,
704                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
705         leAudioCallbacksTest.getValue().onGroupNodeRemoved(device5, 1);
706 
707         mBluetoothDeviceManager.connectAudio(device6.getAddress(), false);
708         verify(mAdapter).setActiveDevice(device6, BluetoothAdapter.ACTIVE_DEVICE_ALL);
709         verify(mBluetoothHeadset, never()).connectAudio();
710         verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
711                 eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
712         verify(mockAudioManager, times(1)).clearCommunicationDevice();
713 
714         // Reconnect other LE Audio earbud
715         devices.add(mockAudioDevice5Info);
716         receiverUnderTest.onReceive(mContext,
717                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
718                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
719         leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
720 
721         // Disconnects audio
722         mBluetoothDeviceManager.disconnectAudio();
723         verify(mockAudioManager, times(2)).clearCommunicationDevice();
724         verify(mBluetoothHeadset, times(1)).disconnectAudio();
725 
726         // TEST 2: HFP preferred for DUPLEX
727         when(mAdapter.getPreferredAudioProfiles(device5)).thenReturn(hfpPreferred);
728         when(mAdapter.getPreferredAudioProfiles(device6)).thenReturn(hfpPreferred);
729         when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
730                 eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL))).thenReturn(true);
731         mBluetoothDeviceManager.connectAudio(device5.getAddress(), false);
732         verify(mAdapter).setActiveDevice(device5, BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL);
733         verify(mAdapter, times(1)).setActiveDevice(device5,
734                 BluetoothAdapter.ACTIVE_DEVICE_ALL);
735         verify(mBluetoothHeadset).connectAudio();
736         mBluetoothDeviceManager.disconnectAudio();
737         verify(mBluetoothHeadset, times(2)).disconnectAudio();
738     }
739 
740     @SmallTest
741     @Test
testClearHearingAidCommunicationDeviceLegacy()742     public void testClearHearingAidCommunicationDeviceLegacy() {
743         assertClearHearingAidOrLeCommunicationDevice(false, AudioDeviceInfo.TYPE_HEARING_AID);
744     }
745 
746     @SmallTest
747     @Test
testClearHearingAidCommunicationDeviceWithFlag()748     public void testClearHearingAidCommunicationDeviceWithFlag() {
749         when(mFeatureFlags.callAudioCommunicationDeviceRefactor()).thenReturn(true);
750         assertClearHearingAidOrLeCommunicationDevice(true, AudioDeviceInfo.TYPE_HEARING_AID);
751     }
752 
753     @SmallTest
754     @Test
testClearLeAudioCommunicationDeviceLegacy()755     public void testClearLeAudioCommunicationDeviceLegacy() {
756         assertClearHearingAidOrLeCommunicationDevice(false, AudioDeviceInfo.TYPE_BLE_HEADSET);
757     }
758 
759     @SmallTest
760     @Test
testClearLeAudioCommunicationDeviceWithFlag()761     public void testClearLeAudioCommunicationDeviceWithFlag() {
762         when(mFeatureFlags.callAudioCommunicationDeviceRefactor()).thenReturn(true);
763         assertClearHearingAidOrLeCommunicationDevice(true, AudioDeviceInfo.TYPE_BLE_HEADSET);
764     }
765 
766     @SmallTest
767     @Test
testConnectedDevicesDoNotContainDuplicateDevices()768     public void testConnectedDevicesDoNotContainDuplicateDevices() {
769         BluetoothDevice hfpDevice = mock(BluetoothDevice.class);
770         when(hfpDevice.getAddress()).thenReturn("00:00:00:00:00:00");
771         when(hfpDevice.getType()).thenReturn(BluetoothDeviceManager.DEVICE_TYPE_HEADSET);
772         BluetoothDevice leDevice = mock(BluetoothDevice.class);
773         when(hfpDevice.getAddress()).thenReturn("00:00:00:00:00:00");
774         when(hfpDevice.getType()).thenReturn(BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO);
775 
776         mBluetoothDeviceManager.onDeviceConnected(hfpDevice,
777                 BluetoothDeviceManager.DEVICE_TYPE_HEADSET);
778         mBluetoothDeviceManager.onDeviceConnected(leDevice,
779                 BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO);
780 
781         assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
782     }
783 
784     @SmallTest
785     @Test
testInBandRingingEnabledForLeDevice()786     public void testInBandRingingEnabledForLeDevice() {
787         when(mBluetoothHeadset.isInbandRingingEnabled()).thenReturn(false);
788         when(mBluetoothLeAudio.isInbandRingtoneEnabled(1)).thenReturn(true);
789         when(mBluetoothLeAudio.getGroupId(eq(device3))).thenReturn(1);
790         receiverUnderTest.onReceive(mContext,
791                 buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3,
792                         BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
793         leAudioCallbacksTest.getValue().onGroupNodeAdded(device3, 1);
794         when(mRouteManager.getBluetoothAudioConnectedDevice()).thenReturn(device3);
795         when(mRouteManager.isCachedLeAudioDevice(eq(device3))).thenReturn(true);
796         when(mBluetoothLeAudio.getConnectedGroupLeadDevice(1)).thenReturn(device3);
797         when(mRouteManager.getMostRecentlyReportedActiveDevice()).thenReturn(device3);
798         assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
799         assertTrue(mBluetoothDeviceManager.isInbandRingingEnabled());
800     }
801 
802     @SmallTest
803     @Test
testRegisterLeAudioCallbackNoPostpone()804     public void testRegisterLeAudioCallbackNoPostpone() {
805         reset(mBluetoothLeAudio);
806         when(mFeatureFlags.postponeRegisterToLeaudio()).thenReturn(false);
807         serviceListenerUnderTest.onServiceConnected(BluetoothProfile.LE_AUDIO,
808                         (BluetoothProfile) mBluetoothLeAudio);
809         // Second time on purpose
810         serviceListenerUnderTest.onServiceConnected(BluetoothProfile.LE_AUDIO,
811                         (BluetoothProfile) mBluetoothLeAudio);
812         verify(mExecutor, times(0)).execute(any());
813         verify(mBluetoothLeAudio, times(1)).registerCallback(any(Executor.class),
814                         any(BluetoothLeAudio.Callback.class));
815     }
816 
817     @SmallTest
818     @Test
testRegisterLeAudioCallbackWithPostpone()819     public void testRegisterLeAudioCallbackWithPostpone() {
820         reset(mBluetoothLeAudio);
821         when(mFeatureFlags.postponeRegisterToLeaudio()).thenReturn(true);
822         serviceListenerUnderTest.onServiceConnected(BluetoothProfile.LE_AUDIO,
823                         (BluetoothProfile) mBluetoothLeAudio);
824         verify(mExecutor, times(1)).execute(any());
825     }
826 
assertClearHearingAidOrLeCommunicationDevice( boolean flagEnabled, int device_type )827     private void assertClearHearingAidOrLeCommunicationDevice(
828             boolean flagEnabled, int device_type
829     ) {
830         AudioDeviceInfo mockAudioDeviceInfo = mock(AudioDeviceInfo.class);
831         when(mockAudioDeviceInfo.getAddress()).thenReturn(DEVICE_ADDRESS_1);
832         when(mockAudioDeviceInfo.getType()).thenReturn(device_type);
833         List<AudioDeviceInfo> devices = new ArrayList<>();
834         devices.add(mockAudioDeviceInfo);
835 
836         when(mockAudioManager.getAvailableCommunicationDevices())
837                 .thenReturn(devices);
838         when(mockAudioManager.setCommunicationDevice(eq(mockAudioDeviceInfo)))
839                 .thenReturn(true);
840 
841         if (flagEnabled) {
842             BluetoothDevice btDevice = device_type == AudioDeviceInfo.TYPE_BLE_HEADSET
843                     ? device1 : null;
844             mCommunicationDeviceTracker.setCommunicationDevice(device_type, btDevice);
845         } else {
846             if (device_type == AudioDeviceInfo.TYPE_BLE_HEADSET) {
847                 mBluetoothDeviceManager.setLeAudioCommunicationDevice();
848             } else {
849                 mBluetoothDeviceManager.setHearingAidCommunicationDevice();
850             }
851         }
852         when(mockAudioManager.getCommunicationDevice()).thenReturn(mSpeakerInfo);
853         if (flagEnabled) {
854             mCommunicationDeviceTracker.clearCommunicationDevice(device_type);
855             assertFalse(mCommunicationDeviceTracker.isAudioDeviceSetForType(device_type));
856         } else {
857             if (device_type == AudioDeviceInfo.TYPE_BLE_HEADSET) {
858                 mBluetoothDeviceManager.clearLeAudioCommunicationDevice();
859                 assertFalse(mBluetoothDeviceManager.isLeAudioCommunicationDevice());
860             } else {
861                 mBluetoothDeviceManager.clearHearingAidCommunicationDevice();
862                 assertFalse(mBluetoothDeviceManager.isHearingAidSetAsCommunicationDevice());
863             }
864         }
865         verify(mRouteManager).onAudioLost(eq(DEVICE_ADDRESS_1));
866     }
867 
createMockAudioDeviceInfo(String address, int audioType)868     private AudioDeviceInfo createMockAudioDeviceInfo(String address, int audioType) {
869         AudioDeviceInfo mockAudioDeviceInfo = mock(AudioDeviceInfo.class);
870         when(mockAudioDeviceInfo.getType()).thenReturn(audioType);
871         if (address != null) {
872             when(mockAudioDeviceInfo.getAddress()).thenReturn(address);
873         }
874         return mockAudioDeviceInfo;
875     }
876 
buildConnectionActionIntent(int state, BluetoothDevice device, int deviceType)877     private Intent buildConnectionActionIntent(int state, BluetoothDevice device, int deviceType) {
878         String intentString;
879 
880         switch (deviceType) {
881             case BluetoothDeviceManager.DEVICE_TYPE_HEADSET:
882                 intentString = BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED;
883                 break;
884             case BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID:
885                 intentString = BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED;
886                 break;
887             case BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO:
888                 intentString = BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED;
889                 break;
890             default:
891                 return null;
892         }
893 
894         Intent i = new Intent(intentString);
895         i.putExtra(BluetoothHeadset.EXTRA_STATE, state);
896         i.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
897         return i;
898     }
899 
900 
buildActiveDeviceChangeActionIntent(BluetoothDevice device, int deviceType)901     private Intent buildActiveDeviceChangeActionIntent(BluetoothDevice device, int deviceType) {
902         String intentString;
903 
904         switch (deviceType) {
905             case BluetoothDeviceManager.DEVICE_TYPE_HEADSET:
906                 intentString = BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED;
907                 break;
908             case BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID:
909                 intentString = BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED;
910                 break;
911             case BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO:
912                 intentString = BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED;
913                 break;
914             default:
915                 return null;
916         }
917 
918         Intent i = new Intent(intentString);
919         i.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
920         i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
921                 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
922         return i;
923     }
924 
makeBluetoothDevice(String address)925     private BluetoothDevice makeBluetoothDevice(String address) {
926         Parcel p1 = Parcel.obtain();
927         p1.writeString(address);
928         p1.setDataPosition(0);
929         BluetoothDevice device = BluetoothDevice.CREATOR.createFromParcel(p1);
930         p1.recycle();
931         return device;
932     }
933 }
934