• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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.hfp;
18 
19 import static org.mockito.Mockito.*;
20 
21 import android.bluetooth.BluetoothAdapter;
22 import android.bluetooth.BluetoothDevice;
23 import android.bluetooth.BluetoothHeadset;
24 import android.bluetooth.BluetoothProfile;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.ServiceConnection;
28 import android.database.Cursor;
29 import android.media.AudioManager;
30 import android.net.Uri;
31 import android.os.HandlerThread;
32 import android.os.UserHandle;
33 import android.provider.CallLog;
34 import android.support.test.InstrumentationRegistry;
35 import android.support.test.filters.MediumTest;
36 import android.support.test.runner.AndroidJUnit4;
37 import android.telephony.PhoneStateListener;
38 import android.test.mock.MockContentProvider;
39 import android.test.mock.MockContentResolver;
40 
41 import com.android.bluetooth.R;
42 import com.android.bluetooth.TestUtils;
43 import com.android.bluetooth.btservice.AdapterService;
44 
45 import org.hamcrest.core.IsInstanceOf;
46 import org.junit.After;
47 import org.junit.Assert;
48 import org.junit.Assume;
49 import org.junit.Before;
50 import org.junit.Test;
51 import org.junit.runner.RunWith;
52 import org.mockito.ArgumentCaptor;
53 import org.mockito.Mock;
54 import org.mockito.MockitoAnnotations;
55 
56 /**
57  * Tests for {@link HeadsetStateMachine}
58  */
59 @MediumTest
60 @RunWith(AndroidJUnit4.class)
61 public class HeadsetStateMachineTest {
62     private static final int CONNECT_TIMEOUT_TEST_MILLIS = 1000;
63     private static final int CONNECT_TIMEOUT_TEST_WAIT_MILLIS = CONNECT_TIMEOUT_TEST_MILLIS * 3 / 2;
64     private static final int ASYNC_CALL_TIMEOUT_MILLIS = 250;
65     private static final String TEST_PHONE_NUMBER = "1234567890";
66     private Context mTargetContext;
67     private BluetoothAdapter mAdapter;
68     private HandlerThread mHandlerThread;
69     private HeadsetStateMachine mHeadsetStateMachine;
70     private BluetoothDevice mTestDevice;
71     private ArgumentCaptor<Intent> mIntentArgument = ArgumentCaptor.forClass(Intent.class);
72 
73     @Mock private AdapterService mAdapterService;
74     @Mock private HeadsetService mHeadsetService;
75     @Mock private HeadsetSystemInterface mSystemInterface;
76     @Mock private AudioManager mAudioManager;
77     @Mock private HeadsetPhoneState mPhoneState;
78     private MockContentResolver mMockContentResolver;
79     private HeadsetNativeInterface mNativeInterface;
80 
81     @Before
setUp()82     public void setUp() throws Exception {
83         mTargetContext = InstrumentationRegistry.getTargetContext();
84         Assume.assumeTrue("Ignore test when HeadsetService is not enabled",
85                 mTargetContext.getResources().getBoolean(R.bool.profile_supported_hs_hfp));
86         // Setup mocks and test assets
87         MockitoAnnotations.initMocks(this);
88         TestUtils.setAdapterService(mAdapterService);
89         // Stub system interface
90         when(mSystemInterface.getHeadsetPhoneState()).thenReturn(mPhoneState);
91         when(mSystemInterface.getAudioManager()).thenReturn(mAudioManager);
92         // This line must be called to make sure relevant objects are initialized properly
93         mAdapter = BluetoothAdapter.getDefaultAdapter();
94         // Get a device for testing
95         mTestDevice = mAdapter.getRemoteDevice("00:01:02:03:04:05");
96         // Spy on native interface
97         mNativeInterface = spy(HeadsetNativeInterface.getInstance());
98         doNothing().when(mNativeInterface).init(anyInt(), anyBoolean());
99         doReturn(true).when(mNativeInterface).connectHfp(mTestDevice);
100         doReturn(true).when(mNativeInterface).disconnectHfp(mTestDevice);
101         doReturn(true).when(mNativeInterface).connectAudio(mTestDevice);
102         doReturn(true).when(mNativeInterface).disconnectAudio(mTestDevice);
103         // Stub headset service
104         mMockContentResolver = new MockContentResolver();
105         when(mHeadsetService.getContentResolver()).thenReturn(mMockContentResolver);
106         doReturn(BluetoothDevice.BOND_BONDED).when(mAdapterService)
107                 .getBondState(any(BluetoothDevice.class));
108         when(mHeadsetService.bindService(any(Intent.class), any(ServiceConnection.class), anyInt()))
109                 .thenReturn(true);
110         when(mHeadsetService.getResources()).thenReturn(
111                 InstrumentationRegistry.getTargetContext().getResources());
112         when(mHeadsetService.getPackageManager()).thenReturn(
113                 InstrumentationRegistry.getContext().getPackageManager());
114         when(mHeadsetService.getPriority(any(BluetoothDevice.class))).thenReturn(
115                 BluetoothProfile.PRIORITY_ON);
116         when(mHeadsetService.getForceScoAudio()).thenReturn(true);
117         when(mHeadsetService.okToAcceptConnection(any(BluetoothDevice.class))).thenReturn(true);
118         when(mHeadsetService.isScoAcceptable(any(BluetoothDevice.class))).thenReturn(true);
119         // Setup thread and looper
120         mHandlerThread = new HandlerThread("HeadsetStateMachineTestHandlerThread");
121         mHandlerThread.start();
122         // Modify CONNECT timeout to a smaller value for test only
123         HeadsetStateMachine.sConnectTimeoutMs = CONNECT_TIMEOUT_TEST_MILLIS;
124         mHeadsetStateMachine = HeadsetObjectsFactory.getInstance()
125                 .makeStateMachine(mTestDevice, mHandlerThread.getLooper(), mHeadsetService,
126                         mAdapterService, mNativeInterface, mSystemInterface);
127     }
128 
129     @After
tearDown()130     public void tearDown() throws Exception {
131         if (!mTargetContext.getResources().getBoolean(R.bool.profile_supported_hs_hfp)) {
132             return;
133         }
134         HeadsetObjectsFactory.getInstance().destroyStateMachine(mHeadsetStateMachine);
135         mHandlerThread.quit();
136         TestUtils.clearAdapterService(mAdapterService);
137     }
138 
139     /**
140      * Test that default state is Disconnected
141      */
142     @Test
testDefaultDisconnectedState()143     public void testDefaultDisconnectedState() {
144         Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED,
145                 mHeadsetStateMachine.getConnectionState());
146         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
147                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnected.class));
148     }
149 
150     /**
151      * Test that state is Connected after calling setUpConnectedState()
152      */
153     @Test
testSetupConnectedState()154     public void testSetupConnectedState() {
155         setUpConnectedState();
156         Assert.assertEquals(BluetoothProfile.STATE_CONNECTED,
157                 mHeadsetStateMachine.getConnectionState());
158         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
159                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connected.class));
160     }
161 
162     /**
163      * Test state transition from Disconnected to Connecting state via CONNECT message
164      */
165     @Test
testStateTransition_DisconnectedToConnecting_Connect()166     public void testStateTransition_DisconnectedToConnecting_Connect() {
167         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.CONNECT, mTestDevice);
168         verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBroadcastAsUser(
169                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
170         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
171                 BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED,
172                 mIntentArgument.getValue());
173         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
174                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connecting.class));
175     }
176 
177     /**
178      * Test state transition from Disconnected to Connecting state via StackEvent.CONNECTED message
179      */
180     @Test
testStateTransition_DisconnectedToConnecting_StackConnected()181     public void testStateTransition_DisconnectedToConnecting_StackConnected() {
182         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
183                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
184                         HeadsetHalConstants.CONNECTION_STATE_CONNECTED, mTestDevice));
185         verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBroadcastAsUser(
186                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
187         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
188                 BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED,
189                 mIntentArgument.getValue());
190         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
191                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connecting.class));
192     }
193 
194     /**
195      * Test state transition from Disconnected to Connecting state via StackEvent.CONNECTING message
196      */
197     @Test
testStateTransition_DisconnectedToConnecting_StackConnecting()198     public void testStateTransition_DisconnectedToConnecting_StackConnecting() {
199         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
200                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
201                         HeadsetHalConstants.CONNECTION_STATE_CONNECTING, mTestDevice));
202         verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBroadcastAsUser(
203                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
204         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
205                 BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED,
206                 mIntentArgument.getValue());
207         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
208                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connecting.class));
209     }
210 
211     /**
212      * Test state transition from Connecting to Disconnected state via StackEvent.DISCONNECTED
213      * message
214      */
215     @Test
testStateTransition_ConnectingToDisconnected_StackDisconnected()216     public void testStateTransition_ConnectingToDisconnected_StackDisconnected() {
217         int numBroadcastsSent = setUpConnectingState();
218         // Indicate disconnecting to test state machine, which should do nothing
219         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
220                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
221                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTING, mTestDevice));
222         // Should do nothing new
223         verify(mHeadsetService,
224                 after(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
225                 any(Intent.class), any(UserHandle.class), anyString());
226         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
227                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connecting.class));
228 
229         // Indicate connection failed to test state machine
230         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
231                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
232                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED, mTestDevice));
233 
234         numBroadcastsSent++;
235         verify(mHeadsetService,
236                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
237                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
238         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
239                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING,
240                 mIntentArgument.getValue());
241         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
242                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnected.class));
243     }
244 
245     /**
246      * Test state transition from Connecting to Disconnected state via CONNECT_TIMEOUT message
247      */
248     @Test
testStateTransition_ConnectingToDisconnected_Timeout()249     public void testStateTransition_ConnectingToDisconnected_Timeout() {
250         int numBroadcastsSent = setUpConnectingState();
251         // Let the connection timeout
252         numBroadcastsSent++;
253         verify(mHeadsetService, timeout(CONNECT_TIMEOUT_TEST_WAIT_MILLIS).times(
254                 numBroadcastsSent)).sendBroadcastAsUser(mIntentArgument.capture(),
255                 eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
256         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
257                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING,
258                 mIntentArgument.getValue());
259         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
260                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnected.class));
261     }
262 
263     /**
264      * Test state transition from Connecting to Connected state via StackEvent.SLC_CONNECTED message
265      */
266     @Test
testStateTransition_ConnectingToConnected_StackSlcConnected()267     public void testStateTransition_ConnectingToConnected_StackSlcConnected() {
268         int numBroadcastsSent = setUpConnectingState();
269         // Indicate connecting to test state machine
270         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
271                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
272                         HeadsetHalConstants.CONNECTION_STATE_CONNECTING, mTestDevice));
273         // Should do nothing
274         verify(mHeadsetService,
275                 after(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
276                 any(Intent.class), any(UserHandle.class), anyString());
277         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
278                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connecting.class));
279 
280         // Indicate RFCOMM connection is successful to test state machine
281         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
282                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
283                         HeadsetHalConstants.CONNECTION_STATE_CONNECTED, mTestDevice));
284         // Should do nothing
285         verify(mHeadsetService,
286                 after(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
287                 any(Intent.class), any(UserHandle.class), anyString());
288         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
289                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connecting.class));
290 
291         // Indicate SLC connection is successful to test state machine
292         numBroadcastsSent++;
293         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
294                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
295                         HeadsetHalConstants.CONNECTION_STATE_SLC_CONNECTED, mTestDevice));
296         verify(mHeadsetService,
297                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
298                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
299         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
300                 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING,
301                 mIntentArgument.getValue());
302         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
303                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connected.class));
304     }
305 
306     /**
307      * Test state transition from Disconnecting to Disconnected state via StackEvent.DISCONNECTED
308      * message
309      */
310     @Test
testStateTransition_DisconnectingToDisconnected_StackDisconnected()311     public void testStateTransition_DisconnectingToDisconnected_StackDisconnected() {
312         int numBroadcastsSent = setUpDisconnectingState();
313         // Send StackEvent.DISCONNECTED message
314         numBroadcastsSent++;
315         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
316                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
317                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED, mTestDevice));
318         verify(mHeadsetService,
319                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
320                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
321         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
322                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_DISCONNECTING,
323                 mIntentArgument.getValue());
324         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
325                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnected.class));
326     }
327 
328     /**
329      * Test state transition from Disconnecting to Disconnected state via CONNECT_TIMEOUT
330      * message
331      */
332     @Test
testStateTransition_DisconnectingToDisconnected_Timeout()333     public void testStateTransition_DisconnectingToDisconnected_Timeout() {
334         int numBroadcastsSent = setUpDisconnectingState();
335         // Let the connection timeout
336         numBroadcastsSent++;
337         verify(mHeadsetService, timeout(CONNECT_TIMEOUT_TEST_WAIT_MILLIS).times(
338                 numBroadcastsSent)).sendBroadcastAsUser(mIntentArgument.capture(),
339                 eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
340         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
341                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_DISCONNECTING,
342                 mIntentArgument.getValue());
343         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
344                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnected.class));
345     }
346 
347     /**
348      * Test state transition from Disconnecting to Connected state via StackEvent.SLC_CONNECTED
349      * message
350      */
351     @Test
testStateTransition_DisconnectingToConnected_StackSlcCconnected()352     public void testStateTransition_DisconnectingToConnected_StackSlcCconnected() {
353         int numBroadcastsSent = setUpDisconnectingState();
354         // Send StackEvent.SLC_CONNECTED message
355         numBroadcastsSent++;
356         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
357                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
358                         HeadsetHalConstants.CONNECTION_STATE_SLC_CONNECTED, mTestDevice));
359         verify(mHeadsetService,
360                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
361                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
362         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
363                 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTING,
364                 mIntentArgument.getValue());
365         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
366                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connected.class));
367     }
368 
369     /**
370      * Test state transition from Connected to Disconnecting state via DISCONNECT message
371      */
372     @Test
testStateTransition_ConnectedToDisconnecting_Disconnect()373     public void testStateTransition_ConnectedToDisconnecting_Disconnect() {
374         int numBroadcastsSent = setUpConnectedState();
375         // Send DISCONNECT message
376         numBroadcastsSent++;
377         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.DISCONNECT, mTestDevice);
378         verify(mHeadsetService,
379                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
380                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
381         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
382                 BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_CONNECTED,
383                 mIntentArgument.getValue());
384         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
385                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnecting.class));
386     }
387 
388     /**
389      * Test state transition from Connected to Disconnecting state via StackEvent.DISCONNECTING
390      * message
391      */
392     @Test
testStateTransition_ConnectedToDisconnecting_StackDisconnecting()393     public void testStateTransition_ConnectedToDisconnecting_StackDisconnecting() {
394         int numBroadcastsSent = setUpConnectedState();
395         // Send StackEvent.DISCONNECTING message
396         numBroadcastsSent++;
397         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
398                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
399                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTING, mTestDevice));
400         verify(mHeadsetService,
401                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
402                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
403         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
404                 BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_CONNECTED,
405                 mIntentArgument.getValue());
406         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
407                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnecting.class));
408     }
409 
410     /**
411      * Test state transition from Connected to Disconnected state via StackEvent.DISCONNECTED
412      * message
413      */
414     @Test
testStateTransition_ConnectedToDisconnected_StackDisconnected()415     public void testStateTransition_ConnectedToDisconnected_StackDisconnected() {
416         int numBroadcastsSent = setUpConnectedState();
417         // Send StackEvent.DISCONNECTED message
418         numBroadcastsSent++;
419         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
420                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
421                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED, mTestDevice));
422         verify(mHeadsetService,
423                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
424                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
425         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
426                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED,
427                 mIntentArgument.getValue());
428         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
429                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnected.class));
430     }
431 
432     /**
433      * Test state transition from Connected to AudioConnecting state via CONNECT_AUDIO message
434      */
435     @Test
testStateTransition_ConnectedToAudioConnecting_ConnectAudio()436     public void testStateTransition_ConnectedToAudioConnecting_ConnectAudio() {
437         int numBroadcastsSent = setUpConnectedState();
438         // Send CONNECT_AUDIO message
439         numBroadcastsSent++;
440         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.CONNECT_AUDIO, mTestDevice);
441         verify(mHeadsetService,
442                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
443                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
444         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
445                 BluetoothHeadset.STATE_AUDIO_CONNECTING, BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
446                 mIntentArgument.getValue());
447         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
448                 IsInstanceOf.instanceOf(HeadsetStateMachine.AudioConnecting.class));
449     }
450 
451     /**
452      * Test state transition from Connected to AudioConnecting state via
453      * StackEvent.AUDIO_CONNECTING message
454      */
455     @Test
testStateTransition_ConnectedToAudioConnecting_StackAudioConnecting()456     public void testStateTransition_ConnectedToAudioConnecting_StackAudioConnecting() {
457         int numBroadcastsSent = setUpConnectedState();
458         // Send StackEvent.AUDIO_CONNECTING message
459         numBroadcastsSent++;
460         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
461                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED,
462                         HeadsetHalConstants.AUDIO_STATE_CONNECTING, mTestDevice));
463         verify(mHeadsetService,
464                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
465                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
466         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
467                 BluetoothHeadset.STATE_AUDIO_CONNECTING, BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
468                 mIntentArgument.getValue());
469         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
470                 IsInstanceOf.instanceOf(HeadsetStateMachine.AudioConnecting.class));
471     }
472 
473     /**
474      * Test state transition from Connected to AudioOn state via StackEvent.AUDIO_CONNECTED message
475      */
476     @Test
testStateTransition_ConnectedToAudioOn_StackAudioConnected()477     public void testStateTransition_ConnectedToAudioOn_StackAudioConnected() {
478         int numBroadcastsSent = setUpConnectedState();
479         // Send StackEvent.AUDIO_CONNECTED message
480         numBroadcastsSent++;
481         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
482                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED,
483                         HeadsetHalConstants.AUDIO_STATE_CONNECTED, mTestDevice));
484         verify(mHeadsetService,
485                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
486                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
487         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
488                 BluetoothHeadset.STATE_AUDIO_CONNECTED, BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
489                 mIntentArgument.getValue());
490         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
491                 IsInstanceOf.instanceOf(HeadsetStateMachine.AudioOn.class));
492     }
493 
494     /**
495      * Test state transition from AudioConnecting to Connected state via CONNECT_TIMEOUT message
496      */
497     @Test
testStateTransition_AudioConnectingToConnected_Timeout()498     public void testStateTransition_AudioConnectingToConnected_Timeout() {
499         int numBroadcastsSent = setUpAudioConnectingState();
500         // Wait for connection to timeout
501         numBroadcastsSent++;
502         verify(mHeadsetService, timeout(CONNECT_TIMEOUT_TEST_WAIT_MILLIS).times(
503                 numBroadcastsSent)).sendBroadcastAsUser(mIntentArgument.capture(),
504                 eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
505         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
506                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTING,
507                 mIntentArgument.getValue());
508         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
509                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connected.class));
510     }
511 
512     /**
513      * Test state transition from AudioConnecting to Connected state via
514      * StackEvent.AUDIO_DISCONNECTED message
515      */
516     @Test
testStateTransition_AudioConnectingToConnected_StackAudioDisconnected()517     public void testStateTransition_AudioConnectingToConnected_StackAudioDisconnected() {
518         int numBroadcastsSent = setUpAudioConnectingState();
519         // Send StackEvent.AUDIO_DISCONNECTED message
520         numBroadcastsSent++;
521         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
522                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED,
523                         HeadsetHalConstants.AUDIO_STATE_DISCONNECTED, mTestDevice));
524         verify(mHeadsetService,
525                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
526                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
527         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
528                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTING,
529                 mIntentArgument.getValue());
530         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
531                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connected.class));
532     }
533 
534     /**
535      * Test state transition from AudioConnecting to Disconnected state via
536      * StackEvent.DISCONNECTED message
537      */
538     @Test
testStateTransition_AudioConnectingToDisconnected_StackDisconnected()539     public void testStateTransition_AudioConnectingToDisconnected_StackDisconnected() {
540         int numBroadcastsSent = setUpAudioConnectingState();
541         // Send StackEvent.DISCONNECTED message
542         numBroadcastsSent += 2;
543         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
544                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
545                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED, mTestDevice));
546         verify(mHeadsetService,
547                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
548                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
549         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
550                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTING,
551                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 2));
552         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
553                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED,
554                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 1));
555         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
556                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnected.class));
557     }
558 
559     /**
560      * Test state transition from AudioConnecting to Disconnecting state via
561      * StackEvent.DISCONNECTING message
562      */
563     @Test
testStateTransition_AudioConnectingToDisconnecting_StackDisconnecting()564     public void testStateTransition_AudioConnectingToDisconnecting_StackDisconnecting() {
565         int numBroadcastsSent = setUpAudioConnectingState();
566         // Send StackEvent.DISCONNECTED message
567         numBroadcastsSent += 2;
568         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
569                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
570                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTING, mTestDevice));
571         verify(mHeadsetService,
572                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
573                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
574         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
575                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTING,
576                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 2));
577         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
578                 BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_CONNECTED,
579                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 1));
580         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
581                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnecting.class));
582     }
583 
584     /**
585      * Test state transition from AudioConnecting to AudioOn state via
586      * StackEvent.AUDIO_CONNECTED message
587      */
588     @Test
testStateTransition_AudioConnectingToAudioOn_StackAudioConnected()589     public void testStateTransition_AudioConnectingToAudioOn_StackAudioConnected() {
590         int numBroadcastsSent = setUpAudioConnectingState();
591         // Send StackEvent.AUDIO_DISCONNECTED message
592         numBroadcastsSent++;
593         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
594                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED,
595                         HeadsetHalConstants.AUDIO_STATE_CONNECTED, mTestDevice));
596         verify(mHeadsetService,
597                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
598                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
599         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
600                 BluetoothHeadset.STATE_AUDIO_CONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTING,
601                 mIntentArgument.getValue());
602         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
603                 IsInstanceOf.instanceOf(HeadsetStateMachine.AudioOn.class));
604     }
605 
606     /**
607      * Test state transition from AudioOn to AudioDisconnecting state via
608      * StackEvent.AUDIO_DISCONNECTING message
609      */
610     @Test
testStateTransition_AudioOnToAudioDisconnecting_StackAudioDisconnecting()611     public void testStateTransition_AudioOnToAudioDisconnecting_StackAudioDisconnecting() {
612         int numBroadcastsSent = setUpAudioOnState();
613         // Send StackEvent.AUDIO_DISCONNECTING message
614         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
615                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED,
616                         HeadsetHalConstants.AUDIO_STATE_DISCONNECTING, mTestDevice));
617         verify(mHeadsetService,
618                 after(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
619                 any(Intent.class), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
620         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
621                 IsInstanceOf.instanceOf(HeadsetStateMachine.AudioDisconnecting.class));
622     }
623 
624     /**
625      * Test state transition from AudioOn to AudioDisconnecting state via
626      * DISCONNECT_AUDIO message
627      */
628     @Test
testStateTransition_AudioOnToAudioDisconnecting_DisconnectAudio()629     public void testStateTransition_AudioOnToAudioDisconnecting_DisconnectAudio() {
630         int numBroadcastsSent = setUpAudioOnState();
631         // Send DISCONNECT_AUDIO message
632         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.DISCONNECT_AUDIO, mTestDevice);
633         // Should not sent any broadcast due to lack of AUDIO_DISCONNECTING intent value
634         verify(mHeadsetService,
635                 after(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
636                 any(Intent.class), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
637         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
638                 IsInstanceOf.instanceOf(HeadsetStateMachine.AudioDisconnecting.class));
639     }
640 
641     /**
642      * Test state transition from AudioOn to AudioDisconnecting state via
643      * Stack.AUDIO_DISCONNECTED message
644      */
645     @Test
testStateTransition_AudioOnToConnected_StackAudioDisconnected()646     public void testStateTransition_AudioOnToConnected_StackAudioDisconnected() {
647         int numBroadcastsSent = setUpAudioOnState();
648         // Send DISCONNECT_AUDIO message
649         numBroadcastsSent++;
650         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
651                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED,
652                         HeadsetHalConstants.AUDIO_STATE_DISCONNECTED, mTestDevice));
653         verify(mHeadsetService,
654                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
655                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
656         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
657                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTED,
658                 mIntentArgument.getValue());
659         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
660                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connected.class));
661     }
662 
663     /**
664      * Test state transition from AudioOn to Disconnected state via
665      * Stack.DISCONNECTED message
666      */
667     @Test
testStateTransition_AudioOnToDisconnected_StackDisconnected()668     public void testStateTransition_AudioOnToDisconnected_StackDisconnected() {
669         int numBroadcastsSent = setUpAudioOnState();
670         // Send StackEvent.DISCONNECTED message
671         numBroadcastsSent += 2;
672         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
673                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
674                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED, mTestDevice));
675         verify(mHeadsetService,
676                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
677                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
678         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
679                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTED,
680                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 2));
681         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
682                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED,
683                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 1));
684         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
685                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnected.class));
686     }
687 
688     /**
689      * Test state transition from AudioOn to Disconnecting state via
690      * Stack.DISCONNECTING message
691      */
692     @Test
testStateTransition_AudioOnToDisconnecting_StackDisconnecting()693     public void testStateTransition_AudioOnToDisconnecting_StackDisconnecting() {
694         int numBroadcastsSent = setUpAudioOnState();
695         // Send StackEvent.DISCONNECTING message
696         numBroadcastsSent += 2;
697         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
698                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
699                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTING, mTestDevice));
700         verify(mHeadsetService,
701                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
702                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
703         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
704                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTED,
705                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 2));
706         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
707                 BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_CONNECTED,
708                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 1));
709         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
710                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnecting.class));
711     }
712 
713     /**
714      * Test state transition from AudioDisconnecting to Connected state via
715      * CONNECT_TIMEOUT message
716      */
717     @Test
testStateTransition_AudioDisconnectingToConnected_Timeout()718     public void testStateTransition_AudioDisconnectingToConnected_Timeout() {
719         int numBroadcastsSent = setUpAudioDisconnectingState();
720         // Wait for connection to timeout
721         numBroadcastsSent++;
722         verify(mHeadsetService, timeout(CONNECT_TIMEOUT_TEST_WAIT_MILLIS).times(
723                 numBroadcastsSent)).sendBroadcastAsUser(mIntentArgument.capture(),
724                 eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
725         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
726                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTED,
727                 mIntentArgument.getValue());
728         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
729                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connected.class));
730     }
731 
732     /**
733      * Test state transition from AudioDisconnecting to Connected state via
734      * Stack.AUDIO_DISCONNECTED message
735      */
736     @Test
testStateTransition_AudioDisconnectingToConnected_StackAudioDisconnected()737     public void testStateTransition_AudioDisconnectingToConnected_StackAudioDisconnected() {
738         int numBroadcastsSent = setUpAudioDisconnectingState();
739         // Send Stack.AUDIO_DISCONNECTED message
740         numBroadcastsSent++;
741         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
742                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED,
743                         HeadsetHalConstants.AUDIO_STATE_DISCONNECTED, mTestDevice));
744         verify(mHeadsetService,
745                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
746                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
747         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
748                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTED,
749                 mIntentArgument.getValue());
750         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
751                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connected.class));
752     }
753 
754     /**
755      * Test state transition from AudioDisconnecting to AudioOn state via
756      * Stack.AUDIO_CONNECTED message
757      */
758     @Test
testStateTransition_AudioDisconnectingToAudioOn_StackAudioConnected()759     public void testStateTransition_AudioDisconnectingToAudioOn_StackAudioConnected() {
760         int numBroadcastsSent = setUpAudioDisconnectingState();
761         // Send Stack.AUDIO_CONNECTED message
762         numBroadcastsSent++;
763         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
764                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED,
765                         HeadsetHalConstants.AUDIO_STATE_CONNECTED, mTestDevice));
766         verify(mHeadsetService,
767                 after(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
768                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
769         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
770                 BluetoothHeadset.STATE_AUDIO_CONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTED,
771                 mIntentArgument.getValue());
772         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
773                 IsInstanceOf.instanceOf(HeadsetStateMachine.AudioOn.class));
774     }
775 
776     /**
777      * Test state transition from AudioDisconnecting to Disconnecting state via
778      * Stack.DISCONNECTING message
779      */
780     @Test
testStateTransition_AudioDisconnectingToDisconnecting_StackDisconnecting()781     public void testStateTransition_AudioDisconnectingToDisconnecting_StackDisconnecting() {
782         int numBroadcastsSent = setUpAudioDisconnectingState();
783         // Send StackEvent.DISCONNECTING message
784         numBroadcastsSent += 2;
785         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
786                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
787                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTING, mTestDevice));
788         verify(mHeadsetService,
789                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
790                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
791         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
792                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTED,
793                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 2));
794         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
795                 BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_CONNECTED,
796                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 1));
797         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
798                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnecting.class));
799     }
800 
801     /**
802      * Test state transition from AudioDisconnecting to Disconnecting state via
803      * Stack.DISCONNECTED message
804      */
805     @Test
testStateTransition_AudioDisconnectingToDisconnected_StackDisconnected()806     public void testStateTransition_AudioDisconnectingToDisconnected_StackDisconnected() {
807         int numBroadcastsSent = setUpAudioDisconnectingState();
808         // Send StackEvent.DISCONNECTED message
809         numBroadcastsSent += 2;
810         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
811                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
812                         HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED, mTestDevice));
813         verify(mHeadsetService,
814                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
815                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
816         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
817                 BluetoothHeadset.STATE_AUDIO_DISCONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTED,
818                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 2));
819         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
820                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED,
821                 mIntentArgument.getAllValues().get(mIntentArgument.getAllValues().size() - 1));
822         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
823                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnected.class));
824     }
825 
826     /**
827      * A test to verify that we correctly subscribe to phone state updates for service and signal
828      * strength information and further updates via AT+BIA command results in update
829      */
830     @Test
testAtBiaEvent_initialSubscriptionWithUpdates()831     public void testAtBiaEvent_initialSubscriptionWithUpdates() {
832         setUpConnectedState();
833         verify(mPhoneState).listenForPhoneState(mTestDevice, PhoneStateListener.LISTEN_SERVICE_STATE
834                 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
835         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
836                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_BIA,
837                         new HeadsetAgIndicatorEnableState(true, true, false, false), mTestDevice));
838         verify(mPhoneState, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).listenForPhoneState(mTestDevice,
839                 PhoneStateListener.LISTEN_SERVICE_STATE);
840         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
841                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_BIA,
842                         new HeadsetAgIndicatorEnableState(false, true, true, false), mTestDevice));
843         verify(mPhoneState, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).listenForPhoneState(mTestDevice,
844                 PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
845         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
846                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_BIA,
847                         new HeadsetAgIndicatorEnableState(false, true, false, false), mTestDevice));
848         verify(mPhoneState, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).listenForPhoneState(mTestDevice,
849                 PhoneStateListener.LISTEN_NONE);
850     }
851 
852     /**
853      * A test to verify that we correctly handles key pressed event from a HSP headset
854      */
855     @Test
testKeyPressedEventWhenIdleAndAudioOff_dialCall()856     public void testKeyPressedEventWhenIdleAndAudioOff_dialCall() {
857         setUpConnectedState();
858         Cursor cursor = mock(Cursor.class);
859         when(cursor.getCount()).thenReturn(1);
860         when(cursor.moveToNext()).thenReturn(true);
861         int magicNumber = 42;
862         when(cursor.getColumnIndexOrThrow(CallLog.Calls.NUMBER)).thenReturn(magicNumber);
863         when(cursor.getString(magicNumber)).thenReturn(TEST_PHONE_NUMBER);
864         MockContentProvider mockContentProvider = new MockContentProvider() {
865             @Override
866             public Cursor query(Uri uri, String[] projection, String selection,
867                     String[] selectionArgs, String sortOrder) {
868                 if (uri == null || !uri.equals(CallLog.Calls.CONTENT_URI)) {
869                     return null;
870                 }
871                 if (projection == null || (projection.length == 0) || !projection[0].equals(
872                         CallLog.Calls.NUMBER)) {
873                     return null;
874                 }
875                 if (selection == null || !selection.equals(
876                         CallLog.Calls.TYPE + "=" + CallLog.Calls.OUTGOING_TYPE)) {
877                     return null;
878                 }
879                 if (selectionArgs != null) {
880                     return null;
881                 }
882                 if (sortOrder == null || !sortOrder.equals(
883                         CallLog.Calls.DEFAULT_SORT_ORDER + " LIMIT 1")) {
884                     return null;
885                 }
886                 return cursor;
887             }
888         };
889         mMockContentResolver.addProvider(CallLog.AUTHORITY, mockContentProvider);
890         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
891                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_KEY_PRESSED, mTestDevice));
892         verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).dialOutgoingCall(mTestDevice,
893                 TEST_PHONE_NUMBER);
894     }
895 
896     /**
897      * A test to verify that we correctly handles key pressed event from a HSP headset
898      */
899     @Test
testKeyPressedEventDuringRinging_answerCall()900     public void testKeyPressedEventDuringRinging_answerCall() {
901         setUpConnectedState();
902         when(mSystemInterface.isRinging()).thenReturn(true);
903         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
904                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_KEY_PRESSED, mTestDevice));
905         verify(mSystemInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).answerCall(mTestDevice);
906     }
907 
908     /**
909      * A test to verify that we correctly handles key pressed event from a HSP headset
910      */
911     @Test
testKeyPressedEventInCallButAudioOff_setActiveDevice()912     public void testKeyPressedEventInCallButAudioOff_setActiveDevice() {
913         setUpConnectedState();
914         when(mSystemInterface.isInCall()).thenReturn(true);
915         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
916                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_KEY_PRESSED, mTestDevice));
917         verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).setActiveDevice(mTestDevice);
918     }
919 
920     /**
921      * A test to verify that we correctly handles key pressed event from a HSP headset
922      */
923     @Test
testKeyPressedEventInCallAndAudioOn_hangupCall()924     public void testKeyPressedEventInCallAndAudioOn_hangupCall() {
925         setUpAudioOnState();
926         when(mSystemInterface.isInCall()).thenReturn(true);
927         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
928                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_KEY_PRESSED, mTestDevice));
929         verify(mSystemInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).hangupCall(mTestDevice);
930     }
931 
932     /**
933      * A test to verify that we correctly handles key pressed event from a HSP headset
934      */
935     @Test
testKeyPressedEventWhenIdleAndAudioOn_disconnectAudio()936     public void testKeyPressedEventWhenIdleAndAudioOn_disconnectAudio() {
937         setUpAudioOnState();
938         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
939                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_KEY_PRESSED, mTestDevice));
940         verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).disconnectAudio(mTestDevice);
941     }
942 
943     /**
944      * Setup Connecting State
945      * @return number of times mHeadsetService.sendBroadcastAsUser() has been invoked
946      */
setUpConnectingState()947     private int setUpConnectingState() {
948         // Put test state machine in connecting state
949         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.CONNECT, mTestDevice);
950         verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBroadcastAsUser(
951                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
952         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
953                 BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED,
954                 mIntentArgument.getValue());
955         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
956                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connecting.class));
957         return 1;
958     }
959 
960     /**
961      * Setup Connected State
962      * @return number of times mHeadsetService.sendBroadcastAsUser() has been invoked
963      */
setUpConnectedState()964     private int setUpConnectedState() {
965         // Put test state machine into connected state
966         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
967                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
968                         HeadsetHalConstants.CONNECTION_STATE_CONNECTED, mTestDevice));
969         verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBroadcastAsUser(
970                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
971         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
972                 BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED,
973                 mIntentArgument.getValue());
974         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
975                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connecting.class));
976         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
977                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED,
978                         HeadsetHalConstants.CONNECTION_STATE_SLC_CONNECTED, mTestDevice));
979         verify(mHeadsetService, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).sendBroadcastAsUser(
980                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
981         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
982                 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING,
983                 mIntentArgument.getValue());
984         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
985                 IsInstanceOf.instanceOf(HeadsetStateMachine.Connected.class));
986         return 2;
987     }
988 
setUpAudioConnectingState()989     private int setUpAudioConnectingState() {
990         int numBroadcastsSent = setUpConnectedState();
991         // Send CONNECT_AUDIO
992         numBroadcastsSent++;
993         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.CONNECT_AUDIO, mTestDevice);
994         verify(mHeadsetService,
995                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
996                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
997         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
998                 BluetoothHeadset.STATE_AUDIO_CONNECTING, BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
999                 mIntentArgument.getValue());
1000         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
1001                 IsInstanceOf.instanceOf(HeadsetStateMachine.AudioConnecting.class));
1002         return numBroadcastsSent;
1003     }
1004 
setUpAudioOnState()1005     private int setUpAudioOnState() {
1006         int numBroadcastsSent = setUpAudioConnectingState();
1007         // Send StackEvent.AUDIO_DISCONNECTED message
1008         numBroadcastsSent++;
1009         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.STACK_EVENT,
1010                 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED,
1011                         HeadsetHalConstants.AUDIO_STATE_CONNECTED, mTestDevice));
1012         verify(mHeadsetService,
1013                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
1014                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
1015         HeadsetTestUtils.verifyAudioStateBroadcast(mTestDevice,
1016                 BluetoothHeadset.STATE_AUDIO_CONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTING,
1017                 mIntentArgument.getValue());
1018         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
1019                 IsInstanceOf.instanceOf(HeadsetStateMachine.AudioOn.class));
1020         return numBroadcastsSent;
1021     }
1022 
setUpAudioDisconnectingState()1023     private int setUpAudioDisconnectingState() {
1024         int numBroadcastsSent = setUpAudioOnState();
1025         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.DISCONNECT_AUDIO, mTestDevice);
1026         // No new broadcast due to lack of AUDIO_DISCONNECTING intent variable
1027         verify(mHeadsetService,
1028                 after(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
1029                 any(Intent.class), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
1030         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
1031                 IsInstanceOf.instanceOf(HeadsetStateMachine.AudioDisconnecting.class));
1032         return numBroadcastsSent;
1033     }
1034 
setUpDisconnectingState()1035     private int setUpDisconnectingState() {
1036         int numBroadcastsSent = setUpConnectedState();
1037         // Send DISCONNECT message
1038         numBroadcastsSent++;
1039         mHeadsetStateMachine.sendMessage(HeadsetStateMachine.DISCONNECT, mTestDevice);
1040         verify(mHeadsetService,
1041                 timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(numBroadcastsSent)).sendBroadcastAsUser(
1042                 mIntentArgument.capture(), eq(UserHandle.ALL), eq(HeadsetService.BLUETOOTH_PERM));
1043         HeadsetTestUtils.verifyConnectionStateBroadcast(mTestDevice,
1044                 BluetoothProfile.STATE_DISCONNECTING, BluetoothProfile.STATE_CONNECTED,
1045                 mIntentArgument.getValue());
1046         Assert.assertThat(mHeadsetStateMachine.getCurrentState(),
1047                 IsInstanceOf.instanceOf(HeadsetStateMachine.Disconnecting.class));
1048         return numBroadcastsSent;
1049     }
1050 }
1051