1 /*
2  * Copyright (C) 2014 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 android.hardware.camera2.cts;
18 
19 import static android.hardware.camera2.cts.CameraTestUtils.*;
20 import static android.hardware.camera2.cts.helpers.AssertHelpers.assertArrayContains;
21 
22 import android.graphics.ImageFormat;
23 import android.graphics.Point;
24 import android.graphics.Rect;
25 import android.hardware.camera2.CameraCharacteristics;
26 import android.hardware.camera2.CameraDevice;
27 import android.hardware.camera2.CaptureRequest;
28 import android.hardware.camera2.CaptureResult;
29 import android.hardware.camera2.DngCreator;
30 import android.media.ImageReader;
31 import android.util.Pair;
32 import android.util.Size;
33 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback;
34 import android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener;
35 import android.hardware.camera2.cts.helpers.Camera2Focuser;
36 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
37 import android.hardware.camera2.params.MeteringRectangle;
38 import android.media.Image;
39 import android.os.ConditionVariable;
40 import android.util.Log;
41 import android.util.Range;
42 import android.util.Rational;
43 import android.view.Surface;
44 
45 import com.android.ex.camera2.blocking.BlockingSessionCallback;
46 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
47 
48 import java.io.ByteArrayOutputStream;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.List;
52 
53 public class StillCaptureTest extends Camera2SurfaceViewTestCase {
54     private static final String TAG = "StillCaptureTest";
55     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
56     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
57     // 60 second to accommodate the possible long exposure time.
58     private static final int RELAXED_CAPTURE_IMAGE_TIMEOUT_MS = CAPTURE_IMAGE_TIMEOUT_MS + 1000;
59     private static final int MAX_REGIONS_AE_INDEX = 0;
60     private static final int MAX_REGIONS_AWB_INDEX = 1;
61     private static final int MAX_REGIONS_AF_INDEX = 2;
62     private static final int WAIT_FOR_FOCUS_DONE_TIMEOUT_MS = 6000;
63     private static final double AE_COMPENSATION_ERROR_TOLERANCE = 0.2;
64     private static final int NUM_FRAMES_WAITED = 30;
65     // 5 percent error margin for resulting metering regions
66     private static final float METERING_REGION_ERROR_PERCENT_DELTA = 0.05f;
67 
68     @Override
setUp()69     protected void setUp() throws Exception {
70         super.setUp();
71     }
72 
73     @Override
tearDown()74     protected void tearDown() throws Exception {
75         super.tearDown();
76     }
77 
78     /**
79      * Test JPEG capture exif fields for each camera.
80      */
testJpegExif()81     public void testJpegExif() throws Exception {
82         for (int i = 0; i < mCameraIds.length; i++) {
83             try {
84                 Log.i(TAG, "Testing JPEG exif for Camera " + mCameraIds[i]);
85                 openDevice(mCameraIds[i]);
86                 if (!mStaticInfo.isColorOutputSupported()) {
87                     Log.i(TAG, "Camera " + mCameraIds[i] +
88                             " does not support color outputs, skipping");
89                     continue;
90                 }
91                 jpegExifTestByCamera();
92             } finally {
93                 closeDevice();
94                 closeImageReader();
95             }
96         }
97     }
98 
99     /**
100      * Test normal still capture sequence.
101      * <p>
102      * Preview and and jpeg output streams are configured. Max still capture
103      * size is used for jpeg capture. The sequence of still capture being test
104      * is: start preview, auto focus, precapture metering (if AE is not
105      * converged), then capture jpeg. The AWB and AE are in auto modes. AF mode
106      * is CONTINUOUS_PICTURE.
107      * </p>
108      */
testTakePicture()109     public void testTakePicture() throws Exception{
110         for (String id : mCameraIds) {
111             try {
112                 Log.i(TAG, "Testing basic take picture for Camera " + id);
113                 openDevice(id);
114                 if (!mStaticInfo.isColorOutputSupported()) {
115                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
116                     continue;
117                 }
118                 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null);
119             } finally {
120                 closeDevice();
121                 closeImageReader();
122             }
123         }
124     }
125 
126     /**
127      * Test basic Raw capture. Raw buffer avaiablility is checked, but raw buffer data is not.
128      */
testBasicRawCapture()129     public void testBasicRawCapture()  throws Exception {
130        for (int i = 0; i < mCameraIds.length; i++) {
131            try {
132                Log.i(TAG, "Testing raw capture for Camera " + mCameraIds[i]);
133                openDevice(mCameraIds[i]);
134 
135                if (!mStaticInfo.isCapabilitySupported(
136                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
137                    Log.i(TAG, "RAW capability is not supported in camera " + mCameraIds[i] +
138                            ". Skip the test.");
139                    continue;
140                }
141 
142                rawCaptureTestByCamera();
143            } finally {
144                closeDevice();
145                closeImageReader();
146            }
147        }
148     }
149 
150 
151     /**
152      * Test the full raw capture use case.
153      *
154      * This includes:
155      * - Configuring the camera with a preview, jpeg, and raw output stream.
156      * - Running preview until AE/AF can settle.
157      * - Capturing with a request targeting all three output streams.
158      */
testFullRawCapture()159     public void testFullRawCapture() throws Exception {
160         for (int i = 0; i < mCameraIds.length; i++) {
161             try {
162                 Log.i(TAG, "Testing raw capture for Camera " + mCameraIds[i]);
163                 openDevice(mCameraIds[i]);
164                 if (!mStaticInfo.isCapabilitySupported(
165                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
166                     Log.i(TAG, "RAW capability is not supported in camera " + mCameraIds[i] +
167                             ". Skip the test.");
168                     continue;
169                 }
170 
171                 fullRawCaptureTestByCamera();
172             } finally {
173                 closeDevice();
174                 closeImageReader();
175             }
176         }
177     }
178     /**
179      * Test touch for focus.
180      * <p>
181      * AF is in CAF mode when preview is started, test uses several pre-selected
182      * regions to simulate touches. Active scan is triggered to make sure the AF
183      * converges in reasonable time.
184      * </p>
185      */
testTouchForFocus()186     public void testTouchForFocus() throws Exception {
187         for (String id : mCameraIds) {
188             try {
189                 Log.i(TAG, "Testing touch for focus for Camera " + id);
190                 openDevice(id);
191                 int maxAfRegions = mStaticInfo.getAfMaxRegionsChecked();
192                 if (!(mStaticInfo.hasFocuser() && maxAfRegions > 0)) {
193                     continue;
194                 }
195                 // TODO: Relax test to use non-SurfaceView output for depth cases
196                 if (!mStaticInfo.isColorOutputSupported()) {
197                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
198                     continue;
199                 }
200                 touchForFocusTestByCamera();
201             } finally {
202                 closeDevice();
203                 closeImageReader();
204             }
205         }
206     }
207 
208     /**
209      * Test all combination of available preview sizes and still sizes.
210      * <p>
211      * For each still capture, Only the jpeg buffer is validated, capture
212      * result validation is covered by {@link #jpegExifTestByCamera} test.
213      * </p>
214      */
testStillPreviewCombination()215     public void testStillPreviewCombination() throws Exception {
216         for (String id : mCameraIds) {
217             try {
218                 Log.i(TAG, "Testing Still preview capture combination for Camera " + id);
219                 openDevice(id);
220                 if (!mStaticInfo.isColorOutputSupported()) {
221                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
222                     continue;
223                 }
224                 previewStillCombinationTestByCamera();
225             } finally {
226                 closeDevice();
227                 closeImageReader();
228             }
229         }
230     }
231 
232     /**
233      * Test AE compensation.
234      * <p>
235      * For each integer EV compensation setting: retrieve the exposure value (exposure time *
236      * sensitivity) with or without compensation, verify if the exposure value is legal (conformed
237      * to what static info has) and the ratio between two exposure values matches EV compensation
238      * setting. Also test for the behavior that exposure settings should be changed when AE
239      * compensation settings is changed, even when AE lock is ON.
240      * </p>
241      */
testAeCompensation()242     public void testAeCompensation() throws Exception {
243         for (String id : mCameraIds) {
244             try {
245                 Log.i(TAG, "Testing AE compensation for Camera " + id);
246                 openDevice(id);
247 
248                 if (mStaticInfo.isHardwareLevelLegacy()) {
249                     Log.i(TAG, "Skipping test on legacy devices");
250                     continue;
251                 }
252                 if (!mStaticInfo.isColorOutputSupported()) {
253                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
254                     continue;
255                 }
256                 aeCompensationTestByCamera();
257             } finally {
258                 closeDevice();
259                 closeImageReader();
260             }
261         }
262     }
263 
264     /**
265      * Test Ae region for still capture.
266      */
testAeRegions()267     public void testAeRegions() throws Exception {
268         for (String id : mCameraIds) {
269             try {
270                 Log.i(TAG, "Testing AE regions for Camera " + id);
271                 openDevice(id);
272 
273                 boolean aeRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AE_INDEX);
274                 if (!aeRegionsSupported) {
275                     continue;
276                 }
277 
278                 ArrayList<MeteringRectangle[]> aeRegionTestCases = get3ARegionTestCasesForCamera();
279                 for (MeteringRectangle[] aeRegions : aeRegionTestCases) {
280                     takePictureTestByCamera(aeRegions, /*awbRegions*/null, /*afRegions*/null);
281                 }
282             } finally {
283                 closeDevice();
284                 closeImageReader();
285             }
286         }
287     }
288 
289     /**
290      * Test AWB region for still capture.
291      */
testAwbRegions()292     public void testAwbRegions() throws Exception {
293         for (String id : mCameraIds) {
294             try {
295                 Log.i(TAG, "Testing AE regions for Camera " + id);
296                 openDevice(id);
297 
298                 boolean awbRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AWB_INDEX);
299                 if (!awbRegionsSupported) {
300                     continue;
301                 }
302 
303                 ArrayList<MeteringRectangle[]> awbRegionTestCases = get3ARegionTestCasesForCamera();
304                 for (MeteringRectangle[] awbRegions : awbRegionTestCases) {
305                     takePictureTestByCamera(/*aeRegions*/null, awbRegions, /*afRegions*/null);
306                 }
307             } finally {
308                 closeDevice();
309                 closeImageReader();
310             }
311         }
312     }
313 
314     /**
315      * Test Af region for still capture.
316      */
testAfRegions()317     public void testAfRegions() throws Exception {
318         for (String id : mCameraIds) {
319             try {
320                 Log.i(TAG, "Testing AF regions for Camera " + id);
321                 openDevice(id);
322 
323                 boolean afRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AF_INDEX);
324                 if (!afRegionsSupported) {
325                     continue;
326                 }
327 
328                 ArrayList<MeteringRectangle[]> afRegionTestCases = get3ARegionTestCasesForCamera();
329                 for (MeteringRectangle[] afRegions : afRegionTestCases) {
330                     takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, afRegions);
331                 }
332             } finally {
333                 closeDevice();
334                 closeImageReader();
335             }
336         }
337     }
338 
339     /**
340      * Test preview is still running after a still request
341      */
testPreviewPersistence()342     public void testPreviewPersistence() throws Exception {
343         for (String id : mCameraIds) {
344             try {
345                 Log.i(TAG, "Testing preview persistence for Camera " + id);
346                 openDevice(id);
347                 if (!mStaticInfo.isColorOutputSupported()) {
348                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
349                     continue;
350                 }
351                 previewPersistenceTestByCamera();
352             } finally {
353                 closeDevice();
354                 closeImageReader();
355             }
356         }
357     }
358 
testAePrecaptureTriggerCancelJpegCapture()359     public void testAePrecaptureTriggerCancelJpegCapture() throws Exception {
360         for (String id : mCameraIds) {
361             try {
362                 Log.i(TAG, "Testing AE precapture cancel for jpeg capture for Camera " + id);
363                 openDevice(id);
364 
365                 // Legacy device doesn't support AE precapture trigger
366                 if (mStaticInfo.isHardwareLevelLegacy()) {
367                     Log.i(TAG, "Skipping AE precapture trigger cancel test on legacy devices");
368                     continue;
369                 }
370                 if (!mStaticInfo.isColorOutputSupported()) {
371                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
372                     continue;
373                 }
374                 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null,
375                         /*addAeTriggerCancel*/true);
376             } finally {
377                 closeDevice();
378                 closeImageReader();
379             }
380         }
381     }
382 
383     /**
384      * Start preview,take a picture and test preview is still running after snapshot
385      */
previewPersistenceTestByCamera()386     private void previewPersistenceTestByCamera() throws Exception {
387         Size maxStillSz = mOrderedStillSizes.get(0);
388         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
389 
390         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
391         SimpleCaptureCallback stillResultListener = new SimpleCaptureCallback();
392         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
393         CaptureRequest.Builder previewRequest =
394                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
395         CaptureRequest.Builder stillRequest =
396                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
397         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
398                 maxStillSz, resultListener, imageListener);
399 
400         // make sure preview is actually running
401         waitForNumResults(resultListener, NUM_FRAMES_WAITED);
402 
403         // take a picture
404         CaptureRequest request = stillRequest.build();
405         mSession.capture(request, stillResultListener, mHandler);
406         stillResultListener.getCaptureResultForRequest(request,
407                 WAIT_FOR_RESULT_TIMEOUT_MS);
408 
409         // validate image
410         Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
411         validateJpegCapture(image, maxStillSz);
412 
413         // make sure preview is still running after still capture
414         waitForNumResults(resultListener, NUM_FRAMES_WAITED);
415 
416         stopPreview();
417 
418         // Free image resources
419         image.close();
420         closeImageReader();
421         return;
422     }
423 
424     /**
425      * Take a picture for a given set of 3A regions for a particular camera.
426      * <p>
427      * Before take a still capture, it triggers an auto focus and lock it first,
428      * then wait for AWB to converge and lock it, then trigger a precapture
429      * metering sequence and wait for AE converged. After capture is received, the
430      * capture result and image are validated.
431      * </p>
432      *
433      * @param aeRegions AE regions for this capture
434      * @param awbRegions AWB regions for this capture
435      * @param afRegions AF regions for this capture
436      */
takePictureTestByCamera( MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, MeteringRectangle[] afRegions)437     private void takePictureTestByCamera(
438             MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions,
439             MeteringRectangle[] afRegions) throws Exception {
440         takePictureTestByCamera(aeRegions, awbRegions, afRegions,
441                 /*addAeTriggerCancel*/false);
442     }
443 
444     /**
445      * Take a picture for a given set of 3A regions for a particular camera.
446      * <p>
447      * Before take a still capture, it triggers an auto focus and lock it first,
448      * then wait for AWB to converge and lock it, then trigger a precapture
449      * metering sequence and wait for AE converged. After capture is received, the
450      * capture result and image are validated. If {@code addAeTriggerCancel} is true,
451      * a precapture trigger cancel will be inserted between two adjacent triggers, which
452      * should effective cancel the first trigger.
453      * </p>
454      *
455      * @param aeRegions AE regions for this capture
456      * @param awbRegions AWB regions for this capture
457      * @param afRegions AF regions for this capture
458      * @param addAeTriggerCancel If a AE precapture trigger cancel is sent after the trigger.
459      */
takePictureTestByCamera( MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, MeteringRectangle[] afRegions, boolean addAeTriggerCancel)460     private void takePictureTestByCamera(
461             MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions,
462             MeteringRectangle[] afRegions, boolean addAeTriggerCancel) throws Exception {
463 
464         boolean hasFocuser = mStaticInfo.hasFocuser();
465 
466         Size maxStillSz = mOrderedStillSizes.get(0);
467         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
468         CaptureResult result;
469         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
470         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
471         CaptureRequest.Builder previewRequest =
472                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
473         CaptureRequest.Builder stillRequest =
474                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
475         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
476                 maxStillSz, resultListener, imageListener);
477 
478         // Set AE mode to ON_AUTO_FLASH if flash is available.
479         if (mStaticInfo.hasFlash()) {
480             previewRequest.set(CaptureRequest.CONTROL_AE_MODE,
481                     CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
482             stillRequest.set(CaptureRequest.CONTROL_AE_MODE,
483                     CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
484         }
485 
486         Camera2Focuser focuser = null;
487         /**
488          * Step 1: trigger an auto focus run, and wait for AF locked.
489          */
490         boolean canSetAfRegion = hasFocuser && (afRegions != null) &&
491                 isRegionsSupportedFor3A(MAX_REGIONS_AF_INDEX);
492         if (hasFocuser) {
493             SimpleAutoFocusListener afListener = new SimpleAutoFocusListener();
494             focuser = new Camera2Focuser(mCamera, mSession, mPreviewSurface, afListener,
495                     mStaticInfo.getCharacteristics(), mHandler);
496             if (canSetAfRegion) {
497                 stillRequest.set(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
498             }
499             focuser.startAutoFocus(afRegions);
500             afListener.waitForAutoFocusDone(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS);
501         }
502 
503         /**
504          * Have to get the current AF mode to be used for other 3A repeating
505          * request, otherwise, the new AF mode in AE/AWB request could be
506          * different with existing repeating requests being sent by focuser,
507          * then it could make AF unlocked too early. Beside that, for still
508          * capture, AF mode must not be different with the one in current
509          * repeating request, otherwise, the still capture itself would trigger
510          * an AF mode change, and the AF lock would be lost for this capture.
511          */
512         int currentAfMode = CaptureRequest.CONTROL_AF_MODE_OFF;
513         if (hasFocuser) {
514             currentAfMode = focuser.getCurrentAfMode();
515         }
516         previewRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode);
517         stillRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode);
518 
519         /**
520          * Step 2: AF is already locked, wait for AWB converged, then lock it.
521          */
522         resultListener = new SimpleCaptureCallback();
523         boolean canSetAwbRegion =
524                 (awbRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AWB_INDEX);
525         if (canSetAwbRegion) {
526             previewRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
527             stillRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
528         }
529         mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
530         if (mStaticInfo.isHardwareLevelLimitedOrBetter()) {
531             waitForResultValue(resultListener, CaptureResult.CONTROL_AWB_STATE,
532                     CaptureResult.CONTROL_AWB_STATE_CONVERGED, NUM_RESULTS_WAIT_TIMEOUT);
533         } else {
534             // LEGACY Devices don't have the AWB_STATE reported in results, so just wait
535             waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
536         }
537         boolean canSetAwbLock = mStaticInfo.isAwbLockSupported();
538         if (canSetAwbLock) {
539             previewRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true);
540         }
541         mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
542         // Validate the next result immediately for region and mode.
543         result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
544         mCollector.expectEquals("AWB mode in result and request should be same",
545                 previewRequest.get(CaptureRequest.CONTROL_AWB_MODE),
546                 result.get(CaptureResult.CONTROL_AWB_MODE));
547         if (canSetAwbRegion) {
548             MeteringRectangle[] resultAwbRegions =
549                     getValueNotNull(result, CaptureResult.CONTROL_AWB_REGIONS);
550             mCollector.expectEquals("AWB regions in result and request should be same",
551                     awbRegions, resultAwbRegions);
552         }
553 
554         /**
555          * Step 3: trigger an AE precapture metering sequence and wait for AE converged.
556          */
557         resultListener = new SimpleCaptureCallback();
558         boolean canSetAeRegion =
559                 (aeRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AE_INDEX);
560         if (canSetAeRegion) {
561             previewRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
562             stillRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
563         }
564         mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
565         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
566                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
567         mSession.capture(previewRequest.build(), resultListener, mHandler);
568         if (addAeTriggerCancel) {
569             // Cancel the current precapture trigger, then send another trigger.
570             // The camera device should behave as if the first trigger is not sent.
571             // Wait one request to make the trigger start doing something before cancel.
572             waitForNumResults(resultListener, /*numResultsWait*/ 1);
573             previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
574                     CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
575             mSession.capture(previewRequest.build(), resultListener, mHandler);
576             waitForResultValue(resultListener, CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER,
577                     CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL,
578                     NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
579             // Issue another trigger
580             previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
581                     CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
582             mSession.capture(previewRequest.build(), resultListener, mHandler);
583         }
584         waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
585 
586         // Validate the next result immediately for region and mode.
587         result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
588         mCollector.expectEquals("AE mode in result and request should be same",
589                 previewRequest.get(CaptureRequest.CONTROL_AE_MODE),
590                 result.get(CaptureResult.CONTROL_AE_MODE));
591         if (canSetAeRegion) {
592             MeteringRectangle[] resultAeRegions =
593                     getValueNotNull(result, CaptureResult.CONTROL_AE_REGIONS);
594 
595             mCollector.expectMeteringRegionsAreSimilar(
596                     "AE regions in result and request should be similar",
597                     aeRegions,
598                     resultAeRegions,
599                     METERING_REGION_ERROR_PERCENT_DELTA);
600         }
601 
602         /**
603          * Step 4: take a picture when all 3A are in good state.
604          */
605         resultListener = new SimpleCaptureCallback();
606         CaptureRequest request = stillRequest.build();
607         mSession.capture(request, resultListener, mHandler);
608         // Validate the next result immediately for region and mode.
609         result = resultListener.getCaptureResultForRequest(request, WAIT_FOR_RESULT_TIMEOUT_MS);
610         mCollector.expectEquals("AF mode in result and request should be same",
611                 stillRequest.get(CaptureRequest.CONTROL_AF_MODE),
612                 result.get(CaptureResult.CONTROL_AF_MODE));
613         if (canSetAfRegion) {
614             MeteringRectangle[] resultAfRegions =
615                     getValueNotNull(result, CaptureResult.CONTROL_AF_REGIONS);
616             mCollector.expectMeteringRegionsAreSimilar(
617                     "AF regions in result and request should be similar",
618                     afRegions,
619                     resultAfRegions,
620                     METERING_REGION_ERROR_PERCENT_DELTA);
621         }
622 
623         if (hasFocuser) {
624             // Unlock auto focus.
625             focuser.cancelAutoFocus();
626         }
627 
628         // validate image
629         Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
630         validateJpegCapture(image, maxStillSz);
631 
632         // Free image resources
633         image.close();
634 
635         stopPreview();
636     }
637 
638     /**
639      * Test touch region for focus by camera.
640      */
touchForFocusTestByCamera()641     private void touchForFocusTestByCamera() throws Exception {
642         SimpleCaptureCallback listener = new SimpleCaptureCallback();
643         CaptureRequest.Builder requestBuilder =
644                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
645         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
646         startPreview(requestBuilder, maxPreviewSz, listener);
647 
648         SimpleAutoFocusListener afListener = new SimpleAutoFocusListener();
649         Camera2Focuser focuser = new Camera2Focuser(mCamera, mSession, mPreviewSurface, afListener,
650                 mStaticInfo.getCharacteristics(), mHandler);
651         ArrayList<MeteringRectangle[]> testAfRegions = get3ARegionTestCasesForCamera();
652 
653         for (MeteringRectangle[] afRegions : testAfRegions) {
654             focuser.touchForAutoFocus(afRegions);
655             afListener.waitForAutoFocusDone(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS);
656             focuser.cancelAutoFocus();
657         }
658     }
659 
previewStillCombinationTestByCamera()660     private void previewStillCombinationTestByCamera() throws Exception {
661         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
662         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
663 
664         for (Size stillSz : mOrderedStillSizes)
665             for (Size previewSz : mOrderedPreviewSizes) {
666                 if (VERBOSE) {
667                     Log.v(TAG, "Testing JPEG capture size " + stillSz.toString()
668                             + " with preview size " + previewSz.toString() + " for camera "
669                             + mCamera.getId());
670                 }
671                 CaptureRequest.Builder previewRequest =
672                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
673                 CaptureRequest.Builder stillRequest =
674                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
675                 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, previewSz,
676                         stillSz, resultListener, imageListener);
677                 mSession.capture(stillRequest.build(), resultListener, mHandler);
678                 Image image = imageListener.getImage((mStaticInfo.isHardwareLevelLegacy()) ?
679                         RELAXED_CAPTURE_IMAGE_TIMEOUT_MS : CAPTURE_IMAGE_TIMEOUT_MS);
680                 validateJpegCapture(image, stillSz);
681 
682                 // Free image resources
683                 image.close();
684 
685                 // stopPreview must be called here to make sure next time a preview stream
686                 // is created with new size.
687                 stopPreview();
688             }
689     }
690 
691     /**
692      * Basic raw capture test for each camera.
693      */
rawCaptureTestByCamera()694     private void rawCaptureTestByCamera() throws Exception {
695         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
696         Size size = mStaticInfo.getRawDimensChecked();
697 
698         // Prepare raw capture and start preview.
699         CaptureRequest.Builder previewBuilder =
700                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
701         CaptureRequest.Builder rawBuilder =
702                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
703         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
704         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
705         prepareRawCaptureAndStartPreview(previewBuilder, rawBuilder, maxPreviewSz, size,
706                 resultListener, imageListener);
707 
708         if (VERBOSE) {
709             Log.v(TAG, "Testing Raw capture with size " + size.toString()
710                     + ", preview size " + maxPreviewSz);
711         }
712 
713         CaptureRequest rawRequest = rawBuilder.build();
714         mSession.capture(rawRequest, resultListener, mHandler);
715 
716         Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
717         validateRaw16Image(image, size);
718         if (DEBUG) {
719             byte[] rawBuffer = getDataFromImage(image);
720             String rawFileName = DEBUG_FILE_NAME_BASE + "/test" + "_" + size.toString() + "_cam" +
721                     mCamera.getId() + ".raw16";
722             Log.d(TAG, "Dump raw file into " + rawFileName);
723             dumpFile(rawFileName, rawBuffer);
724         }
725 
726         // Free image resources
727         image.close();
728 
729         stopPreview();
730     }
731 
fullRawCaptureTestByCamera()732     private void fullRawCaptureTestByCamera() throws Exception {
733         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
734         Size maxStillSz = mOrderedStillSizes.get(0);
735 
736         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
737         SimpleImageReaderListener jpegListener = new SimpleImageReaderListener();
738         SimpleImageReaderListener rawListener = new SimpleImageReaderListener();
739 
740         Size size = mStaticInfo.getRawDimensChecked();
741 
742         if (VERBOSE) {
743             Log.v(TAG, "Testing multi capture with size " + size.toString()
744                     + ", preview size " + maxPreviewSz);
745         }
746 
747         // Prepare raw capture and start preview.
748         CaptureRequest.Builder previewBuilder =
749                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
750         CaptureRequest.Builder multiBuilder =
751                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
752 
753         ImageReader rawReader = null;
754         ImageReader jpegReader = null;
755 
756         try {
757             // Create ImageReaders.
758             rawReader = makeImageReader(size,
759                     ImageFormat.RAW_SENSOR, MAX_READER_IMAGES, rawListener, mHandler);
760             jpegReader = makeImageReader(maxStillSz,
761                     ImageFormat.JPEG, MAX_READER_IMAGES, jpegListener, mHandler);
762             updatePreviewSurface(maxPreviewSz);
763 
764             // Configure output streams with preview and jpeg streams.
765             List<Surface> outputSurfaces = new ArrayList<Surface>();
766             outputSurfaces.add(rawReader.getSurface());
767             outputSurfaces.add(jpegReader.getSurface());
768             outputSurfaces.add(mPreviewSurface);
769             mSessionListener = new BlockingSessionCallback();
770             mSession = configureCameraSession(mCamera, outputSurfaces,
771                     mSessionListener, mHandler);
772 
773             // Configure the requests.
774             previewBuilder.addTarget(mPreviewSurface);
775             multiBuilder.addTarget(mPreviewSurface);
776             multiBuilder.addTarget(rawReader.getSurface());
777             multiBuilder.addTarget(jpegReader.getSurface());
778 
779             // Start preview.
780             mSession.setRepeatingRequest(previewBuilder.build(), null, mHandler);
781 
782             // Poor man's 3A, wait 2 seconds for AE/AF (if any) to settle.
783             // TODO: Do proper 3A trigger and lock (see testTakePictureTest).
784             Thread.sleep(3000);
785 
786             multiBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE,
787                     CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON);
788             CaptureRequest multiRequest = multiBuilder.build();
789 
790             mSession.capture(multiRequest, resultListener, mHandler);
791 
792             CaptureResult result = resultListener.getCaptureResultForRequest(multiRequest,
793                     NUM_RESULTS_WAIT_TIMEOUT);
794             Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
795             basicValidateJpegImage(jpegImage, maxStillSz);
796             Image rawImage = rawListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
797             validateRaw16Image(rawImage, size);
798             verifyRawCaptureResult(multiRequest, result);
799 
800 
801             ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
802             try (DngCreator dngCreator = new DngCreator(mStaticInfo.getCharacteristics(), result)) {
803                 dngCreator.writeImage(outputStream, rawImage);
804             }
805 
806             if (DEBUG) {
807                 byte[] rawBuffer = outputStream.toByteArray();
808                 String rawFileName = DEBUG_FILE_NAME_BASE + "/raw16_" + TAG + size.toString() +
809                         "_cam_" + mCamera.getId() + ".dng";
810                 Log.d(TAG, "Dump raw file into " + rawFileName);
811                 dumpFile(rawFileName, rawBuffer);
812 
813                 byte[] jpegBuffer = getDataFromImage(jpegImage);
814                 String jpegFileName = DEBUG_FILE_NAME_BASE + "/jpeg_" + TAG + size.toString() +
815                         "_cam_" + mCamera.getId() + ".jpg";
816                 Log.d(TAG, "Dump jpeg file into " + rawFileName);
817                 dumpFile(jpegFileName, jpegBuffer);
818             }
819 
820             stopPreview();
821         } finally {
822             CameraTestUtils.closeImageReader(rawReader);
823             CameraTestUtils.closeImageReader(jpegReader);
824             rawReader = null;
825             jpegReader = null;
826         }
827     }
828 
829     /**
830      * Validate that raw {@link CaptureResult}.
831      *
832      * @param rawRequest a {@link CaptureRequest} use to capture a RAW16 image.
833      * @param rawResult the {@link CaptureResult} corresponding to the given request.
834      */
verifyRawCaptureResult(CaptureRequest rawRequest, CaptureResult rawResult)835     private void verifyRawCaptureResult(CaptureRequest rawRequest, CaptureResult rawResult) {
836         assertNotNull(rawRequest);
837         assertNotNull(rawResult);
838 
839         Rational[] empty = new Rational[] { Rational.ZERO, Rational.ZERO, Rational.ZERO};
840         Rational[] neutralColorPoint = mCollector.expectKeyValueNotNull("NeutralColorPoint",
841                 rawResult, CaptureResult.SENSOR_NEUTRAL_COLOR_POINT);
842         if (neutralColorPoint != null) {
843             mCollector.expectEquals("NeutralColorPoint length", empty.length,
844                     neutralColorPoint.length);
845             mCollector.expectNotEquals("NeutralColorPoint cannot be all zeroes, ", empty,
846                     neutralColorPoint);
847             mCollector.expectValuesGreaterOrEqual("NeutralColorPoint", neutralColorPoint,
848                     Rational.ZERO);
849         }
850 
851         mCollector.expectKeyValueGreaterOrEqual(rawResult, CaptureResult.SENSOR_GREEN_SPLIT, 0.0f);
852 
853         Pair<Double, Double>[] noiseProfile = mCollector.expectKeyValueNotNull("NoiseProfile",
854                 rawResult, CaptureResult.SENSOR_NOISE_PROFILE);
855         if (noiseProfile != null) {
856             mCollector.expectEquals("NoiseProfile length", noiseProfile.length,
857                 /*Num CFA channels*/4);
858             for (Pair<Double, Double> p : noiseProfile) {
859                 mCollector.expectTrue("NoiseProfile coefficients " + p +
860                         " must have: S > 0, O >= 0", p.first > 0 && p.second >= 0);
861             }
862         }
863 
864         Integer hotPixelMode = mCollector.expectKeyValueNotNull("HotPixelMode", rawResult,
865                 CaptureResult.HOT_PIXEL_MODE);
866         Boolean hotPixelMapMode = mCollector.expectKeyValueNotNull("HotPixelMapMode", rawResult,
867                 CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE);
868         Point[] hotPixelMap = rawResult.get(CaptureResult.STATISTICS_HOT_PIXEL_MAP);
869 
870         Size pixelArraySize = mStaticInfo.getPixelArraySizeChecked();
871         boolean[] availableHotPixelMapModes = mStaticInfo.getValueFromKeyNonNull(
872                         CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES);
873 
874         if (hotPixelMode != null) {
875             Integer requestMode = mCollector.expectKeyValueNotNull(rawRequest,
876                     CaptureRequest.HOT_PIXEL_MODE);
877             if (requestMode != null) {
878                 mCollector.expectKeyValueEquals(rawResult, CaptureResult.HOT_PIXEL_MODE,
879                         requestMode);
880             }
881         }
882 
883         if (hotPixelMapMode != null) {
884             Boolean requestMapMode = mCollector.expectKeyValueNotNull(rawRequest,
885                     CaptureRequest.STATISTICS_HOT_PIXEL_MAP_MODE);
886             if (requestMapMode != null) {
887                 mCollector.expectKeyValueEquals(rawResult,
888                         CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE, requestMapMode);
889             }
890 
891             if (!hotPixelMapMode) {
892                 mCollector.expectTrue("HotPixelMap must be empty", hotPixelMap == null ||
893                         hotPixelMap.length == 0);
894             } else {
895                 mCollector.expectTrue("HotPixelMap must not be empty", hotPixelMap != null);
896                 mCollector.expectNotNull("AvailableHotPixelMapModes must not be null",
897                         availableHotPixelMapModes);
898                 if (availableHotPixelMapModes != null) {
899                     mCollector.expectContains("HotPixelMapMode", availableHotPixelMapModes, true);
900                 }
901 
902                 int height = pixelArraySize.getHeight();
903                 int width = pixelArraySize.getWidth();
904                 for (Point p : hotPixelMap) {
905                     mCollector.expectTrue("Hotpixel " + p + " must be in pixelArray " +
906                             pixelArraySize, p.x >= 0 && p.x < width && p.y >= 0 && p.y < height);
907                 }
908             }
909         }
910         // TODO: profileHueSatMap, and profileToneCurve aren't supported yet.
911 
912     }
913 
914     /**
915      * Issue a Jpeg capture and validate the exif information.
916      * <p>
917      * TODO: Differentiate full and limited device, some of the checks rely on
918      * per frame control and synchronization, most of them don't.
919      * </p>
920      */
jpegExifTestByCamera()921     private void jpegExifTestByCamera() throws Exception {
922         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
923         Size maxStillSz = mOrderedStillSizes.get(0);
924         if (VERBOSE) {
925             Log.v(TAG, "Testing JPEG exif with jpeg size " + maxStillSz.toString()
926                     + ", preview size " + maxPreviewSz);
927         }
928 
929         // prepare capture and start preview.
930         CaptureRequest.Builder previewBuilder =
931                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
932         CaptureRequest.Builder stillBuilder =
933                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
934         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
935         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
936         prepareStillCaptureAndStartPreview(previewBuilder, stillBuilder, maxPreviewSz, maxStillSz,
937                 resultListener, imageListener);
938 
939         // Set the jpeg keys, then issue a capture
940         Size[] thumbnailSizes = mStaticInfo.getAvailableThumbnailSizesChecked();
941         Size maxThumbnailSize = thumbnailSizes[thumbnailSizes.length - 1];
942         Size[] testThumbnailSizes = new Size[EXIF_TEST_DATA.length];
943         Arrays.fill(testThumbnailSizes, maxThumbnailSize);
944         // Make sure thumbnail size (0, 0) is covered.
945         testThumbnailSizes[0] = new Size(0, 0);
946 
947         for (int i = 0; i < EXIF_TEST_DATA.length; i++) {
948             setJpegKeys(stillBuilder, EXIF_TEST_DATA[i], testThumbnailSizes[i], mCollector);
949 
950             // Capture a jpeg image.
951             CaptureRequest request = stillBuilder.build();
952             mSession.capture(request, resultListener, mHandler);
953             CaptureResult stillResult =
954                     resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT);
955             Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
956 
957             verifyJpegKeys(image, stillResult, maxStillSz, testThumbnailSizes[i], EXIF_TEST_DATA[i],
958                     mStaticInfo, mCollector);
959 
960             // Free image resources
961             image.close();
962         }
963     }
964 
aeCompensationTestByCamera()965     private void aeCompensationTestByCamera() throws Exception {
966         Range<Integer> compensationRange = mStaticInfo.getAeCompensationRangeChecked();
967         // Skip the test if exposure compensation is not supported.
968         if (compensationRange.equals(Range.create(0, 0))) {
969             return;
970         }
971 
972         Rational step = mStaticInfo.getAeCompensationStepChecked();
973         float stepF = (float) step.getNumerator() / step.getDenominator();
974         int stepsPerEv = (int) Math.round(1.0 / stepF);
975         int numSteps = (compensationRange.getUpper() - compensationRange.getLower()) / stepsPerEv;
976 
977         Size maxStillSz = mOrderedStillSizes.get(0);
978         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
979         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
980         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
981         CaptureRequest.Builder previewRequest =
982                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
983         CaptureRequest.Builder stillRequest =
984                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
985         boolean canSetAeLock = mStaticInfo.isAeLockSupported();
986 
987         if (canSetAeLock) {
988             stillRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
989         }
990 
991         CaptureResult normalResult;
992         CaptureResult compensatedResult;
993 
994         // The following variables should only be read under the MANUAL_SENSOR capability guard:
995         long minExposureValue = -1;
996         long maxExposureTimeUs = -1;
997         long maxExposureValuePreview = -1;
998         long maxExposureValueStill = -1;
999         if (mStaticInfo.isCapabilitySupported(
1000                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
1001             // Minimum exposure settings is mostly static while maximum exposure setting depends on
1002             // frame rate range which in term depends on capture request.
1003             minExposureValue = mStaticInfo.getSensitivityMinimumOrDefault() *
1004                     mStaticInfo.getExposureMinimumOrDefault() / 1000;
1005             long maxSensitivity = mStaticInfo.getSensitivityMaximumOrDefault();
1006             maxExposureTimeUs = mStaticInfo.getExposureMaximumOrDefault() / 1000;
1007             maxExposureValuePreview = getMaxExposureValue(previewRequest, maxExposureTimeUs,
1008                     maxSensitivity);
1009             maxExposureValueStill = getMaxExposureValue(stillRequest, maxExposureTimeUs,
1010                     maxSensitivity);
1011         }
1012 
1013         // Set the max number of images to be same as the burst count, as the verification
1014         // could be much slower than producing rate, and we don't want to starve producer.
1015         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
1016                 maxStillSz, resultListener, numSteps, imageListener);
1017 
1018         for (int i = 0; i <= numSteps; i++) {
1019             int exposureCompensation = i * stepsPerEv + compensationRange.getLower();
1020             double expectedRatio = Math.pow(2.0, exposureCompensation / stepsPerEv);
1021 
1022             // Wait for AE to be stabilized before capture: CONVERGED or FLASH_REQUIRED.
1023             waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
1024             normalResult = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
1025 
1026             long normalExposureValue = -1;
1027             if (mStaticInfo.isCapabilitySupported(
1028                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
1029                 // get and check if current exposure value is valid
1030                 normalExposureValue = getExposureValue(normalResult);
1031                 mCollector.expectInRange("Exposure setting out of bound", normalExposureValue,
1032                         minExposureValue, maxExposureValuePreview);
1033 
1034                 // Only run the test if expectedExposureValue is within valid range
1035                 long expectedExposureValue = (long) (normalExposureValue * expectedRatio);
1036                 if (expectedExposureValue < minExposureValue ||
1037                     expectedExposureValue > maxExposureValueStill) {
1038                     continue;
1039                 }
1040                 Log.v(TAG, "Expect ratio: " + expectedRatio +
1041                         " normalExposureValue: " + normalExposureValue +
1042                         " expectedExposureValue: " + expectedExposureValue +
1043                         " minExposureValue: " + minExposureValue +
1044                         " maxExposureValuePreview: " + maxExposureValuePreview +
1045                         " maxExposureValueStill: " + maxExposureValueStill);
1046             }
1047 
1048             // Now issue exposure compensation and wait for AE locked. AE could take a few
1049             // frames to go back to locked state
1050             previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,
1051                     exposureCompensation);
1052             if (canSetAeLock) {
1053                 previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
1054             }
1055             mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
1056             if (canSetAeLock) {
1057                 waitForAeLocked(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
1058             } else {
1059                 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
1060             }
1061 
1062             // Issue still capture
1063             if (VERBOSE) {
1064                 Log.v(TAG, "Verifying capture result for ae compensation value "
1065                         + exposureCompensation);
1066             }
1067 
1068             stillRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposureCompensation);
1069             CaptureRequest request = stillRequest.build();
1070             mSession.capture(request, resultListener, mHandler);
1071 
1072             compensatedResult = resultListener.getCaptureResultForRequest(
1073                     request, WAIT_FOR_RESULT_TIMEOUT_MS);
1074 
1075             if (mStaticInfo.isCapabilitySupported(
1076                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
1077                 // Verify the exposure value compensates as requested
1078                 long compensatedExposureValue = getExposureValue(compensatedResult);
1079                 mCollector.expectInRange("Exposure setting out of bound", compensatedExposureValue,
1080                         minExposureValue, maxExposureValueStill);
1081                 double observedRatio = (double) compensatedExposureValue / normalExposureValue;
1082                 double error = observedRatio / expectedRatio;
1083                 String errorString = String.format(
1084                         "Exposure compensation ratio exceeds error tolerence:" +
1085                         " expected(%f) observed(%f)." +
1086                         " Normal exposure time %d us, sensitivity %d." +
1087                         " Compensated exposure time %d us, sensitivity %d",
1088                         expectedRatio, observedRatio,
1089                         (int) (getValueNotNull(
1090                                 normalResult, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000),
1091                         getValueNotNull(normalResult, CaptureResult.SENSOR_SENSITIVITY),
1092                         (int) (getValueNotNull(
1093                                 compensatedResult, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000),
1094                         getValueNotNull(compensatedResult, CaptureResult.SENSOR_SENSITIVITY));
1095                 mCollector.expectInRange(errorString, error,
1096                         1.0 - AE_COMPENSATION_ERROR_TOLERANCE,
1097                         1.0 + AE_COMPENSATION_ERROR_TOLERANCE);
1098             }
1099 
1100             mCollector.expectEquals("Exposure compensation result should match requested value.",
1101                     exposureCompensation,
1102                     compensatedResult.get(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION));
1103             if (canSetAeLock) {
1104                 mCollector.expectTrue("Exposure lock should be set",
1105                         compensatedResult.get(CaptureResult.CONTROL_AE_LOCK));
1106             }
1107 
1108             Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
1109             validateJpegCapture(image, maxStillSz);
1110             image.close();
1111 
1112             // Recover AE compensation and lock
1113             previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);
1114             if (canSetAeLock) {
1115                 previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, false);
1116             }
1117             mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
1118         }
1119     }
1120 
getExposureValue(CaptureResult result)1121     private long getExposureValue(CaptureResult result) throws Exception {
1122         int expTimeUs = (int) (getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000);
1123         int sensitivity = getValueNotNull(result, CaptureResult.SENSOR_SENSITIVITY);
1124         return expTimeUs * sensitivity;
1125     }
1126 
getMaxExposureValue(CaptureRequest.Builder request, long maxExposureTimeUs, long maxSensitivity)1127     private long getMaxExposureValue(CaptureRequest.Builder request, long maxExposureTimeUs,
1128                 long maxSensitivity)  throws Exception {
1129         Range<Integer> fpsRange = request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
1130         long maxFrameDurationUs = Math.round(1000000.0 / fpsRange.getLower());
1131         long currentMaxExposureTimeUs = Math.min(maxFrameDurationUs, maxExposureTimeUs);
1132         return currentMaxExposureTimeUs * maxSensitivity;
1133     }
1134 
1135 
1136     //----------------------------------------------------------------
1137     //---------Below are common functions for all tests.--------------
1138     //----------------------------------------------------------------
1139     /**
1140      * Validate standard raw (RAW16) capture image.
1141      *
1142      * @param image The raw16 format image captured
1143      * @param rawSize The expected raw size
1144      */
validateRaw16Image(Image image, Size rawSize)1145     private static void validateRaw16Image(Image image, Size rawSize) {
1146         CameraTestUtils.validateImage(image, rawSize.getWidth(), rawSize.getHeight(),
1147                 ImageFormat.RAW_SENSOR, /*filePath*/null);
1148     }
1149 
1150     /**
1151      * Validate JPEG capture image object sanity and test.
1152      * <p>
1153      * In addition to image object sanity, this function also does the decoding
1154      * test, which is slower.
1155      * </p>
1156      *
1157      * @param image The JPEG image to be verified.
1158      * @param jpegSize The JPEG capture size to be verified against.
1159      */
validateJpegCapture(Image image, Size jpegSize)1160     private static void validateJpegCapture(Image image, Size jpegSize) {
1161         CameraTestUtils.validateImage(image, jpegSize.getWidth(), jpegSize.getHeight(),
1162                 ImageFormat.JPEG, /*filePath*/null);
1163     }
1164 
1165     private static class SimpleAutoFocusListener implements Camera2Focuser.AutoFocusListener {
1166         final ConditionVariable focusDone = new ConditionVariable();
1167         @Override
onAutoFocusLocked(boolean success)1168         public void onAutoFocusLocked(boolean success) {
1169             focusDone.open();
1170         }
1171 
waitForAutoFocusDone(long timeoutMs)1172         public void waitForAutoFocusDone(long timeoutMs) {
1173             if (focusDone.block(timeoutMs)) {
1174                 focusDone.close();
1175             } else {
1176                 throw new TimeoutRuntimeException("Wait for auto focus done timed out after "
1177                         + timeoutMs + "ms");
1178             }
1179         }
1180     }
1181 
1182     /**
1183      * Get 5 3A region test cases, each with one square region in it.
1184      * The first one is at center, the other four are at corners of
1185      * active array rectangle.
1186      *
1187      * @return array of test 3A regions
1188      */
get3ARegionTestCasesForCamera()1189     private ArrayList<MeteringRectangle[]> get3ARegionTestCasesForCamera() {
1190         final int TEST_3A_REGION_NUM = 5;
1191         final int DEFAULT_REGION_WEIGHT = 30;
1192         final int DEFAULT_REGION_SCALE_RATIO = 8;
1193         ArrayList<MeteringRectangle[]> testCases =
1194                 new ArrayList<MeteringRectangle[]>(TEST_3A_REGION_NUM);
1195         final Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked();
1196         int regionWidth = activeArraySize.width() / DEFAULT_REGION_SCALE_RATIO - 1;
1197         int regionHeight = activeArraySize.height() / DEFAULT_REGION_SCALE_RATIO - 1;
1198         int centerX = activeArraySize.width() / 2;
1199         int centerY = activeArraySize.height() / 2;
1200         int bottomRightX = activeArraySize.width() - 1;
1201         int bottomRightY = activeArraySize.height() - 1;
1202 
1203         // Center region
1204         testCases.add(
1205                 new MeteringRectangle[] {
1206                     new MeteringRectangle(
1207                             centerX - regionWidth / 2,  // x
1208                             centerY - regionHeight / 2, // y
1209                             regionWidth,                // width
1210                             regionHeight,               // height
1211                             DEFAULT_REGION_WEIGHT)});
1212 
1213         // Upper left corner
1214         testCases.add(
1215                 new MeteringRectangle[] {
1216                     new MeteringRectangle(
1217                             0,                // x
1218                             0,                // y
1219                             regionWidth,      // width
1220                             regionHeight,     // height
1221                             DEFAULT_REGION_WEIGHT)});
1222 
1223         // Upper right corner
1224         testCases.add(
1225                 new MeteringRectangle[] {
1226                     new MeteringRectangle(
1227                             bottomRightX - regionWidth, // x
1228                             0,                          // y
1229                             regionWidth,                // width
1230                             regionHeight,               // height
1231                             DEFAULT_REGION_WEIGHT)});
1232 
1233         // Bottom left corner
1234         testCases.add(
1235                 new MeteringRectangle[] {
1236                     new MeteringRectangle(
1237                             0,                           // x
1238                             bottomRightY - regionHeight, // y
1239                             regionWidth,                 // width
1240                             regionHeight,                // height
1241                             DEFAULT_REGION_WEIGHT)});
1242 
1243         // Bottom right corner
1244         testCases.add(
1245                 new MeteringRectangle[] {
1246                     new MeteringRectangle(
1247                             bottomRightX - regionWidth,  // x
1248                             bottomRightY - regionHeight, // y
1249                             regionWidth,                 // width
1250                             regionHeight,                // height
1251                             DEFAULT_REGION_WEIGHT)});
1252 
1253         if (VERBOSE) {
1254             StringBuilder sb = new StringBuilder();
1255             for (MeteringRectangle[] mr : testCases) {
1256                 sb.append("{");
1257                 sb.append(Arrays.toString(mr));
1258                 sb.append("}, ");
1259             }
1260             if (sb.length() > 1)
1261                 sb.setLength(sb.length() - 2); // Remove the redundant comma and space at the end
1262             Log.v(TAG, "Generated test regions are: " + sb.toString());
1263         }
1264 
1265         return testCases;
1266     }
1267 
isRegionsSupportedFor3A(int index)1268     private boolean isRegionsSupportedFor3A(int index) {
1269         int maxRegions = 0;
1270         switch (index) {
1271             case MAX_REGIONS_AE_INDEX:
1272                 maxRegions = mStaticInfo.getAeMaxRegionsChecked();
1273                 break;
1274             case MAX_REGIONS_AWB_INDEX:
1275                 maxRegions = mStaticInfo.getAwbMaxRegionsChecked();
1276                 break;
1277             case  MAX_REGIONS_AF_INDEX:
1278                 maxRegions = mStaticInfo.getAfMaxRegionsChecked();
1279                 break;
1280             default:
1281                 throw new IllegalArgumentException("Unknown algorithm index");
1282         }
1283         boolean isRegionsSupported = maxRegions > 0;
1284         if (index == MAX_REGIONS_AF_INDEX && isRegionsSupported) {
1285             mCollector.expectTrue(
1286                     "Device reports non-zero max AF region count for a camera without focuser!",
1287                     mStaticInfo.hasFocuser());
1288             isRegionsSupported = isRegionsSupported && mStaticInfo.hasFocuser();
1289         }
1290 
1291         return isRegionsSupported;
1292     }
1293 }
1294