CallAudioRouteStateMachineTest.java revision cff959e60f914754961fde4bcca1a97cd363d1ad
1/*
2 * Copyright (C) 2015 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.app.NotificationManager;
20import android.content.Context;
21import android.media.AudioManager;
22import android.media.IAudioService;
23import android.telecom.CallAudioState;
24import android.test.suitebuilder.annotation.LargeTest;
25import android.test.suitebuilder.annotation.MediumTest;
26import android.test.suitebuilder.annotation.SmallTest;
27
28import com.android.server.telecom.BluetoothManager;
29import com.android.server.telecom.Call;
30import com.android.server.telecom.CallAudioModeStateMachine;
31import com.android.server.telecom.CallAudioRouteStateMachine;
32import com.android.server.telecom.CallsManager;
33import com.android.server.telecom.ConnectionServiceWrapper;
34import com.android.server.telecom.CallAudioManager;
35import com.android.server.telecom.InterruptionFilterProxy;
36import com.android.server.telecom.StatusBarNotifier;
37import com.android.server.telecom.TelecomSystem;
38import com.android.server.telecom.WiredHeadsetManager;
39
40import org.mockito.ArgumentCaptor;
41import org.mockito.Mock;
42import org.mockito.MockitoAnnotations;
43import org.mockito.invocation.InvocationOnMock;
44import org.mockito.stubbing.Answer;
45
46import java.util.ArrayList;
47import java.util.List;
48import java.util.Objects;
49
50import static org.mockito.Matchers.any;
51import static org.mockito.Matchers.anyInt;
52import static org.mockito.Matchers.eq;
53import static org.mockito.Matchers.same;
54import static org.mockito.Mockito.doAnswer;
55import static org.mockito.Mockito.doNothing;
56import static org.mockito.Mockito.doReturn;
57import static org.mockito.Mockito.mock;
58import static org.mockito.Mockito.never;
59import static org.mockito.Mockito.reset;
60import static org.mockito.Mockito.timeout;
61import static org.mockito.Mockito.times;
62import static org.mockito.Mockito.verify;
63import static org.mockito.Mockito.when;
64
65
66public class CallAudioRouteStateMachineTest
67        extends StateMachineTestBase<CallAudioRouteStateMachine> {
68    private static final int NONE = 0;
69    private static final int ON = 1;
70    private static final int OFF = 2;
71
72    static class RoutingTestParameters extends TestParameters {
73        public String name;
74        public int initialRoute;
75        public int initialNotificationFilter;
76        public int availableRoutes; // may excl. speakerphone, because that's always available
77        public int speakerInteraction; // one of NONE, ON, or OFF
78        public int bluetoothInteraction; // one of NONE, ON, or OFF
79        public int action;
80        public int expectedRoute;
81        public int expectedAvailableRoutes; // also may exclude the speakerphone.
82        public int expectedNotificationFilter; // expected end notification filter.
83        public boolean isNotificationChangeExpected; // indicates whether we expect the notification
84                                                     // filter to change during the process of the
85                                                     // test.
86        public boolean doesDeviceSupportEarpiece; // set to false in the case of Wear devices
87        public boolean shouldRunWithFocus;
88
89        public int callSupportedRoutes = CallAudioState.ROUTE_ALL;
90
91        public RoutingTestParameters(String name, int initialRoute,
92                int initialNotificationFilter, int availableRoutes, int speakerInteraction,
93                int bluetoothInteraction, int action, int expectedRoute,
94                int expectedAvailableRoutes, int expectedNotificationFilter,
95                boolean isNotificationChangeExpected, boolean doesDeviceSupportEarpiece,
96                boolean shouldRunWithFocus) {
97            this.name = name;
98            this.initialRoute = initialRoute;
99            this.initialNotificationFilter = initialNotificationFilter;
100            this.availableRoutes = availableRoutes;
101            this.speakerInteraction = speakerInteraction;
102            this.bluetoothInteraction = bluetoothInteraction;
103            this.action = action;
104            this.expectedRoute = expectedRoute;
105            this.expectedAvailableRoutes = expectedAvailableRoutes;
106            this.expectedNotificationFilter = expectedNotificationFilter;
107            this.isNotificationChangeExpected = isNotificationChangeExpected;
108            this.doesDeviceSupportEarpiece = doesDeviceSupportEarpiece;
109            this.shouldRunWithFocus = shouldRunWithFocus;
110        }
111
112        public RoutingTestParameters setCallSupportedRoutes(int routes) {
113            callSupportedRoutes = routes;
114            return this;
115        }
116
117        @Override
118        public String toString() {
119            return "RoutingTestParameters{" +
120                    "name='" + name + '\'' +
121                    ", initialRoute=" + initialRoute +
122                    ", initialNotificationFilter=" + initialNotificationFilter +
123                    ", availableRoutes=" + availableRoutes +
124                    ", speakerInteraction=" + speakerInteraction +
125                    ", bluetoothInteraction=" + bluetoothInteraction +
126                    ", action=" + action +
127                    ", expectedRoute=" + expectedRoute +
128                    ", expectedAvailableRoutes=" + expectedAvailableRoutes +
129                    ", expectedNotificationFilter= " + expectedNotificationFilter +
130                    ", isNotificationChangeExpected=" + isNotificationChangeExpected +
131                    ", doesDeviceSupportEarpiece=" + doesDeviceSupportEarpiece +
132                    ", shouldRunWithFocus=" + shouldRunWithFocus +
133                    '}';
134        }
135    }
136
137    @Mock CallsManager mockCallsManager;
138    @Mock BluetoothManager mockBluetoothManager;
139    @Mock IAudioService mockAudioService;
140    @Mock ConnectionServiceWrapper mockConnectionServiceWrapper;
141    @Mock WiredHeadsetManager mockWiredHeadsetManager;
142    @Mock StatusBarNotifier mockStatusBarNotifier;
143    @Mock Call fakeCall;
144    @Mock InterruptionFilterProxy mMockInterruptionFilterProxy;
145
146    private CallAudioManager.AudioServiceFactory mAudioServiceFactory;
147    private static final int TEST_TIMEOUT = 500;
148    private AudioManager mockAudioManager;
149    private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
150
151    @Override
152    public void setUp() throws Exception {
153        super.setUp();
154        MockitoAnnotations.initMocks(this);
155        mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
156        mockAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
157
158        mAudioServiceFactory = new CallAudioManager.AudioServiceFactory() {
159            @Override
160            public IAudioService getAudioService() {
161                return mockAudioService;
162            }
163        };
164
165        when(mockCallsManager.getForegroundCall()).thenReturn(fakeCall);
166        when(mockCallsManager.getLock()).thenReturn(mLock);
167        when(fakeCall.getConnectionService()).thenReturn(mockConnectionServiceWrapper);
168        when(fakeCall.isAlive()).thenReturn(true);
169        when(fakeCall.getSupportedAudioRoutes()).thenReturn(CallAudioState.ROUTE_ALL);
170        setupInterruptionFilterMocks();
171
172        doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class),
173                any(CallAudioState.class));
174    }
175
176    private void setupInterruptionFilterMocks() {
177        // These mock implementations keep track of when the caller sets the current notification
178        // filter, and ensures the same value is returned via getCurrentInterruptionFilter.
179        final int objId = Objects.hashCode(mMockInterruptionFilterProxy);
180        when(mMockInterruptionFilterProxy.getCurrentInterruptionFilter()).thenReturn(
181                NotificationManager.INTERRUPTION_FILTER_ALL);
182        doAnswer(new Answer<Void>() {
183            @Override
184            public Void answer(InvocationOnMock i) {
185                int requestedFilter = (int) i.getArguments()[0];
186                when(mMockInterruptionFilterProxy.getCurrentInterruptionFilter()).thenReturn(
187                        requestedFilter);
188                return null;
189            }
190        }).when(mMockInterruptionFilterProxy).setInterruptionFilter(anyInt());
191    }
192
193    @LargeTest
194    public void testStateMachineTransitionsWithFocus() throws Throwable {
195        List<RoutingTestParameters> paramList = generateTransitionTests(true);
196        parametrizedTestStateMachine(paramList);
197    }
198
199    @LargeTest
200    public void testStateMachineTransitionsWithoutFocus() throws Throwable {
201        List<RoutingTestParameters> paramList = generateTransitionTests(false);
202        parametrizedTestStateMachine(paramList);
203    }
204
205    @MediumTest
206    public void testSpeakerPersistence() {
207        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
208                mContext,
209                mockCallsManager,
210                mockBluetoothManager,
211                mockWiredHeadsetManager,
212                mockStatusBarNotifier,
213                mAudioServiceFactory,
214                mMockInterruptionFilterProxy,
215                true);
216
217        when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
218        when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true);
219        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(true);
220        doAnswer(new Answer() {
221            @Override
222            public Object answer(InvocationOnMock invocation) throws Throwable {
223                Object[] args = invocation.getArguments();
224                when(mockAudioManager.isSpeakerphoneOn()).thenReturn((Boolean) args[0]);
225                return null;
226            }
227        }).when(mockAudioManager).setSpeakerphoneOn(any(Boolean.class));
228        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER,
229                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER);
230        stateMachine.initialize(initState);
231
232        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
233                CallAudioRouteStateMachine.ACTIVE_FOCUS);
234        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET);
235        CallAudioState expectedMiddleState = new CallAudioState(false,
236                CallAudioState.ROUTE_WIRED_HEADSET,
237                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_SPEAKER);
238        verifyNewSystemCallAudioState(initState, expectedMiddleState);
239        resetMocks();
240
241        stateMachine.sendMessageWithSessionInfo(
242                CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET);
243        verifyNewSystemCallAudioState(expectedMiddleState, initState);
244    }
245
246    @MediumTest
247    public void testUserBluetoothSwitchOff() {
248        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
249                mContext,
250                mockCallsManager,
251                mockBluetoothManager,
252                mockWiredHeadsetManager,
253                mockStatusBarNotifier,
254                mAudioServiceFactory,
255                mMockInterruptionFilterProxy,
256                true);
257
258        when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
259        when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true);
260        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(true);
261
262        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
263                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
264        stateMachine.initialize(initState);
265
266        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
267                CallAudioRouteStateMachine.ACTIVE_FOCUS);
268        stateMachine.sendMessageWithSessionInfo(
269                CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE);
270        CallAudioState expectedEndState = new CallAudioState(false,
271                CallAudioState.ROUTE_EARPIECE,
272                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
273
274        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
275        verifyNewSystemCallAudioState(initState, expectedEndState);
276        // Expecting to end up in earpiece, so we expect notifications to be filtered.
277        assertEquals(NotificationManager.INTERRUPTION_FILTER_ALARMS,
278                mMockInterruptionFilterProxy.getCurrentInterruptionFilter());
279        resetMocks();
280        stateMachine.sendMessageWithSessionInfo(
281                CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH);
282        stateMachine.sendMessageWithSessionInfo(
283                CallAudioRouteStateMachine.CONNECT_BLUETOOTH);
284
285        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
286        assertEquals(expectedEndState, stateMachine.getCurrentCallAudioState());
287    }
288
289    @MediumTest
290    public void testBluetoothRinging() {
291        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
292                mContext,
293                mockCallsManager,
294                mockBluetoothManager,
295                mockWiredHeadsetManager,
296                mockStatusBarNotifier,
297                mAudioServiceFactory,
298                mMockInterruptionFilterProxy,
299                true);
300
301        when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
302        when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true);
303        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false);
304
305        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
306                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
307        stateMachine.initialize(initState);
308
309        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
310                CallAudioRouteStateMachine.RINGING_FOCUS);
311        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
312
313        verify(mockBluetoothManager, never()).connectBluetoothAudio();
314        // Shouldn't change interruption filter when in bluetooth route.
315        assertEquals(NotificationManager.INTERRUPTION_FILTER_ALL,
316                mMockInterruptionFilterProxy.getCurrentInterruptionFilter());
317
318        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
319                CallAudioRouteStateMachine.ACTIVE_FOCUS);
320        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
321        verify(mockBluetoothManager, times(1)).connectBluetoothAudio();
322    }
323
324    @MediumTest
325    public void testConnectBluetoothDuringRinging() {
326        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
327                mContext,
328                mockCallsManager,
329                mockBluetoothManager,
330                mockWiredHeadsetManager,
331                mockStatusBarNotifier,
332                mAudioServiceFactory,
333                mMockInterruptionFilterProxy,
334                true);
335
336        when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
337        when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(false);
338        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false);
339        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE,
340                CallAudioState.ROUTE_EARPIECE);
341        stateMachine.initialize(initState);
342
343        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
344                CallAudioRouteStateMachine.RINGING_FOCUS);
345        when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(true);
346        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.CONNECT_BLUETOOTH);
347        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
348        verify(mockBluetoothManager, never()).connectBluetoothAudio();
349        CallAudioState expectedEndState = new CallAudioState(false,
350                CallAudioState.ROUTE_BLUETOOTH,
351                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH);
352        verifyNewSystemCallAudioState(initState, expectedEndState);
353
354        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
355                CallAudioRouteStateMachine.ACTIVE_FOCUS);
356        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
357        verify(mockBluetoothManager, times(1)).connectBluetoothAudio();
358    }
359
360    @SmallTest
361    public void testInitializationWithEarpieceNoHeadsetNoBluetooth() {
362        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE,
363                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER);
364        initializationTestHelper(expectedState, true);
365    }
366
367    @SmallTest
368    public void testInitializationWithEarpieceAndHeadsetNoBluetooth() {
369        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_WIRED_HEADSET,
370                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_SPEAKER);
371        initializationTestHelper(expectedState, true);
372    }
373
374    @SmallTest
375    public void testInitializationWithEarpieceAndHeadsetAndBluetooth() {
376        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
377                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_SPEAKER
378                | CallAudioState.ROUTE_BLUETOOTH);
379        initializationTestHelper(expectedState, true);
380    }
381
382    @SmallTest
383    public void testInitializationWithEarpieceAndBluetoothNoHeadset() {
384        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
385                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER
386                        | CallAudioState.ROUTE_BLUETOOTH);
387        initializationTestHelper(expectedState, true);
388    }
389
390    @SmallTest
391    public void testInitializationWithNoEarpieceNoHeadsetNoBluetooth() {
392        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER,
393                CallAudioState.ROUTE_SPEAKER);
394        initializationTestHelper(expectedState, false);
395    }
396
397    @SmallTest
398    public void testInitializationWithHeadsetNoBluetoothNoEarpiece() {
399        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_WIRED_HEADSET,
400                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_SPEAKER);
401        initializationTestHelper(expectedState, false);
402    }
403
404    @SmallTest
405    public void testInitializationWithHeadsetAndBluetoothNoEarpiece() {
406        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
407                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_SPEAKER
408                | CallAudioState.ROUTE_BLUETOOTH);
409        initializationTestHelper(expectedState, false);
410    }
411
412    @SmallTest
413    public void testInitializationWithBluetoothNoHeadsetNoEarpiece() {
414        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH,
415                CallAudioState.ROUTE_SPEAKER | CallAudioState.ROUTE_BLUETOOTH);
416        initializationTestHelper(expectedState, false);
417    }
418
419    private void initializationTestHelper(CallAudioState expectedState,
420            boolean doesDeviceSupportEarpiece) {
421        when(mockWiredHeadsetManager.isPluggedIn()).thenReturn(
422                (expectedState.getSupportedRouteMask() & CallAudioState.ROUTE_WIRED_HEADSET) != 0);
423        when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(
424                (expectedState.getSupportedRouteMask() & CallAudioState.ROUTE_BLUETOOTH) != 0);
425
426        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
427                mContext,
428                mockCallsManager,
429                mockBluetoothManager,
430                mockWiredHeadsetManager,
431                mockStatusBarNotifier,
432                mAudioServiceFactory,
433                mMockInterruptionFilterProxy,
434                doesDeviceSupportEarpiece);
435        stateMachine.initialize();
436        assertEquals(expectedState, stateMachine.getCurrentCallAudioState());
437    }
438
439    private List<RoutingTestParameters> generateTransitionTests(boolean shouldRunWithFocus) {
440        List<RoutingTestParameters> params = new ArrayList<>();
441        params.add(new RoutingTestParameters(
442                "Connect headset during earpiece", // name
443                CallAudioState.ROUTE_EARPIECE, // initialRoute
444                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
445                CallAudioState.ROUTE_EARPIECE, // availableRoutes
446                NONE, // speakerInteraction
447                NONE, // bluetoothInteraction
448                CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action
449                CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
450                CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
451                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
452                true, // isNotificationChangeExpected
453                true, // doesDeviceSupportEarpiece
454                shouldRunWithFocus
455        ));
456
457        params.add(new RoutingTestParameters(
458                "Connect headset during bluetooth", // name
459                CallAudioState.ROUTE_BLUETOOTH, // initialRoute
460                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
461                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
462                NONE, // speakerInteraction
463                OFF, // bluetoothInteraction
464                CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action
465                CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
466                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai
467                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
468                false, // isNotificationChangeExpected
469                true, // doesDeviceSupportEarpiece
470                shouldRunWithFocus
471        ));
472
473        params.add(new RoutingTestParameters(
474                "Connect headset during speakerphone", // name
475                CallAudioState.ROUTE_SPEAKER, // initialRoute
476                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
477                CallAudioState.ROUTE_EARPIECE, // availableRoutes
478                OFF, // speakerInteraction
479                NONE, // bluetoothInteraction
480                CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action
481                CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
482                CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
483                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
484                false, // isNotificationChangeExpected
485                true, // doesDeviceSupportEarpiece
486                shouldRunWithFocus
487        ));
488
489        params.add(new RoutingTestParameters(
490                "Disconnect headset during headset", // name
491                CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
492                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
493                CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
494                NONE, // speakerInteraction
495                NONE, // bluetoothInteraction
496                CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
497                CallAudioState.ROUTE_EARPIECE, // expectedRoute
498                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
499                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
500                true, // isNotificationChangeExpected
501                true, // doesDeviceSupportEarpiece
502                shouldRunWithFocus
503        ));
504
505        params.add(new RoutingTestParameters(
506                "Disconnect headset during headset with bluetooth available", // name
507                CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
508                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
509                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
510                NONE, // speakerInteraction
511                NONE, // bluetoothInteraction
512                CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
513                CallAudioState.ROUTE_EARPIECE, // expectedRoute
514                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
515                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
516                true, // isNotificationChangeExpected
517                true, // doesDeviceSupportEarpiece
518                shouldRunWithFocus
519        ));
520
521        params.add(new RoutingTestParameters(
522                "Disconnect headset during bluetooth", // name
523                CallAudioState.ROUTE_BLUETOOTH, // initialRoute
524                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
525                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
526                NONE, // speakerInteraction
527                NONE, // bluetoothInteraction
528                CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
529                CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
530                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
531                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
532                false, // isNotificationChangeExpected
533                true, // doesDeviceSupportEarpiece
534                shouldRunWithFocus
535        ));
536
537        params.add(new RoutingTestParameters(
538                "Disconnect headset during speakerphone", // name
539                CallAudioState.ROUTE_SPEAKER, // initialRoute
540                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
541                CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
542                NONE, // speakerInteraction
543                NONE, // bluetoothInteraction
544                CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
545                CallAudioState.ROUTE_SPEAKER, // expectedRoute
546                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
547                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
548                false, // isNotificationChangeExpected
549                true, // doesDeviceSupportEarpiece
550                shouldRunWithFocus
551        ));
552
553        params.add(new RoutingTestParameters(
554                "Disconnect headset during speakerphone with bluetooth available", // name
555                CallAudioState.ROUTE_SPEAKER, // initialRoute
556                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
557                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
558                NONE, // speakerInteraction
559                NONE, // bluetoothInteraction
560                CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
561                CallAudioState.ROUTE_SPEAKER, // expectedRoute
562                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
563                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
564                false, // isNotificationChangeExpected
565                true, // doesDeviceSupportEarpiece
566                shouldRunWithFocus
567        ));
568
569        params.add(new RoutingTestParameters(
570                "Connect bluetooth during earpiece", // name
571                CallAudioState.ROUTE_EARPIECE, // initialRoute
572                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
573                CallAudioState.ROUTE_EARPIECE, // availableRoutes
574                NONE, // speakerInteraction
575                ON, // bluetoothInteraction
576                CallAudioRouteStateMachine.CONNECT_BLUETOOTH, // action
577                CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
578                CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_EARPIECE, // expectedAvailable
579                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
580                true, // isNotificationChangeExpected
581                true, // doesDeviceSupportEarpiece
582                shouldRunWithFocus
583        ));
584
585        params.add(new RoutingTestParameters(
586                "Connect bluetooth during wired headset", // name
587                CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
588                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
589                CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
590                NONE, // speakerInteraction
591                ON, // bluetoothInteraction
592                CallAudioRouteStateMachine.CONNECT_BLUETOOTH, // action
593                CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
594                CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvai
595                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
596                false, // isNotificationChangeExpected
597                true, // doesDeviceSupportEarpiece
598                shouldRunWithFocus
599        ));
600
601        params.add(new RoutingTestParameters(
602                "Connect bluetooth during speakerphone", // name
603                CallAudioState.ROUTE_SPEAKER, // initialRoute
604                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
605                CallAudioState.ROUTE_EARPIECE, // availableRoutes
606                OFF, // speakerInteraction
607                ON, // bluetoothInteraction
608                CallAudioRouteStateMachine.CONNECT_BLUETOOTH, // action
609                CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
610                CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_EARPIECE, // expectedAvailable
611                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
612                false, // isNotificationChangeExpected
613                true, // doesDeviceSupportEarpiece
614                shouldRunWithFocus
615        ));
616
617        params.add(new RoutingTestParameters(
618                "Disconnect bluetooth during bluetooth without headset in", // name
619                CallAudioState.ROUTE_BLUETOOTH, // initialRoute
620                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
621                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
622                NONE, // speakerInteraction
623                OFF, // bluetoothInteraction
624                CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
625                CallAudioState.ROUTE_EARPIECE, // expectedRoute
626                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
627                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
628                true, // isNotificationChangeExpected
629                true, // doesDeviceSupportEarpiece
630                shouldRunWithFocus
631        ));
632
633        params.add(new RoutingTestParameters(
634                "Disconnect bluetooth during bluetooth without headset in, priority mode ", // name
635                CallAudioState.ROUTE_BLUETOOTH, // initialRoute
636                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // initialNotificationFilter
637                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
638                NONE, // speakerInteraction
639                OFF, // bluetoothInteraction
640                CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
641                CallAudioState.ROUTE_EARPIECE, // expectedRoute
642                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
643                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // expectedNotificationFilter
644                false, // isNotificationChangeExpected
645                true, // doesDeviceSupportEarpiece
646                shouldRunWithFocus
647        ));
648
649        params.add(new RoutingTestParameters(
650                "Disconnect bluetooth during bluetooth with headset in", // name
651                CallAudioState.ROUTE_BLUETOOTH, // initialRoute
652                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
653                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
654                NONE, // speakerInteraction
655                OFF, // bluetoothInteraction
656                CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
657                CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute
658                CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
659                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
660                false, // isNotificationChangeExpected
661                true, // doesDeviceSupportEarpiece
662                shouldRunWithFocus
663        ));
664
665        params.add(new RoutingTestParameters(
666                "Disconnect bluetooth during speakerphone", // name
667                CallAudioState.ROUTE_SPEAKER, // initialRoute
668                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
669                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
670                NONE, // speakerInteraction
671                NONE, // bluetoothInteraction
672                CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
673                CallAudioState.ROUTE_SPEAKER, // expectedRoute
674                CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
675                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
676                false, // isNotificationChangeExpected
677                true, // doesDeviceSupportEarpiece
678                shouldRunWithFocus
679        ));
680
681        params.add(new RoutingTestParameters(
682                "Disconnect bluetooth during earpiece", // name
683                CallAudioState.ROUTE_EARPIECE, // initialRoute
684                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
685                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
686                NONE, // speakerInteraction
687                NONE, // bluetoothInteraction
688                CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
689                CallAudioState.ROUTE_EARPIECE, // expectedRoute
690                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
691                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
692                true, // isNotificationChangeExpected
693                true, // doesDeviceSupportEarpiece
694                shouldRunWithFocus
695        ));
696
697        params.add(new RoutingTestParameters(
698                "Switch to speakerphone from earpiece", // name
699                CallAudioState.ROUTE_EARPIECE, // initialRoute
700                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
701                CallAudioState.ROUTE_EARPIECE, // availableRoutes
702                ON, // speakerInteraction
703                NONE, // bluetoothInteraction
704                CallAudioRouteStateMachine.SWITCH_SPEAKER, // action
705                CallAudioState.ROUTE_SPEAKER, // expectedRoute
706                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
707                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
708                true, // isNotificationChangeExpected
709                true, // doesDeviceSupportEarpiece
710                shouldRunWithFocus
711        ));
712
713        params.add(new RoutingTestParameters(
714                "Switch to speakerphone from headset", // name
715                CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
716                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
717                CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
718                ON, // speakerInteraction
719                NONE, // bluetoothInteraction
720                CallAudioRouteStateMachine.SWITCH_SPEAKER, // action
721                CallAudioState.ROUTE_SPEAKER, // expectedRoute
722                CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes
723                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
724                false, // isNotificationChangeExpected
725                true, // doesDeviceSupportEarpiece
726                shouldRunWithFocus
727        ));
728
729        params.add(new RoutingTestParameters(
730                "Switch to speakerphone from bluetooth", // name
731                CallAudioState.ROUTE_BLUETOOTH, // initialRoute
732                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
733                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
734                ON, // speakerInteraction
735                OFF, // bluetoothInteraction
736                CallAudioRouteStateMachine.SWITCH_SPEAKER, // action
737                CallAudioState.ROUTE_SPEAKER, // expectedRoute
738                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai
739                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
740                false, // isNotificationChangeExpected
741                true, // doesDeviceSupportEarpiece
742                shouldRunWithFocus
743        ));
744
745        params.add(new RoutingTestParameters(
746                "Switch to earpiece from bluetooth", // name
747                CallAudioState.ROUTE_BLUETOOTH, // initialRoute
748                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
749                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
750                NONE, // speakerInteraction
751                OFF, // bluetoothInteraction
752                CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
753                CallAudioState.ROUTE_EARPIECE, // expectedRoute
754                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
755                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
756                true, // isNotificationChangeExpected
757                true, // doesDeviceSupportEarpiece
758                shouldRunWithFocus
759        ));
760
761        params.add(new RoutingTestParameters(
762                "Switch to earpiece from speakerphone", // name
763                CallAudioState.ROUTE_SPEAKER, // initialRoute
764                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
765                CallAudioState.ROUTE_EARPIECE, // availableRoutes
766                OFF, // speakerInteraction
767                NONE, // bluetoothInteraction
768                CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
769                CallAudioState.ROUTE_EARPIECE, // expectedRoute
770                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
771                NotificationManager.INTERRUPTION_FILTER_ALARMS, // expectedNotificationFilter
772                true, // isNotificationChangeExpected
773                true, // doesDeviceSupportEarpiece
774                shouldRunWithFocus
775        ));
776
777        params.add(new RoutingTestParameters(
778                "Switch to earpiece from speakerphone, priority notifications", // name
779                CallAudioState.ROUTE_SPEAKER, // initialRoute
780                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // initialNotificationFilter
781                CallAudioState.ROUTE_EARPIECE, // availableRoutes
782                OFF, // speakerInteraction
783                NONE, // bluetoothInteraction
784                CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
785                CallAudioState.ROUTE_EARPIECE, // expectedRoute
786                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
787                NotificationManager.INTERRUPTION_FILTER_PRIORITY, // expectedNotificationFilter
788                false, // isNotificationChangeExpected
789                true, // doesDeviceSupportEarpiece
790                shouldRunWithFocus
791        ));
792
793        params.add(new RoutingTestParameters(
794                "Switch to earpiece from speakerphone, silent mode", // name
795                CallAudioState.ROUTE_SPEAKER, // initialRoute
796                NotificationManager.INTERRUPTION_FILTER_NONE, // initialNotificationFilter
797                CallAudioState.ROUTE_EARPIECE, // availableRoutes
798                OFF, // speakerInteraction
799                NONE, // bluetoothInteraction
800                CallAudioRouteStateMachine.SWITCH_EARPIECE, // action
801                CallAudioState.ROUTE_EARPIECE, // expectedRoute
802                CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes
803                NotificationManager.INTERRUPTION_FILTER_NONE, // expectedNotificationFilter
804                false, // isNotificationChangeExpected
805                true, // doesDeviceSupportEarpiece
806                shouldRunWithFocus
807        ));
808
809        params.add(new RoutingTestParameters(
810                "Switch to bluetooth from speakerphone", // name
811                CallAudioState.ROUTE_SPEAKER, // initialRoute
812                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
813                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
814                OFF, // speakerInteraction
815                ON, // bluetoothInteraction
816                CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action
817                CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
818                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
819                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
820                false, // isNotificationChangeExpected
821                true, // doesDeviceSupportEarpiece
822                shouldRunWithFocus
823        ));
824
825        params.add(new RoutingTestParameters(
826                "Switch to bluetooth from earpiece", // name
827                CallAudioState.ROUTE_EARPIECE, // initialRoute
828                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
829                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
830                NONE, // speakerInteraction
831                ON, // bluetoothInteraction
832                CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action
833                CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
834                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable
835                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
836                true, // isNotificationChangeExpected
837                true, // doesDeviceSupportEarpiece
838                shouldRunWithFocus
839        ));
840
841        params.add(new RoutingTestParameters(
842                "Switch to bluetooth from wired headset", // name
843                CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
844                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
845                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou
846                NONE, // speakerInteraction
847                ON, // bluetoothInteraction
848                CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action
849                CallAudioState.ROUTE_BLUETOOTH, // expectedRoute
850                CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai
851                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
852                false, // isNotificationChangeExpected
853                true, // doesDeviceSupportEarpiece
854                shouldRunWithFocus
855        ));
856
857        params.add(new RoutingTestParameters(
858                "Switch from bluetooth to wired/earpiece when neither are available", // name
859                CallAudioState.ROUTE_BLUETOOTH, // initialRoute
860                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
861                CallAudioState.ROUTE_BLUETOOTH, // availableRoutes
862                ON, // speakerInteraction
863                OFF, // bluetoothInteraction
864                CallAudioRouteStateMachine.SWITCH_BASELINE_ROUTE, // action
865                CallAudioState.ROUTE_SPEAKER, // expectedRoute
866                CallAudioState.ROUTE_BLUETOOTH, // expectedAvailableRoutes
867                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
868                false, // isNotificationChangeExpected
869                false, // doesDeviceSupportEarpiece
870                shouldRunWithFocus
871        ));
872
873        params.add(new RoutingTestParameters(
874                "Disconnect wired headset when device does not support earpiece", // name
875                CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
876                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
877                CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
878                ON, // speakerInteraction
879                NONE, // bluetoothInteraction
880                CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
881                CallAudioState.ROUTE_SPEAKER, // expectedRoute
882                CallAudioState.ROUTE_SPEAKER, // expectedAvailableRoutes
883                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
884                false, // isNotificationChangeExpected
885                false, // doesDeviceSupportEarpiece
886                shouldRunWithFocus
887        ));
888
889        params.add(new RoutingTestParameters(
890                "Disconnect wired headset when call doesn't support earpiece", // name
891                CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute
892                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
893                CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes
894                ON, // speakerInteraction
895                NONE, // bluetoothInteraction
896                CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action
897                CallAudioState.ROUTE_SPEAKER, // expectedRoute
898                CallAudioState.ROUTE_SPEAKER, // expectedAvailableRoutes
899                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
900                false, // isNotificationChangeExpected
901                true, // doesDeviceSupportEarpiece
902                shouldRunWithFocus
903        ).setCallSupportedRoutes(CallAudioState.ROUTE_ALL & ~CallAudioState.ROUTE_EARPIECE));
904
905        params.add(new RoutingTestParameters(
906                "Disconnect bluetooth when call does not support earpiece", // name
907                CallAudioState.ROUTE_BLUETOOTH, // initialRoute
908                NotificationManager.INTERRUPTION_FILTER_ALL, // initialNotificationFilter
909                CallAudioState.ROUTE_BLUETOOTH,  // availableRoutes
910                ON, // speakerInteraction
911                OFF, // bluetoothInteraction
912                CallAudioRouteStateMachine.DISCONNECT_BLUETOOTH, // action
913                CallAudioState.ROUTE_SPEAKER, // expectedRoute
914                CallAudioState.ROUTE_SPEAKER, // expectedAvailableRoutes
915                NotificationManager.INTERRUPTION_FILTER_ALL, // expectedNotificationFilter
916                false, // isNotificationChangeExpected
917                true, // doesDeviceSupportEarpiece
918                shouldRunWithFocus
919        ).setCallSupportedRoutes(CallAudioState.ROUTE_ALL & ~CallAudioState.ROUTE_EARPIECE));
920
921        return params;
922    }
923
924    @Override
925    protected void runParametrizedTestCase(TestParameters _params) throws Throwable {
926        RoutingTestParameters params = (RoutingTestParameters) _params;
927        if (params.shouldRunWithFocus) {
928            runParametrizedTestCaseWithFocus(params);
929        } else {
930            runParametrizedTestCaseWithoutFocus(params);
931        }
932    }
933
934    private void runParametrizedTestCaseWithFocus(final RoutingTestParameters params)
935            throws Throwable {
936        resetMocks();
937        when(mMockInterruptionFilterProxy.getCurrentInterruptionFilter()).thenReturn(
938                params.initialNotificationFilter);
939
940        // Construct a fresh state machine on every case
941        final CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
942                mContext,
943                mockCallsManager,
944                mockBluetoothManager,
945                mockWiredHeadsetManager,
946                mockStatusBarNotifier,
947                mAudioServiceFactory,
948                mMockInterruptionFilterProxy,
949                params.doesDeviceSupportEarpiece);
950
951        // Set up bluetooth and speakerphone state
952        when(mockBluetoothManager.isBluetoothAudioConnectedOrPending()).thenReturn(
953                params.initialRoute == CallAudioState.ROUTE_BLUETOOTH);
954        when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(
955                (params.availableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0
956                        || (params.expectedAvailableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0);
957        doReturn(params.initialRoute == CallAudioState.ROUTE_SPEAKER).when(mockAudioManager).
958                isSpeakerphoneOn();
959        when(fakeCall.getSupportedAudioRoutes()).thenReturn(params.callSupportedRoutes);
960
961        // Set the initial CallAudioState object
962        final CallAudioState initState = new CallAudioState(false,
963                params.initialRoute, (params.availableRoutes | CallAudioState.ROUTE_SPEAKER));
964        stateMachine.initialize(initState);
965
966        // Make the state machine have focus so that we actually do something
967        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS,
968                CallAudioRouteStateMachine.ACTIVE_FOCUS);
969        stateMachine.sendMessageWithSessionInfo(params.action);
970
971        waitForStateMachineActionCompletion(stateMachine, CallAudioRouteStateMachine.RUN_RUNNABLE);
972
973        // Capture the changes made to the interruption filter and verify that the last change
974        // made to it matches the expected interruption filter.
975        if (params.isNotificationChangeExpected) {
976            ArgumentCaptor<Integer> interruptionCaptor = ArgumentCaptor.forClass(Integer.class);
977            verify(mMockInterruptionFilterProxy, timeout(TEST_TIMEOUT).atLeastOnce())
978                    .setInterruptionFilter(interruptionCaptor.capture());
979            List<Integer> interruptionFilterValues = interruptionCaptor.getAllValues();
980
981            int lastChange = interruptionFilterValues.get(interruptionFilterValues.size() - 1)
982                    .intValue();
983            assertEquals(params.expectedNotificationFilter, lastChange);
984        } else {
985            Thread.sleep(TEST_TIMEOUT);
986            verify(mMockInterruptionFilterProxy, never()).setInterruptionFilter(anyInt());
987        }
988
989        stateMachine.quitStateMachine();
990
991        // Verify interactions with the speakerphone and bluetooth systems
992        switch (params.bluetoothInteraction) {
993            case NONE:
994                verify(mockBluetoothManager, never()).disconnectBluetoothAudio();
995                verify(mockBluetoothManager, never()).connectBluetoothAudio();
996                break;
997            case ON:
998                verify(mockBluetoothManager).connectBluetoothAudio();
999
1000                verify(mockBluetoothManager, never()).disconnectBluetoothAudio();
1001                break;
1002            case OFF:
1003                verify(mockBluetoothManager, never()).connectBluetoothAudio();
1004                verify(mockBluetoothManager).disconnectBluetoothAudio();
1005        }
1006
1007        switch (params.speakerInteraction) {
1008            case NONE:
1009                verify(mockAudioManager, never()).setSpeakerphoneOn(any(Boolean.class));
1010                break;
1011            case ON: // fall through
1012            case OFF:
1013                verify(mockAudioManager).setSpeakerphoneOn(params.speakerInteraction == ON);
1014        }
1015
1016        // Verify the end state
1017        CallAudioState expectedState = new CallAudioState(false, params.expectedRoute,
1018                params.expectedAvailableRoutes | CallAudioState.ROUTE_SPEAKER);
1019        verifyNewSystemCallAudioState(initState, expectedState);
1020    }
1021
1022    private void runParametrizedTestCaseWithoutFocus(final RoutingTestParameters params)
1023            throws Throwable {
1024        resetMocks();
1025
1026        // Construct a fresh state machine on every case
1027        final CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
1028                mContext,
1029                mockCallsManager,
1030                mockBluetoothManager,
1031                mockWiredHeadsetManager,
1032                mockStatusBarNotifier,
1033                mAudioServiceFactory,
1034                mMockInterruptionFilterProxy,
1035                params.doesDeviceSupportEarpiece);
1036
1037        // Set up bluetooth and speakerphone state
1038        when(mockBluetoothManager.isBluetoothAvailable()).thenReturn(
1039                (params.availableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0
1040                || (params.expectedAvailableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0);
1041        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(
1042                params.initialRoute == CallAudioState.ROUTE_SPEAKER);
1043        when(fakeCall.getSupportedAudioRoutes()).thenReturn(params.callSupportedRoutes);
1044
1045        // Set the initial CallAudioState object
1046        CallAudioState initState = new CallAudioState(false,
1047                params.initialRoute, (params.availableRoutes | CallAudioState.ROUTE_SPEAKER));
1048        stateMachine.initialize(initState);
1049        // Omit the focus-getting statement
1050        stateMachine.sendMessageWithSessionInfo(params.action);
1051
1052        waitForStateMachineActionCompletion(stateMachine, CallAudioModeStateMachine.RUN_RUNNABLE);
1053
1054        stateMachine.quitStateMachine();
1055
1056        // Verify that no substantive interactions have taken place with the
1057        // rest of the system
1058        verifyNoSystemAudioChanges();
1059
1060        // Verify the end state
1061        CallAudioState expectedState = new CallAudioState(false, params.expectedRoute,
1062                params.expectedAvailableRoutes | CallAudioState.ROUTE_SPEAKER);
1063        assertEquals(expectedState, stateMachine.getCurrentCallAudioState());
1064    }
1065
1066    private void verifyNoSystemAudioChanges() {
1067        verify(mockBluetoothManager, never()).disconnectBluetoothAudio();
1068        verify(mockBluetoothManager, never()).connectBluetoothAudio();
1069        verify(mockAudioManager, never()).setSpeakerphoneOn(any(Boolean.class));
1070        verify(mockCallsManager, never()).onCallAudioStateChanged(any(CallAudioState.class),
1071                any(CallAudioState.class));
1072        verify(mockConnectionServiceWrapper, never()).onCallAudioStateChanged(
1073                any(Call.class), any(CallAudioState.class));
1074    }
1075
1076    private void verifyNewSystemCallAudioState(CallAudioState expectedOldState,
1077            CallAudioState expectedNewState) {
1078        ArgumentCaptor<CallAudioState> oldStateCaptor = ArgumentCaptor.forClass(
1079                CallAudioState.class);
1080        ArgumentCaptor<CallAudioState> newStateCaptor1 = ArgumentCaptor.forClass(
1081                CallAudioState.class);
1082        ArgumentCaptor<CallAudioState> newStateCaptor2 = ArgumentCaptor.forClass(
1083                CallAudioState.class);
1084        verify(mockCallsManager, timeout(TEST_TIMEOUT).atLeastOnce()).onCallAudioStateChanged(
1085                oldStateCaptor.capture(), newStateCaptor1.capture());
1086        verify(mockConnectionServiceWrapper, timeout(TEST_TIMEOUT).atLeastOnce())
1087                .onCallAudioStateChanged(same(fakeCall), newStateCaptor2.capture());
1088
1089        assertTrue(oldStateCaptor.getValue().equals(expectedOldState));
1090        assertTrue(newStateCaptor1.getValue().equals(expectedNewState));
1091        assertTrue(newStateCaptor2.getValue().equals(expectedNewState));
1092    }
1093
1094    private void resetMocks() {
1095        reset(mockAudioManager, mockBluetoothManager, mockCallsManager,
1096                mockConnectionServiceWrapper, mMockInterruptionFilterProxy, fakeCall);
1097        mMockInterruptionFilterProxy = mock(InterruptionFilterProxy.class);
1098        setupInterruptionFilterMocks();
1099        when(mockCallsManager.getForegroundCall()).thenReturn(fakeCall);
1100        when(fakeCall.getConnectionService()).thenReturn(mockConnectionServiceWrapper);
1101        when(fakeCall.isAlive()).thenReturn(true);
1102        when(fakeCall.getSupportedAudioRoutes()).thenReturn(CallAudioState.ROUTE_ALL);
1103        when(mockCallsManager.getLock()).thenReturn(mLock);
1104        doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class),
1105                any(CallAudioState.class));
1106    }
1107}
1108