cts: Add raw + preview + jpeg CTS test with DNG save.

Bug: 15112503

Change-Id: I98878cbbe625244d4dc617f4391c68342939e3c3
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
index c5e0929..e85d7cc 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -339,8 +339,9 @@
         if (format == ImageFormat.JPEG) {
             buffer = planes[0].getBuffer();
             assertNotNull("Fail to get jpeg ByteBuffer", buffer);
-            data = new byte[buffer.capacity()];
+            data = new byte[buffer.remaining()];
             buffer.get(data);
+            buffer.rewind();
             return data;
         }
 
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
index 7daf859..f50622c 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -25,6 +25,8 @@
 import android.hardware.camera2.CaptureResult;
 import android.location.Location;
 import android.location.LocationManager;
+import android.hardware.camera2.DngCreator;
+import android.media.ImageReader;
 import android.util.Size;
 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureListener;
 import android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener;
@@ -38,9 +40,11 @@
 import android.util.Log;
 import android.util.Range;
 import android.util.Rational;
+import android.view.Surface;
 
 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
 
+import java.io.ByteArrayOutputStream;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -176,8 +180,30 @@
                closeImageReader();
            }
        }
-   }
+    }
 
+
+    /**
+     * Test the full raw capture use case.
+     *
+     * This includes:
+     * - Configuring the camera with a preview, jpeg, and raw output stream.
+     * - Running preview until AE/AF can settle.
+     * - Capturing with a request targeting all three output streams.
+     */
+    public void testFullRawCapture() throws Exception {
+        for (int i = 0; i < mCameraIds.length; i++) {
+            try {
+                Log.i(TAG, "Testing raw capture for Camera " + mCameraIds[i]);
+                openDevice(mCameraIds[i]);
+
+                fullRawCaptureTestByCamera();
+            } finally {
+                closeDevice();
+                closeImageReader();
+            }
+        }
+    }
     /**
      * Test touch for focus.
      * <p>
@@ -625,6 +651,102 @@
         }
     }
 
+    private void fullRawCaptureTestByCamera() throws Exception {
+        Size maxPreviewSz = mOrderedPreviewSizes.get(0);
+        Size maxStillSz = mOrderedStillSizes.get(0);
+        Size[] rawSizes = mStaticInfo.getRawOutputSizesChecked();
+        for (Size size : rawSizes) {
+            if (VERBOSE) {
+                Log.v(TAG, "Testing multi capture with size " + size.toString()
+                        + ", preview size " + maxPreviewSz);
+            }
+
+            // Prepare raw capture and start preview.
+            CaptureRequest.Builder previewBuilder =
+                    mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+            CaptureRequest.Builder multiBuilder =
+                    mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+
+            SimpleCaptureListener resultListener = new SimpleCaptureListener();
+            SimpleImageReaderListener jpegListener = new SimpleImageReaderListener();
+            SimpleImageReaderListener rawListener = new SimpleImageReaderListener();
+
+            updatePreviewSurface(maxPreviewSz);
+
+            ImageReader rawReader = null;
+            ImageReader jpegReader = null;
+            try {
+
+                // Create ImageReaders.
+                rawReader = makeImageReader(size,
+                        ImageFormat.RAW_SENSOR, MAX_READER_IMAGES, rawListener, mHandler);
+                jpegReader = makeImageReader(maxStillSz,
+                        ImageFormat.JPEG, MAX_READER_IMAGES, jpegListener, mHandler);
+
+                // Configure output streams with preview and jpeg streams.
+                List<Surface> outputSurfaces = new ArrayList<Surface>();
+                outputSurfaces.add(rawReader.getSurface());
+                outputSurfaces.add(jpegReader.getSurface());
+                outputSurfaces.add(mPreviewSurface);
+                configureCameraOutputs(mCamera, outputSurfaces, mCameraListener);
+
+                // Configure the requests.
+                previewBuilder.addTarget(mPreviewSurface);
+                multiBuilder.addTarget(mPreviewSurface);
+                multiBuilder.addTarget(rawReader.getSurface());
+                multiBuilder.addTarget(jpegReader.getSurface());
+
+                // Start preview.
+                mCamera.setRepeatingRequest(previewBuilder.build(), null, mHandler);
+
+                // Poor man's 3A, wait 2 seconds for AE/AF (if any) to settle.
+                // TODO: Do proper 3A trigger and lock (see testTakePictureTest).
+                Thread.sleep(3000);
+
+                multiBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE,
+                        CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON);
+                CaptureRequest multiRequest = multiBuilder.build();
+
+                mCamera.capture(multiRequest, resultListener, mHandler);
+
+                CaptureResult result = resultListener.getCaptureResultForRequest(multiRequest,
+                        NUM_RESULTS_WAIT_TIMEOUT);
+                Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+                basicValidateJpegImage(jpegImage, maxStillSz);
+                Image rawImage = rawListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+                validateRaw16Image(rawImage, size);
+
+
+                DngCreator dngCreator = new DngCreator(mStaticInfo.getCharacteristics(), result);
+                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+                dngCreator.writeImage(outputStream, rawImage);
+
+                if (DEBUG) {
+                    byte[] rawBuffer = outputStream.toByteArray();
+                    String rawFileName =
+                            DEBUG_FILE_NAME_BASE + "/raw16_" + TAG + size.toString() +
+                                    "_cam_" + mCamera.getId() + ".dng";
+                    Log.d(TAG, "Dump raw file into " + rawFileName);
+                    dumpFile(rawFileName, rawBuffer);
+
+                    byte[] jpegBuffer = getDataFromImage(jpegImage);
+                    String jpegFileName =
+                            DEBUG_FILE_NAME_BASE + "/jpeg_" + TAG + size.toString() +
+                                    "_cam_" + mCamera.getId() + ".jpg";
+                    Log.d(TAG, "Dump jpeg file into " + rawFileName);
+                    dumpFile(jpegFileName, jpegBuffer);
+                }
+
+                stopPreview();
+            } finally {
+                closeImageReader(rawReader);
+                closeImageReader(jpegReader);
+                rawReader = null;
+                jpegReader = null;
+            }
+        }
+    }
+
     private void verifyRawCaptureResult(CaptureRequest rawRequest,
             SimpleCaptureListener resultListener) {
         // TODO: validate DNG metadata tags.
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index dac1f14..e84d417 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -68,7 +68,7 @@
     private static final String TAG = "SurfaceViewTestCase";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     private static final int WAIT_FOR_SURFACE_CHANGE_TIMEOUT_MS = 1000;
-    private static final int MAX_READER_IMAGES = 5;
+    protected static final int MAX_READER_IMAGES = 5;
 
     // TODO: Use internal storage for this to make sure the file is only visible to test.
     protected static final String DEBUG_FILE_NAME_BASE =
@@ -392,26 +392,56 @@
             ImageReader.OnImageAvailableListener listener) throws Exception {
         closeImageReader();
 
-        mReader = ImageReader.newInstance(size.getWidth(), size.getHeight(), format, maxNumImages);
-        mReaderSurface = mReader.getSurface();
-        mReader.setOnImageAvailableListener(listener, mHandler);
+        ImageReader r = makeImageReader(size, format, maxNumImages, listener,
+                mHandler);
+        mReader = r;
+        mReaderSurface = r.getSurface();
+    }
+
+    /**
+     * Create an {@link ImageReader} object and get the surface.
+     *
+     * @param size The size of this ImageReader to be created.
+     * @param format The format of this ImageReader to be created
+     * @param maxNumImages The max number of images that can be acquired simultaneously.
+     * @param listener The listener used by this ImageReader to notify callbacks.
+     * @param handler The handler to use for any listener callbacks.
+     */
+    protected static ImageReader makeImageReader(Size size, int format,
+                                                             int maxNumImages,
+                                                             ImageReader.OnImageAvailableListener
+                                                                     listener,
+                                                             Handler handler) {
+        ImageReader reader =  ImageReader.newInstance(size.getWidth(), size.getHeight(), format,
+                maxNumImages);
+        reader.setOnImageAvailableListener(listener, handler);
         if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString());
+        return reader;
     }
 
     /**
      * Close the pending images then close current active {@link ImageReader} object.
      */
     protected void closeImageReader() {
-        if (mReader != null) {
+        closeImageReader(mReader);
+        mReader = null;
+        mReaderSurface = null;
+    }
+
+    /**
+     * Close pending images and clean up an {@link ImageReader} object.
+     * @param reader an {@link ImageReader} to close.
+     */
+    public static void closeImageReader(ImageReader reader) {
+        if (reader != null) {
             try {
                 // Close all possible pending images first.
-                Image image = mReader.acquireLatestImage();
+                Image image = reader.acquireLatestImage();
                 if (image != null) {
                     image.close();
                 }
             } finally {
-                mReader.close();
-                mReader = null;
+                reader.close();
             }
         }
     }