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