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