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