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