Home | History | Annotate | Download | only in hearingaid
      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
     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
    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 
    135     private void startService() throws TimeoutException {
    136         TestUtils.startService(mServiceRule, HearingAidService.class);
    137         mService = HearingAidService.getHearingAidService();
    138         Assert.assertNotNull(mService);
    139     }
    140 
    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
    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 
    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 
    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
    187     public void testGetHearingAidService() {
    188         Assert.assertEquals(mService, HearingAidService.getHearingAidService());
    189     }
    190 
    191     /**
    192      * Test stop HearingAid Service
    193      */
    194     @Test
    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
    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
    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, true);
    257         testOkToConnectCase(mSingleDevice,
    258                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_OFF, false);
    259         testOkToConnectCase(mSingleDevice,
    260                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_ON, true);
    261         testOkToConnectCase(mSingleDevice,
    262                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 
    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 
    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 
    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      */
    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 
    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