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