1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server.telecom.tests; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.nullable; 22 import static org.mockito.ArgumentMatchers.same; 23 import static org.mockito.Mockito.atLeastOnce; 24 import static org.mockito.Mockito.doAnswer; 25 import static org.mockito.Mockito.doNothing; 26 import static org.mockito.Mockito.doReturn; 27 import static org.mockito.Mockito.never; 28 import static org.mockito.Mockito.timeout; 29 import static org.mockito.Mockito.verify; 30 import static org.mockito.Mockito.when; 31 32 import android.bluetooth.BluetoothDevice; 33 import android.content.Context; 34 import android.media.AudioDeviceInfo; 35 import android.media.AudioManager; 36 import android.media.IAudioService; 37 import android.os.Handler; 38 import android.os.HandlerThread; 39 import android.telecom.CallAudioState; 40 41 import androidx.test.filters.SmallTest; 42 43 import com.android.server.telecom.Call; 44 import com.android.server.telecom.CallAudioCommunicationDeviceTracker; 45 import com.android.server.telecom.CallAudioManager; 46 import com.android.server.telecom.CallAudioRouteStateMachine; 47 import com.android.server.telecom.CallsManager; 48 import com.android.server.telecom.ConnectionServiceWrapper; 49 import com.android.server.telecom.StatusBarNotifier; 50 import com.android.server.telecom.TelecomSystem; 51 import com.android.server.telecom.WiredHeadsetManager; 52 import com.android.server.telecom.bluetooth.BluetoothRouteManager; 53 54 import org.junit.After; 55 import org.junit.Before; 56 import org.junit.Test; 57 import org.junit.runner.RunWith; 58 import org.junit.runners.Parameterized; 59 import org.mockito.ArgumentCaptor; 60 import org.mockito.Mock; 61 import org.mockito.Mockito; 62 import org.mockito.MockitoAnnotations; 63 64 import java.util.ArrayList; 65 import java.util.Arrays; 66 import java.util.Collection; 67 import java.util.Collections; 68 import java.util.List; 69 import java.util.Set; 70 71 @RunWith(Parameterized.class) 72 public class CallAudioRouteTransitionTests extends TelecomTestCase { 73 private static final int NONE = 0; 74 private static final int ON = 1; 75 private static final int OFF = 2; 76 private static final int OPTIONAL = 3; 77 78 // This is used to simulate the first bluetooth device getting connected -- 79 // it requires two messages: BT device list changed and active device present 80 private static final int SPECIAL_CONNECT_BT_ACTION = 998; 81 // Same, but for disconnection 82 private static final int SPECIAL_DISCONNECT_BT_ACTION = 999; 83 84 static class RoutingTestParameters { 85 public String name; 86 public int initialRoute; 87 public BluetoothDevice initialBluetoothDevice = null; 88 public int availableRoutes; // may excl. speakerphone, because that's always available 89 public List<BluetoothDevice> availableBluetoothDevices = Collections.emptyList(); 90 public int speakerInteraction; // one of NONE, ON, or OFF 91 public int bluetoothInteraction; // one of NONE, ON, or OFF 92 public int action; 93 public int expectedRoute; 94 public BluetoothDevice expectedBluetoothDevice = null; 95 public int expectedAvailableRoutes; // also may exclude the speakerphone. 96 public int earpieceControl; // Allows disabling the earpiece to simulate Wear or Car 97 98 public int callSupportedRoutes = CallAudioState.ROUTE_ALL; 99 RoutingTestParameters(String name, int initialRoute, int availableRoutes, int speakerInteraction, int bluetoothInteraction, int action, int expectedRoute, int expectedAvailableRoutes, int earpieceControl)100 public RoutingTestParameters(String name, int initialRoute, 101 int availableRoutes, int speakerInteraction, 102 int bluetoothInteraction, int action, int expectedRoute, 103 int expectedAvailableRoutes, int earpieceControl) { 104 this.name = name; 105 this.initialRoute = initialRoute; 106 this.availableRoutes = availableRoutes; 107 this.speakerInteraction = speakerInteraction; 108 this.bluetoothInteraction = bluetoothInteraction; 109 this.action = action; 110 this.expectedRoute = expectedRoute; 111 this.expectedAvailableRoutes = expectedAvailableRoutes; 112 this.earpieceControl = earpieceControl; 113 } 114 setCallSupportedRoutes(int routes)115 public RoutingTestParameters setCallSupportedRoutes(int routes) { 116 callSupportedRoutes = routes; 117 return this; 118 } 119 setInitialBluetoothDevice(BluetoothDevice device)120 public RoutingTestParameters setInitialBluetoothDevice(BluetoothDevice device) { 121 initialBluetoothDevice = device; 122 return this; 123 } 124 setAvailableBluetoothDevices(BluetoothDevice... devices)125 public RoutingTestParameters setAvailableBluetoothDevices(BluetoothDevice... devices) { 126 availableBluetoothDevices = Arrays.asList(devices); 127 return this; 128 } 129 setExpectedBluetoothDevice(BluetoothDevice device)130 public RoutingTestParameters setExpectedBluetoothDevice(BluetoothDevice device) { 131 expectedBluetoothDevice = device; 132 return this; 133 } 134 135 @Override toString()136 public String toString() { 137 return "RoutingTestParameters{" + 138 "name='" + name + '\'' + 139 ", initialRoute=" + initialRoute + 140 ", availableRoutes=" + availableRoutes + 141 ", speakerInteraction=" + speakerInteraction + 142 ", bluetoothInteraction=" + bluetoothInteraction + 143 ", action=" + action + 144 ", expectedRoute=" + expectedRoute + 145 ", expectedAvailableRoutes=" + expectedAvailableRoutes + 146 ", earpieceControl=" + earpieceControl + 147 '}'; 148 } 149 } 150 151 private final RoutingTestParameters mParams; 152 @Mock CallsManager mockCallsManager; 153 @Mock BluetoothRouteManager mockBluetoothRouteManager; 154 @Mock IAudioService mockAudioService; 155 @Mock ConnectionServiceWrapper mockConnectionServiceWrapper; 156 @Mock WiredHeadsetManager mockWiredHeadsetManager; 157 @Mock StatusBarNotifier mockStatusBarNotifier; 158 @Mock Call fakeCall; 159 @Mock CallAudioManager mockCallAudioManager; 160 private CallAudioCommunicationDeviceTracker mCommunicationDeviceTracker; 161 private CallAudioManager.AudioServiceFactory mAudioServiceFactory; 162 private static final int TEST_TIMEOUT = 500; 163 private AudioManager mockAudioManager; 164 private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { }; 165 private HandlerThread mHandlerThread; 166 CallAudioRouteTransitionTests(RoutingTestParameters params)167 public CallAudioRouteTransitionTests(RoutingTestParameters params) { 168 mParams = params; 169 } 170 171 @Override 172 @Before setUp()173 public void setUp() throws Exception { 174 super.setUp(); 175 MockitoAnnotations.initMocks(this); 176 mHandlerThread = new HandlerThread("CallAudioRouteTransitionTests"); 177 mHandlerThread.start(); 178 mContext = mComponentContextFixture.getTestDouble().getApplicationContext(); 179 mockAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 180 mCommunicationDeviceTracker = new CallAudioCommunicationDeviceTracker(mContext); 181 mCommunicationDeviceTracker.setBluetoothRouteManager(mockBluetoothRouteManager); 182 183 mAudioServiceFactory = new CallAudioManager.AudioServiceFactory() { 184 @Override 185 public IAudioService getAudioService() { 186 return mockAudioService; 187 } 188 }; 189 190 when(mockCallsManager.getForegroundCall()).thenReturn(fakeCall); 191 when(mockCallsManager.getTrackedCalls()).thenReturn(Set.of(fakeCall)); 192 when(mockCallsManager.getLock()).thenReturn(mLock); 193 when(mockCallsManager.hasVideoCall()).thenReturn(false); 194 when(fakeCall.getConnectionService()).thenReturn(mockConnectionServiceWrapper); 195 when(fakeCall.isAlive()).thenReturn(true); 196 when(fakeCall.getSupportedAudioRoutes()).thenReturn(CallAudioState.ROUTE_ALL); 197 198 doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class), 199 any(CallAudioState.class)); 200 } 201 202 @Override 203 @After tearDown()204 public void tearDown() throws Exception { 205 mHandlerThread.quit(); 206 mHandlerThread.join(); 207 super.tearDown(); 208 } 209 setupMocksForParams(final CallAudioRouteStateMachine sm, RoutingTestParameters params)210 private void setupMocksForParams(final CallAudioRouteStateMachine sm, 211 RoutingTestParameters params) { 212 // Set up bluetooth and speakerphone state 213 doReturn(params.initialRoute == CallAudioState.ROUTE_BLUETOOTH) 214 .when(mockBluetoothRouteManager).isBluetoothAudioConnectedOrPending(); 215 doReturn((params.availableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0 216 || (params.expectedAvailableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0) 217 .when(mockBluetoothRouteManager).isBluetoothAvailable(); 218 doReturn(params.availableBluetoothDevices) 219 .when(mockBluetoothRouteManager).getConnectedDevices(); 220 if (params.initialBluetoothDevice != null) { 221 doReturn(params.initialBluetoothDevice) 222 .when(mockBluetoothRouteManager).getBluetoothAudioConnectedDevice(); 223 } 224 225 226 doAnswer(invocation -> { 227 sm.sendMessageWithSessionInfo(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED); 228 return null; 229 }).when(mockBluetoothRouteManager).connectBluetoothAudio(nullable(String.class)); 230 231 // Set the speakerphone state depending on the message being sent. If it's one of the 232 // speakerphone override ones, set accordingly. Otherwise consult the initial route. 233 boolean speakerphoneOn; 234 if (params.action == CallAudioRouteStateMachine.SPEAKER_ON) { 235 speakerphoneOn = true; 236 } else if (params.action == CallAudioRouteStateMachine.SPEAKER_OFF) { 237 speakerphoneOn = false; 238 } else { 239 speakerphoneOn = params.initialRoute == CallAudioState.ROUTE_SPEAKER; 240 } 241 when(mockAudioManager.isSpeakerphoneOn()).thenReturn(speakerphoneOn); 242 243 when(fakeCall.getSupportedAudioRoutes()).thenReturn(params.callSupportedRoutes); 244 } 245 sendActionToStateMachine(CallAudioRouteStateMachine sm)246 private void sendActionToStateMachine(CallAudioRouteStateMachine sm) { 247 switch (mParams.action) { 248 case SPECIAL_CONNECT_BT_ACTION: 249 sm.sendMessageWithSessionInfo( 250 CallAudioRouteStateMachine.BLUETOOTH_DEVICE_LIST_CHANGED); 251 sm.sendMessageWithSessionInfo( 252 CallAudioRouteStateMachine.BT_ACTIVE_DEVICE_PRESENT); 253 break; 254 case SPECIAL_DISCONNECT_BT_ACTION: 255 sm.sendMessageWithSessionInfo( 256 CallAudioRouteStateMachine.BLUETOOTH_DEVICE_LIST_CHANGED); 257 sm.sendMessageWithSessionInfo( 258 CallAudioRouteStateMachine.BT_ACTIVE_DEVICE_GONE); 259 break; 260 default: 261 sm.sendMessageWithSessionInfo(mParams.action); 262 break; 263 } 264 } 265 266 @Test 267 @SmallTest testActiveTransition()268 public void testActiveTransition() { 269 final CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( 270 mContext, 271 mockCallsManager, 272 mockBluetoothRouteManager, 273 mockWiredHeadsetManager, 274 mockStatusBarNotifier, 275 mAudioServiceFactory, 276 mParams.earpieceControl, 277 mHandlerThread.getLooper(), 278 Runnable::run /** do async stuff sync for test purposes */, 279 mCommunicationDeviceTracker, 280 mFeatureFlags); 281 stateMachine.setCallAudioManager(mockCallAudioManager); 282 283 setupMocksForParams(stateMachine, mParams); 284 285 // Set the initial CallAudioState object 286 final CallAudioState initState = new CallAudioState(false, 287 mParams.initialRoute, (mParams.availableRoutes | CallAudioState.ROUTE_SPEAKER), 288 mParams.initialBluetoothDevice, mParams.availableBluetoothDevices); 289 stateMachine.initialize(initState); 290 291 // Make the state machine have focus so that we actually do something 292 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, 293 CallAudioRouteStateMachine.ACTIVE_FOCUS); 294 // Tell the state machine that BT is on, if that's what the mParams say. 295 if (mParams.initialRoute == CallAudioState.ROUTE_BLUETOOTH) { 296 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED); 297 } 298 waitForHandlerAction(stateMachine.getAdapterHandler(), TEST_TIMEOUT); 299 300 // Clear invocations on mocks to discard stuff from initialization 301 clearInvocations(); 302 303 sendActionToStateMachine(stateMachine); 304 305 waitForHandlerAction(stateMachine.getAdapterHandler(), TEST_TIMEOUT); 306 waitForHandlerAction(stateMachine.getAdapterHandler(), TEST_TIMEOUT); 307 308 Handler h = stateMachine.getAdapterHandler(); 309 waitForHandlerAction(h, TEST_TIMEOUT); 310 stateMachine.quitStateMachine(); 311 312 // Verify interactions with the speakerphone and bluetooth systems 313 switch (mParams.bluetoothInteraction) { 314 case NONE: 315 verify(mockBluetoothRouteManager, never()).disconnectBluetoothAudio(); 316 verify(mockBluetoothRouteManager, never()) 317 .connectBluetoothAudio(nullable(String.class)); 318 break; 319 case ON: 320 if (mParams.expectedBluetoothDevice == null) { 321 verify(mockBluetoothRouteManager, atLeastOnce()).connectBluetoothAudio(null); 322 } else { 323 verify(mockBluetoothRouteManager).connectBluetoothAudio( 324 mParams.expectedBluetoothDevice.getAddress()); 325 } 326 verify(mockBluetoothRouteManager, never()).disconnectBluetoothAudio(); 327 break; 328 case OFF: 329 verify(mockBluetoothRouteManager, never()) 330 .connectBluetoothAudio(nullable(String.class)); 331 verify(mockBluetoothRouteManager).disconnectBluetoothAudio(); 332 break; 333 case OPTIONAL: 334 // optional, don't test 335 break; 336 } 337 338 switch (mParams.speakerInteraction) { 339 case NONE: 340 verify(mockAudioManager, never()).setCommunicationDevice( 341 any(AudioDeviceInfo.class)); 342 break; 343 case ON: 344 ArgumentCaptor<AudioDeviceInfo> infoArgumentCaptor = ArgumentCaptor.forClass( 345 AudioDeviceInfo.class); 346 verify(mockAudioManager).setCommunicationDevice(infoArgumentCaptor.capture()); 347 assertEquals(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, 348 infoArgumentCaptor.getValue().getType()); 349 break; 350 case OFF: 351 verify(mockAudioManager).clearCommunicationDevice(); 352 break; 353 case OPTIONAL: 354 // optional, don't test 355 break; 356 } 357 358 // Verify the end state 359 CallAudioState expectedState = new CallAudioState(false, mParams.expectedRoute, 360 mParams.expectedAvailableRoutes | CallAudioState.ROUTE_SPEAKER, 361 mParams.expectedBluetoothDevice, mParams.availableBluetoothDevices); 362 verifyNewSystemCallAudioState(initState, expectedState); 363 } 364 365 @Test 366 @SmallTest testQuiescentTransition()367 public void testQuiescentTransition() { 368 final CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( 369 mContext, 370 mockCallsManager, 371 mockBluetoothRouteManager, 372 mockWiredHeadsetManager, 373 mockStatusBarNotifier, 374 mAudioServiceFactory, 375 mParams.earpieceControl, 376 mHandlerThread.getLooper(), 377 Runnable::run /** do async stuff sync for test purposes */, 378 mCommunicationDeviceTracker, 379 mFeatureFlags); 380 stateMachine.setCallAudioManager(mockCallAudioManager); 381 382 // Set up bluetooth and speakerphone state 383 doReturn((mParams.availableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0 || 384 (mParams.expectedAvailableRoutes & CallAudioState.ROUTE_BLUETOOTH) != 0) 385 .when(mockBluetoothRouteManager).isBluetoothAvailable(); 386 doReturn(mParams.availableBluetoothDevices) 387 .when(mockBluetoothRouteManager).getConnectedDevices(); 388 when(mockAudioManager.isSpeakerphoneOn()).thenReturn( 389 mParams.initialRoute == CallAudioState.ROUTE_SPEAKER); 390 when(fakeCall.getSupportedAudioRoutes()).thenReturn(mParams.callSupportedRoutes); 391 392 // Set the initial CallAudioState object 393 CallAudioState initState = new CallAudioState(false, 394 mParams.initialRoute, (mParams.availableRoutes | CallAudioState.ROUTE_SPEAKER), 395 mParams.initialBluetoothDevice, mParams.availableBluetoothDevices); 396 stateMachine.initialize(initState); 397 // Omit the focus-getting statement 398 sendActionToStateMachine(stateMachine); 399 400 waitForHandlerAction(stateMachine.getAdapterHandler(), TEST_TIMEOUT); 401 waitForHandlerAction(stateMachine.getAdapterHandler(), TEST_TIMEOUT); 402 403 stateMachine.quitStateMachine(); 404 405 // Verify that no substantive interactions have taken place with the 406 // rest of the system 407 verifyNoSystemAudioChanges(); 408 409 // Special case for SPEAKER_ON -- we don't expect any route transitions to happen when 410 // there are no calls, so set the expected state to the initial route. 411 int expectedRoute = (mParams.action == CallAudioRouteStateMachine.SPEAKER_ON) 412 ? mParams.initialRoute : mParams.expectedRoute; 413 // Verify the end state 414 CallAudioState expectedState = new CallAudioState(false, expectedRoute, 415 mParams.expectedAvailableRoutes | CallAudioState.ROUTE_SPEAKER, 416 mParams.expectedBluetoothDevice, mParams.availableBluetoothDevices); 417 assertEquals(expectedState, stateMachine.getCurrentCallAudioState()); 418 } 419 420 @Parameterized.Parameters(name = "{0}") testParametersCollection()421 public static Collection<RoutingTestParameters> testParametersCollection() { 422 List<RoutingTestParameters> params = new ArrayList<>(); 423 424 params.add(new RoutingTestParameters( 425 "Connect headset during earpiece", // name 426 CallAudioState.ROUTE_EARPIECE, // initialRoute 427 CallAudioState.ROUTE_EARPIECE, // availableRoutes 428 OPTIONAL, // speakerInteraction 429 NONE, // bluetoothInteraction 430 CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action 431 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute 432 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes 433 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 434 )); 435 436 params.add(new RoutingTestParameters( 437 "Connect headset during bluetooth", // name 438 CallAudioState.ROUTE_BLUETOOTH, // initialRoute 439 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 440 OPTIONAL, // speakerInteraction 441 OFF, // bluetoothInteraction 442 CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action 443 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute 444 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai 445 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 446 )); 447 448 params.add(new RoutingTestParameters( 449 "Connect headset during speakerphone", // name 450 CallAudioState.ROUTE_SPEAKER, // initialRoute 451 CallAudioState.ROUTE_EARPIECE, // availableRoutes 452 OFF, // speakerInteraction 453 NONE, // bluetoothInteraction 454 CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET, // action 455 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute 456 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes 457 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 458 )); 459 460 params.add(new RoutingTestParameters( 461 "Disconnect headset during headset", // name 462 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute 463 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes 464 OPTIONAL, // speakerInteraction 465 NONE, // bluetoothInteraction 466 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action 467 CallAudioState.ROUTE_EARPIECE, // expectedRoute 468 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes 469 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 470 )); 471 472 params.add(new RoutingTestParameters( 473 "Disconnect headset during headset with bluetooth available", // name 474 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute 475 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou 476 OPTIONAL, // speakerInteraction 477 ON, // bluetoothInteraction 478 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action 479 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute 480 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable 481 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 482 )); 483 484 params.add(new RoutingTestParameters( 485 "Disconnect headset during bluetooth", // name 486 CallAudioState.ROUTE_BLUETOOTH, // initialRoute 487 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou 488 OPTIONAL, // speakerInteraction 489 NONE, // bluetoothInteraction 490 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action 491 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute 492 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable 493 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 494 )); 495 496 params.add(new RoutingTestParameters( 497 "Disconnect headset during speakerphone", // name 498 CallAudioState.ROUTE_SPEAKER, // initialRoute 499 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes 500 OPTIONAL, // speakerInteraction 501 NONE, // bluetoothInteraction 502 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action 503 CallAudioState.ROUTE_SPEAKER, // expectedRoute 504 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes 505 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 506 )); 507 508 params.add(new RoutingTestParameters( 509 "Disconnect headset during speakerphone with bluetooth available", // name 510 CallAudioState.ROUTE_SPEAKER, // initialRoute 511 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou 512 OPTIONAL, // speakerInteraction 513 NONE, // bluetoothInteraction 514 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action 515 CallAudioState.ROUTE_SPEAKER, // expectedRoute 516 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable 517 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 518 )); 519 520 params.add(new RoutingTestParameters( 521 "Connect bluetooth during earpiece", // name 522 CallAudioState.ROUTE_EARPIECE, // initialRoute 523 CallAudioState.ROUTE_EARPIECE, // availableRoutes 524 OPTIONAL, // speakerInteraction 525 ON, // bluetoothInteraction 526 SPECIAL_CONNECT_BT_ACTION, // action 527 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute 528 CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_EARPIECE, // expectedAvailable 529 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 530 ).setAvailableBluetoothDevices(BluetoothRouteManagerTest.DEVICE1)); 531 532 params.add(new RoutingTestParameters( 533 "Connect bluetooth during wired headset", // name 534 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute 535 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes 536 OPTIONAL, // speakerInteraction 537 ON, // bluetoothInteraction 538 SPECIAL_CONNECT_BT_ACTION, // action 539 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute 540 CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvai 541 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 542 ).setAvailableBluetoothDevices(BluetoothRouteManagerTest.DEVICE1)); 543 544 params.add(new RoutingTestParameters( 545 "Connect bluetooth during speakerphone", // name 546 CallAudioState.ROUTE_SPEAKER, // initialRoute 547 CallAudioState.ROUTE_EARPIECE, // availableRoutes 548 OFF, // speakerInteraction 549 ON, // bluetoothInteraction 550 SPECIAL_CONNECT_BT_ACTION, // action 551 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute 552 CallAudioState.ROUTE_BLUETOOTH | CallAudioState.ROUTE_EARPIECE, // expectedAvailable 553 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 554 ).setAvailableBluetoothDevices(BluetoothRouteManagerTest.DEVICE1)); 555 556 params.add(new RoutingTestParameters( 557 "Disconnect bluetooth during bluetooth without headset in", // name 558 CallAudioState.ROUTE_BLUETOOTH, // initialRoute 559 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 560 OPTIONAL, // speakerInteraction 561 NONE, // bluetoothInteraction 562 SPECIAL_DISCONNECT_BT_ACTION, // action 563 CallAudioState.ROUTE_EARPIECE, // expectedRoute 564 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes 565 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 566 )); 567 568 params.add(new RoutingTestParameters( 569 "Disconnect bluetooth during bluetooth with headset in", // name 570 CallAudioState.ROUTE_BLUETOOTH, // initialRoute 571 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou 572 OPTIONAL, // speakerInteraction 573 NONE, // bluetoothInteraction 574 SPECIAL_DISCONNECT_BT_ACTION, // action 575 CallAudioState.ROUTE_WIRED_HEADSET, // expectedRoute 576 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes 577 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 578 )); 579 580 params.add(new RoutingTestParameters( 581 "Disconnect bluetooth during speakerphone", // name 582 CallAudioState.ROUTE_SPEAKER, // initialRoute 583 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou 584 OPTIONAL, // speakerInteraction 585 NONE, // bluetoothInteraction 586 SPECIAL_DISCONNECT_BT_ACTION, // action 587 CallAudioState.ROUTE_SPEAKER, // expectedRoute 588 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes 589 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 590 )); 591 592 params.add(new RoutingTestParameters( 593 "Disconnect bluetooth during earpiece", // name 594 CallAudioState.ROUTE_EARPIECE, // initialRoute 595 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 596 OPTIONAL, // speakerInteraction 597 NONE, // bluetoothInteraction 598 SPECIAL_DISCONNECT_BT_ACTION, // action 599 CallAudioState.ROUTE_EARPIECE, // expectedRoute 600 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes 601 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 602 )); 603 604 params.add(new RoutingTestParameters( 605 "Switch to speakerphone from earpiece", // name 606 CallAudioState.ROUTE_EARPIECE, // initialRoute 607 CallAudioState.ROUTE_EARPIECE, // availableRoutes 608 ON, // speakerInteraction 609 NONE, // bluetoothInteraction 610 CallAudioRouteStateMachine.SWITCH_SPEAKER, // action 611 CallAudioState.ROUTE_SPEAKER, // expectedRoute 612 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes 613 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 614 )); 615 616 params.add(new RoutingTestParameters( 617 "Switch to speakerphone from headset", // name 618 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute 619 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes 620 ON, // speakerInteraction 621 NONE, // bluetoothInteraction 622 CallAudioRouteStateMachine.SWITCH_SPEAKER, // action 623 CallAudioState.ROUTE_SPEAKER, // expectedRoute 624 CallAudioState.ROUTE_WIRED_HEADSET, // expectedAvailableRoutes 625 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 626 )); 627 628 params.add(new RoutingTestParameters( 629 "Switch to speakerphone from bluetooth", // name 630 CallAudioState.ROUTE_BLUETOOTH, // initialRoute 631 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou 632 ON, // speakerInteraction 633 OFF, // bluetoothInteraction 634 CallAudioRouteStateMachine.SWITCH_SPEAKER, // action 635 CallAudioState.ROUTE_SPEAKER, // expectedRoute 636 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai 637 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 638 )); 639 640 params.add(new RoutingTestParameters( 641 "Switch to earpiece from bluetooth", // name 642 CallAudioState.ROUTE_BLUETOOTH, // initialRoute 643 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 644 OPTIONAL, // speakerInteraction 645 OFF, // bluetoothInteraction 646 CallAudioRouteStateMachine.SWITCH_EARPIECE, // action 647 CallAudioState.ROUTE_EARPIECE, // expectedRoute 648 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable 649 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 650 )); 651 652 params.add(new RoutingTestParameters( 653 "Switch to earpiece from speakerphone", // name 654 CallAudioState.ROUTE_SPEAKER, // initialRoute 655 CallAudioState.ROUTE_EARPIECE, // availableRoutes 656 OFF, // speakerInteraction 657 NONE, // bluetoothInteraction 658 CallAudioRouteStateMachine.SWITCH_EARPIECE, // action 659 CallAudioState.ROUTE_EARPIECE, // expectedRoute 660 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes 661 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 662 )); 663 664 params.add(new RoutingTestParameters( 665 "Switch to earpiece from speakerphone, priority notifications", // name 666 CallAudioState.ROUTE_SPEAKER, // initialRoute 667 CallAudioState.ROUTE_EARPIECE, // availableRoutes 668 OFF, // speakerInteraction 669 NONE, // bluetoothInteraction 670 CallAudioRouteStateMachine.SWITCH_EARPIECE, // action 671 CallAudioState.ROUTE_EARPIECE, // expectedRoute 672 CallAudioState.ROUTE_EARPIECE, // expectedAvailableRoutes 673 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 674 )); 675 676 params.add(new RoutingTestParameters( 677 "Switch to earpiece from speakerphone, silent mode", // 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 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 686 )); 687 688 params.add(new RoutingTestParameters( 689 "Switch to bluetooth from speakerphone", // name 690 CallAudioState.ROUTE_SPEAKER, // initialRoute 691 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 692 OFF, // speakerInteraction 693 ON, // bluetoothInteraction 694 CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action 695 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute 696 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable 697 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 698 )); 699 700 params.add(new RoutingTestParameters( 701 "Switch to bluetooth from earpiece", // name 702 CallAudioState.ROUTE_EARPIECE, // initialRoute 703 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 704 OPTIONAL, // speakerInteraction 705 ON, // bluetoothInteraction 706 CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action 707 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute 708 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailable 709 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 710 )); 711 712 params.add(new RoutingTestParameters( 713 "Switch to bluetooth from wired headset", // name 714 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute 715 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // availableRou 716 OPTIONAL, // speakerInteraction 717 ON, // bluetoothInteraction 718 CallAudioRouteStateMachine.SWITCH_BLUETOOTH, // action 719 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute 720 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_BLUETOOTH, // expectedAvai 721 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 722 )); 723 724 params.add(new RoutingTestParameters( 725 "Switch from bluetooth to wired/earpiece when neither are available", // name 726 CallAudioState.ROUTE_BLUETOOTH, // initialRoute 727 CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 728 ON, // speakerInteraction 729 OFF, // bluetoothInteraction 730 CallAudioRouteStateMachine.SWITCH_BASELINE_ROUTE, // action 731 CallAudioState.ROUTE_SPEAKER, // expectedRoute 732 CallAudioState.ROUTE_BLUETOOTH, // expectedAvailableRoutes 733 CallAudioRouteStateMachine.EARPIECE_FORCE_DISABLED // earpieceControl 734 )); 735 736 params.add(new RoutingTestParameters( 737 "Disconnect wired headset when device does not support earpiece", // name 738 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute 739 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes 740 ON, // speakerInteraction 741 NONE, // bluetoothInteraction 742 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action 743 CallAudioState.ROUTE_SPEAKER, // expectedRoute 744 CallAudioState.ROUTE_SPEAKER, // expectedAvailableRoutes 745 CallAudioRouteStateMachine.EARPIECE_FORCE_DISABLED // earpieceControl 746 )); 747 748 params.add(new RoutingTestParameters( 749 "Disconnect wired headset when call doesn't support earpiece", // name 750 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute 751 CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes 752 ON, // speakerInteraction 753 NONE, // bluetoothInteraction 754 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET, // action 755 CallAudioState.ROUTE_SPEAKER, // expectedRoute 756 CallAudioState.ROUTE_SPEAKER, // expectedAvailableRoutes 757 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 758 ).setCallSupportedRoutes(CallAudioState.ROUTE_ALL & ~CallAudioState.ROUTE_EARPIECE)); 759 760 params.add(new RoutingTestParameters( 761 "Disconnect bluetooth when call does not support earpiece", // name 762 CallAudioState.ROUTE_BLUETOOTH, // initialRoute 763 CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 764 ON, // speakerInteraction 765 NONE, // bluetoothInteraction 766 SPECIAL_DISCONNECT_BT_ACTION, // action 767 CallAudioState.ROUTE_SPEAKER, // expectedRoute 768 CallAudioState.ROUTE_SPEAKER, // expectedAvailableRoutes 769 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 770 ).setCallSupportedRoutes(CallAudioState.ROUTE_ALL & ~CallAudioState.ROUTE_EARPIECE)); 771 772 params.add(new RoutingTestParameters( 773 "Active device deselected during BT", // name 774 CallAudioState.ROUTE_BLUETOOTH, // initialRoute 775 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 776 OPTIONAL, // speakerInteraction 777 NONE, // bluetoothInteraction 778 CallAudioRouteStateMachine.BT_ACTIVE_DEVICE_GONE, // action 779 CallAudioState.ROUTE_EARPIECE, // expectedRoute 780 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailabl 781 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 782 )); 783 784 params.add(new RoutingTestParameters( 785 "Active device selected during earpiece", // name 786 CallAudioState.ROUTE_EARPIECE, // initialRoute 787 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 788 OPTIONAL, // speakerInteraction 789 ON, // bluetoothInteraction 790 CallAudioRouteStateMachine.BT_ACTIVE_DEVICE_PRESENT, // action 791 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute 792 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailabl 793 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 794 )); 795 796 params.add(new RoutingTestParameters( 797 "Speakerphone turned on during earpiece", // name 798 CallAudioState.ROUTE_EARPIECE, // initialRoute 799 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 800 NONE, // speakerInteraction 801 NONE, // bluetoothInteraction 802 CallAudioRouteStateMachine.SPEAKER_ON, // action 803 CallAudioState.ROUTE_SPEAKER, // expectedRoute 804 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailabl 805 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 806 )); 807 808 params.add(new RoutingTestParameters( 809 "Speakerphone turned on during wired headset", // name 810 CallAudioState.ROUTE_WIRED_HEADSET, // initialRoute 811 CallAudioState.ROUTE_EARPIECE 812 | CallAudioState.ROUTE_BLUETOOTH 813 | CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes 814 NONE, // speakerInteraction 815 NONE, // bluetoothInteraction 816 CallAudioRouteStateMachine.SPEAKER_ON, // action 817 CallAudioState.ROUTE_SPEAKER, // expectedRoute 818 CallAudioState.ROUTE_EARPIECE 819 | CallAudioState.ROUTE_BLUETOOTH 820 | CallAudioState.ROUTE_WIRED_HEADSET, // availableRoutes 821 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 822 )); 823 824 params.add(new RoutingTestParameters( 825 "Speakerphone turned on during bluetooth", // name 826 CallAudioState.ROUTE_BLUETOOTH, // initialRoute 827 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 828 NONE, // speakerInteraction 829 OFF, // bluetoothInteraction 830 CallAudioRouteStateMachine.SPEAKER_ON, // action 831 CallAudioState.ROUTE_SPEAKER, // expectedRoute 832 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailabl 833 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 834 )); 835 836 params.add(new RoutingTestParameters( 837 "Speakerphone turned off externally during speaker", // name 838 CallAudioState.ROUTE_SPEAKER, // initialRoute 839 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // availableRoutes 840 OFF, // speakerInteraction 841 ON, // bluetoothInteraction 842 CallAudioRouteStateMachine.SPEAKER_OFF, // action 843 CallAudioState.ROUTE_BLUETOOTH, // expectedRoute 844 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, // expectedAvailabl 845 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 846 )); 847 848 params.add(new RoutingTestParameters( 849 "Connect dock from earpiece", // name 850 CallAudioState.ROUTE_EARPIECE, // initialRoute 851 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // availableRoutes 852 ON, // speakerInteraction 853 NONE, // bluetoothInteraction 854 CallAudioRouteStateMachine.CONNECT_DOCK, // action 855 CallAudioState.ROUTE_SPEAKER, // expectedRoute 856 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // expectedAvailRoutes 857 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 858 )); 859 860 params.add(new RoutingTestParameters( 861 "Disconnect dock from speaker", // name 862 CallAudioState.ROUTE_SPEAKER, // initialRoute 863 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // availableRoutes 864 OFF, // speakerInteraction 865 NONE, // bluetoothInteraction 866 CallAudioRouteStateMachine.DISCONNECT_DOCK, // action 867 CallAudioState.ROUTE_EARPIECE, // expectedRoute 868 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // expectedAvailRoutes 869 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl 870 )); 871 872 return params; 873 } 874 verifyNewSystemCallAudioState(CallAudioState expectedOldState, CallAudioState expectedNewState)875 private void verifyNewSystemCallAudioState(CallAudioState expectedOldState, 876 CallAudioState expectedNewState) { 877 ArgumentCaptor<CallAudioState> oldStateCaptor = ArgumentCaptor.forClass( 878 CallAudioState.class); 879 ArgumentCaptor<CallAudioState> newStateCaptor1 = ArgumentCaptor.forClass( 880 CallAudioState.class); 881 ArgumentCaptor<CallAudioState> newStateCaptor2 = ArgumentCaptor.forClass( 882 CallAudioState.class); 883 verify(mockCallsManager, timeout(TEST_TIMEOUT).atLeastOnce()).onCallAudioStateChanged( 884 oldStateCaptor.capture(), newStateCaptor1.capture()); 885 verify(mockConnectionServiceWrapper, timeout(TEST_TIMEOUT).atLeastOnce()) 886 .onCallAudioStateChanged(same(fakeCall), newStateCaptor2.capture()); 887 888 assertEquals(expectedOldState, oldStateCaptor.getAllValues().get(0)); 889 assertEquals(expectedNewState, newStateCaptor1.getValue()); 890 assertEquals(expectedNewState, newStateCaptor2.getValue()); 891 } 892 verifyNoSystemAudioChanges()893 private void verifyNoSystemAudioChanges() { 894 verify(mockBluetoothRouteManager, never()).disconnectBluetoothAudio(); 895 verify(mockBluetoothRouteManager, never()).connectBluetoothAudio(nullable(String.class)); 896 verify(mockAudioManager, never()).setSpeakerphoneOn(any(Boolean.class)); 897 verify(mockCallsManager, never()).onCallAudioStateChanged(any(CallAudioState.class), 898 any(CallAudioState.class)); 899 verify(mockConnectionServiceWrapper, never()).onCallAudioStateChanged( 900 any(Call.class), any(CallAudioState.class)); 901 } 902 clearInvocations()903 private void clearInvocations() { 904 Mockito.clearInvocations(mockAudioManager, mockBluetoothRouteManager, mockCallsManager, 905 mockConnectionServiceWrapper); 906 } 907 }