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