• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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.cts;
18 
19 import android.graphics.BitmapFactory;
20 import android.graphics.ImageFormat;
21 import android.graphics.Rect;
22 import android.hardware.Camera;
23 import android.hardware.Camera.Area;
24 import android.hardware.Camera.CameraInfo;
25 import android.hardware.Camera.ErrorCallback;
26 import android.hardware.Camera.Face;
27 import android.hardware.Camera.FaceDetectionListener;
28 import android.hardware.Camera.Parameters;
29 import android.hardware.Camera.PictureCallback;
30 import android.hardware.Camera.ShutterCallback;
31 import android.hardware.Camera.Size;
32 import android.media.CamcorderProfile;
33 import android.media.ExifInterface;
34 import android.media.MediaRecorder;
35 import android.os.ConditionVariable;
36 import android.os.Environment;
37 import android.os.Looper;
38 import android.test.ActivityInstrumentationTestCase2;
39 import android.test.MoreAsserts;
40 import android.test.UiThreadTest;
41 import android.test.suitebuilder.annotation.LargeTest;
42 import android.util.Log;
43 import android.view.SurfaceHolder;
44 
45 
46 import java.io.File;
47 import java.io.FileOutputStream;
48 import java.io.IOException;
49 import java.text.SimpleDateFormat;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.Date;
53 import java.util.Iterator;
54 import java.util.List;
55 
56 import junit.framework.AssertionFailedError;
57 
58 /**
59  * This test case must run with hardware. It can't be tested in emulator
60  */
61 @LargeTest
62 public class CameraTest extends ActivityInstrumentationTestCase2<CameraStubActivity> {
63     private static String TAG = "CameraTest";
64     private static final String PACKAGE = "com.android.cts.stub";
65     private static final boolean LOGV = false;
66     private final String JPEG_PATH = Environment.getExternalStorageDirectory().getPath() +
67             "/test.jpg";
68     private byte[] mJpegData;
69 
70     private static final int PREVIEW_CALLBACK_NOT_RECEIVED = 0;
71     private static final int PREVIEW_CALLBACK_RECEIVED = 1;
72     private static final int PREVIEW_CALLBACK_DATA_NULL = 2;
73     private static final int PREVIEW_CALLBACK_INVALID_FRAME_SIZE = 3;
74     private int mPreviewCallbackResult = PREVIEW_CALLBACK_NOT_RECEIVED;
75 
76     private boolean mShutterCallbackResult = false;
77     private boolean mRawPictureCallbackResult = false;
78     private boolean mJpegPictureCallbackResult = false;
79     private static final int NO_ERROR = -1;
80     private int mCameraErrorCode = NO_ERROR;
81     private boolean mAutoFocusSucceeded = false;
82 
83     private static final int WAIT_FOR_COMMAND_TO_COMPLETE = 5000;  // Milliseconds.
84     private static final int WAIT_FOR_FOCUS_TO_COMPLETE = 5000;
85     private static final int WAIT_FOR_SNAPSHOT_TO_COMPLETE = 5000;
86 
87     private static final int FOCUS_AREA = 0;
88     private static final int METERING_AREA = 1;
89 
90     private static final int AUTOEXPOSURE_LOCK = 0;
91     private static final int AUTOWHITEBALANCE_LOCK = 1;
92 
93     private PreviewCallback mPreviewCallback = new PreviewCallback();
94     private TestShutterCallback mShutterCallback = new TestShutterCallback();
95     private RawPictureCallback mRawPictureCallback = new RawPictureCallback();
96     private JpegPictureCallback mJpegPictureCallback = new JpegPictureCallback();
97     private TestErrorCallback mErrorCallback = new TestErrorCallback();
98     private AutoFocusCallback mAutoFocusCallback = new AutoFocusCallback();
99     private AutoFocusMoveCallback mAutoFocusMoveCallback = new AutoFocusMoveCallback();
100 
101     private Looper mLooper = null;
102     private final ConditionVariable mPreviewDone = new ConditionVariable();
103     private final ConditionVariable mFocusDone = new ConditionVariable();
104     private final ConditionVariable mSnapshotDone = new ConditionVariable();
105 
106     Camera mCamera;
107 
CameraTest()108     public CameraTest() {
109         super(PACKAGE, CameraStubActivity.class);
110         if (LOGV) Log.v(TAG, "Camera Constructor");
111     }
112 
113     @Override
setUp()114     protected void setUp() throws Exception {
115         super.setUp();
116         // to start CameraStubActivity.
117         getActivity();
118     }
119 
120     @Override
tearDown()121     protected void tearDown() throws Exception {
122         if (mCamera != null) {
123             mCamera.release();
124             mCamera = null;
125         }
126         super.tearDown();
127     }
128 
129     /*
130      * Initializes the message looper so that the Camera object can
131      * receive the callback messages.
132      */
initializeMessageLooper(final int cameraId)133     private void initializeMessageLooper(final int cameraId) throws IOException {
134         final ConditionVariable startDone = new ConditionVariable();
135         new Thread() {
136             @Override
137             public void run() {
138                 Log.v(TAG, "start loopRun");
139                 // Set up a looper to be used by camera.
140                 Looper.prepare();
141                 // Save the looper so that we can terminate this thread
142                 // after we are done with it.
143                 mLooper = Looper.myLooper();
144                 try {
145                     mCamera = Camera.open(cameraId);
146                     mCamera.setErrorCallback(mErrorCallback);
147                 } catch (RuntimeException e) {
148                     Log.e(TAG, "Fail to open camera." + e);
149                 }
150                 Log.v(TAG, "camera is opened");
151                 startDone.open();
152                 Looper.loop(); // Blocks forever until Looper.quit() is called.
153                 if (LOGV) Log.v(TAG, "initializeMessageLooper: quit.");
154             }
155         }.start();
156 
157         Log.v(TAG, "start waiting for looper");
158         if (!startDone.block(WAIT_FOR_COMMAND_TO_COMPLETE)) {
159             Log.v(TAG, "initializeMessageLooper: start timeout");
160             fail("initializeMessageLooper: start timeout");
161         }
162         assertNotNull("Fail to open camera.", mCamera);
163         mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
164     }
165 
166     /*
167      * Terminates the message looper thread.
168      */
terminateMessageLooper()169     private void terminateMessageLooper() throws Exception {
170         mLooper.quit();
171         // Looper.quit() is asynchronous. The looper may still has some
172         // preview callbacks in the queue after quit is called. The preview
173         // callback still uses the camera object (setHasPreviewCallback).
174         // After camera is released, RuntimeException will be thrown from
175         // the method. So we need to join the looper thread here.
176         mLooper.getThread().join();
177         mCamera.release();
178         mCamera = null;
179         assertEquals("Got camera error callback.", NO_ERROR, mCameraErrorCode);
180     }
181 
182     // Align 'x' to 'to', which should be a power of 2
align(int x, int to)183     private static int align(int x, int to) {
184         return (x + (to-1)) & ~(to - 1);
185     }
calculateBufferSize(int width, int height, int format, int bpp)186     private static int calculateBufferSize(int width, int height,
187                                            int format, int bpp) {
188 
189         if (LOGV) {
190             Log.v(TAG, "calculateBufferSize: w=" + width + ",h=" + height
191             + ",f=" + format + ",bpp=" + bpp);
192         }
193 
194         if (format == ImageFormat.YV12) {
195             /*
196             http://developer.android.com/reference/android/graphics/ImageFormat.html#YV12
197             */
198 
199             int stride = align(width, 16);
200 
201             int y_size = stride * height;
202             int c_stride = align(stride/2, 16);
203             int c_size = c_stride * height/2;
204             int size = y_size + c_size * 2;
205 
206             if (LOGV) {
207                 Log.v(TAG, "calculateBufferSize: YV12 size= " + size);
208             }
209 
210             return size;
211 
212         }
213         else {
214             return width * height * bpp / 8;
215         }
216     }
217 
218     //Implement the previewCallback
219     private final class PreviewCallback
220             implements android.hardware.Camera.PreviewCallback {
onPreviewFrame(byte [] data, Camera camera)221         public void onPreviewFrame(byte [] data, Camera camera) {
222             if (data == null) {
223                 mPreviewCallbackResult = PREVIEW_CALLBACK_DATA_NULL;
224                 mPreviewDone.open();
225                 return;
226             }
227             Size size = camera.getParameters().getPreviewSize();
228             int format = camera.getParameters().getPreviewFormat();
229             int bitsPerPixel = ImageFormat.getBitsPerPixel(format);
230             if (calculateBufferSize(size.width, size.height,
231                     format, bitsPerPixel) != data.length) {
232                 Log.e(TAG, "Invalid frame size " + data.length + ". width=" + size.width
233                         + ". height=" + size.height + ". bitsPerPixel=" + bitsPerPixel);
234                 mPreviewCallbackResult = PREVIEW_CALLBACK_INVALID_FRAME_SIZE;
235                 mPreviewDone.open();
236                 return;
237             }
238             mPreviewCallbackResult = PREVIEW_CALLBACK_RECEIVED;
239             mCamera.stopPreview();
240             if (LOGV) Log.v(TAG, "notify the preview callback");
241             mPreviewDone.open();
242             if (LOGV) Log.v(TAG, "Preview callback stop");
243         }
244     }
245 
246     //Implement the shutterCallback
247     private final class TestShutterCallback implements ShutterCallback {
onShutter()248         public void onShutter() {
249             mShutterCallbackResult = true;
250             if (LOGV) Log.v(TAG, "onShutter called");
251         }
252     }
253 
254     //Implement the RawPictureCallback
255     private final class RawPictureCallback implements PictureCallback {
onPictureTaken(byte [] rawData, Camera camera)256         public void onPictureTaken(byte [] rawData, Camera camera) {
257             mRawPictureCallbackResult = true;
258             if (LOGV) Log.v(TAG, "RawPictureCallback callback");
259         }
260     }
261 
262     // Implement the JpegPictureCallback
263     private final class JpegPictureCallback implements PictureCallback {
onPictureTaken(byte[] rawData, Camera camera)264         public void onPictureTaken(byte[] rawData, Camera camera) {
265             try {
266                 mJpegData = rawData;
267                 if (rawData != null) {
268                     // try to store the picture on the SD card
269                     File rawoutput = new File(JPEG_PATH);
270                     FileOutputStream outStream = new FileOutputStream(rawoutput);
271                     outStream.write(rawData);
272                     outStream.close();
273                     mJpegPictureCallbackResult = true;
274 
275                     if (LOGV) {
276                         Log.v(TAG, "JpegPictureCallback rawDataLength = " + rawData.length);
277                     }
278                 } else {
279                     mJpegPictureCallbackResult = false;
280                 }
281                 mSnapshotDone.open();
282                 if (LOGV) Log.v(TAG, "Jpeg Picture callback");
283             } catch (IOException e) {
284                 // no need to fail here; callback worked fine
285                 Log.w(TAG, "Error writing picture to sd card.");
286             }
287         }
288     }
289 
290     // Implement the ErrorCallback
291     private final class TestErrorCallback implements ErrorCallback {
onError(int error, Camera camera)292         public void onError(int error, Camera camera) {
293             Log.e(TAG, "Got camera error=" + error);
294             mCameraErrorCode = error;
295         }
296     }
297 
298     private final class AutoFocusCallback
299             implements android.hardware.Camera.AutoFocusCallback {
onAutoFocus(boolean success, Camera camera)300         public void onAutoFocus(boolean success, Camera camera) {
301             mAutoFocusSucceeded = success;
302             Log.v(TAG, "AutoFocusCallback success=" + success);
303             mFocusDone.open();
304         }
305     }
306 
307     private final class AutoFocusMoveCallback
308             implements android.hardware.Camera.AutoFocusMoveCallback {
309         @Override
onAutoFocusMoving(boolean start, Camera camera)310         public void onAutoFocusMoving(boolean start, Camera camera) {
311         }
312     }
313 
waitForPreviewDone()314     private void waitForPreviewDone() {
315         if (LOGV) Log.v(TAG, "Wait for preview callback");
316         if (!mPreviewDone.block(WAIT_FOR_COMMAND_TO_COMPLETE)) {
317             // timeout could be expected or unexpected. The caller will decide.
318             Log.v(TAG, "waitForPreviewDone: timeout");
319         }
320         mPreviewDone.close();
321     }
322 
waitForFocusDone()323     private boolean waitForFocusDone() {
324         boolean result = mFocusDone.block(WAIT_FOR_FOCUS_TO_COMPLETE);
325         if (!result) {
326             // timeout could be expected or unexpected. The caller will decide.
327             Log.v(TAG, "waitForFocusDone: timeout");
328         }
329         mFocusDone.close();
330         return result;
331     }
332 
waitForSnapshotDone()333     private void waitForSnapshotDone() {
334         if (!mSnapshotDone.block(WAIT_FOR_SNAPSHOT_TO_COMPLETE)) {
335             // timeout could be expected or unexpected. The caller will decide.
336             Log.v(TAG, "waitForSnapshotDone: timeout");
337         }
338         mSnapshotDone.close();
339     }
340 
checkPreviewCallback()341     private void checkPreviewCallback() throws Exception {
342         if (LOGV) Log.v(TAG, "check preview callback");
343         mCamera.startPreview();
344         waitForPreviewDone();
345         mCamera.setPreviewCallback(null);
346     }
347 
348     /*
349      * Test case 1: Take a picture and verify all the callback
350      * functions are called properly.
351      */
352     @UiThreadTest
testTakePicture()353     public void testTakePicture() throws Exception {
354         int nCameras = Camera.getNumberOfCameras();
355         for (int id = 0; id < nCameras; id++) {
356             Log.v(TAG, "Camera id=" + id);
357             initializeMessageLooper(id);
358             mCamera.startPreview();
359             subtestTakePictureByCamera(false, 0, 0);
360             terminateMessageLooper();
361         }
362     }
363 
subtestTakePictureByCamera(boolean isVideoSnapshot, int videoWidth, int videoHeight)364     private void subtestTakePictureByCamera(boolean isVideoSnapshot,
365             int videoWidth, int videoHeight) throws Exception {
366         int videoSnapshotMinArea =
367                 videoWidth * videoHeight; // Temporary until new API definitions
368 
369         Size pictureSize = mCamera.getParameters().getPictureSize();
370         mCamera.autoFocus(mAutoFocusCallback);
371         assertTrue(waitForFocusDone());
372         mJpegData = null;
373         mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
374         waitForSnapshotDone();
375         assertTrue("Shutter callback not received", mShutterCallbackResult);
376         assertTrue("Raw picture callback not received", mRawPictureCallbackResult);
377         assertTrue("Jpeg picture callback not recieved", mJpegPictureCallbackResult);
378         assertNotNull(mJpegData);
379         BitmapFactory.Options bmpOptions = new BitmapFactory.Options();
380         bmpOptions.inJustDecodeBounds = true;
381         BitmapFactory.decodeByteArray(mJpegData, 0, mJpegData.length, bmpOptions);
382         if (!isVideoSnapshot) {
383             assertEquals(pictureSize.width, bmpOptions.outWidth);
384             assertEquals(pictureSize.height, bmpOptions.outHeight);
385         } else {
386             int realArea = bmpOptions.outWidth * bmpOptions.outHeight;
387             if (LOGV) Log.v(TAG, "Video snapshot is " +
388                     bmpOptions.outWidth + " x " + bmpOptions.outHeight +
389                     ", video size is " + videoWidth + " x " + videoHeight);
390             assertTrue ("Video snapshot too small! Expected at least " +
391                     videoWidth + " x " + videoHeight + " (" +
392                     videoSnapshotMinArea/1000000. + " MP)",
393                     realArea >= videoSnapshotMinArea);
394         }
395     }
396 
397     @UiThreadTest
testPreviewCallback()398     public void testPreviewCallback() throws Exception {
399         int nCameras = Camera.getNumberOfCameras();
400         for (int id = 0; id < nCameras; id++) {
401             Log.v(TAG, "Camera id=" + id);
402             testPreviewCallbackByCamera(id);
403         }
404     }
405 
testPreviewCallbackByCamera(int cameraId)406     private void testPreviewCallbackByCamera(int cameraId) throws Exception {
407         initializeMessageLooper(cameraId);
408         mCamera.setPreviewCallback(mPreviewCallback);
409         checkPreviewCallback();
410         terminateMessageLooper();
411         assertEquals(PREVIEW_CALLBACK_RECEIVED, mPreviewCallbackResult);
412 
413         mPreviewCallbackResult = PREVIEW_CALLBACK_NOT_RECEIVED;
414         initializeMessageLooper(cameraId);
415         checkPreviewCallback();
416         terminateMessageLooper();
417         assertEquals(PREVIEW_CALLBACK_NOT_RECEIVED, mPreviewCallbackResult);
418 
419         // Test all preview sizes.
420         initializeMessageLooper(cameraId);
421         Parameters parameters = mCamera.getParameters();
422         for (Size size: parameters.getSupportedPreviewSizes()) {
423             mPreviewCallbackResult = PREVIEW_CALLBACK_NOT_RECEIVED;
424             mCamera.setPreviewCallback(mPreviewCallback);
425             parameters.setPreviewSize(size.width, size.height);
426             mCamera.setParameters(parameters);
427             assertEquals(size, mCamera.getParameters().getPreviewSize());
428             checkPreviewCallback();
429             assertEquals(PREVIEW_CALLBACK_RECEIVED, mPreviewCallbackResult);
430             try {
431                 // Wait for a while to throw away the remaining preview frames.
432                 Thread.sleep(1000);
433             } catch(Exception e) {
434                 // ignore
435             }
436             mPreviewDone.close();
437         }
438         terminateMessageLooper();
439     }
440 
441     @UiThreadTest
testSetOneShotPreviewCallback()442     public void testSetOneShotPreviewCallback() throws Exception {
443         int nCameras = Camera.getNumberOfCameras();
444         for (int id = 0; id < nCameras; id++) {
445             Log.v(TAG, "Camera id=" + id);
446             testSetOneShotPreviewCallbackByCamera(id);
447         }
448     }
449 
testSetOneShotPreviewCallbackByCamera(int cameraId)450     private void testSetOneShotPreviewCallbackByCamera(int cameraId) throws Exception {
451         initializeMessageLooper(cameraId);
452         mCamera.setOneShotPreviewCallback(mPreviewCallback);
453         checkPreviewCallback();
454         terminateMessageLooper();
455         assertEquals(PREVIEW_CALLBACK_RECEIVED, mPreviewCallbackResult);
456 
457         mPreviewCallbackResult = PREVIEW_CALLBACK_NOT_RECEIVED;
458         initializeMessageLooper(cameraId);
459         checkPreviewCallback();
460         terminateMessageLooper();
461         assertEquals(PREVIEW_CALLBACK_NOT_RECEIVED, mPreviewCallbackResult);
462     }
463 
464     @UiThreadTest
testSetPreviewDisplay()465     public void testSetPreviewDisplay() throws Exception {
466         int nCameras = Camera.getNumberOfCameras();
467         for (int id = 0; id < nCameras; id++) {
468             Log.v(TAG, "Camera id=" + id);
469             testSetPreviewDisplayByCamera(id);
470         }
471     }
472 
testSetPreviewDisplayByCamera(int cameraId)473     private void testSetPreviewDisplayByCamera(int cameraId) throws Exception {
474         SurfaceHolder holder = getActivity().getSurfaceView().getHolder();
475         initializeMessageLooper(cameraId);
476 
477         // Check the order: startPreview->setPreviewDisplay.
478         mCamera.setOneShotPreviewCallback(mPreviewCallback);
479         mCamera.startPreview();
480         mCamera.setPreviewDisplay(holder);
481         waitForPreviewDone();
482         terminateMessageLooper();
483         assertEquals(PREVIEW_CALLBACK_RECEIVED, mPreviewCallbackResult);
484 
485         // Check the order: setPreviewDisplay->startPreview.
486         initializeMessageLooper(cameraId);
487         mPreviewCallbackResult = PREVIEW_CALLBACK_NOT_RECEIVED;
488         mCamera.setOneShotPreviewCallback(mPreviewCallback);
489         mCamera.setPreviewDisplay(holder);
490         mCamera.startPreview();
491         waitForPreviewDone();
492         mCamera.stopPreview();
493         assertEquals(PREVIEW_CALLBACK_RECEIVED, mPreviewCallbackResult);
494 
495         // Check the order: setting preview display to null->startPreview->
496         // setPreviewDisplay.
497         mPreviewCallbackResult = PREVIEW_CALLBACK_NOT_RECEIVED;
498         mCamera.setOneShotPreviewCallback(mPreviewCallback);
499         mCamera.setPreviewDisplay(null);
500         mCamera.startPreview();
501         mCamera.setPreviewDisplay(holder);
502         waitForPreviewDone();
503         terminateMessageLooper();
504         assertEquals(PREVIEW_CALLBACK_RECEIVED, mPreviewCallbackResult);
505     }
506 
507     @UiThreadTest
testDisplayOrientation()508     public void testDisplayOrientation() throws Exception {
509         int nCameras = Camera.getNumberOfCameras();
510         for (int id = 0; id < nCameras; id++) {
511             Log.v(TAG, "Camera id=" + id);
512             testDisplayOrientationByCamera(id);
513         }
514     }
515 
testDisplayOrientationByCamera(int cameraId)516     private void testDisplayOrientationByCamera(int cameraId) throws Exception {
517         initializeMessageLooper(cameraId);
518 
519         // Check valid arguments.
520         mCamera.setDisplayOrientation(0);
521         mCamera.setDisplayOrientation(90);
522         mCamera.setDisplayOrientation(180);
523         mCamera.setDisplayOrientation(270);
524 
525         // Check invalid arguments.
526         try {
527             mCamera.setDisplayOrientation(45);
528             fail("Should throw exception for invalid arguments");
529         } catch (RuntimeException ex) {
530             // expected
531         }
532 
533         // Start preview.
534         mCamera.startPreview();
535 
536         // Check setting orientation during preview is allowed.
537         mCamera.setDisplayOrientation(90);
538         mCamera.setDisplayOrientation(180);
539         mCamera.setDisplayOrientation(270);
540         mCamera.setDisplayOrientation(00);
541 
542         terminateMessageLooper();
543     }
544 
545     @UiThreadTest
testParameters()546     public void testParameters() throws Exception {
547         int nCameras = Camera.getNumberOfCameras();
548         for (int id = 0; id < nCameras; id++) {
549             Log.v(TAG, "Camera id=" + id);
550             testParametersByCamera(id);
551         }
552     }
553 
testParametersByCamera(int cameraId)554     private void testParametersByCamera(int cameraId) throws Exception {
555         initializeMessageLooper(cameraId);
556         // we can get parameters just by getxxx method due to the private constructor
557         Parameters pSet = mCamera.getParameters();
558         assertParameters(pSet);
559         terminateMessageLooper();
560     }
561 
562     // Also test Camera.Parameters
assertParameters(Parameters parameters)563     private void assertParameters(Parameters parameters) {
564         // Parameters constants
565         final int PICTURE_FORMAT = ImageFormat.JPEG;
566         final int PREVIEW_FORMAT = ImageFormat.NV21;
567 
568         // Before setting Parameters
569         final int origPictureFormat = parameters.getPictureFormat();
570         final int origPictureWidth = parameters.getPictureSize().width;
571         final int origPictureHeight = parameters.getPictureSize().height;
572         final int origPreviewFormat = parameters.getPreviewFormat();
573         final int origPreviewWidth = parameters.getPreviewSize().width;
574         final int origPreviewHeight = parameters.getPreviewSize().height;
575         final int origPreviewFrameRate = parameters.getPreviewFrameRate();
576 
577         assertTrue(origPictureWidth > 0);
578         assertTrue(origPictureHeight > 0);
579         assertTrue(origPreviewWidth > 0);
580         assertTrue(origPreviewHeight > 0);
581         assertTrue(origPreviewFrameRate > 0);
582 
583         // The default preview format must be yuv420 (NV21).
584         assertEquals(ImageFormat.NV21, origPreviewFormat);
585 
586         // The default picture format must be Jpeg.
587         assertEquals(ImageFormat.JPEG, origPictureFormat);
588 
589         // If camera supports flash, the default flash mode must be off.
590         String flashMode = parameters.getFlashMode();
591         assertTrue(flashMode == null || flashMode.equals(parameters.FLASH_MODE_OFF));
592         String wb = parameters.getWhiteBalance();
593         assertTrue(wb == null || wb.equals(parameters.WHITE_BALANCE_AUTO));
594         String effect = parameters.getColorEffect();
595         assertTrue(effect == null || effect.equals(parameters.EFFECT_NONE));
596 
597         // Some parameters must be supported.
598         List<Size> previewSizes = parameters.getSupportedPreviewSizes();
599         List<Size> pictureSizes = parameters.getSupportedPictureSizes();
600         List<Integer> previewFormats = parameters.getSupportedPreviewFormats();
601         List<Integer> pictureFormats = parameters.getSupportedPictureFormats();
602         List<Integer> frameRates = parameters.getSupportedPreviewFrameRates();
603         List<String> focusModes = parameters.getSupportedFocusModes();
604         String focusMode = parameters.getFocusMode();
605         float focalLength = parameters.getFocalLength();
606         float horizontalViewAngle = parameters.getHorizontalViewAngle();
607         float verticalViewAngle = parameters.getVerticalViewAngle();
608         int jpegQuality = parameters.getJpegQuality();
609         int jpegThumnailQuality = parameters.getJpegThumbnailQuality();
610         assertTrue(previewSizes != null && previewSizes.size() != 0);
611         assertTrue(pictureSizes != null && pictureSizes.size() != 0);
612         assertTrue(previewFormats != null && previewFormats.size() >= 2);
613         assertTrue(previewFormats.contains(ImageFormat.NV21));
614         assertTrue(previewFormats.contains(ImageFormat.YV12));
615         assertTrue(pictureFormats != null && pictureFormats.size() != 0);
616         assertTrue(frameRates != null && frameRates.size() != 0);
617         assertTrue(focusModes != null && focusModes.size() != 0);
618         assertNotNull(focusMode);
619         // The default focus mode must be auto if it exists.
620         if (focusModes.contains(Parameters.FOCUS_MODE_AUTO)) {
621             assertEquals(Parameters.FOCUS_MODE_AUTO, focusMode);
622         }
623         assertTrue(focalLength > 0);
624         assertTrue(horizontalViewAngle > 0 && horizontalViewAngle <= 360);
625         assertTrue(verticalViewAngle > 0 && verticalViewAngle <= 360);
626         Size previewSize = previewSizes.get(0);
627         Size pictureSize = pictureSizes.get(0);
628         assertTrue(jpegQuality >= 1 && jpegQuality <= 100);
629         assertTrue(jpegThumnailQuality >= 1 && jpegThumnailQuality <= 100);
630 
631         // If a parameter is supported, both getXXX and getSupportedXXX have to
632         // be non null.
633         if (parameters.getWhiteBalance() != null) {
634             assertNotNull(parameters.getSupportedWhiteBalance());
635         }
636         if (parameters.getSupportedWhiteBalance() != null) {
637             assertNotNull(parameters.getWhiteBalance());
638         }
639         if (parameters.getColorEffect() != null) {
640             assertNotNull(parameters.getSupportedColorEffects());
641         }
642         if (parameters.getSupportedColorEffects() != null) {
643             assertNotNull(parameters.getColorEffect());
644         }
645         if (parameters.getAntibanding() != null) {
646             assertNotNull(parameters.getSupportedAntibanding());
647         }
648         if (parameters.getSupportedAntibanding() != null) {
649             assertNotNull(parameters.getAntibanding());
650         }
651         if (parameters.getSceneMode() != null) {
652             assertNotNull(parameters.getSupportedSceneModes());
653         }
654         if (parameters.getSupportedSceneModes() != null) {
655             assertNotNull(parameters.getSceneMode());
656         }
657         if (parameters.getFlashMode() != null) {
658             assertNotNull(parameters.getSupportedFlashModes());
659         }
660         if (parameters.getSupportedFlashModes() != null) {
661             assertNotNull(parameters.getFlashMode());
662         }
663 
664         // Check if the sizes value contain invalid characters.
665         assertNoLetters(parameters.get("preview-size-values"), "preview-size-values");
666         assertNoLetters(parameters.get("picture-size-values"), "picture-size-values");
667         assertNoLetters(parameters.get("jpeg-thumbnail-size-values"),
668                 "jpeg-thumbnail-size-values");
669 
670         // Set the parameters.
671         parameters.setPictureFormat(PICTURE_FORMAT);
672         assertEquals(PICTURE_FORMAT, parameters.getPictureFormat());
673         parameters.setPictureSize(pictureSize.width, pictureSize.height);
674         assertEquals(pictureSize.width, parameters.getPictureSize().width);
675         assertEquals(pictureSize.height, parameters.getPictureSize().height);
676         parameters.setPreviewFormat(PREVIEW_FORMAT);
677         assertEquals(PREVIEW_FORMAT, parameters.getPreviewFormat());
678         parameters.setPreviewFrameRate(frameRates.get(0));
679         assertEquals(frameRates.get(0).intValue(), parameters.getPreviewFrameRate());
680         parameters.setPreviewSize(previewSize.width, previewSize.height);
681         assertEquals(previewSize.width, parameters.getPreviewSize().width);
682         assertEquals(previewSize.height, parameters.getPreviewSize().height);
683 
684         mCamera.setParameters(parameters);
685         Parameters paramActual = mCamera.getParameters();
686 
687         assertTrue(isValidPixelFormat(paramActual.getPictureFormat()));
688         assertEquals(pictureSize.width, paramActual.getPictureSize().width);
689         assertEquals(pictureSize.height, paramActual.getPictureSize().height);
690         assertTrue(isValidPixelFormat(paramActual.getPreviewFormat()));
691         assertEquals(previewSize.width, paramActual.getPreviewSize().width);
692         assertEquals(previewSize.height, paramActual.getPreviewSize().height);
693         assertTrue(paramActual.getPreviewFrameRate() > 0);
694 
695         checkExposureCompensation(parameters);
696         checkPreferredPreviewSizeForVideo(parameters);
697     }
698 
checkPreferredPreviewSizeForVideo(Parameters parameters)699     private void checkPreferredPreviewSizeForVideo(Parameters parameters) {
700         List<Size> videoSizes = parameters.getSupportedVideoSizes();
701         Size preferredPreviewSize = parameters.getPreferredPreviewSizeForVideo();
702 
703         // If getSupportedVideoSizes() returns null,
704         // getPreferredPreviewSizeForVideo() will return null;
705         // otherwise, if getSupportedVideoSizes() does not return null,
706         // getPreferredPreviewSizeForVideo() will not return null.
707         if (videoSizes == null) {
708             assertNull(preferredPreviewSize);
709         } else {
710             assertNotNull(preferredPreviewSize);
711         }
712 
713         // If getPreferredPreviewSizeForVideo() returns null,
714         // getSupportedVideoSizes() will return null;
715         // otherwise, if getPreferredPreviewSizeForVideo() does not return null,
716         // getSupportedVideoSizes() will not return null.
717         if (preferredPreviewSize == null) {
718             assertNull(videoSizes);
719         } else {
720             assertNotNull(videoSizes);
721         }
722 
723         if (videoSizes != null) {  // implies: preferredPreviewSize != null
724             // If getSupportedVideoSizes() does not return null,
725             // the returned list will contain at least one size.
726             assertTrue(videoSizes.size() > 0);
727 
728             // In addition, getPreferredPreviewSizeForVideo() returns a size
729             // that is among the supported preview sizes.
730             List<Size> previewSizes = parameters.getSupportedPreviewSizes();
731             assertNotNull(previewSizes);
732             assertTrue(previewSizes.size() > 0);
733             assertTrue(previewSizes.contains(preferredPreviewSize));
734         }
735     }
736 
checkExposureCompensation(Parameters parameters)737     private void checkExposureCompensation(Parameters parameters) {
738         assertEquals(0, parameters.getExposureCompensation());
739         int max = parameters.getMaxExposureCompensation();
740         int min = parameters.getMinExposureCompensation();
741         float step = parameters.getExposureCompensationStep();
742         if (max == 0 && min == 0) {
743             assertEquals(0f, step, 0.000001f);
744             return;
745         }
746         assertTrue(step > 0);
747         assertTrue(max >= 0);
748         assertTrue(min <= 0);
749     }
750 
isValidPixelFormat(int format)751     private boolean isValidPixelFormat(int format) {
752         return (format == ImageFormat.RGB_565) || (format == ImageFormat.NV21)
753                 || (format == ImageFormat.JPEG) || (format == ImageFormat.YUY2);
754     }
755 
756     @UiThreadTest
testJpegThumbnailSize()757     public void testJpegThumbnailSize() throws Exception {
758         int nCameras = Camera.getNumberOfCameras();
759         for (int id = 0; id < nCameras; id++) {
760             Log.v(TAG, "Camera id=" + id);
761             initializeMessageLooper(id);
762             testJpegThumbnailSizeByCamera(false, 0, 0);
763             terminateMessageLooper();
764         }
765     }
766 
testJpegThumbnailSizeByCamera(boolean recording, int recordingWidth, int recordingHeight)767     private void testJpegThumbnailSizeByCamera(boolean recording,
768             int recordingWidth, int recordingHeight) throws Exception {
769         // Thumbnail size parameters should have valid values.
770         Parameters p = mCamera.getParameters();
771         Size size = p.getJpegThumbnailSize();
772         assertTrue(size.width > 0 && size.height > 0);
773         List<Size> sizes = p.getSupportedJpegThumbnailSizes();
774         assertTrue(sizes.size() >= 2);
775         assertTrue(sizes.contains(size));
776         assertTrue(sizes.contains(mCamera.new Size(0, 0)));
777         Size pictureSize = p.getPictureSize();
778 
779         // Test if the thumbnail size matches the setting.
780         if (!recording) mCamera.startPreview();
781         mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
782         waitForSnapshotDone();
783         assertTrue(mJpegPictureCallbackResult);
784         ExifInterface exif = new ExifInterface(JPEG_PATH);
785         assertTrue(exif.hasThumbnail());
786         byte[] thumb = exif.getThumbnail();
787         BitmapFactory.Options bmpOptions = new BitmapFactory.Options();
788         bmpOptions.inJustDecodeBounds = true;
789         BitmapFactory.decodeByteArray(thumb, 0, thumb.length, bmpOptions);
790         if (!recording) {
791             assertEquals(size.width, bmpOptions.outWidth);
792             assertEquals(size.height, bmpOptions.outHeight);
793         } else {
794             assertTrue(bmpOptions.outWidth >= recordingWidth ||
795                     bmpOptions.outWidth == size.width);
796             assertTrue(bmpOptions.outHeight >= recordingHeight ||
797                     bmpOptions.outHeight == size.height);
798         }
799 
800         // Test no thumbnail case.
801         p.setJpegThumbnailSize(0, 0);
802         mCamera.setParameters(p);
803         Size actual = mCamera.getParameters().getJpegThumbnailSize();
804         assertEquals(0, actual.width);
805         assertEquals(0, actual.height);
806         if (!recording) mCamera.startPreview();
807         mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
808         waitForSnapshotDone();
809         assertTrue(mJpegPictureCallbackResult);
810         exif = new ExifInterface(JPEG_PATH);
811         assertFalse(exif.hasThumbnail());
812     }
813 
814     @UiThreadTest
testJpegExif()815     public void testJpegExif() throws Exception {
816         int nCameras = Camera.getNumberOfCameras();
817         for (int id = 0; id < nCameras; id++) {
818             Log.v(TAG, "Camera id=" + id);
819             initializeMessageLooper(id);
820             testJpegExifByCamera(false);
821             terminateMessageLooper();
822         }
823     }
824 
testJpegExifByCamera(boolean recording)825     private void testJpegExifByCamera(boolean recording) throws Exception {
826         Camera.Parameters parameters = mCamera.getParameters();
827         if (!recording) mCamera.startPreview();
828         double focalLength = parameters.getFocalLength();
829         Date date = new Date(System.currentTimeMillis());
830         String localDatetime = new SimpleDateFormat("yyyy:MM:dd HH:").format(date);
831 
832         mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
833         waitForSnapshotDone();
834 
835         // Test various exif tags.
836         ExifInterface exif = new ExifInterface(JPEG_PATH);
837         assertNotNull(exif.getAttribute(ExifInterface.TAG_MAKE));
838         assertNotNull(exif.getAttribute(ExifInterface.TAG_MODEL));
839         String datetime = exif.getAttribute(ExifInterface.TAG_DATETIME);
840         assertNotNull(datetime);
841         // Datetime should be local time.
842         assertTrue(datetime.startsWith(localDatetime));
843         assertTrue(datetime.length() == 19); // EXIF spec is "YYYY:MM:DD HH:MM:SS".
844         checkGpsDataNull(exif);
845         double exifFocalLength = exif.getAttributeDouble(ExifInterface.TAG_FOCAL_LENGTH, -1);
846         assertEquals(focalLength, exifFocalLength, 0.001);
847         // Test image width and height exif tags. They should match the jpeg.
848         assertBitmapAndJpegSizeEqual(mJpegData, exif);
849 
850         // Test gps exif tags.
851         testGpsExifValues(parameters, 37.736071, -122.441983, 21, 1199145600,
852             "GPS NETWORK HYBRID ARE ALL FINE.");
853         testGpsExifValues(parameters, 0.736071, 0.441983, 1, 1199145601, "GPS");
854         testGpsExifValues(parameters, -89.736071, -179.441983, 100000, 1199145602, "NETWORK");
855 
856         // Test gps tags do not exist after calling removeGpsData. Also check if
857         // image width and height exif match the jpeg when jpeg rotation is set.
858         if (!recording) mCamera.startPreview();
859         parameters.removeGpsData();
860         parameters.setRotation(90); // For testing image width and height exif.
861         mCamera.setParameters(parameters);
862         mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
863         waitForSnapshotDone();
864         exif = new ExifInterface(JPEG_PATH);
865         checkGpsDataNull(exif);
866         assertBitmapAndJpegSizeEqual(mJpegData, exif);
867         // Reset the rotation to prevent from affecting other tests.
868         parameters.setRotation(0);
869         mCamera.setParameters(parameters);
870     }
871 
assertBitmapAndJpegSizeEqual(byte[] jpegData, ExifInterface exif)872     private void assertBitmapAndJpegSizeEqual(byte[] jpegData, ExifInterface exif) {
873         int exifWidth = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0);
874         int exifHeight = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0);
875         assertTrue(exifWidth != 0 && exifHeight != 0);
876         BitmapFactory.Options bmpOptions = new BitmapFactory.Options();
877         bmpOptions.inJustDecodeBounds = true;
878         BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length, bmpOptions);
879         assertEquals(bmpOptions.outWidth, exifWidth);
880         assertEquals(bmpOptions.outHeight, exifHeight);
881     }
882 
testGpsExifValues(Parameters parameters, double latitude, double longitude, double altitude, long timestamp, String method)883     private void testGpsExifValues(Parameters parameters, double latitude,
884             double longitude, double altitude, long timestamp, String method)
885             throws IOException {
886         mCamera.startPreview();
887         parameters.setGpsLatitude(latitude);
888         parameters.setGpsLongitude(longitude);
889         parameters.setGpsAltitude(altitude);
890         parameters.setGpsTimestamp(timestamp);
891         parameters.setGpsProcessingMethod(method);
892         mCamera.setParameters(parameters);
893         mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
894         waitForSnapshotDone();
895         ExifInterface exif = new ExifInterface(JPEG_PATH);
896         assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE));
897         assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE));
898         assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF));
899         assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF));
900         assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP));
901         assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_DATESTAMP));
902         assertEquals(method, exif.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD));
903         float[] latLong = new float[2];
904         assertTrue(exif.getLatLong(latLong));
905         assertEquals((float)latitude, latLong[0], 0.0001f);
906         assertEquals((float)longitude, latLong[1], 0.0001f);
907         assertEquals(altitude, exif.getAltitude(-1), 1);
908         assertEquals(timestamp, exif.getGpsDateTime() / 1000);
909     }
910 
checkGpsDataNull(ExifInterface exif)911     private void checkGpsDataNull(ExifInterface exif) {
912         assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE));
913         assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE));
914         assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF));
915         assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF));
916         assertNull(exif.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP));
917         assertNull(exif.getAttribute(ExifInterface.TAG_GPS_DATESTAMP));
918         assertNull(exif.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD));
919     }
920 
921     @UiThreadTest
testLockUnlock()922     public void testLockUnlock() throws Exception {
923         int nCameras = Camera.getNumberOfCameras();
924         for (int id = 0; id < nCameras; id++) {
925             Log.v(TAG, "Camera id=" + id);
926             testLockUnlockByCamera(id);
927         }
928     }
929 
testLockUnlockByCamera(int cameraId)930     private void testLockUnlockByCamera(int cameraId) throws Exception {
931         initializeMessageLooper(cameraId);
932         Camera.Parameters parameters = mCamera.getParameters();
933         SurfaceHolder surfaceHolder;
934         surfaceHolder = getActivity().getSurfaceView().getHolder();
935         CamcorderProfile profile = CamcorderProfile.get(cameraId,
936                 CamcorderProfile.QUALITY_LOW);
937 
938         // Set the preview size.
939         setPreviewSizeByProfile(parameters, profile);
940 
941         mCamera.setParameters(parameters);
942         mCamera.setPreviewDisplay(surfaceHolder);
943         mCamera.startPreview();
944         mCamera.lock();  // Locking again from the same process has no effect.
945         try {
946             recordVideo(profile, surfaceHolder);
947             fail("Recording should not succeed because camera is locked.");
948         } catch (Exception e) {
949             // expected
950         }
951 
952         mCamera.unlock();  // Unlock the camera so media recorder can use it.
953         try {
954             mCamera.setParameters(parameters);
955             fail("setParameters should not succeed because camera is unlocked.");
956         } catch (RuntimeException e) {
957             // expected
958         }
959 
960         recordVideo(profile, surfaceHolder);  // should not throw exception
961         // Media recorder already releases the camera so the test application
962         // can lock and use the camera now.
963         mCamera.lock();  // should not fail
964         mCamera.setParameters(parameters);  // should not fail
965         terminateMessageLooper();
966     }
967 
setPreviewSizeByProfile(Parameters parameters, CamcorderProfile profile)968     private void setPreviewSizeByProfile(Parameters parameters, CamcorderProfile profile) {
969         if (parameters.getSupportedVideoSizes() == null) {
970             parameters.setPreviewSize(profile.videoFrameWidth,
971                     profile.videoFrameHeight);
972         } else {  // Driver supports separates outputs for preview and video.
973             List<Size> sizes = parameters.getSupportedPreviewSizes();
974             Size preferred = parameters.getPreferredPreviewSizeForVideo();
975             int product = preferred.width * preferred.height;
976             for (Size size: sizes) {
977                 if (size.width * size.height <= product) {
978                     parameters.setPreviewSize(size.width, size.height);
979                     break;
980                 }
981             }
982         }
983     }
984 
recordVideo(CamcorderProfile profile, SurfaceHolder holder)985     private void recordVideo(CamcorderProfile profile,
986             SurfaceHolder holder) throws Exception {
987         MediaRecorder recorder = new MediaRecorder();
988         try {
989             // Pass the camera from the test application to media recorder.
990             recorder.setCamera(mCamera);
991             recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
992             recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
993             recorder.setProfile(profile);
994             recorder.setOutputFile("/dev/null");
995             recorder.setPreviewDisplay(holder.getSurface());
996             recorder.prepare();
997             recorder.start();
998 
999             // Apps can use the camera after start since API level 13.
1000             Parameters parameters = mCamera.getParameters();
1001             if (parameters.isZoomSupported()) {
1002                if (parameters.getMaxZoom() > 0) {
1003                    parameters.setZoom(1);
1004                    mCamera.setParameters(parameters);
1005                    parameters.setZoom(0);
1006                    mCamera.setParameters(parameters);
1007                }
1008             }
1009             if (parameters.isSmoothZoomSupported()) {
1010                 if (parameters.getMaxZoom() > 0) {
1011                     ZoomListener zoomListener = new ZoomListener();
1012                     mCamera.setZoomChangeListener(zoomListener);
1013                     mCamera.startSmoothZoom(1);
1014                     assertTrue(zoomListener.mZoomDone.block(1000));
1015                 }
1016             }
1017 
1018             try {
1019                 mCamera.unlock();
1020                 fail("unlock should not succeed during recording.");
1021             } catch(RuntimeException e) {
1022                 // expected
1023             }
1024 
1025             Thread.sleep(2000);
1026             recorder.stop();
1027         } finally {
1028             recorder.release();
1029         }
1030     }
1031 
1032     @UiThreadTest
testPreviewCallbackWithBuffer()1033     public void testPreviewCallbackWithBuffer() throws Exception {
1034         int nCameras = Camera.getNumberOfCameras();
1035         for (int id = 0; id < nCameras; id++) {
1036             Log.v(TAG, "Camera id=" + id);
1037             testPreviewCallbackWithBufferByCamera(id);
1038         }
1039     }
1040 
testPreviewCallbackWithBufferByCamera(int cameraId)1041     private void testPreviewCallbackWithBufferByCamera(int cameraId) throws Exception {
1042         initializeMessageLooper(cameraId);
1043         SurfaceHolder surfaceHolder;
1044         surfaceHolder = getActivity().getSurfaceView().getHolder();
1045         mCamera.setPreviewDisplay(surfaceHolder);
1046         Parameters parameters = mCamera.getParameters();
1047         PreviewCallbackWithBuffer callback = new PreviewCallbackWithBuffer();
1048         // Test all preview sizes.
1049         for (Size size: parameters.getSupportedPreviewSizes()) {
1050             parameters.setPreviewSize(size.width, size.height);
1051             mCamera.setParameters(parameters);
1052             assertEquals(size, mCamera.getParameters().getPreviewSize());
1053             callback.mNumCbWithBuffer1 = 0;
1054             callback.mNumCbWithBuffer2 = 0;
1055             callback.mNumCbWithBuffer3 = 0;
1056             int format = mCamera.getParameters().getPreviewFormat();
1057             int bitsPerPixel = ImageFormat.getBitsPerPixel(format);
1058             callback.mBuffer1 = new byte[size.width * size.height * bitsPerPixel / 8];
1059             callback.mBuffer2 = new byte[size.width * size.height * bitsPerPixel / 8];
1060             callback.mBuffer3 = new byte[size.width * size.height * bitsPerPixel / 8];
1061 
1062             // Test if we can get the preview callbacks with specified buffers.
1063             mCamera.addCallbackBuffer(callback.mBuffer1);
1064             mCamera.addCallbackBuffer(callback.mBuffer2);
1065             mCamera.setPreviewCallbackWithBuffer(callback);
1066             mCamera.startPreview();
1067             waitForPreviewDone();
1068             assertFalse(callback.mPreviewDataNull);
1069             assertFalse(callback.mInvalidData);
1070             assertEquals(1, callback.mNumCbWithBuffer1);
1071             assertEquals(1, callback.mNumCbWithBuffer2);
1072             assertEquals(0, callback.mNumCbWithBuffer3);
1073 
1074             // Test if preview callback with buffer still works during preview.
1075             mCamera.addCallbackBuffer(callback.mBuffer3);
1076             waitForPreviewDone();
1077             assertFalse(callback.mPreviewDataNull);
1078             assertFalse(callback.mInvalidData);
1079             assertEquals(1, callback.mNumCbWithBuffer1);
1080             assertEquals(1, callback.mNumCbWithBuffer2);
1081             assertEquals(1, callback.mNumCbWithBuffer3);
1082             mCamera.setPreviewCallbackWithBuffer(null);
1083             mCamera.stopPreview();
1084         }
1085         terminateMessageLooper();
1086     }
1087 
1088     private final class PreviewCallbackWithBuffer
1089             implements android.hardware.Camera.PreviewCallback {
1090         public int mNumCbWithBuffer1, mNumCbWithBuffer2, mNumCbWithBuffer3;
1091         public byte[] mBuffer1, mBuffer2, mBuffer3;
1092         public boolean mPreviewDataNull, mInvalidData;
onPreviewFrame(byte[] data, Camera camera)1093         public void onPreviewFrame(byte[] data, Camera camera) {
1094             if (data == null) {
1095                 Log.e(TAG, "Preview data is null!");
1096                 mPreviewDataNull = true;
1097                 mPreviewDone.open();
1098                 return;
1099             }
1100             if (data == mBuffer1) {
1101                 mNumCbWithBuffer1++;
1102             } else if (data == mBuffer2) {
1103                 mNumCbWithBuffer2++;
1104             } else if (data == mBuffer3) {
1105                 mNumCbWithBuffer3++;
1106             } else {
1107                 Log.e(TAG, "Invalid byte array.");
1108                 mInvalidData = true;
1109                 mPreviewDone.open();
1110                 return;
1111             }
1112 
1113             if ((mNumCbWithBuffer1 == 1 && mNumCbWithBuffer2 == 1)
1114                     || mNumCbWithBuffer3 == 1) {
1115                 mPreviewDone.open();
1116             }
1117         }
1118     }
1119 
1120     @UiThreadTest
testImmediateZoom()1121     public void testImmediateZoom() throws Exception {
1122         int nCameras = Camera.getNumberOfCameras();
1123         for (int id = 0; id < nCameras; id++) {
1124             Log.v(TAG, "Camera id=" + id);
1125             testImmediateZoomByCamera(id);
1126         }
1127     }
1128 
testImmediateZoomByCamera(int id)1129     private void testImmediateZoomByCamera(int id) throws Exception {
1130         initializeMessageLooper(id);
1131 
1132         Parameters parameters = mCamera.getParameters();
1133         if (!parameters.isZoomSupported()) {
1134             terminateMessageLooper();
1135             return;
1136         }
1137 
1138         // Test the zoom parameters.
1139         assertEquals(0, parameters.getZoom());  // default zoom should be 0.
1140         for (Size size: parameters.getSupportedPreviewSizes()) {
1141             parameters = mCamera.getParameters();
1142             parameters.setPreviewSize(size.width, size.height);
1143             mCamera.setParameters(parameters);
1144             parameters = mCamera.getParameters();
1145             int maxZoom = parameters.getMaxZoom();
1146             assertTrue(maxZoom >= 0);
1147 
1148             // Zoom ratios should be sorted from small to large.
1149             List<Integer> ratios = parameters.getZoomRatios();
1150             assertEquals(maxZoom + 1, ratios.size());
1151             assertEquals(100, ratios.get(0).intValue());
1152             for (int i = 0; i < ratios.size() - 1; i++) {
1153                 assertTrue(ratios.get(i) < ratios.get(i + 1));
1154             }
1155             mCamera.startPreview();
1156             waitForPreviewDone();
1157 
1158             // Test each zoom step.
1159             for (int i = 0; i <= maxZoom; i++) {
1160                 parameters.setZoom(i);
1161                 mCamera.setParameters(parameters);
1162                 assertEquals(i, mCamera.getParameters().getZoom());
1163             }
1164 
1165             // It should throw exception if an invalid value is passed.
1166             try {
1167                 parameters.setZoom(maxZoom + 1);
1168                 mCamera.setParameters(parameters);
1169                 fail("setZoom should throw exception.");
1170             } catch (RuntimeException e) {
1171                 // expected
1172             }
1173             assertEquals(maxZoom, mCamera.getParameters().getZoom());
1174 
1175             mCamera.takePicture(mShutterCallback, mRawPictureCallback,
1176                                 mJpegPictureCallback);
1177             waitForSnapshotDone();
1178         }
1179 
1180         terminateMessageLooper();
1181     }
1182 
1183     @UiThreadTest
1184     public void testSmoothZoom() throws Exception {
1185         int nCameras = Camera.getNumberOfCameras();
1186         for (int id = 0; id < nCameras; id++) {
1187             Log.v(TAG, "Camera id=" + id);
1188             testSmoothZoomByCamera(id);
1189         }
1190     }
1191 
1192     private void testSmoothZoomByCamera(int id) throws Exception {
1193         initializeMessageLooper(id);
1194 
1195         Parameters parameters = mCamera.getParameters();
1196         if (!parameters.isSmoothZoomSupported()) {
1197             terminateMessageLooper();
1198             return;
1199         }
1200         assertTrue(parameters.isZoomSupported());
1201 
1202         ZoomListener zoomListener = new ZoomListener();
1203         mCamera.setZoomChangeListener(zoomListener);
1204         mCamera.startPreview();
1205         waitForPreviewDone();
1206 
1207         // Immediate zoom should not generate callbacks.
1208         int maxZoom = parameters.getMaxZoom();
1209         parameters.setZoom(maxZoom);
1210         mCamera.setParameters(parameters);
1211         assertEquals(maxZoom, mCamera.getParameters().getZoom());
1212         parameters.setZoom(0);
1213         mCamera.setParameters(parameters);
1214         assertEquals(0, mCamera.getParameters().getZoom());
1215         assertFalse(zoomListener.mZoomDone.block(500));
1216 
1217         // Nothing will happen if zoom is not moving.
1218         mCamera.stopSmoothZoom();
1219 
1220         // It should not generate callbacks if zoom value is not changed.
1221         mCamera.startSmoothZoom(0);
1222         assertFalse(zoomListener.mZoomDone.block(500));
1223         assertEquals(0, mCamera.getParameters().getZoom());
1224 
1225         // Test startSmoothZoom.
1226         mCamera.startSmoothZoom(maxZoom);
1227         assertEquals(true, zoomListener.mZoomDone.block(5000));
1228         assertEquals(maxZoom, mCamera.getParameters().getZoom());
1229         assertEquals(maxZoom, zoomListener.mValues.size());
1230         for(int i = 0; i < maxZoom; i++) {
1231             int value = zoomListener.mValues.get(i);
1232             boolean stopped = zoomListener.mStopped.get(i);
1233             // Make sure we get all the zoom values in order.
1234             assertEquals(i + 1, value);
1235             // All "stopped" except the last should be false.
1236             assertEquals(i == maxZoom - 1, stopped);
1237         }
1238 
1239         // Test startSmoothZoom. Make sure we get all the callbacks.
1240         if (maxZoom > 1) {
1241             zoomListener.mValues.clear();
1242             zoomListener.mStopped.clear();
1243             Log.e(TAG, "zoomListener.mStopped = " + zoomListener.mStopped);
1244             zoomListener.mZoomDone.close();
1245             mCamera.startSmoothZoom(maxZoom / 2);
1246             assertTrue(zoomListener.mZoomDone.block(5000));
1247             assertEquals(maxZoom / 2, mCamera.getParameters().getZoom());
1248             assertEquals(maxZoom - (maxZoom / 2), zoomListener.mValues.size());
1249             for(int i = 0; i < zoomListener.mValues.size(); i++) {
1250                 int value = zoomListener.mValues.get(i);
1251                 boolean stopped = zoomListener.mStopped.get(i);
1252                 // Make sure we get all the zoom values in order.
1253                 assertEquals(maxZoom - 1 - i, value);
1254                 // All "stopped" except the last should be false.
1255                 assertEquals(i == zoomListener.mValues.size() - 1, stopped);
1256             }
1257         }
1258 
1259         // It should throw exception if an invalid value is passed.
1260         try {
1261             mCamera.startSmoothZoom(maxZoom + 1);
1262             fail("startSmoothZoom should throw exception.");
1263         } catch (IllegalArgumentException e) {
1264             // expected
1265         }
1266 
1267         // Test stopSmoothZoom.
1268         zoomListener.mValues.clear();
1269         zoomListener.mStopped.clear();
1270         zoomListener.mZoomDone.close();
1271         parameters.setZoom(0);
1272         mCamera.setParameters(parameters);
1273         assertEquals(0, mCamera.getParameters().getZoom());
1274         mCamera.startSmoothZoom(maxZoom);
1275         mCamera.stopSmoothZoom();
1276         assertTrue(zoomListener.mZoomDone.block(5000));
1277         assertEquals(zoomListener.mValues.size(), mCamera.getParameters().getZoom());
1278         for(int i = 0; i < zoomListener.mValues.size() - 1; i++) {
1279             int value = zoomListener.mValues.get(i);
1280             boolean stopped = zoomListener.mStopped.get(i);
1281             // Make sure we get all the callbacks in order (except the last).
1282             assertEquals(i + 1, value);
1283             // All "stopped" except the last should be false. stopSmoothZoom has been called. So the
1284             // last "stopped" can be true or false.
1285             if (i != zoomListener.mValues.size() - 1) {
1286                 assertFalse(stopped);
1287             }
1288         }
1289 
1290         terminateMessageLooper();
1291     }
1292 
1293     private final class ZoomListener
1294             implements android.hardware.Camera.OnZoomChangeListener {
1295         public ArrayList<Integer> mValues = new ArrayList<Integer>();
1296         public ArrayList<Boolean> mStopped = new ArrayList<Boolean>();
1297         public final ConditionVariable mZoomDone = new ConditionVariable();
1298 
1299         public void onZoomChange(int value, boolean stopped, Camera camera) {
1300             mValues.add(value);
1301             mStopped.add(stopped);
1302             if (stopped) {
1303                 mZoomDone.open();
1304             }
1305         }
1306     }
1307 
1308     @UiThreadTest
1309     public void testFocusDistances() throws Exception {
1310         int nCameras = Camera.getNumberOfCameras();
1311         for (int id = 0; id < nCameras; id++) {
1312             Log.v(TAG, "Camera id=" + id);
1313             testFocusDistancesByCamera(id);
1314         }
1315     }
1316 
1317     private void testFocusDistancesByCamera(int cameraId) throws Exception {
1318         initializeMessageLooper(cameraId);
1319         mCamera.startPreview();
1320         waitForPreviewDone();
1321         Parameters parameters = mCamera.getParameters();
1322 
1323         // Test every supported focus mode.
1324         for (String focusMode: parameters.getSupportedFocusModes()) {
1325             parameters.setFocusMode(focusMode);
1326             mCamera.setParameters(parameters);
1327             parameters = mCamera.getParameters();
1328             assertEquals(focusMode, parameters.getFocusMode());
1329             checkFocusDistances(parameters);
1330             if (Parameters.FOCUS_MODE_AUTO.equals(focusMode)
1331                     || Parameters.FOCUS_MODE_MACRO.equals(focusMode)
1332                     || Parameters.FOCUS_MODE_CONTINUOUS_VIDEO.equals(focusMode)
1333                     || Parameters.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) {
1334                 Log.v(TAG, "Focus mode=" + focusMode);
1335                 mCamera.autoFocus(mAutoFocusCallback);
1336                 assertTrue(waitForFocusDone());
1337                 parameters = mCamera.getParameters();
1338                 checkFocusDistances(parameters);
1339                 float[] initialFocusDistances = new float[3];
1340                 parameters.getFocusDistances(initialFocusDistances);
1341 
1342                 // Focus position should not change after autoFocus call.
1343                 // Continuous autofocus should have stopped. Sleep some time and
1344                 // check. Make sure continuous autofocus is not working. If the
1345                 // focus mode is auto or macro, it is no harm to do the extra
1346                 // test.
1347                 Thread.sleep(500);
1348                 parameters = mCamera.getParameters();
1349                 float[] currentFocusDistances = new float[3];
1350                 parameters.getFocusDistances(currentFocusDistances);
1351                 assertEquals(initialFocusDistances, currentFocusDistances);
1352 
1353                 // Focus position should not change after stopping preview.
1354                 mCamera.stopPreview();
1355                 parameters = mCamera.getParameters();
1356                 parameters.getFocusDistances(currentFocusDistances);
1357                 assertEquals(initialFocusDistances, currentFocusDistances);
1358 
1359                 // Focus position should not change after taking a picture.
1360                 mCamera.startPreview();
1361                 mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
1362                 waitForSnapshotDone();
1363                 parameters = mCamera.getParameters();
1364                 parameters.getFocusDistances(currentFocusDistances);
1365                 assertEquals(initialFocusDistances, currentFocusDistances);
1366                 mCamera.startPreview();
1367             }
1368         }
1369 
1370         // Test if the method throws exception if the argument is invalid.
1371         try {
1372             parameters.getFocusDistances(null);
1373             fail("getFocusDistances should not accept null.");
1374         } catch (IllegalArgumentException e) {
1375             // expected
1376         }
1377 
1378         try {
1379             parameters.getFocusDistances(new float[2]);
1380             fail("getFocusDistances should not accept a float array with two elements.");
1381         } catch (IllegalArgumentException e) {
1382             // expected
1383         }
1384 
1385         try {
1386             parameters.getFocusDistances(new float[4]);
1387             fail("getFocusDistances should not accept a float array with four elements.");
1388         } catch (IllegalArgumentException e) {
1389             // expected
1390         }
1391         terminateMessageLooper();
1392     }
1393 
1394     private void checkFocusDistances(Parameters parameters) {
1395         float[] distances = new float[3];
1396         parameters.getFocusDistances(distances);
1397 
1398         // Focus distances should be greater than 0.
1399         assertTrue(distances[Parameters.FOCUS_DISTANCE_NEAR_INDEX] > 0);
1400         assertTrue(distances[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX] > 0);
1401         assertTrue(distances[Parameters.FOCUS_DISTANCE_FAR_INDEX] > 0);
1402 
1403         // Make sure far focus distance >= optimal focus distance >= near focus distance.
1404         assertTrue(distances[Parameters.FOCUS_DISTANCE_FAR_INDEX] >=
1405                    distances[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX]);
1406         assertTrue(distances[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX] >=
1407                    distances[Parameters.FOCUS_DISTANCE_NEAR_INDEX]);
1408 
1409         // Far focus distance should be infinity in infinity focus mode.
1410         if (Parameters.FOCUS_MODE_INFINITY.equals(parameters.getFocusMode())) {
1411             assertEquals(Float.POSITIVE_INFINITY,
1412                          distances[Parameters.FOCUS_DISTANCE_FAR_INDEX]);
1413         }
1414     }
1415 
1416     @UiThreadTest
1417     public void testCancelAutofocus() throws Exception {
1418         int nCameras = Camera.getNumberOfCameras();
1419         for (int id = 0; id < nCameras; id++) {
1420             Log.v(TAG, "Camera id=" + id);
1421             testCancelAutofocusByCamera(id);
1422         }
1423     }
1424 
1425     private void testCancelAutofocusByCamera(int cameraId) throws Exception {
1426         initializeMessageLooper(cameraId);
1427         Parameters parameters = mCamera.getParameters();
1428         List<String> focusModes = parameters.getSupportedFocusModes();
1429 
1430         if (focusModes.contains(Parameters.FOCUS_MODE_AUTO)) {
1431             parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
1432         } else if (focusModes.contains(Parameters.FOCUS_MODE_MACRO)) {
1433             parameters.setFocusMode(Parameters.FOCUS_MODE_MACRO);
1434         } else {
1435             terminateMessageLooper();
1436             return;
1437         }
1438 
1439         mCamera.setParameters(parameters);
1440 
1441         // Valid to call outside of preview; should just reset lens or
1442         // be a no-op.
1443         mCamera.cancelAutoFocus();
1444 
1445         mCamera.startPreview();
1446 
1447         // No op if autofocus is not in progress.
1448         mCamera.cancelAutoFocus();
1449 
1450         // Try to cancel autofocus immediately.
1451         mCamera.autoFocus(mAutoFocusCallback);
1452         mCamera.cancelAutoFocus();
1453         checkFocusDistanceNotChanging();
1454 
1455         // Try to cancel autofocus after it starts for some time.
1456         mCamera.autoFocus(mAutoFocusCallback);
1457         Thread.sleep(500);
1458         mCamera.cancelAutoFocus();
1459         checkFocusDistanceNotChanging();
1460 
1461         // Try to cancel autofocus after it completes. It should be no op.
1462         mCamera.autoFocus(mAutoFocusCallback);
1463         assertTrue(waitForFocusDone());
1464         mCamera.cancelAutoFocus();
1465 
1466         // Test the case calling cancelAutoFocus and release in a row.
1467         mCamera.autoFocus(mAutoFocusCallback);
1468         mCamera.cancelAutoFocus();
1469         mCamera.release();
1470 
1471         // Ensure the camera can be opened if release is called right after AF.
1472         mCamera = Camera.open(cameraId);
1473         mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder());
1474         mCamera.startPreview();
1475         mCamera.autoFocus(mAutoFocusCallback);
1476         mCamera.release();
1477 
1478         terminateMessageLooper();
1479     }
1480 
1481     private void checkFocusDistanceNotChanging() throws Exception {
1482         float[] distances1 = new float[3];
1483         float[] distances2 = new float[3];
1484         Parameters parameters = mCamera.getParameters();
1485         parameters.getFocusDistances(distances1);
1486         Thread.sleep(100);
1487         parameters = mCamera.getParameters();
1488         parameters.getFocusDistances(distances2);
1489         assertEquals(distances1[Parameters.FOCUS_DISTANCE_NEAR_INDEX],
1490                      distances2[Parameters.FOCUS_DISTANCE_NEAR_INDEX]);
1491         assertEquals(distances1[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX],
1492                      distances2[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX]);
1493         assertEquals(distances1[Parameters.FOCUS_DISTANCE_FAR_INDEX],
1494                      distances2[Parameters.FOCUS_DISTANCE_FAR_INDEX]);
1495     }
1496 
1497     @UiThreadTest
1498     public void testMultipleCameras() throws Exception {
1499         int nCameras = Camera.getNumberOfCameras();
1500         Log.v(TAG, "total " + nCameras + " cameras");
1501         assertTrue(nCameras >= 0);
1502 
1503         boolean backCameraExist = false;
1504         CameraInfo info = new CameraInfo();
1505         for (int i = 0; i < nCameras; i++) {
1506             Camera.getCameraInfo(i, info);
1507             if (info.facing == CameraInfo.CAMERA_FACING_BACK) {
1508                 backCameraExist = true;
1509                 break;
1510             }
1511         }
1512         // Make sure original open still works. It must return a back-facing
1513         // camera.
1514         mCamera = Camera.open();
1515         if (mCamera != null) {
1516             mCamera.release();
1517             assertTrue(backCameraExist);
1518         } else {
1519             assertFalse(backCameraExist);
1520         }
1521 
1522         for (int id = -1; id <= nCameras; id++) {
1523             Log.v(TAG, "testing camera #" + id);
1524 
1525             boolean isBadId = (id < 0 || id >= nCameras);
1526 
1527             try {
1528                 Camera.getCameraInfo(id, info);
1529                 if (isBadId) {
1530                     fail("getCameraInfo should not accept bad cameraId (" + id + ")");
1531                 }
1532             } catch (RuntimeException e) {
1533                 if (!isBadId) throw e;
1534             }
1535 
1536             int facing = info.facing;
1537             int orientation = info.orientation;
1538             assertTrue(facing == CameraInfo.CAMERA_FACING_BACK ||
1539                        facing == CameraInfo.CAMERA_FACING_FRONT);
1540             assertTrue(orientation == 0 || orientation == 90 ||
1541                        orientation == 180 || orientation == 270);
1542 
1543             Camera camera = null;
1544             try {
1545                 camera = Camera.open(id);
1546                 if (isBadId) {
1547                     fail("open() should not accept bad cameraId (" + id + ")");
1548                 }
1549             } catch (RuntimeException e) {
1550                 if (!isBadId) throw e;
1551             } finally {
1552                 if (camera != null) {
1553                     camera.release();
1554                 }
1555             }
1556         }
1557     }
1558 
1559     @UiThreadTest
1560     public void testPreviewPictureSizesCombination() throws Exception {
1561         int nCameras = Camera.getNumberOfCameras();
1562         for (int id = 0; id < nCameras; id++) {
1563             Log.v(TAG, "Camera id=" + id);
1564             testPreviewPictureSizesCombinationByCamera(id);
1565         }
1566     }
1567 
1568     private void testPreviewPictureSizesCombinationByCamera(int cameraId) throws Exception {
1569         initializeMessageLooper(cameraId);
1570         Parameters parameters = mCamera.getParameters();
1571         PreviewCbForPreviewPictureSizesCombination callback =
1572             new PreviewCbForPreviewPictureSizesCombination();
1573 
1574         // Test combination of preview sizes and picture sizes. Pick four of each to test.
1575         // Do not test all combinations because it will timeout. Four is just a small number
1576         // and the test will not timeout.
1577         List<Size> previewSizes = parameters.getSupportedPreviewSizes();
1578         List<Size> pictureSizes = parameters.getSupportedPictureSizes();
1579         int previewSizeTestCount = Math.min(previewSizes.size(), 4);
1580         int pictureSizeTestCount = Math.min(pictureSizes.size(), 4);
1581         // Calculate the step so that the first one and the last one are always tested.
1582         float previewSizeIndexStep = (float) (previewSizes.size() - 1) / (previewSizeTestCount - 1);
1583         float pictureSizeIndexStep = (float) (pictureSizes.size() - 1) / (pictureSizeTestCount - 1);
1584         for (int i = 0; i < previewSizeTestCount; i++) {
1585             for (int j = 0; j < pictureSizeTestCount; j++) {
1586                 Size previewSize = previewSizes.get(Math.round(previewSizeIndexStep * i));
1587                 Size pictureSize = pictureSizes.get(Math.round(pictureSizeIndexStep * j));
1588                 Log.v(TAG, "Test previewSize=(" + previewSize.width + "," +
1589                         previewSize.height + ") pictureSize=(" +
1590                         pictureSize.width + "," + pictureSize.height + ")");
1591                 mPreviewCallbackResult = PREVIEW_CALLBACK_NOT_RECEIVED;
1592                 mCamera.setPreviewCallback(callback);
1593                 callback.expectedPreviewSize = previewSize;
1594                 parameters.setPreviewSize(previewSize.width, previewSize.height);
1595                 parameters.setPictureSize(pictureSize.width, pictureSize.height);
1596                 mCamera.setParameters(parameters);
1597                 assertEquals(previewSize, mCamera.getParameters().getPreviewSize());
1598                 assertEquals(pictureSize, mCamera.getParameters().getPictureSize());
1599 
1600                 // Check if the preview size is the same as requested.
1601                 mCamera.startPreview();
1602                 waitForPreviewDone();
1603                 assertEquals(PREVIEW_CALLBACK_RECEIVED, mPreviewCallbackResult);
1604 
1605                 // Check if the picture size is the same as requested.
1606                 mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
1607                 waitForSnapshotDone();
1608                 assertTrue(mJpegPictureCallbackResult);
1609                 assertNotNull(mJpegData);
1610                 BitmapFactory.Options bmpOptions = new BitmapFactory.Options();
1611                 bmpOptions.inJustDecodeBounds = true;
1612                 BitmapFactory.decodeByteArray(mJpegData, 0, mJpegData.length, bmpOptions);
1613                 assertEquals(pictureSize.width, bmpOptions.outWidth);
1614                 assertEquals(pictureSize.height, bmpOptions.outHeight);
1615             }
1616         }
1617         terminateMessageLooper();
1618     }
1619 
1620     private final class PreviewCbForPreviewPictureSizesCombination
1621             implements android.hardware.Camera.PreviewCallback {
1622         public Size expectedPreviewSize;
1623         public void onPreviewFrame(byte[] data, Camera camera) {
1624             if (data == null) {
1625                 mPreviewCallbackResult = PREVIEW_CALLBACK_DATA_NULL;
1626                 mPreviewDone.open();
1627                 return;
1628             }
1629             Size size = camera.getParameters().getPreviewSize();
1630             int format = camera.getParameters().getPreviewFormat();
1631             int bitsPerPixel = ImageFormat.getBitsPerPixel(format);
1632             if (!expectedPreviewSize.equals(size) ||
1633                     calculateBufferSize(size.width, size.height,
1634                         format, bitsPerPixel) != data.length) {
1635                 Log.e(TAG, "Expected preview width=" + expectedPreviewSize.width + ", height="
1636                         + expectedPreviewSize.height + ". Actual width=" + size.width + ", height="
1637                         + size.height);
1638                 Log.e(TAG, "Frame data length=" + data.length + ". bitsPerPixel=" + bitsPerPixel);
1639                 mPreviewCallbackResult = PREVIEW_CALLBACK_INVALID_FRAME_SIZE;
1640                 mPreviewDone.open();
1641                 return;
1642             }
1643             camera.setPreviewCallback(null);
1644             mPreviewCallbackResult = PREVIEW_CALLBACK_RECEIVED;
1645             mPreviewDone.open();
1646         }
1647     }
1648 
1649     @UiThreadTest
1650     public void testPreviewFpsRange() throws Exception {
1651         int nCameras = Camera.getNumberOfCameras();
1652         for (int id = 0; id < nCameras; id++) {
1653             Log.v(TAG, "Camera id=" + id);
1654             testPreviewFpsRangeByCamera(id);
1655         }
1656     }
1657 
1658     private void testPreviewFpsRangeByCamera(int cameraId) throws Exception {
1659         initializeMessageLooper(cameraId);
1660 
1661         // Test if the parameters exists and minimum fps <= maximum fps.
1662         int[] defaultFps = new int[2];
1663         Parameters parameters = mCamera.getParameters();
1664         parameters.getPreviewFpsRange(defaultFps);
1665         List<int[]> fpsList = parameters.getSupportedPreviewFpsRange();
1666         assertTrue(fpsList.size() > 0);
1667         boolean found = false;
1668         for(int[] fps: fpsList) {
1669             assertTrue(fps[Parameters.PREVIEW_FPS_MIN_INDEX] > 0);
1670             assertTrue(fps[Parameters.PREVIEW_FPS_MIN_INDEX] <=
1671                        fps[Parameters.PREVIEW_FPS_MAX_INDEX]);
1672             if (!found && Arrays.equals(defaultFps, fps)) {
1673                 found = true;
1674             }
1675         }
1676         assertTrue("Preview fps range must be in the supported list.", found);
1677 
1678         // Test if the list is properly sorted.
1679         for (int i = 0; i < fpsList.size() - 1; i++) {
1680             int minFps1 = fpsList.get(i)[Parameters.PREVIEW_FPS_MIN_INDEX];
1681             int maxFps1 = fpsList.get(i)[Parameters.PREVIEW_FPS_MAX_INDEX];
1682             int minFps2 = fpsList.get(i + 1)[Parameters.PREVIEW_FPS_MIN_INDEX];
1683             int maxFps2 = fpsList.get(i + 1)[Parameters.PREVIEW_FPS_MAX_INDEX];
1684             assertTrue(maxFps1 < maxFps2
1685                     || (maxFps1 == maxFps2 && minFps1 < minFps2));
1686         }
1687 
1688         // Test if the actual fps is within fps range.
1689         Size size = parameters.getPreviewSize();
1690         int format = mCamera.getParameters().getPreviewFormat();
1691         int bitsPerPixel = ImageFormat.getBitsPerPixel(format);
1692         byte[] buffer1 = new byte[size.width * size.height * bitsPerPixel / 8];
1693         byte[] buffer2 = new byte[size.width * size.height * bitsPerPixel / 8];
1694         byte[] buffer3 = new byte[size.width * size.height * bitsPerPixel / 8];
1695         FpsRangePreviewCb callback = new FpsRangePreviewCb();
1696         int[] readBackFps = new int[2];
1697         for (int[] fps: fpsList) {
1698             parameters = mCamera.getParameters();
1699             parameters.setPreviewFpsRange(fps[Parameters.PREVIEW_FPS_MIN_INDEX],
1700                                           fps[Parameters.PREVIEW_FPS_MAX_INDEX]);
1701             callback.reset(fps[Parameters.PREVIEW_FPS_MIN_INDEX] / 1000.0,
1702                            fps[Parameters.PREVIEW_FPS_MAX_INDEX] / 1000.0);
1703             mCamera.setParameters(parameters);
1704             parameters = mCamera.getParameters();
1705             parameters.getPreviewFpsRange(readBackFps);
1706             MoreAsserts.assertEquals(fps, readBackFps);
1707             mCamera.addCallbackBuffer(buffer1);
1708             mCamera.addCallbackBuffer(buffer2);
1709             mCamera.addCallbackBuffer(buffer3);
1710             mCamera.setPreviewCallbackWithBuffer(callback);
1711             mCamera.startPreview();
1712             try {
1713                 // Test the frame rate for a while.
1714                 Thread.sleep(3000);
1715             } catch(Exception e) {
1716                 // ignore
1717             }
1718             mCamera.stopPreview();
1719             // See if any frame duration violations occurred during preview run
1720             AssertionFailedError e = callback.getDurationException();
1721             if (e != null) throw(e);
1722         }
1723 
1724         // Test the invalid fps cases.
1725         parameters = mCamera.getParameters();
1726         parameters.setPreviewFpsRange(-1, -1);
1727         try {
1728             mCamera.setParameters(parameters);
1729             fail("Should throw an exception if fps range is negative.");
1730         } catch (RuntimeException e) {
1731             // expected
1732         }
1733         parameters.setPreviewFpsRange(10, 5);
1734         try {
1735             mCamera.setParameters(parameters);
1736             fail("Should throw an exception if fps range is invalid.");
1737         } catch (RuntimeException e) {
1738             // expected
1739         }
1740 
1741         terminateMessageLooper();
1742     }
1743 
1744     private final class FpsRangePreviewCb
1745             implements android.hardware.Camera.PreviewCallback {
1746         private double mMinFps, mMaxFps, mMaxFrameInterval, mMinFrameInterval;
1747         // An array storing the arrival time of the frames in the last second.
1748         private ArrayList<Long> mFrames = new ArrayList<Long>();
1749         private long firstFrameArrivalTime;
1750         private AssertionFailedError mDurationException = null;
1751 
1752         public void reset(double minFps, double maxFps) {
1753             this.mMinFps = minFps;
1754             this.mMaxFps = maxFps;
1755             mMaxFrameInterval = 1000.0 / mMinFps;
1756             mMinFrameInterval = 1000.0 / mMaxFps;
1757             Log.v(TAG, "Min fps=" + mMinFps + ". Max fps=" + mMaxFps
1758                     + ". Min frame interval=" + mMinFrameInterval
1759                     + ". Max frame interval=" + mMaxFrameInterval);
1760             mFrames.clear();
1761             firstFrameArrivalTime = 0;
1762             mDurationException = null;
1763         }
1764 
1765         // This method tests if the actual fps is between minimum and maximum.
1766         // It also tests if the frame interval is too long.
1767         public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
1768             long arrivalTime = System.currentTimeMillis();
1769             camera.addCallbackBuffer(data);
1770             if (firstFrameArrivalTime == 0) firstFrameArrivalTime = arrivalTime;
1771 
1772             // Remove the frames that arrived before the last second.
1773             Iterator<Long> it = mFrames.iterator();
1774             while(it.hasNext()) {
1775                 long time = it.next();
1776                 if (arrivalTime - time > 1000 && mFrames.size() > 2) {
1777                     it.remove();
1778                 } else {
1779                     break;
1780                 }
1781             }
1782 
1783             // Start the test after one second.
1784             if (arrivalTime - firstFrameArrivalTime > 1000) {
1785                 assertTrue(mFrames.size() >= 2);
1786 
1787                 // Check the frame interval and fps. The interval check
1788                 // considers the time variance passing frames from the camera
1789                 // hardware to the callback. It should be a constant time, not a
1790                 // ratio. The fps check is more strict because individual
1791                 // variance is averaged out.
1792 
1793                 // Check if the frame interval is too large or too small.
1794                 // x100 = percent, intervalMargin should be bigger than
1795                 // fpsMargin considering that fps will be in the order of 10.
1796                 double intervalMargin = 0.9;
1797                 long lastArrivalTime = mFrames.get(mFrames.size() - 1);
1798                 double interval = arrivalTime - lastArrivalTime;
1799                 if (LOGV) Log.v(TAG, "Frame interval=" + interval);
1800                 try {
1801                     assertTrue("Frame interval (" + interval + "ms) is too " +
1802                             "large. mMaxFrameInterval=" +
1803                              mMaxFrameInterval + "ms",
1804                             interval < mMaxFrameInterval *
1805                             (1.0 + intervalMargin));
1806                     assertTrue("Frame interval (" + interval + "ms) is too " +
1807                             "small. mMinFrameInterval=" +
1808                             mMinFrameInterval + "ms",
1809                             interval > mMinFrameInterval *
1810                             (1.0 - intervalMargin));
1811 
1812                     // Check if the fps is within range.
1813                     double fpsMargin = 0.5; // x100 = percent
1814                     double avgInterval = (double)(arrivalTime - mFrames.get(0))
1815                             / mFrames.size();
1816                     double fps = 1000.0 / avgInterval;
1817                     assertTrue("Actual fps (" + fps + ") should be larger " +
1818                             "than min fps (" + mMinFps + ")",
1819                             fps >= mMinFps * (1.0 - fpsMargin));
1820                     assertTrue("Actual fps (" + fps + ") should be smaller" +
1821                             "than max fps (" + mMaxFps + ")",
1822                             fps <= mMaxFps * (1.0 + fpsMargin));
1823                 } catch (AssertionFailedError e) {
1824                     // Need to throw this only in the test body, instead of in
1825                     // the callback
1826                     if (mDurationException == null) {
1827                         mDurationException = e;
1828                     }
1829                 }
1830             }
1831             // Add the arrival time of this frame to the list.
1832             mFrames.add(arrivalTime);
1833         }
1834 
1835         public AssertionFailedError getDurationException() {
1836             return mDurationException;
1837         }
1838     }
1839 
1840     private void assertEquals(Size expected, Size actual) {
1841         assertEquals(expected.width, actual.width);
1842         assertEquals(expected.height, actual.height);
1843     }
1844 
1845     private void assertEquals(float[] expected, float[] actual) {
1846         assertEquals(expected.length, actual.length);
1847         for (int i = 0; i < expected.length; i++) {
1848             assertEquals(expected[i], actual[i], 0.000001f);
1849         }
1850     }
1851 
1852     private void assertNoLetters(String value, String key) {
1853         for (int i = 0; i < value.length(); i++) {
1854             char c = value.charAt(i);
1855             assertFalse("Parameter contains invalid characters. key,value=("
1856                     + key + "," + value + ")",
1857                     Character.isLetter(c) && c != 'x');
1858         }
1859     }
1860 
1861     @UiThreadTest
1862     public void testSceneMode() throws Exception {
1863         int nCameras = Camera.getNumberOfCameras();
1864         for (int id = 0; id < nCameras; id++) {
1865             Log.v(TAG, "Camera id=" + id);
1866             testSceneModeByCamera(id);
1867         }
1868     }
1869 
1870     private class SceneModeSettings {
1871         public String mScene, mFlash, mFocus, mWhiteBalance;
1872         public List<String> mSupportedFlash, mSupportedFocus, mSupportedWhiteBalance;
1873 
1874         public SceneModeSettings(Parameters parameters) {
1875             mScene = parameters.getSceneMode();
1876             mFlash = parameters.getFlashMode();
1877             mFocus = parameters.getFocusMode();
1878             mWhiteBalance = parameters.getWhiteBalance();
1879             mSupportedFlash = parameters.getSupportedFlashModes();
1880             mSupportedFocus = parameters.getSupportedFocusModes();
1881             mSupportedWhiteBalance = parameters.getSupportedWhiteBalance();
1882         }
1883     }
1884 
1885     private void testSceneModeByCamera(int cameraId) throws Exception {
1886         initializeMessageLooper(cameraId);
1887         Parameters parameters = mCamera.getParameters();
1888         List<String> supportedSceneModes = parameters.getSupportedSceneModes();
1889         if (supportedSceneModes != null) {
1890             assertEquals(Parameters.SCENE_MODE_AUTO, parameters.getSceneMode());
1891             SceneModeSettings autoSceneMode = new SceneModeSettings(parameters);
1892 
1893             // Store all scene mode affected settings.
1894             SceneModeSettings[] settings = new SceneModeSettings[supportedSceneModes.size()];
1895             for (int i = 0; i < supportedSceneModes.size(); i++) {
1896                 parameters.setSceneMode(supportedSceneModes.get(i));
1897                 mCamera.setParameters(parameters);
1898                 parameters = mCamera.getParameters();
1899                 settings[i] = new SceneModeSettings(parameters);
1900             }
1901 
1902             // Make sure scene mode settings are consistent before preview and
1903             // after preview.
1904             mCamera.startPreview();
1905             waitForPreviewDone();
1906             for (int i = 0; i < supportedSceneModes.size(); i++) {
1907                 String sceneMode = supportedSceneModes.get(i);
1908                 parameters.setSceneMode(sceneMode);
1909                 mCamera.setParameters(parameters);
1910                 parameters = mCamera.getParameters();
1911 
1912                 // In auto scene mode, camera HAL will not remember the previous
1913                 // flash, focus, and white-balance. It will just take values set
1914                 // by parameters. But the supported flash, focus, and
1915                 // white-balance should still be restored in auto scene mode.
1916                 if (!Parameters.SCENE_MODE_AUTO.equals(sceneMode)) {
1917                     assertEquals("Flash is inconsistent in scene mode " + sceneMode,
1918                             settings[i].mFlash, parameters.getFlashMode());
1919                     assertEquals("Focus is inconsistent in scene mode " + sceneMode,
1920                             settings[i].mFocus, parameters.getFocusMode());
1921                     assertEquals("White balance is inconsistent in scene mode " + sceneMode,
1922                             settings[i].mWhiteBalance, parameters.getWhiteBalance());
1923                 }
1924                 assertEquals("Suppported flash modes are inconsistent in scene mode " + sceneMode,
1925                         settings[i].mSupportedFlash, parameters.getSupportedFlashModes());
1926                 assertEquals("Suppported focus modes are inconsistent in scene mode " + sceneMode,
1927                         settings[i].mSupportedFocus, parameters.getSupportedFocusModes());
1928                 assertEquals("Suppported white balance are inconsistent in scene mode " + sceneMode,
1929                         settings[i].mSupportedWhiteBalance, parameters.getSupportedWhiteBalance());
1930             }
1931 
1932             for (int i = 0; i < settings.length; i++) {
1933                 if (Parameters.SCENE_MODE_AUTO.equals(settings[i].mScene)) continue;
1934 
1935                 // Both the setting and the supported settings may change. It is
1936                 // allowed to have more than one supported settings in scene
1937                 // modes. For example, in night scene mode, supported flash
1938                 // modes can have on and off.
1939                 if (autoSceneMode.mSupportedFlash != null) {
1940                     assertTrue(settings[i].mSupportedFlash.contains(settings[i].mFlash));
1941                     for (String mode: settings[i].mSupportedFlash) {
1942                         assertTrue(autoSceneMode.mSupportedFlash.contains(mode));
1943                     }
1944                 }
1945                 if (autoSceneMode.mSupportedFocus != null) {
1946                     assertTrue(settings[i].mSupportedFocus.contains(settings[i].mFocus));
1947                     for (String mode: settings[i].mSupportedFocus) {
1948                         assertTrue(autoSceneMode.mSupportedFocus.contains(mode));
1949                     }
1950                 }
1951                 if (autoSceneMode.mSupportedWhiteBalance != null) {
1952                     assertTrue(settings[i].mSupportedWhiteBalance.contains(settings[i].mWhiteBalance));
1953                     for (String mode: settings[i].mSupportedWhiteBalance) {
1954                         assertTrue(autoSceneMode.mSupportedWhiteBalance.contains(mode));
1955                     }
1956                 }
1957             }
1958         }
1959         terminateMessageLooper();
1960     }
1961 
1962     @UiThreadTest
1963     public void testInvalidParameters() throws Exception {
1964         int nCameras = Camera.getNumberOfCameras();
1965         for (int id = 0; id < nCameras; id++) {
1966             Log.v(TAG, "Camera id=" + id);
1967             testInvalidParametersByCamera(id);
1968         }
1969     }
1970 
1971     private void testInvalidParametersByCamera(int cameraId) throws Exception {
1972         initializeMessageLooper(cameraId);
1973         // Test flash mode.
1974         Parameters parameters = mCamera.getParameters();
1975         List<String> list = parameters.getSupportedFlashModes();
1976         if (list != null && list.size() > 0) {
1977             String original = parameters.getFlashMode();
1978             parameters.setFlashMode("invalid");
1979             try {
1980                 mCamera.setParameters(parameters);
1981                 fail("Should throw exception for invalid parameters");
1982             } catch (RuntimeException e) {
1983                 // expected
1984             }
1985             parameters = mCamera.getParameters();
1986             assertEquals(original, parameters.getFlashMode());
1987         }
1988 
1989         // Test focus mode.
1990         String originalFocus = parameters.getFocusMode();
1991         parameters.setFocusMode("invalid");
1992         try {
1993             mCamera.setParameters(parameters);
1994             fail("Should throw exception for invalid parameters");
1995         } catch (RuntimeException e) {
1996             // expected
1997         }
1998         parameters = mCamera.getParameters();
1999         assertEquals(originalFocus, parameters.getFocusMode());
2000 
2001         // Test preview size.
2002         Size originalSize = parameters.getPreviewSize();
2003         parameters.setPreviewSize(-1, -1);
2004         try {
2005             mCamera.setParameters(parameters);
2006             fail("Should throw exception for invalid parameters");
2007         } catch (RuntimeException e) {
2008             // expected
2009         }
2010         parameters = mCamera.getParameters();
2011         assertEquals(originalSize, parameters.getPreviewSize());
2012 
2013         terminateMessageLooper();
2014     }
2015 
2016     @UiThreadTest
2017     public void testGetParameterDuringFocus() throws Exception {
2018         int nCameras = Camera.getNumberOfCameras();
2019         for (int id = 0; id < nCameras; id++) {
2020             Log.v(TAG, "Camera id=" + id);
2021             testGetParameterDuringFocusByCamera(id);
2022         }
2023     }
2024 
2025     private void testGetParameterDuringFocusByCamera(int cameraId) throws Exception {
2026         initializeMessageLooper(cameraId);
2027         mCamera.startPreview();
2028         Parameters parameters = mCamera.getParameters();
2029         for (String focusMode: parameters.getSupportedFocusModes()) {
2030             if (focusMode.equals(parameters.FOCUS_MODE_AUTO)
2031                     || focusMode.equals(parameters.FOCUS_MODE_MACRO)) {
2032                 parameters.setFocusMode(focusMode);
2033                 mCamera.setParameters(parameters);
2034                 mCamera.autoFocus(mAutoFocusCallback);
2035                 // This should not crash or throw exception.
2036                 mCamera.getParameters();
2037                 waitForFocusDone();
2038 
2039 
2040                 mCamera.autoFocus(mAutoFocusCallback);
2041                 // Add a small delay to make sure focus has started.
2042                 Thread.sleep(100);
2043                 // This should not crash or throw exception.
2044                 mCamera.getParameters();
2045                 waitForFocusDone();
2046             }
2047         }
2048         terminateMessageLooper();
2049     }
2050 
2051     @UiThreadTest
2052     public void testPreviewFormats() throws Exception {
2053         int nCameras = Camera.getNumberOfCameras();
2054         for (int id = 0; id < nCameras; id++) {
2055             Log.v(TAG, "Camera id=" + id);
2056             testPreviewFormatsByCamera(id);
2057         }
2058     }
2059 
2060     private void testPreviewFormatsByCamera(int cameraId) throws Exception {
2061         initializeMessageLooper(cameraId);
2062         Parameters parameters = mCamera.getParameters();
2063         for (int format: parameters.getSupportedPreviewFormats()) {
2064             Log.v(TAG, "Test preview format " + format);
2065             parameters.setPreviewFormat(format);
2066             mCamera.setParameters(parameters);
2067             mCamera.setOneShotPreviewCallback(mPreviewCallback);
2068             mCamera.startPreview();
2069             waitForPreviewDone();
2070             assertEquals(PREVIEW_CALLBACK_RECEIVED, mPreviewCallbackResult);
2071         }
2072         terminateMessageLooper();
2073     }
2074 
2075     @UiThreadTest
2076     public void testMultiCameraRelease() throws Exception {
2077         // Verify that multiple cameras exist, and that they can be opened at the same time
2078         if (LOGV) Log.v(TAG, "testMultiCameraRelease: Checking pre-conditions.");
2079         int nCameras = Camera.getNumberOfCameras();
2080         if (nCameras < 2) {
2081             Log.i(TAG, "Test multi-camera release: Skipping test because only 1 camera available");
2082             return;
2083         }
2084 
2085         Camera testCamera0 = Camera.open(0);
2086         Camera testCamera1 = null;
2087         try {
2088             testCamera1 = Camera.open(1);
2089         } catch (RuntimeException e) {
2090             // Can't open two cameras at once
2091             Log.i(TAG, "testMultiCameraRelease: Skipping test because only 1 camera "+
2092                   "could be opened at once. Second open threw: " + e);
2093             testCamera0.release();
2094             return;
2095         }
2096         testCamera0.release();
2097         testCamera1.release();
2098 
2099         // Start first camera
2100         if (LOGV) Log.v(TAG, "testMultiCameraRelease: Opening camera 0");
2101         initializeMessageLooper(0);
2102         SimplePreviewStreamCb callback0 = new SimplePreviewStreamCb(0);
2103         mCamera.setPreviewCallback(callback0);
2104         if (LOGV) Log.v(TAG, "testMultiCameraRelease: Starting preview on camera 0");
2105         mCamera.startPreview();
2106         // Run preview for a bit
2107         for (int f = 0; f < 100; f++) {
2108             mPreviewDone.close();
2109             assertTrue("testMultiCameraRelease: First camera preview timed out on frame " + f + "!",
2110                        mPreviewDone.block( WAIT_FOR_COMMAND_TO_COMPLETE));
2111         }
2112         if (LOGV) Log.v(TAG, "testMultiCameraRelease: Stopping preview on camera 0");
2113         mCamera.stopPreview();
2114         // Save message looper and camera to deterministically release them, instead
2115         // of letting GC do it at some point.
2116         Camera firstCamera = mCamera;
2117         Looper firstLooper = mLooper;
2118         //terminateMessageLooper(); // Intentionally not calling this
2119         // Preview surface should be released though!
2120         mCamera.setPreviewDisplay(null);
2121 
2122         // Start second camera without releasing the first one (will
2123         // set mCamera and mLooper to new objects)
2124         if (LOGV) Log.v(TAG, "testMultiCameraRelease: Opening camera 1");
2125         initializeMessageLooper(1);
2126         SimplePreviewStreamCb callback1 = new SimplePreviewStreamCb(1);
2127         mCamera.setPreviewCallback(callback1);
2128         if (LOGV) Log.v(TAG, "testMultiCameraRelease: Starting preview on camera 1");
2129         mCamera.startPreview();
2130         // Run preview for a bit - GC of first camera instance should not impact the second's
2131         // operation.
2132         for (int f = 0; f < 100; f++) {
2133             mPreviewDone.close();
2134             assertTrue("testMultiCameraRelease: Second camera preview timed out on frame " + f + "!",
2135                        mPreviewDone.block( WAIT_FOR_COMMAND_TO_COMPLETE));
2136             if (f == 50) {
2137                 // Release first camera mid-preview, should cause no problems
2138                 if (LOGV) Log.v(TAG, "testMultiCameraRelease: Releasing camera 0");
2139                 firstCamera.release();
2140             }
2141         }
2142         if (LOGV) Log.v(TAG, "testMultiCameraRelease: Stopping preview on camera 0");
2143         mCamera.stopPreview();
2144 
2145         firstLooper.quit();
2146         terminateMessageLooper();
2147     }
2148 
2149     // This callback just signals on the condition variable, making it useful for checking that
2150     // preview callbacks don't stop unexpectedly
2151     private final class SimplePreviewStreamCb
2152             implements android.hardware.Camera.PreviewCallback {
2153         private int mId;
2154         public SimplePreviewStreamCb(int id) {
2155             mId = id;
2156         }
2157         public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
2158             if (LOGV) Log.v(TAG, "Preview frame callback, id " + mId + ".");
2159             mPreviewDone.open();
2160         }
2161     }
2162 
2163     @UiThreadTest
2164     public void testFocusAreas() throws Exception {
2165         int nCameras = Camera.getNumberOfCameras();
2166         for (int id = 0; id < nCameras; id++) {
2167             Log.v(TAG, "Camera id=" + id);
2168 
2169             initializeMessageLooper(id);
2170             Parameters parameters = mCamera.getParameters();
2171             int maxNumFocusAreas = parameters.getMaxNumFocusAreas();
2172             assertTrue(maxNumFocusAreas >= 0);
2173             if (maxNumFocusAreas > 0) {
2174                 List<String> focusModes = parameters.getSupportedFocusModes();
2175                 assertTrue(focusModes.contains(Parameters.FOCUS_MODE_AUTO));
2176                 testAreas(FOCUS_AREA, maxNumFocusAreas);
2177             }
2178             terminateMessageLooper();
2179         }
2180     }
2181 
2182     @UiThreadTest
2183     public void testMeteringAreas() throws Exception {
2184         int nCameras = Camera.getNumberOfCameras();
2185         for (int id = 0; id < nCameras; id++) {
2186             Log.v(TAG, "Camera id=" + id);
2187             initializeMessageLooper(id);
2188             Parameters parameters = mCamera.getParameters();
2189             int maxNumMeteringAreas = parameters.getMaxNumMeteringAreas();
2190             assertTrue(maxNumMeteringAreas >= 0);
2191             if (maxNumMeteringAreas > 0) {
2192                 testAreas(METERING_AREA, maxNumMeteringAreas);
2193             }
2194             terminateMessageLooper();
2195         }
2196     }
2197 
2198     private void testAreas(int type, int maxNumAreas) throws Exception {
2199         mCamera.startPreview();
2200 
2201         // Test various valid cases.
2202         testValidAreas(type, null);                                  // the default area
2203         testValidAreas(type, makeAreas(-1000, -1000, 1000, 1000, 1)); // biggest area
2204         testValidAreas(type, makeAreas(-500, -500, 500, 500, 1000)); // medium area & biggest weight
2205         testValidAreas(type, makeAreas(0, 0, 1, 1, 1));              // smallest area
2206 
2207         ArrayList<Area> areas = new ArrayList();
2208         if (maxNumAreas > 1) {
2209             // Test overlapped areas.
2210             testValidAreas(type, makeAreas(-250, -250, 250, 250, 1, 0, 0, 500, 500, 2));
2211             // Test completely disjoint areas.
2212             testValidAreas(type, makeAreas(-250, -250, 0, 0, 1, 900, 900, 1000, 1000, 1));
2213             // Test the maximum number of areas.
2214             testValidAreas(type, makeAreas(-1000, -1000, 1000, 1000, 1000, maxNumAreas));
2215         }
2216 
2217         // Test various invalid cases.
2218         testInvalidAreas(type, makeAreas(-1001, -1000, 1000, 1000, 1));    // left should >= -1000
2219         testInvalidAreas(type, makeAreas(-1000, -1001, 1000, 1000, 1));    // top should >= -1000
2220         testInvalidAreas(type, makeAreas(-1000, -1000, 1001, 1000, 1));    // right should <= 1000
2221         testInvalidAreas(type, makeAreas(-1000, -1000, 1000, 1001, 1));    // bottom should <= 1000
2222         testInvalidAreas(type, makeAreas(-1000, -1000, 1000, 1000, 0));    // weight should >= 1
2223         testInvalidAreas(type, makeAreas(-1000, -1000, 1000, 1001, 1001)); // weight should <= 1000
2224         testInvalidAreas(type, makeAreas(500, -1000, 500, 1000, 1));       // left should < right
2225         testInvalidAreas(type, makeAreas(-1000, 500, 1000, 500, 1));       // top should < bottom
2226         testInvalidAreas(type, makeAreas(500, -1000, 499, 1000, 1));       // left should < right
2227         testInvalidAreas(type, makeAreas(-1000, 500, 100, 499, 1));        // top should < bottom
2228         testInvalidAreas(type, makeAreas(-250, -250, 250, 250, -1));       // weight should >= 1
2229         // Test when the number of areas exceeds maximum.
2230         testInvalidAreas(type, makeAreas(-1000, -1000, 1000, 1000, 1000, maxNumAreas + 1));
2231     }
2232 
2233     private static ArrayList<Area> makeAreas(int left, int top, int right, int bottom, int weight) {
2234         ArrayList<Area> areas = new ArrayList<Area>();
2235         areas.add(new Area(new Rect(left, top, right, bottom), weight));
2236         return areas;
2237     }
2238 
2239     private static ArrayList<Area> makeAreas(int left, int top, int right, int bottom,
2240             int weight, int number) {
2241         ArrayList<Area> areas = new ArrayList<Area>();
2242         for (int i = 0; i < number; i++) {
2243             areas.add(new Area(new Rect(left, top, right, bottom), weight));
2244         }
2245         return areas;
2246     }
2247 
2248     private static ArrayList<Area> makeAreas(int left1, int top1, int right1,
2249             int bottom1, int weight1, int left2, int top2, int right2,
2250             int bottom2, int weight2) {
2251         ArrayList<Area> areas = new ArrayList<Area>();
2252         areas.add(new Area(new Rect(left1, top1, right1, bottom1), weight1));
2253         areas.add(new Area(new Rect(left2, top2, right2, bottom2), weight2));
2254         return areas;
2255     }
2256 
2257     private void testValidAreas(int areaType, ArrayList<Area> areas) {
2258         if (areaType == FOCUS_AREA) {
2259             testValidFocusAreas(areas);
2260         } else {
2261             testValidMeteringAreas(areas);
2262         }
2263     }
2264 
2265     private void testInvalidAreas(int areaType, ArrayList<Area> areas) {
2266         if (areaType == FOCUS_AREA) {
2267             testInvalidFocusAreas(areas);
2268         } else {
2269             testInvalidMeteringAreas(areas);
2270         }
2271     }
2272 
2273     private void testValidFocusAreas(ArrayList<Area> areas) {
2274         Parameters parameters = mCamera.getParameters();
2275         parameters.setFocusAreas(areas);
2276         mCamera.setParameters(parameters);
2277         parameters = mCamera.getParameters();
2278         assertEquals(areas, parameters.getFocusAreas());
2279         mCamera.autoFocus(mAutoFocusCallback);
2280         waitForFocusDone();
2281     }
2282 
2283     private void testInvalidFocusAreas(ArrayList<Area> areas) {
2284         Parameters parameters = mCamera.getParameters();
2285         List<Area> originalAreas = parameters.getFocusAreas();
2286         try {
2287             parameters.setFocusAreas(areas);
2288             mCamera.setParameters(parameters);
2289             fail("Should throw exception when focus area is invalid.");
2290         } catch (RuntimeException e) {
2291             parameters = mCamera.getParameters();
2292             assertEquals(originalAreas, parameters.getFocusAreas());
2293         }
2294     }
2295 
2296     private void testValidMeteringAreas(ArrayList<Area> areas) {
2297         Parameters parameters = mCamera.getParameters();
2298         parameters.setMeteringAreas(areas);
2299         mCamera.setParameters(parameters);
2300         parameters = mCamera.getParameters();
2301         assertEquals(areas, parameters.getMeteringAreas());
2302     }
2303 
2304     private void testInvalidMeteringAreas(ArrayList<Area> areas) {
2305         Parameters parameters = mCamera.getParameters();
2306         List<Area> originalAreas = parameters.getMeteringAreas();
2307         try {
2308             parameters.setMeteringAreas(areas);
2309             mCamera.setParameters(parameters);
2310             fail("Should throw exception when metering area is invalid.");
2311         } catch (RuntimeException e) {
2312             parameters = mCamera.getParameters();
2313             assertEquals(originalAreas, parameters.getMeteringAreas());
2314         }
2315     }
2316 
2317     // Apps should be able to call startPreview in jpeg callback.
2318     @UiThreadTest
2319     public void testJpegCallbackStartPreview() throws Exception {
2320         int nCameras = Camera.getNumberOfCameras();
2321         for (int id = 0; id < nCameras; id++) {
2322             Log.v(TAG, "Camera id=" + id);
2323             testJpegCallbackStartPreviewByCamera(id);
2324         }
2325     }
2326 
2327     private void testJpegCallbackStartPreviewByCamera(int cameraId) throws Exception {
2328         initializeMessageLooper(cameraId);
2329         mCamera.startPreview();
2330         mCamera.takePicture(mShutterCallback, mRawPictureCallback, new JpegStartPreviewCallback());
2331         waitForSnapshotDone();
2332         terminateMessageLooper();
2333         assertTrue(mJpegPictureCallbackResult);
2334     }
2335 
2336     private final class JpegStartPreviewCallback implements PictureCallback {
2337         public void onPictureTaken(byte[] rawData, Camera camera) {
2338             try {
2339                 camera.startPreview();
2340                 mJpegPictureCallbackResult = true;
2341             } catch (Exception e) {
2342             }
2343             mSnapshotDone.open();
2344         }
2345     }
2346 
2347     @UiThreadTest
2348     public void testRecordingHint() throws Exception {
2349         int nCameras = Camera.getNumberOfCameras();
2350         for (int id = 0; id < nCameras; id++) {
2351             Log.v(TAG, "Camera id=" + id);
2352             testRecordingHintByCamera(id);
2353         }
2354     }
2355 
2356     private void testRecordingHintByCamera(int cameraId) throws Exception {
2357         initializeMessageLooper(cameraId);
2358         Parameters parameters = mCamera.getParameters();
2359 
2360         SurfaceHolder holder = getActivity().getSurfaceView().getHolder();
2361         CamcorderProfile profile = CamcorderProfile.get(cameraId,
2362                 CamcorderProfile.QUALITY_LOW);
2363 
2364         setPreviewSizeByProfile(parameters, profile);
2365 
2366         // Test recording videos and taking pictures when the hint is off and on.
2367         for (int i = 0; i < 2; i++) {
2368             parameters.setRecordingHint(i == 0 ? false : true);
2369             mCamera.setParameters(parameters);
2370             mCamera.startPreview();
2371             recordVideoSimple(profile, holder);
2372             mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
2373             waitForSnapshotDone();
2374             assertTrue(mJpegPictureCallbackResult);
2375         }
2376 
2377         // Can change recording hint when the preview is active.
2378         mCamera.startPreview();
2379         parameters.setRecordingHint(false);
2380         mCamera.setParameters(parameters);
2381         parameters.setRecordingHint(true);
2382         mCamera.setParameters(parameters);
2383         terminateMessageLooper();
2384     }
2385 
2386     private void recordVideoSimple(CamcorderProfile profile,
2387             SurfaceHolder holder) throws Exception {
2388         mCamera.unlock();
2389         MediaRecorder recorder = new MediaRecorder();
2390         try {
2391             recorder.setCamera(mCamera);
2392             recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
2393             recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
2394             recorder.setProfile(profile);
2395             recorder.setOutputFile("/dev/null");
2396             recorder.setPreviewDisplay(holder.getSurface());
2397             recorder.prepare();
2398             recorder.start();
2399             Thread.sleep(2000);
2400             recorder.stop();
2401         } finally {
2402             recorder.release();
2403             mCamera.lock();
2404         }
2405     }
2406 
2407     @UiThreadTest
2408     public void testAutoExposureLock() throws Exception {
2409         int nCameras = Camera.getNumberOfCameras();
2410         for (int id = 0; id < nCameras; id++) {
2411             Log.v(TAG, "Camera id=" + id);
2412             initializeMessageLooper(id);
2413             Parameters parameters = mCamera.getParameters();
2414             boolean aeLockSupported = parameters.isAutoExposureLockSupported();
2415             if (aeLockSupported) {
2416                 subtestLockCommon(AUTOEXPOSURE_LOCK);
2417                 subtestLockAdditionalAE();
2418             }
2419             terminateMessageLooper();
2420         }
2421     }
2422 
2423     @UiThreadTest
2424     public void testAutoWhiteBalanceLock() throws Exception {
2425         int nCameras = Camera.getNumberOfCameras();
2426         for (int id = 0; id < nCameras; id++) {
2427             Log.v(TAG, "Camera id=" + id);
2428             initializeMessageLooper(id);
2429             Parameters parameters = mCamera.getParameters();
2430             boolean awbLockSupported = parameters.isAutoWhiteBalanceLockSupported();
2431             if (awbLockSupported) {
2432                 subtestLockCommon(AUTOWHITEBALANCE_LOCK);
2433                 subtestLockAdditionalAWB();
2434             }
2435             terminateMessageLooper();
2436         }
2437     }
2438 
2439     @UiThreadTest
2440     public void test3ALockInteraction() throws Exception {
2441         int nCameras = Camera.getNumberOfCameras();
2442         for (int id = 0; id < nCameras; id++) {
2443             Log.v(TAG, "Camera id=" + id);
2444             initializeMessageLooper(id);
2445             Parameters parameters = mCamera.getParameters();
2446             boolean locksSupported =
2447                     parameters.isAutoWhiteBalanceLockSupported() &&
2448                     parameters.isAutoExposureLockSupported();
2449             if (locksSupported) {
2450                 subtestLockInteractions();
2451             }
2452             terminateMessageLooper();
2453         }
2454     }
2455 
2456     private void subtestLockCommon(int type) {
2457         // Verify lock is not set on open()
2458         assert3ALockState("Lock not released after open()", type, false);
2459 
2460         // Verify lock can be set, unset before preview
2461         set3ALockState(true, type);
2462         assert3ALockState("Lock could not be set before 1st preview!",
2463                 type, true);
2464 
2465         set3ALockState(false, type);
2466         assert3ALockState("Lock could not be unset before 1st preview!",
2467                 type, false);
2468 
2469         // Verify preview start does not set lock
2470         mCamera.startPreview();
2471         assert3ALockState("Lock state changed by preview start!", type, false);
2472 
2473         // Verify lock can be set, unset during preview
2474         set3ALockState(true, type);
2475         assert3ALockState("Lock could not be set during preview!", type, true);
2476 
2477         set3ALockState(false, type);
2478         assert3ALockState("Lock could not be unset during preview!",
2479                 type, false);
2480 
2481         // Verify lock is not cleared by stop preview
2482         set3ALockState(true, type);
2483         mCamera.stopPreview();
2484         assert3ALockState("Lock was cleared by stopPreview!", type, true);
2485 
2486         // Verify that preview start does not clear lock
2487         set3ALockState(true, type);
2488         mCamera.startPreview();
2489         assert3ALockState("Lock state changed by preview start!", type, true);
2490 
2491         // Verify that taking a picture does not clear the lock
2492         set3ALockState(true, type);
2493         mCamera.takePicture(mShutterCallback, mRawPictureCallback,
2494                 mJpegPictureCallback);
2495         waitForSnapshotDone();
2496         assert3ALockState("Lock state was cleared by takePicture!", type, true);
2497 
2498         mCamera.startPreview();
2499         Parameters parameters = mCamera.getParameters();
2500         for (String focusMode: parameters.getSupportedFocusModes()) {
2501             // TODO: Test this for other focus modes as well, once agreement is
2502             // reached on which ones it should apply to
2503             if (!Parameters.FOCUS_MODE_AUTO.equals(focusMode) ) {
2504                 continue;
2505             }
2506 
2507             parameters.setFocusMode(focusMode);
2508             mCamera.setParameters(parameters);
2509 
2510             // Verify that autoFocus does not change the lock
2511             set3ALockState(false, type);
2512             mCamera.autoFocus(mAutoFocusCallback);
2513             assert3ALockState("Lock was set by autoFocus in mode: " + focusMode, type, false);
2514             assertTrue(waitForFocusDone());
2515             assert3ALockState("Lock was set by autoFocus in mode: " + focusMode, type, false);
2516 
2517             // Verify that cancelAutoFocus does not change the lock
2518             mCamera.cancelAutoFocus();
2519             assert3ALockState("Lock was set by cancelAutoFocus!", type, false);
2520 
2521             // Verify that autoFocus does not change the lock
2522             set3ALockState(true, type);
2523             mCamera.autoFocus(mAutoFocusCallback);
2524             assert3ALockState("Lock was cleared by autoFocus in mode: " + focusMode, type, true);
2525             assertTrue(waitForFocusDone());
2526             assert3ALockState("Lock was cleared by autoFocus in mode: " + focusMode, type, true);
2527 
2528             // Verify that cancelAutoFocus does not change the lock
2529             mCamera.cancelAutoFocus();
2530             assert3ALockState("Lock was cleared by cancelAutoFocus!", type, true);
2531         }
2532         mCamera.stopPreview();
2533     }
2534 
2535     private void subtestLockAdditionalAE() {
2536         // Verify that exposure compensation can be used while
2537         // AE lock is active
2538         mCamera.startPreview();
2539         Parameters parameters = mCamera.getParameters();
2540         parameters.setAutoExposureLock(true);
2541         mCamera.setParameters(parameters);
2542         parameters.setExposureCompensation(parameters.getMaxExposureCompensation());
2543         mCamera.setParameters(parameters);
2544         parameters = mCamera.getParameters();
2545         assertTrue("Could not adjust exposure compensation with AE locked!",
2546                 parameters.getExposureCompensation() ==
2547                 parameters.getMaxExposureCompensation() );
2548 
2549         parameters.setExposureCompensation(parameters.getMinExposureCompensation());
2550         mCamera.setParameters(parameters);
2551         parameters = mCamera.getParameters();
2552         assertTrue("Could not adjust exposure compensation with AE locked!",
2553                 parameters.getExposureCompensation() ==
2554                 parameters.getMinExposureCompensation() );
2555         mCamera.stopPreview();
2556     }
2557 
2558     private void subtestLockAdditionalAWB() {
2559         // Verify that switching AWB modes clears AWB lock
2560         mCamera.startPreview();
2561         Parameters parameters = mCamera.getParameters();
2562         String firstWb = null;
2563         for ( String wbMode: parameters.getSupportedWhiteBalance() ) {
2564             if (firstWb == null) {
2565                 firstWb = wbMode;
2566             }
2567             parameters.setWhiteBalance(firstWb);
2568             mCamera.setParameters(parameters);
2569             parameters.setAutoWhiteBalanceLock(true);
2570             mCamera.setParameters(parameters);
2571 
2572             parameters.setWhiteBalance(wbMode);
2573             mCamera.setParameters(parameters);
2574 
2575             if (firstWb == wbMode) {
2576                 assert3ALockState("AWB lock was cleared when WB mode was unchanged!",
2577                         AUTOWHITEBALANCE_LOCK, true);
2578             } else {
2579                 assert3ALockState("Changing WB mode did not clear AWB lock!",
2580                         AUTOWHITEBALANCE_LOCK, false);
2581             }
2582         }
2583         mCamera.stopPreview();
2584     }
2585 
2586     private void subtestLockInteractions() {
2587         // Verify that toggling AE does not change AWB lock state
2588         set3ALockState(false, AUTOWHITEBALANCE_LOCK);
2589         set3ALockState(false, AUTOEXPOSURE_LOCK);
2590 
2591         set3ALockState(true, AUTOEXPOSURE_LOCK);
2592         assert3ALockState("Changing AE lock affected AWB lock!",
2593                 AUTOWHITEBALANCE_LOCK, false);
2594 
2595         set3ALockState(false, AUTOEXPOSURE_LOCK);
2596         assert3ALockState("Changing AE lock affected AWB lock!",
2597                 AUTOWHITEBALANCE_LOCK, false);
2598 
2599         set3ALockState(true, AUTOWHITEBALANCE_LOCK);
2600 
2601         set3ALockState(true, AUTOEXPOSURE_LOCK);
2602         assert3ALockState("Changing AE lock affected AWB lock!",
2603                 AUTOWHITEBALANCE_LOCK, true);
2604 
2605         set3ALockState(false, AUTOEXPOSURE_LOCK);
2606         assert3ALockState("Changing AE lock affected AWB lock!",
2607                 AUTOWHITEBALANCE_LOCK, true);
2608 
2609         // Verify that toggling AWB does not change AE lock state
2610         set3ALockState(false, AUTOWHITEBALANCE_LOCK);
2611         set3ALockState(false, AUTOEXPOSURE_LOCK);
2612 
2613         set3ALockState(true, AUTOWHITEBALANCE_LOCK);
2614         assert3ALockState("Changing AWB lock affected AE lock!",
2615                 AUTOEXPOSURE_LOCK, false);
2616 
2617         set3ALockState(false, AUTOWHITEBALANCE_LOCK);
2618         assert3ALockState("Changing AWB lock affected AE lock!",
2619                 AUTOEXPOSURE_LOCK, false);
2620 
2621         set3ALockState(true, AUTOEXPOSURE_LOCK);
2622 
2623         set3ALockState(true, AUTOWHITEBALANCE_LOCK);
2624         assert3ALockState("Changing AWB lock affected AE lock!",
2625                 AUTOEXPOSURE_LOCK, true);
2626 
2627         set3ALockState(false, AUTOWHITEBALANCE_LOCK);
2628         assert3ALockState("Changing AWB lock affected AE lock!",
2629                 AUTOEXPOSURE_LOCK, true);
2630     }
2631 
2632     private void assert3ALockState(String msg, int type, boolean state) {
2633         Parameters parameters = mCamera.getParameters();
2634         switch (type) {
2635             case AUTOEXPOSURE_LOCK:
2636                 assertTrue(msg, state == parameters.getAutoExposureLock());
2637                 break;
2638             case AUTOWHITEBALANCE_LOCK:
2639                 assertTrue(msg, state == parameters.getAutoWhiteBalanceLock());
2640                 break;
2641             default:
2642                 assertTrue("Unknown lock type " + type, false);
2643                 break;
2644         }
2645     }
2646 
2647     private void set3ALockState(boolean state, int type) {
2648         Parameters parameters = mCamera.getParameters();
2649         switch (type) {
2650             case AUTOEXPOSURE_LOCK:
2651                 parameters.setAutoExposureLock(state);
2652                 break;
2653             case AUTOWHITEBALANCE_LOCK:
2654                 parameters.setAutoWhiteBalanceLock(state);
2655                 break;
2656             default:
2657                 assertTrue("Unknown lock type "+type, false);
2658                 break;
2659         }
2660         mCamera.setParameters(parameters);
2661     }
2662 
2663     @UiThreadTest
2664     public void testFaceDetection() throws Exception {
2665         int nCameras = Camera.getNumberOfCameras();
2666         for (int id = 0; id < nCameras; id++) {
2667             Log.v(TAG, "Camera id=" + id);
2668             testFaceDetectionByCamera(id);
2669         }
2670     }
2671 
2672     private void testFaceDetectionByCamera(int cameraId) throws Exception {
2673         final int FACE_DETECTION_TEST_DURATION = 3000;
2674         initializeMessageLooper(cameraId);
2675         mCamera.startPreview();
2676         Parameters parameters = mCamera.getParameters();
2677         int maxNumOfFaces = parameters.getMaxNumDetectedFaces();
2678         assertTrue(maxNumOfFaces >= 0);
2679         if (maxNumOfFaces == 0) {
2680             try {
2681                 mCamera.startFaceDetection();
2682                 fail("Should throw an exception if face detection is not supported.");
2683             } catch (IllegalArgumentException e) {
2684                 // expected
2685             }
2686             terminateMessageLooper();
2687             return;
2688         }
2689 
2690         mCamera.startFaceDetection();
2691         try {
2692             mCamera.startFaceDetection();
2693             fail("Starting face detection twice should throw an exception");
2694         } catch (RuntimeException e) {
2695             // expected
2696         }
2697         FaceListener listener = new FaceListener();
2698         mCamera.setFaceDetectionListener(listener);
2699         // Sleep some time so the camera has chances to detect faces.
2700         Thread.sleep(FACE_DETECTION_TEST_DURATION);
2701         // The face callback runs in another thread. Release the camera and stop
2702         // the looper. So we do not access the face array from two threads at
2703         // the same time.
2704         terminateMessageLooper();
2705 
2706         // Check if the optional fields are supported.
2707         boolean optionalFieldSupported = false;
2708         Face firstFace = null;
2709         for (Face[] faces: listener.mFacesArray) {
2710             for (Face face: faces) {
2711                 if (face != null) firstFace = face;
2712             }
2713         }
2714         if (firstFace != null) {
2715             if (firstFace.id != -1 || firstFace.leftEye != null
2716                     || firstFace.rightEye != null || firstFace.mouth != null) {
2717                 optionalFieldSupported = true;
2718             }
2719         }
2720 
2721         // Verify the faces array.
2722         for (Face[] faces: listener.mFacesArray) {
2723             testFaces(faces, maxNumOfFaces, optionalFieldSupported);
2724         }
2725 
2726         // After taking a picture, face detection should be started again.
2727         // Also make sure autofocus move callback is supported.
2728         initializeMessageLooper(cameraId);
2729         mCamera.setAutoFocusMoveCallback(mAutoFocusMoveCallback);
2730         mCamera.startPreview();
2731         mCamera.startFaceDetection();
2732         mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback);
2733         waitForSnapshotDone();
2734         mCamera.startPreview();
2735         mCamera.startFaceDetection();
2736         terminateMessageLooper();
2737     }
2738 
2739     private class FaceListener implements FaceDetectionListener {
2740         public ArrayList<Face[]> mFacesArray = new ArrayList<Face[]>();
2741 
2742         @Override
2743         public void onFaceDetection(Face[] faces, Camera camera) {
2744             mFacesArray.add(faces);
2745         }
2746     }
2747 
2748     private void testFaces(Face[] faces, int maxNumOfFaces,
2749             boolean optionalFieldSupported) {
2750         Rect bounds = new Rect(-1000, -1000, 1000, 1000);
2751         assertNotNull(faces);
2752         assertTrue(faces.length <= maxNumOfFaces);
2753         for (int i = 0; i < faces.length; i++) {
2754             Face face = faces[i];
2755             Rect rect = face.rect;
2756             // Check the bounds.
2757             assertNotNull(rect);
2758             assertTrue(rect.width() > 0);
2759             assertTrue(rect.height() > 0);
2760             assertTrue("Coordinates out of bounds. rect=" + rect,
2761                     bounds.contains(rect) || Rect.intersects(bounds, rect));
2762 
2763             // Check the score.
2764             assertTrue(face.score >= 1 && face.score <= 100);
2765 
2766             // Check id, left eye, right eye, and the mouth.
2767             // Optional fields should be all valid or none of them.
2768             if (!optionalFieldSupported) {
2769                 assertEquals(-1, face.id);
2770                 assertNull(face.leftEye);
2771                 assertNull(face.rightEye);
2772                 assertNull(face.mouth);
2773             } else {
2774                 assertTrue(face.id != -1);
2775                 assertNotNull(face.leftEye);
2776                 assertNotNull(face.rightEye);
2777                 assertNotNull(face.mouth);
2778                 assertTrue(bounds.contains(face.leftEye.x, face.leftEye.y));
2779                 assertTrue(bounds.contains(face.rightEye.x, face.rightEye.y));
2780                 assertTrue(bounds.contains(face.mouth.x, face.mouth.y));
2781                 // ID should be unique.
2782                 if (i != faces.length - 1) {
2783                     assertTrue(face.id != faces[i + 1].id);
2784                 }
2785             }
2786         }
2787     }
2788 
2789     @UiThreadTest
2790     public void testVideoSnapshot() throws Exception {
2791         int nCameras = Camera.getNumberOfCameras();
2792         for (int id = 0; id < nCameras; id++) {
2793             Log.v(TAG, "Camera id=" + id);
2794             testVideoSnapshotByCamera(id);
2795         }
2796     }
2797 
2798     private static final int[] mCamcorderProfileList = {
2799         CamcorderProfile.QUALITY_1080P,
2800         CamcorderProfile.QUALITY_480P,
2801         CamcorderProfile.QUALITY_720P,
2802         CamcorderProfile.QUALITY_CIF,
2803         CamcorderProfile.QUALITY_HIGH,
2804         CamcorderProfile.QUALITY_LOW,
2805         CamcorderProfile.QUALITY_QCIF,
2806         CamcorderProfile.QUALITY_QVGA,
2807     };
2808 
2809     private void testVideoSnapshotByCamera(int cameraId) throws Exception {
2810         initializeMessageLooper(cameraId);
2811         Camera.Parameters parameters = mCamera.getParameters();
2812         terminateMessageLooper();
2813         if (!parameters.isVideoSnapshotSupported()) {
2814             return;
2815         }
2816 
2817         SurfaceHolder holder = getActivity().getSurfaceView().getHolder();
2818 
2819         for (int profileId: mCamcorderProfileList) {
2820             if (!CamcorderProfile.hasProfile(cameraId, profileId)) {
2821                 continue;
2822             }
2823             initializeMessageLooper(cameraId);
2824             // Set the preview size.
2825             CamcorderProfile profile = CamcorderProfile.get(cameraId,
2826                     profileId);
2827             setPreviewSizeByProfile(parameters, profile);
2828 
2829             // Set the biggest picture size.
2830             Size biggestSize = mCamera.new Size(-1, -1);
2831             for (Size size: parameters.getSupportedPictureSizes()) {
2832                 if (biggestSize.width < size.width) {
2833                     biggestSize = size;
2834                 }
2835             }
2836             parameters.setPictureSize(biggestSize.width, biggestSize.height);
2837 
2838             mCamera.setParameters(parameters);
2839             mCamera.startPreview();
2840             mCamera.unlock();
2841             MediaRecorder recorder = new MediaRecorder();
2842             try {
2843                 recorder.setCamera(mCamera);
2844                 recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
2845                 recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
2846                 recorder.setProfile(profile);
2847                 recorder.setOutputFile("/dev/null");
2848                 recorder.setPreviewDisplay(holder.getSurface());
2849                 recorder.prepare();
2850                 recorder.start();
2851                 subtestTakePictureByCamera(true,
2852                         profile.videoFrameWidth, profile.videoFrameHeight);
2853                 testJpegExifByCamera(true);
2854                 testJpegThumbnailSizeByCamera(true,
2855                         profile.videoFrameWidth, profile.videoFrameHeight);
2856                 Thread.sleep(2000);
2857                 recorder.stop();
2858             } finally {
2859                 recorder.release();
2860                 mCamera.lock();
2861             }
2862             mCamera.stopPreview();
2863             terminateMessageLooper();
2864         }
2865     }
2866 
2867     public void testPreviewCallbackWithPicture() throws Exception {
2868         int nCameras = Camera.getNumberOfCameras();
2869         for (int id = 0; id < nCameras; id++) {
2870             Log.v(TAG, "Camera id=" + id);
2871             testPreviewCallbackWithPictureByCamera(id);
2872         }
2873     }
2874 
2875     private void testPreviewCallbackWithPictureByCamera(int cameraId)
2876             throws Exception {
2877         initializeMessageLooper(cameraId);
2878 
2879         SimplePreviewStreamCb callback = new SimplePreviewStreamCb(1);
2880         mCamera.setPreviewCallback(callback);
2881 
2882         Log.v(TAG, "Starting preview");
2883         mCamera.startPreview();
2884 
2885         // Wait until callbacks are flowing
2886         for (int i = 0; i < 30; i++) {
2887             assertTrue("testPreviewCallbackWithPicture: Not receiving preview callbacks!",
2888                     mPreviewDone.block( WAIT_FOR_COMMAND_TO_COMPLETE ) );
2889             mPreviewDone.close();
2890         }
2891 
2892         // Now take a picture
2893         Log.v(TAG, "Taking picture now");
2894 
2895         Size pictureSize = mCamera.getParameters().getPictureSize();
2896         mCamera.takePicture(mShutterCallback, mRawPictureCallback,
2897                 mJpegPictureCallback);
2898 
2899         waitForSnapshotDone();
2900 
2901         assertTrue("Shutter callback not received", mShutterCallbackResult);
2902         assertTrue("Raw picture callback not received", mRawPictureCallbackResult);
2903         assertTrue("Jpeg picture callback not received", mJpegPictureCallbackResult);
2904         assertNotNull(mJpegData);
2905         BitmapFactory.Options bmpOptions = new BitmapFactory.Options();
2906         bmpOptions.inJustDecodeBounds = true;
2907         BitmapFactory.decodeByteArray(mJpegData, 0, mJpegData.length, bmpOptions);
2908         assertEquals(pictureSize.width, bmpOptions.outWidth);
2909         assertEquals(pictureSize.height, bmpOptions.outHeight);
2910 
2911         // Restart preview, confirm callbacks still happen
2912         Log.v(TAG, "Restarting preview");
2913         mCamera.startPreview();
2914 
2915         for (int i = 0; i < 30; i++) {
2916             assertTrue("testPreviewCallbackWithPicture: Not receiving preview callbacks!",
2917                     mPreviewDone.block( WAIT_FOR_COMMAND_TO_COMPLETE ) );
2918             mPreviewDone.close();
2919         }
2920 
2921         mCamera.stopPreview();
2922 
2923         terminateMessageLooper();
2924     }
2925 
2926     public void testEnableShutterSound() throws Exception {
2927         int nCameras = Camera.getNumberOfCameras();
2928         for (int id = 0; id < nCameras; id++) {
2929             Log.v(TAG, "Camera id=" + id);
2930             testEnableShutterSoundByCamera(id);
2931         }
2932     }
2933 
2934     private void testEnableShutterSoundByCamera(int id) throws Exception {
2935         CameraInfo info = new CameraInfo();
2936 
2937         Camera.getCameraInfo(id, info);
2938 
2939         initializeMessageLooper(id);
2940 
2941         boolean result;
2942         Log.v(TAG, "testEnableShutterSoundByCamera: canDisableShutterSound: " +
2943                 info.canDisableShutterSound);
2944         result = mCamera.enableShutterSound(false);
2945         assertTrue(result == info.canDisableShutterSound);
2946         result = mCamera.enableShutterSound(true);
2947         assertTrue(result);
2948 
2949         terminateMessageLooper();
2950     }
2951 
2952 }
2953