• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 
17 package com.android.mediaframeworktest.stress;
18 
19 import com.android.ex.camera2.blocking.BlockingSessionCallback;
20 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
21 import com.android.mediaframeworktest.Camera2SurfaceViewTestCase;
22 import com.android.mediaframeworktest.helpers.Camera2Focuser;
23 import com.android.mediaframeworktest.helpers.CameraTestUtils;
24 import com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleCaptureCallback;
25 
26 import android.graphics.ImageFormat;
27 import android.graphics.Point;
28 import android.hardware.camera2.CameraCharacteristics;
29 import android.hardware.camera2.CameraDevice;
30 import android.hardware.camera2.CaptureRequest;
31 import android.hardware.camera2.CaptureResult;
32 import android.hardware.camera2.DngCreator;
33 import android.hardware.camera2.params.MeteringRectangle;
34 import android.media.Image;
35 import android.media.ImageReader;
36 import android.os.ConditionVariable;
37 import android.util.Log;
38 import android.util.Pair;
39 import android.util.Rational;
40 import android.util.Size;
41 import android.view.Surface;
42 
43 import java.io.ByteArrayOutputStream;
44 import java.util.ArrayList;
45 import java.util.List;
46 
47 import static com.android.mediaframeworktest.helpers.CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS;
48 import static com.android.mediaframeworktest.helpers.CameraTestUtils.MAX_READER_IMAGES;
49 import static com.android.mediaframeworktest.helpers.CameraTestUtils.SimpleImageReaderListener;
50 import static com.android.mediaframeworktest.helpers.CameraTestUtils.basicValidateJpegImage;
51 import static com.android.mediaframeworktest.helpers.CameraTestUtils.configureCameraSession;
52 import static com.android.mediaframeworktest.helpers.CameraTestUtils.dumpFile;
53 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getDataFromImage;
54 import static com.android.mediaframeworktest.helpers.CameraTestUtils.getValueNotNull;
55 import static com.android.mediaframeworktest.helpers.CameraTestUtils.makeImageReader;
56 
57 /**
58  * <p>Tests for still capture API.</p>
59  *
60  * adb shell am instrument \
61  *    -e class com.android.mediaframeworktest.stress.Camera2StillCaptureTest#testTakePicture \
62  *    -e iterations 200 \
63  *    -e waitIntervalMs 1000 \
64  *    -e resultToFile false \
65  *    -r -w com.android.mediaframeworktest/.Camera2InstrumentationTestRunner
66  */
67 public class Camera2StillCaptureTest extends Camera2SurfaceViewTestCase {
68     private static final String TAG = "StillCaptureTest";
69     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
70     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
71     // 60 second to accommodate the possible long exposure time.
72     private static final int MAX_REGIONS_AE_INDEX = 0;
73     private static final int MAX_REGIONS_AWB_INDEX = 1;
74     private static final int MAX_REGIONS_AF_INDEX = 2;
75     private static final int WAIT_FOR_FOCUS_DONE_TIMEOUT_MS = 6000;
76     private static final double AE_COMPENSATION_ERROR_TOLERANCE = 0.2;
77     // 5 percent error margin for resulting metering regions
78     private static final float METERING_REGION_ERROR_PERCENT_DELTA = 0.05f;
79 
80     @Override
setUp()81     protected void setUp() throws Exception {
82         super.setUp();
83     }
84 
85     @Override
tearDown()86     protected void tearDown() throws Exception {
87         super.tearDown();
88     }
89 
90     /**
91      * Test normal still capture sequence.
92      * <p>
93      * Preview and and jpeg output streams are configured. Max still capture
94      * size is used for jpeg capture. The sequence of still capture being test
95      * is: start preview, auto focus, precapture metering (if AE is not
96      * converged), then capture jpeg. The AWB and AE are in auto modes. AF mode
97      * is CONTINUOUS_PICTURE.
98      * </p>
99      */
testTakePicture()100     public void testTakePicture() throws Exception{
101         for (String id : mCameraIds) {
102             try {
103                 Log.i(TAG, "Testing basic take picture for Camera " + id);
104                 openDevice(id);
105                 if (!mStaticInfo.isColorOutputSupported()) {
106                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
107                     continue;
108                 }
109 
110                 // Test iteration starts...
111                 for (int iteration = 0; iteration < getIterationCount(); ++iteration) {
112                     Log.v(TAG, String.format("Taking pictures: %d/%d", iteration + 1,
113                             getIterationCount()));
114                     takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null,
115                             /*afRegions*/null);
116                     getResultPrinter().printStatus(getIterationCount(), iteration + 1, id);
117                     Thread.sleep(getTestWaitIntervalMs());
118                 }
119             } finally {
120                 closeDevice();
121                 closeImageReader();
122             }
123         }
124     }
125 
126     /**
127      * Test the full raw capture use case.
128      *
129      * This includes:
130      * - Configuring the camera with a preview, jpeg, and raw output stream.
131      * - Running preview until AE/AF can settle.
132      * - Capturing with a request targeting all three output streams.
133      */
testFullRawCapture()134     public void testFullRawCapture() throws Exception {
135         for (int i = 0; i < mCameraIds.length; i++) {
136             try {
137                 Log.i(TAG, "Testing raw capture for Camera " + mCameraIds[i]);
138                 openDevice(mCameraIds[i]);
139                 if (!mStaticInfo.isCapabilitySupported(
140                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
141                     Log.i(TAG, "RAW capability is not supported in camera " + mCameraIds[i] +
142                             ". Skip the test.");
143                     continue;
144                 }
145 
146                 // Test iteration starts...
147                 for (int iteration = 0; iteration < getIterationCount(); ++iteration) {
148                     Log.v(TAG, String.format("Taking full RAW pictures: %d/%d", iteration + 1,
149                             getIterationCount()));
150                     fullRawCaptureTestByCamera();
151                     getResultPrinter().printStatus(getIterationCount(), iteration + 1,
152                             mCameraIds[i]);
153                     Thread.sleep(getTestWaitIntervalMs());
154                 }
155             } finally {
156                 closeDevice();
157                 closeImageReader();
158             }
159         }
160     }
161 
162     /**
163      * Take a picture for a given set of 3A regions for a particular camera.
164      * <p>
165      * Before take a still capture, it triggers an auto focus and lock it first,
166      * then wait for AWB to converge and lock it, then trigger a precapture
167      * metering sequence and wait for AE converged. After capture is received, the
168      * capture result and image are validated.
169      * </p>
170      *
171      * @param aeRegions AE regions for this capture
172      * @param awbRegions AWB regions for this capture
173      * @param afRegions AF regions for this capture
174      */
takePictureTestByCamera( MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, MeteringRectangle[] afRegions)175     private void takePictureTestByCamera(
176             MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions,
177             MeteringRectangle[] afRegions) throws Exception {
178         takePictureTestByCamera(aeRegions, awbRegions, afRegions,
179                 /*addAeTriggerCancel*/false);
180     }
181 
182     /**
183      * Take a picture for a given set of 3A regions for a particular camera.
184      * <p>
185      * Before take a still capture, it triggers an auto focus and lock it first,
186      * then wait for AWB to converge and lock it, then trigger a precapture
187      * metering sequence and wait for AE converged. After capture is received, the
188      * capture result and image are validated. If {@code addAeTriggerCancel} is true,
189      * a precapture trigger cancel will be inserted between two adjacent triggers, which
190      * should effective cancel the first trigger.
191      * </p>
192      *
193      * @param aeRegions AE regions for this capture
194      * @param awbRegions AWB regions for this capture
195      * @param afRegions AF regions for this capture
196      * @param addAeTriggerCancel If a AE precapture trigger cancel is sent after the trigger.
197      */
takePictureTestByCamera( MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, MeteringRectangle[] afRegions, boolean addAeTriggerCancel)198     private void takePictureTestByCamera(
199             MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions,
200             MeteringRectangle[] afRegions, boolean addAeTriggerCancel) throws Exception {
201 
202         boolean hasFocuser = mStaticInfo.hasFocuser();
203 
204         Size maxStillSz = mOrderedStillSizes.get(0);
205         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
206         CaptureResult result;
207         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
208         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
209         CaptureRequest.Builder previewRequest =
210                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
211         CaptureRequest.Builder stillRequest =
212                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
213         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
214                 maxStillSz, resultListener, imageListener);
215 
216         // Set AE mode to ON_AUTO_FLASH if flash is available.
217         if (mStaticInfo.hasFlash()) {
218             previewRequest.set(CaptureRequest.CONTROL_AE_MODE,
219                     CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
220             stillRequest.set(CaptureRequest.CONTROL_AE_MODE,
221                     CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
222         }
223 
224         Camera2Focuser focuser = null;
225         /**
226          * Step 1: trigger an auto focus run, and wait for AF locked.
227          */
228         boolean canSetAfRegion = hasFocuser && (afRegions != null) &&
229                 isRegionsSupportedFor3A(MAX_REGIONS_AF_INDEX);
230         if (hasFocuser) {
231             SimpleAutoFocusListener afListener = new SimpleAutoFocusListener();
232             focuser = new Camera2Focuser(mCamera, mSession, mPreviewSurface, afListener,
233                     mStaticInfo.getCharacteristics(), mHandler);
234             if (canSetAfRegion) {
235                 stillRequest.set(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
236             }
237             focuser.startAutoFocus(afRegions);
238             afListener.waitForAutoFocusDone(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS);
239         }
240 
241         /**
242          * Have to get the current AF mode to be used for other 3A repeating
243          * request, otherwise, the new AF mode in AE/AWB request could be
244          * different with existing repeating requests being sent by focuser,
245          * then it could make AF unlocked too early. Beside that, for still
246          * capture, AF mode must not be different with the one in current
247          * repeating request, otherwise, the still capture itself would trigger
248          * an AF mode change, and the AF lock would be lost for this capture.
249          */
250         int currentAfMode = CaptureRequest.CONTROL_AF_MODE_OFF;
251         if (hasFocuser) {
252             currentAfMode = focuser.getCurrentAfMode();
253         }
254         previewRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode);
255         stillRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode);
256 
257         /**
258          * Step 2: AF is already locked, wait for AWB converged, then lock it.
259          */
260         resultListener = new SimpleCaptureCallback();
261         boolean canSetAwbRegion =
262                 (awbRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AWB_INDEX);
263         if (canSetAwbRegion) {
264             previewRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
265             stillRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
266         }
267         mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
268         if (mStaticInfo.isHardwareLevelLimitedOrBetter()) {
269             waitForResultValue(resultListener, CaptureResult.CONTROL_AWB_STATE,
270                     CaptureResult.CONTROL_AWB_STATE_CONVERGED, NUM_RESULTS_WAIT_TIMEOUT);
271         } else {
272             // LEGACY Devices don't have the AWB_STATE reported in results, so just wait
273             waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
274         }
275         boolean canSetAwbLock = mStaticInfo.isAwbLockSupported();
276         if (canSetAwbLock) {
277             previewRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true);
278         }
279         mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
280         // Validate the next result immediately for region and mode.
281         result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
282         mCollector.expectEquals("AWB mode in result and request should be same",
283                 previewRequest.get(CaptureRequest.CONTROL_AWB_MODE),
284                 result.get(CaptureResult.CONTROL_AWB_MODE));
285         if (canSetAwbRegion) {
286             MeteringRectangle[] resultAwbRegions =
287                     getValueNotNull(result, CaptureResult.CONTROL_AWB_REGIONS);
288             mCollector.expectEquals("AWB regions in result and request should be same",
289                     awbRegions, resultAwbRegions);
290         }
291 
292         /**
293          * Step 3: trigger an AE precapture metering sequence and wait for AE converged.
294          */
295         resultListener = new SimpleCaptureCallback();
296         boolean canSetAeRegion =
297                 (aeRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AE_INDEX);
298         if (canSetAeRegion) {
299             previewRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
300             stillRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
301         }
302         mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
303         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
304                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
305         mSession.capture(previewRequest.build(), resultListener, mHandler);
306         if (addAeTriggerCancel) {
307             // Cancel the current precapture trigger, then send another trigger.
308             // The camera device should behave as if the first trigger is not sent.
309             // Wait one request to make the trigger start doing something before cancel.
310             waitForNumResults(resultListener, /*numResultsWait*/ 1);
311             previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
312                     CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
313             mSession.capture(previewRequest.build(), resultListener, mHandler);
314             waitForResultValue(resultListener, CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER,
315                     CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL,
316                     NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
317             // Issue another trigger
318             previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
319                     CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
320             mSession.capture(previewRequest.build(), resultListener, mHandler);
321         }
322         waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
323 
324         // Validate the next result immediately for region and mode.
325         result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
326         mCollector.expectEquals("AE mode in result and request should be same",
327                 previewRequest.get(CaptureRequest.CONTROL_AE_MODE),
328                 result.get(CaptureResult.CONTROL_AE_MODE));
329         if (canSetAeRegion) {
330             MeteringRectangle[] resultAeRegions =
331                     getValueNotNull(result, CaptureResult.CONTROL_AE_REGIONS);
332 
333             mCollector.expectMeteringRegionsAreSimilar(
334                     "AE regions in result and request should be similar",
335                     aeRegions,
336                     resultAeRegions,
337                     METERING_REGION_ERROR_PERCENT_DELTA);
338         }
339 
340         /**
341          * Step 4: take a picture when all 3A are in good state.
342          */
343         resultListener = new SimpleCaptureCallback();
344         CaptureRequest request = stillRequest.build();
345         mSession.capture(request, resultListener, mHandler);
346         // Validate the next result immediately for region and mode.
347         result = resultListener.getCaptureResultForRequest(request, WAIT_FOR_RESULT_TIMEOUT_MS);
348         mCollector.expectEquals("AF mode in result and request should be same",
349                 stillRequest.get(CaptureRequest.CONTROL_AF_MODE),
350                 result.get(CaptureResult.CONTROL_AF_MODE));
351         if (canSetAfRegion) {
352             MeteringRectangle[] resultAfRegions =
353                     getValueNotNull(result, CaptureResult.CONTROL_AF_REGIONS);
354             mCollector.expectMeteringRegionsAreSimilar(
355                     "AF regions in result and request should be similar",
356                     afRegions,
357                     resultAfRegions,
358                     METERING_REGION_ERROR_PERCENT_DELTA);
359         }
360 
361         if (hasFocuser) {
362             // Unlock auto focus.
363             focuser.cancelAutoFocus();
364         }
365 
366         // validate image
367         Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
368         validateJpegCapture(image, maxStillSz);
369 
370         // Free image resources
371         image.close();
372 
373         stopPreview();
374     }
375 
fullRawCaptureTestByCamera()376     private void fullRawCaptureTestByCamera() throws Exception {
377         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
378         Size maxStillSz = mOrderedStillSizes.get(0);
379 
380         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
381         SimpleImageReaderListener jpegListener = new SimpleImageReaderListener();
382         SimpleImageReaderListener rawListener = new SimpleImageReaderListener();
383 
384         Size size = mStaticInfo.getRawDimensChecked();
385 
386         if (VERBOSE) {
387             Log.v(TAG, "Testing multi capture with size " + size.toString()
388                     + ", preview size " + maxPreviewSz);
389         }
390 
391         // Prepare raw capture and start preview.
392         CaptureRequest.Builder previewBuilder =
393                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
394         CaptureRequest.Builder multiBuilder =
395                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
396 
397         ImageReader rawReader = null;
398         ImageReader jpegReader = null;
399 
400         try {
401             // Create ImageReaders.
402             rawReader = makeImageReader(size,
403                     ImageFormat.RAW_SENSOR, MAX_READER_IMAGES, rawListener, mHandler);
404             jpegReader = makeImageReader(maxStillSz,
405                     ImageFormat.JPEG, MAX_READER_IMAGES, jpegListener, mHandler);
406             updatePreviewSurface(maxPreviewSz);
407 
408             // Configure output streams with preview and jpeg streams.
409             List<Surface> outputSurfaces = new ArrayList<Surface>();
410             outputSurfaces.add(rawReader.getSurface());
411             outputSurfaces.add(jpegReader.getSurface());
412             outputSurfaces.add(mPreviewSurface);
413             mSessionListener = new BlockingSessionCallback();
414             mSession = configureCameraSession(mCamera, outputSurfaces,
415                     mSessionListener, mHandler);
416 
417             // Configure the requests.
418             previewBuilder.addTarget(mPreviewSurface);
419             multiBuilder.addTarget(mPreviewSurface);
420             multiBuilder.addTarget(rawReader.getSurface());
421             multiBuilder.addTarget(jpegReader.getSurface());
422 
423             // Start preview.
424             mSession.setRepeatingRequest(previewBuilder.build(), null, mHandler);
425 
426             // Poor man's 3A, wait 2 seconds for AE/AF (if any) to settle.
427             // TODO: Do proper 3A trigger and lock (see testTakePictureTest).
428             Thread.sleep(3000);
429 
430             multiBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE,
431                     CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON);
432             CaptureRequest multiRequest = multiBuilder.build();
433 
434             mSession.capture(multiRequest, resultListener, mHandler);
435 
436             CaptureResult result = resultListener.getCaptureResultForRequest(multiRequest,
437                     NUM_RESULTS_WAIT_TIMEOUT);
438             Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
439             basicValidateJpegImage(jpegImage, maxStillSz);
440             Image rawImage = rawListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
441             validateRaw16Image(rawImage, size);
442             verifyRawCaptureResult(multiRequest, result);
443 
444 
445             ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
446             try (DngCreator dngCreator = new DngCreator(mStaticInfo.getCharacteristics(), result)) {
447                 dngCreator.writeImage(outputStream, rawImage);
448             }
449 
450             if (DEBUG) {
451                 byte[] rawBuffer = outputStream.toByteArray();
452                 String rawFileName = DEBUG_FILE_NAME_BASE + "/raw16_" + TAG + size.toString() +
453                         "_cam_" + mCamera.getId() + ".dng";
454                 Log.d(TAG, "Dump raw file into " + rawFileName);
455                 dumpFile(rawFileName, rawBuffer);
456 
457                 byte[] jpegBuffer = getDataFromImage(jpegImage);
458                 String jpegFileName = DEBUG_FILE_NAME_BASE + "/jpeg_" + TAG + size.toString() +
459                         "_cam_" + mCamera.getId() + ".jpg";
460                 Log.d(TAG, "Dump jpeg file into " + rawFileName);
461                 dumpFile(jpegFileName, jpegBuffer);
462             }
463 
464             stopPreview();
465         } finally {
466             CameraTestUtils.closeImageReader(rawReader);
467             CameraTestUtils.closeImageReader(jpegReader);
468             rawReader = null;
469             jpegReader = null;
470         }
471     }
472 
473     /**
474      * Validate that raw {@link CaptureResult}.
475      *
476      * @param rawRequest a {@link CaptureRequest} use to capture a RAW16 image.
477      * @param rawResult the {@link CaptureResult} corresponding to the given request.
478      */
verifyRawCaptureResult(CaptureRequest rawRequest, CaptureResult rawResult)479     private void verifyRawCaptureResult(CaptureRequest rawRequest, CaptureResult rawResult) {
480         assertNotNull(rawRequest);
481         assertNotNull(rawResult);
482 
483         Rational[] empty = new Rational[] { Rational.ZERO, Rational.ZERO, Rational.ZERO};
484         Rational[] neutralColorPoint = mCollector.expectKeyValueNotNull("NeutralColorPoint",
485                 rawResult, CaptureResult.SENSOR_NEUTRAL_COLOR_POINT);
486         if (neutralColorPoint != null) {
487             mCollector.expectEquals("NeutralColorPoint length", empty.length,
488                     neutralColorPoint.length);
489             mCollector.expectNotEquals("NeutralColorPoint cannot be all zeroes, ", empty,
490                     neutralColorPoint);
491             mCollector.expectValuesGreaterOrEqual("NeutralColorPoint", neutralColorPoint,
492                     Rational.ZERO);
493         }
494 
495         mCollector.expectKeyValueGreaterOrEqual(rawResult, CaptureResult.SENSOR_GREEN_SPLIT, 0.0f);
496 
497         Pair<Double, Double>[] noiseProfile = mCollector.expectKeyValueNotNull("NoiseProfile",
498                 rawResult, CaptureResult.SENSOR_NOISE_PROFILE);
499         if (noiseProfile != null) {
500             mCollector.expectEquals("NoiseProfile length", noiseProfile.length,
501                 /*Num CFA channels*/4);
502             for (Pair<Double, Double> p : noiseProfile) {
503                 mCollector.expectTrue("NoiseProfile coefficients " + p +
504                         " must have: S > 0, O >= 0", p.first > 0 && p.second >= 0);
505             }
506         }
507 
508         Integer hotPixelMode = mCollector.expectKeyValueNotNull("HotPixelMode", rawResult,
509                 CaptureResult.HOT_PIXEL_MODE);
510         Boolean hotPixelMapMode = mCollector.expectKeyValueNotNull("HotPixelMapMode", rawResult,
511                 CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE);
512         Point[] hotPixelMap = rawResult.get(CaptureResult.STATISTICS_HOT_PIXEL_MAP);
513 
514         Size pixelArraySize = mStaticInfo.getPixelArraySizeChecked();
515         boolean[] availableHotPixelMapModes = mStaticInfo.getValueFromKeyNonNull(
516                         CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES);
517 
518         if (hotPixelMode != null) {
519             Integer requestMode = mCollector.expectKeyValueNotNull(rawRequest,
520                     CaptureRequest.HOT_PIXEL_MODE);
521             if (requestMode != null) {
522                 mCollector.expectKeyValueEquals(rawResult, CaptureResult.HOT_PIXEL_MODE,
523                         requestMode);
524             }
525         }
526 
527         if (hotPixelMapMode != null) {
528             Boolean requestMapMode = mCollector.expectKeyValueNotNull(rawRequest,
529                     CaptureRequest.STATISTICS_HOT_PIXEL_MAP_MODE);
530             if (requestMapMode != null) {
531                 mCollector.expectKeyValueEquals(rawResult,
532                         CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE, requestMapMode);
533             }
534 
535             if (!hotPixelMapMode) {
536                 mCollector.expectTrue("HotPixelMap must be empty", hotPixelMap == null ||
537                         hotPixelMap.length == 0);
538             } else {
539                 mCollector.expectTrue("HotPixelMap must not be empty", hotPixelMap != null);
540                 mCollector.expectNotNull("AvailableHotPixelMapModes must not be null",
541                         availableHotPixelMapModes);
542                 if (availableHotPixelMapModes != null) {
543                     mCollector.expectContains("HotPixelMapMode", availableHotPixelMapModes, true);
544                 }
545 
546                 int height = pixelArraySize.getHeight();
547                 int width = pixelArraySize.getWidth();
548                 for (Point p : hotPixelMap) {
549                     mCollector.expectTrue("Hotpixel " + p + " must be in pixelArray " +
550                             pixelArraySize, p.x >= 0 && p.x < width && p.y >= 0 && p.y < height);
551                 }
552             }
553         }
554         // TODO: profileHueSatMap, and profileToneCurve aren't supported yet.
555 
556     }
557 
558     //----------------------------------------------------------------
559     //---------Below are common functions for all tests.--------------
560     //----------------------------------------------------------------
561     /**
562      * Validate standard raw (RAW16) capture image.
563      *
564      * @param image The raw16 format image captured
565      * @param rawSize The expected raw size
566      */
validateRaw16Image(Image image, Size rawSize)567     private static void validateRaw16Image(Image image, Size rawSize) {
568         CameraTestUtils.validateImage(image, rawSize.getWidth(), rawSize.getHeight(),
569                 ImageFormat.RAW_SENSOR, /*filePath*/null);
570     }
571 
572     /**
573      * Validate JPEG capture image object sanity and test.
574      * <p>
575      * In addition to image object sanity, this function also does the decoding
576      * test, which is slower.
577      * </p>
578      *
579      * @param image The JPEG image to be verified.
580      * @param jpegSize The JPEG capture size to be verified against.
581      */
validateJpegCapture(Image image, Size jpegSize)582     private static void validateJpegCapture(Image image, Size jpegSize) {
583         CameraTestUtils.validateImage(image, jpegSize.getWidth(), jpegSize.getHeight(),
584                 ImageFormat.JPEG, /*filePath*/null);
585     }
586 
587     private static class SimpleAutoFocusListener implements Camera2Focuser.AutoFocusListener {
588         final ConditionVariable focusDone = new ConditionVariable();
589         @Override
onAutoFocusLocked(boolean success)590         public void onAutoFocusLocked(boolean success) {
591             focusDone.open();
592         }
593 
waitForAutoFocusDone(long timeoutMs)594         public void waitForAutoFocusDone(long timeoutMs) {
595             if (focusDone.block(timeoutMs)) {
596                 focusDone.close();
597             } else {
598                 throw new TimeoutRuntimeException("Wait for auto focus done timed out after "
599                         + timeoutMs + "ms");
600             }
601         }
602     }
603 
isRegionsSupportedFor3A(int index)604     private boolean isRegionsSupportedFor3A(int index) {
605         int maxRegions = 0;
606         switch (index) {
607             case MAX_REGIONS_AE_INDEX:
608                 maxRegions = mStaticInfo.getAeMaxRegionsChecked();
609                 break;
610             case MAX_REGIONS_AWB_INDEX:
611                 maxRegions = mStaticInfo.getAwbMaxRegionsChecked();
612                 break;
613             case  MAX_REGIONS_AF_INDEX:
614                 maxRegions = mStaticInfo.getAfMaxRegionsChecked();
615                 break;
616             default:
617                 throw new IllegalArgumentException("Unknown algorithm index");
618         }
619         boolean isRegionsSupported = maxRegions > 0;
620         if (index == MAX_REGIONS_AF_INDEX && isRegionsSupported) {
621             mCollector.expectTrue(
622                     "Device reports non-zero max AF region count for a camera without focuser!",
623                     mStaticInfo.hasFocuser());
624             isRegionsSupported = isRegionsSupported && mStaticInfo.hasFocuser();
625         }
626 
627         return isRegionsSupported;
628     }
629 }
630