Merge "Camera2: Test creating multiple sessions" into mnc-dev
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
index be80eea..bd350b2 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -36,6 +36,7 @@
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
import android.hardware.camera2.params.MeteringRectangle;
+import android.media.ImageReader;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
@@ -50,9 +51,15 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
import java.util.Set;
+import android.util.Size;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -596,6 +603,98 @@
}
}
+ /**
+ * Verify creating sessions back to back.
+ */
+ public void testCreateSessions() throws Exception {
+ for (int i = 0; i < mCameraIds.length; i++) {
+ try {
+ openDevice(mCameraIds[i], mCameraMockListener);
+ waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
+
+ testCreateSessionsByCamera(mCameraIds[i]);
+ }
+ finally {
+ closeDevice(mCameraIds[i], mCameraMockListener);
+ }
+ }
+ }
+
+ /**
+ * Verify creating sessions back to back and only the last one is valid for
+ * submitting requests.
+ */
+ private void testCreateSessionsByCamera(String cameraId) throws Exception {
+ final int NUM_SESSIONS = 3;
+ final int SESSION_TIMEOUT_MS = 1000;
+ final int CAPTURE_TIMEOUT_MS = 3000;
+
+ if (VERBOSE) {
+ Log.v(TAG, "Testing creating sessions for camera " + cameraId);
+ }
+
+ Size yuvSize = getSortedSizesForFormat(cameraId, mCameraManager, ImageFormat.YUV_420_888,
+ /*bound*/null).get(0);
+ Size jpegSize = getSortedSizesForFormat(cameraId, mCameraManager, ImageFormat.JPEG,
+ /*bound*/null).get(0);
+
+ // Create a list of image readers. JPEG for last one and YUV for the rest.
+ List<ImageReader> imageReaders = new ArrayList<>();
+ List<CameraCaptureSession> allSessions = new ArrayList<>();
+
+ try {
+ for (int i = 0; i < NUM_SESSIONS - 1; i++) {
+ imageReaders.add(ImageReader.newInstance(yuvSize.getWidth(), yuvSize.getHeight(),
+ ImageFormat.YUV_420_888, /*maxImages*/1));
+ }
+ imageReaders.add(ImageReader.newInstance(jpegSize.getWidth(), jpegSize.getHeight(),
+ ImageFormat.JPEG, /*maxImages*/1));
+
+ // Create multiple sessions back to back.
+ MultipleSessionCallback sessionListener =
+ new MultipleSessionCallback(/*failOnConfigureFailed*/true);
+ for (int i = 0; i < NUM_SESSIONS; i++) {
+ List<Surface> outputs = new ArrayList<>();
+ outputs.add(imageReaders.get(i).getSurface());
+ mCamera.createCaptureSession(outputs, sessionListener, mHandler);
+ }
+
+ // Verify we get onConfigured() for all sessions.
+ allSessions = sessionListener.getAllSessions(NUM_SESSIONS,
+ SESSION_TIMEOUT_MS * NUM_SESSIONS);
+ assertEquals(String.format("Got %d sessions but configured %d sessions",
+ allSessions.size(), NUM_SESSIONS), allSessions.size(), NUM_SESSIONS);
+
+ // Verify all sessions except the last one are closed.
+ for (int i = 0; i < NUM_SESSIONS - 1; i++) {
+ sessionListener.waitForSessionClose(allSessions.get(i), SESSION_TIMEOUT_MS);
+ }
+
+ // Verify we can capture a frame with the last session.
+ CameraCaptureSession session = allSessions.get(allSessions.size() - 1);
+ SimpleCaptureCallback captureListener = new SimpleCaptureCallback();
+ ImageReader reader = imageReaders.get(imageReaders.size() - 1);
+ SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
+ reader.setOnImageAvailableListener(imageListener, mHandler);
+
+ CaptureRequest.Builder builder =
+ mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+ builder.addTarget(reader.getSurface());
+ CaptureRequest request = builder.build();
+
+ session.capture(request, captureListener, mHandler);
+ captureListener.getCaptureResultForRequest(request, CAPTURE_TIMEOUT_MS);
+ imageListener.getImage(CAPTURE_TIMEOUT_MS).close();
+ } finally {
+ for (ImageReader reader : imageReaders) {
+ reader.close();
+ }
+ for (CameraCaptureSession session : allSessions) {
+ session.close();
+ }
+ }
+ }
+
private void prepareTestByCamera() throws Exception {
final int PREPARE_TIMEOUT_MS = 10000;
@@ -1529,4 +1628,97 @@
mSessionMockListener = null;
mSessionWaiter = null;
}
+
+ /**
+ * A camera capture session listener that keeps all the configured and closed sessions.
+ */
+ private class MultipleSessionCallback extends CameraCaptureSession.StateCallback {
+ public static final int SESSION_CONFIGURED = 0;
+ public static final int SESSION_CLOSED = 1;
+
+ final List<CameraCaptureSession> mSessions = new ArrayList<>();
+ final Map<CameraCaptureSession, Integer> mSessionStates = new HashMap<>();
+ CameraCaptureSession mCurrentConfiguredSession = null;
+
+ final ReentrantLock mLock = new ReentrantLock();
+ final Condition mNewStateCond = mLock.newCondition();
+
+ final boolean mFailOnConfigureFailed;
+
+ /**
+ * If failOnConfigureFailed is true, it calls fail() when onConfigureFailed() is invoked
+ * for any session.
+ */
+ public MultipleSessionCallback(boolean failOnConfigureFailed) {
+ mFailOnConfigureFailed = failOnConfigureFailed;
+ }
+
+ @Override
+ public void onClosed(CameraCaptureSession session) {
+ mLock.lock();
+ mSessionStates.put(session, SESSION_CLOSED);
+ mNewStateCond.signal();
+ mLock.unlock();
+ }
+
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ mLock.lock();
+ mSessions.add(session);
+ mSessionStates.put(session, SESSION_CONFIGURED);
+ mNewStateCond.signal();
+ mLock.unlock();
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ if (mFailOnConfigureFailed) {
+ fail("Configuring a session failed");
+ }
+ }
+
+ /**
+ * Get a number of sessions that have been configured.
+ */
+ public List<CameraCaptureSession> getAllSessions(int numSessions, int timeoutMs)
+ throws Exception {
+ long remainingTime = timeoutMs;
+ mLock.lock();
+ try {
+ while (mSessions.size() < numSessions) {
+ long startTime = SystemClock.elapsedRealtime();
+ boolean ret = mNewStateCond.await(remainingTime, TimeUnit.MILLISECONDS);
+ remainingTime -= (SystemClock.elapsedRealtime() - startTime);
+ ret &= remainingTime > 0;
+
+ assertTrue("Get " + numSessions + " sessions timed out after " + timeoutMs +
+ "ms", ret);
+ }
+
+ return mSessions;
+ } finally {
+ mLock.unlock();
+ }
+ }
+
+ /**
+ * Wait until a previously-configured sessoin is closed or it times out.
+ */
+ public void waitForSessionClose(CameraCaptureSession session, int timeoutMs) throws Exception {
+ long remainingTime = timeoutMs;
+ mLock.lock();
+ try {
+ while (mSessionStates.get(session).equals(SESSION_CLOSED) == false) {
+ long startTime = SystemClock.elapsedRealtime();
+ boolean ret = mNewStateCond.await(remainingTime, TimeUnit.MILLISECONDS);
+ remainingTime -= (SystemClock.elapsedRealtime() - startTime);
+ ret &= remainingTime > 0;
+
+ assertTrue("Wait for session close timed out after " + timeoutMs + "ms", ret);
+ }
+ } finally {
+ mLock.unlock();
+ }
+ }
+ }
}