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