Home | History | Annotate | Download | only in a2dp
      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.a2dp;
     18 
     19 import static org.mockito.Mockito.*;
     20 
     21 import android.bluetooth.BluetoothA2dp;
     22 import android.bluetooth.BluetoothAdapter;
     23 import android.bluetooth.BluetoothCodecConfig;
     24 import android.bluetooth.BluetoothCodecStatus;
     25 import android.bluetooth.BluetoothDevice;
     26 import android.bluetooth.BluetoothProfile;
     27 import android.bluetooth.BluetoothUuid;
     28 import android.content.BroadcastReceiver;
     29 import android.content.Context;
     30 import android.content.Intent;
     31 import android.content.IntentFilter;
     32 import android.os.Looper;
     33 import android.os.ParcelUuid;
     34 import android.support.test.InstrumentationRegistry;
     35 import android.support.test.filters.MediumTest;
     36 import android.support.test.rule.ServiceTestRule;
     37 import android.support.test.runner.AndroidJUnit4;
     38 
     39 import com.android.bluetooth.R;
     40 import com.android.bluetooth.TestUtils;
     41 import com.android.bluetooth.btservice.AdapterService;
     42 
     43 import org.junit.After;
     44 import org.junit.Assert;
     45 import org.junit.Assume;
     46 import org.junit.Before;
     47 import org.junit.Rule;
     48 import org.junit.Test;
     49 import org.junit.runner.RunWith;
     50 import org.mockito.Mock;
     51 import org.mockito.MockitoAnnotations;
     52 
     53 import java.util.List;
     54 import java.util.concurrent.BlockingQueue;
     55 import java.util.concurrent.LinkedBlockingQueue;
     56 import java.util.concurrent.TimeoutException;
     57 
     58 @MediumTest
     59 @RunWith(AndroidJUnit4.class)
     60 public class A2dpServiceTest {
     61     private static final int MAX_CONNECTED_AUDIO_DEVICES = 5;
     62 
     63     private BluetoothAdapter mAdapter;
     64     private Context mTargetContext;
     65     private A2dpService mA2dpService;
     66     private BluetoothDevice mTestDevice;
     67     private static final int TIMEOUT_MS = 1000;    // 1s
     68 
     69     private BroadcastReceiver mA2dpIntentReceiver;
     70     private final BlockingQueue<Intent> mConnectionStateChangedQueue = new LinkedBlockingQueue<>();
     71     private final BlockingQueue<Intent> mAudioStateChangedQueue = new LinkedBlockingQueue<>();
     72     private final BlockingQueue<Intent> mCodecConfigChangedQueue = new LinkedBlockingQueue<>();
     73 
     74     @Mock private AdapterService mAdapterService;
     75     @Mock private A2dpNativeInterface mA2dpNativeInterface;
     76 
     77     @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule();
     78 
     79     @Before
     80     public void setUp() throws Exception {
     81         mTargetContext = InstrumentationRegistry.getTargetContext();
     82         Assume.assumeTrue("Ignore test when A2dpService is not enabled",
     83                 mTargetContext.getResources().getBoolean(R.bool.profile_supported_a2dp));
     84         // Set up mocks and test assets
     85         MockitoAnnotations.initMocks(this);
     86 
     87         if (Looper.myLooper() == null) {
     88             Looper.prepare();
     89         }
     90 
     91         TestUtils.setAdapterService(mAdapterService);
     92         doReturn(MAX_CONNECTED_AUDIO_DEVICES).when(mAdapterService).getMaxConnectedAudioDevices();
     93         doReturn(false).when(mAdapterService).isQuietModeEnabled();
     94 
     95         mAdapter = BluetoothAdapter.getDefaultAdapter();
     96 
     97         startService();
     98         mA2dpService.mA2dpNativeInterface = mA2dpNativeInterface;
     99 
    100         // Override the timeout value to speed up the test
    101         A2dpStateMachine.sConnectTimeoutMs = TIMEOUT_MS;    // 1s
    102 
    103         // Set up the Connection State Changed receiver
    104         IntentFilter filter = new IntentFilter();
    105         filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
    106         filter.addAction(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED);
    107         filter.addAction(BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED);
    108         mA2dpIntentReceiver = new A2dpIntentReceiver();
    109         mTargetContext.registerReceiver(mA2dpIntentReceiver, filter);
    110 
    111         // Get a device for testing
    112         mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05");
    113         mA2dpService.setPriority(mTestDevice, BluetoothProfile.PRIORITY_UNDEFINED);
    114         doReturn(BluetoothDevice.BOND_BONDED).when(mAdapterService)
    115                 .getBondState(any(BluetoothDevice.class));
    116         doReturn(new ParcelUuid[]{BluetoothUuid.AudioSink}).when(mAdapterService)
    117                 .getRemoteUuids(any(BluetoothDevice.class));
    118     }
    119 
    120     @After
    121     public void tearDown() throws Exception {
    122         if (!mTargetContext.getResources().getBoolean(R.bool.profile_supported_a2dp)) {
    123             return;
    124         }
    125         stopService();
    126         mTargetContext.unregisterReceiver(mA2dpIntentReceiver);
    127         mConnectionStateChangedQueue.clear();
    128         mAudioStateChangedQueue.clear();
    129         mCodecConfigChangedQueue.clear();
    130         TestUtils.clearAdapterService(mAdapterService);
    131     }
    132 
    133     private void startService() throws TimeoutException {
    134         TestUtils.startService(mServiceRule, A2dpService.class);
    135         mA2dpService = A2dpService.getA2dpService();
    136         Assert.assertNotNull(mA2dpService);
    137     }
    138 
    139     private void stopService() throws TimeoutException {
    140         TestUtils.stopService(mServiceRule, A2dpService.class);
    141         mA2dpService = A2dpService.getA2dpService();
    142         Assert.assertNull(mA2dpService);
    143     }
    144 
    145     private class A2dpIntentReceiver extends BroadcastReceiver {
    146         @Override
    147         public void onReceive(Context context, Intent intent) {
    148             if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
    149                 try {
    150                     mConnectionStateChangedQueue.put(intent);
    151                 } catch (InterruptedException e) {
    152                     Assert.fail("Cannot add Intent to the Connection State queue: "
    153                                 + e.getMessage());
    154                 }
    155             }
    156             if (BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED.equals(intent.getAction())) {
    157                 try {
    158                     mAudioStateChangedQueue.put(intent);
    159                 } catch (InterruptedException e) {
    160                     Assert.fail("Cannot add Intent to the Audio State queue: " + e.getMessage());
    161                 }
    162             }
    163             if (BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED.equals(intent.getAction())) {
    164                 try {
    165                     mCodecConfigChangedQueue.put(intent);
    166                 } catch (InterruptedException e) {
    167                     Assert.fail("Cannot add Intent to the Codec Config queue: " + e.getMessage());
    168                 }
    169             }
    170         }
    171     }
    172 
    173     private void verifyConnectionStateIntent(int timeoutMs, BluetoothDevice device,
    174                                              int newState, int prevState) {
    175         Intent intent = TestUtils.waitForIntent(timeoutMs, mConnectionStateChangedQueue);
    176         Assert.assertNotNull(intent);
    177         Assert.assertEquals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
    178                             intent.getAction());
    179         Assert.assertEquals(device, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
    180         Assert.assertEquals(newState, intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
    181         Assert.assertEquals(prevState, intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE,
    182                                                           -1));
    183     }
    184 
    185     private void verifyNoConnectionStateIntent(int timeoutMs) {
    186         Intent intent = TestUtils.waitForNoIntent(timeoutMs, mConnectionStateChangedQueue);
    187         Assert.assertNull(intent);
    188     }
    189 
    190     private void verifyAudioStateIntent(int timeoutMs, BluetoothDevice device,
    191                                              int newState, int prevState) {
    192         Intent intent = TestUtils.waitForIntent(timeoutMs, mAudioStateChangedQueue);
    193         Assert.assertNotNull(intent);
    194         Assert.assertEquals(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED, intent.getAction());
    195         Assert.assertEquals(device, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
    196         Assert.assertEquals(newState, intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
    197         Assert.assertEquals(prevState, intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE,
    198                                                           -1));
    199     }
    200 
    201     private void verifyNoAudioStateIntent(int timeoutMs) {
    202         Intent intent = TestUtils.waitForNoIntent(timeoutMs, mAudioStateChangedQueue);
    203         Assert.assertNull(intent);
    204     }
    205 
    206     private void verifyCodecConfigIntent(int timeoutMs, BluetoothDevice device,
    207                                          BluetoothCodecStatus codecStatus) {
    208         Intent intent = TestUtils.waitForIntent(timeoutMs, mCodecConfigChangedQueue);
    209         Assert.assertNotNull(intent);
    210         Assert.assertEquals(BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED, intent.getAction());
    211         Assert.assertEquals(device, intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE));
    212         Assert.assertEquals(codecStatus,
    213                             intent.getParcelableExtra(BluetoothCodecStatus.EXTRA_CODEC_STATUS));
    214     }
    215 
    216     private void verifyNoCodecConfigIntent(int timeoutMs) {
    217         Intent intent = TestUtils.waitForNoIntent(timeoutMs, mCodecConfigChangedQueue);
    218         Assert.assertNull(intent);
    219     }
    220 
    221     /**
    222      * Test getting A2DP Service: getA2dpService()
    223      */
    224     @Test
    225     public void testGetA2dpService() {
    226         Assert.assertEquals(mA2dpService, A2dpService.getA2dpService());
    227     }
    228 
    229     /**
    230      * Test stop A2DP Service
    231      */
    232     @Test
    233     public void testStopA2dpService() {
    234         // Prepare: connect and set active device
    235         doReturn(true).when(mA2dpNativeInterface).setActiveDevice(any(BluetoothDevice.class));
    236         connectDevice(mTestDevice);
    237         Assert.assertTrue(mA2dpService.setActiveDevice(mTestDevice));
    238         verify(mA2dpNativeInterface).setActiveDevice(mTestDevice);
    239         // A2DP Service is already running: test stop(). Note: must be done on the main thread.
    240         InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
    241             public void run() {
    242                 Assert.assertTrue(mA2dpService.stop());
    243             }
    244         });
    245         // Verify that setActiveDevice(null) was called during shutdown
    246         verify(mA2dpNativeInterface).setActiveDevice(null);
    247         // Try to restart the service. Note: must be done on the main thread.
    248         InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
    249             public void run() {
    250                 Assert.assertTrue(mA2dpService.start());
    251             }
    252         });
    253     }
    254 
    255     /**
    256      * Test get/set priority for BluetoothDevice
    257      */
    258     @Test
    259     public void testGetSetPriority() {
    260         Assert.assertEquals("Initial device priority",
    261                             BluetoothProfile.PRIORITY_UNDEFINED,
    262                             mA2dpService.getPriority(mTestDevice));
    263 
    264         Assert.assertTrue(mA2dpService.setPriority(mTestDevice,  BluetoothProfile.PRIORITY_OFF));
    265         Assert.assertEquals("Setting device priority to PRIORITY_OFF",
    266                             BluetoothProfile.PRIORITY_OFF,
    267                             mA2dpService.getPriority(mTestDevice));
    268 
    269         Assert.assertTrue(mA2dpService.setPriority(mTestDevice,  BluetoothProfile.PRIORITY_ON));
    270         Assert.assertEquals("Setting device priority to PRIORITY_ON",
    271                             BluetoothProfile.PRIORITY_ON,
    272                             mA2dpService.getPriority(mTestDevice));
    273 
    274         Assert.assertTrue(mA2dpService.setPriority(mTestDevice,
    275                                                    BluetoothProfile.PRIORITY_AUTO_CONNECT));
    276         Assert.assertEquals("Setting device priority to PRIORITY_AUTO_CONNECT",
    277                             BluetoothProfile.PRIORITY_AUTO_CONNECT,
    278                             mA2dpService.getPriority(mTestDevice));
    279     }
    280 
    281     /**
    282      *  Test okToConnect method using various test cases
    283      */
    284     @Test
    285     public void testOkToConnect() {
    286         int badPriorityValue = 1024;
    287         int badBondState = 42;
    288         testOkToConnectCase(mTestDevice,
    289                 BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_UNDEFINED, false);
    290         testOkToConnectCase(mTestDevice,
    291                 BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_OFF, false);
    292         testOkToConnectCase(mTestDevice,
    293                 BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_ON, false);
    294         testOkToConnectCase(mTestDevice,
    295                 BluetoothDevice.BOND_NONE, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
    296         testOkToConnectCase(mTestDevice,
    297                 BluetoothDevice.BOND_NONE, badPriorityValue, false);
    298         testOkToConnectCase(mTestDevice,
    299                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_UNDEFINED, true);
    300         testOkToConnectCase(mTestDevice,
    301                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_OFF, false);
    302         testOkToConnectCase(mTestDevice,
    303                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_ON, true);
    304         testOkToConnectCase(mTestDevice,
    305                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
    306         testOkToConnectCase(mTestDevice,
    307                 BluetoothDevice.BOND_BONDING, badPriorityValue, false);
    308         testOkToConnectCase(mTestDevice,
    309                 BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_UNDEFINED, true);
    310         testOkToConnectCase(mTestDevice,
    311                 BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_OFF, false);
    312         testOkToConnectCase(mTestDevice,
    313                 BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_ON, true);
    314         testOkToConnectCase(mTestDevice,
    315                 BluetoothDevice.BOND_BONDED, BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
    316         testOkToConnectCase(mTestDevice,
    317                 BluetoothDevice.BOND_BONDED, badPriorityValue, false);
    318         testOkToConnectCase(mTestDevice,
    319                 badBondState, BluetoothProfile.PRIORITY_UNDEFINED, false);
    320         testOkToConnectCase(mTestDevice,
    321                 badBondState, BluetoothProfile.PRIORITY_OFF, false);
    322         testOkToConnectCase(mTestDevice,
    323                 badBondState, BluetoothProfile.PRIORITY_ON, false);
    324         testOkToConnectCase(mTestDevice,
    325                 badBondState, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
    326         testOkToConnectCase(mTestDevice,
    327                 badBondState, badPriorityValue, false);
    328         // Restore prirority to undefined for this test device
    329         Assert.assertTrue(mA2dpService.setPriority(
    330                 mTestDevice, BluetoothProfile.PRIORITY_UNDEFINED));
    331     }
    332 
    333 
    334     /**
    335      * Test that an outgoing connection to device that does not have A2DP Sink UUID is rejected
    336      */
    337     @Test
    338     public void testOutgoingConnectMissingAudioSinkUuid() {
    339         // Update the device priority so okToConnect() returns true
    340         mA2dpService.setPriority(mTestDevice, BluetoothProfile.PRIORITY_ON);
    341         doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class));
    342         doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class));
    343 
    344         // Return AudioSource UUID instead of AudioSink
    345         doReturn(new ParcelUuid[]{BluetoothUuid.AudioSource}).when(mAdapterService)
    346                 .getRemoteUuids(any(BluetoothDevice.class));
    347 
    348         // Send a connect request
    349         Assert.assertFalse("Connect expected to fail", mA2dpService.connect(mTestDevice));
    350     }
    351 
    352     /**
    353      * Test that an outgoing connection to device with PRIORITY_OFF is rejected
    354      */
    355     @Test
    356     public void testOutgoingConnectPriorityOff() {
    357         doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class));
    358         doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class));
    359 
    360         // Set the device priority to PRIORITY_OFF so connect() should fail
    361         mA2dpService.setPriority(mTestDevice, BluetoothProfile.PRIORITY_OFF);
    362 
    363         // Send a connect request
    364         Assert.assertFalse("Connect expected to fail", mA2dpService.connect(mTestDevice));
    365     }
    366 
    367     /**
    368      * Test that an outgoing connection times out
    369      */
    370     @Test
    371     public void testOutgoingConnectTimeout() {
    372         // Update the device priority so okToConnect() returns true
    373         mA2dpService.setPriority(mTestDevice, BluetoothProfile.PRIORITY_ON);
    374         doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class));
    375         doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class));
    376 
    377         // Send a connect request
    378         Assert.assertTrue("Connect failed", mA2dpService.connect(mTestDevice));
    379 
    380         // Verify the connection state broadcast, and that we are in Connecting state
    381         verifyConnectionStateIntent(TIMEOUT_MS, mTestDevice, BluetoothProfile.STATE_CONNECTING,
    382                                     BluetoothProfile.STATE_DISCONNECTED);
    383         Assert.assertEquals(BluetoothProfile.STATE_CONNECTING,
    384                             mA2dpService.getConnectionState(mTestDevice));
    385 
    386         // Verify the connection state broadcast, and that we are in Disconnected state
    387         verifyConnectionStateIntent(A2dpStateMachine.sConnectTimeoutMs * 2,
    388                                     mTestDevice, BluetoothProfile.STATE_DISCONNECTED,
    389                                     BluetoothProfile.STATE_CONNECTING);
    390         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    391                             mA2dpService.getConnectionState(mTestDevice));
    392     }
    393 
    394     /**
    395      * Test that an outgoing connection/disconnection succeeds
    396      */
    397     @Test
    398     public void testOutgoingConnectDisconnectSuccess() {
    399         A2dpStackEvent connCompletedEvent;
    400 
    401         // Update the device priority so okToConnect() returns true
    402         mA2dpService.setPriority(mTestDevice, BluetoothProfile.PRIORITY_ON);
    403         doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class));
    404         doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class));
    405 
    406         // Send a connect request
    407         Assert.assertTrue("Connect failed", mA2dpService.connect(mTestDevice));
    408 
    409         // Verify the connection state broadcast, and that we are in Connecting state
    410         verifyConnectionStateIntent(TIMEOUT_MS, mTestDevice, BluetoothProfile.STATE_CONNECTING,
    411                                     BluetoothProfile.STATE_DISCONNECTED);
    412         Assert.assertEquals(BluetoothProfile.STATE_CONNECTING,
    413                             mA2dpService.getConnectionState(mTestDevice));
    414 
    415         // Send a message to trigger connection completed
    416         connCompletedEvent = new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
    417         connCompletedEvent.device = mTestDevice;
    418         connCompletedEvent.valueInt = A2dpStackEvent.CONNECTION_STATE_CONNECTED;
    419         mA2dpService.messageFromNative(connCompletedEvent);
    420 
    421         // Verify the connection state broadcast, and that we are in Connected state
    422         verifyConnectionStateIntent(TIMEOUT_MS, mTestDevice, BluetoothProfile.STATE_CONNECTED,
    423                                     BluetoothProfile.STATE_CONNECTING);
    424         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
    425                             mA2dpService.getConnectionState(mTestDevice));
    426 
    427         // Verify the list of connected devices
    428         Assert.assertTrue(mA2dpService.getConnectedDevices().contains(mTestDevice));
    429 
    430         // Send a disconnect request
    431         Assert.assertTrue("Disconnect failed", mA2dpService.disconnect(mTestDevice));
    432 
    433         // Verify the connection state broadcast, and that we are in Disconnecting state
    434         verifyConnectionStateIntent(TIMEOUT_MS, mTestDevice, BluetoothProfile.STATE_DISCONNECTING,
    435                                     BluetoothProfile.STATE_CONNECTED);
    436         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTING,
    437                             mA2dpService.getConnectionState(mTestDevice));
    438 
    439         // Send a message to trigger disconnection completed
    440         connCompletedEvent = new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
    441         connCompletedEvent.device = mTestDevice;
    442         connCompletedEvent.valueInt = A2dpStackEvent.CONNECTION_STATE_DISCONNECTED;
    443         mA2dpService.messageFromNative(connCompletedEvent);
    444 
    445         // Verify the connection state broadcast, and that we are in Disconnected state
    446         verifyConnectionStateIntent(TIMEOUT_MS, mTestDevice, BluetoothProfile.STATE_DISCONNECTED,
    447                                     BluetoothProfile.STATE_DISCONNECTING);
    448         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    449                             mA2dpService.getConnectionState(mTestDevice));
    450 
    451         // Verify the list of connected devices
    452         Assert.assertFalse(mA2dpService.getConnectedDevices().contains(mTestDevice));
    453     }
    454 
    455     /**
    456      * Test that an outgoing connection/disconnection succeeds
    457      */
    458     @Test
    459     public void testMaxConnectDevices() {
    460         A2dpStackEvent connCompletedEvent;
    461         BluetoothDevice[] testDevices = new BluetoothDevice[MAX_CONNECTED_AUDIO_DEVICES];
    462         BluetoothDevice extraTestDevice;
    463 
    464         doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class));
    465         doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class));
    466 
    467         // Prepare and connect all test devices
    468         for (int i = 0; i < MAX_CONNECTED_AUDIO_DEVICES; i++) {
    469             BluetoothDevice testDevice = TestUtils.getTestDevice(mAdapter, i);
    470             testDevices[i] = testDevice;
    471             mA2dpService.setPriority(testDevice, BluetoothProfile.PRIORITY_ON);
    472             // Send a connect request
    473             Assert.assertTrue("Connect failed", mA2dpService.connect(testDevice));
    474             // Verify the connection state broadcast, and that we are in Connecting state
    475             verifyConnectionStateIntent(TIMEOUT_MS, testDevice, BluetoothProfile.STATE_CONNECTING,
    476                                         BluetoothProfile.STATE_DISCONNECTED);
    477             Assert.assertEquals(BluetoothProfile.STATE_CONNECTING,
    478                                 mA2dpService.getConnectionState(testDevice));
    479             // Send a message to trigger connection completed
    480             connCompletedEvent =
    481                 new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
    482             connCompletedEvent.device = testDevice;
    483             connCompletedEvent.valueInt = A2dpStackEvent.CONNECTION_STATE_CONNECTED;
    484             mA2dpService.messageFromNative(connCompletedEvent);
    485 
    486             // Verify the connection state broadcast, and that we are in Connected state
    487             verifyConnectionStateIntent(TIMEOUT_MS, testDevice, BluetoothProfile.STATE_CONNECTED,
    488                                         BluetoothProfile.STATE_CONNECTING);
    489             Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
    490                                 mA2dpService.getConnectionState(testDevice));
    491             // Verify the list of connected devices
    492             Assert.assertTrue(mA2dpService.getConnectedDevices().contains(testDevice));
    493         }
    494 
    495         // Prepare and connect the extra test device. The connect request should fail
    496         extraTestDevice = TestUtils.getTestDevice(mAdapter, MAX_CONNECTED_AUDIO_DEVICES);
    497         mA2dpService.setPriority(extraTestDevice, BluetoothProfile.PRIORITY_ON);
    498         // Send a connect request
    499         Assert.assertFalse("Connect expected to fail", mA2dpService.connect(extraTestDevice));
    500     }
    501 
    502     /**
    503      * Test that only CONNECTION_STATE_CONNECTED or CONNECTION_STATE_CONNECTING A2DP stack events
    504      * will create a state machine.
    505      */
    506     @Test
    507     public void testCreateStateMachineStackEvents() {
    508         A2dpStackEvent stackEvent;
    509 
    510         // Update the device priority so okToConnect() returns true
    511         mA2dpService.setPriority(mTestDevice, BluetoothProfile.PRIORITY_ON);
    512         doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class));
    513         doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class));
    514 
    515         // A2DP stack event: CONNECTION_STATE_CONNECTING - state machine should be created
    516         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_CONNECTING,
    517                                             BluetoothProfile.STATE_DISCONNECTED);
    518         Assert.assertEquals(BluetoothProfile.STATE_CONNECTING,
    519                             mA2dpService.getConnectionState(mTestDevice));
    520         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    521 
    522         // A2DP stack event: CONNECTION_STATE_DISCONNECTED - state machine should be removed
    523         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_DISCONNECTED,
    524                                             BluetoothProfile.STATE_CONNECTING);
    525         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    526                             mA2dpService.getConnectionState(mTestDevice));
    527         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    528         mA2dpService.bondStateChanged(mTestDevice, BluetoothDevice.BOND_NONE);
    529         Assert.assertFalse(mA2dpService.getDevices().contains(mTestDevice));
    530 
    531         // A2DP stack event: CONNECTION_STATE_CONNECTED - state machine should be created
    532         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_CONNECTED,
    533                                             BluetoothProfile.STATE_DISCONNECTED);
    534         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
    535                             mA2dpService.getConnectionState(mTestDevice));
    536         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    537 
    538         // A2DP stack event: CONNECTION_STATE_DISCONNECTED - state machine should be removed
    539         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_DISCONNECTED,
    540                                             BluetoothProfile.STATE_CONNECTED);
    541         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    542                             mA2dpService.getConnectionState(mTestDevice));
    543         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    544         mA2dpService.bondStateChanged(mTestDevice, BluetoothDevice.BOND_NONE);
    545         Assert.assertFalse(mA2dpService.getDevices().contains(mTestDevice));
    546 
    547         // A2DP stack event: CONNECTION_STATE_DISCONNECTING - state machine should not be created
    548         generateUnexpectedConnectionMessageFromNative(mTestDevice,
    549                                                       BluetoothProfile.STATE_DISCONNECTING,
    550                                                       BluetoothProfile.STATE_DISCONNECTED);
    551         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    552                             mA2dpService.getConnectionState(mTestDevice));
    553         Assert.assertFalse(mA2dpService.getDevices().contains(mTestDevice));
    554 
    555         // A2DP stack event: CONNECTION_STATE_DISCONNECTED - state machine should not be created
    556         generateUnexpectedConnectionMessageFromNative(mTestDevice,
    557                                                       BluetoothProfile.STATE_DISCONNECTED,
    558                                                       BluetoothProfile.STATE_DISCONNECTED);
    559         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    560                             mA2dpService.getConnectionState(mTestDevice));
    561         Assert.assertFalse(mA2dpService.getDevices().contains(mTestDevice));
    562     }
    563 
    564     /**
    565      * Test that EVENT_TYPE_AUDIO_STATE_CHANGED and EVENT_TYPE_CODEC_CONFIG_CHANGED events
    566      * are processed.
    567      */
    568     @Test
    569     public void testProcessAudioStateChangedCodecConfigChangedEvents() {
    570         A2dpStackEvent stackEvent;
    571         BluetoothCodecConfig codecConfigSbc =
    572                 new BluetoothCodecConfig(
    573                         BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
    574                         BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
    575                         BluetoothCodecConfig.SAMPLE_RATE_44100,
    576                         BluetoothCodecConfig.BITS_PER_SAMPLE_16,
    577                         BluetoothCodecConfig.CHANNEL_MODE_STEREO,
    578                         0, 0, 0, 0);       // Codec-specific fields
    579         BluetoothCodecConfig codecConfig = codecConfigSbc;
    580         BluetoothCodecConfig[] codecsLocalCapabilities = new BluetoothCodecConfig[1];
    581         BluetoothCodecConfig[] codecsSelectableCapabilities = new BluetoothCodecConfig[1];
    582         codecsLocalCapabilities[0] = codecConfigSbc;
    583         codecsSelectableCapabilities[0] = codecConfigSbc;
    584         BluetoothCodecStatus codecStatus = new BluetoothCodecStatus(codecConfig,
    585                                                                     codecsLocalCapabilities,
    586                                                                     codecsSelectableCapabilities);
    587 
    588         // Update the device priority so okToConnect() returns true
    589         mA2dpService.setPriority(mTestDevice, BluetoothProfile.PRIORITY_ON);
    590         doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class));
    591         doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class));
    592 
    593         // A2DP stack event: EVENT_TYPE_AUDIO_STATE_CHANGED - state machine should not be created
    594         generateUnexpectedAudioMessageFromNative(mTestDevice, A2dpStackEvent.AUDIO_STATE_STARTED,
    595                                                  BluetoothA2dp.STATE_PLAYING,
    596                                                  BluetoothA2dp.STATE_NOT_PLAYING);
    597         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    598                             mA2dpService.getConnectionState(mTestDevice));
    599         Assert.assertFalse(mA2dpService.getDevices().contains(mTestDevice));
    600 
    601         // A2DP stack event: EVENT_TYPE_CODEC_CONFIG_CHANGED - state machine should not be created
    602         generateUnexpectedCodecMessageFromNative(mTestDevice, codecStatus);
    603         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    604                             mA2dpService.getConnectionState(mTestDevice));
    605         Assert.assertFalse(mA2dpService.getDevices().contains(mTestDevice));
    606 
    607         // A2DP stack event: CONNECTION_STATE_CONNECTED - state machine should be created
    608         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_CONNECTED,
    609                                             BluetoothProfile.STATE_DISCONNECTED);
    610         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
    611                             mA2dpService.getConnectionState(mTestDevice));
    612         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    613 
    614         // A2DP stack event: EVENT_TYPE_AUDIO_STATE_CHANGED - Intent broadcast should be generated
    615         // NOTE: The first message (STATE_PLAYING -> STATE_NOT_PLAYING) is generated internally
    616         // by the state machine when Connected, and needs to be extracted first before generating
    617         // the actual message from native.
    618         verifyAudioStateIntent(TIMEOUT_MS, mTestDevice, BluetoothA2dp.STATE_NOT_PLAYING,
    619                                BluetoothA2dp.STATE_PLAYING);
    620         generateAudioMessageFromNative(mTestDevice,
    621                                        A2dpStackEvent.AUDIO_STATE_STARTED,
    622                                        BluetoothA2dp.STATE_PLAYING,
    623                                        BluetoothA2dp.STATE_NOT_PLAYING);
    624         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
    625                             mA2dpService.getConnectionState(mTestDevice));
    626         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    627 
    628         // A2DP stack event: EVENT_TYPE_CODEC_CONFIG_CHANGED - Intent broadcast should be generated
    629         generateCodecMessageFromNative(mTestDevice, codecStatus);
    630         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
    631                             mA2dpService.getConnectionState(mTestDevice));
    632         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    633 
    634         // A2DP stack event: CONNECTION_STATE_DISCONNECTED - state machine should be removed
    635         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_DISCONNECTED,
    636                                             BluetoothProfile.STATE_CONNECTED);
    637         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    638                             mA2dpService.getConnectionState(mTestDevice));
    639         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    640         mA2dpService.bondStateChanged(mTestDevice, BluetoothDevice.BOND_NONE);
    641         Assert.assertFalse(mA2dpService.getDevices().contains(mTestDevice));
    642     }
    643 
    644     /**
    645      * Test that a state machine in DISCONNECTED state is removed only after the device is unbond.
    646      */
    647     @Test
    648     public void testDeleteStateMachineUnbondEvents() {
    649         A2dpStackEvent stackEvent;
    650 
    651         // Update the device priority so okToConnect() returns true
    652         mA2dpService.setPriority(mTestDevice, BluetoothProfile.PRIORITY_ON);
    653         doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class));
    654         doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class));
    655 
    656         // A2DP stack event: CONNECTION_STATE_CONNECTING - state machine should be created
    657         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_CONNECTING,
    658                                             BluetoothProfile.STATE_DISCONNECTED);
    659         Assert.assertEquals(BluetoothProfile.STATE_CONNECTING,
    660                             mA2dpService.getConnectionState(mTestDevice));
    661         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    662         // Device unbond - state machine is not removed
    663         mA2dpService.bondStateChanged(mTestDevice, BluetoothDevice.BOND_NONE);
    664         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    665 
    666         // A2DP stack event: CONNECTION_STATE_CONNECTED - state machine is not removed
    667         mA2dpService.bondStateChanged(mTestDevice, BluetoothDevice.BOND_BONDED);
    668         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_CONNECTED,
    669                                             BluetoothProfile.STATE_CONNECTING);
    670         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
    671                             mA2dpService.getConnectionState(mTestDevice));
    672         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    673         // Device unbond - state machine is not removed
    674         mA2dpService.bondStateChanged(mTestDevice, BluetoothDevice.BOND_NONE);
    675         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    676 
    677         // A2DP stack event: CONNECTION_STATE_DISCONNECTING - state machine is not removed
    678         mA2dpService.bondStateChanged(mTestDevice, BluetoothDevice.BOND_BONDED);
    679         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_DISCONNECTING,
    680                                             BluetoothProfile.STATE_CONNECTED);
    681         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTING,
    682                             mA2dpService.getConnectionState(mTestDevice));
    683         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    684         // Device unbond - state machine is not removed
    685         mA2dpService.bondStateChanged(mTestDevice, BluetoothDevice.BOND_NONE);
    686         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    687 
    688         // A2DP stack event: CONNECTION_STATE_DISCONNECTED - state machine is not removed
    689         mA2dpService.bondStateChanged(mTestDevice, BluetoothDevice.BOND_BONDED);
    690         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_DISCONNECTED,
    691                                             BluetoothProfile.STATE_DISCONNECTING);
    692         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    693                             mA2dpService.getConnectionState(mTestDevice));
    694         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    695         // Device unbond - state machine is removed
    696         mA2dpService.bondStateChanged(mTestDevice, BluetoothDevice.BOND_NONE);
    697         Assert.assertFalse(mA2dpService.getDevices().contains(mTestDevice));
    698     }
    699 
    700     /**
    701      * Test that a CONNECTION_STATE_DISCONNECTED A2DP stack event will remove the state machine
    702      * only if the device is unbond.
    703      */
    704     @Test
    705     public void testDeleteStateMachineDisconnectEvents() {
    706         A2dpStackEvent stackEvent;
    707 
    708         // Update the device priority so okToConnect() returns true
    709         mA2dpService.setPriority(mTestDevice, BluetoothProfile.PRIORITY_ON);
    710         doReturn(true).when(mA2dpNativeInterface).connectA2dp(any(BluetoothDevice.class));
    711         doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(any(BluetoothDevice.class));
    712 
    713         // A2DP stack event: CONNECTION_STATE_CONNECTING - state machine should be created
    714         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_CONNECTING,
    715                                             BluetoothProfile.STATE_DISCONNECTED);
    716         Assert.assertEquals(BluetoothProfile.STATE_CONNECTING,
    717                             mA2dpService.getConnectionState(mTestDevice));
    718         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    719 
    720         // A2DP stack event: CONNECTION_STATE_DISCONNECTED - state machine is not removed
    721         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_DISCONNECTED,
    722                                             BluetoothProfile.STATE_CONNECTING);
    723         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    724                             mA2dpService.getConnectionState(mTestDevice));
    725         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    726 
    727         // A2DP stack event: CONNECTION_STATE_CONNECTING - state machine remains
    728         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_CONNECTING,
    729                                             BluetoothProfile.STATE_DISCONNECTED);
    730         Assert.assertEquals(BluetoothProfile.STATE_CONNECTING,
    731                             mA2dpService.getConnectionState(mTestDevice));
    732         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    733 
    734         // Device bond state marked as unbond - state machine is not removed
    735         doReturn(BluetoothDevice.BOND_NONE).when(mAdapterService)
    736                 .getBondState(any(BluetoothDevice.class));
    737         Assert.assertTrue(mA2dpService.getDevices().contains(mTestDevice));
    738 
    739         // A2DP stack event: CONNECTION_STATE_DISCONNECTED - state machine is removed
    740         generateConnectionMessageFromNative(mTestDevice, BluetoothProfile.STATE_DISCONNECTED,
    741                                             BluetoothProfile.STATE_CONNECTING);
    742         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
    743                             mA2dpService.getConnectionState(mTestDevice));
    744         Assert.assertFalse(mA2dpService.getDevices().contains(mTestDevice));
    745     }
    746 
    747     private void connectDevice(BluetoothDevice device) {
    748         A2dpStackEvent connCompletedEvent;
    749 
    750         List<BluetoothDevice> prevConnectedDevices = mA2dpService.getConnectedDevices();
    751 
    752         // Update the device priority so okToConnect() returns true
    753         mA2dpService.setPriority(device, BluetoothProfile.PRIORITY_ON);
    754         doReturn(true).when(mA2dpNativeInterface).connectA2dp(device);
    755         doReturn(true).when(mA2dpNativeInterface).disconnectA2dp(device);
    756 
    757         // Send a connect request
    758         Assert.assertTrue("Connect failed", mA2dpService.connect(device));
    759 
    760         // Verify the connection state broadcast, and that we are in Connecting state
    761         verifyConnectionStateIntent(TIMEOUT_MS, device, BluetoothProfile.STATE_CONNECTING,
    762                                     BluetoothProfile.STATE_DISCONNECTED);
    763         Assert.assertEquals(BluetoothProfile.STATE_CONNECTING,
    764                             mA2dpService.getConnectionState(device));
    765 
    766         // Send a message to trigger connection completed
    767         connCompletedEvent = new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
    768         connCompletedEvent.device = device;
    769         connCompletedEvent.valueInt = A2dpStackEvent.CONNECTION_STATE_CONNECTED;
    770         mA2dpService.messageFromNative(connCompletedEvent);
    771 
    772         // Verify the connection state broadcast, and that we are in Connected state
    773         verifyConnectionStateIntent(TIMEOUT_MS, device, BluetoothProfile.STATE_CONNECTED,
    774                                     BluetoothProfile.STATE_CONNECTING);
    775         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
    776                             mA2dpService.getConnectionState(device));
    777 
    778         // Verify that the device is in the list of connected devices
    779         Assert.assertTrue(mA2dpService.getConnectedDevices().contains(device));
    780         // Verify the list of previously connected devices
    781         for (BluetoothDevice prevDevice : prevConnectedDevices) {
    782             Assert.assertTrue(mA2dpService.getConnectedDevices().contains(prevDevice));
    783         }
    784     }
    785 
    786     private void generateConnectionMessageFromNative(BluetoothDevice device, int newConnectionState,
    787                                                      int oldConnectionState) {
    788         A2dpStackEvent stackEvent =
    789                 new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
    790         stackEvent.device = device;
    791         stackEvent.valueInt = newConnectionState;
    792         mA2dpService.messageFromNative(stackEvent);
    793         // Verify the connection state broadcast
    794         verifyConnectionStateIntent(TIMEOUT_MS, device, newConnectionState, oldConnectionState);
    795     }
    796 
    797     private void generateUnexpectedConnectionMessageFromNative(BluetoothDevice device,
    798                                                                int newConnectionState,
    799                                                                int oldConnectionState) {
    800         A2dpStackEvent stackEvent =
    801                 new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
    802         stackEvent.device = device;
    803         stackEvent.valueInt = newConnectionState;
    804         mA2dpService.messageFromNative(stackEvent);
    805         // Verify the connection state broadcast
    806         verifyNoConnectionStateIntent(TIMEOUT_MS);
    807     }
    808 
    809     private void generateAudioMessageFromNative(BluetoothDevice device, int audioStackEvent,
    810                                                 int newAudioState, int oldAudioState) {
    811         A2dpStackEvent stackEvent =
    812                 new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
    813         stackEvent.device = device;
    814         stackEvent.valueInt = audioStackEvent;
    815         mA2dpService.messageFromNative(stackEvent);
    816         // Verify the audio state broadcast
    817         verifyAudioStateIntent(TIMEOUT_MS, device, newAudioState, oldAudioState);
    818     }
    819 
    820     private void generateUnexpectedAudioMessageFromNative(BluetoothDevice device,
    821                                                           int audioStackEvent, int newAudioState,
    822                                                           int oldAudioState) {
    823         A2dpStackEvent stackEvent =
    824                 new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED);
    825         stackEvent.device = device;
    826         stackEvent.valueInt = audioStackEvent;
    827         mA2dpService.messageFromNative(stackEvent);
    828         // Verify the audio state broadcast
    829         verifyNoAudioStateIntent(TIMEOUT_MS);
    830     }
    831 
    832     private void generateCodecMessageFromNative(BluetoothDevice device,
    833                                                 BluetoothCodecStatus codecStatus) {
    834         A2dpStackEvent stackEvent =
    835                 new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CODEC_CONFIG_CHANGED);
    836         stackEvent.device = device;
    837         stackEvent.codecStatus = codecStatus;
    838         mA2dpService.messageFromNative(stackEvent);
    839         // Verify the codec status broadcast
    840         verifyCodecConfigIntent(TIMEOUT_MS, device, codecStatus);
    841     }
    842 
    843     private void generateUnexpectedCodecMessageFromNative(BluetoothDevice device,
    844                                                           BluetoothCodecStatus codecStatus) {
    845         A2dpStackEvent stackEvent =
    846                 new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CODEC_CONFIG_CHANGED);
    847         stackEvent.device = device;
    848         stackEvent.codecStatus = codecStatus;
    849         mA2dpService.messageFromNative(stackEvent);
    850         // Verify the codec status broadcast
    851         verifyNoCodecConfigIntent(TIMEOUT_MS);
    852     }
    853 
    854     /**
    855      * Helper function to test okToConnect() method.
    856      *
    857      * @param device test device
    858      * @param bondState bond state value, could be invalid
    859      * @param priority value, could be invalid, coudl be invalid
    860      * @param expected expected result from okToConnect()
    861      */
    862     private void testOkToConnectCase(BluetoothDevice device, int bondState, int priority,
    863             boolean expected) {
    864         doReturn(bondState).when(mAdapterService).getBondState(device);
    865         Assert.assertTrue(mA2dpService.setPriority(device, priority));
    866 
    867         // Test when the AdapterService is in non-quiet mode: the result should not depend
    868         // on whether the connection request is outgoing or incoming.
    869         doReturn(false).when(mAdapterService).isQuietModeEnabled();
    870         Assert.assertEquals(expected, mA2dpService.okToConnect(device, true));  // Outgoing
    871         Assert.assertEquals(expected, mA2dpService.okToConnect(device, false)); // Incoming
    872 
    873         // Test when the AdapterService is in quiet mode: the result should always be
    874         // false when the connection request is incoming.
    875         doReturn(true).when(mAdapterService).isQuietModeEnabled();
    876         Assert.assertEquals(expected, mA2dpService.okToConnect(device, true));  // Outgoing
    877         Assert.assertEquals(false, mA2dpService.okToConnect(device, false)); // Incoming
    878     }
    879 }
    880