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