1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server.telecom.tests; 18 19 import android.bluetooth.BluetoothDevice; 20 import android.bluetooth.BluetoothHeadset; 21 import android.bluetooth.BluetoothHearingAid; 22 import android.content.ContentResolver; 23 import android.telecom.Log; 24 import android.test.suitebuilder.annotation.SmallTest; 25 26 import com.android.internal.os.SomeArgs; 27 import com.android.server.telecom.BluetoothHeadsetProxy; 28 import com.android.server.telecom.TelecomSystem; 29 import com.android.server.telecom.Timeouts; 30 import com.android.server.telecom.bluetooth.BluetoothDeviceManager; 31 import com.android.server.telecom.bluetooth.BluetoothRouteManager; 32 33 import org.junit.Before; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 import org.junit.runners.Parameterized; 37 import org.mockito.Mock; 38 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.Collection; 42 import java.util.Collections; 43 import java.util.List; 44 45 import static com.android.server.telecom.tests.BluetoothRouteManagerTest.DEVICE1; 46 import static com.android.server.telecom.tests.BluetoothRouteManagerTest.DEVICE2; 47 import static com.android.server.telecom.tests.BluetoothRouteManagerTest.DEVICE3; 48 import static com.android.server.telecom.tests.BluetoothRouteManagerTest.executeRoutingAction; 49 import static org.junit.Assert.assertEquals; 50 import static org.mockito.ArgumentMatchers.any; 51 import static org.mockito.ArgumentMatchers.eq; 52 import static org.mockito.ArgumentMatchers.nullable; 53 import static org.mockito.Mockito.clearInvocations; 54 import static org.mockito.Mockito.doAnswer; 55 import static org.mockito.Mockito.never; 56 import static org.mockito.Mockito.verify; 57 import static org.mockito.Mockito.when; 58 59 @RunWith(Parameterized.class) 60 public class BluetoothRouteTransitionTests extends TelecomTestCase { 61 private enum ListenerUpdate { 62 DEVICE_LIST_CHANGED, ACTIVE_DEVICE_PRESENT, ACTIVE_DEVICE_GONE, 63 AUDIO_CONNECTED, AUDIO_DISCONNECTED, UNEXPECTED_STATE_CHANGE 64 } 65 66 private static class BluetoothRouteTestParametersBuilder { 67 private String name; 68 private String initialBluetoothState; 69 private BluetoothDevice initialDevice; 70 private BluetoothDevice audioOnDevice; 71 private int messageType; 72 private BluetoothDevice messageDevice; 73 private ListenerUpdate[] expectedListenerUpdates; 74 private int expectedBluetoothInteraction; 75 private BluetoothDevice expectedConnectionDevice; 76 private String expectedFinalStateName; 77 private BluetoothDevice[] connectedDevices; 78 // the active device as returned by BluetoothHeadset#getActiveDevice 79 private BluetoothDevice activeDevice = null; 80 private List<BluetoothDevice> hearingAidBtDevices = Collections.emptyList(); 81 setName(String name)82 public BluetoothRouteTestParametersBuilder setName(String name) { 83 this.name = name; 84 return this; 85 } 86 setInitialBluetoothState( String initialBluetoothState)87 public BluetoothRouteTestParametersBuilder setInitialBluetoothState( 88 String initialBluetoothState) { 89 this.initialBluetoothState = initialBluetoothState; 90 return this; 91 } 92 setInitialDevice(BluetoothDevice initialDevice)93 public BluetoothRouteTestParametersBuilder setInitialDevice(BluetoothDevice 94 initialDevice) { 95 this.initialDevice = initialDevice; 96 return this; 97 } 98 setMessageType(int messageType)99 public BluetoothRouteTestParametersBuilder setMessageType(int messageType) { 100 this.messageType = messageType; 101 return this; 102 } 103 setMessageDevice(BluetoothDevice messageDevice)104 public BluetoothRouteTestParametersBuilder setMessageDevice(BluetoothDevice messageDevice) { 105 this.messageDevice = messageDevice; 106 return this; 107 } 108 setExpectedListenerUpdates( ListenerUpdate... expectedListenerUpdates)109 public BluetoothRouteTestParametersBuilder setExpectedListenerUpdates( 110 ListenerUpdate... expectedListenerUpdates) { 111 this.expectedListenerUpdates = expectedListenerUpdates; 112 return this; 113 } 114 setExpectedBluetoothInteraction( int expectedBluetoothInteraction)115 public BluetoothRouteTestParametersBuilder setExpectedBluetoothInteraction( 116 int expectedBluetoothInteraction) { 117 this.expectedBluetoothInteraction = expectedBluetoothInteraction; 118 return this; 119 } 120 setExpectedConnectionDevice( BluetoothDevice expectedConnectionDevice)121 public BluetoothRouteTestParametersBuilder setExpectedConnectionDevice( 122 BluetoothDevice expectedConnectionDevice) { 123 this.expectedConnectionDevice = expectedConnectionDevice; 124 return this; 125 } 126 setExpectedFinalStateName( String expectedFinalStateName)127 public BluetoothRouteTestParametersBuilder setExpectedFinalStateName( 128 String expectedFinalStateName) { 129 this.expectedFinalStateName = expectedFinalStateName; 130 return this; 131 } 132 setConnectedDevices( BluetoothDevice... connectedDevices)133 public BluetoothRouteTestParametersBuilder setConnectedDevices( 134 BluetoothDevice... connectedDevices) { 135 this.connectedDevices = connectedDevices; 136 return this; 137 } 138 setAudioOnDevice(BluetoothDevice device)139 public BluetoothRouteTestParametersBuilder setAudioOnDevice(BluetoothDevice device) { 140 this.audioOnDevice = device; 141 return this; 142 } 143 setActiveDevice(BluetoothDevice device)144 public BluetoothRouteTestParametersBuilder setActiveDevice(BluetoothDevice device) { 145 this.activeDevice = device; 146 return this; 147 } 148 setHearingAidBtDevices( List<BluetoothDevice> hearingAidBtDevices)149 public BluetoothRouteTestParametersBuilder setHearingAidBtDevices( 150 List<BluetoothDevice> hearingAidBtDevices) { 151 this.hearingAidBtDevices = hearingAidBtDevices; 152 return this; 153 } 154 build()155 public BluetoothRouteTestParameters build() { 156 return new BluetoothRouteTestParameters(name, 157 initialBluetoothState, 158 initialDevice, 159 messageType, 160 expectedListenerUpdates, 161 expectedBluetoothInteraction, 162 expectedConnectionDevice, 163 expectedFinalStateName, 164 connectedDevices, 165 messageDevice, 166 audioOnDevice, 167 activeDevice, 168 hearingAidBtDevices); 169 170 } 171 } 172 173 private static class BluetoothRouteTestParameters { 174 public String name; 175 public String initialBluetoothState; // One of the state names or prefixes from BRM. 176 public BluetoothDevice initialDevice; // null if we start from AudioOff 177 public BluetoothDevice audioOnDevice; // The device (if any) that is active 178 public int messageType; // Any of the commands from the state machine 179 public BluetoothDevice messageDevice; // The device that should be specified in the message. 180 public ListenerUpdate[] expectedListenerUpdates; // what the listener should expect. 181 public int expectedBluetoothInteraction; // NONE, CONNECT, or DISCONNECT 182 public BluetoothDevice expectedConnectionDevice; // Expected device to connect to. 183 public String expectedFinalStateName; // Expected name of the final state. 184 public BluetoothDevice[] connectedDevices; // array of connected devices 185 // the active device as returned by BluetoothHeadset#getActiveDevice 186 private BluetoothDevice activeDevice = null; 187 private List<BluetoothDevice> hearingAidBtDevices; 188 BluetoothRouteTestParameters(String name, String initialBluetoothState, BluetoothDevice initialDevice, int messageType, ListenerUpdate[] expectedListenerUpdates, int expectedBluetoothInteraction, BluetoothDevice expectedConnectionDevice, String expectedFinalStateName, BluetoothDevice[] connectedDevices, BluetoothDevice messageDevice, BluetoothDevice audioOnDevice, BluetoothDevice activeDevice, List<BluetoothDevice> hearingAidBtDevices)189 public BluetoothRouteTestParameters(String name, String initialBluetoothState, 190 BluetoothDevice initialDevice, int messageType, ListenerUpdate[] 191 expectedListenerUpdates, int expectedBluetoothInteraction, BluetoothDevice 192 expectedConnectionDevice, String expectedFinalStateName, 193 BluetoothDevice[] connectedDevices, BluetoothDevice messageDevice, 194 BluetoothDevice audioOnDevice, BluetoothDevice activeDevice, 195 List<BluetoothDevice> hearingAidBtDevices) { 196 this.name = name; 197 this.initialBluetoothState = initialBluetoothState; 198 this.initialDevice = initialDevice; 199 this.messageType = messageType; 200 this.expectedListenerUpdates = expectedListenerUpdates; 201 this.expectedBluetoothInteraction = expectedBluetoothInteraction; 202 this.expectedConnectionDevice = expectedConnectionDevice; 203 this.expectedFinalStateName = expectedFinalStateName; 204 this.connectedDevices = connectedDevices; 205 this.messageDevice = messageDevice; 206 this.audioOnDevice = audioOnDevice; 207 this.activeDevice = activeDevice; 208 this.hearingAidBtDevices = hearingAidBtDevices; 209 } 210 211 @Override toString()212 public String toString() { 213 return "BluetoothRouteTestParameters{" + 214 "name='" + name + '\'' + 215 ", initialBluetoothState='" + initialBluetoothState + '\'' + 216 ", initialDevice=" + initialDevice + 217 ", messageType=" + messageType + 218 ", messageDevice='" + messageDevice + '\'' + 219 ", expectedListenerUpdate=" + expectedListenerUpdates + 220 ", expectedBluetoothInteraction=" + expectedBluetoothInteraction + 221 ", expectedConnectionDevice='" + expectedConnectionDevice + '\'' + 222 ", expectedFinalStateName='" + expectedFinalStateName + '\'' + 223 ", connectedDevices=" + Arrays.toString(connectedDevices) + 224 ", activeDevice='" + activeDevice + '\'' + 225 ", hearingAidBtDevices ='" + hearingAidBtDevices + '\'' + 226 '}'; 227 } 228 } 229 230 private static final int NONE = 1; 231 private static final int CONNECT = 2; 232 private static final int DISCONNECT = 3; 233 234 private static final int TEST_TIMEOUT = 1000; 235 236 private final BluetoothRouteTestParameters mParams; 237 @Mock private BluetoothDeviceManager mDeviceManager; 238 @Mock private BluetoothHeadsetProxy mHeadsetProxy; 239 @Mock private BluetoothHearingAid mBluetoothHearingAid; 240 @Mock private Timeouts.Adapter mTimeoutsAdapter; 241 @Mock private BluetoothRouteManager.BluetoothStateListener mListener; 242 243 @Override 244 @Before setUp()245 public void setUp() throws Exception { 246 super.setUp(); 247 } 248 BluetoothRouteTransitionTests(BluetoothRouteTestParameters params)249 public BluetoothRouteTransitionTests(BluetoothRouteTestParameters params) { 250 mParams = params; 251 } 252 253 @Test 254 @SmallTest testTransitions()255 public void testTransitions() { 256 BluetoothRouteManager sm = setupStateMachine( 257 mParams.initialBluetoothState, mParams.initialDevice); 258 259 setupConnectedDevices(mParams.connectedDevices, 260 mParams.audioOnDevice, mParams.activeDevice); 261 sm.setActiveDeviceCacheForTesting(mParams.activeDevice, 262 mParams.hearingAidBtDevices.contains(mParams.messageDevice)); 263 if (mParams.initialDevice != null) { 264 doAnswer(invocation -> { 265 SomeArgs args = SomeArgs.obtain(); 266 args.arg1 = Log.createSubsession(); 267 args.arg2 = mParams.initialDevice.getAddress(); 268 when(mHeadsetProxy.getActiveDevice()).thenReturn(null); 269 sm.sendMessage(BluetoothRouteManager.BT_AUDIO_LOST, args); 270 return true; 271 }).when(mDeviceManager).disconnectAudio(); 272 } 273 274 // Go through the utility methods for these two messages 275 if (mParams.messageType == BluetoothRouteManager.NEW_DEVICE_CONNECTED) { 276 sm.onDeviceAdded(mParams.messageDevice.getAddress()); 277 sm.onActiveDeviceChanged(mParams.messageDevice, 278 mParams.hearingAidBtDevices.contains(mParams.messageDevice)); 279 } else if (mParams.messageType == BluetoothRouteManager.LOST_DEVICE) { 280 sm.onActiveDeviceChanged(null, 281 mParams.hearingAidBtDevices.contains(mParams.messageDevice)); 282 if (mParams.hearingAidBtDevices.contains(mParams.messageDevice)) { 283 when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(null, null)); 284 } else { 285 when(mHeadsetProxy.getActiveDevice()).thenReturn(null); 286 } 287 sm.onDeviceLost(mParams.messageDevice.getAddress()); 288 } else { 289 executeRoutingAction(sm, mParams.messageType, 290 mParams.messageDevice == null ? null : mParams.messageDevice.getAddress()); 291 } 292 293 waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT); 294 waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT); 295 waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT); 296 assertEquals(mParams.expectedFinalStateName, sm.getCurrentState().getName()); 297 298 for (ListenerUpdate lu : mParams.expectedListenerUpdates) { 299 switch (lu) { 300 case DEVICE_LIST_CHANGED: 301 verify(mListener).onBluetoothDeviceListChanged(); 302 break; 303 case ACTIVE_DEVICE_PRESENT: 304 verify(mListener).onBluetoothActiveDevicePresent(); 305 break; 306 case ACTIVE_DEVICE_GONE: 307 verify(mListener).onBluetoothActiveDeviceGone(); 308 break; 309 case AUDIO_CONNECTED: 310 verify(mListener).onBluetoothAudioConnected(); 311 break; 312 case AUDIO_DISCONNECTED: 313 verify(mListener).onBluetoothAudioDisconnected(); 314 break; 315 } 316 } 317 318 switch (mParams.expectedBluetoothInteraction) { 319 case NONE: 320 verify(mDeviceManager, never()).connectAudio(nullable(String.class)); 321 break; 322 case CONNECT: 323 verify(mDeviceManager).connectAudio(mParams.expectedConnectionDevice.getAddress()); 324 verify(mDeviceManager, never()).disconnectAudio(); 325 break; 326 case DISCONNECT: 327 verify(mDeviceManager, never()).connectAudio(nullable(String.class)); 328 verify(mDeviceManager).disconnectAudio(); 329 break; 330 } 331 332 sm.getHandler().removeMessages(BluetoothRouteManager.CONNECTION_TIMEOUT); 333 sm.quitNow(); 334 } 335 setupConnectedDevices(BluetoothDevice[] devices, BluetoothDevice audioOnDevice, BluetoothDevice activeDevice)336 private void setupConnectedDevices(BluetoothDevice[] devices, 337 BluetoothDevice audioOnDevice, BluetoothDevice activeDevice) { 338 when(mDeviceManager.getNumConnectedDevices()).thenReturn(devices.length); 339 when(mDeviceManager.getConnectedDevices()).thenReturn(Arrays.asList(devices)); 340 when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices)); 341 when(mHeadsetProxy.getActiveDevice()).thenReturn(activeDevice); 342 if (audioOnDevice != null) { 343 when(mHeadsetProxy.getActiveDevice()).thenReturn(audioOnDevice); 344 when(mHeadsetProxy.getAudioState(audioOnDevice)) 345 .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED); 346 } 347 } 348 setupStateMachine(String initialState, BluetoothDevice initialDevice)349 private BluetoothRouteManager setupStateMachine(String initialState, 350 BluetoothDevice initialDevice) { 351 resetMocks(); 352 when(mDeviceManager.getHeadsetService()).thenReturn(mHeadsetProxy); 353 when(mDeviceManager.getHearingAidService()).thenReturn(mBluetoothHearingAid); 354 when(mDeviceManager.connectAudio(nullable(String.class))).thenReturn(true); 355 when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis( 356 nullable(ContentResolver.class))).thenReturn(100000L); 357 when(mTimeoutsAdapter.getBluetoothPendingTimeoutMillis( 358 nullable(ContentResolver.class))).thenReturn(100000L); 359 BluetoothRouteManager sm = new BluetoothRouteManager(mContext, 360 new TelecomSystem.SyncRoot() { }, mDeviceManager, mTimeoutsAdapter); 361 sm.setListener(mListener); 362 sm.setInitialStateForTesting(initialState, initialDevice); 363 waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT); 364 resetMocks(); 365 return sm; 366 } 367 resetMocks()368 private void resetMocks() { 369 clearInvocations(mDeviceManager, mListener, mHeadsetProxy, mTimeoutsAdapter); 370 } 371 372 @Parameterized.Parameters(name = "{0}") generateTestCases()373 public static Collection<BluetoothRouteTestParameters> generateTestCases() { 374 List<BluetoothRouteTestParameters> result = new ArrayList<>(); 375 result.add(new BluetoothRouteTestParametersBuilder() 376 .setName("New device connected while audio off") 377 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 378 .setInitialDevice(null) 379 .setConnectedDevices(DEVICE1) 380 .setMessageType(BluetoothRouteManager.NEW_DEVICE_CONNECTED) 381 .setMessageDevice(DEVICE1) 382 .setExpectedListenerUpdates(ListenerUpdate.DEVICE_LIST_CHANGED, 383 ListenerUpdate.ACTIVE_DEVICE_PRESENT) 384 .setExpectedBluetoothInteraction(NONE) 385 .setExpectedConnectionDevice(null) 386 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 387 .build()); 388 389 result.add(new BluetoothRouteTestParametersBuilder() 390 .setName("Nonspecific connection request while audio off with BT-active device") 391 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 392 .setInitialDevice(null) 393 .setConnectedDevices(DEVICE2, DEVICE1) 394 .setActiveDevice(DEVICE1) 395 .setMessageType(BluetoothRouteManager.CONNECT_HFP) 396 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED) 397 .setExpectedBluetoothInteraction(CONNECT) 398 .setExpectedConnectionDevice(DEVICE1) 399 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 400 + ":" + DEVICE1) 401 .build()); 402 403 result.add(new BluetoothRouteTestParametersBuilder() 404 .setName("Connection to a device succeeds after pending") 405 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 406 .setInitialDevice(DEVICE2) 407 .setAudioOnDevice(DEVICE2) 408 .setConnectedDevices(DEVICE2, DEVICE1) 409 .setMessageType(BluetoothRouteManager.BT_AUDIO_IS_ON) 410 .setMessageDevice(DEVICE2) 411 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED) 412 .setExpectedBluetoothInteraction(NONE) 413 .setExpectedConnectionDevice(null) 414 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 415 + ":" + DEVICE2) 416 .build()); 417 418 result.add(new BluetoothRouteTestParametersBuilder() 419 .setName("Device loses HFP audio but remains connected. No fallback.") 420 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 421 .setInitialDevice(DEVICE2) 422 .setConnectedDevices(DEVICE2) 423 .setMessageType(BluetoothRouteManager.BT_AUDIO_LOST) 424 .setMessageDevice(DEVICE2) 425 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED) 426 .setExpectedBluetoothInteraction(NONE) 427 .setExpectedConnectionDevice(null) 428 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 429 .build()); 430 431 result.add(new BluetoothRouteTestParametersBuilder() 432 .setName("Device loses HFP audio but remains connected." 433 + " No fallback even though other devices available.") 434 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 435 .setInitialDevice(DEVICE2) 436 .setConnectedDevices(DEVICE2, DEVICE1, DEVICE3) 437 .setMessageType(BluetoothRouteManager.BT_AUDIO_LOST) 438 .setMessageDevice(DEVICE2) 439 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED) 440 .setExpectedBluetoothInteraction(NONE) 441 .setExpectedConnectionDevice(null) 442 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 443 .build()); 444 445 result.add(new BluetoothRouteTestParametersBuilder() 446 .setName("Switch the device that audio is being routed to") 447 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 448 .setInitialDevice(DEVICE2) 449 .setConnectedDevices(DEVICE2, DEVICE1, DEVICE3) 450 .setMessageType(BluetoothRouteManager.CONNECT_HFP) 451 .setMessageDevice(DEVICE3) 452 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED) 453 .setExpectedBluetoothInteraction(CONNECT) 454 .setExpectedConnectionDevice(DEVICE3) 455 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 456 + ":" + DEVICE3) 457 .build()); 458 459 result.add(new BluetoothRouteTestParametersBuilder() 460 .setName("Switch to another device before first device has connected") 461 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 462 .setInitialDevice(DEVICE2) 463 .setConnectedDevices(DEVICE2, DEVICE1, DEVICE3) 464 .setMessageType(BluetoothRouteManager.CONNECT_HFP) 465 .setMessageDevice(DEVICE3) 466 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED) 467 .setExpectedBluetoothInteraction(CONNECT) 468 .setExpectedConnectionDevice(DEVICE3) 469 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX 470 + ":" + DEVICE3) 471 .build()); 472 473 result.add(new BluetoothRouteTestParametersBuilder() 474 .setName("Device gets disconnected while active. No fallback.") 475 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 476 .setInitialDevice(DEVICE2) 477 .setActiveDevice(DEVICE2) 478 .setConnectedDevices() 479 .setMessageType(BluetoothRouteManager.LOST_DEVICE) 480 .setMessageDevice(DEVICE2) 481 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED, 482 ListenerUpdate.DEVICE_LIST_CHANGED, ListenerUpdate.ACTIVE_DEVICE_GONE) 483 .setExpectedBluetoothInteraction(NONE) 484 .setExpectedConnectionDevice(null) 485 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 486 .build()); 487 488 result.add(new BluetoothRouteTestParametersBuilder() 489 .setName("Device gets disconnected while active." 490 + " No fallback even though other devices available.") 491 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 492 .setInitialDevice(DEVICE2) 493 .setConnectedDevices(DEVICE3) 494 .setMessageType(BluetoothRouteManager.LOST_DEVICE) 495 .setMessageDevice(DEVICE2) 496 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED, 497 ListenerUpdate.DEVICE_LIST_CHANGED) 498 .setExpectedBluetoothInteraction(NONE) 499 .setExpectedConnectionDevice(null) 500 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 501 .build()); 502 503 result.add(new BluetoothRouteTestParametersBuilder() 504 .setName("Connection to DEVICE2 times out but device 1 still connected.") 505 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 506 .setInitialDevice(DEVICE2) 507 .setConnectedDevices(DEVICE2, DEVICE1) 508 .setAudioOnDevice(DEVICE1) 509 .setMessageType(BluetoothRouteManager.CONNECTION_TIMEOUT) 510 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED) 511 .setExpectedBluetoothInteraction(NONE) 512 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 513 + ":" + DEVICE1) 514 .build()); 515 516 result.add(new BluetoothRouteTestParametersBuilder() 517 .setName("DEVICE1 somehow becomes active when DEVICE2 is still pending.") 518 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 519 .setInitialDevice(DEVICE2) 520 .setConnectedDevices(DEVICE2, DEVICE1) 521 .setAudioOnDevice(DEVICE1) 522 .setMessageType(BluetoothRouteManager.BT_AUDIO_IS_ON) 523 .setMessageDevice(DEVICE1) 524 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED) 525 .setExpectedBluetoothInteraction(NONE) 526 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 527 + ":" + DEVICE1) 528 .build()); 529 530 result.add(new BluetoothRouteTestParametersBuilder() 531 .setName("Device gets disconnected while pending." 532 + " No fallback even though other devices available.") 533 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 534 .setInitialDevice(DEVICE2) 535 .setConnectedDevices(DEVICE3) 536 .setMessageType(BluetoothRouteManager.LOST_DEVICE) 537 .setMessageDevice(DEVICE2) 538 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED, 539 ListenerUpdate.DEVICE_LIST_CHANGED) 540 .setExpectedBluetoothInteraction(NONE) 541 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 542 .build()); 543 544 result.add(new BluetoothRouteTestParametersBuilder() 545 .setName("Audio disconnect comes with a null device") 546 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 547 .setInitialDevice(DEVICE2) 548 .setConnectedDevices(DEVICE2) 549 .setMessageType(BluetoothRouteManager.BT_AUDIO_LOST) 550 .setMessageDevice(null) 551 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED) 552 .setExpectedBluetoothInteraction(NONE) 553 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 554 .build()); 555 556 result.add(new BluetoothRouteTestParametersBuilder() 557 .setName("Device gets disconnected while pending. No fallback.") 558 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 559 .setInitialDevice(DEVICE2) 560 .setConnectedDevices() 561 .setMessageType(BluetoothRouteManager.LOST_DEVICE) 562 .setMessageDevice(DEVICE2) 563 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED, 564 ListenerUpdate.DEVICE_LIST_CHANGED) 565 .setExpectedBluetoothInteraction(NONE) 566 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 567 .build()); 568 569 result.add(new BluetoothRouteTestParametersBuilder() 570 .setName("Device gets audio-off while in another device's audio on state") 571 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 572 .setInitialDevice(DEVICE2) 573 .setConnectedDevices(DEVICE2, DEVICE1) 574 .setMessageType(BluetoothRouteManager.BT_AUDIO_LOST) 575 .setMessageDevice(DEVICE1) 576 .setExpectedListenerUpdates(ListenerUpdate.UNEXPECTED_STATE_CHANGE) 577 .setExpectedBluetoothInteraction(NONE) 578 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 579 + ":" + DEVICE2) 580 .build()); 581 582 result.add(new BluetoothRouteTestParametersBuilder() 583 .setName("Audio routing requests HFP disconnection while a device is active") 584 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 585 .setInitialDevice(DEVICE2) 586 .setConnectedDevices(DEVICE2, DEVICE3) 587 .setMessageType(BluetoothRouteManager.DISCONNECT_HFP) 588 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED) 589 .setExpectedBluetoothInteraction(DISCONNECT) 590 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 591 .build()); 592 593 result.add(new BluetoothRouteTestParametersBuilder() 594 .setName("Audio routing requests HFP disconnection while a device is pending") 595 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX) 596 .setInitialDevice(DEVICE2) 597 .setConnectedDevices(DEVICE2, DEVICE3) 598 .setMessageType(BluetoothRouteManager.DISCONNECT_HFP) 599 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED) 600 .setExpectedBluetoothInteraction(DISCONNECT) 601 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 602 .build()); 603 604 result.add(new BluetoothRouteTestParametersBuilder() 605 .setName("Bluetooth turns itself on.") 606 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 607 .setInitialDevice(null) 608 .setConnectedDevices(DEVICE2, DEVICE3) 609 .setMessageType(BluetoothRouteManager.BT_AUDIO_IS_ON) 610 .setMessageDevice(DEVICE3) 611 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED) 612 .setExpectedBluetoothInteraction(NONE) 613 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX 614 + ":" + DEVICE3) 615 .build()); 616 617 result.add(new BluetoothRouteTestParametersBuilder() 618 .setName("Hearing aid device disconnects with headset present") 619 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX) 620 .setInitialDevice(DEVICE2) 621 .setConnectedDevices(DEVICE2, DEVICE3) 622 .setHearingAidBtDevices(Collections.singletonList(DEVICE2)) 623 .setMessageType(BluetoothRouteManager.LOST_DEVICE) 624 .setMessageDevice(DEVICE2) 625 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED, 626 ListenerUpdate.DEVICE_LIST_CHANGED) 627 .setExpectedBluetoothInteraction(NONE) 628 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME) 629 .build()); 630 return result; 631 } 632 } 633