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