• 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.CameraCharacteristics;
22 import android.hardware.camera2.CameraDevice;
23 import android.hardware.camera2.CameraManager;
24 import android.hardware.camera2.CameraMetadata;
25 import android.hardware.camera2.CaptureFailure;
26 import android.hardware.camera2.CaptureRequest;
27 import android.hardware.camera2.CaptureResult;
28 import android.hardware.camera2.Size;
29 import static android.hardware.camera2.cts.CameraTestUtils.*;
30 import android.media.ImageReader;
31 import android.os.Handler;
32 import android.os.HandlerThread;
33 import android.test.AndroidTestCase;
34 import android.util.Log;
35 import android.view.Surface;
36 
37 import com.android.ex.camera2.blocking.BlockingStateListener;
38 import static com.android.ex.camera2.blocking.BlockingStateListener.*;
39 
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.concurrent.LinkedBlockingQueue;
43 import java.util.concurrent.TimeUnit;
44 
45 public class CameraCaptureResultTest extends AndroidTestCase {
46     private static final String TAG = "CameraCaptureResultTest";
47     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
48 
49     private CameraManager mCameraManager;
50     private HandlerThread mHandlerThread;
51     private Handler mHandler;
52     private ImageReader mImageReader;
53     private Surface mSurface;
54     private BlockingStateListener mCameraListener;
55 
56     private static final int MAX_NUM_IMAGES = 5;
57     private static final int NUM_FRAMES_VERIFIED = 300;
58     private static final long WAIT_FOR_RESULT_TIMEOUT_MS = 3000;
59 
60     // List that includes all public keys from CaptureResult
61     List<CameraMetadata.Key<?>> mAllKeys;
62 
63     // List tracking the failed test keys.
64     List<CameraMetadata.Key<?>> mFailedKeys = new ArrayList<CameraMetadata.Key<?>>();
65 
66     @Override
setContext(Context context)67     public void setContext(Context context) {
68         mAllKeys = getAllCaptureResultKeys();
69         super.setContext(context);
70     }
71 
72     @Override
setUp()73     protected void setUp() throws Exception {
74         super.setUp();
75         mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
76         assertNotNull("Can't connect to camera manager", mCameraManager);
77         mHandlerThread = new HandlerThread(TAG);
78         mHandlerThread.start();
79         mHandler = new Handler(mHandlerThread.getLooper());
80         mCameraListener = new BlockingStateListener();
81         mFailedKeys.clear();
82     }
83 
84     @Override
tearDown()85     protected void tearDown() throws Exception {
86         mHandlerThread.quitSafely();
87         super.tearDown();
88     }
89 
testCameraCaptureResultAllKeys()90     public void testCameraCaptureResultAllKeys() throws Exception {
91         /**
92          * Hardcode a key waiver list for the keys we want to skip the sanity check.
93          * FIXME: We need get ride of this list, see bug 11116270.
94          */
95         List<CameraMetadata.Key<?>> waiverkeys = new ArrayList<CameraMetadata.Key<?>>();
96         waiverkeys.add(CaptureResult.EDGE_MODE);
97         waiverkeys.add(CaptureResult.JPEG_GPS_COORDINATES);
98         waiverkeys.add(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
99         waiverkeys.add(CaptureResult.JPEG_GPS_TIMESTAMP);
100         waiverkeys.add(CaptureResult.JPEG_ORIENTATION);
101         waiverkeys.add(CaptureResult.JPEG_QUALITY);
102         waiverkeys.add(CaptureResult.JPEG_THUMBNAIL_QUALITY);
103         waiverkeys.add(CaptureResult.JPEG_THUMBNAIL_SIZE);
104         waiverkeys.add(CaptureResult.SENSOR_TEMPERATURE);
105         waiverkeys.add(CaptureResult.TONEMAP_CURVE_BLUE);
106         waiverkeys.add(CaptureResult.TONEMAP_CURVE_GREEN);
107         waiverkeys.add(CaptureResult.TONEMAP_CURVE_RED);
108         waiverkeys.add(CaptureResult.TONEMAP_MODE);
109         waiverkeys.add(CaptureResult.STATISTICS_PREDICTED_COLOR_GAINS);
110         waiverkeys.add(CaptureResult.STATISTICS_PREDICTED_COLOR_TRANSFORM);
111         waiverkeys.add(CaptureResult.STATISTICS_SCENE_FLICKER);
112 
113         String[] ids = mCameraManager.getCameraIdList();
114         for (int i = 0; i < ids.length; i++) {
115             CameraCharacteristics props = mCameraManager.getCameraCharacteristics(ids[i]);
116             assertNotNull("CameraCharacteristics shouldn't be null", props);
117             Integer hwLevel = props.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
118             if (hwLevel != CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL) {
119                 continue;
120             }
121             // TODO: check for LIMITED keys
122 
123             CameraDevice camera = null;
124             try {
125                 Size[] sizes = CameraTestUtils.getSupportedSizeForFormat(
126                         ImageFormat.YUV_420_888, ids[i], mCameraManager);
127                 CameraTestUtils.assertArrayNotEmpty(sizes, "Available sizes shouldn't be empty");
128                 createDefaultSurface(sizes[0]);
129 
130                 if (VERBOSE) {
131                     Log.v(TAG, "Testing camera " + ids[i] + "for size " + sizes[0].toString());
132                 }
133 
134                 camera = CameraTestUtils.openCamera(
135                         mCameraManager, ids[i], mCameraListener, mHandler);
136                 assertNotNull(
137                         String.format("Failed to open camera device %s", ids[i]), camera);
138                 mCameraListener.waitForState(STATE_UNCONFIGURED, CAMERA_OPEN_TIMEOUT_MS);
139 
140                 List<Surface> outputSurfaces = new ArrayList<Surface>(1);
141                 outputSurfaces.add(mSurface);
142                 camera.configureOutputs(outputSurfaces);
143                 mCameraListener.waitForState(STATE_BUSY, CAMERA_BUSY_TIMEOUT_MS);
144                 mCameraListener.waitForState(STATE_IDLE, CAMERA_IDLE_TIMEOUT_MS);
145 
146                 CaptureRequest.Builder requestBuilder =
147                         camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
148                 assertNotNull("Failed to create capture request", requestBuilder);
149                 requestBuilder.addTarget(mSurface);
150 
151                 // Enable face detection if supported
152                 byte[] faceModes = props.get(
153                         CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES);
154                 assertNotNull("Available face detection modes shouldn't be null", faceModes);
155                 for (int m = 0; m < faceModes.length; m++) {
156                     if (faceModes[m] == CameraMetadata.STATISTICS_FACE_DETECT_MODE_FULL) {
157                         if (VERBOSE) {
158                             Log.v(TAG, "testCameraCaptureResultAllKeys - " +
159                                     "setting facedetection mode to full");
160                         }
161                         requestBuilder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE,
162                                 (int)faceModes[m]);
163                     }
164                 }
165 
166                 // Enable lensShading mode, it should be supported by full mode device.
167                 requestBuilder.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE,
168                         CameraMetadata.STATISTICS_LENS_SHADING_MAP_MODE_ON);
169 
170                 SimpleCaptureListener captureListener = new SimpleCaptureListener();
171                 camera.setRepeatingRequest(requestBuilder.build(), captureListener, mHandler);
172 
173                 for (int m = 0; m < NUM_FRAMES_VERIFIED; m++) {
174                     if(VERBOSE) {
175                         Log.v(TAG, "Testing frame " + m);
176                     }
177                     validateCaptureResult(
178                             captureListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS),
179                             waiverkeys);
180                 }
181 
182                 // Stop repeat, wait for captures to complete, and disconnect from surfaces
183                 camera.configureOutputs(/*outputs*/ null);
184                 mCameraListener.waitForState(STATE_BUSY, CAMERA_BUSY_TIMEOUT_MS);
185                 mCameraListener.waitForState(STATE_UNCONFIGURED, CAMERA_IDLE_TIMEOUT_MS);
186                 // Camera has disconnected, clear out the reader
187                 mSurface.release();
188                 mImageReader.close();
189             } finally {
190                 if (camera != null) {
191                     camera.close();
192                 }
193             }
194 
195         }
196     }
197 
validateCaptureResult(CaptureResult result, List<CameraMetadata.Key<?>> skippedKeys)198     private void validateCaptureResult(CaptureResult result,
199             List<CameraMetadata.Key<?>> skippedKeys) throws Exception {
200         for (CameraMetadata.Key<?> key : mAllKeys) {
201             if (!skippedKeys.contains(key) && result.get(key) == null) {
202                 mFailedKeys.add(key);
203             }
204         }
205 
206         StringBuffer failedKeyNames = new StringBuffer("Below Keys have null values:\n");
207         for (CameraMetadata.Key<?> key : mFailedKeys) {
208             failedKeyNames.append(key.getName() + "\n");
209         }
210 
211         assertTrue("Some keys have null values, " + failedKeyNames.toString(),
212                 mFailedKeys.isEmpty());
213     }
214 
215     private static class SimpleCaptureListener extends CameraDevice.CaptureListener {
216         LinkedBlockingQueue<CaptureResult> mQueue = new LinkedBlockingQueue<CaptureResult>();
217 
218         @Override
onCaptureStarted(CameraDevice camera, CaptureRequest request, long timestamp)219         public void onCaptureStarted(CameraDevice camera, CaptureRequest request, long timestamp)
220         {
221         }
222 
223         @Override
onCaptureCompleted(CameraDevice camera, CaptureRequest request, CaptureResult result)224         public void onCaptureCompleted(CameraDevice camera, CaptureRequest request,
225                 CaptureResult result) {
226             try {
227                 mQueue.put(result);
228             } catch (InterruptedException e) {
229                 throw new UnsupportedOperationException(
230                         "Can't handle InterruptedException in onCaptureCompleted");
231             }
232         }
233 
234         @Override
onCaptureFailed(CameraDevice camera, CaptureRequest request, CaptureFailure failure)235         public void onCaptureFailed(CameraDevice camera, CaptureRequest request,
236                 CaptureFailure failure) {
237         }
238 
239         @Override
onCaptureSequenceCompleted(CameraDevice camera, int sequenceId, int frameNumber)240         public void onCaptureSequenceCompleted(CameraDevice camera, int sequenceId,
241                 int frameNumber) {
242         }
243 
getCaptureResult(long timeout)244         public CaptureResult getCaptureResult(long timeout) throws InterruptedException {
245             CaptureResult result = mQueue.poll(timeout, TimeUnit.MILLISECONDS);
246             assertNotNull("Wait for a capture result timed out in " + timeout + "ms", result);
247             return result;
248         }
249     }
250 
createDefaultSurface(Size sz)251     private void createDefaultSurface(Size sz) {
252         mImageReader =
253                 ImageReader.newInstance(sz.getWidth(),
254                         sz.getHeight(),
255                         ImageFormat.YUV_420_888,
256                         MAX_NUM_IMAGES);
257         mImageReader.setOnImageAvailableListener(new ImageDropperListener(), mHandler);
258         mSurface = mImageReader.getSurface();
259     }
260 
261     /**
262      * TODO: Use CameraCharacteristics.getAvailableCaptureResultKeys() once we can filter out
263      * @hide keys.
264      *
265      */
266 
267     /*@O~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
268      * The key entries below this point are generated from metadata
269      * definitions in /system/media/camera/docs. Do not modify by hand or
270      * modify the comment blocks at the start or end.
271      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~*/
272 
getAllCaptureResultKeys()273     private static List<CameraMetadata.Key<?>> getAllCaptureResultKeys() {
274         ArrayList<CameraMetadata.Key<?>> resultKeys = new ArrayList<CameraMetadata.Key<?>>();
275         resultKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM);
276         resultKeys.add(CaptureResult.COLOR_CORRECTION_GAINS);
277         resultKeys.add(CaptureResult.CONTROL_AE_REGIONS);
278         resultKeys.add(CaptureResult.CONTROL_AF_MODE);
279         resultKeys.add(CaptureResult.CONTROL_AF_REGIONS);
280         resultKeys.add(CaptureResult.CONTROL_AWB_MODE);
281         resultKeys.add(CaptureResult.CONTROL_AWB_REGIONS);
282         resultKeys.add(CaptureResult.CONTROL_MODE);
283         resultKeys.add(CaptureResult.CONTROL_AE_STATE);
284         resultKeys.add(CaptureResult.CONTROL_AF_STATE);
285         resultKeys.add(CaptureResult.CONTROL_AWB_STATE);
286         resultKeys.add(CaptureResult.EDGE_MODE);
287         resultKeys.add(CaptureResult.FLASH_MODE);
288         resultKeys.add(CaptureResult.FLASH_STATE);
289         resultKeys.add(CaptureResult.JPEG_GPS_COORDINATES);
290         resultKeys.add(CaptureResult.JPEG_GPS_PROCESSING_METHOD);
291         resultKeys.add(CaptureResult.JPEG_GPS_TIMESTAMP);
292         resultKeys.add(CaptureResult.JPEG_ORIENTATION);
293         resultKeys.add(CaptureResult.JPEG_QUALITY);
294         resultKeys.add(CaptureResult.JPEG_THUMBNAIL_QUALITY);
295         resultKeys.add(CaptureResult.JPEG_THUMBNAIL_SIZE);
296         resultKeys.add(CaptureResult.LENS_APERTURE);
297         resultKeys.add(CaptureResult.LENS_FILTER_DENSITY);
298         resultKeys.add(CaptureResult.LENS_FOCAL_LENGTH);
299         resultKeys.add(CaptureResult.LENS_FOCUS_DISTANCE);
300         resultKeys.add(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE);
301         resultKeys.add(CaptureResult.LENS_FOCUS_RANGE);
302         resultKeys.add(CaptureResult.LENS_STATE);
303         resultKeys.add(CaptureResult.NOISE_REDUCTION_MODE);
304         resultKeys.add(CaptureResult.REQUEST_FRAME_COUNT);
305         resultKeys.add(CaptureResult.SCALER_CROP_REGION);
306         resultKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME);
307         resultKeys.add(CaptureResult.SENSOR_FRAME_DURATION);
308         resultKeys.add(CaptureResult.SENSOR_SENSITIVITY);
309         resultKeys.add(CaptureResult.SENSOR_TIMESTAMP);
310         resultKeys.add(CaptureResult.SENSOR_TEMPERATURE);
311         resultKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
312         resultKeys.add(CaptureResult.STATISTICS_FACE_IDS);
313         resultKeys.add(CaptureResult.STATISTICS_FACE_LANDMARKS);
314         resultKeys.add(CaptureResult.STATISTICS_FACE_RECTANGLES);
315         resultKeys.add(CaptureResult.STATISTICS_FACE_SCORES);
316         resultKeys.add(CaptureResult.STATISTICS_LENS_SHADING_MAP);
317         resultKeys.add(CaptureResult.STATISTICS_PREDICTED_COLOR_GAINS);
318         resultKeys.add(CaptureResult.STATISTICS_PREDICTED_COLOR_TRANSFORM);
319         resultKeys.add(CaptureResult.STATISTICS_SCENE_FLICKER);
320         resultKeys.add(CaptureResult.TONEMAP_CURVE_BLUE);
321         resultKeys.add(CaptureResult.TONEMAP_CURVE_GREEN);
322         resultKeys.add(CaptureResult.TONEMAP_CURVE_RED);
323         resultKeys.add(CaptureResult.TONEMAP_MODE);
324         resultKeys.add(CaptureResult.BLACK_LEVEL_LOCK);
325 
326         // Add STATISTICS_FACES key separately here because it is not
327         // defined in metadata xml file.
328         resultKeys.add(CaptureResult.STATISTICS_FACES);
329 
330         return resultKeys;
331     }
332 
333     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
334      * End generated code
335      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
336 }
337