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.hfp;
18 
19 import static org.mockito.Mockito.*;
20 
21 import android.bluetooth.BluetoothAdapter;
22 import android.bluetooth.BluetoothDevice;
23 import android.bluetooth.BluetoothHeadset;
24 import android.bluetooth.BluetoothProfile;
25 import android.bluetooth.BluetoothUuid;
26 import android.bluetooth.IBluetoothHeadset;
27 import android.content.Context;
28 import android.media.AudioManager;
29 import android.os.ParcelUuid;
30 import android.os.RemoteException;
31 import android.os.SystemClock;
32 
33 import androidx.test.InstrumentationRegistry;
34 import androidx.test.filters.MediumTest;
35 import androidx.test.rule.ServiceTestRule;
36 import androidx.test.runner.AndroidJUnit4;
37 
38 import com.android.bluetooth.R;
39 import com.android.bluetooth.TestUtils;
40 import com.android.bluetooth.btservice.AdapterService;
41 import com.android.bluetooth.btservice.storage.DatabaseManager;
42 
43 import org.hamcrest.Matchers;
44 import org.junit.After;
45 import org.junit.Assert;
46 import org.junit.Assume;
47 import org.junit.Before;
48 import org.junit.Rule;
49 import org.junit.Test;
50 import org.junit.runner.RunWith;
51 import org.mockito.Mock;
52 import org.mockito.MockitoAnnotations;
53 import org.mockito.Spy;
54 
55 import java.lang.reflect.Method;
56 import java.util.ArrayList;
57 import java.util.Collections;
58 import java.util.HashMap;
59 import java.util.Set;
60 
61 /**
62  * Tests for {@link HeadsetService}
63  */
64 @MediumTest
65 @RunWith(AndroidJUnit4.class)
66 public class HeadsetServiceTest {
67     private static final int MAX_HEADSET_CONNECTIONS = 5;
68     private static final ParcelUuid[] FAKE_HEADSET_UUID = {BluetoothUuid.HFP};
69     private static final int ASYNC_CALL_TIMEOUT_MILLIS = 250;
70     private static final String TEST_PHONE_NUMBER = "1234567890";
71 
72     private Context mTargetContext;
73     private HeadsetService mHeadsetService;
74     private IBluetoothHeadset.Stub mHeadsetServiceBinder;
75     private BluetoothAdapter mAdapter;
76     private HeadsetNativeInterface mNativeInterface;
77     private BluetoothDevice mCurrentDevice;
78     private final HashMap<BluetoothDevice, HeadsetStateMachine> mStateMachines = new HashMap<>();
79 
80     @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule();
81 
82     @Spy private HeadsetObjectsFactory mObjectsFactory = HeadsetObjectsFactory.getInstance();
83     @Mock private AdapterService mAdapterService;
84     @Mock private DatabaseManager mDatabaseManager;
85     @Mock private HeadsetSystemInterface mSystemInterface;
86     @Mock private AudioManager mAudioManager;
87     @Mock private HeadsetPhoneState mPhoneState;
88 
89     @Before
setUp()90     public void setUp() throws Exception {
91         mTargetContext = InstrumentationRegistry.getTargetContext();
92         Assume.assumeTrue("Ignore test when HeadsetService is not enabled",
93                 mTargetContext.getResources().getBoolean(R.bool.profile_supported_hs_hfp));
94         MockitoAnnotations.initMocks(this);
95         TestUtils.setAdapterService(mAdapterService);
96         // We cannot mock HeadsetObjectsFactory.getInstance() with Mockito.
97         // Hence we need to use reflection to call a private method to
98         // initialize properly the HeadsetObjectsFactory.sInstance field.
99         Method method = HeadsetObjectsFactory.class.getDeclaredMethod("setInstanceForTesting",
100                 HeadsetObjectsFactory.class);
101         method.setAccessible(true);
102         method.invoke(null, mObjectsFactory);
103         doReturn(MAX_HEADSET_CONNECTIONS).when(mAdapterService).getMaxConnectedAudioDevices();
104         doReturn(new ParcelUuid[]{BluetoothUuid.HFP}).when(mAdapterService)
105                 .getRemoteUuids(any(BluetoothDevice.class));
106         // This line must be called to make sure relevant objects are initialized properly
107         mAdapter = BluetoothAdapter.getDefaultAdapter();
108         // Mock methods in AdapterService
109         doReturn(FAKE_HEADSET_UUID).when(mAdapterService)
110                 .getRemoteUuids(any(BluetoothDevice.class));
111         doReturn(BluetoothDevice.BOND_BONDED).when(mAdapterService)
112                 .getBondState(any(BluetoothDevice.class));
113         doAnswer(invocation -> {
114             Set<BluetoothDevice> keys = mStateMachines.keySet();
115             return keys.toArray(new BluetoothDevice[keys.size()]);
116         }).when(mAdapterService).getBondedDevices();
117         // Mock system interface
118         doNothing().when(mSystemInterface).init();
119         doNothing().when(mSystemInterface).stop();
120         when(mSystemInterface.getHeadsetPhoneState()).thenReturn(mPhoneState);
121         when(mSystemInterface.getAudioManager()).thenReturn(mAudioManager);
122         when(mSystemInterface.isCallIdle()).thenReturn(true);
123         // Mock methods in HeadsetNativeInterface
124         mNativeInterface = spy(HeadsetNativeInterface.getInstance());
125         doNothing().when(mNativeInterface).init(anyInt(), anyBoolean());
126         doNothing().when(mNativeInterface).cleanup();
127         doReturn(true).when(mNativeInterface).connectHfp(any(BluetoothDevice.class));
128         doReturn(true).when(mNativeInterface).disconnectHfp(any(BluetoothDevice.class));
129         doReturn(true).when(mNativeInterface).connectAudio(any(BluetoothDevice.class));
130         doReturn(true).when(mNativeInterface).disconnectAudio(any(BluetoothDevice.class));
131         doReturn(true).when(mNativeInterface).setActiveDevice(any(BluetoothDevice.class));
132         doReturn(true).when(mNativeInterface).sendBsir(any(BluetoothDevice.class), anyBoolean());
133         // Mock methods in HeadsetObjectsFactory
134         doAnswer(invocation -> {
135             Assert.assertNotNull(mCurrentDevice);
136             final HeadsetStateMachine stateMachine = mock(HeadsetStateMachine.class);
137             doReturn(BluetoothProfile.STATE_DISCONNECTED).when(stateMachine).getConnectionState();
138             doReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED).when(stateMachine).getAudioState();
139             mStateMachines.put(mCurrentDevice, stateMachine);
140             return stateMachine;
141         }).when(mObjectsFactory).makeStateMachine(any(), any(), any(), any(), any(), any());
142         doReturn(mSystemInterface).when(mObjectsFactory).makeSystemInterface(any());
143         doReturn(mNativeInterface).when(mObjectsFactory).getNativeInterface();
144         TestUtils.startService(mServiceRule, HeadsetService.class);
145         mHeadsetService = HeadsetService.getHeadsetService();
146         Assert.assertNotNull(mHeadsetService);
147         verify(mObjectsFactory).makeSystemInterface(mHeadsetService);
148         verify(mObjectsFactory).getNativeInterface();
149         mHeadsetServiceBinder = (IBluetoothHeadset.Stub) mHeadsetService.initBinder();
150         Assert.assertNotNull(mHeadsetServiceBinder);
151         mHeadsetServiceBinder.setForceScoAudio(true);
152         // Mock database for getConnectionPolicy()
153         when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager);
154     }
155 
156     @After
tearDown()157     public void tearDown() throws Exception {
158         if (!mTargetContext.getResources().getBoolean(R.bool.profile_supported_hs_hfp)) {
159             return;
160         }
161         TestUtils.stopService(mServiceRule, HeadsetService.class);
162         mHeadsetService = HeadsetService.getHeadsetService();
163         Assert.assertNull(mHeadsetService);
164         mStateMachines.clear();
165         mCurrentDevice = null;
166         Method method = HeadsetObjectsFactory.class.getDeclaredMethod("setInstanceForTesting",
167                 HeadsetObjectsFactory.class);
168         method.setAccessible(true);
169         method.invoke(null, (HeadsetObjectsFactory) null);
170         TestUtils.clearAdapterService(mAdapterService);
171     }
172 
173     /**
174      * Test to verify that HeadsetService can be successfully started
175      */
176     @Test
testGetHeadsetService()177     public void testGetHeadsetService() {
178         Assert.assertEquals(mHeadsetService, HeadsetService.getHeadsetService());
179         // Verify default connection and audio states
180         mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
181         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
182                 mHeadsetService.getConnectionState(mCurrentDevice));
183         Assert.assertEquals(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
184                 mHeadsetService.getAudioState(mCurrentDevice));
185     }
186 
187     /**
188      *  Test okToAcceptConnection method using various test cases
189      */
190     @Test
testOkToAcceptConnection()191     public void testOkToAcceptConnection() {
192         mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
193         int badPriorityValue = 1024;
194         int badBondState = 42;
195         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_NONE,
196                 BluetoothProfile.CONNECTION_POLICY_UNKNOWN, false);
197         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_NONE,
198                 BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, false);
199         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_NONE,
200                 BluetoothProfile.CONNECTION_POLICY_ALLOWED, false);
201         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_NONE, badPriorityValue,
202                 false);
203         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDING,
204                 BluetoothProfile.CONNECTION_POLICY_UNKNOWN, false);
205         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDING,
206                 BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, false);
207         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDING,
208                 BluetoothProfile.CONNECTION_POLICY_ALLOWED, false);
209         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDING, badPriorityValue,
210                 false);
211         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDED,
212                 BluetoothProfile.CONNECTION_POLICY_UNKNOWN, true);
213         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDED,
214                 BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, false);
215         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDED,
216                 BluetoothProfile.CONNECTION_POLICY_ALLOWED, true);
217         testOkToAcceptConnectionCase(mCurrentDevice, BluetoothDevice.BOND_BONDED, badPriorityValue,
218                 false);
219         testOkToAcceptConnectionCase(mCurrentDevice, badBondState,
220                 BluetoothProfile.CONNECTION_POLICY_UNKNOWN, false);
221         testOkToAcceptConnectionCase(mCurrentDevice, badBondState,
222                 BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, false);
223         testOkToAcceptConnectionCase(mCurrentDevice, badBondState,
224                 BluetoothProfile.CONNECTION_POLICY_ALLOWED, false);
225         testOkToAcceptConnectionCase(mCurrentDevice, badBondState, badPriorityValue, false);
226     }
227 
228     /**
229      * Test to verify that {@link HeadsetService#connect(BluetoothDevice)} returns true when the
230      * device was not connected and number of connected devices is less than
231      * {@link #MAX_HEADSET_CONNECTIONS}
232      */
233     @Test
testConnectDevice_connectDeviceBelowLimit()234     public void testConnectDevice_connectDeviceBelowLimit() {
235         when(mDatabaseManager.getProfileConnectionPolicy(any(BluetoothDevice.class),
236                 eq(BluetoothProfile.HEADSET)))
237                 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
238         mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
239         Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
240         verify(mObjectsFactory).makeStateMachine(mCurrentDevice,
241                 mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService, mAdapterService,
242                 mNativeInterface, mSystemInterface);
243         verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.CONNECT,
244                 mCurrentDevice);
245         when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
246         when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
247                 BluetoothProfile.STATE_CONNECTING);
248         Assert.assertEquals(BluetoothProfile.STATE_CONNECTING,
249                 mHeadsetService.getConnectionState(mCurrentDevice));
250         when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
251                 BluetoothProfile.STATE_CONNECTED);
252         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
253                 mHeadsetService.getConnectionState(mCurrentDevice));
254         Assert.assertEquals(Collections.singletonList(mCurrentDevice),
255                 mHeadsetService.getConnectedDevices());
256         // 2nd connection attempt will fail
257         Assert.assertFalse(mHeadsetService.connect(mCurrentDevice));
258         // Verify makeStateMachine is only called once
259         verify(mObjectsFactory).makeStateMachine(any(), any(), any(), any(), any(), any());
260         // Verify CONNECT is only sent once
261         verify(mStateMachines.get(mCurrentDevice)).sendMessage(eq(HeadsetStateMachine.CONNECT),
262                 any());
263     }
264 
265     /**
266      * Test that {@link HeadsetService#messageFromNative(HeadsetStackEvent)} will send correct
267      * message to the underlying state machine
268      */
269     @Test
testMessageFromNative_deviceConnected()270     public void testMessageFromNative_deviceConnected() {
271         mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
272         // Test connect from native
273         HeadsetStackEvent connectedEvent =
274                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
275                         HeadsetHalConstants.CONNECTION_STATE_CONNECTED, mCurrentDevice);
276         mHeadsetService.messageFromNative(connectedEvent);
277         verify(mObjectsFactory).makeStateMachine(mCurrentDevice,
278                 mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService, mAdapterService,
279                 mNativeInterface, mSystemInterface);
280         verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.STACK_EVENT,
281                 connectedEvent);
282         when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
283         when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
284                 BluetoothProfile.STATE_CONNECTED);
285         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
286                 mHeadsetService.getConnectionState(mCurrentDevice));
287         Assert.assertEquals(Collections.singletonList(mCurrentDevice),
288                 mHeadsetService.getConnectedDevices());
289         // Test disconnect from native
290         HeadsetStackEvent disconnectEvent =
291                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
292                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED, mCurrentDevice);
293         mHeadsetService.messageFromNative(disconnectEvent);
294         verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.STACK_EVENT,
295                 disconnectEvent);
296         when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
297                 BluetoothProfile.STATE_DISCONNECTED);
298         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
299                 mHeadsetService.getConnectionState(mCurrentDevice));
300         Assert.assertEquals(Collections.EMPTY_LIST, mHeadsetService.getConnectedDevices());
301     }
302 
303     /**
304      * Stack connection event to {@link HeadsetHalConstants#CONNECTION_STATE_CONNECTING} should
305      * create new state machine
306      */
307     @Test
testMessageFromNative_deviceConnectingUnknown()308     public void testMessageFromNative_deviceConnectingUnknown() {
309         mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
310         HeadsetStackEvent connectingEvent =
311                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
312                         HeadsetHalConstants.CONNECTION_STATE_CONNECTING, mCurrentDevice);
313         mHeadsetService.messageFromNative(connectingEvent);
314         verify(mObjectsFactory).makeStateMachine(mCurrentDevice,
315                 mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService, mAdapterService,
316                 mNativeInterface, mSystemInterface);
317         verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.STACK_EVENT,
318                 connectingEvent);
319     }
320 
321     /**
322      * Stack connection event to {@link HeadsetHalConstants#CONNECTION_STATE_DISCONNECTED} should
323      * crash by throwing {@link IllegalStateException} if the device is unknown
324      */
325     @Test
testMessageFromNative_deviceDisconnectedUnknown()326     public void testMessageFromNative_deviceDisconnectedUnknown() {
327         mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
328         HeadsetStackEvent connectingEvent =
329                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
330                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED, mCurrentDevice);
331         try {
332             mHeadsetService.messageFromNative(connectingEvent);
333             Assert.fail("Expect an IllegalStateException");
334         } catch (IllegalStateException exception) {
335             // Do nothing
336         }
337         verifyNoMoreInteractions(mObjectsFactory);
338     }
339 
340     /**
341      * Test to verify that {@link HeadsetService#connect(BluetoothDevice)} fails after
342      * {@link #MAX_HEADSET_CONNECTIONS} connection requests
343      */
344     @Test
testConnectDevice_connectDeviceAboveLimit()345     public void testConnectDevice_connectDeviceAboveLimit() {
346         ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>();
347         when(mDatabaseManager.getProfileConnectionPolicy(any(BluetoothDevice.class),
348                 eq(BluetoothProfile.HEADSET)))
349                 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
350         for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) {
351             mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
352             Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
353             verify(mObjectsFactory).makeStateMachine(mCurrentDevice,
354                     mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService,
355                     mAdapterService, mNativeInterface, mSystemInterface);
356             verify(mObjectsFactory, times(i + 1)).makeStateMachine(any(BluetoothDevice.class),
357                     eq(mHeadsetService.getStateMachinesThreadLooper()), eq(mHeadsetService),
358                     eq(mAdapterService), eq(mNativeInterface), eq(mSystemInterface));
359             verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.CONNECT,
360                     mCurrentDevice);
361             verify(mStateMachines.get(mCurrentDevice)).sendMessage(eq(HeadsetStateMachine.CONNECT),
362                     any(BluetoothDevice.class));
363             // Put device to connecting
364             when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
365                     BluetoothProfile.STATE_CONNECTING);
366             Assert.assertThat(mHeadsetService.getConnectedDevices(),
367                     Matchers.containsInAnyOrder(connectedDevices.toArray()));
368             // Put device to connected
369             connectedDevices.add(mCurrentDevice);
370             when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
371             when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
372                     BluetoothProfile.STATE_CONNECTED);
373             Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
374                     mHeadsetService.getConnectionState(mCurrentDevice));
375             Assert.assertThat(mHeadsetService.getConnectedDevices(),
376                     Matchers.containsInAnyOrder(connectedDevices.toArray()));
377         }
378         // Connect the next device will fail
379         mCurrentDevice = TestUtils.getTestDevice(mAdapter, MAX_HEADSET_CONNECTIONS);
380         Assert.assertFalse(mHeadsetService.connect(mCurrentDevice));
381         // Though connection failed, a new state machine is still lazily created for the device
382         verify(mObjectsFactory, times(MAX_HEADSET_CONNECTIONS + 1)).makeStateMachine(
383                 any(BluetoothDevice.class), eq(mHeadsetService.getStateMachinesThreadLooper()),
384                 eq(mHeadsetService), eq(mAdapterService), eq(mNativeInterface),
385                 eq(mSystemInterface));
386         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
387                 mHeadsetService.getConnectionState(mCurrentDevice));
388         Assert.assertThat(mHeadsetService.getConnectedDevices(),
389                 Matchers.containsInAnyOrder(connectedDevices.toArray()));
390     }
391 
392     /**
393      * Test to verify that {@link HeadsetService#connectAudio(BluetoothDevice)} return true when
394      * the device is connected and audio is not connected and returns false when audio is already
395      * connecting
396      */
397     @Test
testConnectAudio_withOneDevice()398     public void testConnectAudio_withOneDevice() {
399         when(mDatabaseManager.getProfileConnectionPolicy(any(BluetoothDevice.class),
400                 eq(BluetoothProfile.HEADSET)))
401                 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
402         mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
403         Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
404         verify(mObjectsFactory).makeStateMachine(mCurrentDevice,
405                 mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService, mAdapterService,
406                 mNativeInterface, mSystemInterface);
407         verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.CONNECT,
408                 mCurrentDevice);
409         when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
410         when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
411                 BluetoothProfile.STATE_CONNECTED);
412         when(mStateMachines.get(mCurrentDevice).getConnectingTimestampMs()).thenReturn(
413                 SystemClock.uptimeMillis());
414         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
415                 mHeadsetService.getConnectionState(mCurrentDevice));
416         Assert.assertEquals(Collections.singletonList(mCurrentDevice),
417                 mHeadsetService.getConnectedDevices());
418         mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
419                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED);
420         // Test connect audio - set the device first as the active device
421         Assert.assertTrue(mHeadsetService.setActiveDevice(mCurrentDevice));
422         Assert.assertTrue(mHeadsetService.connectAudio(mCurrentDevice));
423         verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.CONNECT_AUDIO,
424                 mCurrentDevice);
425         when(mStateMachines.get(mCurrentDevice).getAudioState()).thenReturn(
426                 BluetoothHeadset.STATE_AUDIO_CONNECTING);
427         // 2nd connection attempt for the same device will succeed as well
428         Assert.assertTrue(mHeadsetService.connectAudio(mCurrentDevice));
429         // Verify CONNECT_AUDIO is only sent once
430         verify(mStateMachines.get(mCurrentDevice)).sendMessage(
431                 eq(HeadsetStateMachine.CONNECT_AUDIO), any());
432         // Test disconnect audio
433         Assert.assertTrue(mHeadsetService.disconnectAudio(mCurrentDevice));
434         verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.DISCONNECT_AUDIO,
435                 mCurrentDevice);
436         when(mStateMachines.get(mCurrentDevice).getAudioState()).thenReturn(
437                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
438         // Further disconnection requests will fail
439         Assert.assertFalse(mHeadsetService.disconnectAudio(mCurrentDevice));
440         verify(mStateMachines.get(mCurrentDevice)).sendMessage(
441                 eq(HeadsetStateMachine.DISCONNECT_AUDIO), any(BluetoothDevice.class));
442     }
443 
444     /**
445      * Test to verify that HFP audio connection can be initiated when multiple devices are connected
446      * and can be canceled or disconnected as well
447      */
448     @Test
testConnectAudio_withMultipleDevices()449     public void testConnectAudio_withMultipleDevices() {
450         ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>();
451         when(mDatabaseManager.getProfileConnectionPolicy(any(BluetoothDevice.class),
452                 eq(BluetoothProfile.HEADSET)))
453                 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
454         for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) {
455             mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
456             Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
457             verify(mObjectsFactory).makeStateMachine(mCurrentDevice,
458                     mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService,
459                     mAdapterService, mNativeInterface, mSystemInterface);
460             verify(mObjectsFactory, times(i + 1)).makeStateMachine(any(BluetoothDevice.class),
461                     eq(mHeadsetService.getStateMachinesThreadLooper()), eq(mHeadsetService),
462                     eq(mAdapterService), eq(mNativeInterface), eq(mSystemInterface));
463             verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.CONNECT,
464                     mCurrentDevice);
465             verify(mStateMachines.get(mCurrentDevice)).sendMessage(eq(HeadsetStateMachine.CONNECT),
466                     any(BluetoothDevice.class));
467             // Put device to connecting
468             when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
469                     BluetoothProfile.STATE_CONNECTING);
470             mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
471                     BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING);
472             Assert.assertThat(mHeadsetService.getConnectedDevices(),
473                     Matchers.containsInAnyOrder(connectedDevices.toArray()));
474             // Put device to connected
475             connectedDevices.add(mCurrentDevice);
476             when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
477             when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
478                     BluetoothProfile.STATE_CONNECTED);
479             when(mStateMachines.get(mCurrentDevice).getConnectingTimestampMs()).thenReturn(
480                     SystemClock.uptimeMillis());
481             Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
482                     mHeadsetService.getConnectionState(mCurrentDevice));
483             mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
484                     BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED);
485             Assert.assertThat(mHeadsetService.getConnectedDevices(),
486                     Matchers.containsInAnyOrder(connectedDevices.toArray()));
487             // Try to connect audio
488             // Should fail
489             Assert.assertFalse(mHeadsetService.connectAudio(mCurrentDevice));
490             // Should succeed after setActiveDevice()
491             Assert.assertTrue(mHeadsetService.setActiveDevice(mCurrentDevice));
492             Assert.assertTrue(mHeadsetService.connectAudio(mCurrentDevice));
493             verify(mStateMachines.get(mCurrentDevice)).sendMessage(
494                     HeadsetStateMachine.CONNECT_AUDIO, mCurrentDevice);
495             // Put device to audio connecting state
496             when(mStateMachines.get(mCurrentDevice).getAudioState()).thenReturn(
497                     BluetoothHeadset.STATE_AUDIO_CONNECTING);
498             // 2nd connection attempt will also succeed
499             Assert.assertTrue(mHeadsetService.connectAudio(mCurrentDevice));
500             // Verify CONNECT_AUDIO is only sent once
501             verify(mStateMachines.get(mCurrentDevice)).sendMessage(
502                     eq(HeadsetStateMachine.CONNECT_AUDIO), any());
503             // Put device to audio connected state
504             when(mStateMachines.get(mCurrentDevice).getAudioState()).thenReturn(
505                     BluetoothHeadset.STATE_AUDIO_CONNECTED);
506             // Disconnect audio
507             Assert.assertTrue(mHeadsetService.disconnectAudio(mCurrentDevice));
508             verify(mStateMachines.get(mCurrentDevice)).sendMessage(
509                     HeadsetStateMachine.DISCONNECT_AUDIO, mCurrentDevice);
510             when(mStateMachines.get(mCurrentDevice).getAudioState()).thenReturn(
511                     BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
512             // Further disconnection requests will fail
513             Assert.assertFalse(mHeadsetService.disconnectAudio(mCurrentDevice));
514             verify(mStateMachines.get(mCurrentDevice)).sendMessage(
515                     eq(HeadsetStateMachine.DISCONNECT_AUDIO), any(BluetoothDevice.class));
516         }
517     }
518 
519     /**
520      * Verify that only one device can be in audio connecting or audio connected state, further
521      * attempt to call {@link HeadsetService#connectAudio(BluetoothDevice)} should fail by returning
522      * false
523      */
524     @Test
testConnectAudio_connectTwoAudioChannelsShouldFail()525     public void testConnectAudio_connectTwoAudioChannelsShouldFail() {
526         ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>();
527         when(mDatabaseManager.getProfileConnectionPolicy(any(BluetoothDevice.class),
528                 eq(BluetoothProfile.HEADSET)))
529                 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
530         for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) {
531             mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
532             Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
533             verify(mObjectsFactory).makeStateMachine(mCurrentDevice,
534                     mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService,
535                     mAdapterService, mNativeInterface, mSystemInterface);
536             verify(mObjectsFactory, times(i + 1)).makeStateMachine(any(BluetoothDevice.class),
537                     eq(mHeadsetService.getStateMachinesThreadLooper()), eq(mHeadsetService),
538                     eq(mAdapterService), eq(mNativeInterface), eq(mSystemInterface));
539             verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.CONNECT,
540                     mCurrentDevice);
541             verify(mStateMachines.get(mCurrentDevice)).sendMessage(eq(HeadsetStateMachine.CONNECT),
542                     any(BluetoothDevice.class));
543             // Put device to connecting
544             when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
545                     BluetoothProfile.STATE_CONNECTING);
546             mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
547                     BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING);
548             Assert.assertThat(mHeadsetService.getConnectedDevices(),
549                     Matchers.containsInAnyOrder(connectedDevices.toArray()));
550             // Put device to connected
551             connectedDevices.add(mCurrentDevice);
552             when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
553             when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
554                     BluetoothProfile.STATE_CONNECTED);
555             when(mStateMachines.get(mCurrentDevice).getConnectingTimestampMs()).thenReturn(
556                     SystemClock.uptimeMillis());
557             mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
558                     BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED);
559             Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
560                     mHeadsetService.getConnectionState(mCurrentDevice));
561             Assert.assertThat(mHeadsetService.getConnectedDevices(),
562                     Matchers.containsInAnyOrder(connectedDevices.toArray()));
563         }
564         if (MAX_HEADSET_CONNECTIONS >= 2) {
565             // Try to connect audio
566             BluetoothDevice firstDevice = connectedDevices.get(0);
567             BluetoothDevice secondDevice = connectedDevices.get(1);
568             // Set the first device as the active device
569             Assert.assertTrue(mHeadsetService.setActiveDevice(firstDevice));
570             Assert.assertTrue(mHeadsetService.connectAudio(firstDevice));
571             verify(mStateMachines.get(firstDevice)).sendMessage(HeadsetStateMachine.CONNECT_AUDIO,
572                     firstDevice);
573             // Put device to audio connecting state
574             when(mStateMachines.get(firstDevice).getAudioState()).thenReturn(
575                     BluetoothHeadset.STATE_AUDIO_CONNECTING);
576             // 2nd connection attempt will succeed for the same device
577             Assert.assertTrue(mHeadsetService.connectAudio(firstDevice));
578             // Connect to 2nd device will fail
579             Assert.assertFalse(mHeadsetService.connectAudio(secondDevice));
580             verify(mStateMachines.get(secondDevice), never()).sendMessage(
581                     HeadsetStateMachine.CONNECT_AUDIO, secondDevice);
582             // Put device to audio connected state
583             when(mStateMachines.get(firstDevice).getAudioState()).thenReturn(
584                     BluetoothHeadset.STATE_AUDIO_CONNECTED);
585             // Connect to 2nd device will fail
586             Assert.assertFalse(mHeadsetService.connectAudio(secondDevice));
587             verify(mStateMachines.get(secondDevice), never()).sendMessage(
588                     HeadsetStateMachine.CONNECT_AUDIO, secondDevice);
589         }
590     }
591 
592     /**
593      * Verify that {@link HeadsetService#connectAudio()} will connect to first connected/connecting
594      * device
595      */
596     @Test
testConnectAudio_firstConnectedAudioDevice()597     public void testConnectAudio_firstConnectedAudioDevice() {
598         ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>();
599         when(mDatabaseManager.getProfileConnectionPolicy(any(BluetoothDevice.class),
600                 eq(BluetoothProfile.HEADSET)))
601                 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
602         doAnswer(invocation -> {
603             BluetoothDevice[] devicesArray = new BluetoothDevice[connectedDevices.size()];
604             return connectedDevices.toArray(devicesArray);
605         }).when(mAdapterService).getBondedDevices();
606         for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) {
607             mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
608             Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
609             verify(mObjectsFactory).makeStateMachine(mCurrentDevice,
610                     mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService,
611                     mAdapterService, mNativeInterface, mSystemInterface);
612             verify(mObjectsFactory, times(i + 1)).makeStateMachine(any(BluetoothDevice.class),
613                     eq(mHeadsetService.getStateMachinesThreadLooper()), eq(mHeadsetService),
614                     eq(mAdapterService), eq(mNativeInterface), eq(mSystemInterface));
615             verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.CONNECT,
616                     mCurrentDevice);
617             verify(mStateMachines.get(mCurrentDevice)).sendMessage(eq(HeadsetStateMachine.CONNECT),
618                     any(BluetoothDevice.class));
619             // Put device to connecting
620             when(mStateMachines.get(mCurrentDevice).getConnectingTimestampMs()).thenReturn(
621                     SystemClock.uptimeMillis());
622             when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
623                     BluetoothProfile.STATE_CONNECTING);
624             mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
625                     BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING);
626             Assert.assertThat(mHeadsetService.getConnectedDevices(),
627                     Matchers.containsInAnyOrder(connectedDevices.toArray()));
628             // Put device to connected
629             connectedDevices.add(mCurrentDevice);
630             when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
631             when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
632                     BluetoothProfile.STATE_CONNECTED);
633             when(mStateMachines.get(mCurrentDevice).getConnectingTimestampMs()).thenReturn(
634                     SystemClock.uptimeMillis());
635             Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
636                     mHeadsetService.getConnectionState(mCurrentDevice));
637             Assert.assertThat(mHeadsetService.getConnectedDevices(),
638                     Matchers.containsInAnyOrder(connectedDevices.toArray()));
639             mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
640                     BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED);
641         }
642         // Try to connect audio
643         BluetoothDevice firstDevice = connectedDevices.get(0);
644         Assert.assertTrue(mHeadsetService.setActiveDevice(firstDevice));
645         Assert.assertTrue(mHeadsetService.connectAudio());
646         verify(mStateMachines.get(firstDevice)).sendMessage(HeadsetStateMachine.CONNECT_AUDIO,
647                 firstDevice);
648     }
649 
650     /**
651      * Test to verify that {@link HeadsetService#connectAudio(BluetoothDevice)} fails if device
652      * was never connected
653      */
654     @Test
testConnectAudio_deviceNeverConnected()655     public void testConnectAudio_deviceNeverConnected() {
656         mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
657         Assert.assertFalse(mHeadsetService.connectAudio(mCurrentDevice));
658     }
659 
660     /**
661      * Test to verify that {@link HeadsetService#connectAudio(BluetoothDevice)} fails if device
662      * is disconnected
663      */
664     @Test
testConnectAudio_deviceDisconnected()665     public void testConnectAudio_deviceDisconnected() {
666         when(mDatabaseManager.getProfileConnectionPolicy(any(BluetoothDevice.class),
667                 eq(BluetoothProfile.HEADSET)))
668                 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
669         mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
670         HeadsetCallState headsetCallState =
671                 new HeadsetCallState(1, 0, HeadsetHalConstants.CALL_STATE_ALERTING,
672                         TEST_PHONE_NUMBER, 128, "");
673         Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
674         verify(mObjectsFactory).makeStateMachine(mCurrentDevice,
675                 mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService, mAdapterService,
676                 mNativeInterface, mSystemInterface);
677         verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.CONNECT,
678                 mCurrentDevice);
679         when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
680         // Put device in disconnected state
681         when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
682                 BluetoothProfile.STATE_DISCONNECTED);
683         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
684                 mHeadsetService.getConnectionState(mCurrentDevice));
685         Assert.assertEquals(Collections.EMPTY_LIST, mHeadsetService.getConnectedDevices());
686         mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
687                 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED);
688         // connectAudio should fail
689         Assert.assertFalse(mHeadsetService.connectAudio(mCurrentDevice));
690         verify(mStateMachines.get(mCurrentDevice), never()).sendMessage(
691                 eq(HeadsetStateMachine.CONNECT_AUDIO), any());
692     }
693 
694     /**
695      * Verifies that phone state change will trigger a system-wide saving of call state even when
696      * no device is connected
697      *
698      * @throws RemoteException if binder call fails
699      */
700     @Test
testPhoneStateChange_noDeviceSaveState()701     public void testPhoneStateChange_noDeviceSaveState() throws RemoteException {
702         HeadsetCallState headsetCallState =
703                 new HeadsetCallState(1, 0, HeadsetHalConstants.CALL_STATE_ALERTING,
704                         TEST_PHONE_NUMBER, 128, "");
705         mHeadsetServiceBinder.phoneStateChanged(headsetCallState.mNumActive,
706                 headsetCallState.mNumHeld, headsetCallState.mCallState, headsetCallState.mNumber,
707                 headsetCallState.mType, headsetCallState.mName);
708         HeadsetTestUtils.verifyPhoneStateChangeSetters(mPhoneState, headsetCallState,
709                 ASYNC_CALL_TIMEOUT_MILLIS);
710     }
711 
712     /**
713      * Verifies that phone state change will trigger a system-wide saving of call state and send
714      * state change to connected devices
715      *
716      * @throws RemoteException if binder call fails
717      */
718     @Test
testPhoneStateChange_oneDeviceSaveState()719     public void testPhoneStateChange_oneDeviceSaveState() throws RemoteException {
720         HeadsetCallState headsetCallState =
721                 new HeadsetCallState(1, 0, HeadsetHalConstants.CALL_STATE_ALERTING,
722                         TEST_PHONE_NUMBER, 128, "");
723         when(mDatabaseManager.getProfileConnectionPolicy(any(BluetoothDevice.class),
724                 eq(BluetoothProfile.HEADSET)))
725                 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
726         mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
727         final ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>();
728         // Connect one device
729         Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
730         verify(mObjectsFactory).makeStateMachine(mCurrentDevice,
731                 mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService, mAdapterService,
732                 mNativeInterface, mSystemInterface);
733         verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.CONNECT,
734                 mCurrentDevice);
735         when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
736         // Put device to connecting
737         when(mStateMachines.get(mCurrentDevice).getConnectingTimestampMs()).thenReturn(
738                 SystemClock.uptimeMillis());
739         when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
740                 BluetoothProfile.STATE_CONNECTING);
741         mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
742                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING);
743         Assert.assertThat(mHeadsetService.getConnectedDevices(),
744                 Matchers.containsInAnyOrder(connectedDevices.toArray()));
745         // Put device to connected
746         connectedDevices.add(mCurrentDevice);
747         when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
748         when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
749                 BluetoothProfile.STATE_CONNECTED);
750         when(mStateMachines.get(mCurrentDevice).getConnectingTimestampMs()).thenReturn(
751                 SystemClock.uptimeMillis());
752         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
753                 mHeadsetService.getConnectionState(mCurrentDevice));
754         Assert.assertThat(mHeadsetService.getConnectedDevices(),
755                 Matchers.containsInAnyOrder(connectedDevices.toArray()));
756         mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
757                 BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED);
758         // Change phone state
759         mHeadsetServiceBinder.phoneStateChanged(headsetCallState.mNumActive,
760                 headsetCallState.mNumHeld, headsetCallState.mCallState, headsetCallState.mNumber,
761                 headsetCallState.mType, headsetCallState.mName);
762         // Make sure we notify device about this change
763         verify(mStateMachines.get(mCurrentDevice)).sendMessage(
764                 HeadsetStateMachine.CALL_STATE_CHANGED, headsetCallState);
765         // Make sure state is updated once in phone state holder
766         HeadsetTestUtils.verifyPhoneStateChangeSetters(mPhoneState, headsetCallState,
767                 ASYNC_CALL_TIMEOUT_MILLIS);
768     }
769 
770     /**
771      * Verifies that phone state change will trigger a system-wide saving of call state and send
772      * state change to connected devices
773      *
774      * @throws RemoteException if binder call fails
775      */
776     @Test
testPhoneStateChange_multipleDevicesSaveState()777     public void testPhoneStateChange_multipleDevicesSaveState() throws RemoteException {
778         HeadsetCallState headsetCallState =
779                 new HeadsetCallState(1, 0, HeadsetHalConstants.CALL_STATE_ALERTING,
780                         TEST_PHONE_NUMBER, 128, "");
781         final ArrayList<BluetoothDevice> connectedDevices = new ArrayList<>();
782         when(mDatabaseManager.getProfileConnectionPolicy(any(BluetoothDevice.class),
783                 eq(BluetoothProfile.HEADSET)))
784                 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
785         for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) {
786             mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
787             Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
788             verify(mObjectsFactory).makeStateMachine(mCurrentDevice,
789                     mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService,
790                     mAdapterService, mNativeInterface, mSystemInterface);
791             verify(mObjectsFactory, times(i + 1)).makeStateMachine(any(BluetoothDevice.class),
792                     eq(mHeadsetService.getStateMachinesThreadLooper()), eq(mHeadsetService),
793                     eq(mAdapterService), eq(mNativeInterface), eq(mSystemInterface));
794             verify(mStateMachines.get(mCurrentDevice)).sendMessage(HeadsetStateMachine.CONNECT,
795                     mCurrentDevice);
796             verify(mStateMachines.get(mCurrentDevice)).sendMessage(eq(HeadsetStateMachine.CONNECT),
797                     any(BluetoothDevice.class));
798             // Put device to connecting
799             when(mStateMachines.get(mCurrentDevice).getConnectingTimestampMs()).thenReturn(
800                     SystemClock.uptimeMillis());
801             when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
802                     BluetoothProfile.STATE_CONNECTING);
803             mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
804                     BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING);
805             Assert.assertThat(mHeadsetService.getConnectedDevices(),
806                     Matchers.containsInAnyOrder(connectedDevices.toArray()));
807             // Put device to connected
808             connectedDevices.add(mCurrentDevice);
809             when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
810             when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
811                     BluetoothProfile.STATE_CONNECTED);
812             when(mStateMachines.get(mCurrentDevice).getConnectingTimestampMs()).thenReturn(
813                     SystemClock.uptimeMillis());
814             Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
815                     mHeadsetService.getConnectionState(mCurrentDevice));
816             Assert.assertThat(mHeadsetService.getConnectedDevices(),
817                     Matchers.containsInAnyOrder(connectedDevices.toArray()));
818             mHeadsetService.onConnectionStateChangedFromStateMachine(mCurrentDevice,
819                     BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_CONNECTED);
820         }
821         // Change phone state
822         mHeadsetServiceBinder.phoneStateChanged(headsetCallState.mNumActive,
823                 headsetCallState.mNumHeld, headsetCallState.mCallState, headsetCallState.mNumber,
824                 headsetCallState.mType, headsetCallState.mName);
825         // Make sure we notify devices about this change
826         for (BluetoothDevice device : connectedDevices) {
827             verify(mStateMachines.get(device)).sendMessage(HeadsetStateMachine.CALL_STATE_CHANGED,
828                     headsetCallState);
829         }
830         // Make sure state is updated once in phone state holder
831         HeadsetTestUtils.verifyPhoneStateChangeSetters(mPhoneState, headsetCallState,
832                 ASYNC_CALL_TIMEOUT_MILLIS);
833     }
834 
835     /**
836      * Test that whether active device been removed after enable silence mode
837      */
838     @Test
testSetSilenceMode()839     public void testSetSilenceMode() {
840         when(mDatabaseManager.getProfileConnectionPolicy(any(BluetoothDevice.class),
841                 eq(BluetoothProfile.HEADSET)))
842                 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN);
843         for (int i = 0; i < 2; i++) {
844             mCurrentDevice = TestUtils.getTestDevice(mAdapter, i);
845             Assert.assertTrue(mHeadsetService.connect(mCurrentDevice));
846             when(mStateMachines.get(mCurrentDevice).getDevice()).thenReturn(mCurrentDevice);
847             when(mStateMachines.get(mCurrentDevice).getConnectionState()).thenReturn(
848                     BluetoothProfile.STATE_CONNECTED);
849             when(mStateMachines.get(mCurrentDevice).setSilenceDevice(
850                     anyBoolean())).thenReturn(true);
851         }
852         mCurrentDevice = TestUtils.getTestDevice(mAdapter, 0);
853         BluetoothDevice otherDevice = TestUtils.getTestDevice(mAdapter, 1);
854 
855         // Test whether active device been removed after enable silence mode.
856         Assert.assertTrue(mHeadsetService.setActiveDevice(mCurrentDevice));
857         Assert.assertEquals(mCurrentDevice, mHeadsetService.getActiveDevice());
858         Assert.assertTrue(mHeadsetService.setSilenceMode(mCurrentDevice, true));
859         Assert.assertNull(mHeadsetService.getActiveDevice());
860 
861         // Test whether active device been resumed after disable silence mode.
862         Assert.assertTrue(mHeadsetService.setSilenceMode(mCurrentDevice, false));
863         Assert.assertEquals(mCurrentDevice, mHeadsetService.getActiveDevice());
864 
865         // Test that active device should not be changed when silence a non-active device
866         Assert.assertTrue(mHeadsetService.setActiveDevice(mCurrentDevice));
867         Assert.assertEquals(mCurrentDevice, mHeadsetService.getActiveDevice());
868         Assert.assertTrue(mHeadsetService.setSilenceMode(otherDevice, true));
869         Assert.assertEquals(mCurrentDevice, mHeadsetService.getActiveDevice());
870 
871         // Test that active device should not be changed when another device exits silence mode
872         Assert.assertTrue(mHeadsetService.setSilenceMode(otherDevice, false));
873         Assert.assertEquals(mCurrentDevice, mHeadsetService.getActiveDevice());
874     }
875 
876     /*
877      *  Helper function to test okToAcceptConnection() method
878      *
879      *  @param device test device
880      *  @param bondState bond state value, could be invalid
881      *  @param priority value, could be invalid, coudl be invalid
882      *  @param expected expected result from okToAcceptConnection()
883      */
testOkToAcceptConnectionCase(BluetoothDevice device, int bondState, int priority, boolean expected)884     private void testOkToAcceptConnectionCase(BluetoothDevice device, int bondState, int priority,
885             boolean expected) {
886         doReturn(bondState).when(mAdapterService).getBondState(device);
887         when(mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.HEADSET))
888                 .thenReturn(priority);
889         Assert.assertEquals(expected, mHeadsetService.okToAcceptConnection(device));
890     }
891 
892 }
893