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.hfp; 18 19 import static org.hamcrest.Matchers.*; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.anyBoolean; 22 import static org.mockito.ArgumentMatchers.anyInt; 23 import static org.mockito.ArgumentMatchers.eq; 24 import static org.mockito.Mockito.*; 25 26 import android.app.Activity; 27 import android.app.Instrumentation; 28 import android.bluetooth.BluetoothAdapter; 29 import android.bluetooth.BluetoothDevice; 30 import android.bluetooth.BluetoothHeadset; 31 import android.bluetooth.BluetoothProfile; 32 import android.bluetooth.BluetoothUuid; 33 import android.bluetooth.IBluetoothHeadset; 34 import android.content.BroadcastReceiver; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.content.IntentFilter; 38 import android.media.AudioManager; 39 import android.net.Uri; 40 import android.os.ParcelUuid; 41 import android.os.PowerManager; 42 import android.os.RemoteException; 43 import android.telecom.PhoneAccount; 44 45 import androidx.test.InstrumentationRegistry; 46 import androidx.test.espresso.intent.Intents; 47 import androidx.test.espresso.intent.matcher.IntentMatchers; 48 import androidx.test.filters.MediumTest; 49 import androidx.test.rule.ServiceTestRule; 50 import androidx.test.runner.AndroidJUnit4; 51 52 import com.android.bluetooth.R; 53 import com.android.bluetooth.TestUtils; 54 import com.android.bluetooth.btservice.AdapterService; 55 import com.android.bluetooth.btservice.storage.DatabaseManager; 56 57 import org.hamcrest.Matchers; 58 import org.junit.After; 59 import org.junit.Assert; 60 import org.junit.Assume; 61 import org.junit.Before; 62 import org.junit.Rule; 63 import org.junit.Test; 64 import org.junit.runner.RunWith; 65 import org.mockito.ArgumentCaptor; 66 import org.mockito.Mock; 67 import org.mockito.MockitoAnnotations; 68 import org.mockito.Spy; 69 70 import java.lang.reflect.Method; 71 import java.util.Collections; 72 import java.util.HashSet; 73 import java.util.List; 74 import java.util.concurrent.BlockingQueue; 75 import java.util.concurrent.LinkedBlockingQueue; 76 77 /** 78 * A set of integration test that involves both {@link HeadsetService} and 79 * {@link HeadsetStateMachine} 80 */ 81 @MediumTest 82 @RunWith(AndroidJUnit4.class) 83 public class HeadsetServiceAndStateMachineTest { 84 private static final int ASYNC_CALL_TIMEOUT_MILLIS = 250; 85 private static final int START_VR_TIMEOUT_MILLIS = 1000; 86 private static final int START_VR_TIMEOUT_WAIT_MILLIS = START_VR_TIMEOUT_MILLIS * 3 / 2; 87 private static final int MAX_HEADSET_CONNECTIONS = 5; 88 private static final ParcelUuid[] FAKE_HEADSET_UUID = {BluetoothUuid.HFP}; 89 private static final String TEST_PHONE_NUMBER = "1234567890"; 90 private static final String TEST_CALLER_ID = "Test Name"; 91 92 @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule(); 93 94 private Context mTargetContext; 95 private HeadsetService mHeadsetService; 96 private IBluetoothHeadset.Stub mHeadsetServiceBinder; 97 private BluetoothAdapter mAdapter; 98 private HeadsetNativeInterface mNativeInterface; 99 private ArgumentCaptor<HeadsetStateMachine> mStateMachineArgument = 100 ArgumentCaptor.forClass(HeadsetStateMachine.class); 101 private HashSet<BluetoothDevice> mBondedDevices = new HashSet<>(); 102 private final BlockingQueue<Intent> mConnectionStateChangedQueue = new LinkedBlockingQueue<>(); 103 private final BlockingQueue<Intent> mActiveDeviceChangedQueue = new LinkedBlockingQueue<>(); 104 private final BlockingQueue<Intent> mAudioStateChangedQueue = new LinkedBlockingQueue<>(); 105 private HeadsetIntentReceiver mHeadsetIntentReceiver; 106 private int mOriginalVrTimeoutMs = 5000; 107 private PowerManager.WakeLock mVoiceRecognitionWakeLock; 108 109 private class HeadsetIntentReceiver extends BroadcastReceiver { 110 @Override onReceive(Context context, Intent intent)111 public void onReceive(Context context, Intent intent) { 112 String action = intent.getAction(); 113 if (action == null) { 114 Assert.fail("Action is null for intent " + intent); 115 return; 116 } 117 switch (action) { 118 case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED: 119 try { 120 mConnectionStateChangedQueue.put(intent); 121 } catch (InterruptedException e) { 122 Assert.fail("Cannot add Intent to the Connection State Changed queue: " 123 + e.getMessage()); 124 } 125 break; 126 case BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED: 127 try { 128 mActiveDeviceChangedQueue.put(intent); 129 } catch (InterruptedException e) { 130 Assert.fail("Cannot add Intent to the Active Device Changed queue: " 131 + e.getMessage()); 132 } 133 break; 134 case BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED: 135 try { 136 mAudioStateChangedQueue.put(intent); 137 } catch (InterruptedException e) { 138 Assert.fail("Cannot add Intent to the Audio State Changed queue: " 139 + e.getMessage()); 140 } 141 break; 142 default: 143 Assert.fail("Unknown action " + action); 144 } 145 146 } 147 } 148 149 @Spy private HeadsetObjectsFactory mObjectsFactory = HeadsetObjectsFactory.getInstance(); 150 @Mock private AdapterService mAdapterService; 151 @Mock private DatabaseManager mDatabaseManager; 152 @Mock private HeadsetSystemInterface mSystemInterface; 153 @Mock private AudioManager mAudioManager; 154 @Mock private HeadsetPhoneState mPhoneState; 155 156 @Before setUp()157 public void setUp() throws Exception { 158 mTargetContext = InstrumentationRegistry.getTargetContext(); 159 Assume.assumeTrue("Ignore test when HeadsetService is not enabled", 160 mTargetContext.getResources().getBoolean(R.bool.profile_supported_hs_hfp)); 161 MockitoAnnotations.initMocks(this); 162 PowerManager powerManager = 163 (PowerManager) mTargetContext.getSystemService(Context.POWER_SERVICE); 164 mVoiceRecognitionWakeLock = 165 powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "VoiceRecognitionTest"); 166 TestUtils.setAdapterService(mAdapterService); 167 doReturn(MAX_HEADSET_CONNECTIONS).when(mAdapterService).getMaxConnectedAudioDevices(); 168 doReturn(new ParcelUuid[]{BluetoothUuid.HFP}).when(mAdapterService) 169 .getRemoteUuids(any(BluetoothDevice.class)); 170 doReturn(mDatabaseManager).when(mAdapterService).getDatabase(); 171 doReturn(true, false).when(mAdapterService).isStartedProfile(anyString()); 172 // We cannot mock HeadsetObjectsFactory.getInstance() with Mockito. 173 // Hence we need to use reflection to call a private method to 174 // initialize properly the HeadsetObjectsFactory.sInstance field. 175 Method method = HeadsetObjectsFactory.class.getDeclaredMethod("setInstanceForTesting", 176 HeadsetObjectsFactory.class); 177 method.setAccessible(true); 178 method.invoke(null, mObjectsFactory); 179 // This line must be called to make sure relevant objects are initialized properly 180 mAdapter = BluetoothAdapter.getDefaultAdapter(); 181 // Mock methods in AdapterService 182 doReturn(FAKE_HEADSET_UUID).when(mAdapterService) 183 .getRemoteUuids(any(BluetoothDevice.class)); 184 doReturn(BluetoothDevice.BOND_BONDED).when(mAdapterService) 185 .getBondState(any(BluetoothDevice.class)); 186 doAnswer(invocation -> mBondedDevices.toArray(new BluetoothDevice[]{})).when( 187 mAdapterService).getBondedDevices(); 188 // Mock system interface 189 doNothing().when(mSystemInterface).stop(); 190 when(mSystemInterface.getHeadsetPhoneState()).thenReturn(mPhoneState); 191 when(mSystemInterface.getAudioManager()).thenReturn(mAudioManager); 192 when(mSystemInterface.activateVoiceRecognition()).thenReturn(true); 193 when(mSystemInterface.deactivateVoiceRecognition()).thenReturn(true); 194 when(mSystemInterface.getVoiceRecognitionWakeLock()).thenReturn(mVoiceRecognitionWakeLock); 195 when(mSystemInterface.isCallIdle()).thenReturn(true); 196 // Mock methods in HeadsetNativeInterface 197 mNativeInterface = spy(HeadsetNativeInterface.getInstance()); 198 doNothing().when(mNativeInterface).init(anyInt(), anyBoolean()); 199 doNothing().when(mNativeInterface).cleanup(); 200 doReturn(true).when(mNativeInterface).connectHfp(any(BluetoothDevice.class)); 201 doReturn(true).when(mNativeInterface).disconnectHfp(any(BluetoothDevice.class)); 202 doReturn(true).when(mNativeInterface).connectAudio(any(BluetoothDevice.class)); 203 doReturn(true).when(mNativeInterface).disconnectAudio(any(BluetoothDevice.class)); 204 doReturn(true).when(mNativeInterface).setActiveDevice(any(BluetoothDevice.class)); 205 doReturn(true).when(mNativeInterface).sendBsir(any(BluetoothDevice.class), anyBoolean()); 206 doReturn(true).when(mNativeInterface).startVoiceRecognition(any(BluetoothDevice.class)); 207 doReturn(true).when(mNativeInterface).stopVoiceRecognition(any(BluetoothDevice.class)); 208 doReturn(true).when(mNativeInterface) 209 .atResponseCode(any(BluetoothDevice.class), anyInt(), anyInt()); 210 // Use real state machines here 211 doCallRealMethod().when(mObjectsFactory) 212 .makeStateMachine(any(), any(), any(), any(), any(), any()); 213 // Mock methods in HeadsetObjectsFactory 214 doReturn(mSystemInterface).when(mObjectsFactory).makeSystemInterface(any()); 215 doReturn(mNativeInterface).when(mObjectsFactory).getNativeInterface(); 216 Intents.init(); 217 // Modify start VR timeout to a smaller value for testing 218 mOriginalVrTimeoutMs = HeadsetService.sStartVrTimeoutMs; 219 HeadsetService.sStartVrTimeoutMs = START_VR_TIMEOUT_MILLIS; 220 TestUtils.startService(mServiceRule, HeadsetService.class); 221 mHeadsetService = HeadsetService.getHeadsetService(); 222 Assert.assertNotNull(mHeadsetService); 223 verify(mObjectsFactory).makeSystemInterface(mHeadsetService); 224 verify(mObjectsFactory).getNativeInterface(); 225 verify(mNativeInterface).init(MAX_HEADSET_CONNECTIONS + 1, true /* inband ringtone */); 226 mHeadsetServiceBinder = (IBluetoothHeadset.Stub) mHeadsetService.initBinder(); 227 Assert.assertNotNull(mHeadsetServiceBinder); 228 229 // Set up the Connection State Changed receiver 230 IntentFilter filter = new IntentFilter(); 231 filter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 232 filter.addAction(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED); 233 filter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 234 mHeadsetIntentReceiver = new HeadsetIntentReceiver(); 235 mTargetContext.registerReceiver(mHeadsetIntentReceiver, filter); 236 } 237 238 @After tearDown()239 public void tearDown() throws Exception { 240 if (!mTargetContext.getResources().getBoolean(R.bool.profile_supported_hs_hfp)) { 241 return; 242 } 243 mTargetContext.unregisterReceiver(mHeadsetIntentReceiver); 244 TestUtils.stopService(mServiceRule, HeadsetService.class); 245 HeadsetService.sStartVrTimeoutMs = mOriginalVrTimeoutMs; 246 Intents.release(); 247 mHeadsetService = HeadsetService.getHeadsetService(); 248 Assert.assertNull(mHeadsetService); 249 Method method = HeadsetObjectsFactory.class.getDeclaredMethod("setInstanceForTesting", 250 HeadsetObjectsFactory.class); 251 method.setAccessible(true); 252 method.invoke(null, (HeadsetObjectsFactory) null); 253 TestUtils.clearAdapterService(mAdapterService); 254 mBondedDevices.clear(); 255 mConnectionStateChangedQueue.clear(); 256 mActiveDeviceChangedQueue.clear(); 257 // Clear classes that is spied on and has static life time 258 clearInvocations(mNativeInterface); 259 } 260 261 /** 262 * Test to verify that HeadsetService can be successfully started 263 */ 264 @Test testGetHeadsetService()265 public void testGetHeadsetService() { 266 Assert.assertEquals(mHeadsetService, HeadsetService.getHeadsetService()); 267 // Verify default connection and audio states 268 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 269 Assert.assertEquals(BluetoothProfile.STATE_DISCONNECTED, 270 mHeadsetService.getConnectionState(device)); 271 Assert.assertEquals(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 272 mHeadsetService.getAudioState(device)); 273 } 274 275 /** 276 * Test to verify that {@link HeadsetService#connect(BluetoothDevice)} actually result in a 277 * call to native interface to create HFP 278 */ 279 @Test testConnectFromApi()280 public void testConnectFromApi() { 281 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 282 when(mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.HEADSET)) 283 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 284 mBondedDevices.add(device); 285 Assert.assertTrue(mHeadsetService.connect(device)); 286 verify(mObjectsFactory).makeStateMachine(device, 287 mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService, mAdapterService, 288 mNativeInterface, mSystemInterface); 289 // Wait ASYNC_CALL_TIMEOUT_MILLIS for state to settle, timing is also tested here and 290 // 250ms for processing two messages should be way more than enough. Anything that breaks 291 // this indicate some breakage in other part of Android OS 292 waitAndVerifyConnectionStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 293 BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); 294 verify(mNativeInterface).connectHfp(device); 295 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 296 mHeadsetService.getConnectionState(device)); 297 Assert.assertEquals(Collections.singletonList(device), 298 mHeadsetService.getDevicesMatchingConnectionStates( 299 new int[]{BluetoothProfile.STATE_CONNECTING})); 300 // Get feedback from native to put device into connected state 301 HeadsetStackEvent connectedEvent = 302 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED, 303 HeadsetHalConstants.CONNECTION_STATE_SLC_CONNECTED, device); 304 mHeadsetService.messageFromNative(connectedEvent); 305 // Wait ASYNC_CALL_TIMEOUT_MILLIS for state to settle, timing is also tested here and 306 // 250ms for processing two messages should be way more than enough. Anything that breaks 307 // this indicate some breakage in other part of Android OS 308 waitAndVerifyConnectionStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 309 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); 310 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 311 mHeadsetService.getConnectionState(device)); 312 Assert.assertEquals(Collections.singletonList(device), 313 mHeadsetService.getDevicesMatchingConnectionStates( 314 new int[]{BluetoothProfile.STATE_CONNECTED})); 315 } 316 317 /** 318 * Test to verify that {@link BluetoothDevice#ACTION_BOND_STATE_CHANGED} intent with 319 * {@link BluetoothDevice#EXTRA_BOND_STATE} as {@link BluetoothDevice#BOND_NONE} will cause a 320 * disconnected device to be removed from state machine map 321 */ 322 @Test testUnbondDevice_disconnectBeforeUnbond()323 public void testUnbondDevice_disconnectBeforeUnbond() { 324 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 325 when(mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.HEADSET)) 326 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 327 mBondedDevices.add(device); 328 Assert.assertTrue(mHeadsetService.connect(device)); 329 verify(mObjectsFactory).makeStateMachine(device, 330 mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService, mAdapterService, 331 mNativeInterface, mSystemInterface); 332 // Wait ASYNC_CALL_TIMEOUT_MILLIS for state to settle, timing is also tested here and 333 // 250ms for processing two messages should be way more than enough. Anything that breaks 334 // this indicate some breakage in other part of Android OS 335 waitAndVerifyConnectionStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 336 BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); 337 verify(mNativeInterface).connectHfp(device); 338 // Get feedback from native layer to go back to disconnected state 339 HeadsetStackEvent connectedEvent = 340 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED, 341 HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED, device); 342 mHeadsetService.messageFromNative(connectedEvent); 343 // Wait ASYNC_CALL_TIMEOUT_MILLIS for state to settle, timing is also tested here and 344 // 250ms for processing two messages should be way more than enough. Anything that breaks 345 // this indicate some breakage in other part of Android OS 346 waitAndVerifyConnectionStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 347 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTING); 348 // Send unbond intent 349 doReturn(BluetoothDevice.BOND_NONE).when(mAdapterService).getBondState(eq(device)); 350 Intent unbondIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 351 unbondIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE); 352 unbondIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 353 InstrumentationRegistry.getTargetContext().sendBroadcast(unbondIntent); 354 // Check that the state machine is actually destroyed 355 verify(mObjectsFactory, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).destroyStateMachine( 356 mStateMachineArgument.capture()); 357 Assert.assertEquals(device, mStateMachineArgument.getValue().getDevice()); 358 } 359 360 /** 361 * Test to verify that if a device can be property disconnected after 362 * {@link BluetoothDevice#ACTION_BOND_STATE_CHANGED} intent with 363 * {@link BluetoothDevice#EXTRA_BOND_STATE} as {@link BluetoothDevice#BOND_NONE} is received. 364 */ 365 @Test testUnbondDevice_disconnectAfterUnbond()366 public void testUnbondDevice_disconnectAfterUnbond() { 367 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 368 when(mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.HEADSET)) 369 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 370 mBondedDevices.add(device); 371 Assert.assertTrue(mHeadsetService.connect(device)); 372 verify(mObjectsFactory).makeStateMachine(device, 373 mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService, mAdapterService, 374 mNativeInterface, mSystemInterface); 375 // Wait ASYNC_CALL_TIMEOUT_MILLIS for state to settle, timing is also tested here and 376 // 250ms for processing two messages should be way more than enough. Anything that breaks 377 // this indicate some breakage in other part of Android OS 378 verify(mNativeInterface, after(ASYNC_CALL_TIMEOUT_MILLIS)).connectHfp(device); 379 waitAndVerifyConnectionStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 380 BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); 381 // Get feedback from native layer to go to connected state 382 HeadsetStackEvent connectedEvent = 383 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED, 384 HeadsetHalConstants.CONNECTION_STATE_SLC_CONNECTED, device); 385 mHeadsetService.messageFromNative(connectedEvent); 386 // Wait ASYNC_CALL_TIMEOUT_MILLIS for state to settle, timing is also tested here and 387 // 250ms for processing two messages should be way more than enough. Anything that breaks 388 // this indicate some breakage in other part of Android OS 389 waitAndVerifyConnectionStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 390 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); 391 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 392 mHeadsetService.getConnectionState(device)); 393 Assert.assertEquals(Collections.singletonList(device), 394 mHeadsetService.getConnectedDevices()); 395 // Send unbond intent 396 doReturn(BluetoothDevice.BOND_NONE).when(mAdapterService).getBondState(eq(device)); 397 Intent unbondIntent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED); 398 unbondIntent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE); 399 unbondIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 400 InstrumentationRegistry.getTargetContext().sendBroadcast(unbondIntent); 401 // Check that the state machine is not destroyed 402 verify(mObjectsFactory, after(ASYNC_CALL_TIMEOUT_MILLIS).never()).destroyStateMachine( 403 any()); 404 // Now disconnect the device 405 HeadsetStackEvent connectingEvent = 406 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED, 407 HeadsetHalConstants.CONNECTION_STATE_DISCONNECTED, device); 408 mHeadsetService.messageFromNative(connectingEvent); 409 waitAndVerifyConnectionStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 410 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.STATE_CONNECTED); 411 // Check that the state machine is destroyed after another async call 412 verify(mObjectsFactory, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).destroyStateMachine( 413 mStateMachineArgument.capture()); 414 Assert.assertEquals(device, mStateMachineArgument.getValue().getDevice()); 415 416 } 417 418 /** 419 * Test the functionality of 420 * {@link BluetoothHeadset#startScoUsingVirtualVoiceCall()} and 421 * {@link BluetoothHeadset#stopScoUsingVirtualVoiceCall()} 422 * 423 * Normal start and stop 424 */ 425 @Test testVirtualCall_normalStartStop()426 public void testVirtualCall_normalStartStop() throws RemoteException { 427 for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) { 428 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, i); 429 connectTestDevice(device); 430 Assert.assertThat(mHeadsetServiceBinder.getConnectedDevices(), 431 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 432 Assert.assertThat(mHeadsetServiceBinder.getDevicesMatchingConnectionStates( 433 new int[]{BluetoothProfile.STATE_CONNECTED}, mAdapter.getAttributionSource()), 434 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 435 } 436 List<BluetoothDevice> connectedDevices = mHeadsetServiceBinder.getConnectedDevices(); 437 Assert.assertThat(connectedDevices, Matchers.containsInAnyOrder(mBondedDevices.toArray())); 438 Assert.assertFalse(mHeadsetService.isVirtualCallStarted()); 439 BluetoothDevice activeDevice = connectedDevices.get(MAX_HEADSET_CONNECTIONS / 2); 440 Assert.assertTrue(mHeadsetServiceBinder.setActiveDevice(activeDevice, 441 mAdapter.getAttributionSource())); 442 verify(mNativeInterface).setActiveDevice(activeDevice); 443 waitAndVerifyActiveDeviceChangedIntent(ASYNC_CALL_TIMEOUT_MILLIS, activeDevice); 444 Assert.assertEquals(activeDevice, 445 mHeadsetServiceBinder.getActiveDevice(mAdapter.getAttributionSource())); 446 // Start virtual call 447 Assert.assertTrue(mHeadsetServiceBinder 448 .startScoUsingVirtualVoiceCall(mAdapter.getAttributionSource())); 449 Assert.assertTrue(mHeadsetService.isVirtualCallStarted()); 450 verifyVirtualCallStartSequenceInvocations(connectedDevices); 451 // End virtual call 452 Assert.assertTrue(mHeadsetServiceBinder 453 .stopScoUsingVirtualVoiceCall(mAdapter.getAttributionSource())); 454 Assert.assertFalse(mHeadsetService.isVirtualCallStarted()); 455 verifyVirtualCallStopSequenceInvocations(connectedDevices); 456 } 457 458 /** 459 * Test the functionality of 460 * {@link BluetoothHeadset#startScoUsingVirtualVoiceCall()} and 461 * {@link BluetoothHeadset#stopScoUsingVirtualVoiceCall()} 462 * 463 * Virtual call should be preempted by telecom call 464 */ 465 @Test testVirtualCall_preemptedByTelecomCall()466 public void testVirtualCall_preemptedByTelecomCall() throws RemoteException { 467 for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) { 468 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, i); 469 connectTestDevice(device); 470 Assert.assertThat(mHeadsetServiceBinder.getConnectedDevices(), 471 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 472 Assert.assertThat(mHeadsetServiceBinder.getDevicesMatchingConnectionStates( 473 new int[]{BluetoothProfile.STATE_CONNECTED}, mAdapter.getAttributionSource()), 474 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 475 } 476 List<BluetoothDevice> connectedDevices = mHeadsetServiceBinder.getConnectedDevices(); 477 Assert.assertThat(connectedDevices, Matchers.containsInAnyOrder(mBondedDevices.toArray())); 478 Assert.assertFalse(mHeadsetService.isVirtualCallStarted()); 479 BluetoothDevice activeDevice = connectedDevices.get(MAX_HEADSET_CONNECTIONS / 2); 480 Assert.assertTrue(mHeadsetServiceBinder.setActiveDevice(activeDevice, 481 mAdapter.getAttributionSource())); 482 verify(mNativeInterface).setActiveDevice(activeDevice); 483 waitAndVerifyActiveDeviceChangedIntent(ASYNC_CALL_TIMEOUT_MILLIS, activeDevice); 484 Assert.assertEquals(activeDevice, 485 mHeadsetServiceBinder.getActiveDevice(mAdapter.getAttributionSource())); 486 // Start virtual call 487 Assert.assertTrue(mHeadsetServiceBinder 488 .startScoUsingVirtualVoiceCall(mAdapter.getAttributionSource())); 489 Assert.assertTrue(mHeadsetService.isVirtualCallStarted()); 490 verifyVirtualCallStartSequenceInvocations(connectedDevices); 491 // Virtual call should be preempted by telecom call 492 mHeadsetServiceBinder.phoneStateChanged(0, 0, HeadsetHalConstants.CALL_STATE_INCOMING, 493 TEST_PHONE_NUMBER, 128, "", mAdapter.getAttributionSource()); 494 Assert.assertFalse(mHeadsetService.isVirtualCallStarted()); 495 verifyVirtualCallStopSequenceInvocations(connectedDevices); 496 verifyCallStateToNativeInvocation( 497 new HeadsetCallState(0, 0, HeadsetHalConstants.CALL_STATE_INCOMING, 498 TEST_PHONE_NUMBER, 128, ""), connectedDevices); 499 } 500 501 /** 502 * Test the functionality of 503 * {@link BluetoothHeadset#startScoUsingVirtualVoiceCall()} and 504 * {@link BluetoothHeadset#stopScoUsingVirtualVoiceCall()} 505 * 506 * Virtual call should be rejected when there is a telecom call 507 */ 508 @Test testVirtualCall_rejectedWhenThereIsTelecomCall()509 public void testVirtualCall_rejectedWhenThereIsTelecomCall() throws RemoteException { 510 for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) { 511 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, i); 512 connectTestDevice(device); 513 Assert.assertThat(mHeadsetServiceBinder.getConnectedDevices(), 514 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 515 Assert.assertThat(mHeadsetServiceBinder.getDevicesMatchingConnectionStates( 516 new int[]{BluetoothProfile.STATE_CONNECTED}, mAdapter.getAttributionSource()), 517 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 518 } 519 List<BluetoothDevice> connectedDevices = mHeadsetServiceBinder.getConnectedDevices(); 520 Assert.assertThat(connectedDevices, Matchers.containsInAnyOrder(mBondedDevices.toArray())); 521 Assert.assertFalse(mHeadsetService.isVirtualCallStarted()); 522 BluetoothDevice activeDevice = connectedDevices.get(MAX_HEADSET_CONNECTIONS / 2); 523 Assert.assertTrue(mHeadsetServiceBinder.setActiveDevice(activeDevice, 524 mAdapter.getAttributionSource())); 525 verify(mNativeInterface).setActiveDevice(activeDevice); 526 waitAndVerifyActiveDeviceChangedIntent(ASYNC_CALL_TIMEOUT_MILLIS, activeDevice); 527 Assert.assertEquals(activeDevice, 528 mHeadsetServiceBinder.getActiveDevice(mAdapter.getAttributionSource())); 529 // Reject virtual call setup if call state is not idle 530 when(mSystemInterface.isCallIdle()).thenReturn(false); 531 Assert.assertFalse(mHeadsetServiceBinder 532 .startScoUsingVirtualVoiceCall(mAdapter.getAttributionSource())); 533 Assert.assertFalse(mHeadsetService.isVirtualCallStarted()); 534 } 535 536 /** 537 * Test the behavior when dialing outgoing call from the headset 538 */ 539 @Test testDialingOutCall_NormalDialingOut()540 public void testDialingOutCall_NormalDialingOut() throws RemoteException { 541 for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) { 542 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, i); 543 connectTestDevice(device); 544 Assert.assertThat(mHeadsetServiceBinder.getConnectedDevices(), 545 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 546 Assert.assertThat(mHeadsetServiceBinder.getDevicesMatchingConnectionStates( 547 new int[]{BluetoothProfile.STATE_CONNECTED}, mAdapter.getAttributionSource()), 548 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 549 } 550 List<BluetoothDevice> connectedDevices = mHeadsetServiceBinder.getConnectedDevices(); 551 Assert.assertThat(connectedDevices, Matchers.containsInAnyOrder(mBondedDevices.toArray())); 552 Assert.assertFalse(mHeadsetService.isVirtualCallStarted()); 553 BluetoothDevice activeDevice = connectedDevices.get(0); 554 Assert.assertTrue(mHeadsetServiceBinder.setActiveDevice(activeDevice, 555 mAdapter.getAttributionSource())); 556 verify(mNativeInterface).setActiveDevice(activeDevice); 557 waitAndVerifyActiveDeviceChangedIntent(ASYNC_CALL_TIMEOUT_MILLIS, activeDevice); 558 Assert.assertEquals(activeDevice, 559 mHeadsetServiceBinder.getActiveDevice(mAdapter.getAttributionSource())); 560 // Try dialing out from the a non active Headset 561 BluetoothDevice dialingOutDevice = connectedDevices.get(1); 562 HeadsetStackEvent dialingOutEvent = 563 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_DIAL_CALL, TEST_PHONE_NUMBER, 564 dialingOutDevice); 565 Uri dialOutUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, TEST_PHONE_NUMBER, null); 566 Instrumentation.ActivityResult result = 567 new Instrumentation.ActivityResult(Activity.RESULT_OK, null); 568 Intents.intending(IntentMatchers.hasAction(Intent.ACTION_CALL_PRIVILEGED)) 569 .respondWith(result); 570 mHeadsetService.messageFromNative(dialingOutEvent); 571 waitAndVerifyActiveDeviceChangedIntent(ASYNC_CALL_TIMEOUT_MILLIS, dialingOutDevice); 572 TestUtils.waitForLooperToFinishScheduledTask( 573 mHeadsetService.getStateMachinesThreadLooper()); 574 Assert.assertTrue(mHeadsetService.hasDeviceInitiatedDialingOut()); 575 // Make sure the correct intent is fired 576 Intents.intended(allOf(IntentMatchers.hasAction(Intent.ACTION_CALL_PRIVILEGED), 577 IntentMatchers.hasData(dialOutUri)), Intents.times(1)); 578 // Further dial out attempt from same device will fail 579 mHeadsetService.messageFromNative(dialingOutEvent); 580 TestUtils.waitForLooperToFinishScheduledTask( 581 mHeadsetService.getStateMachinesThreadLooper()); 582 verify(mNativeInterface).atResponseCode(dialingOutDevice, 583 HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 584 // Further dial out attempt from other device will fail 585 HeadsetStackEvent dialingOutEventOtherDevice = 586 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_DIAL_CALL, TEST_PHONE_NUMBER, 587 activeDevice); 588 mHeadsetService.messageFromNative(dialingOutEventOtherDevice); 589 TestUtils.waitForLooperToFinishScheduledTask( 590 mHeadsetService.getStateMachinesThreadLooper()); 591 verify(mNativeInterface).atResponseCode(activeDevice, HeadsetHalConstants.AT_RESPONSE_ERROR, 592 0); 593 TestUtils.waitForNoIntent(ASYNC_CALL_TIMEOUT_MILLIS, mActiveDeviceChangedQueue); 594 Assert.assertEquals(dialingOutDevice, 595 mHeadsetServiceBinder.getActiveDevice(mAdapter.getAttributionSource())); 596 // Make sure only one intent is fired 597 Intents.intended(allOf(IntentMatchers.hasAction(Intent.ACTION_CALL_PRIVILEGED), 598 IntentMatchers.hasData(dialOutUri)), Intents.times(1)); 599 // Verify that phone state update confirms the dial out event 600 mHeadsetServiceBinder.phoneStateChanged(0, 0, HeadsetHalConstants.CALL_STATE_DIALING, 601 TEST_PHONE_NUMBER, 128, "", mAdapter.getAttributionSource()); 602 HeadsetCallState dialingCallState = 603 new HeadsetCallState(0, 0, HeadsetHalConstants.CALL_STATE_DIALING, 604 TEST_PHONE_NUMBER, 128, ""); 605 verifyCallStateToNativeInvocation(dialingCallState, connectedDevices); 606 verify(mNativeInterface).atResponseCode(dialingOutDevice, 607 HeadsetHalConstants.AT_RESPONSE_OK, 0); 608 // Verify that IDLE phone state clears the dialing out flag 609 mHeadsetServiceBinder.phoneStateChanged(1, 0, HeadsetHalConstants.CALL_STATE_IDLE, 610 TEST_PHONE_NUMBER, 128, "", mAdapter.getAttributionSource()); 611 HeadsetCallState activeCallState = 612 new HeadsetCallState(0, 0, HeadsetHalConstants.CALL_STATE_DIALING, 613 TEST_PHONE_NUMBER, 128, ""); 614 verifyCallStateToNativeInvocation(activeCallState, connectedDevices); 615 Assert.assertFalse(mHeadsetService.hasDeviceInitiatedDialingOut()); 616 } 617 618 /** 619 * Test the behavior when dialing outgoing call from the headset 620 */ 621 @Test testDialingOutCall_DialingOutPreemptVirtualCall()622 public void testDialingOutCall_DialingOutPreemptVirtualCall() throws RemoteException { 623 for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) { 624 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, i); 625 connectTestDevice(device); 626 Assert.assertThat(mHeadsetServiceBinder.getConnectedDevices(), 627 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 628 Assert.assertThat(mHeadsetServiceBinder.getDevicesMatchingConnectionStates( 629 new int[]{BluetoothProfile.STATE_CONNECTED}, mAdapter.getAttributionSource()), 630 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 631 } 632 List<BluetoothDevice> connectedDevices = mHeadsetServiceBinder.getConnectedDevices(); 633 Assert.assertThat(connectedDevices, Matchers.containsInAnyOrder(mBondedDevices.toArray())); 634 Assert.assertFalse(mHeadsetService.isVirtualCallStarted()); 635 BluetoothDevice activeDevice = connectedDevices.get(0); 636 Assert.assertTrue(mHeadsetServiceBinder.setActiveDevice(activeDevice, 637 mAdapter.getAttributionSource())); 638 verify(mNativeInterface).setActiveDevice(activeDevice); 639 waitAndVerifyActiveDeviceChangedIntent(ASYNC_CALL_TIMEOUT_MILLIS, activeDevice); 640 Assert.assertEquals(activeDevice, 641 mHeadsetServiceBinder.getActiveDevice(mAdapter.getAttributionSource())); 642 // Start virtual call 643 Assert.assertTrue(mHeadsetServiceBinder 644 .startScoUsingVirtualVoiceCall(mAdapter.getAttributionSource())); 645 Assert.assertTrue(mHeadsetService.isVirtualCallStarted()); 646 verifyVirtualCallStartSequenceInvocations(connectedDevices); 647 // Try dialing out from the a non active Headset 648 BluetoothDevice dialingOutDevice = connectedDevices.get(1); 649 HeadsetStackEvent dialingOutEvent = 650 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_DIAL_CALL, TEST_PHONE_NUMBER, 651 dialingOutDevice); 652 Uri dialOutUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, TEST_PHONE_NUMBER, null); 653 Instrumentation.ActivityResult result = 654 new Instrumentation.ActivityResult(Activity.RESULT_OK, null); 655 Intents.intending(IntentMatchers.hasAction(Intent.ACTION_CALL_PRIVILEGED)) 656 .respondWith(result); 657 mHeadsetService.messageFromNative(dialingOutEvent); 658 waitAndVerifyActiveDeviceChangedIntent(ASYNC_CALL_TIMEOUT_MILLIS, dialingOutDevice); 659 TestUtils.waitForLooperToFinishScheduledTask( 660 mHeadsetService.getStateMachinesThreadLooper()); 661 Assert.assertTrue(mHeadsetService.hasDeviceInitiatedDialingOut()); 662 // Make sure the correct intent is fired 663 Intents.intended(allOf(IntentMatchers.hasAction(Intent.ACTION_CALL_PRIVILEGED), 664 IntentMatchers.hasData(dialOutUri)), Intents.times(1)); 665 // Virtual call should be preempted by dialing out call 666 Assert.assertFalse(mHeadsetService.isVirtualCallStarted()); 667 verifyVirtualCallStopSequenceInvocations(connectedDevices); 668 } 669 670 /** 671 * Test to verify the following behavior regarding active HF initiated voice recognition 672 * in the successful scenario 673 * 1. HF device sends AT+BVRA=1 674 * 2. HeadsetStateMachine sends out {@link Intent#ACTION_VOICE_COMMAND} 675 * 3. AG call {@link BluetoothHeadset#stopVoiceRecognition(BluetoothDevice)} to indicate 676 * that voice recognition has stopped 677 * 4. AG sends OK to HF 678 * 679 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 680 */ 681 @Test testVoiceRecognition_SingleHfInitiatedSuccess()682 public void testVoiceRecognition_SingleHfInitiatedSuccess() { 683 // Connect HF 684 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 685 connectTestDevice(device); 686 // Make device active 687 Assert.assertTrue(mHeadsetService.setActiveDevice(device)); 688 verify(mNativeInterface).setActiveDevice(device); 689 Assert.assertEquals(device, mHeadsetService.getActiveDevice()); 690 // Start voice recognition 691 startVoiceRecognitionFromHf(device); 692 } 693 694 /** 695 * Test to verify the following behavior regarding active HF stop voice recognition 696 * in the successful scenario 697 * 1. HF device sends AT+BVRA=0 698 * 2. Let voice recognition app to stop 699 * 3. AG respond with OK 700 * 4. Disconnect audio 701 * 702 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 703 */ 704 @Test testVoiceRecognition_SingleHfStopSuccess()705 public void testVoiceRecognition_SingleHfStopSuccess() { 706 // Connect HF 707 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 708 connectTestDevice(device); 709 // Make device active 710 Assert.assertTrue(mHeadsetService.setActiveDevice(device)); 711 verify(mNativeInterface).setActiveDevice(device); 712 Assert.assertEquals(device, mHeadsetService.getActiveDevice()); 713 // Start voice recognition 714 startVoiceRecognitionFromHf(device); 715 // Stop voice recognition 716 HeadsetStackEvent stopVrEvent = 717 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, 718 HeadsetHalConstants.VR_STATE_STOPPED, device); 719 mHeadsetService.messageFromNative(stopVrEvent); 720 verify(mSystemInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).deactivateVoiceRecognition(); 721 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS).times(2)).atResponseCode(device, 722 HeadsetHalConstants.AT_RESPONSE_OK, 0); 723 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).disconnectAudio(device); 724 verifyNoMoreInteractions(mNativeInterface); 725 } 726 727 /** 728 * Test to verify the following behavior regarding active HF initiated voice recognition 729 * in the failed to activate scenario 730 * 1. HF device sends AT+BVRA=1 731 * 2. HeadsetStateMachine sends out {@link Intent#ACTION_VOICE_COMMAND} 732 * 3. Failed to activate voice recognition through intent 733 * 4. AG sends ERROR to HF 734 * 735 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 736 */ 737 @Test testVoiceRecognition_SingleHfInitiatedFailedToActivate()738 public void testVoiceRecognition_SingleHfInitiatedFailedToActivate() { 739 when(mSystemInterface.activateVoiceRecognition()).thenReturn(false); 740 // Connect HF 741 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 742 connectTestDevice(device); 743 // Make device active 744 Assert.assertTrue(mHeadsetService.setActiveDevice(device)); 745 verify(mNativeInterface).setActiveDevice(device); 746 Assert.assertEquals(device, mHeadsetService.getActiveDevice()); 747 // Start voice recognition 748 HeadsetStackEvent startVrEvent = 749 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, 750 HeadsetHalConstants.VR_STATE_STARTED, device); 751 mHeadsetService.messageFromNative(startVrEvent); 752 verify(mSystemInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).activateVoiceRecognition(); 753 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).atResponseCode(device, 754 HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 755 verifyNoMoreInteractions(mNativeInterface); 756 verifyZeroInteractions(mAudioManager); 757 } 758 759 760 /** 761 * Test to verify the following behavior regarding active HF initiated voice recognition 762 * in the timeout scenario 763 * 1. HF device sends AT+BVRA=1 764 * 2. HeadsetStateMachine sends out {@link Intent#ACTION_VOICE_COMMAND} 765 * 3. AG failed to get back to us on time 766 * 4. AG sends ERROR to HF 767 * 768 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 769 */ 770 @Test testVoiceRecognition_SingleHfInitiatedTimeout()771 public void testVoiceRecognition_SingleHfInitiatedTimeout() { 772 // Connect HF 773 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 774 connectTestDevice(device); 775 // Make device active 776 Assert.assertTrue(mHeadsetService.setActiveDevice(device)); 777 verify(mNativeInterface).setActiveDevice(device); 778 Assert.assertEquals(device, mHeadsetService.getActiveDevice()); 779 // Start voice recognition 780 HeadsetStackEvent startVrEvent = 781 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, 782 HeadsetHalConstants.VR_STATE_STARTED, device); 783 mHeadsetService.messageFromNative(startVrEvent); 784 verify(mSystemInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).activateVoiceRecognition(); 785 verify(mNativeInterface, timeout(START_VR_TIMEOUT_WAIT_MILLIS)).atResponseCode(device, 786 HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 787 verifyNoMoreInteractions(mNativeInterface); 788 verifyZeroInteractions(mAudioManager); 789 } 790 791 /** 792 * Test to verify the following behavior regarding AG initiated voice recognition 793 * in the successful scenario 794 * 1. AG starts voice recognition and notify the Bluetooth stack via 795 * {@link BluetoothHeadset#startVoiceRecognition(BluetoothDevice)} to indicate that voice 796 * recognition has started 797 * 2. AG send +BVRA:1 to HF 798 * 3. AG start SCO connection if SCO has not been started 799 * 800 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 801 */ 802 @Test testVoiceRecognition_SingleAgInitiatedSuccess()803 public void testVoiceRecognition_SingleAgInitiatedSuccess() { 804 // Connect HF 805 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 806 connectTestDevice(device); 807 // Make device active 808 Assert.assertTrue(mHeadsetService.setActiveDevice(device)); 809 verify(mNativeInterface).setActiveDevice(device); 810 Assert.assertEquals(device, mHeadsetService.getActiveDevice()); 811 // Start voice recognition 812 startVoiceRecognitionFromAg(); 813 } 814 815 /** 816 * Test to verify the following behavior regarding AG initiated voice recognition 817 * in the successful scenario 818 * 1. AG starts voice recognition and notify the Bluetooth stack via 819 * {@link BluetoothHeadset#startVoiceRecognition(BluetoothDevice)} to indicate that voice 820 * recognition has started, BluetoothDevice is null in this case 821 * 2. AG send +BVRA:1 to current active HF 822 * 3. AG start SCO connection if SCO has not been started 823 * 824 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 825 */ 826 @Test testVoiceRecognition_SingleAgInitiatedSuccessNullInput()827 public void testVoiceRecognition_SingleAgInitiatedSuccessNullInput() { 828 // Connect HF 829 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 830 connectTestDevice(device); 831 // Make device active 832 Assert.assertTrue(mHeadsetService.setActiveDevice(device)); 833 verify(mNativeInterface).setActiveDevice(device); 834 Assert.assertEquals(device, mHeadsetService.getActiveDevice()); 835 // Start voice recognition on null argument should go to active device 836 Assert.assertTrue(mHeadsetService.startVoiceRecognition(null)); 837 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).startVoiceRecognition(device); 838 } 839 840 /** 841 * Test to verify the following behavior regarding AG initiated voice recognition 842 * in the successful scenario 843 * 1. AG starts voice recognition and notify the Bluetooth stack via 844 * {@link BluetoothHeadset#startVoiceRecognition(BluetoothDevice)} to indicate that voice 845 * recognition has started, BluetoothDevice is null and active device is null 846 * 2. The call should fail 847 * 848 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 849 */ 850 @Test testVoiceRecognition_SingleAgInitiatedFailNullActiveDevice()851 public void testVoiceRecognition_SingleAgInitiatedFailNullActiveDevice() { 852 // Connect HF 853 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 854 connectTestDevice(device); 855 // Make device active 856 Assert.assertTrue(mHeadsetService.setActiveDevice(null)); 857 // TODO(b/79760385): setActiveDevice(null) does not propagate to native layer 858 // verify(mNativeInterface).setActiveDevice(null); 859 Assert.assertNull(mHeadsetService.getActiveDevice()); 860 // Start voice recognition on null argument should fail 861 Assert.assertFalse(mHeadsetService.startVoiceRecognition(null)); 862 } 863 864 /** 865 * Test to verify the following behavior regarding AG stops voice recognition 866 * in the successful scenario 867 * 1. AG stops voice recognition and notify the Bluetooth stack via 868 * {@link BluetoothHeadset#stopVoiceRecognition(BluetoothDevice)} to indicate that voice 869 * recognition has stopped 870 * 2. AG send +BVRA:0 to HF 871 * 3. AG stop SCO connection 872 * 873 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 874 */ 875 @Test testVoiceRecognition_SingleAgStopSuccess()876 public void testVoiceRecognition_SingleAgStopSuccess() { 877 // Connect HF 878 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, 0); 879 connectTestDevice(device); 880 // Make device active 881 Assert.assertTrue(mHeadsetService.setActiveDevice(device)); 882 verify(mNativeInterface).setActiveDevice(device); 883 Assert.assertEquals(device, mHeadsetService.getActiveDevice()); 884 // Start voice recognition 885 startVoiceRecognitionFromAg(); 886 // Stop voice recognition 887 Assert.assertTrue(mHeadsetService.stopVoiceRecognition(device)); 888 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).stopVoiceRecognition(device); 889 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).disconnectAudio(device); 890 verifyNoMoreInteractions(mNativeInterface); 891 } 892 893 /** 894 * Test to verify the following behavior regarding AG initiated voice recognition 895 * in the device not connected failure scenario 896 * 1. AG starts voice recognition and notify the Bluetooth stack via 897 * {@link BluetoothHeadset#startVoiceRecognition(BluetoothDevice)} to indicate that voice 898 * recognition has started 899 * 2. Device is not connected, return false 900 * 901 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 902 */ 903 @Test testVoiceRecognition_SingleAgInitiatedDeviceNotConnected()904 public void testVoiceRecognition_SingleAgInitiatedDeviceNotConnected() { 905 // Start voice recognition 906 BluetoothDevice disconnectedDevice = TestUtils.getTestDevice(mAdapter, 0); 907 Assert.assertFalse(mHeadsetService.startVoiceRecognition(disconnectedDevice)); 908 verifyNoMoreInteractions(mNativeInterface); 909 verifyZeroInteractions(mAudioManager); 910 } 911 912 /** 913 * Test to verify the following behavior regarding non active HF initiated voice recognition 914 * in the successful scenario 915 * 1. HF device sends AT+BVRA=1 916 * 2. HeadsetStateMachine sends out {@link Intent#ACTION_VOICE_COMMAND} 917 * 3. AG call {@link BluetoothHeadset#startVoiceRecognition(BluetoothDevice)} to indicate 918 * that voice recognition has started 919 * 4. AG sends OK to HF 920 * 5. Suspend A2DP 921 * 6. Start SCO if SCO hasn't been started 922 * 923 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 924 */ 925 @Test testVoiceRecognition_MultiHfInitiatedSwitchActiveDeviceSuccess()926 public void testVoiceRecognition_MultiHfInitiatedSwitchActiveDeviceSuccess() { 927 // Connect two devices 928 BluetoothDevice deviceA = TestUtils.getTestDevice(mAdapter, 0); 929 connectTestDevice(deviceA); 930 BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); 931 connectTestDevice(deviceB); 932 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); 933 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); 934 // Set active device to device B 935 Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); 936 verify(mNativeInterface).setActiveDevice(deviceB); 937 Assert.assertEquals(deviceB, mHeadsetService.getActiveDevice()); 938 // Start voice recognition from non active device A 939 HeadsetStackEvent startVrEventA = 940 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, 941 HeadsetHalConstants.VR_STATE_STARTED, deviceA); 942 mHeadsetService.messageFromNative(startVrEventA); 943 verify(mSystemInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).activateVoiceRecognition(); 944 // Active device should have been swapped to device A 945 verify(mNativeInterface).setActiveDevice(deviceA); 946 Assert.assertEquals(deviceA, mHeadsetService.getActiveDevice()); 947 // Start voice recognition from other device should fail 948 HeadsetStackEvent startVrEventB = 949 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, 950 HeadsetHalConstants.VR_STATE_STARTED, deviceB); 951 mHeadsetService.messageFromNative(startVrEventB); 952 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).atResponseCode(deviceB, 953 HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 954 // Reply to continue voice recognition 955 mHeadsetService.startVoiceRecognition(deviceA); 956 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).atResponseCode(deviceA, 957 HeadsetHalConstants.AT_RESPONSE_OK, 0); 958 verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS)) 959 .setParameters("A2dpSuspended=true"); 960 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connectAudio(deviceA); 961 verifyNoMoreInteractions(mNativeInterface); 962 } 963 964 /** 965 * Test to verify the following behavior regarding non active HF initiated voice recognition 966 * in the successful scenario 967 * 1. HF device sends AT+BVRA=1 968 * 2. HeadsetStateMachine sends out {@link Intent#ACTION_VOICE_COMMAND} 969 * 3. AG call {@link BluetoothHeadset#startVoiceRecognition(BluetoothDevice)} to indicate 970 * that voice recognition has started, but on a wrong HF 971 * 4. Headset service instead keep using the initiating HF 972 * 5. AG sends OK to HF 973 * 6. Suspend A2DP 974 * 7. Start SCO if SCO hasn't been started 975 * 976 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 977 */ 978 @Test testVoiceRecognition_MultiHfInitiatedSwitchActiveDeviceReplyWrongHfSuccess()979 public void testVoiceRecognition_MultiHfInitiatedSwitchActiveDeviceReplyWrongHfSuccess() { 980 // Connect two devices 981 BluetoothDevice deviceA = TestUtils.getTestDevice(mAdapter, 0); 982 connectTestDevice(deviceA); 983 BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); 984 connectTestDevice(deviceB); 985 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); 986 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); 987 // Set active device to device B 988 Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); 989 verify(mNativeInterface).setActiveDevice(deviceB); 990 Assert.assertEquals(deviceB, mHeadsetService.getActiveDevice()); 991 // Start voice recognition from non active device A 992 HeadsetStackEvent startVrEventA = 993 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, 994 HeadsetHalConstants.VR_STATE_STARTED, deviceA); 995 mHeadsetService.messageFromNative(startVrEventA); 996 verify(mSystemInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).activateVoiceRecognition(); 997 // Active device should have been swapped to device A 998 verify(mNativeInterface).setActiveDevice(deviceA); 999 Assert.assertEquals(deviceA, mHeadsetService.getActiveDevice()); 1000 // Start voice recognition from other device should fail 1001 HeadsetStackEvent startVrEventB = 1002 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, 1003 HeadsetHalConstants.VR_STATE_STARTED, deviceB); 1004 mHeadsetService.messageFromNative(startVrEventB); 1005 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).atResponseCode(deviceB, 1006 HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1007 // Reply to continue voice recognition on a wrong device 1008 mHeadsetService.startVoiceRecognition(deviceB); 1009 // We still continue on the initiating HF 1010 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).atResponseCode(deviceA, 1011 HeadsetHalConstants.AT_RESPONSE_OK, 0); 1012 verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS)) 1013 .setParameters("A2dpSuspended=true"); 1014 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connectAudio(deviceA); 1015 verifyNoMoreInteractions(mNativeInterface); 1016 } 1017 1018 1019 /** 1020 * Test to verify the following behavior regarding AG initiated voice recognition 1021 * in the successful scenario 1022 * 1. AG starts voice recognition and notify the Bluetooth stack via 1023 * {@link BluetoothHeadset#startVoiceRecognition(BluetoothDevice)} to indicate that voice 1024 * recognition has started 1025 * 2. Suspend A2DP 1026 * 3. AG send +BVRA:1 to HF 1027 * 4. AG start SCO connection if SCO has not been started 1028 * 1029 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 1030 */ 1031 @Test testVoiceRecognition_MultiAgInitiatedSuccess()1032 public void testVoiceRecognition_MultiAgInitiatedSuccess() { 1033 // Connect two devices 1034 BluetoothDevice deviceA = TestUtils.getTestDevice(mAdapter, 0); 1035 connectTestDevice(deviceA); 1036 BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); 1037 connectTestDevice(deviceB); 1038 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); 1039 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); 1040 // Set active device to device B 1041 Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); 1042 verify(mNativeInterface).setActiveDevice(deviceB); 1043 Assert.assertEquals(deviceB, mHeadsetService.getActiveDevice()); 1044 // Start voice recognition 1045 startVoiceRecognitionFromAg(); 1046 // Start voice recognition from other device should fail 1047 HeadsetStackEvent startVrEventA = 1048 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, 1049 HeadsetHalConstants.VR_STATE_STARTED, deviceA); 1050 mHeadsetService.messageFromNative(startVrEventA); 1051 // TODO(b/79660380): Workaround in case voice recognition was not terminated properly 1052 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).stopVoiceRecognition(deviceB); 1053 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).disconnectAudio(deviceB); 1054 // This request should still fail 1055 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).atResponseCode(deviceA, 1056 HeadsetHalConstants.AT_RESPONSE_ERROR, 0); 1057 verifyNoMoreInteractions(mNativeInterface); 1058 } 1059 1060 /** 1061 * Test to verify the following behavior regarding AG initiated voice recognition 1062 * in the device not active failure scenario 1063 * 1. AG starts voice recognition and notify the Bluetooth stack via 1064 * {@link BluetoothHeadset#startVoiceRecognition(BluetoothDevice)} to indicate that voice 1065 * recognition has started 1066 * 2. Device is not active, should do voice recognition on active device only 1067 * 1068 * Reference: Section 4.25, Page 64/144 of HFP 1.7.1 specification 1069 */ 1070 @Test testVoiceRecognition_MultiAgInitiatedDeviceNotActive()1071 public void testVoiceRecognition_MultiAgInitiatedDeviceNotActive() { 1072 // Connect two devices 1073 BluetoothDevice deviceA = TestUtils.getTestDevice(mAdapter, 0); 1074 connectTestDevice(deviceA); 1075 BluetoothDevice deviceB = TestUtils.getTestDevice(mAdapter, 1); 1076 connectTestDevice(deviceB); 1077 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceA, false); 1078 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).sendBsir(deviceB, false); 1079 // Set active device to device B 1080 Assert.assertTrue(mHeadsetService.setActiveDevice(deviceB)); 1081 verify(mNativeInterface).setActiveDevice(deviceB); 1082 Assert.assertEquals(deviceB, mHeadsetService.getActiveDevice()); 1083 // Start voice recognition should succeed 1084 Assert.assertTrue(mHeadsetService.startVoiceRecognition(deviceA)); 1085 verify(mNativeInterface).setActiveDevice(deviceA); 1086 Assert.assertEquals(deviceA, mHeadsetService.getActiveDevice()); 1087 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).startVoiceRecognition(deviceA); 1088 verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS)) 1089 .setParameters("A2dpSuspended=true"); 1090 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connectAudio(deviceA); 1091 waitAndVerifyAudioStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, deviceA, 1092 BluetoothHeadset.STATE_AUDIO_CONNECTING, BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 1093 mHeadsetService.messageFromNative( 1094 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED, 1095 HeadsetHalConstants.AUDIO_STATE_CONNECTED, deviceA)); 1096 waitAndVerifyAudioStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, deviceA, 1097 BluetoothHeadset.STATE_AUDIO_CONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTING); 1098 verifyNoMoreInteractions(mNativeInterface); 1099 } 1100 1101 /** 1102 * Test to verify the call state and caller information are correctly delivered 1103 * {@link BluetoothHeadset#phoneStateChanged(int, int, int, String, int, String, boolean)} 1104 */ 1105 @Test testPhoneStateChangedWithIncomingCallState()1106 public void testPhoneStateChangedWithIncomingCallState() throws RemoteException { 1107 // Connect HF 1108 for (int i = 0; i < MAX_HEADSET_CONNECTIONS; ++i) { 1109 BluetoothDevice device = TestUtils.getTestDevice(mAdapter, i); 1110 connectTestDevice(device); 1111 Assert.assertThat(mHeadsetServiceBinder.getConnectedDevices(), 1112 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 1113 Assert.assertThat(mHeadsetServiceBinder.getDevicesMatchingConnectionStates( 1114 new int[]{BluetoothProfile.STATE_CONNECTED}, mAdapter.getAttributionSource()), 1115 Matchers.containsInAnyOrder(mBondedDevices.toArray())); 1116 } 1117 List<BluetoothDevice> connectedDevices = mHeadsetServiceBinder.getConnectedDevices(); 1118 Assert.assertThat(connectedDevices, Matchers.containsInAnyOrder(mBondedDevices.toArray())); 1119 // Incoming call update by telecom 1120 mHeadsetServiceBinder.phoneStateChanged(0, 0, HeadsetHalConstants.CALL_STATE_INCOMING, 1121 TEST_PHONE_NUMBER, 128, TEST_CALLER_ID, mAdapter.getAttributionSource()); 1122 HeadsetCallState incomingCallState = new HeadsetCallState(0, 0, 1123 HeadsetHalConstants.CALL_STATE_INCOMING, TEST_PHONE_NUMBER, 128, TEST_CALLER_ID); 1124 verifyCallStateToNativeInvocation(incomingCallState, connectedDevices); 1125 } 1126 startVoiceRecognitionFromHf(BluetoothDevice device)1127 private void startVoiceRecognitionFromHf(BluetoothDevice device) { 1128 // Start voice recognition 1129 HeadsetStackEvent startVrEvent = 1130 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_VR_STATE_CHANGED, 1131 HeadsetHalConstants.VR_STATE_STARTED, device); 1132 mHeadsetService.messageFromNative(startVrEvent); 1133 verify(mSystemInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).activateVoiceRecognition(); 1134 Assert.assertTrue(mHeadsetService.startVoiceRecognition(device)); 1135 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).atResponseCode(device, 1136 HeadsetHalConstants.AT_RESPONSE_OK, 0); 1137 verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS)) 1138 .setParameters("A2dpSuspended=true"); 1139 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connectAudio(device); 1140 waitAndVerifyAudioStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 1141 BluetoothHeadset.STATE_AUDIO_CONNECTING, BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 1142 mHeadsetService.messageFromNative( 1143 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED, 1144 HeadsetHalConstants.AUDIO_STATE_CONNECTED, device)); 1145 waitAndVerifyAudioStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 1146 BluetoothHeadset.STATE_AUDIO_CONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTING); 1147 verifyNoMoreInteractions(mNativeInterface); 1148 } 1149 startVoiceRecognitionFromAg()1150 private void startVoiceRecognitionFromAg() { 1151 BluetoothDevice device = mHeadsetService.getActiveDevice(); 1152 Assert.assertNotNull(device); 1153 Assert.assertTrue(mHeadsetService.startVoiceRecognition(device)); 1154 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).startVoiceRecognition(device); 1155 verify(mAudioManager, timeout(ASYNC_CALL_TIMEOUT_MILLIS)) 1156 .setParameters("A2dpSuspended=true"); 1157 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).connectAudio(device); 1158 waitAndVerifyAudioStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 1159 BluetoothHeadset.STATE_AUDIO_CONNECTING, BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 1160 mHeadsetService.messageFromNative( 1161 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED, 1162 HeadsetHalConstants.AUDIO_STATE_CONNECTED, device)); 1163 waitAndVerifyAudioStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 1164 BluetoothHeadset.STATE_AUDIO_CONNECTED, BluetoothHeadset.STATE_AUDIO_CONNECTING); 1165 verifyNoMoreInteractions(mNativeInterface); 1166 } 1167 connectTestDevice(BluetoothDevice device)1168 private void connectTestDevice(BluetoothDevice device) { 1169 when(mDatabaseManager.getProfileConnectionPolicy(device, BluetoothProfile.HEADSET)) 1170 .thenReturn(BluetoothProfile.CONNECTION_POLICY_UNKNOWN); 1171 // Make device bonded 1172 mBondedDevices.add(device); 1173 // Use connecting event to indicate that device is connecting 1174 HeadsetStackEvent rfcommConnectedEvent = 1175 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED, 1176 HeadsetHalConstants.CONNECTION_STATE_CONNECTED, device); 1177 mHeadsetService.messageFromNative(rfcommConnectedEvent); 1178 verify(mObjectsFactory).makeStateMachine(device, 1179 mHeadsetService.getStateMachinesThreadLooper(), mHeadsetService, mAdapterService, 1180 mNativeInterface, mSystemInterface); 1181 // Wait ASYNC_CALL_TIMEOUT_MILLIS for state to settle, timing is also tested here and 1182 // 250ms for processing two messages should be way more than enough. Anything that breaks 1183 // this indicate some breakage in other part of Android OS 1184 waitAndVerifyConnectionStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 1185 BluetoothProfile.STATE_CONNECTING, BluetoothProfile.STATE_DISCONNECTED); 1186 Assert.assertEquals(BluetoothProfile.STATE_CONNECTING, 1187 mHeadsetService.getConnectionState(device)); 1188 Assert.assertEquals(Collections.singletonList(device), 1189 mHeadsetService.getDevicesMatchingConnectionStates( 1190 new int[]{BluetoothProfile.STATE_CONNECTING})); 1191 // Get feedback from native to put device into connected state 1192 HeadsetStackEvent slcConnectedEvent = 1193 new HeadsetStackEvent(HeadsetStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED, 1194 HeadsetHalConstants.CONNECTION_STATE_SLC_CONNECTED, device); 1195 mHeadsetService.messageFromNative(slcConnectedEvent); 1196 // Wait ASYNC_CALL_TIMEOUT_MILLIS for state to settle, timing is also tested here and 1197 // 250ms for processing two messages should be way more than enough. Anything that breaks 1198 // this indicate some breakage in other part of Android OS 1199 waitAndVerifyConnectionStateIntent(ASYNC_CALL_TIMEOUT_MILLIS, device, 1200 BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_CONNECTING); 1201 Assert.assertEquals(BluetoothProfile.STATE_CONNECTED, 1202 mHeadsetService.getConnectionState(device)); 1203 } 1204 waitAndVerifyConnectionStateIntent(int timeoutMs, BluetoothDevice device, int newState, int prevState)1205 private void waitAndVerifyConnectionStateIntent(int timeoutMs, BluetoothDevice device, 1206 int newState, int prevState) { 1207 Intent intent = TestUtils.waitForIntent(timeoutMs, mConnectionStateChangedQueue); 1208 Assert.assertNotNull(intent); 1209 HeadsetTestUtils.verifyConnectionStateBroadcast(device, newState, prevState, intent, false); 1210 } 1211 waitAndVerifyActiveDeviceChangedIntent(int timeoutMs, BluetoothDevice device)1212 private void waitAndVerifyActiveDeviceChangedIntent(int timeoutMs, BluetoothDevice device) { 1213 Intent intent = TestUtils.waitForIntent(timeoutMs, mActiveDeviceChangedQueue); 1214 Assert.assertNotNull(intent); 1215 HeadsetTestUtils.verifyActiveDeviceChangedBroadcast(device, intent, false); 1216 } 1217 waitAndVerifyAudioStateIntent(int timeoutMs, BluetoothDevice device, int newState, int prevState)1218 private void waitAndVerifyAudioStateIntent(int timeoutMs, BluetoothDevice device, int newState, 1219 int prevState) { 1220 Intent intent = TestUtils.waitForIntent(timeoutMs, mAudioStateChangedQueue); 1221 Assert.assertNotNull(intent); 1222 HeadsetTestUtils.verifyAudioStateBroadcast(device, newState, prevState, intent); 1223 } 1224 1225 /** 1226 * Verify the series of invocations after 1227 * {@link BluetoothHeadset#startScoUsingVirtualVoiceCall()} 1228 * 1229 * @param connectedDevices must be in the same sequence as 1230 * {@link BluetoothHeadset#getConnectedDevices()} 1231 */ verifyVirtualCallStartSequenceInvocations(List<BluetoothDevice> connectedDevices)1232 private void verifyVirtualCallStartSequenceInvocations(List<BluetoothDevice> connectedDevices) { 1233 // Do not verify HeadsetPhoneState changes as it is verified in HeadsetServiceTest 1234 verifyCallStateToNativeInvocation( 1235 new HeadsetCallState(0, 0, HeadsetHalConstants.CALL_STATE_DIALING, "", 0, ""), 1236 connectedDevices); 1237 verifyCallStateToNativeInvocation( 1238 new HeadsetCallState(0, 0, HeadsetHalConstants.CALL_STATE_ALERTING, "", 0, ""), 1239 connectedDevices); 1240 verifyCallStateToNativeInvocation( 1241 new HeadsetCallState(1, 0, HeadsetHalConstants.CALL_STATE_IDLE, "", 0, ""), 1242 connectedDevices); 1243 } 1244 verifyVirtualCallStopSequenceInvocations(List<BluetoothDevice> connectedDevices)1245 private void verifyVirtualCallStopSequenceInvocations(List<BluetoothDevice> connectedDevices) { 1246 verifyCallStateToNativeInvocation( 1247 new HeadsetCallState(0, 0, HeadsetHalConstants.CALL_STATE_IDLE, "", 0, ""), 1248 connectedDevices); 1249 } 1250 verifyCallStateToNativeInvocation(HeadsetCallState headsetCallState, List<BluetoothDevice> connectedDevices)1251 private void verifyCallStateToNativeInvocation(HeadsetCallState headsetCallState, 1252 List<BluetoothDevice> connectedDevices) { 1253 for (BluetoothDevice device : connectedDevices) { 1254 verify(mNativeInterface, timeout(ASYNC_CALL_TIMEOUT_MILLIS)).phoneStateChange(device, 1255 headsetCallState); 1256 } 1257 } 1258 } 1259