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