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