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