VideoProviderTest.java revision b492f4c845e61fac17c0e523363607d2dd6ba987
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
17package com.android.server.telecom.tests;
18
19import com.android.server.telecom.CallAudioManager;
20import com.android.server.telecom.Log;
21
22import org.mockito.ArgumentCaptor;
23import org.mockito.Mock;
24import org.mockito.Mockito;
25import org.mockito.internal.exceptions.ExceptionIncludingMockitoWarnings;
26import org.mockito.invocation.InvocationOnMock;
27import org.mockito.stubbing.Answer;
28
29import android.content.Context;
30import android.content.Intent;
31import android.graphics.Camera;
32import android.graphics.SurfaceTexture;
33import android.net.Uri;
34import android.os.Handler;
35import android.os.Looper;
36import android.telecom.Call;
37import android.telecom.CallAudioState;
38import android.telecom.Connection;
39import android.telecom.Connection.VideoProvider;
40import android.telecom.InCallService;
41import android.telecom.InCallService.VideoCall;
42import android.telecom.ParcelableCall;
43import android.telecom.TelecomManager;
44import android.telecom.VideoCallImpl;
45import android.telecom.VideoProfile;
46import android.telecom.VideoProfile.CameraCapabilities;
47import android.view.Surface;
48
49import com.google.common.base.Predicate;
50
51import java.util.List;
52import java.util.concurrent.CountDownLatch;
53import java.util.concurrent.RunnableFuture;
54import java.util.concurrent.TimeUnit;
55
56import static android.test.MoreAsserts.assertEquals;
57import static org.mockito.Matchers.any;
58import static org.mockito.Matchers.anyInt;
59import static org.mockito.Matchers.anyLong;
60import static org.mockito.Matchers.eq;
61import static org.mockito.Mockito.doAnswer;
62import static org.mockito.Mockito.doReturn;
63import static org.mockito.Mockito.times;
64import static org.mockito.Mockito.timeout;
65import static org.mockito.Mockito.mock;
66import static org.mockito.Mockito.verify;
67import static org.mockito.Mockito.when;
68
69/**
70 * Performs tests of the {@link VideoProvider} and {@link VideoCall} APIs.  Ensures that requests
71 * sent from an InCallService are routed through Telecom to a VideoProvider, and that callbacks are
72 * correctly routed.
73 */
74public class VideoProviderTest extends TelecomSystemTest {
75    private static final int ORIENTATION_0 = 0;
76    private static final int ORIENTATION_90 = 90;
77    private static final float ZOOM_LEVEL = 3.0f;
78
79    @Mock private VideoCall.Callback mVideoCallCallback;
80    private IdPair mCallIds;
81    private InCallService.VideoCall mVideoCall;
82    private VideoCallImpl mVideoCallImpl;
83    private ConnectionServiceFixture.ConnectionInfo mConnectionInfo;
84    private CountDownLatch mVerificationLock;
85
86    private Answer mVerification = new Answer() {
87        @Override
88        public Object answer(InvocationOnMock i) {
89            mVerificationLock.countDown();
90            return null;
91        }
92    };
93
94    @Override
95    public void setUp() throws Exception {
96        super.setUp();
97
98        mCallIds = startAndMakeActiveOutgoingCall(
99                "650-555-1212",
100                mPhoneAccountA0.getAccountHandle(),
101                mConnectionServiceFixtureA);
102
103        // Set the video provider on the connection.
104        mConnectionServiceFixtureA.sendSetVideoProvider(
105                mConnectionServiceFixtureA.mLatestConnectionId);
106
107        // Provide a mocked VideoCall.Callback to receive callbacks via.
108        mVideoCallCallback = mock(InCallService.VideoCall.Callback.class);
109
110        mVideoCall = mInCallServiceFixtureX.getCall(mCallIds.mCallId).getVideoCallImpl();
111        mVideoCallImpl = (VideoCallImpl) mVideoCall;
112        mVideoCall.registerCallback(mVideoCallCallback);
113
114        mConnectionInfo = mConnectionServiceFixtureA.mConnectionById.get(mCallIds.mConnectionId);
115        mVerificationLock = new CountDownLatch(1);
116    }
117
118    @Override
119    public void tearDown() throws Exception {
120        super.tearDown();
121    }
122
123    /**
124     * Tests the {@link VideoCall#setCamera(String)}, {@link VideoProvider#onSetCamera(String)},
125     * and {@link VideoCall.Callback#onCameraCapabilitiesChanged(CameraCapabilities)}
126     * APIS.
127     */
128    public void testCameraChange() throws Exception {
129        // Wait until the callback has been received before performing verification.
130        doAnswer(mVerification).when(mVideoCallCallback)
131                .onCameraCapabilitiesChanged(any(CameraCapabilities.class));
132
133        // Make 2 setCamera requests.
134        mVideoCall.setCamera(MockVideoProvider.CAMERA_FRONT);
135        mVideoCall.setCamera(MockVideoProvider.CAMERA_BACK);
136
137        mVerificationLock.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
138
139        // Capture the video profile reported via the callback.
140        ArgumentCaptor<CameraCapabilities> cameraCapabilitiesCaptor =
141                ArgumentCaptor.forClass(CameraCapabilities.class);
142
143        // Verify that the callback was called twice and capture the callback arguments.
144        verify(mVideoCallCallback, timeout(TEST_TIMEOUT).times(2))
145                .onCameraCapabilitiesChanged(cameraCapabilitiesCaptor.capture());
146
147        assertEquals(2, cameraCapabilitiesCaptor.getAllValues().size());
148
149        List<CameraCapabilities> cameraCapabilities = cameraCapabilitiesCaptor.getAllValues();
150        // Ensure dimensions are as expected.
151        assertEquals(MockVideoProvider.CAMERA_FRONT_DIMENSIONS,
152                cameraCapabilities.get(0).getHeight());
153        assertEquals(MockVideoProvider.CAMERA_BACK_DIMENSIONS,
154                cameraCapabilities.get(1).getHeight());
155    }
156
157    /**
158     * Tests the {@link VideoCall#setPreviewSurface(Surface)} and
159     * {@link VideoProvider#onSetPreviewSurface(Surface)} APIs.
160     */
161    public void testSetPreviewSurface() throws Exception {
162        final Surface surface = new Surface(new SurfaceTexture(1));
163        mVideoCall.setPreviewSurface(surface);
164
165        assertTrueWithTimeout(new Predicate<Void>() {
166            @Override
167            public boolean apply(Void v) {
168                return mConnectionInfo.mockVideoProvider.getPreviewSurface() == surface;
169            }
170        });
171
172        mVideoCall.setPreviewSurface(null);
173
174        assertTrueWithTimeout(new Predicate<Void>() {
175            @Override
176            public boolean apply(Void v) {
177                return mConnectionInfo.mockVideoProvider.getPreviewSurface() == null;
178            }
179        });
180    }
181
182    /**
183     * Tests the {@link VideoCall#setDisplaySurface(Surface)} and
184     * {@link VideoProvider#onSetDisplaySurface(Surface)} APIs.
185     */
186    public void testSetDisplaySurface() throws Exception {
187        final Surface surface = new Surface(new SurfaceTexture(1));
188        mVideoCall.setDisplaySurface(surface);
189
190        assertTrueWithTimeout(new Predicate<Void>() {
191            @Override
192            public boolean apply(Void v) {
193                return mConnectionInfo.mockVideoProvider.getDisplaySurface() == surface;
194            }
195        });
196
197        mVideoCall.setDisplaySurface(null);
198
199        assertTrueWithTimeout(new Predicate<Void>() {
200            @Override
201            public boolean apply(Void v) {
202                return mConnectionInfo.mockVideoProvider.getDisplaySurface() == null;
203            }
204        });
205    }
206
207    /**
208     * Tests the {@link VideoCall#setDeviceOrientation(int)} and
209     * {@link VideoProvider#onSetDeviceOrientation(int)} APIs.
210     */
211    public void testSetDeviceOrientation() throws Exception {
212        mVideoCall.setDeviceOrientation(ORIENTATION_0);
213
214        assertTrueWithTimeout(new Predicate<Void>() {
215            @Override
216            public boolean apply(Void v) {
217                return mConnectionInfo.mockVideoProvider.getDeviceOrientation() == ORIENTATION_0;
218            }
219        });
220
221        mVideoCall.setDeviceOrientation(ORIENTATION_90);
222
223        assertTrueWithTimeout(new Predicate<Void>() {
224            @Override
225            public boolean apply(Void v) {
226                return mConnectionInfo.mockVideoProvider.getDeviceOrientation() == ORIENTATION_90;
227            }
228        });
229    }
230
231    /**
232     * Tests the {@link VideoCall#setZoom(float)} and {@link VideoProvider#onSetZoom(float)} APIs.
233     */
234    public void testSetZoom() throws Exception {
235        mVideoCall.setZoom(ZOOM_LEVEL);
236
237        assertTrueWithTimeout(new Predicate<Void>() {
238            @Override
239            public boolean apply(Void v) {
240                return mConnectionInfo.mockVideoProvider.getZoom() == ZOOM_LEVEL;
241            }
242        });
243    }
244
245    /**
246     * Tests the {@link VideoCall#sendSessionModifyRequest(VideoProfile)},
247     * {@link VideoProvider#onSendSessionModifyRequest(VideoProfile, VideoProfile)},
248     * {@link VideoProvider#receiveSessionModifyResponse(int, VideoProfile, VideoProfile)}, and
249     * {@link VideoCall.Callback#onSessionModifyResponseReceived(int, VideoProfile, VideoProfile)}
250     * APIs.
251     *
252     * Emulates a scenario where an InCallService sends a request to upgrade to video, which the
253     * peer accepts as-is.
254     */
255    public void testSessionModifyRequest() throws Exception {
256        VideoProfile requestProfile = new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL);
257
258        // Set the starting video state on the video call impl; normally this would be set based on
259        // the original android.telecom.Call instance.
260        mVideoCallImpl.setVideoState(VideoProfile.STATE_RX_ENABLED);
261
262        doAnswer(mVerification).when(mVideoCallCallback)
263                .onSessionModifyResponseReceived(anyInt(), any(VideoProfile.class),
264                        any(VideoProfile.class));
265
266        // Send the request.
267        mVideoCall.sendSessionModifyRequest(requestProfile);
268
269        mVerificationLock.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
270
271        // Capture the video profiles from the callback.
272        ArgumentCaptor<VideoProfile> fromVideoProfileCaptor =
273                ArgumentCaptor.forClass(VideoProfile.class);
274        ArgumentCaptor<VideoProfile> toVideoProfileCaptor =
275                ArgumentCaptor.forClass(VideoProfile.class);
276
277        // Verify we got a response and capture the profiles.
278        verify(mVideoCallCallback, timeout(TEST_TIMEOUT))
279                .onSessionModifyResponseReceived(eq(VideoProvider.SESSION_MODIFY_REQUEST_SUCCESS),
280                        fromVideoProfileCaptor.capture(), toVideoProfileCaptor.capture());
281
282        assertEquals(VideoProfile.STATE_RX_ENABLED,
283                fromVideoProfileCaptor.getValue().getVideoState());
284        assertEquals(VideoProfile.STATE_BIDIRECTIONAL,
285                toVideoProfileCaptor.getValue().getVideoState());
286    }
287
288    /**
289     * Tests the {@link VideoCall#sendSessionModifyResponse(VideoProfile)},
290     * and {@link VideoProvider#onSendSessionModifyResponse(VideoProfile)} APIs.
291     */
292    public void testSessionModifyResponse() throws Exception {
293        VideoProfile sessionModifyResponse = new VideoProfile(VideoProfile.STATE_TX_ENABLED);
294
295        mVideoCall.sendSessionModifyResponse(sessionModifyResponse);
296
297        assertTrueWithTimeout(new Predicate<Void>() {
298            @Override
299            public boolean apply(Void v) {
300                VideoProfile response = mConnectionInfo.mockVideoProvider
301                        .getSessionModifyResponse();
302                return response != null && response.getVideoState() == VideoProfile.STATE_TX_ENABLED;
303            }
304        });
305    }
306
307    /**
308     * Tests the {@link VideoCall#requestCameraCapabilities()} ()},
309     * {@link VideoProvider#onRequestCameraCapabilities()} ()}, and
310     * {@link VideoCall.Callback#onCameraCapabilitiesChanged(CameraCapabilities)} APIs.
311     */
312    public void testRequestCameraCapabilities() throws Exception {
313        // Wait until the callback has been received before performing verification.
314        doAnswer(mVerification).when(mVideoCallCallback)
315                .onCameraCapabilitiesChanged(any(CameraCapabilities.class));
316
317        mVideoCall.requestCameraCapabilities();
318
319        mVerificationLock.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
320
321        verify(mVideoCallCallback, timeout(TEST_TIMEOUT))
322                .onCameraCapabilitiesChanged(any(CameraCapabilities.class));
323    }
324
325    /**
326     * Tests the {@link VideoCall#setPauseImage(Uri)}, and
327     * {@link VideoProvider#onSetPauseImage(Uri)} APIs.
328     */
329    public void testSetPauseImage() throws Exception {
330        final Uri testUri = Uri.fromParts("file", "test.jpg", null);
331        mVideoCall.setPauseImage(testUri);
332
333        assertTrueWithTimeout(new Predicate<Void>() {
334            @Override
335            public boolean apply(Void v) {
336                Uri pauseImage = mConnectionInfo.mockVideoProvider.getPauseImage();
337                return pauseImage != null && pauseImage.equals(testUri);
338            }
339        });
340    }
341
342    /**
343     * Tests the {@link VideoCall#requestCallDataUsage()},
344     * {@link VideoProvider#onRequestConnectionDataUsage()}, and
345     * {@link VideoCall.Callback#onCallDataUsageChanged(long)} APIs.
346     */
347    public void testRequestDataUsage() throws Exception {
348        // Wait until the callback has been received before performing verification.
349        doAnswer(mVerification).when(mVideoCallCallback)
350                .onCallDataUsageChanged(anyLong());
351
352        mVideoCall.requestCallDataUsage();
353
354        mVerificationLock.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
355
356        verify(mVideoCallCallback, timeout(TEST_TIMEOUT))
357                .onCallDataUsageChanged(eq(MockVideoProvider.DATA_USAGE));
358    }
359
360    /**
361     * Tests the {@link VideoProvider#receiveSessionModifyRequest(VideoProfile)},
362     * {@link VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)} APIs.
363     */
364    public void testReceiveSessionModifyRequest() throws Exception {
365        // Wait until the callback has been received before performing verification.
366        doAnswer(mVerification).when(mVideoCallCallback)
367                .onSessionModifyRequestReceived(any(VideoProfile.class));
368
369        mConnectionInfo.mockVideoProvider.sendMockSessionModifyRequest();
370
371        mVerificationLock.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
372
373        ArgumentCaptor<VideoProfile> requestProfileCaptor =
374                ArgumentCaptor.forClass(VideoProfile.class);
375        verify(mVideoCallCallback, timeout(TEST_TIMEOUT))
376                .onSessionModifyRequestReceived(requestProfileCaptor.capture());
377        assertEquals(VideoProfile.STATE_BIDIRECTIONAL,
378                requestProfileCaptor.getValue().getVideoState());
379    }
380
381
382    /**
383     * Tests the {@link VideoProvider#handleCallSessionEvent(int)}, and
384     * {@link VideoCall.Callback#onCallSessionEvent(int)} APIs.
385     */
386    public void testSessionEvent() throws Exception {
387        // Wait until the callback has been received before performing verification.
388        doAnswer(mVerification).when(mVideoCallCallback)
389                .onCallSessionEvent(anyInt());
390
391        mConnectionInfo.mockVideoProvider.sendMockSessionEvent(
392                VideoProvider.SESSION_EVENT_CAMERA_READY);
393
394        mVerificationLock.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
395
396        verify(mVideoCallCallback, timeout(TEST_TIMEOUT))
397                .onCallSessionEvent(eq(VideoProvider.SESSION_EVENT_CAMERA_READY));
398    }
399
400    /**
401     * Tests the {@link VideoProvider#changePeerDimensions(int, int)} and
402     * {@link VideoCall.Callback#onPeerDimensionsChanged(int, int)} APIs.
403     */
404    public void testPeerDimensionChange() throws Exception {
405        // Wait until the callback has been received before performing verification.
406        doAnswer(mVerification).when(mVideoCallCallback)
407                .onPeerDimensionsChanged(anyInt(), anyInt());
408
409        mConnectionInfo.mockVideoProvider.sendMockPeerDimensions(MockVideoProvider.PEER_DIMENSIONS,
410                MockVideoProvider.PEER_DIMENSIONS);
411
412        mVerificationLock.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
413
414        verify(mVideoCallCallback, timeout(TEST_TIMEOUT))
415                .onPeerDimensionsChanged(eq(MockVideoProvider.PEER_DIMENSIONS),
416                        eq(MockVideoProvider.PEER_DIMENSIONS));
417    }
418
419    /**
420     * Tests the {@link VideoProvider#changeVideoQuality(int)} and
421     * {@link VideoCall.Callback#onVideoQualityChanged(int)} APIs.
422     */
423    public void testVideoQualityChange() throws Exception {
424        // Wait until the callback has been received before performing verification.
425        doAnswer(mVerification).when(mVideoCallCallback)
426                .onVideoQualityChanged(anyInt());
427
428        mConnectionInfo.mockVideoProvider.sendMockVideoQuality(VideoProfile.QUALITY_HIGH);
429
430        mVerificationLock.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
431
432        verify(mVideoCallCallback, timeout(TEST_TIMEOUT))
433                .onVideoQualityChanged(eq(VideoProfile.QUALITY_HIGH));
434    }
435}
436