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.bluetooth.BluetoothDevice; 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.MediumTest; 25 import android.test.suitebuilder.annotation.SmallTest; 26 27 import com.android.server.telecom.bluetooth.BluetoothRouteManager; 28 import com.android.server.telecom.Call; 29 import com.android.server.telecom.CallAudioRouteStateMachine; 30 import com.android.server.telecom.CallsManager; 31 import com.android.server.telecom.ConnectionServiceWrapper; 32 import com.android.server.telecom.CallAudioManager; 33 import com.android.server.telecom.StatusBarNotifier; 34 import com.android.server.telecom.TelecomSystem; 35 import com.android.server.telecom.WiredHeadsetManager; 36 37 import org.junit.Before; 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 import org.junit.runners.JUnit4; 41 import org.mockito.ArgumentCaptor; 42 import org.mockito.Mock; 43 import org.mockito.MockitoAnnotations; 44 import org.mockito.invocation.InvocationOnMock; 45 import org.mockito.stubbing.Answer; 46 47 import java.util.Arrays; 48 import java.util.Collection; 49 import java.util.Collections; 50 import java.util.List; 51 52 import static org.junit.Assert.assertEquals; 53 import static org.junit.Assert.assertNotNull; 54 import static org.junit.Assert.assertTrue; 55 import static org.mockito.ArgumentMatchers.nullable; 56 import static org.mockito.Matchers.any; 57 import static org.mockito.Matchers.same; 58 import static org.mockito.Mockito.doAnswer; 59 import static org.mockito.Mockito.doNothing; 60 import static org.mockito.Mockito.mock; 61 import static org.mockito.Mockito.never; 62 import static org.mockito.Mockito.reset; 63 import static org.mockito.Mockito.timeout; 64 import static org.mockito.Mockito.times; 65 import static org.mockito.Mockito.verify; 66 import static org.mockito.Mockito.when; 67 68 @RunWith(JUnit4.class) 69 public class CallAudioRouteStateMachineTest extends TelecomSystemTest { 70 71 private static final BluetoothDevice bluetoothDevice1 = 72 BluetoothRouteManagerTest.makeBluetoothDevice("00:00:00:00:00:01"); 73 private static final BluetoothDevice bluetoothDevice2 = 74 BluetoothRouteManagerTest.makeBluetoothDevice("00:00:00:00:00:02"); 75 private static final BluetoothDevice bluetoothDevice3 = 76 BluetoothRouteManagerTest.makeBluetoothDevice("00:00:00:00:00:03"); 77 78 @Mock CallsManager mockCallsManager; 79 @Mock BluetoothRouteManager mockBluetoothRouteManager; 80 @Mock IAudioService mockAudioService; 81 @Mock ConnectionServiceWrapper mockConnectionServiceWrapper; 82 @Mock WiredHeadsetManager mockWiredHeadsetManager; 83 @Mock StatusBarNotifier mockStatusBarNotifier; 84 @Mock Call fakeCall; 85 @Mock CallAudioManager mockCallAudioManager; 86 87 private CallAudioManager.AudioServiceFactory mAudioServiceFactory; 88 private static final int TEST_TIMEOUT = 500; 89 private AudioManager mockAudioManager; 90 private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { }; 91 92 @Override 93 @Before 94 public void setUp() throws Exception { 95 super.setUp(); 96 MockitoAnnotations.initMocks(this); 97 mContext = mComponentContextFixture.getTestDouble().getApplicationContext(); 98 mockAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 99 100 mAudioServiceFactory = new CallAudioManager.AudioServiceFactory() { 101 @Override 102 public IAudioService getAudioService() { 103 return mockAudioService; 104 } 105 }; 106 107 when(mockCallsManager.getForegroundCall()).thenReturn(fakeCall); 108 when(mockCallsManager.getLock()).thenReturn(mLock); 109 when(mockCallsManager.hasVideoCall()).thenReturn(false); 110 when(fakeCall.getConnectionService()).thenReturn(mockConnectionServiceWrapper); 111 when(fakeCall.isAlive()).thenReturn(true); 112 when(fakeCall.getSupportedAudioRoutes()).thenReturn(CallAudioState.ROUTE_ALL); 113 114 doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class), 115 any(CallAudioState.class)); 116 } 117 118 @SmallTest 119 @Test 120 public void testEarpieceAutodetect() { 121 CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( 122 mContext, 123 mockCallsManager, 124 mockBluetoothRouteManager, 125 mockWiredHeadsetManager, 126 mockStatusBarNotifier, 127 mAudioServiceFactory, 128 CallAudioRouteStateMachine.EARPIECE_AUTO_DETECT); 129 130 // Since we don't know if we're on a platform with an earpiece or not, all we can do 131 // is ensure the stateMachine construction didn't fail. But at least we exercised the 132 // autodetection code... 133 assertNotNull(stateMachine); 134 } 135 136 @MediumTest 137 @Test 138 public void testSpeakerPersistence() { 139 CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( 140 mContext, 141 mockCallsManager, 142 mockBluetoothRouteManager, 143 mockWiredHeadsetManager, 144 mockStatusBarNotifier, 145 mAudioServiceFactory, 146 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 147 148 when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false); 149 when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true); 150 when(mockAudioManager.isSpeakerphoneOn()).thenReturn(true); 151 doAnswer(new Answer() { 152 @Override 153 public Object answer(InvocationOnMock invocation) throws Throwable { 154 Object[] args = invocation.getArguments(); 155 when(mockAudioManager.isSpeakerphoneOn()).thenReturn((Boolean) args[0]); 156 return null; 157 } 158 }).when(mockAudioManager).setSpeakerphoneOn(any(Boolean.class)); 159 CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER, 160 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER); 161 stateMachine.initialize(initState); 162 163 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, 164 CallAudioRouteStateMachine.ACTIVE_FOCUS); 165 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.CONNECT_WIRED_HEADSET); 166 CallAudioState expectedMiddleState = new CallAudioState(false, 167 CallAudioState.ROUTE_WIRED_HEADSET, 168 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_SPEAKER); 169 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 170 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 171 verifyNewSystemCallAudioState(initState, expectedMiddleState); 172 resetMocks(); 173 174 stateMachine.sendMessageWithSessionInfo( 175 CallAudioRouteStateMachine.DISCONNECT_WIRED_HEADSET); 176 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 177 verifyNewSystemCallAudioState(expectedMiddleState, initState); 178 } 179 180 @MediumTest 181 @Test 182 public void testUserBluetoothSwitchOff() { 183 CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( 184 mContext, 185 mockCallsManager, 186 mockBluetoothRouteManager, 187 mockWiredHeadsetManager, 188 mockStatusBarNotifier, 189 mAudioServiceFactory, 190 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 191 stateMachine.setCallAudioManager(mockCallAudioManager); 192 193 when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false); 194 when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true); 195 when(mockAudioManager.isSpeakerphoneOn()).thenReturn(true); 196 197 CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH, 198 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH); 199 stateMachine.initialize(initState); 200 201 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, 202 CallAudioRouteStateMachine.ACTIVE_FOCUS); 203 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED); 204 stateMachine.sendMessageWithSessionInfo( 205 CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE, 206 CallAudioRouteStateMachine.NO_INCLUDE_BLUETOOTH_IN_BASELINE); 207 CallAudioState expectedEndState = new CallAudioState(false, 208 CallAudioState.ROUTE_EARPIECE, 209 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH); 210 211 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 212 verifyNewSystemCallAudioState(initState, expectedEndState); 213 resetMocks(); 214 stateMachine.sendMessageWithSessionInfo( 215 CallAudioRouteStateMachine.BT_ACTIVE_DEVICE_GONE); 216 stateMachine.sendMessageWithSessionInfo( 217 CallAudioRouteStateMachine.BT_ACTIVE_DEVICE_PRESENT); 218 219 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 220 assertEquals(expectedEndState, stateMachine.getCurrentCallAudioState()); 221 } 222 223 @MediumTest 224 @Test 225 public void testUserBluetoothSwitchOffAndOnAgain() { 226 CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( 227 mContext, 228 mockCallsManager, 229 mockBluetoothRouteManager, 230 mockWiredHeadsetManager, 231 mockStatusBarNotifier, 232 mAudioServiceFactory, 233 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 234 stateMachine.setCallAudioManager(mockCallAudioManager); 235 Collection<BluetoothDevice> availableDevices = Collections.singleton(bluetoothDevice1); 236 237 when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false); 238 when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true); 239 when(mockBluetoothRouteManager.getConnectedDevices()).thenReturn(availableDevices); 240 241 CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH, 242 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH); 243 stateMachine.initialize(initState); 244 245 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, 246 CallAudioRouteStateMachine.ACTIVE_FOCUS); 247 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED); 248 249 // Switch off the BT route explicitly. 250 stateMachine.sendMessageWithSessionInfo( 251 CallAudioRouteStateMachine.USER_SWITCH_BASELINE_ROUTE, 252 CallAudioRouteStateMachine.NO_INCLUDE_BLUETOOTH_IN_BASELINE); 253 CallAudioState expectedMidState = new CallAudioState(false, 254 CallAudioState.ROUTE_EARPIECE, 255 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, 256 null, availableDevices); 257 258 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 259 verifyNewSystemCallAudioState(initState, expectedMidState); 260 resetMocks(); 261 262 // Now, switch back to BT explicitly 263 when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false); 264 when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true); 265 when(mockBluetoothRouteManager.getConnectedDevices()).thenReturn(availableDevices); 266 doAnswer(invocation -> { 267 when(mockBluetoothRouteManager.getBluetoothAudioConnectedDevice()) 268 .thenReturn(bluetoothDevice1); 269 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED); 270 return null; 271 }).when(mockBluetoothRouteManager).connectBluetoothAudio(nullable(String.class)); 272 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.USER_SWITCH_BLUETOOTH); 273 CallAudioState expectedEndState = new CallAudioState(false, 274 CallAudioState.ROUTE_BLUETOOTH, 275 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, 276 bluetoothDevice1, availableDevices); 277 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 278 // second wait needed for the BT_AUDIO_CONNECTED message 279 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 280 verifyNewSystemCallAudioState(expectedMidState, expectedEndState); 281 282 stateMachine.sendMessageWithSessionInfo( 283 CallAudioRouteStateMachine.BT_ACTIVE_DEVICE_GONE); 284 when(mockBluetoothRouteManager.getBluetoothAudioConnectedDevice()) 285 .thenReturn(null); 286 stateMachine.sendMessageWithSessionInfo( 287 CallAudioRouteStateMachine.BT_ACTIVE_DEVICE_PRESENT); 288 289 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 290 // second wait needed for the BT_AUDIO_CONNECTED message 291 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 292 // Verify that we're still on bluetooth. 293 assertEquals(expectedEndState, stateMachine.getCurrentCallAudioState()); 294 } 295 296 @MediumTest 297 @Test 298 public void testBluetoothRinging() { 299 CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( 300 mContext, 301 mockCallsManager, 302 mockBluetoothRouteManager, 303 mockWiredHeadsetManager, 304 mockStatusBarNotifier, 305 mAudioServiceFactory, 306 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 307 stateMachine.setCallAudioManager(mockCallAudioManager); 308 309 when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false); 310 when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true); 311 when(mockBluetoothRouteManager.getConnectedDevices()) 312 .thenReturn(Collections.singletonList(bluetoothDevice1)); 313 when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false); 314 315 CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH, 316 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH); 317 stateMachine.initialize(initState); 318 319 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, 320 CallAudioRouteStateMachine.RINGING_FOCUS); 321 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 322 323 verify(mockBluetoothRouteManager, never()).connectBluetoothAudio(nullable(String.class)); 324 325 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, 326 CallAudioRouteStateMachine.ACTIVE_FOCUS); 327 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 328 verify(mockBluetoothRouteManager, times(1)).connectBluetoothAudio(nullable(String.class)); 329 } 330 331 @MediumTest 332 @Test 333 public void testConnectBluetoothDuringRinging() { 334 CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( 335 mContext, 336 mockCallsManager, 337 mockBluetoothRouteManager, 338 mockWiredHeadsetManager, 339 mockStatusBarNotifier, 340 mAudioServiceFactory, 341 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 342 stateMachine.setCallAudioManager(mockCallAudioManager); 343 setInBandRing(false); 344 when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false); 345 when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(false); 346 when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false); 347 CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE, 348 CallAudioState.ROUTE_EARPIECE); 349 stateMachine.initialize(initState); 350 351 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, 352 CallAudioRouteStateMachine.RINGING_FOCUS); 353 // Wait for the state machine to finish transiting to ActiveEarpiece before hooking up 354 // bluetooth mocks 355 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 356 357 when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true); 358 when(mockBluetoothRouteManager.getConnectedDevices()) 359 .thenReturn(Collections.singletonList(bluetoothDevice1)); 360 stateMachine.sendMessageWithSessionInfo( 361 CallAudioRouteStateMachine.BLUETOOTH_DEVICE_LIST_CHANGED); 362 stateMachine.sendMessageWithSessionInfo( 363 CallAudioRouteStateMachine.BT_ACTIVE_DEVICE_PRESENT); 364 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 365 366 verify(mockBluetoothRouteManager, never()).connectBluetoothAudio(null); 367 CallAudioState expectedEndState = new CallAudioState(false, 368 CallAudioState.ROUTE_BLUETOOTH, 369 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, 370 null, Collections.singletonList(bluetoothDevice1)); 371 verifyNewSystemCallAudioState(initState, expectedEndState); 372 373 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, 374 CallAudioRouteStateMachine.ACTIVE_FOCUS); 375 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 376 verify(mockBluetoothRouteManager, times(1)).connectBluetoothAudio(null); 377 378 when(mockBluetoothRouteManager.getBluetoothAudioConnectedDevice()) 379 .thenReturn(bluetoothDevice1); 380 stateMachine.sendMessage(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED); 381 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 382 verify(mockCallAudioManager, times(1)).onRingerModeChange(); 383 } 384 385 @SmallTest 386 @Test 387 public void testConnectSpecificBluetoothDevice() { 388 CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( 389 mContext, 390 mockCallsManager, 391 mockBluetoothRouteManager, 392 mockWiredHeadsetManager, 393 mockStatusBarNotifier, 394 mAudioServiceFactory, 395 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 396 stateMachine.setCallAudioManager(mockCallAudioManager); 397 List<BluetoothDevice> availableDevices = 398 Arrays.asList(bluetoothDevice1, bluetoothDevice2, bluetoothDevice3); 399 400 when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false); 401 when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false); 402 when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true); 403 when(mockBluetoothRouteManager.getConnectedDevices()).thenReturn(availableDevices); 404 doAnswer(invocation -> { 405 when(mockBluetoothRouteManager.getBluetoothAudioConnectedDevice()) 406 .thenReturn(bluetoothDevice2); 407 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED); 408 return null; 409 }).when(mockBluetoothRouteManager).connectBluetoothAudio(bluetoothDevice2.getAddress()); 410 411 CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE, 412 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, null, 413 availableDevices); 414 stateMachine.initialize(initState); 415 416 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, 417 CallAudioRouteStateMachine.ACTIVE_FOCUS); 418 419 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.USER_SWITCH_BLUETOOTH, 420 0, bluetoothDevice2.getAddress()); 421 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 422 423 verify(mockBluetoothRouteManager).connectBluetoothAudio(bluetoothDevice2.getAddress()); 424 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 425 CallAudioState expectedEndState = new CallAudioState(false, 426 CallAudioState.ROUTE_BLUETOOTH, 427 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, 428 bluetoothDevice2, 429 availableDevices); 430 431 verifyNewSystemCallAudioState(initState, expectedEndState); 432 } 433 434 @SmallTest 435 @Test 436 public void testFocusChangeWithAlreadyActiveBtDevice() { 437 CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( 438 mContext, 439 mockCallsManager, 440 mockBluetoothRouteManager, 441 mockWiredHeadsetManager, 442 mockStatusBarNotifier, 443 mAudioServiceFactory, 444 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 445 stateMachine.setCallAudioManager(mockCallAudioManager); 446 List<BluetoothDevice> availableDevices = 447 Arrays.asList(bluetoothDevice1, bluetoothDevice2); 448 449 // Set up a state where there's an HFP connected bluetooth device already. 450 when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false); 451 when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true); 452 when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true); 453 when(mockBluetoothRouteManager.getConnectedDevices()).thenReturn(availableDevices); 454 when(mockBluetoothRouteManager.getBluetoothAudioConnectedDevice()) 455 .thenReturn(bluetoothDevice1); 456 457 // We want to be in the QuiescentBluetoothRoute because there's no call yet 458 CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH, 459 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_BLUETOOTH, 460 bluetoothDevice1, availableDevices); 461 stateMachine.initialize(initState); 462 463 // Switch to active, pretending that a call came in. 464 stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.SWITCH_FOCUS, 465 CallAudioRouteStateMachine.ACTIVE_FOCUS); 466 waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT); 467 468 // Make sure that we've successfully switched to the active BT route without actually 469 // calling connectAudio. 470 verify(mockBluetoothRouteManager, never()).connectBluetoothAudio(nullable(String.class)); 471 assertTrue(stateMachine.isInActiveState()); 472 } 473 474 @SmallTest 475 @Test 476 public void testInitializationWithEarpieceNoHeadsetNoBluetooth() { 477 CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE, 478 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER); 479 initializationTestHelper(expectedState, CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 480 } 481 482 @SmallTest 483 @Test 484 public void testInitializationWithEarpieceAndHeadsetNoBluetooth() { 485 CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_WIRED_HEADSET, 486 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_SPEAKER); 487 initializationTestHelper(expectedState, CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 488 } 489 490 @SmallTest 491 @Test 492 public void testInitializationWithEarpieceAndHeadsetAndBluetooth() { 493 CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH, 494 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_SPEAKER 495 | CallAudioState.ROUTE_BLUETOOTH); 496 initializationTestHelper(expectedState, CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 497 } 498 499 @SmallTest 500 @Test 501 public void testInitializationWithEarpieceAndBluetoothNoHeadset() { 502 CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH, 503 CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER 504 | CallAudioState.ROUTE_BLUETOOTH); 505 initializationTestHelper(expectedState, CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED); 506 } 507 508 @SmallTest 509 @Test 510 public void testInitializationWithNoEarpieceNoHeadsetNoBluetooth() { 511 CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER, 512 CallAudioState.ROUTE_SPEAKER); 513 initializationTestHelper(expectedState, CallAudioRouteStateMachine.EARPIECE_FORCE_DISABLED); 514 } 515 516 @SmallTest 517 @Test 518 public void testInitializationWithHeadsetNoBluetoothNoEarpiece() { 519 CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_WIRED_HEADSET, 520 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_SPEAKER); 521 initializationTestHelper(expectedState, CallAudioRouteStateMachine.EARPIECE_FORCE_DISABLED); 522 } 523 524 @SmallTest 525 @Test 526 public void testInitializationWithHeadsetAndBluetoothNoEarpiece() { 527 CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH, 528 CallAudioState.ROUTE_WIRED_HEADSET | CallAudioState.ROUTE_SPEAKER 529 | CallAudioState.ROUTE_BLUETOOTH); 530 initializationTestHelper(expectedState, CallAudioRouteStateMachine.EARPIECE_FORCE_DISABLED); 531 } 532 533 @SmallTest 534 @Test 535 public void testInitializationWithBluetoothNoHeadsetNoEarpiece() { 536 CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_BLUETOOTH, 537 CallAudioState.ROUTE_SPEAKER | CallAudioState.ROUTE_BLUETOOTH); 538 initializationTestHelper(expectedState, CallAudioRouteStateMachine.EARPIECE_FORCE_DISABLED); 539 } 540 541 private void initializationTestHelper(CallAudioState expectedState, 542 int earpieceControl) { 543 when(mockWiredHeadsetManager.isPluggedIn()).thenReturn( 544 (expectedState.getSupportedRouteMask() & CallAudioState.ROUTE_WIRED_HEADSET) != 0); 545 when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn( 546 (expectedState.getSupportedRouteMask() & CallAudioState.ROUTE_BLUETOOTH) != 0); 547 548 CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine( 549 mContext, 550 mockCallsManager, 551 mockBluetoothRouteManager, 552 mockWiredHeadsetManager, 553 mockStatusBarNotifier, 554 mAudioServiceFactory, 555 earpieceControl); 556 stateMachine.initialize(); 557 assertEquals(expectedState, stateMachine.getCurrentCallAudioState()); 558 } 559 560 private void verifyNewSystemCallAudioState(CallAudioState expectedOldState, 561 CallAudioState expectedNewState) { 562 ArgumentCaptor<CallAudioState> oldStateCaptor = ArgumentCaptor.forClass( 563 CallAudioState.class); 564 ArgumentCaptor<CallAudioState> newStateCaptor1 = ArgumentCaptor.forClass( 565 CallAudioState.class); 566 ArgumentCaptor<CallAudioState> newStateCaptor2 = ArgumentCaptor.forClass( 567 CallAudioState.class); 568 verify(mockCallsManager, timeout(TEST_TIMEOUT).atLeastOnce()).onCallAudioStateChanged( 569 oldStateCaptor.capture(), newStateCaptor1.capture()); 570 verify(mockConnectionServiceWrapper, timeout(TEST_TIMEOUT).atLeastOnce()) 571 .onCallAudioStateChanged(same(fakeCall), newStateCaptor2.capture()); 572 573 assertTrue(oldStateCaptor.getAllValues().get(0).equals(expectedOldState)); 574 assertTrue(newStateCaptor1.getValue().equals(expectedNewState)); 575 assertTrue(newStateCaptor2.getValue().equals(expectedNewState)); 576 } 577 578 private void setInBandRing(boolean enabled) { 579 when(mockBluetoothRouteManager.isInbandRingingEnabled()).thenReturn(enabled); 580 } 581 582 private void resetMocks() { 583 reset(mockAudioManager, mockBluetoothRouteManager, mockCallsManager, 584 mockConnectionServiceWrapper); 585 fakeCall = mock(Call.class); 586 when(mockCallsManager.getForegroundCall()).thenReturn(fakeCall); 587 when(fakeCall.getConnectionService()).thenReturn(mockConnectionServiceWrapper); 588 when(fakeCall.isAlive()).thenReturn(true); 589 when(fakeCall.getSupportedAudioRoutes()).thenReturn(CallAudioState.ROUTE_ALL); 590 when(mockCallsManager.getLock()).thenReturn(mLock); 591 doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class), 592 any(CallAudioState.class)); 593 } 594 } 595