BluetoothRouteManagerTest.java revision ea8d15df3c4d563274a7f7755e8c55d42bc9e805
1/* 2 * Copyright (C) 2016 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 17package com.android.server.telecom.tests; 18 19import android.bluetooth.BluetoothDevice; 20import android.content.ContentResolver; 21import android.os.Parcel; 22import android.telecom.Log; 23import android.test.suitebuilder.annotation.LargeTest; 24import android.test.suitebuilder.annotation.SmallTest; 25import android.util.Pair; 26 27import com.android.internal.os.SomeArgs; 28import com.android.server.telecom.BluetoothHeadsetProxy; 29import com.android.server.telecom.CallAudioModeStateMachine; 30import com.android.server.telecom.TelecomSystem; 31import com.android.server.telecom.Timeouts; 32import com.android.server.telecom.bluetooth.BluetoothDeviceManager; 33import com.android.server.telecom.bluetooth.BluetoothRouteManager; 34 35import org.mockito.Mock; 36 37import java.util.ArrayList; 38import java.util.Arrays; 39import java.util.List; 40import java.util.Objects; 41 42import static org.mockito.Matchers.any; 43import static org.mockito.Matchers.anyInt; 44import static org.mockito.Matchers.anyString; 45import static org.mockito.Matchers.eq; 46import static org.mockito.Mockito.doAnswer; 47import static org.mockito.Mockito.mock; 48import static org.mockito.Mockito.never; 49import static org.mockito.Mockito.reset; 50import static org.mockito.Mockito.times; 51import static org.mockito.Mockito.verify; 52import static org.mockito.Mockito.when; 53 54public class BluetoothRouteManagerTest extends StateMachineTestBase<BluetoothRouteManager> { 55 private static class BluetoothRouteTestParametersBuilder { 56 private String name; 57 private String initialBluetoothState; 58 private BluetoothDevice initialDevice; 59 private BluetoothDevice audioOnDevice; 60 private int messageType; 61 private String messageDevice; 62 private Pair<Integer, Integer> expectedListenerUpdate; 63 private int expectedBluetoothInteraction; 64 private String expectedConnectionAddress; 65 private String expectedFinalStateName; 66 private BluetoothDevice[] connectedDevices; 67 68 public BluetoothRouteTestParametersBuilder setName(String name) { 69 this.name = name; 70 return this; 71 } 72 73 public BluetoothRouteTestParametersBuilder setInitialBluetoothState( 74 String initialBluetoothState) { 75 this.initialBluetoothState = initialBluetoothState; 76 return this; 77 } 78 79 public BluetoothRouteTestParametersBuilder setInitialDevice(BluetoothDevice 80 initialDevice) { 81 this.initialDevice = initialDevice; 82 return this; 83 } 84 85 public BluetoothRouteTestParametersBuilder setMessageType(int messageType) { 86 this.messageType = messageType; 87 return this; 88 } 89 90 public BluetoothRouteTestParametersBuilder setMessageDevice(String messageDevice) { 91 this.messageDevice = messageDevice; 92 return this; 93 } 94 95 public BluetoothRouteTestParametersBuilder setExpectedListenerUpdate(Pair<Integer, 96 Integer> expectedListenerUpdate) { 97 this.expectedListenerUpdate = expectedListenerUpdate; 98 return this; 99 } 100 101 public BluetoothRouteTestParametersBuilder setExpectedBluetoothInteraction( 102 int expectedBluetoothInteraction) { 103 this.expectedBluetoothInteraction = expectedBluetoothInteraction; 104 return this; 105 } 106 107 public BluetoothRouteTestParametersBuilder setExpectedConnectionAddress(String 108 expectedConnectionAddress) { 109 this.expectedConnectionAddress = expectedConnectionAddress; 110 return this; 111 } 112 113 public BluetoothRouteTestParametersBuilder setExpectedFinalStateName( 114 String expectedFinalStateName) { 115 this.expectedFinalStateName = expectedFinalStateName; 116 return this; 117 } 118 119 public BluetoothRouteTestParametersBuilder setConnectedDevices( 120 BluetoothDevice... connectedDevices) { 121 this.connectedDevices = connectedDevices; 122 return this; 123 } 124 125 public BluetoothRouteTestParametersBuilder setAudioOnDevice(BluetoothDevice device) { 126 this.audioOnDevice = device; 127 return this; 128 } 129 130 public BluetoothRouteTestParameters build() { 131 return new BluetoothRouteTestParameters(name, 132 initialBluetoothState, 133 initialDevice, 134 messageType, 135 expectedListenerUpdate, 136 expectedBluetoothInteraction, 137 expectedConnectionAddress, 138 expectedFinalStateName, 139 connectedDevices, 140 messageDevice, 141 audioOnDevice); 142 } 143 } 144 145 private static class BluetoothRouteTestParameters extends TestParameters { 146 public String name; 147 public String initialBluetoothState; // One of the state names or prefixes from BRM. 148 public BluetoothDevice initialDevice; // null if we start from AudioOff 149 public BluetoothDevice audioOnDevice; // The device (if any) that is active 150 public int messageType; // Any of the commands from the state machine 151 public String messageDevice; // The device that should be specified in the message. 152 // TODO: Change this when refactoring CARSM. 153 public Pair<Integer, Integer> expectedListenerUpdate; // (old state, new state) 154 public int expectedBluetoothInteraction; // NONE, CONNECT, or DISCONNECT 155 // TODO: this will always be none for now. Change once BT changes their API. 156 public String expectedConnectionAddress; // Expected device to connect to. 157 public String expectedFinalStateName; // Expected name of the final state. 158 public BluetoothDevice[] connectedDevices; // array of connected devices 159 160 public BluetoothRouteTestParameters(String name, String initialBluetoothState, 161 BluetoothDevice initialDevice, int messageType, Pair<Integer, Integer> 162 expectedListenerUpdate, int expectedBluetoothInteraction, String 163 expectedConnectionAddress, String expectedFinalStateName, 164 BluetoothDevice[] connectedDevices, String messageDevice, 165 BluetoothDevice audioOnDevice) { 166 this.name = name; 167 this.initialBluetoothState = initialBluetoothState; 168 this.initialDevice = initialDevice; 169 this.messageType = messageType; 170 this.expectedListenerUpdate = expectedListenerUpdate; 171 this.expectedBluetoothInteraction = expectedBluetoothInteraction; 172 this.expectedConnectionAddress = expectedConnectionAddress; 173 this.expectedFinalStateName = expectedFinalStateName; 174 this.connectedDevices = connectedDevices; 175 this.messageDevice = messageDevice; 176 this.audioOnDevice = audioOnDevice; 177 } 178 179 @Override 180 public String toString() { 181 return "BluetoothRouteTestParameters{" + 182 "name='" + name + '\'' + 183 ", initialBluetoothState='" + initialBluetoothState + '\'' + 184 ", initialDevice=" + initialDevice + 185 ", messageType=" + messageType + 186 ", messageDevice='" + messageDevice + '\'' + 187 ", expectedListenerUpdate=" + expectedListenerUpdate + 188 ", expectedBluetoothInteraction=" + expectedBluetoothInteraction + 189 ", expectedConnectionAddress='" + expectedConnectionAddress + '\'' + 190 ", expectedFinalStateName='" + expectedFinalStateName + '\'' + 191 ", connectedDevices=" + Arrays.toString(connectedDevices) + 192 '}'; 193 } 194 } 195 196 private static final int NONE = 1; 197 private static final int CONNECT = 2; 198 private static final int DISCONNECT = 3; 199 200 @Mock private BluetoothDeviceManager mDeviceManager; 201 @Mock private BluetoothHeadsetProxy mHeadsetProxy; 202 @Mock private Timeouts.Adapter mTimeoutsAdapter; 203 @Mock private BluetoothRouteManager.BluetoothStateListener mListener; 204 205 private BluetoothDevice device1; 206 private BluetoothDevice device2; 207 private BluetoothDevice device3; 208 209 @Override 210 public void setUp() throws Exception { 211 super.setUp(); 212 mContext = mComponentContextFixture.getTestDouble().getApplicationContext(); 213 214 device1 = makeBluetoothDevice("00:00:00:00:00:01"); 215 device2 = makeBluetoothDevice("00:00:00:00:00:02"); 216 device3 = makeBluetoothDevice("00:00:00:00:00:03"); 217 } 218 219 @LargeTest 220 public void testTransitions() throws Throwable { 221 List<BluetoothRouteTestParameters> testCases = generateTestCases(); 222 parametrizedTestStateMachine(testCases); 223 } 224 225 @SmallTest 226 public void testConnectHfpRetryWhileNotConnected() { 227 BluetoothRouteManager sm = setupStateMachine( 228 BluetoothRouteManager.AUDIO_OFF_STATE_NAME, null); 229 setupConnectedDevices(new BluetoothDevice[]{device1}, null); 230 when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis( 231 any(ContentResolver.class))).thenReturn(0L); 232 when(mHeadsetProxy.connectAudio()).thenReturn(false); 233 executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, null); 234 // Wait 3 times: for the first connection attempt, the retry attempt, and once more to 235 // make sure there are only two attempts. 236 waitForStateMachineActionCompletion(sm, BluetoothRouteManager.RUN_RUNNABLE); 237 waitForStateMachineActionCompletion(sm, BluetoothRouteManager.RUN_RUNNABLE); 238 waitForStateMachineActionCompletion(sm, BluetoothRouteManager.RUN_RUNNABLE); 239 // TODO: verify address 240 verify(mHeadsetProxy, times(2)).connectAudio(); 241 assertEquals(BluetoothRouteManager.AUDIO_OFF_STATE_NAME, sm.getCurrentState().getName()); 242 sm.getHandler().removeMessages(BluetoothRouteManager.CONNECTION_TIMEOUT); 243 sm.quitNow(); 244 } 245 246 @SmallTest 247 public void testConnectHfpRetryWhileConnectedToAnotherDevice() { 248 BluetoothRouteManager sm = setupStateMachine( 249 BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, device1); 250 setupConnectedDevices(new BluetoothDevice[]{device1, device2}, null); 251 when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis( 252 any(ContentResolver.class))).thenReturn(0L); 253 when(mHeadsetProxy.connectAudio()).thenReturn(false); 254 executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, device2.getAddress()); 255 // Wait 3 times: the first connection attempt is accounted for in executeRoutingAction, 256 // so wait for the retry attempt, again to make sure there are only two attempts, and 257 // once more for good luck. 258 waitForStateMachineActionCompletion(sm, BluetoothRouteManager.RUN_RUNNABLE); 259 waitForStateMachineActionCompletion(sm, BluetoothRouteManager.RUN_RUNNABLE); 260 waitForStateMachineActionCompletion(sm, BluetoothRouteManager.RUN_RUNNABLE); 261 // TODO: verify address of device2 262 verify(mHeadsetProxy, times(2)).connectAudio(); 263 assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 264 + ":" + device1.getAddress(), 265 sm.getCurrentState().getName()); 266 sm.getHandler().removeMessages(BluetoothRouteManager.CONNECTION_TIMEOUT); 267 sm.quitNow(); 268 } 269 270 @SmallTest 271 public void testProperFallbackOrder1() { 272 // Device 1, 2, 3 are connected in that order. Device 1 is activated, then device 2. 273 // Disconnect device 2, verify fallback to device 1. Disconnect device 1, fallback to 274 // device 3. 275 BluetoothRouteManager sm = setupStateMachine( 276 BluetoothRouteManager.AUDIO_OFF_STATE_NAME, null); 277 setupConnectedDevices(new BluetoothDevice[]{device3, device2, device1}, null); 278 executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, device1.getAddress()); 279 // TODO: verify address 280 verify(mHeadsetProxy, times(1)).connectAudio(); 281 282 setupConnectedDevices(new BluetoothDevice[]{device3, device2, device1}, device1); 283 executeRoutingAction(sm, BluetoothRouteManager.HFP_IS_ON, device1.getAddress()); 284 285 executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, device2.getAddress()); 286 // TODO: verify address 287 verify(mHeadsetProxy, times(2)).connectAudio(); 288 289 setupConnectedDevices(new BluetoothDevice[]{device3, device2, device1}, device2); 290 executeRoutingAction(sm, BluetoothRouteManager.HFP_IS_ON, device2.getAddress()); 291 // Disconnect device 2 292 setupConnectedDevices(new BluetoothDevice[]{device3, device1}, null); 293 executeRoutingAction(sm, BluetoothRouteManager.LOST_DEVICE, device2.getAddress()); 294 // Verify that we've fallen back to device 1 295 verify(mHeadsetProxy, times(3)).connectAudio(); 296 assertEquals(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 297 + ":" + device1.getAddress(), 298 sm.getCurrentState().getName()); 299 setupConnectedDevices(new BluetoothDevice[]{device3, device1}, device1); 300 executeRoutingAction(sm, BluetoothRouteManager.HFP_IS_ON, device1.getAddress()); 301 assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 302 + ":" + device1.getAddress(), 303 sm.getCurrentState().getName()); 304 305 // Disconnect device 1 306 setupConnectedDevices(new BluetoothDevice[]{device3}, null); 307 executeRoutingAction(sm, BluetoothRouteManager.LOST_DEVICE, device1.getAddress()); 308 // Verify that we've fallen back to device 3 309 verify(mHeadsetProxy, times(4)).connectAudio(); 310 assertEquals(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 311 + ":" + device3.getAddress(), 312 sm.getCurrentState().getName()); 313 setupConnectedDevices(new BluetoothDevice[]{device3}, device3); 314 executeRoutingAction(sm, BluetoothRouteManager.HFP_IS_ON, device3.getAddress()); 315 assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 316 + ":" + device3.getAddress(), 317 sm.getCurrentState().getName()); 318 319 sm.getHandler().removeMessages(BluetoothRouteManager.CONNECTION_TIMEOUT); 320 sm.quitNow(); 321 } 322 323 @SmallTest 324 public void testProperFallbackOrder2() { 325 // Device 1, 2, 3 are connected in that order. Device 3 is activated. 326 // Disconnect device 3, verify fallback to device 2. Disconnect device 2, fallback to 327 // device 1. 328 BluetoothRouteManager sm = setupStateMachine( 329 BluetoothRouteManager.AUDIO_OFF_STATE_NAME, null); 330 setupConnectedDevices(new BluetoothDevice[]{device3, device2, device1}, null); 331 executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, device3.getAddress()); 332 // TODO: verify address 333 verify(mHeadsetProxy, times(1)).connectAudio(); 334 335 setupConnectedDevices(new BluetoothDevice[]{device3, device2, device1}, device3); 336 executeRoutingAction(sm, BluetoothRouteManager.HFP_IS_ON, device3.getAddress()); 337 338 // Disconnect device 2 339 setupConnectedDevices(new BluetoothDevice[]{device2, device1}, null); 340 executeRoutingAction(sm, BluetoothRouteManager.LOST_DEVICE, device3.getAddress()); 341 // Verify that we've fallen back to device 2 342 verify(mHeadsetProxy, times(2)).connectAudio(); 343 assertEquals(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 344 + ":" + device2.getAddress(), 345 sm.getCurrentState().getName()); 346 setupConnectedDevices(new BluetoothDevice[]{device2, device1}, device2); 347 executeRoutingAction(sm, BluetoothRouteManager.HFP_IS_ON, device2.getAddress()); 348 assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 349 + ":" + device2.getAddress(), 350 sm.getCurrentState().getName()); 351 352 // Disconnect device 2 353 setupConnectedDevices(new BluetoothDevice[]{device1}, null); 354 executeRoutingAction(sm, BluetoothRouteManager.LOST_DEVICE, device2.getAddress()); 355 // Verify that we've fallen back to device 1 356 verify(mHeadsetProxy, times(3)).connectAudio(); 357 assertEquals(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 358 + ":" + device1.getAddress(), 359 sm.getCurrentState().getName()); 360 setupConnectedDevices(new BluetoothDevice[]{device1}, device1); 361 executeRoutingAction(sm, BluetoothRouteManager.HFP_IS_ON, device1.getAddress()); 362 assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 363 + ":" + device1.getAddress(), 364 sm.getCurrentState().getName()); 365 366 sm.getHandler().removeMessages(BluetoothRouteManager.CONNECTION_TIMEOUT); 367 sm.quitNow(); 368 } 369 370 @Override 371 protected void runParametrizedTestCase(TestParameters _params) { 372 BluetoothRouteTestParameters params = (BluetoothRouteTestParameters) _params; 373 BluetoothRouteManager sm = setupStateMachine( 374 params.initialBluetoothState, params.initialDevice); 375 376 setupConnectedDevices(params.connectedDevices, params.audioOnDevice); 377 executeRoutingAction(sm, params.messageType, params.messageDevice); 378 379 assertEquals(params.expectedFinalStateName, sm.getCurrentState().getName()); 380 381 if (params.expectedListenerUpdate != null) { 382 verify(mListener).onBluetoothStateChange(params.expectedListenerUpdate.first, 383 params.expectedListenerUpdate.second); 384 } else { 385 verify(mListener, never()).onBluetoothStateChange(anyInt(), anyInt()); 386 } 387 // TODO: work the address in here 388 switch (params.expectedBluetoothInteraction) { 389 case NONE: 390 verify(mHeadsetProxy, never()).connectAudio(); 391 verify(mHeadsetProxy, never()).disconnectAudio(); 392 break; 393 case CONNECT: 394 verify(mHeadsetProxy).connectAudio(); 395 verify(mHeadsetProxy, never()).disconnectAudio(); 396 break; 397 case DISCONNECT: 398 verify(mHeadsetProxy, never()).connectAudio(); 399 verify(mHeadsetProxy).disconnectAudio(); 400 break; 401 } 402 403 sm.getHandler().removeMessages(BluetoothRouteManager.CONNECTION_TIMEOUT); 404 sm.quitNow(); 405 } 406 407 private BluetoothRouteManager setupStateMachine(String initialState, 408 BluetoothDevice initialDevice) { 409 resetMocks(true); 410 BluetoothRouteManager sm = new BluetoothRouteManager(mContext, 411 new TelecomSystem.SyncRoot() { }, mDeviceManager, mTimeoutsAdapter); 412 sm.setListener(mListener); 413 sm.setInitialStateForTesting(initialState, initialDevice); 414 waitForStateMachineActionCompletion(sm, BluetoothRouteManager.RUN_RUNNABLE); 415 resetMocks(false); 416 return sm; 417 } 418 419 private void setupConnectedDevices(BluetoothDevice[] devices, BluetoothDevice activeDevice) { 420 when(mDeviceManager.getNumConnectedDevices()).thenReturn(devices.length); 421 when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices)); 422 if (activeDevice != null) { 423 when(mHeadsetProxy.isAudioConnected(eq(activeDevice))).thenReturn(true); 424 } 425 doAnswer(invocation -> { 426 BluetoothDevice first = getFirstExcluding(devices, 427 (String) invocation.getArguments()[0]); 428 return first == null ? null : first.getAddress(); 429 }).when(mDeviceManager).getMostRecentlyConnectedDevice(anyString()); 430 } 431 432 private void executeRoutingAction(BluetoothRouteManager brm, int message, String device) { 433 SomeArgs args = SomeArgs.obtain(); 434 args.arg1 = Log.createSubsession(); 435 args.arg2 = device; 436 brm.sendMessage(message, args); 437 waitForStateMachineActionCompletion(brm, CallAudioModeStateMachine.RUN_RUNNABLE); 438 } 439 440 private BluetoothDevice makeBluetoothDevice(String address) { 441 Parcel p1 = Parcel.obtain(); 442 p1.writeString(address); 443 p1.setDataPosition(0); 444 BluetoothDevice device = BluetoothDevice.CREATOR.createFromParcel(p1); 445 p1.recycle(); 446 return device; 447 } 448 449 private void resetMocks(boolean createNewMocks) { 450 reset(mDeviceManager, mListener, mHeadsetProxy, mTimeoutsAdapter); 451 if (createNewMocks) { 452 mDeviceManager = mock(BluetoothDeviceManager.class); 453 mListener = mock(BluetoothRouteManager.BluetoothStateListener.class); 454 mHeadsetProxy = mock(BluetoothHeadsetProxy.class); 455 mTimeoutsAdapter = mock(Timeouts.Adapter.class); 456 } 457 when(mDeviceManager.getHeadsetService()).thenReturn(mHeadsetProxy); 458 when(mHeadsetProxy.connectAudio()).thenReturn(true); 459 when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis( 460 any(ContentResolver.class))).thenReturn(100000L); 461 when(mTimeoutsAdapter.getBluetoothPendingTimeoutMillis( 462 any(ContentResolver.class))).thenReturn(100000L); 463 } 464 465 private static BluetoothDevice getFirstExcluding( 466 BluetoothDevice[] devices, String excludeAddress) { 467 for (BluetoothDevice x : devices) { 468 if (!Objects.equals(excludeAddress, x.getAddress())) { 469 return x; 470 } 471 } 472 return null; 473 } 474 475 private List<BluetoothRouteTestParameters> generateTestCases() { 476 List<BluetoothRouteTestParameters> result = new ArrayList<>(); 477 result.add(new BluetoothRouteTestParametersBuilder() 478 .setName("New device connected while audio off") 479 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 480 .setInitialDevice(null) 481 .setConnectedDevices(device1) 482 .setMessageType(BluetoothRouteManager.NEW_DEVICE_CONNECTED) 483 .setMessageDevice(device1.getAddress()) 484 .setExpectedListenerUpdate(Pair.create( 485 BluetoothRouteManager.BLUETOOTH_DISCONNECTED, 486 BluetoothRouteManager.BLUETOOTH_DEVICE_CONNECTED)) 487 .setExpectedBluetoothInteraction(NONE) 488 .setExpectedConnectionAddress(null) 489 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 490 .build()); 491 492 result.add(new BluetoothRouteTestParametersBuilder() 493 .setName("Nonspecific connection request while audio off.") 494 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 495 .setInitialDevice(null) 496 .setConnectedDevices(device2, device1) 497 .setMessageType(BluetoothRouteManager.CONNECT_HFP) 498 .setExpectedListenerUpdate(Pair.create( 499 BluetoothRouteManager.BLUETOOTH_DEVICE_CONNECTED, 500 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING)) 501 .setExpectedBluetoothInteraction(CONNECT) 502 .setExpectedConnectionAddress(device2.getAddress()) 503 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 504 + ":" + device2.getAddress()) 505 .build()); 506 507 result.add(new BluetoothRouteTestParametersBuilder() 508 .setName("Connection to a device succeeds after pending") 509 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 510 .setInitialDevice(device2) 511 .setAudioOnDevice(device2) 512 .setConnectedDevices(device2, device1) 513 .setMessageType(BluetoothRouteManager.HFP_IS_ON) 514 .setMessageDevice(device2.getAddress()) 515 .setExpectedListenerUpdate(Pair.create( 516 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING, 517 BluetoothRouteManager.BLUETOOTH_AUDIO_CONNECTED)) 518 .setExpectedBluetoothInteraction(NONE) 519 .setExpectedConnectionAddress(null) 520 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 521 + ":" + device2.getAddress()) 522 .build()); 523 524 result.add(new BluetoothRouteTestParametersBuilder() 525 .setName("Device loses HFP audio but remains connected. No fallback.") 526 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 527 .setInitialDevice(device2) 528 .setConnectedDevices(device2) 529 .setMessageType(BluetoothRouteManager.HFP_LOST) 530 .setMessageDevice(device2.getAddress()) 531 .setExpectedListenerUpdate(Pair.create( 532 BluetoothRouteManager.BLUETOOTH_AUDIO_CONNECTED, 533 BluetoothRouteManager.BLUETOOTH_DEVICE_CONNECTED)) 534 .setExpectedBluetoothInteraction(NONE) 535 .setExpectedConnectionAddress(null) 536 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 537 .build()); 538 539 result.add(new BluetoothRouteTestParametersBuilder() 540 .setName("Device loses HFP audio but remains connected. Fallback.") 541 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 542 .setInitialDevice(device2) 543 .setConnectedDevices(device2, device1, device3) 544 .setMessageType(BluetoothRouteManager.HFP_LOST) 545 .setMessageDevice(device2.getAddress()) 546 .setExpectedListenerUpdate(Pair.create( 547 BluetoothRouteManager.BLUETOOTH_AUDIO_CONNECTED, 548 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING)) 549 .setExpectedBluetoothInteraction(CONNECT) 550 .setExpectedConnectionAddress(device1.getAddress()) 551 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 552 + ":" + device1.getAddress()) 553 .build()); 554 555 result.add(new BluetoothRouteTestParametersBuilder() 556 .setName("Switch active devices") 557 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 558 .setInitialDevice(device2) 559 .setConnectedDevices(device2, device1, device3) 560 .setMessageType(BluetoothRouteManager.CONNECT_HFP) 561 .setMessageDevice(device3.getAddress()) 562 .setExpectedListenerUpdate(Pair.create( 563 BluetoothRouteManager.BLUETOOTH_AUDIO_CONNECTED, 564 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING)) 565 .setExpectedBluetoothInteraction(CONNECT) 566 .setExpectedConnectionAddress(device3.getAddress()) 567 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 568 + ":" + device3.getAddress()) 569 .build()); 570 571 result.add(new BluetoothRouteTestParametersBuilder() 572 .setName("Switch to another device before first device has connected") 573 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 574 .setInitialDevice(device2) 575 .setConnectedDevices(device2, device1, device3) 576 .setMessageType(BluetoothRouteManager.CONNECT_HFP) 577 .setMessageDevice(device3.getAddress()) 578 .setExpectedListenerUpdate(Pair.create( 579 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING, 580 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING)) 581 .setExpectedBluetoothInteraction(CONNECT) 582 .setExpectedConnectionAddress(device3.getAddress()) 583 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 584 + ":" + device3.getAddress()) 585 .build()); 586 587 result.add(new BluetoothRouteTestParametersBuilder() 588 .setName("Device gets disconnected while active. No fallback.") 589 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 590 .setInitialDevice(device2) 591 .setConnectedDevices() 592 .setMessageType(BluetoothRouteManager.LOST_DEVICE) 593 .setMessageDevice(device2.getAddress()) 594 .setExpectedListenerUpdate(Pair.create( 595 BluetoothRouteManager.BLUETOOTH_AUDIO_CONNECTED, 596 BluetoothRouteManager.BLUETOOTH_DISCONNECTED)) 597 .setExpectedBluetoothInteraction(NONE) 598 .setExpectedConnectionAddress(null) 599 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 600 .build()); 601 602 result.add(new BluetoothRouteTestParametersBuilder() 603 .setName("Device gets disconnected while active. Fallback.") 604 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 605 .setInitialDevice(device2) 606 .setConnectedDevices(device3) 607 .setMessageType(BluetoothRouteManager.LOST_DEVICE) 608 .setMessageDevice(device2.getAddress()) 609 .setExpectedListenerUpdate(Pair.create( 610 BluetoothRouteManager.BLUETOOTH_AUDIO_CONNECTED, 611 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING)) 612 .setExpectedBluetoothInteraction(CONNECT) 613 .setExpectedConnectionAddress(device3.getAddress()) 614 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 615 + ":" + device3.getAddress()) 616 .build()); 617 618 result.add(new BluetoothRouteTestParametersBuilder() 619 .setName("Connection to device2 times out but device 1 still connected.") 620 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 621 .setInitialDevice(device2) 622 .setConnectedDevices(device2, device1) 623 .setAudioOnDevice(device1) 624 .setMessageType(BluetoothRouteManager.CONNECTION_TIMEOUT) 625 .setExpectedListenerUpdate(Pair.create( 626 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING, 627 BluetoothRouteManager.BLUETOOTH_AUDIO_CONNECTED)) 628 .setExpectedBluetoothInteraction(NONE) 629 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 630 + ":" + device1.getAddress()) 631 .build()); 632 633 result.add(new BluetoothRouteTestParametersBuilder() 634 .setName("device1 somehow becomes active when device2 is still pending.") 635 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 636 .setInitialDevice(device2) 637 .setConnectedDevices(device2, device1) 638 .setAudioOnDevice(device1) 639 .setMessageType(BluetoothRouteManager.HFP_IS_ON) 640 .setMessageDevice(device1.getAddress()) 641 .setExpectedListenerUpdate(Pair.create( 642 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING, 643 BluetoothRouteManager.BLUETOOTH_AUDIO_CONNECTED)) 644 .setExpectedBluetoothInteraction(NONE) 645 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 646 + ":" + device1.getAddress()) 647 .build()); 648 649 result.add(new BluetoothRouteTestParametersBuilder() 650 .setName("Device gets disconnected while pending. Fallback.") 651 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 652 .setInitialDevice(device2) 653 .setConnectedDevices(device3) 654 .setMessageType(BluetoothRouteManager.LOST_DEVICE) 655 .setMessageDevice(device2.getAddress()) 656 .setExpectedListenerUpdate(Pair.create( 657 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING, 658 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING)) 659 .setExpectedBluetoothInteraction(CONNECT) 660 .setExpectedConnectionAddress(device3.getAddress()) 661 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 662 + ":" + device3.getAddress()) 663 .build()); 664 665 result.add(new BluetoothRouteTestParametersBuilder() 666 .setName("Device gets disconnected while pending. No fallback.") 667 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 668 .setInitialDevice(device2) 669 .setConnectedDevices() 670 .setMessageType(BluetoothRouteManager.LOST_DEVICE) 671 .setMessageDevice(device2.getAddress()) 672 .setExpectedListenerUpdate(Pair.create( 673 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING, 674 BluetoothRouteManager.BLUETOOTH_DISCONNECTED)) 675 .setExpectedBluetoothInteraction(NONE) 676 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 677 .build()); 678 679 result.add(new BluetoothRouteTestParametersBuilder() 680 .setName("Audio routing requests HFP disconnection while a device is active") 681 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 682 .setInitialDevice(device2) 683 .setConnectedDevices(device2, device3) 684 .setMessageType(BluetoothRouteManager.DISCONNECT_HFP) 685 .setExpectedListenerUpdate(Pair.create( 686 BluetoothRouteManager.BLUETOOTH_AUDIO_CONNECTED, 687 BluetoothRouteManager.BLUETOOTH_DEVICE_CONNECTED)) 688 .setExpectedBluetoothInteraction(DISCONNECT) 689 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 690 .build()); 691 692 result.add(new BluetoothRouteTestParametersBuilder() 693 .setName("Audio routing requests HFP disconnection while a device is pending") 694 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 695 .setInitialDevice(device2) 696 .setConnectedDevices(device2, device3) 697 .setMessageType(BluetoothRouteManager.DISCONNECT_HFP) 698 .setExpectedListenerUpdate(Pair.create( 699 BluetoothRouteManager.BLUETOOTH_AUDIO_PENDING, 700 BluetoothRouteManager.BLUETOOTH_DEVICE_CONNECTED)) 701 .setExpectedBluetoothInteraction(DISCONNECT) 702 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 703 .build()); 704 705 result.add(new BluetoothRouteTestParametersBuilder() 706 .setName("Bluetooth turns itself on.") 707 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 708 .setInitialDevice(null) 709 .setConnectedDevices(device2, device3) 710 .setMessageType(BluetoothRouteManager.HFP_IS_ON) 711 .setMessageDevice(device3.getAddress()) 712 .setExpectedListenerUpdate(Pair.create( 713 BluetoothRouteManager.BLUETOOTH_DEVICE_CONNECTED, 714 BluetoothRouteManager.BLUETOOTH_AUDIO_CONNECTED)) 715 .setExpectedBluetoothInteraction(NONE) 716 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 717 + ":" + device3.getAddress()) 718 .build()); 719 720 return result; 721 } 722} 723