• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 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 android.content.Context;
20 import android.graphics.ImageFormat;
21 import android.hardware.camera2.CameraCaptureSession;
22 import android.hardware.camera2.CameraCharacteristics;
23 import android.hardware.camera2.CameraDevice;
24 import android.hardware.camera2.CaptureRequest;
25 import android.hardware.camera2.CaptureResult;
26 import android.hardware.camera2.TotalCaptureResult;
27 import android.media.Image;
28 import android.media.ImageReader;
29 import android.os.SystemClock;
30 import android.util.Pair;
31 import android.util.Size;
32 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
33 
34 import static android.hardware.camera2.cts.CameraTestUtils.*;
35 import static android.hardware.camera2.cts.helpers.CameraSessionUtils.*;
36 
37 import android.util.Log;
38 import android.view.Surface;
39 
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.List;
45 import java.util.Set;
46 import java.util.concurrent.LinkedBlockingQueue;
47 import java.util.concurrent.TimeUnit;
48 
49 public class CaptureResultTest extends Camera2AndroidTestCase {
50     private static final String TAG = "CaptureResultTest";
51     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
52     private static final int MAX_NUM_IMAGES = MAX_READER_IMAGES;
53     private static final int NUM_FRAMES_VERIFIED = 30;
54     private static final long WAIT_FOR_RESULT_TIMEOUT_MS = 3000;
55 
56     // List that includes all public keys from CaptureResult
57     List<CaptureResult.Key<?>> mAllKeys;
58 
59     // List tracking the failed test keys.
60 
61     @Override
setContext(Context context)62     public void setContext(Context context) {
63         mAllKeys = getAllCaptureResultKeys();
64         super.setContext(context);
65 
66         /**
67          * Workaround for mockito and JB-MR2 incompatibility
68          *
69          * Avoid java.lang.IllegalArgumentException: dexcache == null
70          * https://code.google.com/p/dexmaker/issues/detail?id=2
71          */
72         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
73     }
74 
75     @Override
setUp()76     protected void setUp() throws Exception {
77         super.setUp();
78     }
79 
80     @Override
tearDown()81     protected void tearDown() throws Exception {
82         super.tearDown();
83     }
84 
85     /**
86      * <p>
87      * Basic non-null check test for multiple capture results.
88      * </p>
89      * <p>
90      * When capturing many frames, some camera devices may return some results that have null keys
91      * randomly, which is an API violation and could cause application crash randomly. This test
92      * runs a typical flexible yuv capture many times, and checks if there is any null entries in
93      * a capture result.
94      * </p>
95      */
testCameraCaptureResultAllKeys()96     public void testCameraCaptureResultAllKeys() throws Exception {
97         for (String id : mCameraIds) {
98             try {
99                 openDevice(id);
100                 // Create image reader and surface.
101                 Size size = mOrderedPreviewSizes.get(0);
102                 createDefaultImageReader(size, ImageFormat.YUV_420_888, MAX_NUM_IMAGES,
103                         new ImageDropperListener());
104 
105                 // Configure output streams.
106                 List<Surface> outputSurfaces = new ArrayList<Surface>(1);
107                 outputSurfaces.add(mReaderSurface);
108                 createSession(outputSurfaces);
109 
110                 CaptureRequest.Builder requestBuilder =
111                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
112                 assertNotNull("Failed to create capture request", requestBuilder);
113                 requestBuilder.addTarget(mReaderSurface);
114 
115                 // Start capture
116                 SimpleCaptureCallback captureListener = new SimpleCaptureCallback();
117                 startCapture(requestBuilder.build(), /*repeating*/true, captureListener, mHandler);
118 
119                 // Get the waived keys for current camera device
120                 List<CaptureResult.Key<?>> waiverkeys = getWaiverKeysForCamera();
121 
122                 // Verify results
123                 validateCaptureResult(captureListener, waiverkeys, requestBuilder,
124                         NUM_FRAMES_VERIFIED);
125 
126                 stopCapture(/*fast*/false);
127             } finally {
128                 closeDevice(id);
129                 closeDefaultImageReader();
130             }
131         }
132     }
133 
134     /**
135      * Check partial results conform to its specification.
136      * <p>
137      * The test is skipped if partial result is not supported on device. </p>
138      * <p>Test summary:<ul>
139      * <li>1. Number of partial results is less than or equal to
140      * {@link CameraCharacteristics#REQUEST_PARTIAL_RESULT_COUNT}.
141      * <li>2. Each key appeared in partial results must be unique across all partial results.
142      * <li>3. All keys appeared in partial results must be present in TotalCaptureResult
143      * <li>4. Also test onCaptureComplete callback always happen after onCaptureStart or
144      * onCaptureProgressed callbacks.
145      * </ul></p>
146      */
testPartialResult()147     public void testPartialResult() throws Exception {
148         final int NUM_FRAMES_TESTED = 30;
149         final int WAIT_FOR_RESULT_TIMOUT_MS = 2000;
150         for (String id : mCameraIds) {
151             try {
152                 openDevice(id);
153 
154                 // Skip the test if partial result is not supported
155                 int partialResultCount = mStaticInfo.getPartialResultCount();
156                 if (partialResultCount == 1) {
157                     continue;
158                 }
159 
160                 // Create image reader and surface.
161                 Size size = mOrderedPreviewSizes.get(0);
162                 createDefaultImageReader(size, ImageFormat.YUV_420_888, MAX_NUM_IMAGES,
163                         new ImageDropperListener());
164 
165                 // Configure output streams.
166                 List<Surface> outputSurfaces = new ArrayList<Surface>(1);
167                 outputSurfaces.add(mReaderSurface);
168                 createSession(outputSurfaces);
169 
170                 CaptureRequest.Builder requestBuilder =
171                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
172                 assertNotNull("Failed to create capture request", requestBuilder);
173                 requestBuilder.addTarget(mReaderSurface);
174                 TotalAndPartialResultListener listener =
175                         new TotalAndPartialResultListener();
176 
177                 // Start capture
178                 for (Integer frame = 0; frame < NUM_FRAMES_TESTED; frame++) {
179                     // Set a different tag for each request so the listener can group
180                     // partial results by each request
181                     requestBuilder.setTag(frame);
182                     startCapture(
183                             requestBuilder.build(), /*repeating*/false,
184                             listener, mHandler);
185                 }
186 
187                 // Verify capture results
188                 for (int frame = 0; frame < NUM_FRAMES_TESTED; frame++) {
189                     Pair<TotalCaptureResult, List<CaptureResult>> resultPair =
190                             listener.getCaptureResultPairs(WAIT_FOR_RESULT_TIMOUT_MS);
191 
192                     List<CaptureResult> partialResults = resultPair.second;
193 
194                     if (partialResults == null) {
195                         // HAL only sends total result is legal
196                         partialResults = new ArrayList<>();
197                     }
198 
199                     TotalCaptureResult totalResult = resultPair.first;
200 
201                     mCollector.expectLessOrEqual("Too many partial results",
202                             partialResultCount, partialResults.size());
203                     Set<CaptureResult.Key<?>> appearedPartialKeys =
204                             new HashSet<CaptureResult.Key<?>>();
205                     for (CaptureResult partialResult : partialResults) {
206                         List<CaptureResult.Key<?>> partialKeys = partialResult.getKeys();
207                         mCollector.expectValuesUnique("Partial result keys: ", partialKeys);
208                         for (CaptureResult.Key<?> key : partialKeys) {
209                             mCollector.expectTrue(
210                                     String.format("Key %s appears in multiple partial results",
211                                             key.getName()),
212                                     !appearedPartialKeys.contains(key));
213                         }
214                         appearedPartialKeys.addAll(partialKeys);
215                     }
216 
217                     // Test total result against the partial results
218                     List<CaptureResult.Key<?>> totalResultKeys = totalResult.getKeys();
219                     mCollector.expectTrue(
220                             "TotalCaptureResult must be a super set of partial capture results",
221                             totalResultKeys.containsAll(appearedPartialKeys));
222 
223                     List<CaptureResult> totalResultPartials = totalResult.getPartialResults();
224                     mCollector.expectEquals("TotalCaptureResult's partial results must match " +
225                             "the ones observed by #onCaptureProgressed",
226                             partialResults, totalResultPartials);
227 
228                     if (VERBOSE) {
229                         Log.v(TAG, "testPartialResult - Observed " +
230                                 partialResults.size() + "; queried for " +
231                                 totalResultPartials.size());
232                     }
233                 }
234 
235                 int errorCode = listener.getErrorCode();
236                 if ((errorCode & TotalAndPartialResultListener.ERROR_DUPLICATED_REQUEST) != 0) {
237                     mCollector.addMessage("Listener received multiple onCaptureComplete" +
238                             " callback for the same request");
239                 }
240                 if ((errorCode & TotalAndPartialResultListener.ERROR_WRONG_CALLBACK_ORDER) != 0) {
241                     mCollector.addMessage("Listener received onCaptureStart or" +
242                             " onCaptureProgressed after onCaptureComplete");
243                 }
244 
245                 stopCapture(/*fast*/false);
246             } finally {
247                 closeDevice(id);
248                 closeDefaultImageReader();
249             }
250         }
251     }
252 
253     /**
254      * Check that the timestamps passed in the results, buffers, and capture callbacks match for
255      * a single request, and increase monotonically
256      */
testResultTimestamps()257     public void testResultTimestamps() throws Exception {
258         for (String id : mCameraIds) {
259             ImageReader previewReader = null;
260             ImageReader jpegReader = null;
261 
262             SimpleImageReaderListener jpegListener = new SimpleImageReaderListener();
263             SimpleImageReaderListener prevListener = new SimpleImageReaderListener();
264             try {
265                 openDevice(id);
266 
267                 CaptureRequest.Builder previewBuilder =
268                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
269                 CaptureRequest.Builder multiBuilder =
270                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
271 
272                 // Create image reader and surface.
273                 Size previewSize = mOrderedPreviewSizes.get(0);
274                 Size jpegSize = mOrderedStillSizes.get(0);
275 
276                 // Create ImageReaders.
277                 previewReader = makeImageReader(previewSize, ImageFormat.YUV_420_888,
278                         MAX_NUM_IMAGES, prevListener, mHandler);
279                 jpegReader = makeImageReader(jpegSize, ImageFormat.JPEG,
280                         MAX_NUM_IMAGES, jpegListener, mHandler);
281 
282                 // Configure output streams with preview and jpeg streams.
283                 List<Surface> outputSurfaces = new ArrayList<>(Arrays.asList(
284                         previewReader.getSurface(), jpegReader.getSurface()));
285 
286                 SessionListener mockSessionListener = getMockSessionListener();
287 
288                 CameraCaptureSession session = configureAndVerifySession(mockSessionListener,
289                         mCamera, outputSurfaces, mHandler);
290 
291                 // Configure the requests.
292                 previewBuilder.addTarget(previewReader.getSurface());
293                 multiBuilder.addTarget(previewReader.getSurface());
294                 multiBuilder.addTarget(jpegReader.getSurface());
295 
296                 CaptureCallback mockCaptureCallback = getMockCaptureListener();
297 
298                 // Capture targeting only preview
299                 Pair<TotalCaptureResult, Long> result = captureAndVerifyResult(mockCaptureCallback,
300                         session, previewBuilder.build(), mHandler);
301 
302                 // Check if all timestamps are the same
303                 validateTimestamps("Result 1", result.first,
304                         prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result.second);
305 
306                 // Capture targeting both jpeg and preview
307                 Pair<TotalCaptureResult, Long> result2 = captureAndVerifyResult(mockCaptureCallback,
308                         session, multiBuilder.build(), mHandler);
309 
310                 // Check if all timestamps are the same
311                 validateTimestamps("Result 2 Preview", result2.first,
312                         prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result2.second);
313                 validateTimestamps("Result 2 Jpeg", result2.first,
314                         jpegListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result2.second);
315 
316                 // Check if timestamps are increasing
317                 mCollector.expectGreater("Timestamps must be increasing.", result.second,
318                         result2.second);
319 
320                 // Capture two preview frames
321                 long startTime = SystemClock.elapsedRealtimeNanos();
322                 Pair<TotalCaptureResult, Long> result3 = captureAndVerifyResult(mockCaptureCallback,
323                         session, previewBuilder.build(), mHandler);
324                 Pair<TotalCaptureResult, Long> result4 = captureAndVerifyResult(mockCaptureCallback,
325                         session, previewBuilder.build(), mHandler);
326                 long clockDiff = SystemClock.elapsedRealtimeNanos() - startTime;
327                 long resultDiff = result4.second - result3.second;
328 
329                 // Check if all timestamps are the same
330                 validateTimestamps("Result 3", result3.first,
331                         prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result3.second);
332                 validateTimestamps("Result 4", result4.first,
333                         prevListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS), result4.second);
334 
335                 // Check that the timestamps monotonically increase at a reasonable rate
336                 mCollector.expectGreaterOrEqual("Timestamps increase faster than system clock.",
337                         resultDiff, clockDiff);
338                 mCollector.expectGreater("Timestamps must be increasing.", result3.second,
339                         result4.second);
340             } finally {
341                 closeDevice(id);
342                 closeImageReader(previewReader);
343                 closeImageReader(jpegReader);
344             }
345         }
346     }
347 
validateTimestamps(String msg, TotalCaptureResult result, Image resultImage, long captureTime)348     private void validateTimestamps(String msg, TotalCaptureResult result, Image resultImage,
349                                     long captureTime) {
350         mCollector.expectKeyValueEquals(result, CaptureResult.SENSOR_TIMESTAMP, captureTime);
351         mCollector.expectEquals(msg + ": Capture timestamp must be same as resultImage timestamp",
352                 resultImage.getTimestamp(), captureTime);
353     }
354 
validateCaptureResult(SimpleCaptureCallback captureListener, List<CaptureResult.Key<?>> skippedKeys, CaptureRequest.Builder requestBuilder, int numFramesVerified)355     private void validateCaptureResult(SimpleCaptureCallback captureListener,
356             List<CaptureResult.Key<?>> skippedKeys, CaptureRequest.Builder requestBuilder,
357             int numFramesVerified) throws Exception {
358         CaptureResult result = null;
359         for (int i = 0; i < numFramesVerified; i++) {
360             String failMsg = "Failed capture result " + i + " test ";
361             result = captureListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
362 
363             for (CaptureResult.Key<?> key : mAllKeys) {
364                 if (!skippedKeys.contains(key)) {
365                     /**
366                      * Check the critical tags here.
367                      * TODO: Can use the same key for request and result when request/result
368                      * becomes symmetric (b/14059883). Then below check can be wrapped into
369                      * a generic function.
370                      */
371                     String msg = failMsg + "for key " + key.getName();
372                     if (key.equals(CaptureResult.CONTROL_AE_MODE)) {
373                         mCollector.expectEquals(msg,
374                                 requestBuilder.get(CaptureRequest.CONTROL_AE_MODE),
375                                 result.get(CaptureResult.CONTROL_AE_MODE));
376                     } else if (key.equals(CaptureResult.CONTROL_AF_MODE)) {
377                         mCollector.expectEquals(msg,
378                                 requestBuilder.get(CaptureRequest.CONTROL_AF_MODE),
379                                 result.get(CaptureResult.CONTROL_AF_MODE));
380                     } else if (key.equals(CaptureResult.CONTROL_AWB_MODE)) {
381                         mCollector.expectEquals(msg,
382                                 requestBuilder.get(CaptureRequest.CONTROL_AWB_MODE),
383                                 result.get(CaptureResult.CONTROL_AWB_MODE));
384                     } else if (key.equals(CaptureResult.CONTROL_MODE)) {
385                         mCollector.expectEquals(msg,
386                                 requestBuilder.get(CaptureRequest.CONTROL_MODE),
387                                 result.get(CaptureResult.CONTROL_MODE));
388                     } else if (key.equals(CaptureResult.STATISTICS_FACE_DETECT_MODE)) {
389                         mCollector.expectEquals(msg,
390                                 requestBuilder.get(CaptureRequest.STATISTICS_FACE_DETECT_MODE),
391                                 result.get(CaptureResult.STATISTICS_FACE_DETECT_MODE));
392                     } else if (key.equals(CaptureResult.NOISE_REDUCTION_MODE)) {
393                         mCollector.expectEquals(msg,
394                                 requestBuilder.get(CaptureRequest.NOISE_REDUCTION_MODE),
395                                 result.get(CaptureResult.NOISE_REDUCTION_MODE));
396                     } else if (key.equals(CaptureResult.NOISE_REDUCTION_MODE)) {
397                         mCollector.expectEquals(msg,
398                                 requestBuilder.get(CaptureRequest.NOISE_REDUCTION_MODE),
399                                 result.get(CaptureResult.NOISE_REDUCTION_MODE));
400                     } else if (key.equals(CaptureResult.REQUEST_PIPELINE_DEPTH)) {
401 
402                     } else {
403                         // Only do non-null check for the rest of keys.
404                         mCollector.expectKeyValueNotNull(failMsg, result, key);
405                     }
406                 } else {
407                     // These keys should always be null
408                     if (key.equals(CaptureResult.CONTROL_AE_REGIONS)) {
409                         mCollector.expectNull(
410                                 "Capture result contains AE regions but aeMaxRegions is 0",
411                                 result.get(CaptureResult.CONTROL_AE_REGIONS));
412                     } else if (key.equals(CaptureResult.CONTROL_AWB_REGIONS)) {
413                         mCollector.expectNull(
414                                 "Capture result contains AWB regions but awbMaxRegions is 0",
415                                 result.get(CaptureResult.CONTROL_AWB_REGIONS));
416                     } else if (key.equals(CaptureResult.CONTROL_AF_REGIONS)) {
417                         mCollector.expectNull(
418                                 "Capture result contains AF regions but afMaxRegions is 0",
419                                 result.get(CaptureResult.CONTROL_AF_REGIONS));
420                     }
421                 }
422             }
423         }
424     }
425 
426     /*
427      * Add waiver keys per camera device hardware level and capability.
428      *
429      * Must be called after camera device is opened.
430      */
getWaiverKeysForCamera()431     private List<CaptureResult.Key<?>> getWaiverKeysForCamera() {
432         List<CaptureResult.Key<?>> waiverKeys = new ArrayList<>();
433 
434         // Global waiver keys
435         waiverKeys.add(CaptureResult.JPEG_GPS_LOCATION);
436         waiverKeys.add(CaptureResult.JPEG_ORIENTATION);
437         waiverKeys.add(CaptureResult.JPEG_QUALITY);
438         waiverKeys.add(CaptureResult.JPEG_THUMBNAIL_QUALITY);
439         waiverKeys.add(CaptureResult.JPEG_THUMBNAIL_SIZE);
440 
441         // Keys only present when corresponding control is on are being
442         // verified in its own functional test
443         // Only present when tone mapping mode is CONTRAST_CURVE
444         waiverKeys.add(CaptureResult.TONEMAP_CURVE);
445         // Only present when test pattern mode is SOLID_COLOR.
446         // TODO: verify this key in test pattern test later
447         waiverKeys.add(CaptureResult.SENSOR_TEST_PATTERN_DATA);
448         // Only present when STATISTICS_LENS_SHADING_MAP_MODE is ON
449         waiverKeys.add(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP);
450         //  Only present when STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES is ON
451         waiverKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP);
452         //  Only present when face detection is on
453         waiverKeys.add(CaptureResult.STATISTICS_FACES);
454 
455         //Keys not required if RAW is not supported
456         if (!mStaticInfo.isCapabilitySupported(
457                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
458             waiverKeys.add(CaptureResult.SENSOR_NEUTRAL_COLOR_POINT);
459             waiverKeys.add(CaptureResult.SENSOR_GREEN_SPLIT);
460             waiverKeys.add(CaptureResult.SENSOR_NOISE_PROFILE);
461         }
462 
463         if (mStaticInfo.getAeMaxRegionsChecked() == 0) {
464             waiverKeys.add(CaptureResult.CONTROL_AE_REGIONS);
465         }
466         if (mStaticInfo.getAwbMaxRegionsChecked() == 0) {
467             waiverKeys.add(CaptureResult.CONTROL_AWB_REGIONS);
468         }
469         if (mStaticInfo.getAfMaxRegionsChecked() == 0) {
470             waiverKeys.add(CaptureResult.CONTROL_AF_REGIONS);
471         }
472 
473         if (mStaticInfo.isHardwareLevelFull()) {
474             return waiverKeys;
475         }
476 
477         /*
478          * Hardware Level = LIMITED or LEGACY
479          */
480         // Key not present if certain control is not supported
481         if (!mStaticInfo.isManualColorCorrectionSupported()) {
482             waiverKeys.add(CaptureResult.COLOR_CORRECTION_GAINS);
483             waiverKeys.add(CaptureResult.COLOR_CORRECTION_MODE);
484             waiverKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM);
485         }
486 
487         if (!mStaticInfo.isManualColorAberrationControlSupported()) {
488             waiverKeys.add(CaptureResult.COLOR_CORRECTION_ABERRATION_MODE);
489         }
490 
491         if (!mStaticInfo.isManualToneMapSupported()) {
492             waiverKeys.add(CaptureResult.TONEMAP_MODE);
493         }
494 
495         if (!mStaticInfo.isEdgeModeControlSupported()) {
496             waiverKeys.add(CaptureResult.EDGE_MODE);
497         }
498 
499         if (!mStaticInfo.isHotPixelMapModeControlSupported()) {
500             waiverKeys.add(CaptureResult.HOT_PIXEL_MODE);
501         }
502 
503         if (!mStaticInfo.isNoiseReductionModeControlSupported()) {
504             waiverKeys.add(CaptureResult.NOISE_REDUCTION_MODE);
505         }
506 
507         if (!mStaticInfo.isManualLensShadingMapSupported()) {
508             waiverKeys.add(CaptureResult.SHADING_MODE);
509         }
510 
511         //Keys not required if manual sensor control is not supported
512         if (!mStaticInfo.isCapabilitySupported(
513                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
514             waiverKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME);
515             waiverKeys.add(CaptureResult.SENSOR_FRAME_DURATION);
516             waiverKeys.add(CaptureResult.SENSOR_SENSITIVITY);
517             waiverKeys.add(CaptureResult.BLACK_LEVEL_LOCK);
518             waiverKeys.add(CaptureResult.LENS_FOCUS_RANGE);
519             waiverKeys.add(CaptureResult.LENS_FOCUS_DISTANCE);
520             waiverKeys.add(CaptureResult.LENS_STATE);
521             waiverKeys.add(CaptureResult.LENS_APERTURE);
522             waiverKeys.add(CaptureResult.LENS_FILTER_DENSITY);
523         }
524 
525         if (mStaticInfo.isHardwareLevelLimited()) {
526             return waiverKeys;
527         }
528 
529         /*
530          * Hardware Level = LEGACY
531          */
532         waiverKeys.add(CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER);
533         waiverKeys.add(CaptureResult.CONTROL_AE_STATE);
534         waiverKeys.add(CaptureResult.CONTROL_AWB_STATE);
535         waiverKeys.add(CaptureResult.FLASH_STATE);
536         waiverKeys.add(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE);
537         waiverKeys.add(CaptureResult.SENSOR_ROLLING_SHUTTER_SKEW);
538         waiverKeys.add(CaptureResult.STATISTICS_LENS_SHADING_MAP_MODE);
539         waiverKeys.add(CaptureResult.STATISTICS_SCENE_FLICKER);
540         waiverKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE);
541         waiverKeys.add(CaptureResult.CONTROL_AE_TARGET_FPS_RANGE);
542         waiverKeys.add(CaptureResult.CONTROL_AF_TRIGGER);
543 
544         return waiverKeys;
545     }
546 
547     /**
548      * A capture listener implementation for collecting both partial and total results.
549      *
550      * <p> This is not a full-blown class and has some implicit assumptions. The class groups
551      * capture results by capture request, so the user must guarantee each request this listener
552      * is listening is unique. This class is not thread safe, so don't attach an instance object
553      * with multiple handlers.</p>
554      * */
555     private static class TotalAndPartialResultListener
556             extends CameraCaptureSession.CaptureCallback {
557         static final int ERROR_DUPLICATED_REQUEST = 1 << 0;
558         static final int ERROR_WRONG_CALLBACK_ORDER = 1 << 1;
559 
560         private final LinkedBlockingQueue<Pair<TotalCaptureResult, List<CaptureResult>> > mQueue =
561                 new LinkedBlockingQueue<>();
562         private final HashMap<CaptureRequest, List<CaptureResult>> mPartialResultsMap =
563                 new HashMap<CaptureRequest, List<CaptureResult>>();
564         private final HashSet<CaptureRequest> completedRequests = new HashSet<>();
565         private int errorCode = 0;
566 
567         @Override
onCaptureStarted( CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber)568         public void onCaptureStarted(
569             CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber)
570         {
571             checkCallbackOrder(request);
572             createMapEntryIfNecessary(request);
573         }
574 
575         @Override
onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result)576         public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
577                 TotalCaptureResult result) {
578             try {
579                 List<CaptureResult> partialResultsList = mPartialResultsMap.get(request);
580                 if (partialResultsList == null) {
581                     Log.w(TAG, "onCaptureCompleted: unknown request");
582                 }
583                 mQueue.put(new Pair<TotalCaptureResult, List<CaptureResult>>(
584                         result, partialResultsList));
585                 mPartialResultsMap.remove(request);
586                 boolean newEntryAdded = completedRequests.add(request);
587                 if (!newEntryAdded) {
588                     Integer frame = (Integer) request.getTag();
589                     Log.e(TAG, "Frame " + frame + "ERROR_DUPLICATED_REQUEST");
590                     errorCode |= ERROR_DUPLICATED_REQUEST;
591                 }
592             } catch (InterruptedException e) {
593                 throw new UnsupportedOperationException(
594                         "Can't handle InterruptedException in onCaptureCompleted");
595             }
596         }
597 
598         @Override
onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult)599         public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
600                 CaptureResult partialResult) {
601             createMapEntryIfNecessary(request);
602             List<CaptureResult> partialResultsList = mPartialResultsMap.get(request);
603             partialResultsList.add(partialResult);
604         }
605 
createMapEntryIfNecessary(CaptureRequest request)606         private void createMapEntryIfNecessary(CaptureRequest request) {
607             if (!mPartialResultsMap.containsKey(request)) {
608                 // create a new entry in the map
609                 mPartialResultsMap.put(request, new ArrayList<CaptureResult>());
610             }
611         }
612 
checkCallbackOrder(CaptureRequest request)613         private void checkCallbackOrder(CaptureRequest request) {
614             if (completedRequests.contains(request)) {
615                 Integer frame = (Integer) request.getTag();
616                 Log.e(TAG, "Frame " + frame + "ERROR_WRONG_CALLBACK_ORDER");
617                 errorCode |= ERROR_WRONG_CALLBACK_ORDER;
618             }
619         }
620 
getCaptureResultPairs(long timeout)621         public Pair<TotalCaptureResult, List<CaptureResult>> getCaptureResultPairs(long timeout) {
622             try {
623                 Pair<TotalCaptureResult, List<CaptureResult>> result =
624                         mQueue.poll(timeout, TimeUnit.MILLISECONDS);
625                 assertNotNull("Wait for a capture result timed out in " + timeout + "ms", result);
626                 return result;
627             } catch (InterruptedException e) {
628                 throw new UnsupportedOperationException("Unhandled interrupted exception", e);
629             }
630         }
631 
getErrorCode()632         public int getErrorCode() {
633             return errorCode;
634         }
635     }
636 
637     /**
638      * TODO: Use CameraCharacteristics.getAvailableCaptureResultKeys() once we can filter out
639      * @hide keys.
640      *
641      */
642 
643     /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
644      * The key entries below this point are generated from metadata
645      * definitions in /system/media/camera/docs. Do not modify by hand or
646      * modify the comment blocks at the start or end.
647      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
648 
getAllCaptureResultKeys()649     private static List<CaptureResult.Key<?>> getAllCaptureResultKeys() {
650         ArrayList<CaptureResult.Key<?>> resultKeys = new ArrayList<CaptureResult.Key<?>>();
651         resultKeys.add(CaptureResult.COLOR_CORRECTION_MODE);
652         resultKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM);
653         resultKeys.add(CaptureResult.COLOR_CORRECTION_GAINS);
654         resultKeys.add(CaptureResult.COLOR_CORRECTION_ABERRATION_MODE);
655         resultKeys.add(CaptureResult.CONTROL_AE_ANTIBANDING_MODE);
656         resultKeys.add(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION);
657         resultKeys.add(CaptureResult.CONTROL_AE_LOCK);
658         resultKeys.add(CaptureResult.CONTROL_AE_MODE);
659         resultKeys.add(CaptureResult.CONTROL_AE_REGIONS);
660         resultKeys.add(CaptureResult.CONTROL_AE_TARGET_FPS_RANGE);
661         resultKeys.add(CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER);
662         resultKeys.add(CaptureResult.CONTROL_AF_MODE);
663         resultKeys.add(CaptureResult.CONTROL_AF_REGIONS);
664         resultKeys.add(CaptureResult.CONTROL_AF_TRIGGER);
665         resultKeys.add(CaptureResult.CONTROL_AWB_LOCK);
666         resultKeys.add(CaptureResult.CONTROL_AWB_MODE);
667         resultKeys.add(CaptureResult.CONTROL_AWB_REGIONS);
668         resultKeys.add(CaptureResult.CONTROL_CAPTURE_INTENT);
669         resultKeys.add(CaptureResult.CONTROL_EFFECT_MODE);
670         resultKeys.add(CaptureResult.CONTROL_MODE);
671         resultKeys.add(CaptureResult.CONTROL_SCENE_MODE);
672         resultKeys.add(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE);
673         resultKeys.add(CaptureResult.CONTROL_AE_STATE);
674         resultKeys.add(CaptureResult.CONTROL_AF_STATE);
675         resultKeys.add(CaptureResult.CONTROL_AWB_STATE);
676         resultKeys.add(CaptureResult.EDGE_MODE);
677         resultKeys.add(CaptureResult.FLASH_MODE);
678         resultKeys.add(CaptureResult.FLASH_STATE);
679         resultKeys.add(CaptureResult.HOT_PIXEL_MODE);
680         resultKeys.add(CaptureResult.JPEG_GPS_LOCATION);
681         resultKeys.add(CaptureResult.JPEG_ORIENTATION);
682         resultKeys.add(CaptureResult.JPEG_QUALITY);
683         resultKeys.add(CaptureResult.JPEG_THUMBNAIL_QUALITY);
684         resultKeys.add(CaptureResult.JPEG_THUMBNAIL_SIZE);
685         resultKeys.add(CaptureResult.LENS_APERTURE);
686         resultKeys.add(CaptureResult.LENS_FILTER_DENSITY);
687         resultKeys.add(CaptureResult.LENS_FOCAL_LENGTH);
688         resultKeys.add(CaptureResult.LENS_FOCUS_DISTANCE);
689         resultKeys.add(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE);
690         resultKeys.add(CaptureResult.LENS_FOCUS_RANGE);
691         resultKeys.add(CaptureResult.LENS_STATE);
692         resultKeys.add(CaptureResult.NOISE_REDUCTION_MODE);
693         resultKeys.add(CaptureResult.REQUEST_PIPELINE_DEPTH);
694         resultKeys.add(CaptureResult.SCALER_CROP_REGION);
695         resultKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME);
696         resultKeys.add(CaptureResult.SENSOR_FRAME_DURATION);
697         resultKeys.add(CaptureResult.SENSOR_SENSITIVITY);
698         resultKeys.add(CaptureResult.SENSOR_TIMESTAMP);
699         resultKeys.add(CaptureResult.SENSOR_NEUTRAL_COLOR_POINT);
700         resultKeys.add(CaptureResult.SENSOR_NOISE_PROFILE);
701         resultKeys.add(CaptureResult.SENSOR_GREEN_SPLIT);
702         resultKeys.add(CaptureResult.SENSOR_TEST_PATTERN_DATA);
703         resultKeys.add(CaptureResult.SENSOR_TEST_PATTERN_MODE);
704         resultKeys.add(CaptureResult.SENSOR_ROLLING_SHUTTER_SKEW);
705         resultKeys.add(CaptureResult.SHADING_MODE);
706         resultKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
707         resultKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE);
708         resultKeys.add(CaptureResult.STATISTICS_FACES);
709         resultKeys.add(CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP);
710         resultKeys.add(CaptureResult.STATISTICS_SCENE_FLICKER);
711         resultKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP);
712         resultKeys.add(CaptureResult.STATISTICS_LENS_SHADING_MAP_MODE);
713         resultKeys.add(CaptureResult.TONEMAP_CURVE);
714         resultKeys.add(CaptureResult.TONEMAP_MODE);
715         resultKeys.add(CaptureResult.BLACK_LEVEL_LOCK);
716 
717         return resultKeys;
718     }
719 
720     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
721      * End generated code
722      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
723 }
724