• 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 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