• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 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.bluetooth.btservice;
18 
19 import static org.mockito.Mockito.*;
20 
21 import android.bluetooth.BluetoothA2dp;
22 import android.bluetooth.BluetoothAdapter;
23 import android.bluetooth.BluetoothDevice;
24 import android.bluetooth.BluetoothHeadset;
25 import android.bluetooth.BluetoothHearingAid;
26 import android.bluetooth.BluetoothProfile;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.media.AudioManager;
30 import android.support.test.InstrumentationRegistry;
31 import android.support.test.filters.MediumTest;
32 import android.support.test.runner.AndroidJUnit4;
33 
34 import com.android.bluetooth.R;
35 import com.android.bluetooth.TestUtils;
36 import com.android.bluetooth.a2dp.A2dpService;
37 import com.android.bluetooth.hearingaid.HearingAidService;
38 import com.android.bluetooth.hfp.HeadsetService;
39 
40 import org.junit.After;
41 import org.junit.Assert;
42 import org.junit.Assume;
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 import org.mockito.Mock;
47 import org.mockito.MockitoAnnotations;
48 
49 @MediumTest
50 @RunWith(AndroidJUnit4.class)
51 public class ActiveDeviceManagerTest {
52     private BluetoothAdapter mAdapter;
53     private Context mContext;
54     private BluetoothDevice mA2dpDevice;
55     private BluetoothDevice mHeadsetDevice;
56     private BluetoothDevice mA2dpHeadsetDevice;
57     private BluetoothDevice mHearingAidDevice;
58     private ActiveDeviceManager mActiveDeviceManager;
59     private static final int TIMEOUT_MS = 1000;
60 
61     @Mock private AdapterService mAdapterService;
62     @Mock private ServiceFactory mServiceFactory;
63     @Mock private A2dpService mA2dpService;
64     @Mock private HeadsetService mHeadsetService;
65     @Mock private HearingAidService mHearingAidService;
66     @Mock private AudioManager mAudioManager;
67 
68     @Before
setUp()69     public void setUp() throws Exception {
70         mContext = InstrumentationRegistry.getTargetContext();
71         Assume.assumeTrue("Ignore test when A2dpService is not enabled",
72                 mContext.getResources().getBoolean(R.bool.profile_supported_a2dp));
73         Assume.assumeTrue("Ignore test when HeadsetService is not enabled",
74                 mContext.getResources().getBoolean(R.bool.profile_supported_hs_hfp));
75 
76         // Set up mocks and test assets
77         MockitoAnnotations.initMocks(this);
78         TestUtils.setAdapterService(mAdapterService);
79         when(mAdapterService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager);
80         when(mServiceFactory.getA2dpService()).thenReturn(mA2dpService);
81         when(mServiceFactory.getHeadsetService()).thenReturn(mHeadsetService);
82         when(mServiceFactory.getHearingAidService()).thenReturn(mHearingAidService);
83         when(mA2dpService.setActiveDevice(any())).thenReturn(true);
84         when(mHeadsetService.setActiveDevice(any())).thenReturn(true);
85         when(mHearingAidService.setActiveDevice(any())).thenReturn(true);
86 
87         mActiveDeviceManager = new ActiveDeviceManager(mAdapterService, mServiceFactory);
88         mActiveDeviceManager.start();
89         mAdapter = BluetoothAdapter.getDefaultAdapter();
90 
91         // Get devices for testing
92         mA2dpDevice = TestUtils.getTestDevice(mAdapter, 0);
93         mHeadsetDevice = TestUtils.getTestDevice(mAdapter, 1);
94         mA2dpHeadsetDevice = TestUtils.getTestDevice(mAdapter, 2);
95         mHearingAidDevice = TestUtils.getTestDevice(mAdapter, 3);
96     }
97 
98     @After
tearDown()99     public void tearDown() throws Exception {
100         if (!mContext.getResources().getBoolean(R.bool.profile_supported_hs_hfp)
101                 || !mContext.getResources().getBoolean(R.bool.profile_supported_a2dp)) {
102             return;
103         }
104         mActiveDeviceManager.cleanup();
105         TestUtils.clearAdapterService(mAdapterService);
106     }
107 
108     @Test
testSetUpAndTearDown()109     public void testSetUpAndTearDown() {}
110 
111     /**
112      * One A2DP is connected.
113      */
114     @Test
onlyA2dpConnected_setA2dpActive()115     public void onlyA2dpConnected_setA2dpActive() {
116         a2dpConnected(mA2dpDevice);
117         verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
118     }
119 
120     /**
121      * Two A2DP are connected. Should set the second one active.
122      */
123     @Test
secondA2dpConnected_setSecondA2dpActive()124     public void secondA2dpConnected_setSecondA2dpActive() {
125         a2dpConnected(mA2dpDevice);
126         verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
127 
128         a2dpConnected(mA2dpHeadsetDevice);
129         verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
130     }
131 
132     /**
133      * One A2DP is connected and disconnected later. Should then set active device to null.
134      */
135     @Test
lastA2dpDisconnected_clearA2dpActive()136     public void lastA2dpDisconnected_clearA2dpActive() {
137         a2dpConnected(mA2dpDevice);
138         verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
139 
140         a2dpDisconnected(mA2dpDevice);
141         verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
142     }
143 
144     /**
145      * Two A2DP are connected and active device is explicitly set.
146      */
147     @Test
a2dpActiveDeviceSelected_setActive()148     public void a2dpActiveDeviceSelected_setActive() {
149         a2dpConnected(mA2dpDevice);
150         verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
151 
152         a2dpConnected(mA2dpHeadsetDevice);
153         verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
154 
155         a2dpActiveDeviceChanged(mA2dpDevice);
156         // Don't call mA2dpService.setActiveDevice()
157         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
158         verify(mA2dpService, times(1)).setActiveDevice(mA2dpDevice);
159         Assert.assertEquals(mA2dpDevice, mActiveDeviceManager.getA2dpActiveDevice());
160     }
161 
162     /**
163      * One Headset is connected.
164      */
165     @Test
onlyHeadsetConnected_setHeadsetActive()166     public void onlyHeadsetConnected_setHeadsetActive() {
167         headsetConnected(mHeadsetDevice);
168         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
169     }
170 
171     /**
172      * Two Headset are connected. Should set the second one active.
173      */
174     @Test
secondHeadsetConnected_setSecondHeadsetActive()175     public void secondHeadsetConnected_setSecondHeadsetActive() {
176         headsetConnected(mHeadsetDevice);
177         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
178 
179         headsetConnected(mA2dpHeadsetDevice);
180         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
181     }
182 
183     /**
184      * One Headset is connected and disconnected later. Should then set active device to null.
185      */
186     @Test
lastHeadsetDisconnected_clearHeadsetActive()187     public void lastHeadsetDisconnected_clearHeadsetActive() {
188         headsetConnected(mHeadsetDevice);
189         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
190 
191         headsetDisconnected(mHeadsetDevice);
192         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
193     }
194 
195     /**
196      * Two Headset are connected and active device is explicitly set.
197      */
198     @Test
headsetActiveDeviceSelected_setActive()199     public void headsetActiveDeviceSelected_setActive() {
200         headsetConnected(mHeadsetDevice);
201         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
202 
203         headsetConnected(mA2dpHeadsetDevice);
204         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
205 
206         headsetActiveDeviceChanged(mHeadsetDevice);
207         // Don't call mHeadsetService.setActiveDevice()
208         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
209         verify(mHeadsetService, times(1)).setActiveDevice(mHeadsetDevice);
210         Assert.assertEquals(mHeadsetDevice, mActiveDeviceManager.getHfpActiveDevice());
211     }
212 
213     /**
214      * A combo (A2DP + Headset) device is connected. Then a Hearing Aid is connected.
215      */
216     @Test
hearingAidActive_clearA2dpAndHeadsetActive()217     public void hearingAidActive_clearA2dpAndHeadsetActive() {
218         Assume.assumeTrue("Ignore test when HearingAidService is not enabled",
219                 mContext.getResources().getBoolean(R.bool.profile_supported_hearing_aid));
220 
221         a2dpConnected(mA2dpHeadsetDevice);
222         headsetConnected(mA2dpHeadsetDevice);
223         verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
224         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpHeadsetDevice);
225 
226         hearingAidActiveDeviceChanged(mHearingAidDevice);
227         verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
228         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
229     }
230 
231     /**
232      * A Hearing Aid is connected. Then a combo (A2DP + Headset) device is connected.
233      */
234     @Test
hearingAidActive_dontSetA2dpAndHeadsetActive()235     public void hearingAidActive_dontSetA2dpAndHeadsetActive() {
236         Assume.assumeTrue("Ignore test when HearingAidService is not enabled",
237                 mContext.getResources().getBoolean(R.bool.profile_supported_hearing_aid));
238 
239         hearingAidActiveDeviceChanged(mHearingAidDevice);
240         a2dpConnected(mA2dpHeadsetDevice);
241         headsetConnected(mA2dpHeadsetDevice);
242 
243         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
244         verify(mA2dpService, never()).setActiveDevice(mA2dpHeadsetDevice);
245         verify(mHeadsetService, never()).setActiveDevice(mA2dpHeadsetDevice);
246     }
247 
248     /**
249      * A Hearing Aid is connected. Then an A2DP active device is explicitly set.
250      */
251     @Test
hearingAidActive_setA2dpActiveExplicitly()252     public void hearingAidActive_setA2dpActiveExplicitly() {
253         Assume.assumeTrue("Ignore test when HearingAidService is not enabled",
254                 mContext.getResources().getBoolean(R.bool.profile_supported_hearing_aid));
255 
256         hearingAidActiveDeviceChanged(mHearingAidDevice);
257         a2dpConnected(mA2dpHeadsetDevice);
258         a2dpActiveDeviceChanged(mA2dpHeadsetDevice);
259 
260         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
261         verify(mHearingAidService).setActiveDevice(isNull());
262         // Don't call mA2dpService.setActiveDevice()
263         verify(mA2dpService, never()).setActiveDevice(mA2dpHeadsetDevice);
264         Assert.assertEquals(mA2dpHeadsetDevice, mActiveDeviceManager.getA2dpActiveDevice());
265         Assert.assertEquals(null, mActiveDeviceManager.getHearingAidActiveDevice());
266     }
267 
268     /**
269      * A Hearing Aid is connected. Then a Headset active device is explicitly set.
270      */
271     @Test
hearingAidActive_setHeadsetActiveExplicitly()272     public void hearingAidActive_setHeadsetActiveExplicitly() {
273         Assume.assumeTrue("Ignore test when HearingAidService is not enabled",
274                 mContext.getResources().getBoolean(R.bool.profile_supported_hearing_aid));
275 
276         hearingAidActiveDeviceChanged(mHearingAidDevice);
277         headsetConnected(mA2dpHeadsetDevice);
278         headsetActiveDeviceChanged(mA2dpHeadsetDevice);
279 
280         TestUtils.waitForLooperToFinishScheduledTask(mActiveDeviceManager.getHandlerLooper());
281         verify(mHearingAidService).setActiveDevice(isNull());
282         // Don't call mHeadsetService.setActiveDevice()
283         verify(mHeadsetService, never()).setActiveDevice(mA2dpHeadsetDevice);
284         Assert.assertEquals(mA2dpHeadsetDevice, mActiveDeviceManager.getHfpActiveDevice());
285         Assert.assertEquals(null, mActiveDeviceManager.getHearingAidActiveDevice());
286     }
287 
288     /**
289      * A wired audio device is connected. Then all active devices are set to null.
290      */
291     @Test
wiredAudioDeviceConnected_setAllActiveDevicesNull()292     public void wiredAudioDeviceConnected_setAllActiveDevicesNull() {
293         a2dpConnected(mA2dpDevice);
294         headsetConnected(mHeadsetDevice);
295         verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(mA2dpDevice);
296         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(mHeadsetDevice);
297 
298         mActiveDeviceManager.wiredAudioDeviceConnected();
299         verify(mA2dpService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
300         verify(mHeadsetService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
301         verify(mHearingAidService, timeout(TIMEOUT_MS)).setActiveDevice(isNull());
302     }
303 
304     /**
305      * Helper to indicate A2dp connected for a device.
306      */
a2dpConnected(BluetoothDevice device)307     private void a2dpConnected(BluetoothDevice device) {
308         Intent intent = new Intent(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
309         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
310         intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_DISCONNECTED);
311         intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
312         mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent);
313     }
314 
315     /**
316      * Helper to indicate A2dp disconnected for a device.
317      */
a2dpDisconnected(BluetoothDevice device)318     private void a2dpDisconnected(BluetoothDevice device) {
319         Intent intent = new Intent(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
320         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
321         intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTED);
322         intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED);
323         mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent);
324     }
325 
326     /**
327      * Helper to indicate A2dp active device changed for a device.
328      */
a2dpActiveDeviceChanged(BluetoothDevice device)329     private void a2dpActiveDeviceChanged(BluetoothDevice device) {
330         Intent intent = new Intent(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
331         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
332         mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent);
333     }
334 
335     /**
336      * Helper to indicate Headset connected for a device.
337      */
headsetConnected(BluetoothDevice device)338     private void headsetConnected(BluetoothDevice device) {
339         Intent intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
340         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
341         intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_DISCONNECTED);
342         intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_CONNECTED);
343         mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent);
344     }
345 
346     /**
347      * Helper to indicate Headset disconnected for a device.
348      */
headsetDisconnected(BluetoothDevice device)349     private void headsetDisconnected(BluetoothDevice device) {
350         Intent intent = new Intent(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
351         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
352         intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, BluetoothProfile.STATE_CONNECTED);
353         intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED);
354         mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent);
355     }
356 
357     /**
358      * Helper to indicate Headset active device changed for a device.
359      */
headsetActiveDeviceChanged(BluetoothDevice device)360     private void headsetActiveDeviceChanged(BluetoothDevice device) {
361         Intent intent = new Intent(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED);
362         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
363         mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent);
364     }
365 
366     /**
367      * Helper to indicate Hearing Aid active device changed for a device.
368      */
hearingAidActiveDeviceChanged(BluetoothDevice device)369     private void hearingAidActiveDeviceChanged(BluetoothDevice device) {
370         Intent intent = new Intent(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
371         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
372         mActiveDeviceManager.getBroadcastReceiver().onReceive(mContext, intent);
373     }
374 }
375