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