• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.bluetooth.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
setUp()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
tearDown()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 
startService()133     private void startService() throws TimeoutException {
134         TestUtils.startService(mServiceRule, A2dpService.class);
135         mA2dpService = A2dpService.getA2dpService();
136         Assert.assertNotNull(mA2dpService);
137     }
138 
stopService()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
onReceive(Context context, Intent intent)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 
verifyConnectionStateIntent(int timeoutMs, BluetoothDevice device, int newState, int prevState)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 
verifyNoConnectionStateIntent(int timeoutMs)185     private void verifyNoConnectionStateIntent(int timeoutMs) {
186         Intent intent = TestUtils.waitForNoIntent(timeoutMs, mConnectionStateChangedQueue);
187         Assert.assertNull(intent);
188     }
189 
verifyAudioStateIntent(int timeoutMs, BluetoothDevice device, int newState, int prevState)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 
verifyNoAudioStateIntent(int timeoutMs)201     private void verifyNoAudioStateIntent(int timeoutMs) {
202         Intent intent = TestUtils.waitForNoIntent(timeoutMs, mAudioStateChangedQueue);
203         Assert.assertNull(intent);
204     }
205 
verifyCodecConfigIntent(int timeoutMs, BluetoothDevice device, BluetoothCodecStatus codecStatus)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 
verifyNoCodecConfigIntent(int timeoutMs)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
testGetA2dpService()225     public void testGetA2dpService() {
226         Assert.assertEquals(mA2dpService, A2dpService.getA2dpService());
227     }
228 
229     /**
230      * Test stop A2DP Service
231      */
232     @Test
testStopA2dpService()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
testGetSetPriority()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
testOkToConnect()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, false);
300         testOkToConnectCase(mTestDevice,
301                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_OFF, false);
302         testOkToConnectCase(mTestDevice,
303                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_ON, false);
304         testOkToConnectCase(mTestDevice,
305                 BluetoothDevice.BOND_BONDING, BluetoothProfile.PRIORITY_AUTO_CONNECT, false);
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
testOutgoingConnectMissingAudioSinkUuid()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
testOutgoingConnectPriorityOff()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
testOutgoingConnectTimeout()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
testOutgoingConnectDisconnectSuccess()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
testMaxConnectDevices()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
testCreateStateMachineStackEvents()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
testProcessAudioStateChangedCodecConfigChangedEvents()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
testDeleteStateMachineUnbondEvents()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
testDeleteStateMachineDisconnectEvents()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 
connectDevice(BluetoothDevice device)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 
generateConnectionMessageFromNative(BluetoothDevice device, int newConnectionState, int oldConnectionState)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 
generateUnexpectedConnectionMessageFromNative(BluetoothDevice device, int newConnectionState, int oldConnectionState)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 
generateAudioMessageFromNative(BluetoothDevice device, int audioStackEvent, int newAudioState, int oldAudioState)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 
generateUnexpectedAudioMessageFromNative(BluetoothDevice device, int audioStackEvent, int newAudioState, int oldAudioState)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 
generateCodecMessageFromNative(BluetoothDevice device, BluetoothCodecStatus codecStatus)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 
generateUnexpectedCodecMessageFromNative(BluetoothDevice device, BluetoothCodecStatus codecStatus)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      */
testOkToConnectCase(BluetoothDevice device, int bondState, int priority, boolean expected)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