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