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