Home | History | Annotate | Download | only in tests
      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