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.hearingaid; 18 19 import static org.mockito.Mockito.*; 20 21 import android.bluetooth.BluetoothAdapter; 22 import android.bluetooth.BluetoothDevice; 23 import android.bluetooth.BluetoothHearingAid; 24 import android.bluetooth.BluetoothProfile; 25 import android.bluetooth.BluetoothUuid; 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.media.AudioManager; 31 import android.os.Looper; 32 import android.os.ParcelUuid; 33 34 import androidx.test.InstrumentationRegistry; 35 import androidx.test.filters.MediumTest; 36 import androidx.test.rule.ServiceTestRule; 37 import androidx.test.runner.AndroidJUnit4; 38 39 import com.android.bluetooth.TestUtils; 40 import com.android.bluetooth.btservice.AdapterService; 41 import com.android.bluetooth.btservice.storage.DatabaseManager; 42 import com.android.internal.R; 43 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 54 import java.util.HashMap; 55 import java.util.List; 56 import java.util.concurrent.LinkedBlockingQueue; 57 import java.util.concurrent.TimeoutException; 58 59 @MediumTest 60 @RunWith(AndroidJUnit4.class) 61 public class HearingAidServiceTest { 62 private BluetoothAdapter mAdapter; 63 private Context mTargetContext; 64 private HearingAidService mService; 65 private BluetoothDevice mLeftDevice; 66 private BluetoothDevice mRightDevice; 67 private BluetoothDevice mSingleDevice; 68 private HashMap<BluetoothDevice, LinkedBlockingQueue<Intent>> mDeviceQueueMap; 69 private static final int TIMEOUT_MS = 1000; 70 71 private BroadcastReceiver mHearingAidIntentReceiver; 72 73 @Mock private AdapterService mAdapterService; 74 @Mock private DatabaseManager mDatabaseManager; 75 @Mock private HearingAidNativeInterface mNativeInterface; 76 @Mock private AudioManager mAudioManager; 77 78 @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule(); 79 80 @Before setUp()81 public void setUp() throws Exception { 82 mTargetContext = InstrumentationRegistry.getTargetContext(); 83 Assume.assumeTrue("Ignore test when HearingAidService is not enabled", 84 mTargetContext.getResources().getBoolean( 85 R.bool.config_hearing_aid_profile_supported)); 86 // Set up mocks and test assets 87 MockitoAnnotations.initMocks(this); 88 89 if (Looper.myLooper() == null) { 90 Looper.prepare(); 91 } 92 93 TestUtils.setAdapterService(mAdapterService); 94 95 mAdapter = BluetoothAdapter.getDefaultAdapter(); 96 97 startService(); 98 mService.mHearingAidNativeInterface = mNativeInterface; 99 mService.mAudioManager = mAudioManager; 100 101 // Override the timeout value to speed up the test 102 HearingAidStateMachine.sConnectTimeoutMs = TIMEOUT_MS; // 1s 103 104 // Set up the Connection State Changed receiver 105 IntentFilter filter = new IntentFilter(); 106 filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED); 107 mHearingAidIntentReceiver = new HearingAidIntentReceiver(); 108 mTargetContext.registerReceiver(mHearingAidIntentReceiver, filter); 109 110 // Get a device for testing 111 mLeftDevice = TestUtils.getTestDevice(mAdapter, 0); 112 mRightDevice = TestUtils.getTestDevice(mAdapter, 1); 113 mSingleDevice = TestUtils.getTestDevice(mAdapter, 2); 114 mDeviceQueueMap = new HashMap<>(); 115 mDeviceQueueMap.put(mLeftDevice, new LinkedBlockingQueue<>()); 116 mDeviceQueueMap.put(mRightDevice, new LinkedBlockingQueue<>()); 117 mDeviceQueueMap.put(mSingleDevice, new LinkedBlockingQueue<>()); 118 doReturn(BluetoothDevice.BOND_BONDED).when(mAdapterService) 119 .getBondState(any(BluetoothDevice.class)); 120 doReturn(new ParcelUuid[]{BluetoothUuid.HEARING_AID}).when(mAdapterService) 121 .getRemoteUuids(any(BluetoothDevice.class)); 122 } 123 124 @After tearDown()125 public void tearDown() throws Exception { 126 if (!mTargetContext.getResources().getBoolean( 127 R.bool.config_hearing_aid_profile_supported)) { 128 return; 129 } 130 stopService(); 131 mTargetContext.unregisterReceiver(mHearingAidIntentReceiver); 132 mDeviceQueueMap.clear(); 133 TestUtils.clearAdapterService(mAdapterService); 134 reset(mAudioManager); 135 } 136 startService()137 private void startService() throws TimeoutException { 138 TestUtils.startService(mServiceRule, HearingAidService.class); 139 mService = HearingAidService.getHearingAidService(); 140 Assert.assertNotNull(mService); 141 } 142 stopService()143 private void stopService() throws TimeoutException { 144 TestUtils.stopService(mServiceRule, HearingAidService.class); 145 mService = HearingAidService.getHearingAidService(); 146 Assert.assertNull(mService); 147 } 148 149 private class HearingAidIntentReceiver extends BroadcastReceiver { 150 @Override onReceive(Context context, Intent intent)151 public void onReceive(Context context, Intent intent) { 152 if (BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) { 153 try { 154 BluetoothDevice device = intent.getParcelableExtra( 155 BluetoothDevice.EXTRA_DEVICE); 156 Assert.assertNotNull(device); 157 LinkedBlockingQueue<Intent> queue = mDeviceQueueMap.get(device); 158 Assert.assertNotNull(queue); 159 queue.put(intent); 160 } catch (InterruptedException e) { 161 Assert.fail("Cannot add Intent to the Connection State queue: " 162 + e.getMessage()); 163 } 164 } 165 } 166 } 167 verifyConnectionStateIntent(int timeoutMs, BluetoothDevice device, int newState, int prevState)168 private void verifyConnectionStateIntent(int timeoutMs, BluetoothDevice device, 169 int newState, int prevState) { 170 Intent intent = TestUtils.waitForIntent(timeoutMs, mDeviceQueueMap.get(device)); 171 Assert.assertNotNull(intent); 172 Assert.assertEquals(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED, 173 intent.getAction()); 174 Assert.assertEquals(device, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)); 175 Assert.assertEquals(newState, intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1)); 176 Assert.assertEquals(prevState, intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 177 -1)); 178 } 179 verifyNoConnectionStateIntent(int timeoutMs, BluetoothDevice device)180 private void verifyNoConnectionStateIntent(int timeoutMs, BluetoothDevice device) { 181 Intent intent = TestUtils.waitForNoIntent(timeoutMs, mDeviceQueueMap.get(device)); 182 Assert.assertNull(intent); 183 } 184 185 /** 186 * Test getting HearingAid Service: getHearingAidService() 187 */ 188 @Test testGetHearingAidService()189 public void testGetHearingAidService() { 190 Assert.assertEquals(mService, HearingAidService.getHearingAidService()); 191 } 192 193 /** 194 * Test stop HearingAid Service 195 */ 196 @Test testStopHearingAidService()197 public void testStopHearingAidService() { 198 // Prepare: connect 199 connectDevice(mLeftDevice); 200 // HearingAid Service is already running: test stop(). Note: must be done on the main thread 201 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 202 public void run() { 203 Assert.assertTrue(mService.stop()); 204 } 205 }); 206 // Try to restart the service. Note: must be done on the main thread 207 InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { 208 public void run() { 209 Assert.assertTrue(mService.start()); 210 } 211 }); 212 } 213 214 /** 215 * Test get/set priority for BluetoothDevice 216 */ 217 @Test testGetSetPriority()218 public void testGetSetPriority() { 219 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 220 when(mDatabaseManager.getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 221 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 222 Assert.assertEquals("Initial device priority", 223 BluetoothProfile.CONNECTION_POLICY_UNKNOWN, 224 mService.getConnectionPolicy(mLeftDevice)); 225 226 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 227 when(mDatabaseManager.getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 228 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 229 Assert.assertEquals("Setting device priority to PRIORITY_OFF", 230 BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, 231 mService.getConnectionPolicy(mLeftDevice)); 232 233 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 234 when(mDatabaseManager.getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 235 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 236 Assert.assertEquals("Setting device priority to PRIORITY_ON", 237 BluetoothProfile.CONNECTION_POLICY_ALLOWED, 238 mService.getConnectionPolicy(mLeftDevice)); 239 } 240 241 /** 242 * Test okToConnect method using various test cases 243 */ 244 @Test testOkToConnect()245 public void testOkToConnect() { 246 int badPriorityValue = 1024; 247 int badBondState = 42; 248 testOkToConnectCase(mSingleDevice, 249 BluetoothDevice.BOND_NONE, BluetoothProfile.CONNECTION_POLICY_UNKNOWN, false); 250 testOkToConnectCase(mSingleDevice, 251 BluetoothDevice.BOND_NONE, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, false); 252 testOkToConnectCase(mSingleDevice, 253 BluetoothDevice.BOND_NONE, BluetoothProfile.CONNECTION_POLICY_ALLOWED, false); 254 testOkToConnectCase(mSingleDevice, 255 BluetoothDevice.BOND_NONE, badPriorityValue, false); 256 testOkToConnectCase(mSingleDevice, 257 BluetoothDevice.BOND_BONDING, BluetoothProfile.CONNECTION_POLICY_UNKNOWN, false); 258 testOkToConnectCase(mSingleDevice, 259 BluetoothDevice.BOND_BONDING, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, false); 260 testOkToConnectCase(mSingleDevice, 261 BluetoothDevice.BOND_BONDING, BluetoothProfile.CONNECTION_POLICY_ALLOWED, false); 262 testOkToConnectCase(mSingleDevice, 263 BluetoothDevice.BOND_BONDING, badPriorityValue, false); 264 testOkToConnectCase(mSingleDevice, 265 BluetoothDevice.BOND_BONDED, BluetoothProfile.CONNECTION_POLICY_UNKNOWN, true); 266 testOkToConnectCase(mSingleDevice, 267 BluetoothDevice.BOND_BONDED, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, false); 268 testOkToConnectCase(mSingleDevice, 269 BluetoothDevice.BOND_BONDED, BluetoothProfile.CONNECTION_POLICY_ALLOWED, true); 270 testOkToConnectCase(mSingleDevice, 271 BluetoothDevice.BOND_BONDED, badPriorityValue, false); 272 testOkToConnectCase(mSingleDevice, 273 badBondState, BluetoothProfile.CONNECTION_POLICY_UNKNOWN, false); 274 testOkToConnectCase(mSingleDevice, 275 badBondState, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN, false); 276 testOkToConnectCase(mSingleDevice, 277 badBondState, BluetoothProfile.CONNECTION_POLICY_ALLOWED, false); 278 testOkToConnectCase(mSingleDevice, 279 badBondState, badPriorityValue, false); 280 } 281 282 /** 283 * Test that an outgoing connection to device that does not have Hearing Aid UUID is rejected 284 */ 285 @Test testOutgoingConnectMissingHearingAidUuid()286 public void testOutgoingConnectMissingHearingAidUuid() { 287 // Update the device priority so okToConnect() returns true 288 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 289 when(mDatabaseManager.getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 290 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 291 when(mDatabaseManager 292 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 293 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 294 when(mDatabaseManager 295 .getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.HEARING_AID)) 296 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 297 doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); 298 doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); 299 300 // Return No UUID 301 doReturn(new ParcelUuid[]{}).when(mAdapterService) 302 .getRemoteUuids(any(BluetoothDevice.class)); 303 304 // Send a connect request 305 Assert.assertFalse("Connect expected to fail", mService.connect(mLeftDevice)); 306 } 307 308 /** 309 * Test that an outgoing connection to device with PRIORITY_OFF is rejected 310 */ 311 @Test testOutgoingConnectPriorityOff()312 public void testOutgoingConnectPriorityOff() { 313 doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); 314 doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); 315 316 // Set the device priority to PRIORITY_OFF so connect() should fail 317 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 318 when(mDatabaseManager 319 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 320 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 321 322 // Send a connect request 323 Assert.assertFalse("Connect expected to fail", mService.connect(mLeftDevice)); 324 } 325 326 /** 327 * Test that an outgoing connection times out 328 */ 329 @Test testOutgoingConnectTimeout()330 public void testOutgoingConnectTimeout() { 331 // Update the device priority so okToConnect() returns true 332 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 333 when(mDatabaseManager 334 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 335 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 336 when(mDatabaseManager 337 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 338 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 339 when(mDatabaseManager 340 .getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.HEARING_AID)) 341 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 342 doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); 343 doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); 344 345 // Send a connect request 346 Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); 347 348 // Verify the connection state broadcast, and that we are in Connecting state 349 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, 350 BluetoothProfile.STATE_DISCONNECTED); 351 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 352 mService.getConnectionState(mLeftDevice)); 353 354 // Verify the connection state broadcast, and that we are in Disconnected state 355 verifyConnectionStateIntent(HearingAidStateMachine.sConnectTimeoutMs * 2, 356 mLeftDevice, BluetoothProfile.STATE_DISCONNECTED, 357 BluetoothProfile.STATE_CONNECTING); 358 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 359 mService.getConnectionState(mLeftDevice)); 360 } 361 362 /** 363 * Test that the Hearing Aid Service connects to left and right device at the same time. 364 */ 365 @Test testConnectAPair_connectBothDevices()366 public void testConnectAPair_connectBothDevices() { 367 // Update hiSyncId map 368 getHiSyncIdFromNative(); 369 // Update the device priority so okToConnect() returns true 370 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 371 when(mDatabaseManager 372 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 373 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 374 when(mDatabaseManager 375 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 376 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 377 when(mDatabaseManager 378 .getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.HEARING_AID)) 379 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 380 doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); 381 doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); 382 383 // Send a connect request 384 Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); 385 386 // Verify the connection state broadcast, and that we are in Connecting state 387 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, 388 BluetoothProfile.STATE_DISCONNECTED); 389 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 390 mService.getConnectionState(mLeftDevice)); 391 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, 392 BluetoothProfile.STATE_DISCONNECTED); 393 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 394 mService.getConnectionState(mRightDevice)); 395 } 396 397 /** 398 * Test that the service disconnects the current pair before connecting to another pair. 399 */ 400 @Test testConnectAnotherPair_disconnectCurrentPair()401 public void testConnectAnotherPair_disconnectCurrentPair() { 402 // Update hiSyncId map 403 getHiSyncIdFromNative(); 404 // Update the device priority so okToConnect() returns true 405 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 406 when(mDatabaseManager 407 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 408 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 409 when(mDatabaseManager 410 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 411 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 412 when(mDatabaseManager 413 .getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.HEARING_AID)) 414 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 415 doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); 416 doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); 417 418 // Send a connect request 419 Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); 420 421 // Verify the connection state broadcast, and that we are in Connecting state 422 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, 423 BluetoothProfile.STATE_DISCONNECTED); 424 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, 425 BluetoothProfile.STATE_DISCONNECTED); 426 427 HearingAidStackEvent connCompletedEvent; 428 // Send a message to trigger connection completed 429 connCompletedEvent = new HearingAidStackEvent( 430 HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 431 connCompletedEvent.device = mLeftDevice; 432 connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; 433 mService.messageFromNative(connCompletedEvent); 434 connCompletedEvent = new HearingAidStackEvent( 435 HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 436 connCompletedEvent.device = mRightDevice; 437 connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; 438 mService.messageFromNative(connCompletedEvent); 439 440 // Verify the connection state broadcast, and that we are in Connected state for right side 441 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTED, 442 BluetoothProfile.STATE_CONNECTING); 443 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTED, 444 BluetoothProfile.STATE_CONNECTING); 445 446 // Send a connect request for another pair 447 Assert.assertTrue("Connect failed", mService.connect(mSingleDevice)); 448 449 // Verify the connection state broadcast, and that the first pair is in Disconnecting state 450 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_DISCONNECTING, 451 BluetoothProfile.STATE_CONNECTED); 452 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_DISCONNECTING, 453 BluetoothProfile.STATE_CONNECTED); 454 Assert.assertFalse(mService.getConnectedDevices().contains(mLeftDevice)); 455 Assert.assertFalse(mService.getConnectedDevices().contains(mRightDevice)); 456 457 // Verify the connection state broadcast, and that the second device is in Connecting state 458 verifyConnectionStateIntent(TIMEOUT_MS, mSingleDevice, BluetoothProfile.STATE_CONNECTING, 459 BluetoothProfile.STATE_DISCONNECTED); 460 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 461 mService.getConnectionState(mSingleDevice)); 462 } 463 464 /** 465 * Test that the outgoing connect/disconnect and audio switch is successful. 466 */ 467 @Test testAudioManagerConnectDisconnect()468 public void testAudioManagerConnectDisconnect() { 469 // Update hiSyncId map 470 getHiSyncIdFromNative(); 471 // Update the device priority so okToConnect() returns true 472 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 473 when(mDatabaseManager 474 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 475 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 476 when(mDatabaseManager 477 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 478 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 479 when(mDatabaseManager 480 .getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.HEARING_AID)) 481 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 482 doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); 483 doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); 484 485 // Send a connect request 486 Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); 487 Assert.assertTrue("Connect failed", mService.connect(mRightDevice)); 488 489 // Verify the connection state broadcast, and that we are in Connecting state 490 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, 491 BluetoothProfile.STATE_DISCONNECTED); 492 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 493 mService.getConnectionState(mLeftDevice)); 494 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, 495 BluetoothProfile.STATE_DISCONNECTED); 496 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 497 mService.getConnectionState(mRightDevice)); 498 499 HearingAidStackEvent connCompletedEvent; 500 // Send a message to trigger connection completed 501 connCompletedEvent = new HearingAidStackEvent( 502 HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 503 connCompletedEvent.device = mLeftDevice; 504 connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; 505 mService.messageFromNative(connCompletedEvent); 506 507 // Verify the connection state broadcast, and that we are in Connected state 508 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTED, 509 BluetoothProfile.STATE_CONNECTING); 510 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 511 mService.getConnectionState(mLeftDevice)); 512 513 // Send a message to trigger connection completed for right side 514 connCompletedEvent = new HearingAidStackEvent( 515 HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 516 connCompletedEvent.device = mRightDevice; 517 connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; 518 mService.messageFromNative(connCompletedEvent); 519 520 // Verify the connection state broadcast, and that we are in Connected state for right side 521 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTED, 522 BluetoothProfile.STATE_CONNECTING); 523 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 524 mService.getConnectionState(mRightDevice)); 525 526 // Verify the list of connected devices 527 Assert.assertTrue(mService.getConnectedDevices().contains(mLeftDevice)); 528 Assert.assertTrue(mService.getConnectedDevices().contains(mRightDevice)); 529 530 // Verify the audio is routed to Hearing Aid Profile 531 verify(mAudioManager).setBluetoothHearingAidDeviceConnectionState( 532 any(BluetoothDevice.class), eq(BluetoothProfile.STATE_CONNECTED), 533 eq(true), eq(0)); 534 535 // Send a disconnect request 536 Assert.assertTrue("Disconnect failed", mService.disconnect(mLeftDevice)); 537 Assert.assertTrue("Disconnect failed", mService.disconnect(mRightDevice)); 538 539 // Verify the connection state broadcast, and that we are in Disconnecting state 540 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_DISCONNECTING, 541 BluetoothProfile.STATE_CONNECTED); 542 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTING, 543 mService.getConnectionState(mLeftDevice)); 544 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_DISCONNECTING, 545 BluetoothProfile.STATE_CONNECTED); 546 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTING, 547 mService.getConnectionState(mRightDevice)); 548 549 // Send a message to trigger disconnection completed 550 connCompletedEvent = new HearingAidStackEvent( 551 HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 552 connCompletedEvent.device = mLeftDevice; 553 connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_DISCONNECTED; 554 mService.messageFromNative(connCompletedEvent); 555 556 // Verify the connection state broadcast, and that we are in Disconnected state 557 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_DISCONNECTED, 558 BluetoothProfile.STATE_DISCONNECTING); 559 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 560 mService.getConnectionState(mLeftDevice)); 561 562 // Send a message to trigger disconnection completed to the right device 563 connCompletedEvent = new HearingAidStackEvent( 564 HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 565 connCompletedEvent.device = mRightDevice; 566 connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_DISCONNECTED; 567 mService.messageFromNative(connCompletedEvent); 568 569 // Verify the connection state broadcast, and that we are in Disconnected state 570 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_DISCONNECTED, 571 BluetoothProfile.STATE_DISCONNECTING); 572 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 573 mService.getConnectionState(mRightDevice)); 574 575 // Verify the list of connected devices 576 Assert.assertFalse(mService.getConnectedDevices().contains(mLeftDevice)); 577 Assert.assertFalse(mService.getConnectedDevices().contains(mRightDevice)); 578 579 // Verify the audio is not routed to Hearing Aid Profile 580 verify(mAudioManager).setBluetoothHearingAidDeviceConnectionState( 581 any(BluetoothDevice.class), eq(BluetoothProfile.STATE_DISCONNECTED), 582 eq(false), eq(0)); 583 } 584 585 /** 586 * Test that only CONNECTION_STATE_CONNECTED or CONNECTION_STATE_CONNECTING Hearing Aid stack 587 * events will create a state machine. 588 */ 589 @Test testCreateStateMachineStackEvents()590 public void testCreateStateMachineStackEvents() { 591 // Update the device priority so okToConnect() returns true 592 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 593 when(mDatabaseManager 594 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 595 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 596 when(mDatabaseManager 597 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 598 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 599 when(mDatabaseManager 600 .getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.HEARING_AID)) 601 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 602 doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); 603 doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); 604 605 // Hearing Aid stack event: CONNECTION_STATE_CONNECTING - state machine should be created 606 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTING, 607 BluetoothProfile.STATE_DISCONNECTED); 608 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 609 mService.getConnectionState(mLeftDevice)); 610 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 611 612 // HearingAid stack event: CONNECTION_STATE_DISCONNECTED - state machine should be removed 613 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_DISCONNECTED, 614 BluetoothProfile.STATE_CONNECTING); 615 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 616 mService.getConnectionState(mLeftDevice)); 617 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 618 mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_NONE); 619 Assert.assertFalse(mService.getDevices().contains(mLeftDevice)); 620 621 // stack event: CONNECTION_STATE_CONNECTED - state machine should be created 622 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTED, 623 BluetoothProfile.STATE_DISCONNECTED); 624 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 625 mService.getConnectionState(mLeftDevice)); 626 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 627 628 // stack event: CONNECTION_STATE_DISCONNECTED - state machine should be removed 629 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_DISCONNECTED, 630 BluetoothProfile.STATE_CONNECTED); 631 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 632 mService.getConnectionState(mLeftDevice)); 633 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 634 mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_NONE); 635 Assert.assertFalse(mService.getDevices().contains(mLeftDevice)); 636 637 // stack event: CONNECTION_STATE_DISCONNECTING - state machine should not be created 638 generateUnexpectedConnectionMessageFromNative(mLeftDevice, 639 BluetoothProfile.STATE_DISCONNECTING, 640 BluetoothProfile.STATE_DISCONNECTED); 641 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 642 mService.getConnectionState(mLeftDevice)); 643 Assert.assertFalse(mService.getDevices().contains(mLeftDevice)); 644 645 // stack event: CONNECTION_STATE_DISCONNECTED - state machine should not be created 646 generateUnexpectedConnectionMessageFromNative(mLeftDevice, 647 BluetoothProfile.STATE_DISCONNECTED, 648 BluetoothProfile.STATE_DISCONNECTED); 649 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 650 mService.getConnectionState(mLeftDevice)); 651 Assert.assertFalse(mService.getDevices().contains(mLeftDevice)); 652 } 653 654 /** 655 * Test that a state machine in DISCONNECTED state is removed only after the device is unbond. 656 */ 657 @Test testDeleteStateMachineUnbondEvents()658 public void testDeleteStateMachineUnbondEvents() { 659 // Update the device priority so okToConnect() returns true 660 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 661 when(mDatabaseManager 662 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 663 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 664 when(mDatabaseManager 665 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 666 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 667 when(mDatabaseManager 668 .getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.HEARING_AID)) 669 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 670 doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); 671 doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); 672 673 // HearingAid stack event: CONNECTION_STATE_CONNECTING - state machine should be created 674 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTING, 675 BluetoothProfile.STATE_DISCONNECTED); 676 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 677 mService.getConnectionState(mLeftDevice)); 678 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 679 // Device unbond - state machine is not removed 680 mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_NONE); 681 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 682 683 // HearingAid stack event: CONNECTION_STATE_CONNECTED - state machine is not removed 684 mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_BONDED); 685 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTED, 686 BluetoothProfile.STATE_CONNECTING); 687 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 688 mService.getConnectionState(mLeftDevice)); 689 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 690 // Device unbond - state machine is not removed 691 mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_NONE); 692 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 693 694 // HearingAid stack event: CONNECTION_STATE_DISCONNECTING - state machine is not removed 695 mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_BONDED); 696 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_DISCONNECTING, 697 BluetoothProfile.STATE_CONNECTED); 698 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTING, 699 mService.getConnectionState(mLeftDevice)); 700 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 701 // Device unbond - state machine is not removed 702 mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_NONE); 703 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 704 705 // HearingAid stack event: CONNECTION_STATE_DISCONNECTED - state machine is not removed 706 mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_BONDED); 707 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_DISCONNECTED, 708 BluetoothProfile.STATE_DISCONNECTING); 709 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 710 mService.getConnectionState(mLeftDevice)); 711 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 712 // Device unbond - state machine is removed 713 mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_NONE); 714 Assert.assertFalse(mService.getDevices().contains(mLeftDevice)); 715 } 716 717 /** 718 * Test that a CONNECTION_STATE_DISCONNECTED Hearing Aid stack event will remove the state 719 * machine only if the device is unbond. 720 */ 721 @Test testDeleteStateMachineDisconnectEvents()722 public void testDeleteStateMachineDisconnectEvents() { 723 // Update the device priority so okToConnect() returns true 724 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 725 when(mDatabaseManager 726 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 727 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 728 when(mDatabaseManager 729 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 730 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 731 when(mDatabaseManager 732 .getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.HEARING_AID)) 733 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 734 doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); 735 doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); 736 737 // HearingAid stack event: CONNECTION_STATE_CONNECTING - state machine should be created 738 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTING, 739 BluetoothProfile.STATE_DISCONNECTED); 740 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 741 mService.getConnectionState(mLeftDevice)); 742 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 743 744 // HearingAid stack event: CONNECTION_STATE_DISCONNECTED - state machine is not removed 745 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_DISCONNECTED, 746 BluetoothProfile.STATE_CONNECTING); 747 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 748 mService.getConnectionState(mLeftDevice)); 749 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 750 751 // HearingAid stack event: CONNECTION_STATE_CONNECTING - state machine remains 752 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTING, 753 BluetoothProfile.STATE_DISCONNECTED); 754 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 755 mService.getConnectionState(mLeftDevice)); 756 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 757 758 // Device bond state marked as unbond - state machine is not removed 759 doReturn(BluetoothDevice.BOND_NONE).when(mAdapterService) 760 .getBondState(any(BluetoothDevice.class)); 761 Assert.assertTrue(mService.getDevices().contains(mLeftDevice)); 762 763 // HearingAid stack event: CONNECTION_STATE_DISCONNECTED - state machine is removed 764 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_DISCONNECTED, 765 BluetoothProfile.STATE_CONNECTING); 766 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 767 mService.getConnectionState(mLeftDevice)); 768 Assert.assertFalse(mService.getDevices().contains(mLeftDevice)); 769 } 770 771 @Test testConnectionStateChangedActiveDevice()772 public void testConnectionStateChangedActiveDevice() { 773 // Update hiSyncId map 774 getHiSyncIdFromNative(); 775 // Update the device priority so okToConnect() returns true 776 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 777 when(mDatabaseManager 778 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 779 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 780 when(mDatabaseManager 781 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 782 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 783 when(mDatabaseManager 784 .getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.HEARING_AID)) 785 .thenReturn(BluetoothProfile.CONNECTION_POLICY_FORBIDDEN); 786 787 generateConnectionMessageFromNative(mRightDevice, BluetoothProfile.STATE_CONNECTED, 788 BluetoothProfile.STATE_DISCONNECTED); 789 Assert.assertTrue(mService.getActiveDevices().contains(mRightDevice)); 790 Assert.assertFalse(mService.getActiveDevices().contains(mLeftDevice)); 791 792 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTED, 793 BluetoothProfile.STATE_DISCONNECTED); 794 Assert.assertTrue(mService.getActiveDevices().contains(mRightDevice)); 795 Assert.assertTrue(mService.getActiveDevices().contains(mLeftDevice)); 796 797 generateConnectionMessageFromNative(mRightDevice, BluetoothProfile.STATE_DISCONNECTED, 798 BluetoothProfile.STATE_CONNECTED); 799 Assert.assertFalse(mService.getActiveDevices().contains(mRightDevice)); 800 Assert.assertTrue(mService.getActiveDevices().contains(mLeftDevice)); 801 802 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_DISCONNECTED, 803 BluetoothProfile.STATE_CONNECTED); 804 Assert.assertFalse(mService.getActiveDevices().contains(mRightDevice)); 805 Assert.assertFalse(mService.getActiveDevices().contains(mLeftDevice)); 806 } 807 808 @Test testConnectionStateChangedAnotherActiveDevice()809 public void testConnectionStateChangedAnotherActiveDevice() { 810 // Update hiSyncId map 811 getHiSyncIdFromNative(); 812 // Update the device priority so okToConnect() returns true 813 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 814 when(mDatabaseManager 815 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 816 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 817 when(mDatabaseManager 818 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 819 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 820 when(mDatabaseManager 821 .getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.HEARING_AID)) 822 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 823 824 generateConnectionMessageFromNative(mRightDevice, BluetoothProfile.STATE_CONNECTED, 825 BluetoothProfile.STATE_DISCONNECTED); 826 Assert.assertTrue(mService.getActiveDevices().contains(mRightDevice)); 827 Assert.assertFalse(mService.getActiveDevices().contains(mLeftDevice)); 828 829 generateConnectionMessageFromNative(mLeftDevice, BluetoothProfile.STATE_CONNECTED, 830 BluetoothProfile.STATE_DISCONNECTED); 831 Assert.assertTrue(mService.getActiveDevices().contains(mRightDevice)); 832 Assert.assertTrue(mService.getActiveDevices().contains(mLeftDevice)); 833 834 generateConnectionMessageFromNative(mSingleDevice, BluetoothProfile.STATE_CONNECTED, 835 BluetoothProfile.STATE_DISCONNECTED); 836 Assert.assertFalse(mService.getActiveDevices().contains(mRightDevice)); 837 Assert.assertFalse(mService.getActiveDevices().contains(mLeftDevice)); 838 Assert.assertTrue(mService.getActiveDevices().contains(mSingleDevice)); 839 } 840 841 /** 842 * Verify the correctness during first time connection. 843 * Connect to left device -> Get left device hiSyncId -> Connect to right device -> 844 * Get right device hiSyncId -> Both devices should be always connected 845 */ 846 @Test firstTimeConnection_shouldConnectToBothDevices()847 public void firstTimeConnection_shouldConnectToBothDevices() { 848 // Update the device priority so okToConnect() returns true 849 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 850 when(mDatabaseManager 851 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 852 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 853 when(mDatabaseManager 854 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 855 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 856 doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); 857 doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); 858 // Send a connect request for left device 859 Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); 860 // Verify the connection state broadcast, and that we are in Connecting state 861 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, 862 BluetoothProfile.STATE_DISCONNECTED); 863 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 864 mService.getConnectionState(mLeftDevice)); 865 866 HearingAidStackEvent connCompletedEvent; 867 // Send a message to trigger connection completed 868 connCompletedEvent = new HearingAidStackEvent( 869 HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 870 connCompletedEvent.device = mLeftDevice; 871 connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; 872 mService.messageFromNative(connCompletedEvent); 873 874 // Verify the connection state broadcast, and that we are in Connected state 875 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTED, 876 BluetoothProfile.STATE_CONNECTING); 877 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 878 mService.getConnectionState(mLeftDevice)); 879 880 // Get hiSyncId for left device 881 HearingAidStackEvent hiSyncIdEvent = new HearingAidStackEvent( 882 HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); 883 hiSyncIdEvent.device = mLeftDevice; 884 hiSyncIdEvent.valueInt1 = 0x02; 885 hiSyncIdEvent.valueLong2 = 0x0101; 886 mService.messageFromNative(hiSyncIdEvent); 887 888 // Send a connect request for right device 889 Assert.assertTrue("Connect failed", mService.connect(mRightDevice)); 890 // Verify the connection state broadcast, and that we are in Connecting state 891 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, 892 BluetoothProfile.STATE_DISCONNECTED); 893 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 894 mService.getConnectionState(mRightDevice)); 895 // Verify the left device is still connected 896 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 897 mService.getConnectionState(mLeftDevice)); 898 899 // Send a message to trigger connection completed 900 connCompletedEvent = new HearingAidStackEvent( 901 HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 902 connCompletedEvent.device = mRightDevice; 903 connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; 904 mService.messageFromNative(connCompletedEvent); 905 906 // Verify the connection state broadcast, and that we are in Connected state 907 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTED, 908 BluetoothProfile.STATE_CONNECTING); 909 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 910 mService.getConnectionState(mRightDevice)); 911 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 912 mService.getConnectionState(mLeftDevice)); 913 914 // Get hiSyncId for right device 915 hiSyncIdEvent = new HearingAidStackEvent( 916 HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); 917 hiSyncIdEvent.device = mRightDevice; 918 hiSyncIdEvent.valueInt1 = 0x02; 919 hiSyncIdEvent.valueLong2 = 0x0101; 920 mService.messageFromNative(hiSyncIdEvent); 921 922 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 923 mService.getConnectionState(mRightDevice)); 924 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 925 mService.getConnectionState(mLeftDevice)); 926 } 927 928 /** 929 * Get the HiSyncId from native stack after connecting to left device, then connect right 930 */ 931 @Test getHiSyncId_afterFirstDeviceConnected()932 public void getHiSyncId_afterFirstDeviceConnected() { 933 // Update the device priority so okToConnect() returns true 934 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 935 when(mDatabaseManager 936 .getProfileConnectionPolicy(mLeftDevice, BluetoothProfile.HEARING_AID)) 937 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 938 when(mDatabaseManager 939 .getProfileConnectionPolicy(mRightDevice, BluetoothProfile.HEARING_AID)) 940 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 941 when(mDatabaseManager 942 .getProfileConnectionPolicy(mSingleDevice, BluetoothProfile.HEARING_AID)) 943 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 944 doReturn(true).when(mNativeInterface).connectHearingAid(any(BluetoothDevice.class)); 945 doReturn(true).when(mNativeInterface).disconnectHearingAid(any(BluetoothDevice.class)); 946 // Send a connect request 947 Assert.assertTrue("Connect failed", mService.connect(mLeftDevice)); 948 // Verify the connection state broadcast, and that we are in Connecting state 949 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTING, 950 BluetoothProfile.STATE_DISCONNECTED); 951 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 952 mService.getConnectionState(mLeftDevice)); 953 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 954 mService.getConnectionState(mRightDevice)); 955 956 HearingAidStackEvent connCompletedEvent; 957 // Send a message to trigger connection completed 958 connCompletedEvent = new HearingAidStackEvent( 959 HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 960 connCompletedEvent.device = mLeftDevice; 961 connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; 962 mService.messageFromNative(connCompletedEvent); 963 // Verify the connection state broadcast, and that we are in Connected state 964 verifyConnectionStateIntent(TIMEOUT_MS, mLeftDevice, BluetoothProfile.STATE_CONNECTED, 965 BluetoothProfile.STATE_CONNECTING); 966 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 967 mService.getConnectionState(mLeftDevice)); 968 969 // Get hiSyncId update from native stack 970 getHiSyncIdFromNative(); 971 // Send a connect request for right 972 Assert.assertTrue("Connect failed", mService.connect(mRightDevice)); 973 // Verify the connection state broadcast, and that we are in Connecting state 974 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTING, 975 BluetoothProfile.STATE_DISCONNECTED); 976 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 977 mService.getConnectionState(mRightDevice)); 978 // Verify the left device is still connected 979 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 980 mService.getConnectionState(mLeftDevice)); 981 982 // Send a message to trigger connection completed 983 connCompletedEvent = new HearingAidStackEvent( 984 HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 985 connCompletedEvent.device = mRightDevice; 986 connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; 987 mService.messageFromNative(connCompletedEvent); 988 989 // Verify the connection state broadcast, and that we are in Connected state 990 verifyConnectionStateIntent(TIMEOUT_MS, mRightDevice, BluetoothProfile.STATE_CONNECTED, 991 BluetoothProfile.STATE_CONNECTING); 992 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 993 mService.getConnectionState(mRightDevice)); 994 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 995 mService.getConnectionState(mLeftDevice)); 996 } 997 998 /** 999 * Test that the service can update HiSyncId from native message 1000 */ 1001 @Test getHiSyncIdFromNative_addToMap()1002 public void getHiSyncIdFromNative_addToMap() { 1003 getHiSyncIdFromNative(); 1004 Assert.assertTrue("hiSyncIdMap should contain mLeftDevice", 1005 mService.getHiSyncIdMap().containsKey(mLeftDevice)); 1006 Assert.assertTrue("hiSyncIdMap should contain mRightDevice", 1007 mService.getHiSyncIdMap().containsKey(mRightDevice)); 1008 Assert.assertTrue("hiSyncIdMap should contain mSingleDevice", 1009 mService.getHiSyncIdMap().containsKey(mSingleDevice)); 1010 } 1011 1012 /** 1013 * Test that the service removes the device from HiSyncIdMap when it's unbonded 1014 */ 1015 @Test deviceUnbonded_removeHiSyncId()1016 public void deviceUnbonded_removeHiSyncId() { 1017 getHiSyncIdFromNative(); 1018 mService.bondStateChanged(mLeftDevice, BluetoothDevice.BOND_NONE); 1019 Assert.assertFalse("hiSyncIdMap shouldn't contain mLeftDevice", 1020 mService.getHiSyncIdMap().containsKey(mLeftDevice)); 1021 } 1022 connectDevice(BluetoothDevice device)1023 private void connectDevice(BluetoothDevice device) { 1024 HearingAidStackEvent connCompletedEvent; 1025 1026 List<BluetoothDevice> prevConnectedDevices = mService.getConnectedDevices(); 1027 1028 // Update the device priority so okToConnect() returns true 1029 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 1030 when(mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.HEARING_AID)) 1031 .thenReturn(BluetoothProfile.CONNECTION_POLICY_ALLOWED); 1032 doReturn(true).when(mNativeInterface).connectHearingAid(device); 1033 doReturn(true).when(mNativeInterface).disconnectHearingAid(device); 1034 1035 // Send a connect request 1036 Assert.assertTrue("Connect failed", mService.connect(device)); 1037 1038 // Verify the connection state broadcast, and that we are in Connecting state 1039 verifyConnectionStateIntent(TIMEOUT_MS, device, BluetoothProfile.STATE_CONNECTING, 1040 BluetoothProfile.STATE_DISCONNECTED); 1041 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 1042 mService.getConnectionState(device)); 1043 1044 // Send a message to trigger connection completed 1045 connCompletedEvent = new HearingAidStackEvent( 1046 HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 1047 connCompletedEvent.device = device; 1048 connCompletedEvent.valueInt1 = HearingAidStackEvent.CONNECTION_STATE_CONNECTED; 1049 mService.messageFromNative(connCompletedEvent); 1050 1051 // Verify the connection state broadcast, and that we are in Connected state 1052 verifyConnectionStateIntent(TIMEOUT_MS, device, BluetoothProfile.STATE_CONNECTED, 1053 BluetoothProfile.STATE_CONNECTING); 1054 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 1055 mService.getConnectionState(device)); 1056 1057 // Verify that the device is in the list of connected devices 1058 Assert.assertTrue(mService.getConnectedDevices().contains(device)); 1059 // Verify the list of previously connected devices 1060 for (BluetoothDevice prevDevice : prevConnectedDevices) { 1061 Assert.assertTrue(mService.getConnectedDevices().contains(prevDevice)); 1062 } 1063 } 1064 generateConnectionMessageFromNative(BluetoothDevice device, int newConnectionState, int oldConnectionState)1065 private void generateConnectionMessageFromNative(BluetoothDevice device, int newConnectionState, 1066 int oldConnectionState) { 1067 HearingAidStackEvent stackEvent = 1068 new HearingAidStackEvent(HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 1069 stackEvent.device = device; 1070 stackEvent.valueInt1 = newConnectionState; 1071 mService.messageFromNative(stackEvent); 1072 // Verify the connection state broadcast 1073 verifyConnectionStateIntent(TIMEOUT_MS, device, newConnectionState, oldConnectionState); 1074 } 1075 generateUnexpectedConnectionMessageFromNative(BluetoothDevice device, int newConnectionState, int oldConnectionState)1076 private void generateUnexpectedConnectionMessageFromNative(BluetoothDevice device, 1077 int newConnectionState, int oldConnectionState) { 1078 HearingAidStackEvent stackEvent = 1079 new HearingAidStackEvent(HearingAidStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 1080 stackEvent.device = device; 1081 stackEvent.valueInt1 = newConnectionState; 1082 mService.messageFromNative(stackEvent); 1083 // Verify the connection state broadcast 1084 verifyNoConnectionStateIntent(TIMEOUT_MS, device); 1085 } 1086 1087 /** 1088 * Helper function to test okToConnect() method 1089 * 1090 * @param device test device 1091 * @param bondState bond state value, could be invalid 1092 * @param priority value, could be invalid, coudl be invalid 1093 * @param expected expected result from okToConnect() 1094 */ testOkToConnectCase(BluetoothDevice device, int bondState, int priority, boolean expected)1095 private void testOkToConnectCase(BluetoothDevice device, int bondState, int priority, 1096 boolean expected) { 1097 doReturn(bondState).when(mAdapterService).getBondState(device); 1098 when(mAdapterService.getDatabase()).thenReturn(mDatabaseManager); 1099 when(mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.HEARING_AID)) 1100 .thenReturn(priority); 1101 Assert.assertEquals(expected, mService.okToConnect(device)); 1102 } 1103 getHiSyncIdFromNative()1104 private void getHiSyncIdFromNative() { 1105 HearingAidStackEvent event = new HearingAidStackEvent( 1106 HearingAidStackEvent.EVENT_TYPE_DEVICE_AVAILABLE); 1107 event.device = mLeftDevice; 1108 event.valueInt1 = 0x02; 1109 event.valueLong2 = 0x0101; 1110 mService.messageFromNative(event); 1111 event.device = mRightDevice; 1112 event.valueInt1 = 0x03; 1113 mService.messageFromNative(event); 1114 event.device = mSingleDevice; 1115 event.valueInt1 = 0x00; 1116 event.valueLong2 = 0x0102; 1117 mService.messageFromNative(event); 1118 } 1119 } 1120