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