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