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