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 org.junit.After;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.junit.runner.RunWith;
23 import org.junit.runners.JUnit4;
24 import org.mockito.ArgumentCaptor;
25 
26 import android.os.Process;
27 import android.os.RemoteException;
28 import android.telecom.CallAudioState;
29 import android.telecom.DisconnectCause;
30 import android.telecom.VideoProfile;
31 import android.test.suitebuilder.annotation.LargeTest;
32 import android.test.suitebuilder.annotation.MediumTest;
33 
34 import com.android.server.telecom.CallAudioModeStateMachine;
35 import com.android.server.telecom.CallAudioRouteStateMachine;
36 
37 import java.util.List;
38 
39 import static org.junit.Assert.assertEquals;
40 import static org.junit.Assert.assertFalse;
41 import static org.junit.Assert.assertTrue;
42 import static org.junit.Assert.fail;
43 import static org.mockito.Mockito.atLeastOnce;
44 import static org.mockito.Mockito.verify;
45 
46 /**
47  * System tests for video-specific behavior in telecom.
48  * TODO: Add unit tests which ensure that auto-speakerphone does not occur when using a wired
49  * headset or a bluetooth headset.
50  */
51 @RunWith(JUnit4.class)
52 public class VideoCallTests extends TelecomSystemTest {
53 
54     @Override
55     @Before
setUp()56     public void setUp() throws Exception {
57         super.setUp();
58     }
59 
60     @Override
61     @After
tearDown()62     public void tearDown() throws Exception {
63         super.tearDown();
64     }
65 
66     /**
67      * Tests to ensure an incoming video-call is automatically routed to the speakerphone when
68      * the call is answered and neither a wired headset nor bluetooth headset are connected.
69      */
70     @MediumTest
71     @Test
testAutoSpeakerphoneIncomingBidirectional()72     public void testAutoSpeakerphoneIncomingBidirectional() throws Exception {
73         // Start an incoming video call.
74         IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
75                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
76                 VideoProfile.STATE_BIDIRECTIONAL);
77 
78         verifyAudioRoute(CallAudioState.ROUTE_SPEAKER);
79     }
80 
81     /**
82      * Tests to ensure an incoming receive-only video-call is answered in speakerphone mode.  Note
83      * that this is not a scenario we would expect normally with the default dialer as it will
84      * always answer incoming video calls as bi-directional.  It is, however, possible for a third
85      * party dialer to answer an incoming video call a a one-way video call.
86      */
87     @MediumTest
88     @Test
testAutoSpeakerphoneIncomingReceiveOnly()89     public void testAutoSpeakerphoneIncomingReceiveOnly() throws Exception {
90         // Start an incoming video call.
91         IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
92                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
93                 VideoProfile.STATE_RX_ENABLED);
94 
95         verifyAudioRoute(CallAudioState.ROUTE_SPEAKER);
96     }
97 
98     /**
99      * Tests audio routing for an outgoing video call made with bidirectional video.  Expect to be
100      * in speaker mode.
101      */
102     @MediumTest
103     @Test
testAutoSpeakerphoneOutgoingBidirectional()104     public void testAutoSpeakerphoneOutgoingBidirectional() throws Exception {
105         // Start an incoming video call.
106         IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
107                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
108                 VideoProfile.STATE_BIDIRECTIONAL);
109 
110         verifyAudioRoute(CallAudioState.ROUTE_SPEAKER);
111     }
112 
113     /**
114      * Tests audio routing for an outgoing video call made with transmit only video.  Expect to be
115      * in speaker mode.  Note: The default UI does not support making one-way video calls, but the
116      * APIs do and a third party incall UI could choose to support that.
117      */
118     @MediumTest
119     @Test
testAutoSpeakerphoneOutgoingTransmitOnly()120     public void testAutoSpeakerphoneOutgoingTransmitOnly() throws Exception {
121         // Start an incoming video call.
122         IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
123                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
124                 VideoProfile.STATE_TX_ENABLED);
125 
126         verifyAudioRoute(CallAudioState.ROUTE_SPEAKER);
127     }
128 
129     /**
130      * Tests audio routing for an outgoing video call made with transmit only video.  Expect to be
131      * in speaker mode.  Note: The default UI does not support making one-way video calls, but the
132      * APIs do and a third party incall UI could choose to support that.
133      */
134     @MediumTest
135     @Test
testNoAutoSpeakerphoneOnOutgoing()136     public void testNoAutoSpeakerphoneOnOutgoing() throws Exception {
137         // Start an incoming video call.
138         IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
139                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
140                 VideoProfile.STATE_AUDIO_ONLY);
141 
142         verifyAudioRoute(CallAudioState.ROUTE_EARPIECE);
143     }
144 
145     /**
146      * Tests to ensure an incoming audio-only call is routed to the earpiece.
147      */
148     @MediumTest
149     @Test
testNoAutoSpeakerphoneOnIncoming()150     public void testNoAutoSpeakerphoneOnIncoming() throws Exception {
151 
152         // Start an incoming video call.
153         IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
154                 mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA,
155                 VideoProfile.STATE_AUDIO_ONLY);
156 
157         verifyAudioRoute(CallAudioState.ROUTE_EARPIECE);
158     }
159 
160     /**
161      * Ensure that when an incoming video call is missed, the video state history still includes
162      * video calling. This is important for the call log.
163      */
164     @LargeTest
165     @Test
testIncomingVideoCallMissedCheckVideoHistory()166     public void testIncomingVideoCallMissedCheckVideoHistory() throws Exception {
167         IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
168                 VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA);
169         com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls()
170                 .iterator().next();
171 
172         mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.MISSED);
173 
174         assertTrue(VideoProfile.isVideo(call.getVideoStateHistory()));
175     }
176 
177     /**
178      * Ensure that when an incoming video call is rejected, the video state history still includes
179      * video calling. This is important for the call log.
180      */
181     @LargeTest
182     @Test
testIncomingVideoCallRejectedCheckVideoHistory()183     public void testIncomingVideoCallRejectedCheckVideoHistory() throws Exception {
184         IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
185                 VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA);
186         com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls()
187                 .iterator().next();
188 
189         mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.REJECTED);
190 
191         assertTrue(VideoProfile.isVideo(call.getVideoStateHistory()));
192     }
193 
194 
195     /**
196      * Ensure that when an outgoing video call is canceled, the video state history still includes
197      * video calling. This is important for the call log.
198      */
199     @LargeTest
200     @Test
testOutgoingVideoCallCanceledCheckVideoHistory()201     public void testOutgoingVideoCallCanceledCheckVideoHistory() throws Exception {
202         IdPair ids = startOutgoingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
203                 mConnectionServiceFixtureA, Process.myUserHandle(),
204                 VideoProfile.STATE_BIDIRECTIONAL);
205         com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls()
206                 .iterator().next();
207 
208         mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
209 
210         assertTrue(VideoProfile.isVideo(call.getVideoStateHistory()));
211     }
212 
213     /**
214      * Ensure that when an outgoing video call is rejected, the video state history still includes
215      * video calling. This is important for the call log.
216      */
217     @LargeTest
218     @Test
testOutgoingVideoCallRejectedCheckVideoHistory()219     public void testOutgoingVideoCallRejectedCheckVideoHistory() throws Exception {
220         IdPair ids = startOutgoingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
221                 mConnectionServiceFixtureA, Process.myUserHandle(),
222                 VideoProfile.STATE_BIDIRECTIONAL);
223         com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls()
224                 .iterator().next();
225 
226         mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.REMOTE);
227 
228         assertTrue(VideoProfile.isVideo(call.getVideoStateHistory()));
229     }
230 
231     /**
232      * Ensure that when an outgoing video call is answered as audio only, the video state history
233      * shows that the call was audio only. This is important for the call log.
234      */
235     @LargeTest
236     @Test
testOutgoingVideoCallAnsweredAsAudio()237     public void testOutgoingVideoCallAnsweredAsAudio() throws Exception {
238         IdPair ids = startOutgoingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(),
239                 mConnectionServiceFixtureA, Process.myUserHandle(),
240                 VideoProfile.STATE_BIDIRECTIONAL);
241         com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls()
242                 .iterator().next();
243 
244         mConnectionServiceFixtureA.mConnectionById.get(ids.mConnectionId).videoState
245                 = VideoProfile.STATE_AUDIO_ONLY;
246         mConnectionServiceFixtureA.sendSetVideoState(ids.mConnectionId);
247         mConnectionServiceFixtureA.sendSetActive(ids.mConnectionId);
248 
249         assertFalse(VideoProfile.isVideo(call.getVideoStateHistory()));
250     }
251 
252     /**
253      * Verifies that the
254      * {@link android.telecom.InCallService#onCallAudioStateChanged(CallAudioState)} change is
255      * called with an expected route and number of changes.
256      *
257      * @param expectedRoute The expected audio route on the latest change.
258      */
verifyAudioRoute(int expectedRoute)259     private void verifyAudioRoute(int expectedRoute) throws Exception {
260         // Capture all onCallAudioStateChanged callbacks to InCall.
261         CallAudioRouteStateMachine carsm = mTelecomSystem.getCallsManager()
262                 .getCallAudioManager().getCallAudioRouteStateMachine();
263         CallAudioModeStateMachine camsm = mTelecomSystem.getCallsManager()
264                 .getCallAudioManager().getCallAudioModeStateMachine();
265         waitForHandlerAction(camsm.getHandler(), TEST_TIMEOUT);
266         final boolean[] success = {true};
267         carsm.sendMessage(CallAudioRouteStateMachine.RUN_RUNNABLE, (Runnable) () -> {
268             ArgumentCaptor<CallAudioState> callAudioStateArgumentCaptor = ArgumentCaptor.forClass(
269                     CallAudioState.class);
270             try {
271                 verify(mInCallServiceFixtureX.getTestDouble(), atLeastOnce())
272                         .onCallAudioStateChanged(callAudioStateArgumentCaptor.capture());
273             } catch (RemoteException e) {
274                 fail("Remote exception in InCallServiceFixture");
275             }
276             List<CallAudioState> changes = callAudioStateArgumentCaptor.getAllValues();
277             assertEquals(expectedRoute, changes.get(changes.size() - 1).getRoute());
278             success[0] = true;
279         });
280         waitForHandlerAction(carsm.getHandler(), TEST_TIMEOUT);
281         assertTrue(success[0]);
282     }
283 }
284