• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.server.telecom.tests.BluetoothRouteManagerTest.DEVICE1;
20 import static com.android.server.telecom.tests.BluetoothRouteManagerTest.DEVICE2;
21 import static com.android.server.telecom.tests.BluetoothRouteManagerTest.DEVICE3;
22 import static com.android.server.telecom.tests.BluetoothRouteManagerTest.executeRoutingAction;
23 
24 import static org.junit.Assert.assertEquals;
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.ArgumentMatchers.eq;
27 import static org.mockito.ArgumentMatchers.nullable;
28 import static org.mockito.Mockito.clearInvocations;
29 import static org.mockito.Mockito.doAnswer;
30 import static org.mockito.Mockito.never;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 
34 import android.bluetooth.BluetoothAdapter;
35 import android.bluetooth.BluetoothDevice;
36 import android.bluetooth.BluetoothHeadset;
37 import android.bluetooth.BluetoothHearingAid;
38 import android.bluetooth.BluetoothLeAudio;
39 import android.bluetooth.BluetoothProfile;
40 import android.bluetooth.BluetoothStatusCodes;
41 import android.content.ContentResolver;
42 import android.telecom.Log;
43 
44 import androidx.test.filters.SmallTest;
45 
46 import com.android.internal.os.SomeArgs;
47 import com.android.server.telecom.CallAudioCommunicationDeviceTracker;
48 import com.android.server.telecom.TelecomSystem;
49 import com.android.server.telecom.Timeouts;
50 import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
51 import com.android.server.telecom.bluetooth.BluetoothRouteManager;
52 
53 import org.junit.After;
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 import org.junit.runners.Parameterized;
58 import org.mockito.Mock;
59 
60 import java.util.ArrayList;
61 import java.util.Arrays;
62 import java.util.Collection;
63 import java.util.Collections;
64 import java.util.List;
65 import java.util.stream.Collectors;
66 
67 @RunWith(Parameterized.class)
68 public class BluetoothRouteTransitionTests extends TelecomTestCase {
69     private enum ListenerUpdate {
70         DEVICE_LIST_CHANGED, ACTIVE_DEVICE_PRESENT, ACTIVE_DEVICE_GONE,
71         AUDIO_CONNECTING, AUDIO_CONNECTED, AUDIO_DISCONNECTED, UNEXPECTED_STATE_CHANGE
72     }
73 
74     private static class BluetoothRouteTestParametersBuilder {
75         private String name;
76         private String initialBluetoothState;
77         private BluetoothDevice initialDevice;
78         private BluetoothDevice audioOnDevice;
79         private int messageType;
80         private BluetoothDevice messageDevice;
81         private ListenerUpdate[] expectedListenerUpdates;
82         private int expectedBluetoothInteraction;
83         private BluetoothDevice expectedConnectionDevice;
84         private String expectedFinalStateName;
85         private BluetoothDevice[] connectedDevices;
86         // the active device as returned by BluetoothAdapter#getActiveDevices
87         private BluetoothDevice activeDevice = null;
88         private List<BluetoothDevice> hearingAidBtDevices = Collections.emptyList();
89         private List<BluetoothDevice> leAudioDevices = Collections.emptyList();
90 
setName(String name)91         public BluetoothRouteTestParametersBuilder setName(String name) {
92             this.name = name;
93             return this;
94         }
95 
setInitialBluetoothState( String initialBluetoothState)96         public BluetoothRouteTestParametersBuilder setInitialBluetoothState(
97                 String initialBluetoothState) {
98             this.initialBluetoothState = initialBluetoothState;
99             return this;
100         }
101 
setInitialDevice(BluetoothDevice initialDevice)102         public BluetoothRouteTestParametersBuilder setInitialDevice(BluetoothDevice
103                 initialDevice) {
104             this.initialDevice = initialDevice;
105             return this;
106         }
107 
setMessageType(int messageType)108         public BluetoothRouteTestParametersBuilder setMessageType(int messageType) {
109             this.messageType = messageType;
110             return this;
111         }
112 
setMessageDevice(BluetoothDevice messageDevice)113         public BluetoothRouteTestParametersBuilder setMessageDevice(BluetoothDevice messageDevice) {
114             this.messageDevice = messageDevice;
115             return this;
116         }
117 
setExpectedListenerUpdates( ListenerUpdate... expectedListenerUpdates)118         public BluetoothRouteTestParametersBuilder setExpectedListenerUpdates(
119                 ListenerUpdate... expectedListenerUpdates) {
120             this.expectedListenerUpdates = expectedListenerUpdates;
121             return this;
122         }
123 
setExpectedBluetoothInteraction( int expectedBluetoothInteraction)124         public BluetoothRouteTestParametersBuilder setExpectedBluetoothInteraction(
125                 int expectedBluetoothInteraction) {
126             this.expectedBluetoothInteraction = expectedBluetoothInteraction;
127             return this;
128         }
129 
setExpectedConnectionDevice( BluetoothDevice expectedConnectionDevice)130         public BluetoothRouteTestParametersBuilder setExpectedConnectionDevice(
131                 BluetoothDevice expectedConnectionDevice) {
132             this.expectedConnectionDevice = expectedConnectionDevice;
133             return this;
134         }
135 
setExpectedFinalStateName( String expectedFinalStateName)136         public BluetoothRouteTestParametersBuilder setExpectedFinalStateName(
137                 String expectedFinalStateName) {
138             this.expectedFinalStateName = expectedFinalStateName;
139             return this;
140         }
141 
setConnectedDevices( BluetoothDevice... connectedDevices)142         public BluetoothRouteTestParametersBuilder setConnectedDevices(
143                 BluetoothDevice... connectedDevices) {
144             this.connectedDevices = connectedDevices;
145             return this;
146         }
147 
setAudioOnDevice(BluetoothDevice device)148         public BluetoothRouteTestParametersBuilder setAudioOnDevice(BluetoothDevice device) {
149             this.audioOnDevice = device;
150             return this;
151         }
152 
setActiveDevice(BluetoothDevice device)153         public BluetoothRouteTestParametersBuilder setActiveDevice(BluetoothDevice device) {
154             this.activeDevice = device;
155             return this;
156         }
157 
setHearingAidBtDevices( List<BluetoothDevice> hearingAidBtDevices)158         public BluetoothRouteTestParametersBuilder setHearingAidBtDevices(
159                 List<BluetoothDevice> hearingAidBtDevices) {
160             this.hearingAidBtDevices = hearingAidBtDevices;
161             return this;
162         }
163 
setLeAudioDevices( List<BluetoothDevice> leAudioDevices)164         public BluetoothRouteTestParametersBuilder setLeAudioDevices(
165                 List<BluetoothDevice> leAudioDevices) {
166             this.leAudioDevices = leAudioDevices;
167             return this;
168         }
169 
build()170         public BluetoothRouteTestParameters build() {
171             return new BluetoothRouteTestParameters(name,
172                     initialBluetoothState,
173                     initialDevice,
174                     messageType,
175                     expectedListenerUpdates,
176                     expectedBluetoothInteraction,
177                     expectedConnectionDevice,
178                     expectedFinalStateName,
179                     connectedDevices,
180                     messageDevice,
181                     audioOnDevice,
182                     activeDevice,
183                     hearingAidBtDevices,
184                     leAudioDevices);
185 
186         }
187     }
188 
189     private static class BluetoothRouteTestParameters {
190         public String name;
191         public String initialBluetoothState; // One of the state names or prefixes from BRM.
192         public BluetoothDevice initialDevice; // null if we start from AudioOff
193         public BluetoothDevice audioOnDevice; // The device (if any) that is active
194         public int messageType; // Any of the commands from the state machine
195         public BluetoothDevice messageDevice; // The device that should be specified in the message.
196         public ListenerUpdate[] expectedListenerUpdates; // what the listener should expect.
197         // NONE, CONNECT, CONNECT_SWITCH_DEVICE or DISCONNECT
198         public int expectedBluetoothInteraction;
199         public BluetoothDevice expectedConnectionDevice; // Expected device to connect to.
200         public String expectedFinalStateName; // Expected name of the final state.
201         public BluetoothDevice[] connectedDevices; // array of connected devices
202         // the active device as returned by BluetoothAdapter#getActiveDevices
203         private BluetoothDevice activeDevice = null;
204         private List<BluetoothDevice> hearingAidBtDevices;
205         private List<BluetoothDevice> leAudioDevices;
206 
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, List<BluetoothDevice> leAudioDevices)207         public BluetoothRouteTestParameters(String name, String initialBluetoothState,
208                 BluetoothDevice initialDevice, int messageType, ListenerUpdate[]
209                 expectedListenerUpdates, int expectedBluetoothInteraction, BluetoothDevice
210                 expectedConnectionDevice, String expectedFinalStateName,
211                 BluetoothDevice[] connectedDevices, BluetoothDevice messageDevice,
212                 BluetoothDevice audioOnDevice, BluetoothDevice activeDevice,
213                 List<BluetoothDevice> hearingAidBtDevices, List<BluetoothDevice> leAudioDevices) {
214             this.name = name;
215             this.initialBluetoothState = initialBluetoothState;
216             this.initialDevice = initialDevice;
217             this.messageType = messageType;
218             this.expectedListenerUpdates = expectedListenerUpdates;
219             this.expectedBluetoothInteraction = expectedBluetoothInteraction;
220             this.expectedConnectionDevice = expectedConnectionDevice;
221             this.expectedFinalStateName = expectedFinalStateName;
222             this.connectedDevices = connectedDevices;
223             this.messageDevice = messageDevice;
224             this.audioOnDevice = audioOnDevice;
225             this.activeDevice = activeDevice;
226             this.hearingAidBtDevices = hearingAidBtDevices;
227             this.leAudioDevices = leAudioDevices;
228         }
229 
230         @Override
toString()231         public String toString() {
232             String expectedListenerUpdatesStr = expectedListenerUpdates == null ? ""
233                     : Arrays.stream(expectedListenerUpdates).map(ListenerUpdate::name)
234                             .collect(Collectors.joining(","));
235             return "BluetoothRouteTestParameters{" +
236                     "name='" + name + '\'' +
237                     ", initialBluetoothState='" + initialBluetoothState + '\'' +
238                     ", initialDevice=" + initialDevice +
239                     ", messageType=" + messageType +
240                     ", messageDevice='" + messageDevice + '\'' +
241                     ", expectedListenerUpdate='" + expectedListenerUpdatesStr + '\'' +
242                     ", expectedBluetoothInteraction=" + expectedBluetoothInteraction +
243                     ", expectedConnectionDevice='" + expectedConnectionDevice + '\'' +
244                     ", expectedFinalStateName='" + expectedFinalStateName + '\'' +
245                     ", connectedDevices=" + Arrays.toString(connectedDevices) +
246                     ", activeDevice='" + activeDevice + '\'' +
247                     ", hearingAidBtDevices ='" + hearingAidBtDevices + '\'' +
248                     ", leAudioDevices ='" + leAudioDevices + '\'' +
249                     '}';
250         }
251     }
252 
253     private static final int NONE = 1;
254     private static final int CONNECT = 2;
255     private static final int DISCONNECT = 3;
256     private static final int CONNECT_SWITCH_DEVICE = 4;
257 
258     private static final int TEST_TIMEOUT = 1000;
259 
260     private final BluetoothRouteTestParameters mParams;
261     @Mock private BluetoothDeviceManager mDeviceManager;
262     @Mock private BluetoothAdapter mBluetoothAdapter;
263     @Mock private BluetoothHeadset mBluetoothHeadset;
264     @Mock private BluetoothHearingAid mBluetoothHearingAid;
265     @Mock private BluetoothLeAudio mBluetoothLeAudio;
266     @Mock private Timeouts.Adapter mTimeoutsAdapter;
267     @Mock private BluetoothRouteManager.BluetoothStateListener mListener;
268     @Mock private CallAudioCommunicationDeviceTracker mCommunicationDeviceTracker;
269 
270     @Override
271     @Before
setUp()272     public void setUp() throws Exception {
273         super.setUp();
274         when(mDeviceManager.getBluetoothAdapter()).thenReturn(mBluetoothAdapter);
275     }
276 
277     @Override
278     @After
tearDown()279     public void tearDown() throws Exception {
280         super.tearDown();
281     }
282 
BluetoothRouteTransitionTests(BluetoothRouteTestParameters params)283     public BluetoothRouteTransitionTests(BluetoothRouteTestParameters params) {
284         mParams = params;
285     }
286 
287     @Test
288     @SmallTest
testTransitions()289     public void testTransitions() {
290         BluetoothRouteManager sm = setupStateMachine(
291                 mParams.initialBluetoothState, mParams.initialDevice);
292 
293         int deviceType = BluetoothDeviceManager.DEVICE_TYPE_HEADSET;
294         if (mParams.hearingAidBtDevices.contains(mParams.messageDevice)) {
295             deviceType = BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID;
296         } else if (mParams.hearingAidBtDevices.contains(mParams.messageDevice)) {
297             deviceType = BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO;
298         }
299 
300         setupConnectedDevices(mParams.connectedDevices,
301                 mParams.audioOnDevice, mParams.activeDevice);
302         sm.setActiveDeviceCacheForTesting(mParams.activeDevice, deviceType);
303         if (mParams.initialDevice != null) {
304             doAnswer(invocation -> {
305                 SomeArgs args = SomeArgs.obtain();
306                 args.arg1 = Log.createSubsession();
307                 args.arg2 = mParams.initialDevice.getAddress();
308                 when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
309                     .thenReturn(Arrays.asList((BluetoothDevice) null));
310                 sm.sendMessage(BluetoothRouteManager.BT_AUDIO_LOST, args);
311                 return BluetoothStatusCodes.SUCCESS;
312             }).when(mDeviceManager).disconnectAudio();
313         }
314 
315         // Go through the utility methods for these two messages
316         if (mParams.messageType == BluetoothRouteManager.NEW_DEVICE_CONNECTED) {
317             sm.onDeviceAdded(mParams.messageDevice.getAddress());
318             sm.onActiveDeviceChanged(mParams.messageDevice, deviceType);
319         } else if (mParams.messageType == BluetoothRouteManager.LOST_DEVICE) {
320             sm.onActiveDeviceChanged(null, deviceType);
321             if (mParams.hearingAidBtDevices.contains(mParams.messageDevice)) {
322                 when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEARING_AID)))
323                     .thenReturn(Arrays.asList(null, null));
324                 when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.LE_AUDIO)))
325                     .thenReturn(mParams.leAudioDevices.stream()
326                        .filter(device -> device != mParams.messageDevice)
327                        .collect(Collectors.toList()));
328             } else {
329                 when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
330                     .thenReturn(Arrays.asList((BluetoothDevice) null));
331             }
332             sm.onDeviceLost(mParams.messageDevice.getAddress());
333         } else {
334             executeRoutingAction(sm, mParams.messageType,
335                     mParams.messageDevice == null ? null : mParams.messageDevice.getAddress());
336         }
337 
338         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
339         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
340         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
341         assertEquals(mParams.expectedFinalStateName, sm.getCurrentState().getName());
342 
343         for (ListenerUpdate lu : mParams.expectedListenerUpdates) {
344             switch (lu) {
345                 case DEVICE_LIST_CHANGED:
346                     verify(mListener).onBluetoothDeviceListChanged();
347                     break;
348                 case ACTIVE_DEVICE_PRESENT:
349                     verify(mListener).onBluetoothActiveDevicePresent();
350                     break;
351                 case ACTIVE_DEVICE_GONE:
352                     verify(mListener).onBluetoothActiveDeviceGone();
353                     break;
354                 case AUDIO_CONNECTING:
355                     verify(mListener).onBluetoothAudioConnecting();
356                     break;
357                 case AUDIO_CONNECTED:
358                     verify(mListener).onBluetoothAudioConnected();
359                     break;
360                 case AUDIO_DISCONNECTED:
361                     verify(mListener).onBluetoothAudioDisconnected();
362                     break;
363             }
364         }
365 
366         switch (mParams.expectedBluetoothInteraction) {
367             case NONE:
368                 verify(mDeviceManager, never()).connectAudio(nullable(String.class),
369                     any(boolean.class));
370                 break;
371             case CONNECT:
372                 verify(mDeviceManager).connectAudio(mParams.expectedConnectionDevice.getAddress(),
373                     false);
374                 verify(mDeviceManager, never()).disconnectAudio();
375                 break;
376             case CONNECT_SWITCH_DEVICE:
377                 verify(mDeviceManager).disconnectAudio();
378                 verify(mDeviceManager).connectAudio(mParams.expectedConnectionDevice.getAddress(),
379                     true);
380             break;
381             case DISCONNECT:
382                 verify(mDeviceManager, never()).connectAudio(nullable(String.class),
383                     any(boolean.class));
384                 verify(mDeviceManager).disconnectAudio();
385                 break;
386         }
387 
388         sm.getHandler().removeMessages(BluetoothRouteManager.CONNECTION_TIMEOUT);
389         sm.quitNow();
390     }
391 
setupConnectedDevices(BluetoothDevice[] devices, BluetoothDevice audioOnDevice, BluetoothDevice activeDevice)392     private void setupConnectedDevices(BluetoothDevice[] devices,
393             BluetoothDevice audioOnDevice, BluetoothDevice activeDevice) {
394         when(mDeviceManager.getNumConnectedDevices()).thenReturn(devices.length);
395         when(mDeviceManager.getConnectedDevices()).thenReturn(Arrays.asList(devices));
396         when(mBluetoothHeadset.getConnectedDevices()).thenReturn(Arrays.asList(devices));
397         when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
398             .thenReturn(Arrays.asList(activeDevice));
399         when(mBluetoothHeadset.getAudioState(nullable(BluetoothDevice.class)))
400                 .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
401         if (audioOnDevice != null) {
402             when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
403                 .thenReturn(Arrays.asList(audioOnDevice));
404             when(mBluetoothHeadset.getAudioState(audioOnDevice))
405                     .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED);
406         }
407     }
408 
setupStateMachine(String initialState, BluetoothDevice initialDevice)409     private BluetoothRouteManager setupStateMachine(String initialState,
410             BluetoothDevice initialDevice) {
411         resetMocks();
412         when(mDeviceManager.getBluetoothHeadset()).thenReturn(mBluetoothHeadset);
413         when(mDeviceManager.getBluetoothHearingAid()).thenReturn(mBluetoothHearingAid);
414         when(mDeviceManager.getLeAudioService()).thenReturn(mBluetoothLeAudio);
415         when(mDeviceManager.connectAudio(nullable(String.class), any(boolean.class)))
416             .thenReturn(true);
417         when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
418                 nullable(ContentResolver.class))).thenReturn(100000L);
419         when(mTimeoutsAdapter.getBluetoothPendingTimeoutMillis(
420                 nullable(ContentResolver.class))).thenReturn(100000L);
421         BluetoothRouteManager sm = new BluetoothRouteManager(mContext,
422                 new TelecomSystem.SyncRoot() { }, mDeviceManager,
423                 mTimeoutsAdapter, mCommunicationDeviceTracker, mFeatureFlags,
424                 mContext.getMainLooper());
425         sm.setListener(mListener);
426         sm.setInitialStateForTesting(initialState, initialDevice);
427         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
428         resetMocks();
429         return sm;
430     }
431 
resetMocks()432     private void resetMocks() {
433         clearInvocations(mDeviceManager, mListener, mBluetoothHeadset, mTimeoutsAdapter);
434     }
435 
436     @Parameterized.Parameters(name = "{0}")
generateTestCases()437     public static Collection<BluetoothRouteTestParameters> generateTestCases() {
438         List<BluetoothRouteTestParameters> result = new ArrayList<>();
439         result.add(new BluetoothRouteTestParametersBuilder()
440                 .setName("New device connected while audio off")
441                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
442                 .setInitialDevice(null)
443                 .setConnectedDevices(DEVICE1)
444                 .setMessageType(BluetoothRouteManager.NEW_DEVICE_CONNECTED)
445                 .setMessageDevice(DEVICE1)
446                 .setExpectedListenerUpdates(ListenerUpdate.DEVICE_LIST_CHANGED,
447                         ListenerUpdate.ACTIVE_DEVICE_PRESENT)
448                 .setExpectedBluetoothInteraction(NONE)
449                 .setExpectedConnectionDevice(null)
450                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
451                 .build());
452 
453         result.add(new BluetoothRouteTestParametersBuilder()
454                 .setName("Nonspecific connection request while audio off with BT-active device")
455                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
456                 .setInitialDevice(null)
457                 .setConnectedDevices(DEVICE2, DEVICE1)
458                 .setActiveDevice(DEVICE1)
459                 .setMessageType(BluetoothRouteManager.CONNECT_BT)
460                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTING)
461                 .setExpectedBluetoothInteraction(CONNECT)
462                 .setExpectedConnectionDevice(DEVICE1)
463                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
464                         + ":" + DEVICE1)
465                 .build());
466 
467         result.add(new BluetoothRouteTestParametersBuilder()
468                 .setName("Connection to a device succeeds after pending")
469                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX)
470                 .setInitialDevice(DEVICE2)
471                 .setAudioOnDevice(DEVICE2)
472                 .setConnectedDevices(DEVICE2, DEVICE1)
473                 .setMessageType(BluetoothRouteManager.BT_AUDIO_IS_ON)
474                 .setMessageDevice(DEVICE2)
475                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
476                 .setExpectedBluetoothInteraction(NONE)
477                 .setExpectedConnectionDevice(null)
478                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
479                         + ":" + DEVICE2)
480                 .build());
481 
482         result.add(new BluetoothRouteTestParametersBuilder()
483                 .setName("Device loses BT audio but remains connected. No fallback.")
484                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
485                 .setInitialDevice(DEVICE2)
486                 .setConnectedDevices(DEVICE2)
487                 .setMessageType(BluetoothRouteManager.BT_AUDIO_LOST)
488                 .setMessageDevice(DEVICE2)
489                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED)
490                 .setExpectedBluetoothInteraction(NONE)
491                 .setExpectedConnectionDevice(null)
492                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
493                 .build());
494 
495         result.add(new BluetoothRouteTestParametersBuilder()
496                 .setName("Device loses BT audio but remains connected."
497                         + " No fallback even though other devices available.")
498                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
499                 .setInitialDevice(DEVICE2)
500                 .setConnectedDevices(DEVICE2, DEVICE1, DEVICE3)
501                 .setMessageType(BluetoothRouteManager.BT_AUDIO_LOST)
502                 .setMessageDevice(DEVICE2)
503                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED)
504                 .setExpectedBluetoothInteraction(NONE)
505                 .setExpectedConnectionDevice(null)
506                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
507                 .build());
508 
509         result.add(new BluetoothRouteTestParametersBuilder()
510                 .setName("Switch the device that audio is being routed to")
511                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
512                 .setInitialDevice(DEVICE2)
513                 .setConnectedDevices(DEVICE2, DEVICE1, DEVICE3)
514                 .setMessageType(BluetoothRouteManager.CONNECT_BT)
515                 .setMessageDevice(DEVICE3)
516                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTING)
517                 .setExpectedBluetoothInteraction(CONNECT_SWITCH_DEVICE)
518                 .setExpectedConnectionDevice(DEVICE3)
519                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
520                         + ":" + DEVICE3)
521                 .build());
522 
523         result.add(new BluetoothRouteTestParametersBuilder()
524                 .setName("Switch to another device before first device has connected")
525                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX)
526                 .setInitialDevice(DEVICE2)
527                 .setConnectedDevices(DEVICE2, DEVICE1, DEVICE3)
528                 .setMessageType(BluetoothRouteManager.CONNECT_BT)
529                 .setMessageDevice(DEVICE3)
530                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTING)
531                 .setExpectedBluetoothInteraction(CONNECT_SWITCH_DEVICE)
532                 .setExpectedConnectionDevice(DEVICE3)
533                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
534                         + ":" + DEVICE3)
535                 .build());
536 
537         result.add(new BluetoothRouteTestParametersBuilder()
538                 .setName("Device gets disconnected while active. No fallback.")
539                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
540                 .setInitialDevice(DEVICE2)
541                 .setActiveDevice(DEVICE2)
542                 .setConnectedDevices()
543                 .setMessageType(BluetoothRouteManager.LOST_DEVICE)
544                 .setMessageDevice(DEVICE2)
545                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED,
546                         ListenerUpdate.DEVICE_LIST_CHANGED, ListenerUpdate.ACTIVE_DEVICE_GONE)
547                 .setExpectedBluetoothInteraction(NONE)
548                 .setExpectedConnectionDevice(null)
549                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
550                 .build());
551 
552         result.add(new BluetoothRouteTestParametersBuilder()
553                 .setName("Device gets disconnected while active."
554                         + " No fallback even though other devices available.")
555                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
556                 .setInitialDevice(DEVICE2)
557                 .setConnectedDevices(DEVICE3)
558                 .setMessageType(BluetoothRouteManager.LOST_DEVICE)
559                 .setMessageDevice(DEVICE2)
560                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED,
561                         ListenerUpdate.DEVICE_LIST_CHANGED)
562                 .setExpectedBluetoothInteraction(NONE)
563                 .setExpectedConnectionDevice(null)
564                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
565                 .build());
566 
567         result.add(new BluetoothRouteTestParametersBuilder()
568                 .setName("Connection to DEVICE2 times out but device 1 still connected.")
569                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX)
570                 .setInitialDevice(DEVICE2)
571                 .setConnectedDevices(DEVICE2, DEVICE1)
572                 .setAudioOnDevice(DEVICE1)
573                 .setMessageType(BluetoothRouteManager.CONNECTION_TIMEOUT)
574                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
575                 .setExpectedBluetoothInteraction(NONE)
576                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
577                         + ":" + DEVICE1)
578                 .build());
579 
580         result.add(new BluetoothRouteTestParametersBuilder()
581                 .setName("DEVICE1 somehow becomes active when DEVICE2 is still pending.")
582                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX)
583                 .setInitialDevice(DEVICE2)
584                 .setConnectedDevices(DEVICE2, DEVICE1)
585                 .setAudioOnDevice(DEVICE1)
586                 .setMessageType(BluetoothRouteManager.BT_AUDIO_IS_ON)
587                 .setMessageDevice(DEVICE1)
588                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
589                 .setExpectedBluetoothInteraction(NONE)
590                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
591                         + ":" + DEVICE1)
592                 .build());
593 
594         result.add(new BluetoothRouteTestParametersBuilder()
595                 .setName("Device gets disconnected while pending."
596                         + " No fallback even though other devices available.")
597                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX)
598                 .setInitialDevice(DEVICE2)
599                 .setConnectedDevices(DEVICE3)
600                 .setMessageType(BluetoothRouteManager.LOST_DEVICE)
601                 .setMessageDevice(DEVICE2)
602                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED,
603                         ListenerUpdate.DEVICE_LIST_CHANGED)
604                 .setExpectedBluetoothInteraction(NONE)
605                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
606                 .build());
607 
608         result.add(new BluetoothRouteTestParametersBuilder()
609                 .setName("Audio disconnect comes with a null device")
610                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
611                 .setInitialDevice(DEVICE2)
612                 .setConnectedDevices(DEVICE2)
613                 .setMessageType(BluetoothRouteManager.BT_AUDIO_LOST)
614                 .setMessageDevice(null)
615                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED)
616                 .setExpectedBluetoothInteraction(NONE)
617                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
618                 .build());
619 
620         result.add(new BluetoothRouteTestParametersBuilder()
621                 .setName("Device gets disconnected while pending. No fallback.")
622                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX)
623                 .setInitialDevice(DEVICE2)
624                 .setConnectedDevices()
625                 .setMessageType(BluetoothRouteManager.LOST_DEVICE)
626                 .setMessageDevice(DEVICE2)
627                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED,
628                         ListenerUpdate.DEVICE_LIST_CHANGED)
629                 .setExpectedBluetoothInteraction(NONE)
630                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
631                 .build());
632 
633         result.add(new BluetoothRouteTestParametersBuilder()
634                 .setName("Device gets audio-off while in another device's audio on state")
635                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
636                 .setInitialDevice(DEVICE2)
637                 .setConnectedDevices(DEVICE2, DEVICE1)
638                 .setMessageType(BluetoothRouteManager.BT_AUDIO_LOST)
639                 .setMessageDevice(DEVICE1)
640                 .setExpectedListenerUpdates(ListenerUpdate.UNEXPECTED_STATE_CHANGE)
641                 .setExpectedBluetoothInteraction(NONE)
642                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
643                         + ":" + DEVICE2)
644                 .build());
645 
646         result.add(new BluetoothRouteTestParametersBuilder()
647                 .setName("Audio routing requests BT disconnection while a device is active")
648                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
649                 .setInitialDevice(DEVICE2)
650                 .setConnectedDevices(DEVICE2, DEVICE3)
651                 .setMessageType(BluetoothRouteManager.DISCONNECT_BT)
652                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED)
653                 .setExpectedBluetoothInteraction(DISCONNECT)
654                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
655                 .build());
656 
657         result.add(new BluetoothRouteTestParametersBuilder()
658                 .setName("Audio routing requests BT disconnection while a device is pending")
659                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX)
660                 .setInitialDevice(DEVICE2)
661                 .setConnectedDevices(DEVICE2, DEVICE3)
662                 .setMessageType(BluetoothRouteManager.DISCONNECT_BT)
663                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED)
664                 .setExpectedBluetoothInteraction(DISCONNECT)
665                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
666                 .build());
667 
668         result.add(new BluetoothRouteTestParametersBuilder()
669                 .setName("Bluetooth turns itself on.")
670                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
671                 .setInitialDevice(null)
672                 .setConnectedDevices(DEVICE2, DEVICE3)
673                 .setMessageType(BluetoothRouteManager.BT_AUDIO_IS_ON)
674                 .setMessageDevice(DEVICE3)
675                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
676                 .setExpectedBluetoothInteraction(NONE)
677                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
678                         + ":" + DEVICE3)
679                 .build());
680 
681         result.add(new BluetoothRouteTestParametersBuilder()
682                 .setName("Hearing aid device disconnects with headset present")
683                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
684                 .setInitialDevice(DEVICE2)
685                 .setConnectedDevices(DEVICE2, DEVICE3)
686                 .setHearingAidBtDevices(Collections.singletonList(DEVICE2))
687                 .setMessageType(BluetoothRouteManager.LOST_DEVICE)
688                 .setMessageDevice(DEVICE2)
689                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED,
690                         ListenerUpdate.DEVICE_LIST_CHANGED)
691                 .setExpectedBluetoothInteraction(NONE)
692                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
693                 .build());
694 
695         result.add(new BluetoothRouteTestParametersBuilder()
696                 .setName("connect BT to an already active device when in audio off.")
697                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
698                 .setAudioOnDevice(DEVICE2)
699                 .setActiveDevice(DEVICE2)
700                 .setConnectedDevices(DEVICE2, DEVICE3)
701                 .setHearingAidBtDevices(Collections.singletonList(DEVICE2))
702                 .setMessageType(BluetoothRouteManager.CONNECT_BT)
703                 .setMessageDevice(DEVICE2)
704                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
705                 .setExpectedBluetoothInteraction(NONE)
706                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
707                         + ":" + DEVICE2)
708                 .build());
709 
710         result.add(new BluetoothRouteTestParametersBuilder()
711                 .setName("le audio device disconnects with hearing aid present")
712                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
713                 .setInitialDevice(DEVICE2)
714                 .setConnectedDevices(DEVICE2, DEVICE3)
715                 .setLeAudioDevices(Collections.singletonList(DEVICE2))
716                 .setHearingAidBtDevices(Collections.singletonList(DEVICE3))
717                 .setMessageType(BluetoothRouteManager.LOST_DEVICE)
718                 .setMessageDevice(DEVICE2)
719                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED,
720                         ListenerUpdate.DEVICE_LIST_CHANGED)
721                 .setExpectedBluetoothInteraction(NONE)
722                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
723                 .build());
724 
725         result.add(new BluetoothRouteTestParametersBuilder()
726                 .setName("le audio device disconnects with another one connected")
727                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
728                 .setInitialDevice(DEVICE1)
729                 .setConnectedDevices(DEVICE1, DEVICE2, DEVICE3)
730                 .setHearingAidBtDevices(Collections.singletonList(DEVICE3))
731                 .setLeAudioDevices(Arrays.asList(DEVICE1, DEVICE2))
732                 .setMessageType(BluetoothRouteManager.LOST_DEVICE)
733                 .setMessageDevice(DEVICE1)
734                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED,
735                         ListenerUpdate.DEVICE_LIST_CHANGED)
736                 .setExpectedBluetoothInteraction(NONE)
737                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
738                 .build());
739 
740         return result;
741     }
742 }
743