• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
21 import android.graphics.Bitmap;
22 import android.graphics.Bitmap.Config;
23 import android.graphics.ImageFormat;
24 import android.graphics.Point;
25 import android.graphics.Rect;
26 import android.hardware.camera2.CameraCharacteristics;
27 import android.hardware.camera2.CameraDevice;
28 import android.hardware.camera2.CaptureRequest;
29 import android.hardware.camera2.CaptureResult;
30 import android.hardware.camera2.DngCreator;
31 import android.hardware.camera2.params.DynamicRangeProfiles;
32 import android.hardware.camera2.params.OutputConfiguration;
33 import android.location.Location;
34 import android.location.LocationManager;
35 import android.media.ImageReader;
36 import android.util.Pair;
37 import android.util.Size;
38 import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback;
39 import android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener;
40 import android.hardware.camera2.cts.helpers.Camera2Focuser;
41 import android.hardware.camera2.cts.helpers.StaticMetadata;
42 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
43 import android.hardware.camera2.params.MeteringRectangle;
44 import android.media.Image;
45 import android.os.ConditionVariable;
46 import android.util.Log;
47 import android.util.Range;
48 import android.util.Rational;
49 import android.view.Surface;
50 
51 import com.android.ex.camera2.blocking.BlockingSessionCallback;
52 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
53 
54 import java.io.ByteArrayOutputStream;
55 import java.util.ArrayList;
56 import java.util.Arrays;
57 import java.util.List;
58 import java.util.Set;
59 
60 import junit.framework.Assert;
61 
62 import org.junit.runners.Parameterized;
63 import org.junit.runner.RunWith;
64 import org.junit.Test;
65 
66 @RunWith(Parameterized.class)
67 public class StillCaptureTest 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 RELAXED_CAPTURE_IMAGE_TIMEOUT_MS = CAPTURE_IMAGE_TIMEOUT_MS + 1000;
73     private static final int MAX_REGIONS_AE_INDEX = 0;
74     private static final int MAX_REGIONS_AWB_INDEX = 1;
75     private static final int MAX_REGIONS_AF_INDEX = 2;
76     private static final int WAIT_FOR_FOCUS_DONE_TIMEOUT_MS = 6000;
77     private static final double AE_COMPENSATION_ERROR_TOLERANCE = 0.2;
78     private static final int NUM_FRAMES_WAITED = 30;
79     // 5 percent error margin for resulting metering regions
80     private static final float METERING_REGION_ERROR_PERCENT_DELTA = 0.05f;
81     // Android CDD (5.0 and newer) required number of simultenous bitmap allocations for camera
82     private static final int MAX_ALLOCATED_BITMAPS = 3;
83 
84     @Override
setUp()85     public void setUp() throws Exception {
86         super.setUp();
87     }
88 
89     @Override
tearDown()90     public void tearDown() throws Exception {
91         super.tearDown();
92     }
93 
94     /**
95      * Test JPEG capture exif fields for each camera.
96      */
97     @Test
testJpegExif()98     public void testJpegExif() throws Exception {
99         for (int i = 0; i < mCameraIdsUnderTest.length; i++) {
100             try {
101                 Log.i(TAG, "Testing JPEG exif for Camera " + mCameraIdsUnderTest[i]);
102                 if (!mAllStaticInfo.get(mCameraIdsUnderTest[i]).isColorOutputSupported()) {
103                     Log.i(TAG, "Camera " + mCameraIdsUnderTest[i] +
104                             " does not support color outputs, skipping");
105                     continue;
106                 }
107                 openDevice(mCameraIdsUnderTest[i]);
108                 Size maxJpegSize = mOrderedStillSizes.get(0);
109                 stillExifTestByCamera(ImageFormat.JPEG, maxJpegSize);
110             } finally {
111                 closeDevice();
112                 closeImageReader();
113             }
114         }
115     }
116 
117     /**
118      * Test HEIC capture exif fields for each camera.
119      */
120     @Test
testHeicExif()121     public void testHeicExif() throws Exception {
122         for (int i = 0; i < mCameraIdsUnderTest.length; i++) {
123             try {
124                 Log.i(TAG, "Testing HEIC exif for Camera " + mCameraIdsUnderTest[i]);
125                 if (!mAllStaticInfo.get(mCameraIdsUnderTest[i]).isColorOutputSupported()) {
126                     Log.i(TAG, "Camera " + mCameraIdsUnderTest[i] +
127                             " does not support color outputs, skipping");
128                     continue;
129                 }
130                 if (!mAllStaticInfo.get(mCameraIdsUnderTest[i]).isHeicSupported()) {
131                     Log.i(TAG, "Camera " + mCameraIdsUnderTest[i] +
132                             " does not support HEIC, skipping");
133                     continue;
134                 }
135 
136                 openDevice(mCameraIdsUnderTest[i]);
137 
138                 // Test maximum Heic size capture
139                 List<Size> orderedHeicSizes = CameraTestUtils.getSupportedHeicSizes(
140                         mCameraIdsUnderTest[i], mCameraManager, null/*bound*/);
141                 Size maxHeicSize = orderedHeicSizes.get(0);
142                 stillExifTestByCamera(ImageFormat.HEIC, maxHeicSize);
143 
144                 // Test preview size Heic capture
145                 Size previewSize = mOrderedPreviewSizes.get(0);
146                 stillExifTestByCamera(ImageFormat.HEIC, previewSize);
147 
148             } finally {
149                 closeDevice();
150                 closeImageReader();
151             }
152         }
153     }
154 
155     /**
156      * Test dynamic depth capture along with preview for each camera.
157      */
158     @Test
testDynamicDepthCapture()159     public void testDynamicDepthCapture() throws Exception {
160         for (int i = 0; i < mCameraIdsUnderTest.length; i++) {
161             try {
162                 Log.i(TAG, "Testing dynamic depth for Camera " + mCameraIdsUnderTest[i]);
163                 if (!mAllStaticInfo.get(mCameraIdsUnderTest[i]).isColorOutputSupported()) {
164                     Log.i(TAG, "Camera " + mCameraIdsUnderTest[i] +
165                             " does not support color outputs, skipping");
166                     continue;
167                 }
168                 if (!mAllStaticInfo.get(mCameraIdsUnderTest[i]).isDepthJpegSupported()) {
169                     Log.i(TAG, "Camera " + mCameraIdsUnderTest[i] +
170                             " does not support dynamic depth, skipping");
171                     continue;
172                 }
173 
174                 openDevice(mCameraIdsUnderTest[i]);
175 
176                 // Check the maximum supported size.
177                 List<Size> orderedDepthJpegSizes = CameraTestUtils.getSortedSizesForFormat(
178                         mCameraIdsUnderTest[i], mCameraManager, ImageFormat.DEPTH_JPEG, null/*bound*/);
179                 Size maxDepthJpegSize = orderedDepthJpegSizes.get(0);
180                 stillDynamicDepthTestByCamera(ImageFormat.DEPTH_JPEG, maxDepthJpegSize);
181             } finally {
182                 closeDevice();
183                 closeImageReader();
184             }
185         }
186     }
187 
188     /**
189      * Test Jpeg/R capture along with preview for each camera.
190      */
191     @Test
testJpegRCapture()192     public void testJpegRCapture() throws Exception {
193         for (int i = 0; i < mCameraIdsUnderTest.length; i++) {
194             try {
195                 Log.i(TAG, "Testing Jpeg/R for Camera " + mCameraIdsUnderTest[i]);
196                 if (!mAllStaticInfo.get(mCameraIdsUnderTest[i]).isColorOutputSupported()) {
197                     Log.i(TAG, "Camera " + mCameraIdsUnderTest[i] +
198                             " does not support color outputs, skipping");
199                     continue;
200                 }
201                 if (!mAllStaticInfo.get(mCameraIdsUnderTest[i]).isJpegRSupported()) {
202                     Log.i(TAG, "Camera " + mCameraIdsUnderTest[i] +
203                             " does not support Jpeg/R, skipping");
204                     continue;
205                 }
206 
207                 openDevice(mCameraIdsUnderTest[i]);
208 
209                 // Check the maximum supported size.
210                 List<Size> orderedJpegRSizes = CameraTestUtils.getSortedSizesForFormat(
211                         mCameraIdsUnderTest[i], mCameraManager, ImageFormat.JPEG_R, null/*bound*/);
212                 Size maxJpegRSize = orderedJpegRSizes.get(0);
213                 stillJpegRTestByCamera(ImageFormat.JPEG_R, maxJpegRSize);
214             } finally {
215                 closeDevice();
216                 closeImageReader();
217             }
218         }
219     }
220 
221     /**
222      * Issue a still capture and validate the Jpeg/R output.
223      */
stillJpegRTestByCamera(int format, Size stillSize)224     private void stillJpegRTestByCamera(int format, Size stillSize) throws Exception {
225         assertTrue(format == ImageFormat.JPEG_R);
226 
227         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
228         if (VERBOSE) {
229             Log.v(TAG, "Testing Jpeg/R with size " + stillSize.toString()
230                     + ", preview size " + maxPreviewSz);
231         }
232 
233         // prepare capture and start preview.
234         CaptureRequest.Builder previewBuilder =
235                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
236         CaptureRequest.Builder stillBuilder =
237                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
238         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
239         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
240 
241         updatePreviewSurface(maxPreviewSz);
242         createImageReader(stillSize, format, MAX_READER_IMAGES, imageListener);
243 
244         List<OutputConfiguration> outputConfigs = new ArrayList<>();
245         OutputConfiguration previewConfig = new OutputConfiguration(mPreviewSurface);
246         previewConfig.setDynamicRangeProfile(DynamicRangeProfiles.HLG10);
247         outputConfigs.add(previewConfig);
248         outputConfigs.add(new OutputConfiguration(mReaderSurface));
249         mSessionListener = new BlockingSessionCallback();
250         mSession = configureCameraSessionWithConfig(mCamera, outputConfigs, mSessionListener,
251                 mHandler);
252 
253         previewBuilder.addTarget(mPreviewSurface);
254         stillBuilder.addTarget(mReaderSurface);
255 
256         // Start preview.
257         mSession.setRepeatingRequest(previewBuilder.build(), resultListener, mHandler);
258 
259         // Capture a few Jpeg/R images and check whether they are valid jpegs.
260         for (int i = 0; i < MAX_READER_IMAGES; i++) {
261             CaptureRequest request = stillBuilder.build();
262             mSession.capture(request, resultListener, mHandler);
263             assertNotNull(resultListener.getCaptureResultForRequest(request,
264                     NUM_RESULTS_WAIT_TIMEOUT));
265             Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
266             assertNotNull("Unable to acquire next image", image);
267             CameraTestUtils.validateImage(image, stillSize.getWidth(), stillSize.getHeight(),
268                     format, null /*filePath*/);
269 
270             // Free image resources
271             image.close();
272         }
273     }
274 
275     /**
276      * Test normal still capture sequence.
277      * <p>
278      * Preview and jpeg output streams are configured. Max still capture
279      * size is used for jpeg capture. The sequence of still capture being test
280      * is: start preview, auto focus, precapture metering (if AE is not
281      * converged), then capture jpeg. The AWB and AE are in auto modes. AF mode
282      * is CONTINUOUS_PICTURE.
283      * </p>
284      */
285     @Test
testTakePicture()286     public void testTakePicture() throws Exception{
287         for (String id : mCameraIdsUnderTest) {
288             try {
289                 Log.i(TAG, "Testing basic take picture for Camera " + id);
290                 if (!mAllStaticInfo.get(id).isColorOutputSupported()) {
291                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
292                     continue;
293                 }
294                 openDevice(id);
295                 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null);
296             } finally {
297                 closeDevice();
298                 closeImageReader();
299             }
300         }
301     }
302 
303     /**
304      * Test ZSL still capture sequence.
305      * <p>
306      * Preview and jpeg output streams are configured. Max still capture
307      * size is used for jpeg capture. The sequence of still capture being test
308      * is: start preview, auto focus, precapture metering (if AE is not
309      * converged), then capture jpeg. The AWB and AE are in auto modes. AF mode
310      * is CONTINUOUS_PICTURE. Same as testTakePicture, but with enableZSL set.
311      * </p>
312      */
313     @Test
testTakePictureZsl()314     public void testTakePictureZsl() throws Exception{
315         for (String id : mCameraIdsUnderTest) {
316             try {
317                 Log.i(TAG, "Testing basic ZSL take picture for Camera " + id);
318                 if (!mAllStaticInfo.get(id).isColorOutputSupported()) {
319                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
320                     continue;
321                 }
322                 openDevice(id);
323                 CaptureRequest.Builder stillRequest =
324                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
325                 stillRequest.set(CaptureRequest.CONTROL_ENABLE_ZSL, true);
326                 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null,
327                         /*addAeTriggerCancel*/false, /*allocateBitmap*/false,
328                         /*previewRequest*/null, stillRequest);
329             } finally {
330                 closeDevice();
331                 closeImageReader();
332             }
333         }
334     }
335 
336     /**
337      * Test basic Raw capture. Raw buffer avaiablility is checked, but raw buffer data is not.
338      */
339     @Test
testBasicRawCapture()340     public void testBasicRawCapture()  throws Exception {
341        for (int i = 0; i < mCameraIdsUnderTest.length; i++) {
342            try {
343                Log.i(TAG, "Testing raw capture for Camera " + mCameraIdsUnderTest[i]);
344 
345                if (!mAllStaticInfo.get(mCameraIdsUnderTest[i]).isCapabilitySupported(
346                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
347                    Log.i(TAG, "RAW capability is not supported in camera " + mCameraIdsUnderTest[i] +
348                            ". Skip the test.");
349                    continue;
350                }
351 
352                openDevice(mCameraIdsUnderTest[i]);
353                rawCaptureTestByCamera(/*stillRequest*/null);
354            } finally {
355                closeDevice();
356                closeImageReader();
357            }
358        }
359     }
360 
361     /**
362      * Test basic Raw ZSL capture. Raw buffer avaiablility is checked, but raw buffer data is not.
363      */
364     @Test
testBasicRawZslCapture()365     public void testBasicRawZslCapture()  throws Exception {
366        for (int i = 0; i < mCameraIdsUnderTest.length; i++) {
367            try {
368                Log.i(TAG, "Testing raw ZSL capture for Camera " + mCameraIdsUnderTest[i]);
369 
370                if (!mAllStaticInfo.get(mCameraIdsUnderTest[i]).isCapabilitySupported(
371                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
372                    Log.i(TAG, "RAW capability is not supported in camera " + mCameraIdsUnderTest[i] +
373                            ". Skip the test.");
374                    continue;
375                }
376                openDevice(mCameraIdsUnderTest[i]);
377                CaptureRequest.Builder stillRequest =
378                        mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
379                stillRequest.set(CaptureRequest.CONTROL_ENABLE_ZSL, true);
380                rawCaptureTestByCamera(stillRequest);
381            } finally {
382                closeDevice();
383                closeImageReader();
384            }
385        }
386     }
387 
388 
389     /**
390      * Test the full raw capture use case.
391      *
392      * This includes:
393      * - Configuring the camera with a preview, jpeg, and raw output stream.
394      * - Running preview until AE/AF can settle.
395      * - Capturing with a request targeting all three output streams.
396      */
397     @Test
testFullRawCapture()398     public void testFullRawCapture() throws Exception {
399         for (int i = 0; i < mCameraIdsUnderTest.length; i++) {
400             try {
401                 Log.i(TAG, "Testing raw+JPEG capture for Camera " + mCameraIdsUnderTest[i]);
402                 if (!mAllStaticInfo.get(mCameraIdsUnderTest[i]).isCapabilitySupported(
403                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
404                     Log.i(TAG, "RAW capability is not supported in camera " + mCameraIdsUnderTest[i] +
405                             ". Skip the test.");
406                     continue;
407                 }
408 
409                 openDevice(mCameraIdsUnderTest[i]);
410                 fullRawCaptureTestByCamera(/*stillRequest*/null);
411             } finally {
412                 closeDevice();
413                 closeImageReader();
414             }
415         }
416     }
417 
418     /**
419      * Test the full raw capture ZSL use case.
420      *
421      * This includes:
422      * - Configuring the camera with a preview, jpeg, and raw output stream.
423      * - Running preview until AE/AF can settle.
424      * - Capturing with a request targeting all three output streams.
425      */
426     @Test
testFullRawZSLCapture()427     public void testFullRawZSLCapture() throws Exception {
428         for (int i = 0; i < mCameraIdsUnderTest.length; i++) {
429             try {
430                 Log.i(TAG, "Testing raw+JPEG ZSL capture for Camera " + mCameraIdsUnderTest[i]);
431                 if (!mAllStaticInfo.get(mCameraIdsUnderTest[i]).isCapabilitySupported(
432                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
433                     Log.i(TAG, "RAW capability is not supported in camera " + mCameraIdsUnderTest[i] +
434                             ". Skip the test.");
435                     continue;
436                 }
437                 openDevice(mCameraIdsUnderTest[i]);
438                 CaptureRequest.Builder stillRequest =
439                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
440                 stillRequest.set(CaptureRequest.CONTROL_ENABLE_ZSL, true);
441                 fullRawCaptureTestByCamera(stillRequest);
442             } finally {
443                 closeDevice();
444                 closeImageReader();
445             }
446         }
447     }
448 
449     /**
450      * Test touch for focus.
451      * <p>
452      * AF is in CAF mode when preview is started, test uses several pre-selected
453      * regions to simulate touches. Active scan is triggered to make sure the AF
454      * converges in reasonable time.
455      * </p>
456      */
457     @Test
testTouchForFocus()458     public void testTouchForFocus() throws Exception {
459         for (String id : mCameraIdsUnderTest) {
460             try {
461                 Log.i(TAG, "Testing touch for focus for Camera " + id);
462                 StaticMetadata staticInfo = mAllStaticInfo.get(id);
463                 int maxAfRegions = staticInfo.getAfMaxRegionsChecked();
464                 if (!(staticInfo.hasFocuser() && maxAfRegions > 0)) {
465                     continue;
466                 }
467                 // TODO: Relax test to use non-SurfaceView output for depth cases
468                 if (!staticInfo.isColorOutputSupported()) {
469                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
470                     continue;
471                 }
472                 openDevice(id);
473                 touchForFocusTestByCamera();
474             } finally {
475                 closeDevice();
476                 closeImageReader();
477             }
478         }
479     }
480 
481     /**
482      * Test all combination of available preview sizes and still sizes.
483      * <p>
484      * For each still capture, Only the jpeg buffer is validated, capture
485      * result validation is covered by {@link #stillExifTestByCamera} test.
486      * </p>
487      */
488     @Test(timeout=120*60*1000) // timeout = 120 mins for long running tests
testStillPreviewCombination()489     public void testStillPreviewCombination() throws Exception {
490         for (String id : mCameraIdsUnderTest) {
491             try {
492                 Log.i(TAG, "Testing Still preview capture combination for Camera " + id);
493                 if (!mAllStaticInfo.get(id).isColorOutputSupported()) {
494                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
495                     continue;
496                 }
497                 openDevice(id);
498                 previewStillCombinationTestByCamera();
499             } finally {
500                 closeDevice();
501                 closeImageReader();
502             }
503         }
504     }
505 
506     /**
507      * Test AE compensation.
508      * <p>
509      * For each integer EV compensation setting: retrieve the exposure value (exposure time *
510      * sensitivity) with or without compensation, verify if the exposure value is legal (conformed
511      * to what static info has) and the ratio between two exposure values matches EV compensation
512      * setting. Also test for the behavior that exposure settings should be changed when AE
513      * compensation settings is changed, even when AE lock is ON.
514      * </p>
515      */
516     @Test
testAeCompensation()517     public void testAeCompensation() throws Exception {
518         for (String id : mCameraIdsUnderTest) {
519             try {
520                 Log.i(TAG, "Testing AE compensation for Camera " + id);
521 
522                 StaticMetadata staticInfo = mAllStaticInfo.get(id);
523                 if (staticInfo.isHardwareLevelLegacy()) {
524                     Log.i(TAG, "Skipping test on legacy devices");
525                     continue;
526                 }
527                 if (!staticInfo.isColorOutputSupported()) {
528                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
529                     continue;
530                 }
531                 openDevice(id);
532                 aeCompensationTestByCamera();
533             } finally {
534                 closeDevice();
535                 closeImageReader();
536             }
537         }
538     }
539 
540     /**
541      * Test Ae region for still capture.
542      */
543     @Test
testAeRegions()544     public void testAeRegions() throws Exception {
545         for (String id : mCameraIdsUnderTest) {
546             try {
547                 Log.i(TAG, "Testing AE regions for Camera " + id);
548                 openDevice(id);
549 
550                 boolean aeRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AE_INDEX);
551                 if (!aeRegionsSupported) {
552                     continue;
553                 }
554 
555                 ArrayList<MeteringRectangle[]> aeRegionTestCases = get3ARegionTestCasesForCamera();
556                 for (MeteringRectangle[] aeRegions : aeRegionTestCases) {
557                     takePictureTestByCamera(aeRegions, /*awbRegions*/null, /*afRegions*/null);
558                 }
559             } finally {
560                 closeDevice();
561                 closeImageReader();
562             }
563         }
564     }
565 
566     /**
567      * Test AWB region for still capture.
568      */
569     @Test
testAwbRegions()570     public void testAwbRegions() throws Exception {
571         for (String id : mCameraIdsUnderTest) {
572             try {
573                 Log.i(TAG, "Testing AE regions for Camera " + id);
574                 openDevice(id);
575 
576                 boolean awbRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AWB_INDEX);
577                 if (!awbRegionsSupported) {
578                     continue;
579                 }
580 
581                 ArrayList<MeteringRectangle[]> awbRegionTestCases = get3ARegionTestCasesForCamera();
582                 for (MeteringRectangle[] awbRegions : awbRegionTestCases) {
583                     takePictureTestByCamera(/*aeRegions*/null, awbRegions, /*afRegions*/null);
584                 }
585             } finally {
586                 closeDevice();
587                 closeImageReader();
588             }
589         }
590     }
591 
592     /**
593      * Test Af region for still capture.
594      */
595     @Test
testAfRegions()596     public void testAfRegions() throws Exception {
597         for (String id : mCameraIdsUnderTest) {
598             try {
599                 Log.i(TAG, "Testing AF regions for Camera " + id);
600                 openDevice(id);
601 
602                 boolean afRegionsSupported = isRegionsSupportedFor3A(MAX_REGIONS_AF_INDEX);
603                 if (!afRegionsSupported) {
604                     continue;
605                 }
606 
607                 ArrayList<MeteringRectangle[]> afRegionTestCases = get3ARegionTestCasesForCamera();
608                 for (MeteringRectangle[] afRegions : afRegionTestCases) {
609                     takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, afRegions);
610                 }
611             } finally {
612                 closeDevice();
613                 closeImageReader();
614             }
615         }
616     }
617 
618     /**
619      * Test preview is still running after a still request
620      */
621     @Test
testPreviewPersistence()622     public void testPreviewPersistence() throws Exception {
623         for (String id : mCameraIdsUnderTest) {
624             try {
625                 Log.i(TAG, "Testing preview persistence for Camera " + id);
626                 if (!mAllStaticInfo.get(id).isColorOutputSupported()) {
627                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
628                     continue;
629                 }
630                 openDevice(id);
631                 previewPersistenceTestByCamera();
632             } finally {
633                 closeDevice();
634                 closeImageReader();
635             }
636         }
637     }
638 
639     @Test
testAePrecaptureTriggerCancelJpegCapture()640     public void testAePrecaptureTriggerCancelJpegCapture() throws Exception {
641         for (String id : mCameraIdsUnderTest) {
642             try {
643                 Log.i(TAG, "Testing AE precapture cancel for jpeg capture for Camera " + id);
644 
645                 StaticMetadata staticInfo = mAllStaticInfo.get(id);
646                 // Legacy device doesn't support AE precapture trigger
647                 if (staticInfo.isHardwareLevelLegacy()) {
648                     Log.i(TAG, "Skipping AE precapture trigger cancel test on legacy devices");
649                     continue;
650                 }
651                 if (!staticInfo.isColorOutputSupported()) {
652                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
653                     continue;
654                 }
655                 openDevice(id);
656                 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null,
657                         /*addAeTriggerCancel*/true, /*allocateBitmap*/false,
658                         /*previewRequest*/null, /*stillRequest*/null);
659             } finally {
660                 closeDevice();
661                 closeImageReader();
662             }
663         }
664     }
665 
666     /**
667      * Test allocate some bitmaps while taking picture.
668      * <p>
669      * Per android CDD (5.0 and newer), android devices should support allocation of at least 3
670      * bitmaps equal to the size of the images produced by the largest resolution camera sensor on
671      * the devices.
672      * </p>
673      */
674     @Test
testAllocateBitmap()675     public void testAllocateBitmap() throws Exception {
676         for (String id : mCameraIdsUnderTest) {
677             try {
678                 Log.i(TAG, "Testing bitmap allocations for Camera " + id);
679                 if (!mAllStaticInfo.get(id).isColorOutputSupported()) {
680                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
681                     continue;
682                 }
683                 openDevice(id);
684                 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null,
685                         /*addAeTriggerCancel*/false, /*allocateBitmap*/true,
686                         /*previewRequest*/null, /*stillRequest*/null);
687             } finally {
688                 closeDevice();
689                 closeImageReader();
690             }
691         }
692 
693     }
694 
695     /**
696      * Test focal length controls.
697      */
698     @Test
testFocalLengths()699     public void testFocalLengths() throws Exception {
700         for (String id : mCameraIdsUnderTest) {
701             try {
702                 StaticMetadata staticInfo = mAllStaticInfo.get(id);
703                 if (staticInfo.isHardwareLevelLegacy()) {
704                     Log.i(TAG, "Camera " + id + " is legacy, skipping");
705                     continue;
706                 }
707                 if (!staticInfo.isColorOutputSupported()) {
708                     Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
709                     continue;
710                 }
711                 if (staticInfo.isExternalCamera()) {
712                     Log.i(TAG, "Camera " + id + " is external, skipping");
713                     continue;
714                 }
715                 openDevice(id);
716                 focalLengthTestByCamera();
717             } finally {
718                 closeDevice();
719                 closeImageReader();
720             }
721         }
722     }
723 
focalLengthTestByCamera()724     private void focalLengthTestByCamera() throws Exception {
725         float[] focalLengths = mStaticInfo.getAvailableFocalLengthsChecked();
726         int numStillCaptures = focalLengths.length;
727 
728         Size maxStillSz = mOrderedStillSizes.get(0);
729         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
730         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
731         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
732         CaptureRequest.Builder previewRequest =
733                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
734         CaptureRequest.Builder stillRequest =
735                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
736         Size thumbnailSize = new Size(0, 0);
737         Location sTestLocation = new Location(LocationManager.GPS_PROVIDER);
738         sTestLocation.setTime(1199145600000L);
739         sTestLocation.setLatitude(37.736071);
740         sTestLocation.setLongitude(-122.441983);
741         sTestLocation.setAltitude(21.0);
742         ExifTestData exifTestData = new ExifTestData(
743                 /* gpsLocation */ sTestLocation,
744                 /* orientation */ 0,
745                 /* jpgQuality */ (byte) 80,
746                 /* thumbnailQuality */ (byte) 75);
747         setJpegKeys(stillRequest, exifTestData, thumbnailSize, mCollector);
748         CaptureResult result;
749 
750         // Set the max number of images to number of focal lengths supported
751         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
752                 maxStillSz, resultListener, focalLengths.length, imageListener, false /*isHeic*/);
753 
754         for(float focalLength : focalLengths) {
755 
756             previewRequest.set(CaptureRequest.LENS_FOCAL_LENGTH, focalLength);
757             mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
758             waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
759             waitForResultValue(resultListener, CaptureResult.LENS_STATE,
760                     CaptureResult.LENS_STATE_STATIONARY, NUM_RESULTS_WAIT_TIMEOUT);
761             result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
762             Float focalLengthInResult = result.get(CaptureResult.LENS_FOCAL_LENGTH);
763             Set<Float> validFocalLengths = getAvailableFocalLengthsForResult(
764                     result, mStaticInfo, mAllStaticInfo);
765             if (focalLengths.length > 1) {
766                 mCollector.expectEquals(
767                         "Focal length in preview result and request should be the same",
768                         previewRequest.get(CaptureRequest.LENS_FOCAL_LENGTH),
769                         focalLengthInResult);
770             } else {
771                 mCollector.expectTrue(
772                         "Focal length in preview result should be a supported value",
773                         validFocalLengths.contains(focalLengthInResult));
774             }
775 
776             stillRequest.set(CaptureRequest.LENS_FOCAL_LENGTH, focalLength);
777             CaptureRequest request = stillRequest.build();
778             resultListener = new SimpleCaptureCallback();
779             mSession.capture(request, resultListener, mHandler);
780             result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
781             focalLengthInResult = result.get(CaptureResult.LENS_FOCAL_LENGTH);
782             if (focalLengths.length > 1) {
783                 mCollector.expectEquals(
784                         "Focal length in still capture result and request should be the same",
785                         stillRequest.get(CaptureRequest.LENS_FOCAL_LENGTH),
786                         result.get(CaptureResult.LENS_FOCAL_LENGTH));
787             } else {
788                 mCollector.expectTrue(
789                         "Focal length in still capture result should be a supported value",
790                         validFocalLengths.contains(focalLengthInResult));
791             }
792 
793             Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
794 
795             validateJpegCapture(image, maxStillSz);
796             verifyJpegKeys(image, result, maxStillSz, thumbnailSize, exifTestData,
797                     mStaticInfo, mAllStaticInfo, mCollector, mDebugFileNameBase, ImageFormat.JPEG);
798         }
799     }
800 
801 
802     /**
803      * Start preview,take a picture and test preview is still running after snapshot
804      */
previewPersistenceTestByCamera()805     private void previewPersistenceTestByCamera() throws Exception {
806         Size maxStillSz = mOrderedStillSizes.get(0);
807         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
808 
809         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
810         SimpleCaptureCallback stillResultListener = new SimpleCaptureCallback();
811         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
812         CaptureRequest.Builder previewRequest =
813                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
814         CaptureRequest.Builder stillRequest =
815                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
816         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
817                 maxStillSz, resultListener, imageListener, false /*isHeic*/);
818 
819         // make sure preview is actually running
820         waitForNumResults(resultListener, NUM_FRAMES_WAITED);
821 
822         // take a picture
823         CaptureRequest request = stillRequest.build();
824         mSession.capture(request, stillResultListener, mHandler);
825         stillResultListener.getCaptureResultForRequest(request,
826                 WAIT_FOR_RESULT_TIMEOUT_MS);
827 
828         // validate image
829         Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
830         validateJpegCapture(image, maxStillSz);
831 
832         // make sure preview is still running after still capture
833         waitForNumResults(resultListener, NUM_FRAMES_WAITED);
834 
835         stopPreview();
836 
837         // Free image resources
838         image.close();
839         closeImageReader();
840         return;
841     }
842 
843     /**
844      * Take a picture for a given set of 3A regions for a particular camera.
845      * <p>
846      * Before take a still capture, it triggers an auto focus and lock it first,
847      * then wait for AWB to converge and lock it, then trigger a precapture
848      * metering sequence and wait for AE converged. After capture is received, the
849      * capture result and image are validated.
850      * </p>
851      *
852      * @param aeRegions AE regions for this capture
853      * @param awbRegions AWB regions for this capture
854      * @param afRegions AF regions for this capture
855      */
takePictureTestByCamera( MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, MeteringRectangle[] afRegions)856     private void takePictureTestByCamera(
857             MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions,
858             MeteringRectangle[] afRegions) throws Exception {
859         takePictureTestByCamera(aeRegions, awbRegions, afRegions,
860                 /*addAeTriggerCancel*/false, /*allocateBitmap*/false,
861                 /*previewRequest*/null, /*stillRequest*/null);
862     }
863 
864     /**
865      * Take a picture for a given set of 3A regions for a particular camera.
866      * <p>
867      * Before take a still capture, it triggers an auto focus and lock it first,
868      * then wait for AWB to converge and lock it, then trigger a precapture
869      * metering sequence and wait for AE converged. After capture is received, the
870      * capture result and image are validated. If {@code addAeTriggerCancel} is true,
871      * a precapture trigger cancel will be inserted between two adjacent triggers, which
872      * should effective cancel the first trigger.
873      * </p>
874      *
875      * @param aeRegions AE regions for this capture
876      * @param awbRegions AWB regions for this capture
877      * @param afRegions AF regions for this capture
878      * @param addAeTriggerCancel If a AE precapture trigger cancel is sent after the trigger.
879      * @param allocateBitmap If a set of bitmaps are allocated during the test for memory test.
880      * @param previewRequest The preview request builder to use, or null to use the default
881      * @param stillRequest The still capture request to use, or null to use the default
882      */
takePictureTestByCamera( MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions, MeteringRectangle[] afRegions, boolean addAeTriggerCancel, boolean allocateBitmap, CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest)883     private void takePictureTestByCamera(
884             MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions,
885             MeteringRectangle[] afRegions, boolean addAeTriggerCancel, boolean allocateBitmap,
886             CaptureRequest.Builder previewRequest, CaptureRequest.Builder stillRequest)
887                     throws Exception {
888 
889         boolean hasFocuser = mStaticInfo.hasFocuser();
890 
891         Size maxStillSz = mOrderedStillSizes.get(0);
892         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
893         CaptureResult result;
894         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
895         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
896         if (previewRequest == null) {
897             previewRequest = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
898         }
899         if (stillRequest == null) {
900             stillRequest = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
901         }
902         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
903                 maxStillSz, resultListener, imageListener, false /*isHeic*/);
904 
905         // Set AE mode to ON_AUTO_FLASH if flash is available.
906         if (mStaticInfo.hasFlash()) {
907             previewRequest.set(CaptureRequest.CONTROL_AE_MODE,
908                     CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
909             stillRequest.set(CaptureRequest.CONTROL_AE_MODE,
910                     CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
911         }
912 
913         Camera2Focuser focuser = null;
914         /**
915          * Step 1: trigger an auto focus run, and wait for AF locked.
916          */
917         boolean canSetAfRegion = hasFocuser && (afRegions != null) &&
918                 isRegionsSupportedFor3A(MAX_REGIONS_AF_INDEX);
919         if (hasFocuser) {
920             SimpleAutoFocusListener afListener = new SimpleAutoFocusListener();
921             focuser = new Camera2Focuser(mCamera, mSession, mPreviewSurface, afListener,
922                     mStaticInfo.getCharacteristics(), mHandler);
923             if (canSetAfRegion) {
924                 previewRequest.set(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
925                 stillRequest.set(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
926             }
927             focuser.startAutoFocus(afRegions);
928             afListener.waitForAutoFocusDone(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS);
929         }
930 
931         /**
932          * Have to get the current AF mode to be used for other 3A repeating
933          * request, otherwise, the new AF mode in AE/AWB request could be
934          * different with existing repeating requests being sent by focuser,
935          * then it could make AF unlocked too early. Beside that, for still
936          * capture, AF mode must not be different with the one in current
937          * repeating request, otherwise, the still capture itself would trigger
938          * an AF mode change, and the AF lock would be lost for this capture.
939          */
940         int currentAfMode = CaptureRequest.CONTROL_AF_MODE_OFF;
941         if (hasFocuser) {
942             currentAfMode = focuser.getCurrentAfMode();
943         }
944         previewRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode);
945         stillRequest.set(CaptureRequest.CONTROL_AF_MODE, currentAfMode);
946 
947         /**
948          * Step 2: AF is already locked, wait for AWB converged, then lock it.
949          */
950         resultListener = new SimpleCaptureCallback();
951         boolean canSetAwbRegion =
952                 (awbRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AWB_INDEX);
953         if (canSetAwbRegion) {
954             previewRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
955             stillRequest.set(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
956         }
957         mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
958         if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
959             waitForResultValue(resultListener, CaptureResult.CONTROL_AWB_STATE,
960                     CaptureResult.CONTROL_AWB_STATE_CONVERGED, NUM_RESULTS_WAIT_TIMEOUT);
961         } else {
962             // LEGACY Devices don't have the AWB_STATE reported in results, so just wait
963             waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
964         }
965         boolean canSetAwbLock = mStaticInfo.isAwbLockSupported();
966         if (canSetAwbLock) {
967             previewRequest.set(CaptureRequest.CONTROL_AWB_LOCK, true);
968         }
969         mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
970         // Validate the next result immediately for region and mode.
971         result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
972         mCollector.expectEquals("AWB mode in result and request should be same",
973                 previewRequest.get(CaptureRequest.CONTROL_AWB_MODE),
974                 result.get(CaptureResult.CONTROL_AWB_MODE));
975         if (canSetAwbRegion) {
976             MeteringRectangle[] resultAwbRegions =
977                     getValueNotNull(result, CaptureResult.CONTROL_AWB_REGIONS);
978             mCollector.expectEquals("AWB regions in result and request should be same",
979                     awbRegions, resultAwbRegions);
980         }
981 
982         /**
983          * Step 3: trigger an AE precapture metering sequence and wait for AE converged.
984          */
985         resultListener = new SimpleCaptureCallback();
986         boolean canSetAeRegion =
987                 (aeRegions != null) && isRegionsSupportedFor3A(MAX_REGIONS_AE_INDEX);
988         if (canSetAeRegion) {
989             previewRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
990             stillRequest.set(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
991         }
992         mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
993         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
994                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
995         mSession.capture(previewRequest.build(), resultListener, mHandler);
996         if (addAeTriggerCancel) {
997             // Cancel the current precapture trigger, then send another trigger.
998             // The camera device should behave as if the first trigger is not sent.
999             // Wait one request to make the trigger start doing something before cancel.
1000             waitForNumResults(resultListener, /*numResultsWait*/ 1);
1001             previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
1002                     CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
1003             mSession.capture(previewRequest.build(), resultListener, mHandler);
1004             waitForResultValue(resultListener, CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER,
1005                     CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL,
1006                     NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
1007             // Issue another trigger
1008             previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
1009                     CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
1010             mSession.capture(previewRequest.build(), resultListener, mHandler);
1011         }
1012         waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
1013 
1014         // Validate the next result immediately for region and mode.
1015         result = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
1016         mCollector.expectEquals("AE mode in result and request should be same",
1017                 previewRequest.get(CaptureRequest.CONTROL_AE_MODE),
1018                 result.get(CaptureResult.CONTROL_AE_MODE));
1019         if (canSetAeRegion) {
1020             MeteringRectangle[] resultAeRegions =
1021                     getValueNotNull(result, CaptureResult.CONTROL_AE_REGIONS);
1022 
1023             mCollector.expectMeteringRegionsAreSimilar(
1024                     "AE regions in result and request should be similar",
1025                     aeRegions,
1026                     resultAeRegions,
1027                     METERING_REGION_ERROR_PERCENT_DELTA);
1028         }
1029 
1030         /**
1031          * Step 4: take a picture when all 3A are in good state.
1032          */
1033         resultListener = new SimpleCaptureCallback();
1034         CaptureRequest request = stillRequest.build();
1035         mSession.capture(request, resultListener, mHandler);
1036         // Validate the next result immediately for region and mode.
1037         result = resultListener.getCaptureResultForRequest(request, WAIT_FOR_RESULT_TIMEOUT_MS);
1038         mCollector.expectEquals("AF mode in result and request should be same",
1039                 stillRequest.get(CaptureRequest.CONTROL_AF_MODE),
1040                 result.get(CaptureResult.CONTROL_AF_MODE));
1041         if (canSetAfRegion) {
1042             MeteringRectangle[] resultAfRegions =
1043                     getValueNotNull(result, CaptureResult.CONTROL_AF_REGIONS);
1044             mCollector.expectMeteringRegionsAreSimilar(
1045                     "AF regions in result and request should be similar",
1046                     afRegions,
1047                     resultAfRegions,
1048                     METERING_REGION_ERROR_PERCENT_DELTA);
1049         }
1050 
1051         if (hasFocuser) {
1052             // Unlock auto focus.
1053             focuser.cancelAutoFocus();
1054         }
1055 
1056         // validate image
1057         Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
1058         validateJpegCapture(image, maxStillSz);
1059         // Test if the system can allocate 3 bitmap successfully, per android CDD camera memory
1060         // requirements added by CDD 5.0
1061         if (allocateBitmap) {
1062             Bitmap bm[] = new Bitmap[MAX_ALLOCATED_BITMAPS];
1063             for (int i = 0; i < MAX_ALLOCATED_BITMAPS; i++) {
1064                 bm[i] = Bitmap.createBitmap(
1065                         maxStillSz.getWidth(), maxStillSz.getHeight(), Config.ARGB_8888);
1066                 assertNotNull("Created bitmap #" + i + " shouldn't be null", bm[i]);
1067             }
1068         }
1069 
1070         // Free image resources
1071         image.close();
1072 
1073         stopPreview();
1074     }
1075 
1076     /**
1077      * Test touch region for focus by camera.
1078      */
touchForFocusTestByCamera()1079     private void touchForFocusTestByCamera() throws Exception {
1080         SimpleCaptureCallback listener = new SimpleCaptureCallback();
1081         CaptureRequest.Builder requestBuilder =
1082                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1083         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
1084         startPreview(requestBuilder, maxPreviewSz, listener);
1085 
1086         SimpleAutoFocusListener afListener = new SimpleAutoFocusListener();
1087         Camera2Focuser focuser = new Camera2Focuser(mCamera, mSession, mPreviewSurface, afListener,
1088                 mStaticInfo.getCharacteristics(), mHandler);
1089         ArrayList<MeteringRectangle[]> testAfRegions = get3ARegionTestCasesForCamera();
1090 
1091         for (MeteringRectangle[] afRegions : testAfRegions) {
1092             focuser.touchForAutoFocus(afRegions);
1093             afListener.waitForAutoFocusDone(WAIT_FOR_FOCUS_DONE_TIMEOUT_MS);
1094             focuser.cancelAutoFocus();
1095         }
1096     }
1097 
previewStillCombinationTestByCamera()1098     private void previewStillCombinationTestByCamera() throws Exception {
1099         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
1100         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
1101 
1102         Size QCIF = new Size(176, 144);
1103         Size FULL_HD = new Size(1920, 1080);
1104         for (Size stillSz : mOrderedStillSizes)
1105             for (Size previewSz : mOrderedPreviewSizes) {
1106                 if (VERBOSE) {
1107                     Log.v(TAG, "Testing JPEG capture size " + stillSz.toString()
1108                             + " with preview size " + previewSz.toString() + " for camera "
1109                             + mCamera.getId());
1110                 }
1111 
1112                 // Skip testing QCIF + >FullHD combinations
1113                 if (stillSz.equals(QCIF) &&
1114                         ((previewSz.getWidth() > FULL_HD.getWidth()) ||
1115                          (previewSz.getHeight() > FULL_HD.getHeight()))) {
1116                     continue;
1117                 }
1118 
1119                 if (previewSz.equals(QCIF) &&
1120                         ((stillSz.getWidth() > FULL_HD.getWidth()) ||
1121                          (stillSz.getHeight() > FULL_HD.getHeight()))) {
1122                     continue;
1123                 }
1124 
1125                 CaptureRequest.Builder previewRequest =
1126                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1127                 CaptureRequest.Builder stillRequest =
1128                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
1129                 prepareStillCaptureAndStartPreview(previewRequest, stillRequest, previewSz,
1130                         stillSz, resultListener, imageListener, false /*isHeic*/);
1131                 mSession.capture(stillRequest.build(), resultListener, mHandler);
1132                 Image image = imageListener.getImage((mStaticInfo.isHardwareLevelLegacy()) ?
1133                         RELAXED_CAPTURE_IMAGE_TIMEOUT_MS : CAPTURE_IMAGE_TIMEOUT_MS);
1134                 validateJpegCapture(image, stillSz);
1135 
1136                 // Free image resources
1137                 image.close();
1138 
1139                 // stopPreview must be called here to make sure next time a preview stream
1140                 // is created with new size.
1141                 stopPreview();
1142                 // Drain the results after each combination. Depending on the device the results
1143                 // can be relatively big and could accumulate fairly quickly after many iterations.
1144                 resultListener.drain();
1145             }
1146     }
1147 
1148     /**
1149      * Basic raw capture test for each camera.
1150      */
rawCaptureTestByCamera(CaptureRequest.Builder stillRequest)1151     private void rawCaptureTestByCamera(CaptureRequest.Builder stillRequest) throws Exception {
1152         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
1153         Size size = mStaticInfo.getRawDimensChecked();
1154 
1155         // Prepare raw capture and start preview.
1156         CaptureRequest.Builder previewBuilder =
1157                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1158         CaptureRequest.Builder rawBuilder = (stillRequest != null) ? stillRequest :
1159                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
1160         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
1161         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
1162         prepareRawCaptureAndStartPreview(previewBuilder, rawBuilder, maxPreviewSz, size,
1163                 resultListener, imageListener);
1164 
1165         if (VERBOSE) {
1166             Log.v(TAG, "Testing Raw capture with size " + size.toString()
1167                     + ", preview size " + maxPreviewSz);
1168         }
1169 
1170         CaptureRequest rawRequest = rawBuilder.build();
1171         mSession.capture(rawRequest, resultListener, mHandler);
1172 
1173         Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
1174         validateRaw16Image(image, size);
1175         if (DEBUG) {
1176             byte[] rawBuffer = getDataFromImage(image);
1177             String rawFileName = mDebugFileNameBase + "/test" + "_" + size.toString() + "_cam" +
1178                     mCamera.getId() + ".raw16";
1179             Log.d(TAG, "Dump raw file into " + rawFileName);
1180             dumpFile(rawFileName, rawBuffer);
1181         }
1182 
1183         // Free image resources
1184         image.close();
1185 
1186         stopPreview();
1187     }
1188 
fullRawCaptureTestByCamera(CaptureRequest.Builder stillRequest)1189     private void fullRawCaptureTestByCamera(CaptureRequest.Builder stillRequest) throws Exception {
1190         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
1191         Size maxStillSz = mOrderedStillSizes.get(0);
1192 
1193         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
1194         SimpleImageReaderListener jpegListener = new SimpleImageReaderListener();
1195         SimpleImageReaderListener rawListener = new SimpleImageReaderListener();
1196 
1197         Size size = mStaticInfo.getRawDimensChecked();
1198 
1199         if (VERBOSE) {
1200             Log.v(TAG, "Testing multi capture with size " + size.toString()
1201                     + ", preview size " + maxPreviewSz);
1202         }
1203 
1204         // Prepare raw capture and start preview.
1205         CaptureRequest.Builder previewBuilder =
1206                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1207         CaptureRequest.Builder multiBuilder = (stillRequest != null) ? stillRequest :
1208                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
1209 
1210         ImageReader rawReader = null;
1211         ImageReader jpegReader = null;
1212 
1213         try {
1214             // Create ImageReaders.
1215             rawReader = makeImageReader(size,
1216                     ImageFormat.RAW_SENSOR, MAX_READER_IMAGES, rawListener, mHandler);
1217             jpegReader = makeImageReader(maxStillSz,
1218                     ImageFormat.JPEG, MAX_READER_IMAGES, jpegListener, mHandler);
1219             updatePreviewSurface(maxPreviewSz);
1220 
1221             // Configure output streams with preview and jpeg streams.
1222             List<Surface> outputSurfaces = new ArrayList<Surface>();
1223             outputSurfaces.add(rawReader.getSurface());
1224             outputSurfaces.add(jpegReader.getSurface());
1225             outputSurfaces.add(mPreviewSurface);
1226             mSessionListener = new BlockingSessionCallback();
1227             mSession = configureCameraSession(mCamera, outputSurfaces,
1228                     mSessionListener, mHandler);
1229 
1230             // Configure the requests.
1231             previewBuilder.addTarget(mPreviewSurface);
1232             multiBuilder.addTarget(mPreviewSurface);
1233             multiBuilder.addTarget(rawReader.getSurface());
1234             multiBuilder.addTarget(jpegReader.getSurface());
1235 
1236             // Start preview.
1237             mSession.setRepeatingRequest(previewBuilder.build(), null, mHandler);
1238 
1239             // Poor man's 3A, wait 2 seconds for AE/AF (if any) to settle.
1240             // TODO: Do proper 3A trigger and lock (see testTakePictureTest).
1241             Thread.sleep(3000);
1242 
1243             multiBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE,
1244                     CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE_ON);
1245             CaptureRequest multiRequest = multiBuilder.build();
1246 
1247             mSession.capture(multiRequest, resultListener, mHandler);
1248 
1249             CaptureResult result = resultListener.getCaptureResultForRequest(multiRequest,
1250                     NUM_RESULTS_WAIT_TIMEOUT);
1251             Image jpegImage = jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
1252             basicValidateBlobImage(jpegImage, maxStillSz, ImageFormat.JPEG);
1253             Image rawImage = rawListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
1254             validateRaw16Image(rawImage, size);
1255             verifyRawCaptureResult(multiRequest, result);
1256 
1257 
1258             ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
1259             try (DngCreator dngCreator = new DngCreator(mStaticInfo.getCharacteristics(), result)) {
1260                 dngCreator.writeImage(outputStream, rawImage);
1261             }
1262 
1263             if (DEBUG) {
1264                 byte[] rawBuffer = outputStream.toByteArray();
1265                 String rawFileName = mDebugFileNameBase + "/raw16_" + TAG + size.toString() +
1266                         "_cam_" + mCamera.getId() + ".dng";
1267                 Log.d(TAG, "Dump raw file into " + rawFileName);
1268                 dumpFile(rawFileName, rawBuffer);
1269 
1270                 byte[] jpegBuffer = getDataFromImage(jpegImage);
1271                 String jpegFileName = mDebugFileNameBase + "/jpeg_" + TAG + size.toString() +
1272                         "_cam_" + mCamera.getId() + ".jpg";
1273                 Log.d(TAG, "Dump jpeg file into " + rawFileName);
1274                 dumpFile(jpegFileName, jpegBuffer);
1275             }
1276 
1277             stopPreview();
1278         } finally {
1279             CameraTestUtils.closeImageReader(rawReader);
1280             CameraTestUtils.closeImageReader(jpegReader);
1281             rawReader = null;
1282             jpegReader = null;
1283         }
1284     }
1285 
1286     /**
1287      * Validate that raw {@link CaptureResult}.
1288      *
1289      * @param rawRequest a {@link CaptureRequest} use to capture a RAW16 image.
1290      * @param rawResult the {@link CaptureResult} corresponding to the given request.
1291      */
verifyRawCaptureResult(CaptureRequest rawRequest, CaptureResult rawResult)1292     private void verifyRawCaptureResult(CaptureRequest rawRequest, CaptureResult rawResult) {
1293         assertNotNull(rawRequest);
1294         assertNotNull(rawResult);
1295 
1296         if (!mStaticInfo.isMonochromeCamera()) {
1297             Rational[] empty = new Rational[] { Rational.ZERO, Rational.ZERO, Rational.ZERO};
1298             Rational[] neutralColorPoint = mCollector.expectKeyValueNotNull("NeutralColorPoint",
1299                     rawResult, CaptureResult.SENSOR_NEUTRAL_COLOR_POINT);
1300             if (neutralColorPoint != null) {
1301                 mCollector.expectEquals("NeutralColorPoint length", empty.length,
1302                         neutralColorPoint.length);
1303                 mCollector.expectNotEquals("NeutralColorPoint cannot be all zeroes, ", empty,
1304                         neutralColorPoint);
1305                 mCollector.expectValuesGreaterOrEqual("NeutralColorPoint", neutralColorPoint,
1306                         Rational.ZERO);
1307             }
1308 
1309             mCollector.expectKeyValueGreaterOrEqual(rawResult,
1310                     CaptureResult.SENSOR_GREEN_SPLIT, 0.0f);
1311         }
1312 
1313         Pair<Double, Double>[] noiseProfile = mCollector.expectKeyValueNotNull("NoiseProfile",
1314                 rawResult, CaptureResult.SENSOR_NOISE_PROFILE);
1315         if (noiseProfile != null) {
1316             int cfa = mStaticInfo.getCFAChecked();
1317             int numCfaChannels = 0;
1318             switch (cfa) {
1319                 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB:
1320                 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG:
1321                 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG:
1322                 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR:
1323                     numCfaChannels = 4;
1324                     break;
1325                 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO:
1326                 case CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR:
1327                     numCfaChannels = 1;
1328                     break;
1329                 default:
1330                     Assert.fail("Invalid color filter arrangement " + cfa);
1331                     break;
1332             }
1333             mCollector.expectEquals("NoiseProfile length", noiseProfile.length, numCfaChannels);
1334             for (Pair<Double, Double> p : noiseProfile) {
1335                 mCollector.expectTrue("NoiseProfile coefficients " + p +
1336                         " must have: S > 0, O >= 0", p.first > 0 && p.second >= 0);
1337             }
1338         }
1339 
1340         Integer hotPixelMode = mCollector.expectKeyValueNotNull("HotPixelMode", rawResult,
1341                 CaptureResult.HOT_PIXEL_MODE);
1342         Boolean hotPixelMapMode = mCollector.expectKeyValueNotNull("HotPixelMapMode", rawResult,
1343                 CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE);
1344         Point[] hotPixelMap = rawResult.get(CaptureResult.STATISTICS_HOT_PIXEL_MAP);
1345 
1346         Size pixelArraySize = mStaticInfo.getPixelArraySizeChecked();
1347         boolean[] availableHotPixelMapModes = mStaticInfo.getValueFromKeyNonNull(
1348                         CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES);
1349 
1350         if (hotPixelMode != null) {
1351             Integer requestMode = mCollector.expectKeyValueNotNull(rawRequest,
1352                     CaptureRequest.HOT_PIXEL_MODE);
1353             if (requestMode != null) {
1354                 mCollector.expectKeyValueEquals(rawResult, CaptureResult.HOT_PIXEL_MODE,
1355                         requestMode);
1356             }
1357         }
1358 
1359         if (hotPixelMapMode != null) {
1360             Boolean requestMapMode = mCollector.expectKeyValueNotNull(rawRequest,
1361                     CaptureRequest.STATISTICS_HOT_PIXEL_MAP_MODE);
1362             if (requestMapMode != null) {
1363                 mCollector.expectKeyValueEquals(rawResult,
1364                         CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE, requestMapMode);
1365             }
1366 
1367             if (!hotPixelMapMode) {
1368                 mCollector.expectTrue("HotPixelMap must be empty", hotPixelMap == null ||
1369                         hotPixelMap.length == 0);
1370             } else {
1371                 mCollector.expectTrue("HotPixelMap must not be empty", hotPixelMap != null);
1372                 mCollector.expectNotNull("AvailableHotPixelMapModes must not be null",
1373                         availableHotPixelMapModes);
1374                 if (availableHotPixelMapModes != null) {
1375                     mCollector.expectContains("HotPixelMapMode", availableHotPixelMapModes, true);
1376                 }
1377 
1378                 int height = pixelArraySize.getHeight();
1379                 int width = pixelArraySize.getWidth();
1380                 for (Point p : hotPixelMap) {
1381                     mCollector.expectTrue("Hotpixel " + p + " must be in pixelArray " +
1382                             pixelArraySize, p.x >= 0 && p.x < width && p.y >= 0 && p.y < height);
1383                 }
1384             }
1385         }
1386         // TODO: profileHueSatMap, and profileToneCurve aren't supported yet.
1387 
1388     }
1389 
1390     /**
1391      * Issue a still capture and validate the exif information.
1392      * <p>
1393      * TODO: Differentiate full and limited device, some of the checks rely on
1394      * per frame control and synchronization, most of them don't.
1395      * </p>
1396      */
stillExifTestByCamera(int format, Size stillSize)1397     private void stillExifTestByCamera(int format, Size stillSize) throws Exception {
1398         assertTrue(format == ImageFormat.JPEG || format == ImageFormat.HEIC);
1399         boolean isHeic = (format == ImageFormat.HEIC);
1400 
1401         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
1402         if (VERBOSE) {
1403             Log.v(TAG, "Testing exif with size " + stillSize.toString()
1404                     + ", preview size " + maxPreviewSz);
1405         }
1406 
1407         // prepare capture and start preview.
1408         CaptureRequest.Builder previewBuilder =
1409                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1410         CaptureRequest.Builder stillBuilder =
1411                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
1412         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
1413         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
1414         prepareStillCaptureAndStartPreview(previewBuilder, stillBuilder, maxPreviewSz, stillSize,
1415                 resultListener, imageListener, isHeic);
1416 
1417         // Set the jpeg keys, then issue a capture
1418         Size[] thumbnailSizes = mStaticInfo.getAvailableThumbnailSizesChecked();
1419         Size maxThumbnailSize = thumbnailSizes[thumbnailSizes.length - 1];
1420         Size[] testThumbnailSizes = new Size[EXIF_TEST_DATA.length];
1421         Arrays.fill(testThumbnailSizes, maxThumbnailSize);
1422         // Make sure thumbnail size (0, 0) is covered.
1423         testThumbnailSizes[0] = new Size(0, 0);
1424 
1425         for (int i = 0; i < EXIF_TEST_DATA.length; i++) {
1426             setJpegKeys(stillBuilder, EXIF_TEST_DATA[i], testThumbnailSizes[i], mCollector);
1427 
1428             // Capture a jpeg/heic image.
1429             CaptureRequest request = stillBuilder.build();
1430             mSession.capture(request, resultListener, mHandler);
1431             CaptureResult stillResult =
1432                     resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT);
1433             Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
1434 
1435             verifyJpegKeys(image, stillResult, stillSize, testThumbnailSizes[i], EXIF_TEST_DATA[i],
1436                     mStaticInfo, mAllStaticInfo, mCollector, mDebugFileNameBase, format);
1437 
1438             // Free image resources
1439             image.close();
1440         }
1441 
1442         // Check that after clearing JPEG_GPS_LOCATION with null,
1443         // the value reflects the null value.
1444         stillBuilder.set(CaptureRequest.JPEG_GPS_LOCATION, null);
1445         Assert.assertNull("JPEG_GPS_LOCATION value should be null if set to null",
1446                 stillBuilder.get(CaptureRequest.JPEG_GPS_LOCATION));
1447     }
1448 
1449     /**
1450      * Issue a still capture and validate the dynamic depth output.
1451      */
stillDynamicDepthTestByCamera(int format, Size stillSize)1452     private void stillDynamicDepthTestByCamera(int format, Size stillSize) throws Exception {
1453         assertTrue(format == ImageFormat.DEPTH_JPEG);
1454 
1455         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
1456         if (VERBOSE) {
1457             Log.v(TAG, "Testing dynamic depth with size " + stillSize.toString()
1458                     + ", preview size " + maxPreviewSz);
1459         }
1460 
1461         // prepare capture and start preview.
1462         CaptureRequest.Builder previewBuilder =
1463                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1464         CaptureRequest.Builder stillBuilder =
1465                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
1466         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
1467         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
1468         prepareCaptureAndStartPreview(previewBuilder, stillBuilder, maxPreviewSz, stillSize,
1469                 ImageFormat.DEPTH_JPEG, resultListener, /*sessionListener*/null,
1470                 MAX_READER_IMAGES, imageListener);
1471 
1472         // Capture a few dynamic depth images and check whether they are valid jpegs.
1473         for (int i = 0; i < MAX_READER_IMAGES; i++) {
1474             CaptureRequest request = stillBuilder.build();
1475             mSession.capture(request, resultListener, mHandler);
1476             CaptureResult stillResult =
1477                 resultListener.getCaptureResultForRequest(request, NUM_RESULTS_WAIT_TIMEOUT);
1478             Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
1479             assertNotNull("Unable to acquire next image", image);
1480             CameraTestUtils.validateImage(image, stillSize.getWidth(), stillSize.getHeight(),
1481                     format, null /*filePath*/);
1482 
1483             // Free image resources
1484             image.close();
1485         }
1486     }
1487 
aeCompensationTestByCamera()1488     private void aeCompensationTestByCamera() throws Exception {
1489         Range<Integer> compensationRange = mStaticInfo.getAeCompensationRangeChecked();
1490         // Skip the test if exposure compensation is not supported.
1491         if (compensationRange.equals(Range.create(0, 0))) {
1492             return;
1493         }
1494 
1495         Rational step = mStaticInfo.getAeCompensationStepChecked();
1496         float stepF = (float) step.getNumerator() / step.getDenominator();
1497         int stepsPerEv = (int) Math.round(1.0 / stepF);
1498         int numSteps = (compensationRange.getUpper() - compensationRange.getLower()) / stepsPerEv;
1499 
1500         Size maxStillSz = mOrderedStillSizes.get(0);
1501         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
1502         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
1503         SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
1504         CaptureRequest.Builder previewRequest =
1505                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
1506         CaptureRequest.Builder stillRequest =
1507                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
1508         boolean canSetAeLock = mStaticInfo.isAeLockSupported();
1509         boolean canReadSensorSettings = mStaticInfo.isCapabilitySupported(
1510                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS);
1511 
1512         if (canSetAeLock) {
1513             stillRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
1514         }
1515 
1516         CaptureResult normalResult;
1517         CaptureResult compensatedResult;
1518 
1519         boolean canReadExposureValueRange = mStaticInfo.areKeysAvailable(
1520                 CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
1521                 CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
1522         boolean canVerifyExposureValue = canReadSensorSettings && canReadExposureValueRange;
1523         long minExposureValue = -1;
1524         long maxExposureValuePreview = -1;
1525         long maxExposureValueStill = -1;
1526         if (canReadExposureValueRange) {
1527             // Minimum exposure settings is mostly static while maximum exposure setting depends on
1528             // frame rate range which in term depends on capture request.
1529             minExposureValue = mStaticInfo.getSensitivityMinimumOrDefault() *
1530                     mStaticInfo.getExposureMinimumOrDefault() / 1000;
1531             long maxSensitivity = mStaticInfo.getSensitivityMaximumOrDefault();
1532             long maxExposureTimeUs = mStaticInfo.getExposureMaximumOrDefault() / 1000;
1533             maxExposureValuePreview = getMaxExposureValue(previewRequest, maxExposureTimeUs,
1534                     maxSensitivity);
1535             maxExposureValueStill = getMaxExposureValue(stillRequest, maxExposureTimeUs,
1536                     maxSensitivity);
1537         }
1538 
1539         // Set the max number of images to be same as the burst count, as the verification
1540         // could be much slower than producing rate, and we don't want to starve producer.
1541         prepareStillCaptureAndStartPreview(previewRequest, stillRequest, maxPreviewSz,
1542                 maxStillSz, resultListener, numSteps, imageListener, false /*isHeic*/);
1543 
1544         for (int i = 0; i <= numSteps; i++) {
1545             int exposureCompensation = i * stepsPerEv + compensationRange.getLower();
1546             double expectedRatio = Math.pow(2.0, exposureCompensation / stepsPerEv);
1547 
1548             // Wait for AE to be stabilized before capture: CONVERGED or FLASH_REQUIRED.
1549             waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
1550             normalResult = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
1551 
1552             long normalExposureValue = -1;
1553             if (canVerifyExposureValue) {
1554                 // get and check if current exposure value is valid
1555                 normalExposureValue = getExposureValue(normalResult);
1556                 mCollector.expectInRange("Exposure setting out of bound", normalExposureValue,
1557                         minExposureValue, maxExposureValuePreview);
1558 
1559                 // Only run the test if expectedExposureValue is within valid range
1560                 long expectedExposureValue = (long) (normalExposureValue * expectedRatio);
1561                 if (expectedExposureValue < minExposureValue ||
1562                     expectedExposureValue > maxExposureValueStill) {
1563                     continue;
1564                 }
1565                 Log.v(TAG, "Expect ratio: " + expectedRatio +
1566                         " normalExposureValue: " + normalExposureValue +
1567                         " expectedExposureValue: " + expectedExposureValue +
1568                         " minExposureValue: " + minExposureValue +
1569                         " maxExposureValuePreview: " + maxExposureValuePreview +
1570                         " maxExposureValueStill: " + maxExposureValueStill);
1571             }
1572 
1573             // Now issue exposure compensation and wait for AE locked. AE could take a few
1574             // frames to go back to locked state
1575             previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,
1576                     exposureCompensation);
1577             if (canSetAeLock) {
1578                 previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
1579             }
1580             mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
1581             if (canSetAeLock) {
1582                 waitForAeLocked(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
1583             } else {
1584                 waitForSettingsApplied(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
1585             }
1586 
1587             // Issue still capture
1588             if (VERBOSE) {
1589                 Log.v(TAG, "Verifying capture result for ae compensation value "
1590                         + exposureCompensation);
1591             }
1592 
1593             stillRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, exposureCompensation);
1594             CaptureRequest request = stillRequest.build();
1595             mSession.capture(request, resultListener, mHandler);
1596 
1597             compensatedResult = resultListener.getCaptureResultForRequest(
1598                     request, WAIT_FOR_RESULT_TIMEOUT_MS);
1599 
1600             if (canVerifyExposureValue) {
1601                 // Verify the exposure value compensates as requested
1602                 long compensatedExposureValue = getExposureValue(compensatedResult);
1603                 mCollector.expectInRange("Exposure setting out of bound", compensatedExposureValue,
1604                         minExposureValue, maxExposureValueStill);
1605                 double observedRatio = (double) compensatedExposureValue / normalExposureValue;
1606                 double error = observedRatio / expectedRatio;
1607                 String errorString = String.format(
1608                         "Exposure compensation ratio exceeds error tolerence:" +
1609                         " expected(%f) observed(%f)." +
1610                         " Normal exposure time %d us, sensitivity %d." +
1611                         " Compensated exposure time %d us, sensitivity %d",
1612                         expectedRatio, observedRatio,
1613                         (int) (getValueNotNull(
1614                                 normalResult, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000),
1615                         getValueNotNull(normalResult, CaptureResult.SENSOR_SENSITIVITY),
1616                         (int) (getValueNotNull(
1617                                 compensatedResult, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000),
1618                         getValueNotNull(compensatedResult, CaptureResult.SENSOR_SENSITIVITY));
1619                 mCollector.expectInRange(errorString, error,
1620                         1.0 - AE_COMPENSATION_ERROR_TOLERANCE,
1621                         1.0 + AE_COMPENSATION_ERROR_TOLERANCE);
1622             }
1623 
1624             mCollector.expectEquals("Exposure compensation result should match requested value.",
1625                     exposureCompensation,
1626                     compensatedResult.get(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION));
1627             if (canSetAeLock) {
1628                 mCollector.expectTrue("Exposure lock should be set",
1629                         compensatedResult.get(CaptureResult.CONTROL_AE_LOCK));
1630             }
1631 
1632             Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
1633             validateJpegCapture(image, maxStillSz);
1634             image.close();
1635 
1636             // Recover AE compensation and lock
1637             previewRequest.set(CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION, 0);
1638             if (canSetAeLock) {
1639                 previewRequest.set(CaptureRequest.CONTROL_AE_LOCK, false);
1640             }
1641             mSession.setRepeatingRequest(previewRequest.build(), resultListener, mHandler);
1642         }
1643     }
1644 
getExposureValue(CaptureResult result)1645     private long getExposureValue(CaptureResult result) throws Exception {
1646         int expTimeUs = (int) (getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000);
1647         int sensitivity = getValueNotNull(result, CaptureResult.SENSOR_SENSITIVITY);
1648         Integer postRawSensitivity = result.get(CaptureResult.CONTROL_POST_RAW_SENSITIVITY_BOOST);
1649         if (postRawSensitivity != null) {
1650             return (long) sensitivity * postRawSensitivity / 100 * expTimeUs;
1651         }
1652         return (long) sensitivity * expTimeUs;
1653     }
1654 
getMaxExposureValue(CaptureRequest.Builder request, long maxExposureTimeUs, long maxSensitivity)1655     private long getMaxExposureValue(CaptureRequest.Builder request, long maxExposureTimeUs,
1656                 long maxSensitivity)  throws Exception {
1657         Range<Integer> fpsRange = request.get(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE);
1658         long maxFrameDurationUs = Math.round(1000000.0 / fpsRange.getLower());
1659         long currentMaxExposureTimeUs = Math.min(maxFrameDurationUs, maxExposureTimeUs);
1660         return currentMaxExposureTimeUs * maxSensitivity;
1661     }
1662 
1663 
1664     //----------------------------------------------------------------
1665     //---------Below are common functions for all tests.--------------
1666     //----------------------------------------------------------------
1667     /**
1668      * Validate standard raw (RAW16) capture image.
1669      *
1670      * @param image The raw16 format image captured
1671      * @param rawSize The expected raw size
1672      */
validateRaw16Image(Image image, Size rawSize)1673     private static void validateRaw16Image(Image image, Size rawSize) {
1674         CameraTestUtils.validateImage(image, rawSize.getWidth(), rawSize.getHeight(),
1675                 ImageFormat.RAW_SENSOR, /*filePath*/null);
1676     }
1677 
1678     /**
1679      * Validate JPEG capture image object correctness and test.
1680      * <p>
1681      * In addition to image object correctness, this function also does the decoding
1682      * test, which is slower.
1683      * </p>
1684      *
1685      * @param image The JPEG image to be verified.
1686      * @param jpegSize The JPEG capture size to be verified against.
1687      */
validateJpegCapture(Image image, Size jpegSize)1688     private static void validateJpegCapture(Image image, Size jpegSize) {
1689         CameraTestUtils.validateImage(image, jpegSize.getWidth(), jpegSize.getHeight(),
1690                 ImageFormat.JPEG, /*filePath*/null);
1691     }
1692 
1693     private static class SimpleAutoFocusListener implements Camera2Focuser.AutoFocusListener {
1694         final ConditionVariable focusDone = new ConditionVariable();
1695         @Override
onAutoFocusLocked(boolean success)1696         public void onAutoFocusLocked(boolean success) {
1697             focusDone.open();
1698         }
1699 
waitForAutoFocusDone(long timeoutMs)1700         public void waitForAutoFocusDone(long timeoutMs) {
1701             if (focusDone.block(timeoutMs)) {
1702                 focusDone.close();
1703             } else {
1704                 throw new TimeoutRuntimeException("Wait for auto focus done timed out after "
1705                         + timeoutMs + "ms");
1706             }
1707         }
1708     }
1709 
1710     /**
1711      * Get 5 3A region test cases, each with one square region in it.
1712      * The first one is at center, the other four are at corners of
1713      * active array rectangle.
1714      *
1715      * @return array of test 3A regions
1716      */
get3ARegionTestCasesForCamera()1717     private ArrayList<MeteringRectangle[]> get3ARegionTestCasesForCamera() {
1718         final int TEST_3A_REGION_NUM = 5;
1719         final int DEFAULT_REGION_WEIGHT = 30;
1720         final int DEFAULT_REGION_SCALE_RATIO = 8;
1721         ArrayList<MeteringRectangle[]> testCases =
1722                 new ArrayList<MeteringRectangle[]>(TEST_3A_REGION_NUM);
1723         final Rect activeArraySize = mStaticInfo.getActiveArraySizeChecked();
1724         int regionWidth = activeArraySize.width() / DEFAULT_REGION_SCALE_RATIO - 1;
1725         int regionHeight = activeArraySize.height() / DEFAULT_REGION_SCALE_RATIO - 1;
1726         int centerX = activeArraySize.width() / 2;
1727         int centerY = activeArraySize.height() / 2;
1728         int bottomRightX = activeArraySize.width() - 1;
1729         int bottomRightY = activeArraySize.height() - 1;
1730 
1731         // Center region
1732         testCases.add(
1733                 new MeteringRectangle[] {
1734                     new MeteringRectangle(
1735                             centerX - regionWidth / 2,  // x
1736                             centerY - regionHeight / 2, // y
1737                             regionWidth,                // width
1738                             regionHeight,               // height
1739                             DEFAULT_REGION_WEIGHT)});
1740 
1741         // Upper left corner
1742         testCases.add(
1743                 new MeteringRectangle[] {
1744                     new MeteringRectangle(
1745                             0,                // x
1746                             0,                // y
1747                             regionWidth,      // width
1748                             regionHeight,     // height
1749                             DEFAULT_REGION_WEIGHT)});
1750 
1751         // Upper right corner
1752         testCases.add(
1753                 new MeteringRectangle[] {
1754                     new MeteringRectangle(
1755                             bottomRightX - regionWidth, // x
1756                             0,                          // y
1757                             regionWidth,                // width
1758                             regionHeight,               // height
1759                             DEFAULT_REGION_WEIGHT)});
1760 
1761         // Bottom left corner
1762         testCases.add(
1763                 new MeteringRectangle[] {
1764                     new MeteringRectangle(
1765                             0,                           // x
1766                             bottomRightY - regionHeight, // y
1767                             regionWidth,                 // width
1768                             regionHeight,                // height
1769                             DEFAULT_REGION_WEIGHT)});
1770 
1771         // Bottom right corner
1772         testCases.add(
1773                 new MeteringRectangle[] {
1774                     new MeteringRectangle(
1775                             bottomRightX - regionWidth,  // x
1776                             bottomRightY - regionHeight, // y
1777                             regionWidth,                 // width
1778                             regionHeight,                // height
1779                             DEFAULT_REGION_WEIGHT)});
1780 
1781         if (VERBOSE) {
1782             StringBuilder sb = new StringBuilder();
1783             for (MeteringRectangle[] mr : testCases) {
1784                 sb.append("{");
1785                 sb.append(Arrays.toString(mr));
1786                 sb.append("}, ");
1787             }
1788             if (sb.length() > 1)
1789                 sb.setLength(sb.length() - 2); // Remove the redundant comma and space at the end
1790             Log.v(TAG, "Generated test regions are: " + sb.toString());
1791         }
1792 
1793         return testCases;
1794     }
1795 
isRegionsSupportedFor3A(int index)1796     private boolean isRegionsSupportedFor3A(int index) {
1797         int maxRegions = 0;
1798         switch (index) {
1799             case MAX_REGIONS_AE_INDEX:
1800                 maxRegions = mStaticInfo.getAeMaxRegionsChecked();
1801                 break;
1802             case MAX_REGIONS_AWB_INDEX:
1803                 maxRegions = mStaticInfo.getAwbMaxRegionsChecked();
1804                 break;
1805             case  MAX_REGIONS_AF_INDEX:
1806                 maxRegions = mStaticInfo.getAfMaxRegionsChecked();
1807                 break;
1808             default:
1809                 throw new IllegalArgumentException("Unknown algorithm index");
1810         }
1811         boolean isRegionsSupported = maxRegions > 0;
1812         if (index == MAX_REGIONS_AF_INDEX && isRegionsSupported) {
1813             mCollector.expectTrue(
1814                     "Device reports non-zero max AF region count for a camera without focuser!",
1815                     mStaticInfo.hasFocuser());
1816             isRegionsSupported = isRegionsSupported && mStaticInfo.hasFocuser();
1817         }
1818 
1819         return isRegionsSupported;
1820     }
1821 }
1822