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