1 package com.android.bluetooth.hfpclient;
2 
3 import android.bluetooth.BluetoothAdapter;
4 import android.bluetooth.BluetoothDevice;
5 import android.bluetooth.BluetoothProfile;
6 import android.content.Context;
7 import android.content.Intent;
8 import android.media.AudioManager;
9 import android.os.Bundle;
10 import android.test.AndroidTestCase;
11 import android.util.Log;
12 
13 import java.nio.ByteBuffer;
14 import java.util.List;
15 import java.util.Arrays;
16 import java.util.ArrayList;
17 
18 import com.android.bluetooth.btservice.AdapterService;
19 
20 import static org.mockito.Mockito.*;
21 import org.mockito.ArgumentCaptor;
22 
23 public class HeadsetClientStateMachineTest extends AndroidTestCase {
24     private BluetoothAdapter mAdapter = null;
25 
26     @Override
setUp()27     protected void setUp() throws Exception {
28         AdapterService inst = AdapterService.getAdapterService();
29         assertTrue(inst != null);
30         mAdapter = BluetoothAdapter.getDefaultAdapter();
31     }
32 
33     // Test that default state is disconnected
testDefaultDisconnectedState()34     public void testDefaultDisconnectedState() {
35         HeadsetClientService mockService = mock(HeadsetClientService.class);
36         AudioManager mockAudioManager = mock(AudioManager.class);
37 
38         when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager);
39 
40         HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(
41             mockService, getContext().getMainLooper());
42         assertEquals(
43             mockSM.getConnectionState((BluetoothDevice) null), BluetoothProfile.STATE_DISCONNECTED);
44     }
45 
46     // Test that an incoming connection with low priority is rejected
testIncomingPriorityReject()47     public void testIncomingPriorityReject() {
48         HeadsetClientService mockService = mock(HeadsetClientService.class);
49         AudioManager mockAudioManager = mock(AudioManager.class);
50         BluetoothDevice device = mAdapter.getRemoteDevice("00:01:02:03:04:05");
51 
52         when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager);
53 
54         HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(
55             mockService, getContext().getMainLooper());
56         mockSM.start();
57 
58         // Return false for priority.
59         when(mockService.getPriority(any(BluetoothDevice.class))).thenReturn(
60             BluetoothProfile.PRIORITY_OFF);
61 
62         // Inject an event for when incoming connection is requested
63         StackEvent connStCh =
64             new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
65         connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
66         connStCh.valueInt2 = 0;
67         connStCh.valueInt3 = 0;
68         connStCh.device = device;
69         mockSM.sendMessage(StackEvent.STACK_EVENT, connStCh);
70 
71         // Verify that no connection state broadcast is executed
72         verify(mockService, never()).sendBroadcast(any(Intent.class), anyString());
73         // Check we are in disconnected state still.
74         assertTrue(mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Disconnected);
75     }
76 
77     // Test that an incoming connection with high priority is accepted
testIncomingPriorityAccept()78     public void testIncomingPriorityAccept() {
79         HeadsetClientService mockService = mock(HeadsetClientService.class);
80         AudioManager mockAudioManager = mock(AudioManager.class);
81         BluetoothDevice device = mAdapter.getRemoteDevice("00:01:02:03:04:05");
82 
83         when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager);
84         // Set a valid volume
85         when(mockAudioManager.getStreamVolume(anyInt())).thenReturn(2);
86         when(mockAudioManager.getStreamMaxVolume(anyInt())).thenReturn(10);
87         when(mockAudioManager.getStreamMinVolume(anyInt())).thenReturn(1);
88 
89 
90         HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(
91             mockService, getContext().getMainLooper());
92         mockSM.start();
93 
94         // Return false for priority.
95         when(mockService.getPriority(any(BluetoothDevice.class))).thenReturn(
96             BluetoothProfile.PRIORITY_ON);
97 
98         // Inject an event for when incoming connection is requested
99         StackEvent connStCh =
100             new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
101         connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
102         connStCh.valueInt2 = 0;
103         connStCh.valueInt3 = 0;
104         connStCh.device = device;
105         mockSM.sendMessage(StackEvent.STACK_EVENT, connStCh);
106 
107         // Verify that one connection state broadcast is executed
108         ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class);
109         verify(mockService,
110             timeout(1000)).sendBroadcast(intentArgument1.capture(), anyString());
111         assertEquals(BluetoothProfile.STATE_CONNECTING,
112             intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
113 
114         // Check we are in connecting state now.
115         assertTrue(mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Connecting);
116 
117         // Send a message to trigger SLC connection
118         StackEvent slcEvent =
119             new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
120         slcEvent.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_SLC_CONNECTED;
121         slcEvent.valueInt2 = HeadsetClientHalConstants.PEER_FEAT_ECS;
122         slcEvent.valueInt3 = 0;
123         slcEvent.device = device;
124         mockSM.sendMessage(StackEvent.STACK_EVENT, slcEvent);
125 
126         // Verify that one connection state broadcast is executed
127         ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class);
128         verify(mockService,
129             timeout(1000).times(2)).sendBroadcast(intentArgument2.capture(), anyString());
130         assertEquals(BluetoothProfile.STATE_CONNECTED,
131             intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
132         // Check we are in connecting state now.
133         assertTrue(mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Connected);
134     }
135 
136     // Test that an incoming connection that times out
testIncomingTimeout()137     public void testIncomingTimeout() {
138         HeadsetClientService mockService = mock(HeadsetClientService.class);
139         AudioManager mockAudioManager = mock(AudioManager.class);
140         BluetoothDevice device = mAdapter.getRemoteDevice("00:01:02:03:04:05");
141 
142         when(mockService.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager);
143         // Set a valid volume
144         when(mockAudioManager.getStreamVolume(anyInt())).thenReturn(2);
145         when(mockAudioManager.getStreamMaxVolume(anyInt())).thenReturn(10);
146         when(mockAudioManager.getStreamMinVolume(anyInt())).thenReturn(1);
147 
148 
149         HeadsetClientStateMachine mockSM = new HeadsetClientStateMachine(
150             mockService, getContext().getMainLooper());
151         mockSM.start();
152 
153         // Return false for priority.
154         when(mockService.getPriority(any(BluetoothDevice.class))).thenReturn(
155             BluetoothProfile.PRIORITY_ON);
156 
157         // Inject an event for when incoming connection is requested
158         StackEvent connStCh =
159             new StackEvent(StackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
160         connStCh.valueInt = HeadsetClientHalConstants.CONNECTION_STATE_CONNECTED;
161         connStCh.valueInt2 = 0;
162         connStCh.valueInt3 = 0;
163         connStCh.device = device;
164         mockSM.sendMessage(StackEvent.STACK_EVENT, connStCh);
165 
166         // Verify that one connection state broadcast is executed
167         ArgumentCaptor<Intent> intentArgument1 = ArgumentCaptor.forClass(Intent.class);
168         verify(mockService, timeout(1000)).sendBroadcast(intentArgument1.capture(), anyString());
169         assertEquals(BluetoothProfile.STATE_CONNECTING,
170             intentArgument1.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
171 
172         // Check we are in connecting state now.
173         assertTrue(mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Connecting);
174 
175         // Verify that one connection state broadcast is executed
176         ArgumentCaptor<Intent> intentArgument2 = ArgumentCaptor.forClass(Intent.class);
177         verify(mockService,
178             timeout(HeadsetClientStateMachine.CONNECTING_TIMEOUT_MS * 2).times(2)).sendBroadcast(
179             intentArgument2.capture(), anyString());
180         assertEquals(BluetoothProfile.STATE_DISCONNECTED,
181             intentArgument2.getValue().getIntExtra(BluetoothProfile.EXTRA_STATE, -1));
182 
183         // Check we are in connecting state now.
184         assertTrue(mockSM.getCurrentState() instanceof HeadsetClientStateMachine.Disconnected);
185     }
186 }
187