CameraDeviceBinderTest.java revision 5c207ec9a080f3be8ca28de8310483fe1c182c51
1/* 2 * Copyright (C) 2013 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.mediaframeworktest.integration; 18 19import android.graphics.ImageFormat; 20import android.graphics.SurfaceTexture; 21import android.hardware.camera2.CameraMetadata; 22import android.hardware.camera2.CameraCharacteristics; 23import android.hardware.camera2.CaptureRequest; 24import android.hardware.camera2.ICameraDeviceCallbacks; 25import android.hardware.camera2.ICameraDeviceUser; 26import android.hardware.camera2.impl.CameraMetadataNative; 27import android.hardware.camera2.utils.BinderHolder; 28import android.media.Image; 29import android.media.ImageReader; 30import android.os.Handler; 31import android.os.HandlerThread; 32import android.os.RemoteException; 33import android.os.SystemClock; 34import android.test.AndroidTestCase; 35import android.test.suitebuilder.annotation.SmallTest; 36import android.util.Log; 37import android.view.Surface; 38 39import static android.hardware.camera2.CameraDevice.TEMPLATE_PREVIEW; 40 41import com.android.mediaframeworktest.MediaFrameworkIntegrationTestRunner; 42 43import org.mockito.ArgumentMatcher; 44import org.mockito.ArgumentCaptor; 45import static org.mockito.Mockito.*; 46 47public class CameraDeviceBinderTest extends AndroidTestCase { 48 private static String TAG = "CameraDeviceBinderTest"; 49 // Number of streaming callbacks need to check. 50 private static int NUM_CALLBACKS_CHECKED = 10; 51 // Wait for capture result timeout value: 1500ms 52 private final static int WAIT_FOR_COMPLETE_TIMEOUT_MS = 1500; 53 // Wait for flush timeout value: 1000ms 54 private final static int WAIT_FOR_FLUSH_TIMEOUT_MS = 1000; 55 // Wait for idle timeout value: 2000ms 56 private final static int WAIT_FOR_IDLE_TIMEOUT_MS = 2000; 57 // Wait while camera device starts working on requests 58 private final static int WAIT_FOR_WORK_MS = 300; 59 // Default size is VGA, which is mandatory camera supported image size by CDD. 60 private static final int DEFAULT_IMAGE_WIDTH = 640; 61 private static final int DEFAULT_IMAGE_HEIGHT = 480; 62 private static final int MAX_NUM_IMAGES = 5; 63 64 private int mCameraId; 65 private ICameraDeviceUser mCameraUser; 66 private CameraBinderTestUtils mUtils; 67 private ICameraDeviceCallbacks.Stub mMockCb; 68 private Surface mSurface; 69 private HandlerThread mHandlerThread; 70 private Handler mHandler; 71 ImageReader mImageReader; 72 73 public CameraDeviceBinderTest() { 74 } 75 76 private class ImageDropperListener implements ImageReader.OnImageAvailableListener { 77 78 @Override 79 public void onImageAvailable(ImageReader reader) { 80 Image image = reader.acquireNextImage(); 81 if (image != null) image.close(); 82 } 83 } 84 85 public class DummyCameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub { 86 87 @Override 88 public void onCameraError(int errorCode) { 89 } 90 91 @Override 92 public void onCameraIdle() { 93 } 94 95 @Override 96 public void onCaptureStarted(int requestId, long timestamp) { 97 } 98 99 @Override 100 public void onResultReceived(int frameId, CameraMetadataNative result) { 101 } 102 } 103 104 class IsMetadataNotEmpty extends ArgumentMatcher<CameraMetadataNative> { 105 @Override 106 public boolean matches(Object obj) { 107 return !((CameraMetadataNative) obj).isEmpty(); 108 } 109 } 110 111 private void createDefaultSurface() { 112 mImageReader = 113 ImageReader.newInstance(DEFAULT_IMAGE_WIDTH, 114 DEFAULT_IMAGE_HEIGHT, 115 ImageFormat.YUV_420_888, 116 MAX_NUM_IMAGES); 117 mImageReader.setOnImageAvailableListener(new ImageDropperListener(), mHandler); 118 mSurface = mImageReader.getSurface(); 119 } 120 121 private CaptureRequest.Builder createDefaultBuilder(boolean needStream) throws Exception { 122 CameraMetadataNative metadata = new CameraMetadataNative(); 123 assertTrue(metadata.isEmpty()); 124 125 int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata); 126 assertEquals(CameraBinderTestUtils.NO_ERROR, status); 127 assertFalse(metadata.isEmpty()); 128 129 CaptureRequest.Builder request = new CaptureRequest.Builder(metadata); 130 assertFalse(request.isEmpty()); 131 assertFalse(metadata.isEmpty()); 132 if (needStream) { 133 int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20, 134 /* ignored */30, mSurface); 135 assertEquals(0, streamId); 136 request.addTarget(mSurface); 137 } 138 return request; 139 } 140 141 private int submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception { 142 int requestId = mCameraUser.submitRequest(request, streaming); 143 assertTrue( 144 "Request IDs should be non-negative (expected: >= 0, actual: " + requestId + ")", 145 requestId >= 0); 146 return requestId; 147 } 148 149 @Override 150 protected void setUp() throws Exception { 151 super.setUp(); 152 153 /** 154 * Workaround for mockito and JB-MR2 incompatibility 155 * 156 * Avoid java.lang.IllegalArgumentException: dexcache == null 157 * https://code.google.com/p/dexmaker/issues/detail?id=2 158 */ 159 System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); 160 mUtils = new CameraBinderTestUtils(getContext()); 161 162 // This cannot be set in the constructor, since the onCreate isn't 163 // called yet 164 mCameraId = MediaFrameworkIntegrationTestRunner.mCameraId; 165 166 ICameraDeviceCallbacks.Stub dummyCallbacks = new DummyCameraDeviceCallbacks(); 167 168 String clientPackageName = getContext().getPackageName(); 169 170 mMockCb = spy(dummyCallbacks); 171 172 BinderHolder holder = new BinderHolder(); 173 mUtils.getCameraService().connectDevice(mMockCb, mCameraId, 174 clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder); 175 mCameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder()); 176 assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser); 177 mHandlerThread = new HandlerThread(TAG); 178 mHandlerThread.start(); 179 mHandler = new Handler(mHandlerThread.getLooper()); 180 createDefaultSurface(); 181 182 Log.v(TAG, String.format("Camera %s connected", mCameraId)); 183 } 184 185 @Override 186 protected void tearDown() throws Exception { 187 mCameraUser.disconnect(); 188 mCameraUser = null; 189 mSurface.release(); 190 mImageReader.close(); 191 mHandlerThread.quitSafely(); 192 } 193 194 @SmallTest 195 public void testCreateDefaultRequest() throws Exception { 196 CameraMetadataNative metadata = new CameraMetadataNative(); 197 assertTrue(metadata.isEmpty()); 198 199 int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata); 200 assertEquals(CameraBinderTestUtils.NO_ERROR, status); 201 assertFalse(metadata.isEmpty()); 202 203 } 204 205 @SmallTest 206 public void testCreateStream() throws Exception { 207 int streamId = mCameraUser.createStream(/* ignored */10, /* ignored */20, /* ignored */30, 208 mSurface); 209 assertEquals(0, streamId); 210 211 assertEquals(CameraBinderTestUtils.ALREADY_EXISTS, 212 mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, mSurface)); 213 214 assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId)); 215 } 216 217 @SmallTest 218 public void testDeleteInvalidStream() throws Exception { 219 assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(-1)); 220 assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0)); 221 assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(1)); 222 assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0xC0FFEE)); 223 } 224 225 @SmallTest 226 public void testCreateStreamTwo() throws Exception { 227 228 // Create first stream 229 int streamId = mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, 230 mSurface); 231 assertEquals(0, streamId); 232 233 assertEquals(CameraBinderTestUtils.ALREADY_EXISTS, 234 mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, mSurface)); 235 236 // Create second stream with a different surface. 237 SurfaceTexture surfaceTexture = new SurfaceTexture(/* ignored */0); 238 surfaceTexture.setDefaultBufferSize(640, 480); 239 Surface surface2 = new Surface(surfaceTexture); 240 241 int streamId2 = mCameraUser.createStream(/* ignored */0, /* ignored */0, /* ignored */0, 242 surface2); 243 assertEquals(1, streamId2); 244 245 // Clean up streams 246 assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId)); 247 assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId2)); 248 } 249 250 @SmallTest 251 public void testSubmitBadRequest() throws Exception { 252 253 CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */false); 254 CaptureRequest request1 = builder.build(); 255 int status = mCameraUser.submitRequest(request1, /* streaming */false); 256 assertEquals("Expected submitRequest to return BAD_VALUE " + 257 "since we had 0 surface targets set.", CameraBinderTestUtils.BAD_VALUE, status); 258 259 builder.addTarget(mSurface); 260 CaptureRequest request2 = builder.build(); 261 status = mCameraUser.submitRequest(request2, /* streaming */false); 262 assertEquals("Expected submitRequest to return BAD_VALUE since " + 263 "the target surface wasn't registered with createStream.", 264 CameraBinderTestUtils.BAD_VALUE, status); 265 } 266 267 @SmallTest 268 public void testSubmitGoodRequest() throws Exception { 269 270 CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true); 271 CaptureRequest request = builder.build(); 272 273 // Submit valid request twice. 274 int requestId1 = submitCameraRequest(request, /* streaming */false); 275 int requestId2 = submitCameraRequest(request, /* streaming */false); 276 assertNotSame("Request IDs should be unique for multiple requests", requestId1, requestId2); 277 278 } 279 280 @SmallTest 281 public void testSubmitStreamingRequest() throws Exception { 282 283 CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true); 284 285 CaptureRequest request = builder.build(); 286 287 // Submit valid request once (non-streaming), and another time 288 // (streaming) 289 int requestId1 = submitCameraRequest(request, /* streaming */false); 290 291 int requestIdStreaming = submitCameraRequest(request, /* streaming */true); 292 assertNotSame("Request IDs should be unique for multiple requests", requestId1, 293 requestIdStreaming); 294 295 int status = mCameraUser.cancelRequest(-1); 296 assertEquals("Invalid request IDs should not be cancellable", 297 CameraBinderTestUtils.BAD_VALUE, status); 298 299 status = mCameraUser.cancelRequest(requestId1); 300 assertEquals("Non-streaming request IDs should not be cancellable", 301 CameraBinderTestUtils.BAD_VALUE, status); 302 303 status = mCameraUser.cancelRequest(requestIdStreaming); 304 assertEquals("Streaming request IDs should be cancellable", CameraBinderTestUtils.NO_ERROR, 305 status); 306 307 } 308 309 @SmallTest 310 public void testCameraInfo() throws RemoteException { 311 CameraMetadataNative info = new CameraMetadataNative(); 312 313 int status = mCameraUser.getCameraInfo(/*out*/info); 314 assertEquals(CameraBinderTestUtils.NO_ERROR, status); 315 316 assertFalse(info.isEmpty()); 317 assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS)); 318 } 319 320 @SmallTest 321 public void testCameraCharacteristics() throws RemoteException { 322 CameraMetadataNative info = new CameraMetadataNative(); 323 324 int status = mUtils.getCameraService().getCameraCharacteristics(mCameraId, /*out*/info); 325 assertEquals(CameraBinderTestUtils.NO_ERROR, status); 326 327 assertFalse(info.isEmpty()); 328 assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS)); 329 } 330 331 @SmallTest 332 public void testWaitUntilIdle() throws Exception { 333 CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true); 334 int requestIdStreaming = submitCameraRequest(builder.build(), /* streaming */true); 335 336 // Test Bad case first: waitUntilIdle when there is active repeating request 337 int status = mCameraUser.waitUntilIdle(); 338 assertEquals("waitUntilIdle is invalid operation when there is active repeating request", 339 CameraBinderTestUtils.INVALID_OPERATION, status); 340 341 // Test good case, waitUntilIdle when there is no active repeating request 342 status = mCameraUser.cancelRequest(requestIdStreaming); 343 assertEquals(CameraBinderTestUtils.NO_ERROR, status); 344 status = mCameraUser.waitUntilIdle(); 345 assertEquals(CameraBinderTestUtils.NO_ERROR, status); 346 } 347 348 @SmallTest 349 public void testCaptureResultCallbacks() throws Exception { 350 IsMetadataNotEmpty matcher = new IsMetadataNotEmpty(); 351 CaptureRequest request = createDefaultBuilder(/* needStream */true).build(); 352 353 // Test both single request and streaming request. 354 int requestId1 = submitCameraRequest(request, /* streaming */false); 355 verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onResultReceived( 356 eq(requestId1), 357 argThat(matcher)); 358 359 int streamingId = submitCameraRequest(request, /* streaming */true); 360 verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED)) 361 .onResultReceived( 362 eq(streamingId), 363 argThat(matcher)); 364 } 365 366 @SmallTest 367 public void testCaptureStartedCallbacks() throws Exception { 368 CaptureRequest request = createDefaultBuilder(/* needStream */true).build(); 369 370 ArgumentCaptor<Long> timestamps = ArgumentCaptor.forClass(Long.class); 371 372 // Test both single request and streaming request. 373 int requestId1 = submitCameraRequest(request, /* streaming */false); 374 verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onCaptureStarted( 375 eq(requestId1), 376 anyLong()); 377 378 int streamingId = submitCameraRequest(request, /* streaming */true); 379 verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED)) 380 .onCaptureStarted( 381 eq(streamingId), 382 timestamps.capture()); 383 384 long timestamp = 0; // All timestamps should be larger than 0. 385 for (Long nextTimestamp : timestamps.getAllValues()) { 386 Log.v(TAG, "next t: " + nextTimestamp + " current t: " + timestamp); 387 assertTrue("Captures are out of order", timestamp < nextTimestamp); 388 timestamp = nextTimestamp; 389 } 390 } 391 392 @SmallTest 393 public void testIdleCallback() throws Exception { 394 int status; 395 CaptureRequest request = createDefaultBuilder(/* needStream */true).build(); 396 397 // Try streaming 398 int streamingId = submitCameraRequest(request, /* streaming */true); 399 400 // Wait a bit to fill up the queue 401 SystemClock.sleep(WAIT_FOR_WORK_MS); 402 403 // Cancel and make sure we eventually quiesce 404 status = mCameraUser.cancelRequest(streamingId); 405 406 verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(1)).onCameraIdle(); 407 408 // Submit a few capture requests 409 int requestId1 = submitCameraRequest(request, /* streaming */false); 410 int requestId2 = submitCameraRequest(request, /* streaming */false); 411 int requestId3 = submitCameraRequest(request, /* streaming */false); 412 int requestId4 = submitCameraRequest(request, /* streaming */false); 413 int requestId5 = submitCameraRequest(request, /* streaming */false); 414 415 // And wait for more idle 416 verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(2)).onCameraIdle(); 417 418 } 419 420 @SmallTest 421 public void testFlush() throws Exception { 422 int status; 423 424 // Initial flush should work 425 status = mCameraUser.flush(); 426 assertEquals(CameraBinderTestUtils.NO_ERROR, status); 427 428 // Then set up a stream 429 CaptureRequest request = createDefaultBuilder(/* needStream */true).build(); 430 431 // Flush should still be a no-op, really 432 status = mCameraUser.flush(); 433 assertEquals(CameraBinderTestUtils.NO_ERROR, status); 434 435 // Submit a few capture requests 436 int requestId1 = submitCameraRequest(request, /* streaming */false); 437 int requestId2 = submitCameraRequest(request, /* streaming */false); 438 int requestId3 = submitCameraRequest(request, /* streaming */false); 439 int requestId4 = submitCameraRequest(request, /* streaming */false); 440 int requestId5 = submitCameraRequest(request, /* streaming */false); 441 442 // Then flush and wait for idle 443 status = mCameraUser.flush(); 444 assertEquals(CameraBinderTestUtils.NO_ERROR, status); 445 446 verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(1)).onCameraIdle(); 447 448 // Now a streaming request 449 int streamingId = submitCameraRequest(request, /* streaming */true); 450 451 // Wait a bit to fill up the queue 452 SystemClock.sleep(WAIT_FOR_WORK_MS); 453 454 // Then flush and wait for the idle callback 455 status = mCameraUser.flush(); 456 assertEquals(CameraBinderTestUtils.NO_ERROR, status); 457 458 verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(2)).onCameraIdle(); 459 460 // TODO: When errors are hooked up, count that errors + successful 461 // requests equal to 5. 462 } 463} 464