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