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