1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.cts; 18 19 import android.content.pm.PackageManager; 20 import android.graphics.BitmapFactory; 21 import android.graphics.ImageFormat; 22 import android.graphics.Rect; 23 import android.hardware.Camera; 24 import android.hardware.Camera.Area; 25 import android.hardware.Camera.CameraInfo; 26 import android.hardware.Camera.ErrorCallback; 27 import android.hardware.Camera.Face; 28 import android.hardware.Camera.FaceDetectionListener; 29 import android.hardware.Camera.Parameters; 30 import android.hardware.Camera.PictureCallback; 31 import android.hardware.Camera.ShutterCallback; 32 import android.hardware.Camera.Size; 33 import android.media.CamcorderProfile; 34 import android.media.ExifInterface; 35 import android.media.MediaRecorder; 36 import android.os.Build; 37 import android.os.ConditionVariable; 38 import android.os.Environment; 39 import android.os.Looper; 40 import android.os.SystemClock; 41 import android.test.ActivityInstrumentationTestCase2; 42 import android.test.MoreAsserts; 43 import android.test.UiThreadTest; 44 import android.test.suitebuilder.annotation.LargeTest; 45 import android.util.Log; 46 import android.view.SurfaceHolder; 47 48 import 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 final String TAG = "CameraTest"; 68 private static final String PACKAGE = "android.hardware.cts"; 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 if (!recording) mCamera.startPreview(); 864 Date date = new Date(System.currentTimeMillis()); 865 String localDatetime = new SimpleDateFormat("yyyy:MM:dd HH:").format(date); 866 867 mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback); 868 waitForSnapshotDone(); 869 870 Camera.Parameters parameters = mCamera.getParameters(); 871 double focalLength = parameters.getFocalLength(); 872 873 // Test various exif tags. 874 ExifInterface exif = new ExifInterface(JPEG_PATH); 875 StringBuffer failedCause = new StringBuffer("Jpeg exif test failed:\n"); 876 boolean extraExiftestPassed = checkExtraExifTagsSucceeds(failedCause, exif); 877 878 if (VERBOSE) Log.v(TAG, "Testing exif tag TAG_DATETIME"); 879 String datetime = exif.getAttribute(ExifInterface.TAG_DATETIME); 880 assertNotNull(datetime); 881 // Datetime should be local time. 882 assertTrue(datetime.startsWith(localDatetime)); 883 assertTrue(datetime.length() == 19); // EXIF spec is "YYYY:MM:DD HH:MM:SS". 884 checkGpsDataNull(exif); 885 double exifFocalLength = exif.getAttributeDouble(ExifInterface.TAG_FOCAL_LENGTH, -1); 886 assertEquals(focalLength, exifFocalLength, 0.001); 887 // Test image width and height exif tags. They should match the jpeg. 888 assertBitmapAndJpegSizeEqual(mJpegData, exif); 889 890 // Test gps exif tags. 891 if (VERBOSE) Log.v(TAG, "Testing exif GPS tags"); 892 testGpsExifValues(parameters, 37.736071, -122.441983, 21, 1199145600, 893 "GPS NETWORK HYBRID ARE ALL FINE."); 894 testGpsExifValues(parameters, 0.736071, 0.441983, 1, 1199145601, "GPS"); 895 testGpsExifValues(parameters, -89.736071, -179.441983, 100000, 1199145602, "NETWORK"); 896 897 // Test gps tags do not exist after calling removeGpsData. Also check if 898 // image width and height exif match the jpeg when jpeg rotation is set. 899 if (VERBOSE) Log.v(TAG, "Testing exif GPS tag removal"); 900 if (!recording) mCamera.startPreview(); 901 parameters.removeGpsData(); 902 parameters.setRotation(90); // For testing image width and height exif. 903 mCamera.setParameters(parameters); 904 mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback); 905 waitForSnapshotDone(); 906 exif = new ExifInterface(JPEG_PATH); 907 checkGpsDataNull(exif); 908 assertBitmapAndJpegSizeEqual(mJpegData, exif); 909 // Reset the rotation to prevent from affecting other tests. 910 parameters.setRotation(0); 911 mCamera.setParameters(parameters); 912 } 913 914 /** 915 * Sanity check of some extra exif tags. 916 * <p> 917 * Sanity check some extra exif tags without asserting the check failures 918 * immediately. When a failure is detected, the failure cause is logged, 919 * the rest of the tests are still executed. The caller can assert with the 920 * failure cause based on the returned test status. 921 * </p> 922 * 923 * @param logBuf Log failure cause to this StringBuffer if there is 924 * any failure. 925 * @param exif The exif data associated with a jpeg image being tested. 926 * @return true if no test failure is found, false if there is any failure. 927 */ checkExtraExifTagsSucceeds(StringBuffer logBuf, ExifInterface exif)928 private boolean checkExtraExifTagsSucceeds(StringBuffer logBuf, ExifInterface exif) { 929 if (logBuf == null || exif == null) { 930 throw new IllegalArgumentException("failureCause and exif shouldn't be null"); 931 } 932 933 if (VERBOSE) Log.v(TAG, "Testing extra exif tags"); 934 boolean allTestsPassed = true; 935 boolean passedSoFar = true; 936 String failureMsg; 937 938 // TAG_EXPOSURE_TIME 939 // ExifInterface API gives exposure time value in the form of float instead of rational 940 String exposureTime = exif.getAttribute(ExifInterface.TAG_EXPOSURE_TIME); 941 passedSoFar = expectNotNull("Exif TAG_EXPOSURE_TIME is null!", logBuf, exposureTime); 942 if (passedSoFar) { 943 double exposureTimeValue = Double.parseDouble(exposureTime); 944 failureMsg = "Exif exposure time " + exposureTime + " should be a positive value"; 945 passedSoFar = expectTrue(failureMsg, logBuf, exposureTimeValue > 0); 946 } 947 allTestsPassed = allTestsPassed && passedSoFar; 948 949 // TAG_APERTURE 950 // ExifInterface API gives aperture value in the form of float instead of rational 951 String aperture = exif.getAttribute(ExifInterface.TAG_APERTURE); 952 passedSoFar = expectNotNull("Exif TAG_APERTURE is null!", logBuf, aperture); 953 if (passedSoFar) { 954 double apertureValue = Double.parseDouble(aperture); 955 passedSoFar = expectTrue("Exif TAG_APERTURE value " + aperture + " should be positive!", 956 logBuf, apertureValue > 0); 957 } 958 allTestsPassed = allTestsPassed && passedSoFar; 959 960 // TAG_FLASH 961 String flash = exif.getAttribute(ExifInterface.TAG_FLASH); 962 passedSoFar = expectNotNull("Exif TAG_FLASH is null!", logBuf, flash); 963 allTestsPassed = allTestsPassed && passedSoFar; 964 965 // TAG_WHITE_BALANCE 966 String whiteBalance = exif.getAttribute(ExifInterface.TAG_WHITE_BALANCE); 967 passedSoFar = expectNotNull("Exif TAG_WHITE_BALANCE is null!", logBuf, whiteBalance); 968 allTestsPassed = allTestsPassed && passedSoFar; 969 970 // TAG_MAKE 971 String make = exif.getAttribute(ExifInterface.TAG_MAKE); 972 passedSoFar = expectNotNull("Exif TAG_MAKE is null!", logBuf, make); 973 if (passedSoFar) { 974 passedSoFar = expectTrue("Exif TAG_MODEL value: " + make 975 + " should match build manufacturer: " + Build.MANUFACTURER, logBuf, 976 make.equals(Build.MANUFACTURER)); 977 } 978 allTestsPassed = allTestsPassed && passedSoFar; 979 980 // TAG_MODEL 981 String model = exif.getAttribute(ExifInterface.TAG_MODEL); 982 passedSoFar = expectNotNull("Exif TAG_MODEL is null!", logBuf, model); 983 if (passedSoFar) { 984 passedSoFar = expectTrue("Exif TAG_MODEL value: " + model 985 + " should match build manufacturer: " + Build.MODEL, logBuf, 986 model.equals(Build.MODEL)); 987 } 988 allTestsPassed = allTestsPassed && passedSoFar; 989 990 // TAG_ISO 991 int iso = exif.getAttributeInt(ExifInterface.TAG_ISO, -1); 992 passedSoFar = expectTrue("Exif ISO value " + iso + " is invalid", logBuf, iso > 0); 993 allTestsPassed = allTestsPassed && passedSoFar; 994 995 // TAG_DATETIME_DIGITIZED (a.k.a Create time for digital cameras). 996 String digitizedTime = exif.getAttribute(TAG_DATETIME_DIGITIZED); 997 passedSoFar = expectNotNull("Exif TAG_DATETIME_DIGITIZED is null!", logBuf, digitizedTime); 998 if (passedSoFar) { 999 String datetime = exif.getAttribute(ExifInterface.TAG_DATETIME); 1000 passedSoFar = expectNotNull("Exif TAG_DATETIME is null!", logBuf, datetime); 1001 if (passedSoFar) { 1002 passedSoFar = expectTrue("dataTime should match digitizedTime", logBuf, 1003 digitizedTime.equals(datetime)); 1004 } 1005 } 1006 allTestsPassed = allTestsPassed && passedSoFar; 1007 1008 /** 1009 * TAG_SUBSEC_TIME. Since the sub second tag strings are truncated to at 1010 * most 9 digits in ExifInterface implementation, use getAttributeInt to 1011 * sanitize it. When the default value -1 is returned, it means that 1012 * this exif tag either doesn't exist or is a non-numerical invalid 1013 * string. Same rule applies to the rest of sub second tags. 1014 */ 1015 int subSecTime = exif.getAttributeInt(TAG_SUBSEC_TIME, -1); 1016 passedSoFar = expectTrue( 1017 "Exif TAG_SUBSEC_TIME value is null or invalid!", logBuf, subSecTime > 0); 1018 allTestsPassed = allTestsPassed && passedSoFar; 1019 1020 // TAG_SUBSEC_TIME_ORIG 1021 int subSecTimeOrig = exif.getAttributeInt(TAG_SUBSEC_TIME_ORIG, -1); 1022 passedSoFar = expectTrue( 1023 "Exif TAG_SUBSEC_TIME_ORIG value is null or invalid!", logBuf, subSecTimeOrig > 0); 1024 allTestsPassed = allTestsPassed && passedSoFar; 1025 1026 // TAG_SUBSEC_TIME_DIG 1027 int subSecTimeDig = exif.getAttributeInt(TAG_SUBSEC_TIME_DIG, -1); 1028 passedSoFar = expectTrue( 1029 "Exif TAG_SUBSEC_TIME_DIG value is null or invalid!", logBuf, subSecTimeDig > 0); 1030 allTestsPassed = allTestsPassed && passedSoFar; 1031 1032 return allTestsPassed; 1033 } 1034 1035 /** 1036 * Check if object is null and log failure msg. 1037 * 1038 * @param msg Failure msg. 1039 * @param logBuffer StringBuffer to log the failure msg. 1040 * @param obj Object to test. 1041 * @return true if object is not null, otherwise return false. 1042 */ expectNotNull(String msg, StringBuffer logBuffer, Object obj)1043 private boolean expectNotNull(String msg, StringBuffer logBuffer, Object obj) 1044 { 1045 if (obj == null) { 1046 logBuffer.append(msg + "\n"); 1047 } 1048 return (obj != null); 1049 } 1050 1051 /** 1052 * Check if condition is false and log failure msg. 1053 * 1054 * @param msg Failure msg. 1055 * @param logBuffer StringBuffer to log the failure msg. 1056 * @param condition Condition to test. 1057 * @return The value of the condition. 1058 */ expectTrue(String msg, StringBuffer logBuffer, boolean condition)1059 private boolean expectTrue(String msg, StringBuffer logBuffer, boolean condition) { 1060 if (!condition) { 1061 logBuffer.append(msg + "\n"); 1062 } 1063 return condition; 1064 } 1065 assertBitmapAndJpegSizeEqual(byte[] jpegData, ExifInterface exif)1066 private void assertBitmapAndJpegSizeEqual(byte[] jpegData, ExifInterface exif) { 1067 int exifWidth = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0); 1068 int exifHeight = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0); 1069 assertTrue(exifWidth != 0 && exifHeight != 0); 1070 BitmapFactory.Options bmpOptions = new BitmapFactory.Options(); 1071 bmpOptions.inJustDecodeBounds = true; 1072 BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length, bmpOptions); 1073 assertEquals(bmpOptions.outWidth, exifWidth); 1074 assertEquals(bmpOptions.outHeight, exifHeight); 1075 } 1076 testGpsExifValues(Parameters parameters, double latitude, double longitude, double altitude, long timestamp, String method)1077 private void testGpsExifValues(Parameters parameters, double latitude, 1078 double longitude, double altitude, long timestamp, String method) 1079 throws IOException { 1080 mCamera.startPreview(); 1081 parameters.setGpsLatitude(latitude); 1082 parameters.setGpsLongitude(longitude); 1083 parameters.setGpsAltitude(altitude); 1084 parameters.setGpsTimestamp(timestamp); 1085 parameters.setGpsProcessingMethod(method); 1086 mCamera.setParameters(parameters); 1087 mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback); 1088 waitForSnapshotDone(); 1089 ExifInterface exif = new ExifInterface(JPEG_PATH); 1090 assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE)); 1091 assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE)); 1092 assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF)); 1093 assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF)); 1094 assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP)); 1095 assertNotNull(exif.getAttribute(ExifInterface.TAG_GPS_DATESTAMP)); 1096 assertEquals(method, exif.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD)); 1097 float[] latLong = new float[2]; 1098 assertTrue(exif.getLatLong(latLong)); 1099 assertEquals((float)latitude, latLong[0], 0.0001f); 1100 assertEquals((float)longitude, latLong[1], 0.0001f); 1101 assertEquals(altitude, exif.getAltitude(-1), 1); 1102 assertEquals(timestamp, getGpsDateTimeFromJpeg(exif) / 1000); 1103 } 1104 getGpsDateTimeFromJpeg(ExifInterface exif)1105 private long getGpsDateTimeFromJpeg(ExifInterface exif) { 1106 String date = exif.getAttribute(ExifInterface.TAG_GPS_DATESTAMP); 1107 String time = exif.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP); 1108 if (date == null || time == null) return -1; 1109 1110 String dateTimeString = date + ' ' + time; 1111 ParsePosition pos = new ParsePosition(0); 1112 try { 1113 SimpleDateFormat formatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); 1114 formatter.setTimeZone(TimeZone.getTimeZone("UTC")); 1115 1116 Date datetime = formatter.parse(dateTimeString, pos); 1117 if (datetime == null) return -1; 1118 return datetime.getTime(); 1119 } catch (IllegalArgumentException ex) { 1120 return -1; 1121 } 1122 } 1123 checkGpsDataNull(ExifInterface exif)1124 private void checkGpsDataNull(ExifInterface exif) { 1125 assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE)); 1126 assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE)); 1127 assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF)); 1128 assertNull(exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF)); 1129 assertNull(exif.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP)); 1130 assertNull(exif.getAttribute(ExifInterface.TAG_GPS_DATESTAMP)); 1131 assertNull(exif.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD)); 1132 } 1133 1134 @UiThreadTest testLockUnlock()1135 public void testLockUnlock() throws Exception { 1136 int nCameras = Camera.getNumberOfCameras(); 1137 for (int id = 0; id < nCameras; id++) { 1138 Log.v(TAG, "Camera id=" + id); 1139 testLockUnlockByCamera(id); 1140 } 1141 } 1142 testLockUnlockByCamera(int cameraId)1143 private void testLockUnlockByCamera(int cameraId) throws Exception { 1144 initializeMessageLooper(cameraId); 1145 Camera.Parameters parameters = mCamera.getParameters(); 1146 SurfaceHolder surfaceHolder; 1147 surfaceHolder = getActivity().getSurfaceView().getHolder(); 1148 CamcorderProfile profile = CamcorderProfile.get(cameraId, 1149 CamcorderProfile.QUALITY_LOW); 1150 1151 // Set the preview size. 1152 setPreviewSizeByProfile(parameters, profile); 1153 1154 mCamera.setParameters(parameters); 1155 mCamera.setPreviewDisplay(surfaceHolder); 1156 mCamera.startPreview(); 1157 mCamera.lock(); // Locking again from the same process has no effect. 1158 try { 1159 recordVideo(profile, surfaceHolder); 1160 fail("Recording should not succeed because camera is locked."); 1161 } catch (Exception e) { 1162 // expected 1163 } 1164 1165 mCamera.unlock(); // Unlock the camera so media recorder can use it. 1166 try { 1167 mCamera.setParameters(parameters); 1168 fail("setParameters should not succeed because camera is unlocked."); 1169 } catch (RuntimeException e) { 1170 // expected 1171 } 1172 1173 recordVideo(profile, surfaceHolder); // should not throw exception 1174 // Media recorder already releases the camera so the test application 1175 // can lock and use the camera now. 1176 mCamera.lock(); // should not fail 1177 mCamera.setParameters(parameters); // should not fail 1178 terminateMessageLooper(); 1179 } 1180 setPreviewSizeByProfile(Parameters parameters, CamcorderProfile profile)1181 private void setPreviewSizeByProfile(Parameters parameters, CamcorderProfile profile) { 1182 if (parameters.getSupportedVideoSizes() == null) { 1183 parameters.setPreviewSize(profile.videoFrameWidth, 1184 profile.videoFrameHeight); 1185 } else { // Driver supports separates outputs for preview and video. 1186 List<Size> sizes = parameters.getSupportedPreviewSizes(); 1187 Size preferred = parameters.getPreferredPreviewSizeForVideo(); 1188 int product = preferred.width * preferred.height; 1189 for (Size size: sizes) { 1190 if (size.width * size.height <= product) { 1191 parameters.setPreviewSize(size.width, size.height); 1192 break; 1193 } 1194 } 1195 } 1196 } 1197 recordVideo(CamcorderProfile profile, SurfaceHolder holder)1198 private void recordVideo(CamcorderProfile profile, 1199 SurfaceHolder holder) throws Exception { 1200 MediaRecorder recorder = new MediaRecorder(); 1201 try { 1202 // Pass the camera from the test application to media recorder. 1203 recorder.setCamera(mCamera); 1204 recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); 1205 recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 1206 recorder.setProfile(profile); 1207 recorder.setOutputFile("/dev/null"); 1208 recorder.setPreviewDisplay(holder.getSurface()); 1209 recorder.prepare(); 1210 recorder.start(); 1211 1212 // Apps can use the camera after start since API level 13. 1213 Parameters parameters = mCamera.getParameters(); 1214 if (parameters.isZoomSupported()) { 1215 if (parameters.getMaxZoom() > 0) { 1216 parameters.setZoom(1); 1217 mCamera.setParameters(parameters); 1218 parameters.setZoom(0); 1219 mCamera.setParameters(parameters); 1220 } 1221 } 1222 if (parameters.isSmoothZoomSupported()) { 1223 if (parameters.getMaxZoom() > 0) { 1224 ZoomListener zoomListener = new ZoomListener(); 1225 mCamera.setZoomChangeListener(zoomListener); 1226 mCamera.startSmoothZoom(1); 1227 assertTrue(zoomListener.mZoomDone.block(1000)); 1228 } 1229 } 1230 1231 try { 1232 mCamera.unlock(); 1233 fail("unlock should not succeed during recording."); 1234 } catch(RuntimeException e) { 1235 // expected 1236 } 1237 1238 Thread.sleep(2000); 1239 recorder.stop(); 1240 } finally { 1241 recorder.release(); 1242 } 1243 } 1244 1245 @UiThreadTest testPreviewCallbackWithBuffer()1246 public void testPreviewCallbackWithBuffer() throws Exception { 1247 int nCameras = Camera.getNumberOfCameras(); 1248 for (int id = 0; id < nCameras; id++) { 1249 Log.v(TAG, "Camera id=" + id); 1250 testPreviewCallbackWithBufferByCamera(id); 1251 } 1252 } 1253 testPreviewCallbackWithBufferByCamera(int cameraId)1254 private void testPreviewCallbackWithBufferByCamera(int cameraId) throws Exception { 1255 initializeMessageLooper(cameraId); 1256 SurfaceHolder surfaceHolder; 1257 surfaceHolder = getActivity().getSurfaceView().getHolder(); 1258 mCamera.setPreviewDisplay(surfaceHolder); 1259 Parameters parameters = mCamera.getParameters(); 1260 PreviewCallbackWithBuffer callback = new PreviewCallbackWithBuffer(); 1261 // Test all preview sizes. 1262 for (Size size: parameters.getSupportedPreviewSizes()) { 1263 parameters.setPreviewSize(size.width, size.height); 1264 mCamera.setParameters(parameters); 1265 assertEquals(size, mCamera.getParameters().getPreviewSize()); 1266 callback.mNumCbWithBuffer1 = 0; 1267 callback.mNumCbWithBuffer2 = 0; 1268 callback.mNumCbWithBuffer3 = 0; 1269 int format = mCamera.getParameters().getPreviewFormat(); 1270 int bitsPerPixel = ImageFormat.getBitsPerPixel(format); 1271 callback.mBuffer1 = new byte[size.width * size.height * bitsPerPixel / 8]; 1272 callback.mBuffer2 = new byte[size.width * size.height * bitsPerPixel / 8]; 1273 callback.mBuffer3 = new byte[size.width * size.height * bitsPerPixel / 8]; 1274 1275 // Test if we can get the preview callbacks with specified buffers. 1276 mCamera.addCallbackBuffer(callback.mBuffer1); 1277 mCamera.addCallbackBuffer(callback.mBuffer2); 1278 mCamera.setPreviewCallbackWithBuffer(callback); 1279 mCamera.startPreview(); 1280 waitForPreviewDone(); 1281 assertFalse(callback.mPreviewDataNull); 1282 assertFalse(callback.mInvalidData); 1283 assertEquals(1, callback.mNumCbWithBuffer1); 1284 assertEquals(1, callback.mNumCbWithBuffer2); 1285 assertEquals(0, callback.mNumCbWithBuffer3); 1286 1287 // Test if preview callback with buffer still works during preview. 1288 mCamera.addCallbackBuffer(callback.mBuffer3); 1289 waitForPreviewDone(); 1290 assertFalse(callback.mPreviewDataNull); 1291 assertFalse(callback.mInvalidData); 1292 assertEquals(1, callback.mNumCbWithBuffer1); 1293 assertEquals(1, callback.mNumCbWithBuffer2); 1294 assertEquals(1, callback.mNumCbWithBuffer3); 1295 mCamera.setPreviewCallbackWithBuffer(null); 1296 mCamera.stopPreview(); 1297 } 1298 terminateMessageLooper(); 1299 } 1300 1301 private final class PreviewCallbackWithBuffer 1302 implements android.hardware.Camera.PreviewCallback { 1303 public int mNumCbWithBuffer1, mNumCbWithBuffer2, mNumCbWithBuffer3; 1304 public byte[] mBuffer1, mBuffer2, mBuffer3; 1305 public boolean mPreviewDataNull, mInvalidData; onPreviewFrame(byte[] data, Camera camera)1306 public void onPreviewFrame(byte[] data, Camera camera) { 1307 if (data == null) { 1308 Log.e(TAG, "Preview data is null!"); 1309 mPreviewDataNull = true; 1310 mPreviewDone.open(); 1311 return; 1312 } 1313 if (data == mBuffer1) { 1314 mNumCbWithBuffer1++; 1315 } else if (data == mBuffer2) { 1316 mNumCbWithBuffer2++; 1317 } else if (data == mBuffer3) { 1318 mNumCbWithBuffer3++; 1319 } else { 1320 Log.e(TAG, "Invalid byte array."); 1321 mInvalidData = true; 1322 mPreviewDone.open(); 1323 return; 1324 } 1325 1326 if ((mNumCbWithBuffer1 == 1 && mNumCbWithBuffer2 == 1) 1327 || mNumCbWithBuffer3 == 1) { 1328 mPreviewDone.open(); 1329 } 1330 } 1331 } 1332 1333 @UiThreadTest testImmediateZoom()1334 public void testImmediateZoom() throws Exception { 1335 int nCameras = Camera.getNumberOfCameras(); 1336 for (int id = 0; id < nCameras; id++) { 1337 Log.v(TAG, "Camera id=" + id); 1338 testImmediateZoomByCamera(id); 1339 } 1340 } 1341 testImmediateZoomByCamera(int id)1342 private void testImmediateZoomByCamera(int id) throws Exception { 1343 initializeMessageLooper(id); 1344 1345 Parameters parameters = mCamera.getParameters(); 1346 if (!parameters.isZoomSupported()) { 1347 terminateMessageLooper(); 1348 return; 1349 } 1350 1351 // Test the zoom parameters. 1352 assertEquals(0, parameters.getZoom()); // default zoom should be 0. 1353 for (Size size: parameters.getSupportedPreviewSizes()) { 1354 parameters = mCamera.getParameters(); 1355 parameters.setPreviewSize(size.width, size.height); 1356 mCamera.setParameters(parameters); 1357 parameters = mCamera.getParameters(); 1358 int maxZoom = parameters.getMaxZoom(); 1359 assertTrue(maxZoom >= 0); 1360 1361 // Zoom ratios should be sorted from small to large. 1362 List<Integer> ratios = parameters.getZoomRatios(); 1363 assertEquals(maxZoom + 1, ratios.size()); 1364 assertEquals(100, ratios.get(0).intValue()); 1365 for (int i = 0; i < ratios.size() - 1; i++) { 1366 assertTrue(ratios.get(i) < ratios.get(i + 1)); 1367 } 1368 blockingStartPreview(); 1369 1370 // Test each zoom step. 1371 for (int i = 0; i <= maxZoom; i++) { 1372 parameters.setZoom(i); 1373 mCamera.setParameters(parameters); 1374 assertEquals(i, mCamera.getParameters().getZoom()); 1375 } 1376 1377 // It should throw exception if an invalid value is passed. 1378 try { 1379 parameters.setZoom(maxZoom + 1); 1380 mCamera.setParameters(parameters); 1381 fail("setZoom should throw exception."); 1382 } catch (RuntimeException e) { 1383 // expected 1384 } 1385 assertEquals(maxZoom, mCamera.getParameters().getZoom()); 1386 1387 mCamera.takePicture(mShutterCallback, mRawPictureCallback, 1388 mJpegPictureCallback); 1389 waitForSnapshotDone(); 1390 } 1391 1392 terminateMessageLooper(); 1393 } 1394 1395 @UiThreadTest 1396 public void testSmoothZoom() throws Exception { 1397 int nCameras = Camera.getNumberOfCameras(); 1398 for (int id = 0; id < nCameras; id++) { 1399 Log.v(TAG, "Camera id=" + id); 1400 testSmoothZoomByCamera(id); 1401 } 1402 } 1403 1404 private void testSmoothZoomByCamera(int id) throws Exception { 1405 initializeMessageLooper(id); 1406 1407 Parameters parameters = mCamera.getParameters(); 1408 if (!parameters.isSmoothZoomSupported()) { 1409 terminateMessageLooper(); 1410 return; 1411 } 1412 assertTrue(parameters.isZoomSupported()); 1413 1414 ZoomListener zoomListener = new ZoomListener(); 1415 mCamera.setZoomChangeListener(zoomListener); 1416 mCamera.startPreview(); 1417 waitForPreviewDone(); 1418 1419 // Immediate zoom should not generate callbacks. 1420 int maxZoom = parameters.getMaxZoom(); 1421 parameters.setZoom(maxZoom); 1422 mCamera.setParameters(parameters); 1423 assertEquals(maxZoom, mCamera.getParameters().getZoom()); 1424 parameters.setZoom(0); 1425 mCamera.setParameters(parameters); 1426 assertEquals(0, mCamera.getParameters().getZoom()); 1427 assertFalse(zoomListener.mZoomDone.block(500)); 1428 1429 // Nothing will happen if zoom is not moving. 1430 mCamera.stopSmoothZoom(); 1431 1432 // It should not generate callbacks if zoom value is not changed. 1433 mCamera.startSmoothZoom(0); 1434 assertFalse(zoomListener.mZoomDone.block(500)); 1435 assertEquals(0, mCamera.getParameters().getZoom()); 1436 1437 // Test startSmoothZoom. 1438 mCamera.startSmoothZoom(maxZoom); 1439 assertEquals(true, zoomListener.mZoomDone.block(5000)); 1440 assertEquals(maxZoom, mCamera.getParameters().getZoom()); 1441 assertEquals(maxZoom, zoomListener.mValues.size()); 1442 for(int i = 0; i < maxZoom; i++) { 1443 int value = zoomListener.mValues.get(i); 1444 boolean stopped = zoomListener.mStopped.get(i); 1445 // Make sure we get all the zoom values in order. 1446 assertEquals(i + 1, value); 1447 // All "stopped" except the last should be false. 1448 assertEquals(i == maxZoom - 1, stopped); 1449 } 1450 1451 // Test startSmoothZoom. Make sure we get all the callbacks. 1452 if (maxZoom > 1) { 1453 zoomListener.mValues.clear(); 1454 zoomListener.mStopped.clear(); 1455 Log.e(TAG, "zoomListener.mStopped = " + zoomListener.mStopped); 1456 zoomListener.mZoomDone.close(); 1457 mCamera.startSmoothZoom(maxZoom / 2); 1458 assertTrue(zoomListener.mZoomDone.block(5000)); 1459 assertEquals(maxZoom / 2, mCamera.getParameters().getZoom()); 1460 assertEquals(maxZoom - (maxZoom / 2), zoomListener.mValues.size()); 1461 for(int i = 0; i < zoomListener.mValues.size(); i++) { 1462 int value = zoomListener.mValues.get(i); 1463 boolean stopped = zoomListener.mStopped.get(i); 1464 // Make sure we get all the zoom values in order. 1465 assertEquals(maxZoom - 1 - i, value); 1466 // All "stopped" except the last should be false. 1467 assertEquals(i == zoomListener.mValues.size() - 1, stopped); 1468 } 1469 } 1470 1471 // It should throw exception if an invalid value is passed. 1472 try { 1473 mCamera.startSmoothZoom(maxZoom + 1); 1474 fail("startSmoothZoom should throw exception."); 1475 } catch (IllegalArgumentException e) { 1476 // expected 1477 } 1478 1479 // Test stopSmoothZoom. 1480 zoomListener.mValues.clear(); 1481 zoomListener.mStopped.clear(); 1482 zoomListener.mZoomDone.close(); 1483 parameters.setZoom(0); 1484 mCamera.setParameters(parameters); 1485 assertEquals(0, mCamera.getParameters().getZoom()); 1486 mCamera.startSmoothZoom(maxZoom); 1487 mCamera.stopSmoothZoom(); 1488 assertTrue(zoomListener.mZoomDone.block(5000)); 1489 assertEquals(zoomListener.mValues.size(), mCamera.getParameters().getZoom()); 1490 for(int i = 0; i < zoomListener.mValues.size() - 1; i++) { 1491 int value = zoomListener.mValues.get(i); 1492 boolean stopped = zoomListener.mStopped.get(i); 1493 // Make sure we get all the callbacks in order (except the last). 1494 assertEquals(i + 1, value); 1495 // All "stopped" except the last should be false. stopSmoothZoom has been called. So the 1496 // last "stopped" can be true or false. 1497 if (i != zoomListener.mValues.size() - 1) { 1498 assertFalse(stopped); 1499 } 1500 } 1501 1502 terminateMessageLooper(); 1503 } 1504 1505 private final class ZoomListener 1506 implements android.hardware.Camera.OnZoomChangeListener { 1507 public ArrayList<Integer> mValues = new ArrayList<Integer>(); 1508 public ArrayList<Boolean> mStopped = new ArrayList<Boolean>(); 1509 public final ConditionVariable mZoomDone = new ConditionVariable(); 1510 1511 public void onZoomChange(int value, boolean stopped, Camera camera) { 1512 mValues.add(value); 1513 mStopped.add(stopped); 1514 if (stopped) { 1515 mZoomDone.open(); 1516 } 1517 } 1518 } 1519 1520 @UiThreadTest 1521 public void testFocusDistances() throws Exception { 1522 int nCameras = Camera.getNumberOfCameras(); 1523 for (int id = 0; id < nCameras; id++) { 1524 Log.v(TAG, "Camera id=" + id); 1525 testFocusDistancesByCamera(id); 1526 } 1527 } 1528 1529 private void testFocusDistancesByCamera(int cameraId) throws Exception { 1530 initializeMessageLooper(cameraId); 1531 blockingStartPreview(); 1532 1533 Parameters parameters = mCamera.getParameters(); 1534 1535 // Test every supported focus mode. 1536 for (String focusMode: parameters.getSupportedFocusModes()) { 1537 parameters.setFocusMode(focusMode); 1538 mCamera.setParameters(parameters); 1539 parameters = mCamera.getParameters(); 1540 assertEquals(focusMode, parameters.getFocusMode()); 1541 checkFocusDistances(parameters); 1542 if (Parameters.FOCUS_MODE_AUTO.equals(focusMode) 1543 || Parameters.FOCUS_MODE_MACRO.equals(focusMode) 1544 || Parameters.FOCUS_MODE_CONTINUOUS_VIDEO.equals(focusMode) 1545 || Parameters.FOCUS_MODE_CONTINUOUS_PICTURE.equals(focusMode)) { 1546 Log.v(TAG, "Focus mode=" + focusMode); 1547 mCamera.autoFocus(mAutoFocusCallback); 1548 assertTrue(waitForFocusDone()); 1549 parameters = mCamera.getParameters(); 1550 checkFocusDistances(parameters); 1551 float[] initialFocusDistances = new float[3]; 1552 parameters.getFocusDistances(initialFocusDistances); 1553 1554 // Focus position should not change after autoFocus call. 1555 // Continuous autofocus should have stopped. Sleep some time and 1556 // check. Make sure continuous autofocus is not working. If the 1557 // focus mode is auto or macro, it is no harm to do the extra 1558 // test. 1559 Thread.sleep(500); 1560 parameters = mCamera.getParameters(); 1561 float[] currentFocusDistances = new float[3]; 1562 parameters.getFocusDistances(currentFocusDistances); 1563 assertEquals(initialFocusDistances, currentFocusDistances); 1564 1565 // Focus position should not change after stopping preview. 1566 mCamera.stopPreview(); 1567 parameters = mCamera.getParameters(); 1568 parameters.getFocusDistances(currentFocusDistances); 1569 assertEquals(initialFocusDistances, currentFocusDistances); 1570 1571 // Focus position should not change after taking a picture. 1572 mCamera.startPreview(); 1573 mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback); 1574 waitForSnapshotDone(); 1575 parameters = mCamera.getParameters(); 1576 parameters.getFocusDistances(currentFocusDistances); 1577 assertEquals(initialFocusDistances, currentFocusDistances); 1578 mCamera.startPreview(); 1579 } 1580 } 1581 1582 // Test if the method throws exception if the argument is invalid. 1583 try { 1584 parameters.getFocusDistances(null); 1585 fail("getFocusDistances should not accept null."); 1586 } catch (IllegalArgumentException e) { 1587 // expected 1588 } 1589 1590 try { 1591 parameters.getFocusDistances(new float[2]); 1592 fail("getFocusDistances should not accept a float array with two elements."); 1593 } catch (IllegalArgumentException e) { 1594 // expected 1595 } 1596 1597 try { 1598 parameters.getFocusDistances(new float[4]); 1599 fail("getFocusDistances should not accept a float array with four elements."); 1600 } catch (IllegalArgumentException e) { 1601 // expected 1602 } 1603 terminateMessageLooper(); 1604 } 1605 1606 private void checkFocusDistances(Parameters parameters) { 1607 float[] distances = new float[3]; 1608 parameters.getFocusDistances(distances); 1609 1610 // Focus distances should be greater than 0. 1611 assertTrue(distances[Parameters.FOCUS_DISTANCE_NEAR_INDEX] > 0); 1612 assertTrue(distances[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX] > 0); 1613 assertTrue(distances[Parameters.FOCUS_DISTANCE_FAR_INDEX] > 0); 1614 1615 // Make sure far focus distance >= optimal focus distance >= near focus distance. 1616 assertTrue(distances[Parameters.FOCUS_DISTANCE_FAR_INDEX] >= 1617 distances[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX]); 1618 assertTrue(distances[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX] >= 1619 distances[Parameters.FOCUS_DISTANCE_NEAR_INDEX]); 1620 1621 // Far focus distance should be infinity in infinity focus mode. 1622 if (Parameters.FOCUS_MODE_INFINITY.equals(parameters.getFocusMode())) { 1623 assertEquals(Float.POSITIVE_INFINITY, 1624 distances[Parameters.FOCUS_DISTANCE_FAR_INDEX]); 1625 } 1626 } 1627 1628 @UiThreadTest 1629 public void testCancelAutofocus() throws Exception { 1630 int nCameras = Camera.getNumberOfCameras(); 1631 for (int id = 0; id < nCameras; id++) { 1632 Log.v(TAG, "Camera id=" + id); 1633 testCancelAutofocusByCamera(id); 1634 } 1635 } 1636 1637 private void testCancelAutofocusByCamera(int cameraId) throws Exception { 1638 initializeMessageLooper(cameraId); 1639 Parameters parameters = mCamera.getParameters(); 1640 List<String> focusModes = parameters.getSupportedFocusModes(); 1641 1642 if (focusModes.contains(Parameters.FOCUS_MODE_AUTO)) { 1643 parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO); 1644 } else if (focusModes.contains(Parameters.FOCUS_MODE_MACRO)) { 1645 parameters.setFocusMode(Parameters.FOCUS_MODE_MACRO); 1646 } else { 1647 terminateMessageLooper(); 1648 return; 1649 } 1650 1651 mCamera.setParameters(parameters); 1652 1653 // Valid to call outside of preview; should just reset lens or 1654 // be a no-op. 1655 mCamera.cancelAutoFocus(); 1656 1657 mCamera.startPreview(); 1658 1659 // No op if autofocus is not in progress. 1660 mCamera.cancelAutoFocus(); 1661 1662 // Try to cancel autofocus immediately. 1663 mCamera.autoFocus(mAutoFocusCallback); 1664 mCamera.cancelAutoFocus(); 1665 checkFocusDistanceNotChanging(); 1666 1667 // Try to cancel autofocus after it starts for some time. 1668 mCamera.autoFocus(mAutoFocusCallback); 1669 Thread.sleep(500); 1670 mCamera.cancelAutoFocus(); 1671 checkFocusDistanceNotChanging(); 1672 1673 // Try to cancel autofocus after it completes. It should be no op. 1674 mCamera.autoFocus(mAutoFocusCallback); 1675 assertTrue(waitForFocusDone()); 1676 mCamera.cancelAutoFocus(); 1677 1678 // Test the case calling cancelAutoFocus and release in a row. 1679 mCamera.autoFocus(mAutoFocusCallback); 1680 mCamera.cancelAutoFocus(); 1681 mCamera.release(); 1682 1683 // Ensure the camera can be opened if release is called right after AF. 1684 mCamera = Camera.open(cameraId); 1685 mCamera.setPreviewDisplay(getActivity().getSurfaceView().getHolder()); 1686 mCamera.startPreview(); 1687 mCamera.autoFocus(mAutoFocusCallback); 1688 mCamera.release(); 1689 1690 terminateMessageLooper(); 1691 } 1692 1693 private void checkFocusDistanceNotChanging() throws Exception { 1694 float[] distances1 = new float[3]; 1695 float[] distances2 = new float[3]; 1696 Parameters parameters = mCamera.getParameters(); 1697 parameters.getFocusDistances(distances1); 1698 Thread.sleep(100); 1699 parameters = mCamera.getParameters(); 1700 parameters.getFocusDistances(distances2); 1701 assertEquals(distances1[Parameters.FOCUS_DISTANCE_NEAR_INDEX], 1702 distances2[Parameters.FOCUS_DISTANCE_NEAR_INDEX]); 1703 assertEquals(distances1[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX], 1704 distances2[Parameters.FOCUS_DISTANCE_OPTIMAL_INDEX]); 1705 assertEquals(distances1[Parameters.FOCUS_DISTANCE_FAR_INDEX], 1706 distances2[Parameters.FOCUS_DISTANCE_FAR_INDEX]); 1707 } 1708 1709 @UiThreadTest 1710 public void testMultipleCameras() throws Exception { 1711 int nCameras = Camera.getNumberOfCameras(); 1712 Log.v(TAG, "total " + nCameras + " cameras"); 1713 assertTrue(nCameras >= 0); 1714 1715 boolean backCameraExist = false; 1716 CameraInfo info = new CameraInfo(); 1717 for (int i = 0; i < nCameras; i++) { 1718 Camera.getCameraInfo(i, info); 1719 if (info.facing == CameraInfo.CAMERA_FACING_BACK) { 1720 backCameraExist = true; 1721 break; 1722 } 1723 } 1724 // Make sure original open still works. It must return a back-facing 1725 // camera. 1726 mCamera = Camera.open(); 1727 if (mCamera != null) { 1728 mCamera.release(); 1729 assertTrue(backCameraExist); 1730 } else { 1731 assertFalse(backCameraExist); 1732 } 1733 1734 for (int id = -1; id <= nCameras; id++) { 1735 Log.v(TAG, "testing camera #" + id); 1736 1737 boolean isBadId = (id < 0 || id >= nCameras); 1738 1739 try { 1740 Camera.getCameraInfo(id, info); 1741 if (isBadId) { 1742 fail("getCameraInfo should not accept bad cameraId (" + id + ")"); 1743 } 1744 } catch (RuntimeException e) { 1745 if (!isBadId) throw e; 1746 } 1747 1748 int facing = info.facing; 1749 int orientation = info.orientation; 1750 assertTrue(facing == CameraInfo.CAMERA_FACING_BACK || 1751 facing == CameraInfo.CAMERA_FACING_FRONT); 1752 assertTrue(orientation == 0 || orientation == 90 || 1753 orientation == 180 || orientation == 270); 1754 1755 Camera camera = null; 1756 try { 1757 camera = Camera.open(id); 1758 if (isBadId) { 1759 fail("open() should not accept bad cameraId (" + id + ")"); 1760 } 1761 } catch (RuntimeException e) { 1762 if (!isBadId) throw e; 1763 } finally { 1764 if (camera != null) { 1765 camera.release(); 1766 } 1767 } 1768 } 1769 } 1770 1771 @UiThreadTest 1772 public void testPreviewPictureSizesCombination() throws Exception { 1773 int nCameras = Camera.getNumberOfCameras(); 1774 for (int id = 0; id < nCameras; id++) { 1775 Log.v(TAG, "Camera id=" + id); 1776 testPreviewPictureSizesCombinationByCamera(id); 1777 } 1778 } 1779 1780 private void testPreviewPictureSizesCombinationByCamera(int cameraId) throws Exception { 1781 initializeMessageLooper(cameraId); 1782 Parameters parameters = mCamera.getParameters(); 1783 PreviewCbForPreviewPictureSizesCombination callback = 1784 new PreviewCbForPreviewPictureSizesCombination(); 1785 1786 // Test all combination of preview sizes and picture sizes. 1787 for (Size previewSize: parameters.getSupportedPreviewSizes()) { 1788 for (Size pictureSize: parameters.getSupportedPictureSizes()) { 1789 Log.v(TAG, "Test previewSize=(" + previewSize.width + "," + 1790 previewSize.height + ") pictureSize=(" + 1791 pictureSize.width + "," + pictureSize.height + ")"); 1792 mPreviewCallbackResult = PREVIEW_CALLBACK_NOT_RECEIVED; 1793 mCamera.setPreviewCallback(callback); 1794 callback.expectedPreviewSize = previewSize; 1795 parameters.setPreviewSize(previewSize.width, previewSize.height); 1796 parameters.setPictureSize(pictureSize.width, pictureSize.height); 1797 mCamera.setParameters(parameters); 1798 assertEquals(previewSize, mCamera.getParameters().getPreviewSize()); 1799 assertEquals(pictureSize, mCamera.getParameters().getPictureSize()); 1800 1801 // Check if the preview size is the same as requested. 1802 mCamera.startPreview(); 1803 waitForPreviewDone(); 1804 assertEquals(PREVIEW_CALLBACK_RECEIVED, mPreviewCallbackResult); 1805 1806 // Check if the picture size is the same as requested. 1807 mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback); 1808 waitForSnapshotDone(); 1809 assertTrue(mJpegPictureCallbackResult); 1810 assertNotNull(mJpegData); 1811 BitmapFactory.Options bmpOptions = new BitmapFactory.Options(); 1812 bmpOptions.inJustDecodeBounds = true; 1813 BitmapFactory.decodeByteArray(mJpegData, 0, mJpegData.length, bmpOptions); 1814 assertEquals(pictureSize.width, bmpOptions.outWidth); 1815 assertEquals(pictureSize.height, bmpOptions.outHeight); 1816 } 1817 } 1818 terminateMessageLooper(); 1819 } 1820 1821 private final class PreviewCbForPreviewPictureSizesCombination 1822 implements android.hardware.Camera.PreviewCallback { 1823 public Size expectedPreviewSize; 1824 public void onPreviewFrame(byte[] data, Camera camera) { 1825 if (data == null) { 1826 mPreviewCallbackResult = PREVIEW_CALLBACK_DATA_NULL; 1827 mPreviewDone.open(); 1828 return; 1829 } 1830 Size size = camera.getParameters().getPreviewSize(); 1831 int format = camera.getParameters().getPreviewFormat(); 1832 int bitsPerPixel = ImageFormat.getBitsPerPixel(format); 1833 if (!expectedPreviewSize.equals(size) || 1834 calculateBufferSize(size.width, size.height, 1835 format, bitsPerPixel) != data.length) { 1836 Log.e(TAG, "Expected preview width=" + expectedPreviewSize.width + ", height=" 1837 + expectedPreviewSize.height + ". Actual width=" + size.width + ", height=" 1838 + size.height); 1839 Log.e(TAG, "Frame data length=" + data.length + ". bitsPerPixel=" + bitsPerPixel); 1840 mPreviewCallbackResult = PREVIEW_CALLBACK_INVALID_FRAME_SIZE; 1841 mPreviewDone.open(); 1842 return; 1843 } 1844 camera.setPreviewCallback(null); 1845 mPreviewCallbackResult = PREVIEW_CALLBACK_RECEIVED; 1846 mPreviewDone.open(); 1847 } 1848 } 1849 1850 @UiThreadTest 1851 public void testPreviewFpsRange() throws Exception { 1852 int nCameras = Camera.getNumberOfCameras(); 1853 for (int id = 0; id < nCameras; id++) { 1854 Log.v(TAG, "Camera id=" + id); 1855 testPreviewFpsRangeByCamera(id); 1856 } 1857 } 1858 1859 private void testPreviewFpsRangeByCamera(int cameraId) throws Exception { 1860 initializeMessageLooper(cameraId); 1861 1862 // Test if the parameters exists and minimum fps <= maximum fps. 1863 final int INTERVAL_ERROR_THRESHOLD = 10; 1864 int[] defaultFps = new int[2]; 1865 Parameters parameters = mCamera.getParameters(); 1866 parameters.getPreviewFpsRange(defaultFps); 1867 List<int[]> fpsList = parameters.getSupportedPreviewFpsRange(); 1868 assertTrue(fpsList.size() > 0); 1869 boolean found = false; 1870 for(int[] fps: fpsList) { 1871 assertTrue(fps[Parameters.PREVIEW_FPS_MIN_INDEX] > 0); 1872 assertTrue(fps[Parameters.PREVIEW_FPS_MIN_INDEX] <= 1873 fps[Parameters.PREVIEW_FPS_MAX_INDEX]); 1874 if (!found && Arrays.equals(defaultFps, fps)) { 1875 found = true; 1876 } 1877 } 1878 assertTrue("Preview fps range must be in the supported list.", found); 1879 1880 // Test if the list is properly sorted. 1881 for (int i = 0; i < fpsList.size() - 1; i++) { 1882 int minFps1 = fpsList.get(i)[Parameters.PREVIEW_FPS_MIN_INDEX]; 1883 int maxFps1 = fpsList.get(i)[Parameters.PREVIEW_FPS_MAX_INDEX]; 1884 int minFps2 = fpsList.get(i + 1)[Parameters.PREVIEW_FPS_MIN_INDEX]; 1885 int maxFps2 = fpsList.get(i + 1)[Parameters.PREVIEW_FPS_MAX_INDEX]; 1886 assertTrue(maxFps1 < maxFps2 1887 || (maxFps1 == maxFps2 && minFps1 < minFps2)); 1888 } 1889 1890 // Test if the actual fps is within fps range. 1891 Size size = parameters.getPreviewSize(); 1892 int format = mCamera.getParameters().getPreviewFormat(); 1893 int bitsPerPixel = ImageFormat.getBitsPerPixel(format); 1894 byte[] buffer1 = new byte[size.width * size.height * bitsPerPixel / 8]; 1895 byte[] buffer2 = new byte[size.width * size.height * bitsPerPixel / 8]; 1896 byte[] buffer3 = new byte[size.width * size.height * bitsPerPixel / 8]; 1897 FpsRangePreviewCb callback = new FpsRangePreviewCb(); 1898 int[] readBackFps = new int[2]; 1899 for (int[] fps: fpsList) { 1900 parameters = mCamera.getParameters(); 1901 parameters.setPreviewFpsRange(fps[Parameters.PREVIEW_FPS_MIN_INDEX], 1902 fps[Parameters.PREVIEW_FPS_MAX_INDEX]); 1903 callback.reset(fps[Parameters.PREVIEW_FPS_MIN_INDEX] / 1000.0, 1904 fps[Parameters.PREVIEW_FPS_MAX_INDEX] / 1000.0); 1905 mCamera.setParameters(parameters); 1906 parameters = mCamera.getParameters(); 1907 parameters.getPreviewFpsRange(readBackFps); 1908 MoreAsserts.assertEquals(fps, readBackFps); 1909 mCamera.addCallbackBuffer(buffer1); 1910 mCamera.addCallbackBuffer(buffer2); 1911 mCamera.addCallbackBuffer(buffer3); 1912 mCamera.setPreviewCallbackWithBuffer(callback); 1913 mCamera.startPreview(); 1914 try { 1915 // Test the frame rate for a while. 1916 Thread.sleep(3000); 1917 } catch(Exception e) { 1918 // ignore 1919 } 1920 mCamera.stopPreview(); 1921 // See if any frame duration violations occurred during preview run 1922 AssertionFailedError e = callback.getDurationException(); 1923 if (e != null) throw(e); 1924 int numIntervalError = callback.getNumIntervalError(); 1925 if (numIntervalError > INTERVAL_ERROR_THRESHOLD) { 1926 fail(String.format( 1927 "Too many preview callback frame intervals out of bounds: " + 1928 "Count is %d, limit is %d", 1929 numIntervalError, INTERVAL_ERROR_THRESHOLD)); 1930 } 1931 } 1932 1933 // Test the invalid fps cases. 1934 parameters = mCamera.getParameters(); 1935 parameters.setPreviewFpsRange(-1, -1); 1936 try { 1937 mCamera.setParameters(parameters); 1938 fail("Should throw an exception if fps range is negative."); 1939 } catch (RuntimeException e) { 1940 // expected 1941 } 1942 parameters.setPreviewFpsRange(10, 5); 1943 try { 1944 mCamera.setParameters(parameters); 1945 fail("Should throw an exception if fps range is invalid."); 1946 } catch (RuntimeException e) { 1947 // expected 1948 } 1949 1950 terminateMessageLooper(); 1951 } 1952 1953 private final class FpsRangePreviewCb 1954 implements android.hardware.Camera.PreviewCallback { 1955 private double mMinFps, mMaxFps, mMaxFrameInterval, mMinFrameInterval; 1956 // An array storing the arrival time of the frames in the last second. 1957 private ArrayList<Long> mFrames = new ArrayList<Long>(); 1958 private long firstFrameArrivalTime; 1959 private AssertionFailedError mDurationException = null; 1960 private int numIntervalError; 1961 1962 public void reset(double minFps, double maxFps) { 1963 this.mMinFps = minFps; 1964 this.mMaxFps = maxFps; 1965 mMaxFrameInterval = 1000.0 / mMinFps; 1966 mMinFrameInterval = 1000.0 / mMaxFps; 1967 Log.v(TAG, "Min fps=" + mMinFps + ". Max fps=" + mMaxFps 1968 + ". Min frame interval=" + mMinFrameInterval 1969 + ". Max frame interval=" + mMaxFrameInterval); 1970 mFrames.clear(); 1971 firstFrameArrivalTime = 0; 1972 mDurationException = null; 1973 numIntervalError = 0; 1974 } 1975 1976 // This method tests if the actual fps is between minimum and maximum. 1977 // It also tests if the frame interval is too long. 1978 public void onPreviewFrame(byte[] data, android.hardware.Camera camera) { 1979 long arrivalTime = SystemClock.elapsedRealtime(); 1980 camera.addCallbackBuffer(data); 1981 if (firstFrameArrivalTime == 0) firstFrameArrivalTime = arrivalTime; 1982 1983 // Remove the frames that arrived before the last second. 1984 Iterator<Long> it = mFrames.iterator(); 1985 while(it.hasNext()) { 1986 long time = it.next(); 1987 if (arrivalTime - time > 1000 && mFrames.size() > 2) { 1988 it.remove(); 1989 } else { 1990 break; 1991 } 1992 } 1993 1994 // Start the test after one second. 1995 if (arrivalTime - firstFrameArrivalTime > 1000) { 1996 assertTrue(mFrames.size() >= 2); 1997 1998 // Check the frame interval and fps. The interval check 1999 // considers the time variance passing frames from the camera 2000 // hardware to the callback. It should be a constant time, not a 2001 // ratio. The fps check is more strict because individual 2002 // variance is averaged out. 2003 2004 // Check if the frame interval is too large or too small. 2005 // x100 = percent, intervalMargin should be bigger than 2006 // fpsMargin considering that fps will be in the order of 10. 2007 double intervalMargin = 0.9; 2008 long lastArrivalTime = mFrames.get(mFrames.size() - 1); 2009 double interval = arrivalTime - lastArrivalTime; 2010 if (VERBOSE) Log.v(TAG, "Frame interval=" + interval); 2011 2012 try { 2013 if (interval > mMaxFrameInterval * (1.0 + intervalMargin) || 2014 interval < mMinFrameInterval * (1.0 - intervalMargin)) { 2015 Log.i(TAG, "Bad frame interval=" + interval + "ms. Out out range " + 2016 mMinFrameInterval * (1.0 - intervalMargin) + "/" + 2017 mMaxFrameInterval * (1.0 + intervalMargin)); 2018 numIntervalError++; 2019 } 2020 // Check if the fps is within range. 2021 double fpsMargin = 0.5; // x100 = percent 2022 double avgInterval = (double)(arrivalTime - mFrames.get(0)) 2023 / mFrames.size(); 2024 double fps = 1000.0 / avgInterval; 2025 assertTrue("Actual fps (" + fps + ") should be larger " + 2026 "than min fps (" + mMinFps + ")", 2027 fps >= mMinFps * (1.0 - fpsMargin)); 2028 assertTrue("Actual fps (" + fps + ") should be smaller" + 2029 "than max fps (" + mMaxFps + ")", 2030 fps <= mMaxFps * (1.0 + fpsMargin)); 2031 } catch (AssertionFailedError e) { 2032 // Need to throw this only in the test body, instead of in 2033 // the callback 2034 if (mDurationException == null) { 2035 mDurationException = e; 2036 } 2037 } 2038 } 2039 // Add the arrival time of this frame to the list. 2040 mFrames.add(arrivalTime); 2041 } 2042 2043 public AssertionFailedError getDurationException() { 2044 return mDurationException; 2045 } 2046 public int getNumIntervalError() { 2047 return numIntervalError; 2048 } 2049 } 2050 2051 private void assertEquals(Size expected, Size actual) { 2052 assertEquals(expected.width, actual.width); 2053 assertEquals(expected.height, actual.height); 2054 } 2055 2056 private void assertEquals(float[] expected, float[] actual) { 2057 assertEquals(expected.length, actual.length); 2058 for (int i = 0; i < expected.length; i++) { 2059 assertEquals(expected[i], actual[i], 0.000001f); 2060 } 2061 } 2062 2063 private void assertNoLetters(String value, String key) { 2064 for (int i = 0; i < value.length(); i++) { 2065 char c = value.charAt(i); 2066 assertFalse("Parameter contains invalid characters. key,value=(" 2067 + key + "," + value + ")", 2068 Character.isLetter(c) && c != 'x'); 2069 } 2070 } 2071 2072 @UiThreadTest 2073 public void testSceneMode() throws Exception { 2074 int nCameras = Camera.getNumberOfCameras(); 2075 for (int id = 0; id < nCameras; id++) { 2076 Log.v(TAG, "Camera id=" + id); 2077 testSceneModeByCamera(id); 2078 } 2079 } 2080 2081 private class SceneModeSettings { 2082 public String mScene, mFlash, mFocus, mWhiteBalance; 2083 public List<String> mSupportedFlash, mSupportedFocus, mSupportedWhiteBalance; 2084 2085 public SceneModeSettings(Parameters parameters) { 2086 mScene = parameters.getSceneMode(); 2087 mFlash = parameters.getFlashMode(); 2088 mFocus = parameters.getFocusMode(); 2089 mWhiteBalance = parameters.getWhiteBalance(); 2090 mSupportedFlash = parameters.getSupportedFlashModes(); 2091 mSupportedFocus = parameters.getSupportedFocusModes(); 2092 mSupportedWhiteBalance = parameters.getSupportedWhiteBalance(); 2093 } 2094 } 2095 2096 private void testSceneModeByCamera(int cameraId) throws Exception { 2097 initializeMessageLooper(cameraId); 2098 Parameters parameters = mCamera.getParameters(); 2099 List<String> supportedSceneModes = parameters.getSupportedSceneModes(); 2100 if (supportedSceneModes != null) { 2101 assertEquals(Parameters.SCENE_MODE_AUTO, parameters.getSceneMode()); 2102 SceneModeSettings autoSceneMode = new SceneModeSettings(parameters); 2103 2104 // Store all scene mode affected settings. 2105 SceneModeSettings[] settings = new SceneModeSettings[supportedSceneModes.size()]; 2106 for (int i = 0; i < supportedSceneModes.size(); i++) { 2107 parameters.setSceneMode(supportedSceneModes.get(i)); 2108 mCamera.setParameters(parameters); 2109 parameters = mCamera.getParameters(); 2110 settings[i] = new SceneModeSettings(parameters); 2111 } 2112 2113 // Make sure scene mode settings are consistent before preview and 2114 // after preview. 2115 blockingStartPreview(); 2116 for (int i = 0; i < supportedSceneModes.size(); i++) { 2117 String sceneMode = supportedSceneModes.get(i); 2118 parameters.setSceneMode(sceneMode); 2119 mCamera.setParameters(parameters); 2120 parameters = mCamera.getParameters(); 2121 2122 // In auto scene mode, camera HAL will not remember the previous 2123 // flash, focus, and white-balance. It will just take values set 2124 // by parameters. But the supported flash, focus, and 2125 // white-balance should still be restored in auto scene mode. 2126 if (!Parameters.SCENE_MODE_AUTO.equals(sceneMode)) { 2127 assertEquals("Flash is inconsistent in scene mode " + sceneMode, 2128 settings[i].mFlash, parameters.getFlashMode()); 2129 assertEquals("Focus is inconsistent in scene mode " + sceneMode, 2130 settings[i].mFocus, parameters.getFocusMode()); 2131 assertEquals("White balance is inconsistent in scene mode " + sceneMode, 2132 settings[i].mWhiteBalance, parameters.getWhiteBalance()); 2133 } 2134 assertEquals("Suppported flash modes are inconsistent in scene mode " + sceneMode, 2135 settings[i].mSupportedFlash, parameters.getSupportedFlashModes()); 2136 assertEquals("Suppported focus modes are inconsistent in scene mode " + sceneMode, 2137 settings[i].mSupportedFocus, parameters.getSupportedFocusModes()); 2138 assertEquals("Suppported white balance are inconsistent in scene mode " + sceneMode, 2139 settings[i].mSupportedWhiteBalance, parameters.getSupportedWhiteBalance()); 2140 } 2141 2142 for (int i = 0; i < settings.length; i++) { 2143 if (Parameters.SCENE_MODE_AUTO.equals(settings[i].mScene)) continue; 2144 2145 // Both the setting and the supported settings may change. It is 2146 // allowed to have more than one supported settings in scene 2147 // modes. For example, in night scene mode, supported flash 2148 // modes can have on and off. 2149 if (autoSceneMode.mSupportedFlash != null) { 2150 assertTrue(settings[i].mSupportedFlash.contains(settings[i].mFlash)); 2151 for (String mode: settings[i].mSupportedFlash) { 2152 assertTrue(autoSceneMode.mSupportedFlash.contains(mode)); 2153 } 2154 } 2155 if (autoSceneMode.mSupportedFocus != null) { 2156 assertTrue(settings[i].mSupportedFocus.contains(settings[i].mFocus)); 2157 for (String mode: settings[i].mSupportedFocus) { 2158 assertTrue(autoSceneMode.mSupportedFocus.contains(mode)); 2159 } 2160 } 2161 if (autoSceneMode.mSupportedWhiteBalance != null) { 2162 assertTrue(settings[i].mSupportedWhiteBalance.contains(settings[i].mWhiteBalance)); 2163 for (String mode: settings[i].mSupportedWhiteBalance) { 2164 assertTrue(autoSceneMode.mSupportedWhiteBalance.contains(mode)); 2165 } 2166 } 2167 } 2168 } 2169 terminateMessageLooper(); 2170 } 2171 2172 @UiThreadTest 2173 public void testInvalidParameters() throws Exception { 2174 int nCameras = Camera.getNumberOfCameras(); 2175 for (int id = 0; id < nCameras; id++) { 2176 Log.v(TAG, "Camera id=" + id); 2177 testInvalidParametersByCamera(id); 2178 } 2179 } 2180 2181 private void testInvalidParametersByCamera(int cameraId) throws Exception { 2182 initializeMessageLooper(cameraId); 2183 // Test flash mode. 2184 Parameters parameters = mCamera.getParameters(); 2185 List<String> list = parameters.getSupportedFlashModes(); 2186 if (list != null && list.size() > 0) { 2187 String original = parameters.getFlashMode(); 2188 parameters.setFlashMode("invalid"); 2189 try { 2190 mCamera.setParameters(parameters); 2191 fail("Should throw exception for invalid parameters"); 2192 } catch (RuntimeException e) { 2193 // expected 2194 } 2195 parameters = mCamera.getParameters(); 2196 assertEquals(original, parameters.getFlashMode()); 2197 } 2198 2199 // Test focus mode. 2200 String originalFocus = parameters.getFocusMode(); 2201 parameters.setFocusMode("invalid"); 2202 try { 2203 mCamera.setParameters(parameters); 2204 fail("Should throw exception for invalid parameters"); 2205 } catch (RuntimeException e) { 2206 // expected 2207 } 2208 parameters = mCamera.getParameters(); 2209 assertEquals(originalFocus, parameters.getFocusMode()); 2210 2211 // Test preview size. 2212 Size originalSize = parameters.getPreviewSize(); 2213 parameters.setPreviewSize(-1, -1); 2214 try { 2215 mCamera.setParameters(parameters); 2216 fail("Should throw exception for invalid parameters"); 2217 } catch (RuntimeException e) { 2218 // expected 2219 } 2220 parameters = mCamera.getParameters(); 2221 assertEquals(originalSize, parameters.getPreviewSize()); 2222 2223 terminateMessageLooper(); 2224 } 2225 2226 @UiThreadTest 2227 public void testGetParameterDuringFocus() throws Exception { 2228 int nCameras = Camera.getNumberOfCameras(); 2229 for (int id = 0; id < nCameras; id++) { 2230 Log.v(TAG, "Camera id=" + id); 2231 testGetParameterDuringFocusByCamera(id); 2232 } 2233 } 2234 2235 private void testGetParameterDuringFocusByCamera(int cameraId) throws Exception { 2236 initializeMessageLooper(cameraId); 2237 mCamera.startPreview(); 2238 Parameters parameters = mCamera.getParameters(); 2239 for (String focusMode: parameters.getSupportedFocusModes()) { 2240 if (focusMode.equals(parameters.FOCUS_MODE_AUTO) 2241 || focusMode.equals(parameters.FOCUS_MODE_MACRO)) { 2242 parameters.setFocusMode(focusMode); 2243 mCamera.setParameters(parameters); 2244 mCamera.autoFocus(mAutoFocusCallback); 2245 // This should not crash or throw exception. 2246 mCamera.getParameters(); 2247 waitForFocusDone(); 2248 2249 2250 mCamera.autoFocus(mAutoFocusCallback); 2251 // Add a small delay to make sure focus has started. 2252 Thread.sleep(100); 2253 // This should not crash or throw exception. 2254 mCamera.getParameters(); 2255 waitForFocusDone(); 2256 } 2257 } 2258 terminateMessageLooper(); 2259 } 2260 2261 @UiThreadTest 2262 public void testPreviewFormats() throws Exception { 2263 int nCameras = Camera.getNumberOfCameras(); 2264 for (int id = 0; id < nCameras; id++) { 2265 Log.v(TAG, "Camera id=" + id); 2266 testPreviewFormatsByCamera(id); 2267 } 2268 } 2269 2270 private void testPreviewFormatsByCamera(int cameraId) throws Exception { 2271 initializeMessageLooper(cameraId); 2272 Parameters parameters = mCamera.getParameters(); 2273 for (int format: parameters.getSupportedPreviewFormats()) { 2274 Log.v(TAG, "Test preview format " + format); 2275 parameters.setPreviewFormat(format); 2276 mCamera.setParameters(parameters); 2277 mCamera.setOneShotPreviewCallback(mPreviewCallback); 2278 mCamera.startPreview(); 2279 waitForPreviewDone(); 2280 assertEquals(PREVIEW_CALLBACK_RECEIVED, mPreviewCallbackResult); 2281 } 2282 terminateMessageLooper(); 2283 } 2284 2285 @UiThreadTest 2286 public void testMultiCameraRelease() throws Exception { 2287 // Verify that multiple cameras exist, and that they can be opened at the same time 2288 if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Checking pre-conditions."); 2289 int nCameras = Camera.getNumberOfCameras(); 2290 if (nCameras < 2) { 2291 Log.i(TAG, "Test multi-camera release: Skipping test because only 1 camera available"); 2292 return; 2293 } 2294 2295 Camera testCamera0 = Camera.open(0); 2296 Camera testCamera1 = null; 2297 try { 2298 testCamera1 = Camera.open(1); 2299 } catch (RuntimeException e) { 2300 // Can't open two cameras at once 2301 Log.i(TAG, "testMultiCameraRelease: Skipping test because only 1 camera "+ 2302 "could be opened at once. Second open threw: " + e); 2303 testCamera0.release(); 2304 return; 2305 } 2306 testCamera0.release(); 2307 testCamera1.release(); 2308 2309 // Start first camera 2310 if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Opening camera 0"); 2311 initializeMessageLooper(0); 2312 SimplePreviewStreamCb callback0 = new SimplePreviewStreamCb(0); 2313 mCamera.setPreviewCallback(callback0); 2314 if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Starting preview on camera 0"); 2315 mCamera.startPreview(); 2316 // Run preview for a bit 2317 for (int f = 0; f < 100; f++) { 2318 mPreviewDone.close(); 2319 assertTrue("testMultiCameraRelease: First camera preview timed out on frame " + f + "!", 2320 mPreviewDone.block( WAIT_FOR_COMMAND_TO_COMPLETE)); 2321 } 2322 if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Stopping preview on camera 0"); 2323 mCamera.stopPreview(); 2324 // Save message looper and camera to deterministically release them, instead 2325 // of letting GC do it at some point. 2326 Camera firstCamera = mCamera; 2327 Looper firstLooper = mLooper; 2328 //terminateMessageLooper(); // Intentionally not calling this 2329 // Preview surface should be released though! 2330 mCamera.setPreviewDisplay(null); 2331 2332 // Start second camera without releasing the first one (will 2333 // set mCamera and mLooper to new objects) 2334 if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Opening camera 1"); 2335 initializeMessageLooper(1); 2336 SimplePreviewStreamCb callback1 = new SimplePreviewStreamCb(1); 2337 mCamera.setPreviewCallback(callback1); 2338 if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Starting preview on camera 1"); 2339 mCamera.startPreview(); 2340 // Run preview for a bit - GC of first camera instance should not impact the second's 2341 // operation. 2342 for (int f = 0; f < 100; f++) { 2343 mPreviewDone.close(); 2344 assertTrue("testMultiCameraRelease: Second camera preview timed out on frame " + f + "!", 2345 mPreviewDone.block( WAIT_FOR_COMMAND_TO_COMPLETE)); 2346 if (f == 50) { 2347 // Release first camera mid-preview, should cause no problems 2348 if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Releasing camera 0"); 2349 firstCamera.release(); 2350 } 2351 } 2352 if (VERBOSE) Log.v(TAG, "testMultiCameraRelease: Stopping preview on camera 0"); 2353 mCamera.stopPreview(); 2354 2355 firstLooper.quit(); 2356 terminateMessageLooper(); 2357 } 2358 2359 // This callback just signals on the condition variable, making it useful for checking that 2360 // preview callbacks don't stop unexpectedly 2361 private final class SimplePreviewStreamCb 2362 implements android.hardware.Camera.PreviewCallback { 2363 private int mId; 2364 public SimplePreviewStreamCb(int id) { 2365 mId = id; 2366 } 2367 public void onPreviewFrame(byte[] data, android.hardware.Camera camera) { 2368 if (VERBOSE) Log.v(TAG, "Preview frame callback, id " + mId + "."); 2369 mPreviewDone.open(); 2370 } 2371 } 2372 2373 @UiThreadTest 2374 public void testFocusAreas() throws Exception { 2375 int nCameras = Camera.getNumberOfCameras(); 2376 for (int id = 0; id < nCameras; id++) { 2377 Log.v(TAG, "Camera id=" + id); 2378 2379 initializeMessageLooper(id); 2380 Parameters parameters = mCamera.getParameters(); 2381 int maxNumFocusAreas = parameters.getMaxNumFocusAreas(); 2382 assertTrue(maxNumFocusAreas >= 0); 2383 if (maxNumFocusAreas > 0) { 2384 List<String> focusModes = parameters.getSupportedFocusModes(); 2385 assertTrue(focusModes.contains(Parameters.FOCUS_MODE_AUTO)); 2386 testAreas(FOCUS_AREA, maxNumFocusAreas); 2387 } 2388 terminateMessageLooper(); 2389 } 2390 } 2391 2392 @UiThreadTest 2393 public void testMeteringAreas() throws Exception { 2394 int nCameras = Camera.getNumberOfCameras(); 2395 for (int id = 0; id < nCameras; id++) { 2396 Log.v(TAG, "Camera id=" + id); 2397 initializeMessageLooper(id); 2398 Parameters parameters = mCamera.getParameters(); 2399 int maxNumMeteringAreas = parameters.getMaxNumMeteringAreas(); 2400 assertTrue(maxNumMeteringAreas >= 0); 2401 if (maxNumMeteringAreas > 0) { 2402 testAreas(METERING_AREA, maxNumMeteringAreas); 2403 } 2404 terminateMessageLooper(); 2405 } 2406 } 2407 2408 private void testAreas(int type, int maxNumAreas) throws Exception { 2409 mCamera.startPreview(); 2410 2411 // Test various valid cases. 2412 testValidAreas(type, null); // the default area 2413 testValidAreas(type, makeAreas(-1000, -1000, 1000, 1000, 1)); // biggest area 2414 testValidAreas(type, makeAreas(-500, -500, 500, 500, 1000)); // medium area & biggest weight 2415 testValidAreas(type, makeAreas(0, 0, 1, 1, 1)); // smallest area 2416 2417 ArrayList<Area> areas = new ArrayList(); 2418 if (maxNumAreas > 1) { 2419 // Test overlapped areas. 2420 testValidAreas(type, makeAreas(-250, -250, 250, 250, 1, 0, 0, 500, 500, 2)); 2421 // Test completely disjoint areas. 2422 testValidAreas(type, makeAreas(-250, -250, 0, 0, 1, 900, 900, 1000, 1000, 1)); 2423 // Test the maximum number of areas. 2424 testValidAreas(type, makeAreas(-1000, -1000, 1000, 1000, 1000, maxNumAreas)); 2425 } 2426 2427 // Test various invalid cases. 2428 testInvalidAreas(type, makeAreas(-1001, -1000, 1000, 1000, 1)); // left should >= -1000 2429 testInvalidAreas(type, makeAreas(-1000, -1001, 1000, 1000, 1)); // top should >= -1000 2430 testInvalidAreas(type, makeAreas(-1000, -1000, 1001, 1000, 1)); // right should <= 1000 2431 testInvalidAreas(type, makeAreas(-1000, -1000, 1000, 1001, 1)); // bottom should <= 1000 2432 testInvalidAreas(type, makeAreas(-1000, -1000, 1000, 1000, 0)); // weight should >= 1 2433 testInvalidAreas(type, makeAreas(-1000, -1000, 1000, 1001, 1001)); // weight should <= 1000 2434 testInvalidAreas(type, makeAreas(500, -1000, 500, 1000, 1)); // left should < right 2435 testInvalidAreas(type, makeAreas(-1000, 500, 1000, 500, 1)); // top should < bottom 2436 testInvalidAreas(type, makeAreas(500, -1000, 499, 1000, 1)); // left should < right 2437 testInvalidAreas(type, makeAreas(-1000, 500, 100, 499, 1)); // top should < bottom 2438 testInvalidAreas(type, makeAreas(-250, -250, 250, 250, -1)); // weight should >= 1 2439 // Test when the number of areas exceeds maximum. 2440 testInvalidAreas(type, makeAreas(-1000, -1000, 1000, 1000, 1000, maxNumAreas + 1)); 2441 } 2442 2443 private static ArrayList<Area> makeAreas(int left, int top, int right, int bottom, int weight) { 2444 ArrayList<Area> areas = new ArrayList<Area>(); 2445 areas.add(new Area(new Rect(left, top, right, bottom), weight)); 2446 return areas; 2447 } 2448 2449 private static ArrayList<Area> makeAreas(int left, int top, int right, int bottom, 2450 int weight, int number) { 2451 ArrayList<Area> areas = new ArrayList<Area>(); 2452 for (int i = 0; i < number; i++) { 2453 areas.add(new Area(new Rect(left, top, right, bottom), weight)); 2454 } 2455 return areas; 2456 } 2457 2458 private static ArrayList<Area> makeAreas(int left1, int top1, int right1, 2459 int bottom1, int weight1, int left2, int top2, int right2, 2460 int bottom2, int weight2) { 2461 ArrayList<Area> areas = new ArrayList<Area>(); 2462 areas.add(new Area(new Rect(left1, top1, right1, bottom1), weight1)); 2463 areas.add(new Area(new Rect(left2, top2, right2, bottom2), weight2)); 2464 return areas; 2465 } 2466 2467 private void testValidAreas(int areaType, ArrayList<Area> areas) { 2468 if (areaType == FOCUS_AREA) { 2469 testValidFocusAreas(areas); 2470 } else { 2471 testValidMeteringAreas(areas); 2472 } 2473 } 2474 2475 private void testInvalidAreas(int areaType, ArrayList<Area> areas) { 2476 if (areaType == FOCUS_AREA) { 2477 testInvalidFocusAreas(areas); 2478 } else { 2479 testInvalidMeteringAreas(areas); 2480 } 2481 } 2482 2483 private void testValidFocusAreas(ArrayList<Area> areas) { 2484 Parameters parameters = mCamera.getParameters(); 2485 parameters.setFocusAreas(areas); 2486 mCamera.setParameters(parameters); 2487 parameters = mCamera.getParameters(); 2488 assertEquals(areas, parameters.getFocusAreas()); 2489 mCamera.autoFocus(mAutoFocusCallback); 2490 waitForFocusDone(); 2491 } 2492 2493 private void testInvalidFocusAreas(ArrayList<Area> areas) { 2494 Parameters parameters = mCamera.getParameters(); 2495 List<Area> originalAreas = parameters.getFocusAreas(); 2496 try { 2497 parameters.setFocusAreas(areas); 2498 mCamera.setParameters(parameters); 2499 fail("Should throw exception when focus area is invalid."); 2500 } catch (RuntimeException e) { 2501 parameters = mCamera.getParameters(); 2502 assertEquals(originalAreas, parameters.getFocusAreas()); 2503 } 2504 } 2505 2506 private void testValidMeteringAreas(ArrayList<Area> areas) { 2507 Parameters parameters = mCamera.getParameters(); 2508 parameters.setMeteringAreas(areas); 2509 mCamera.setParameters(parameters); 2510 parameters = mCamera.getParameters(); 2511 assertEquals(areas, parameters.getMeteringAreas()); 2512 } 2513 2514 private void testInvalidMeteringAreas(ArrayList<Area> areas) { 2515 Parameters parameters = mCamera.getParameters(); 2516 List<Area> originalAreas = parameters.getMeteringAreas(); 2517 try { 2518 parameters.setMeteringAreas(areas); 2519 mCamera.setParameters(parameters); 2520 fail("Should throw exception when metering area is invalid."); 2521 } catch (RuntimeException e) { 2522 parameters = mCamera.getParameters(); 2523 assertEquals(originalAreas, parameters.getMeteringAreas()); 2524 } 2525 } 2526 2527 // Apps should be able to call startPreview in jpeg callback. 2528 @UiThreadTest 2529 public void testJpegCallbackStartPreview() throws Exception { 2530 int nCameras = Camera.getNumberOfCameras(); 2531 for (int id = 0; id < nCameras; id++) { 2532 Log.v(TAG, "Camera id=" + id); 2533 testJpegCallbackStartPreviewByCamera(id); 2534 } 2535 } 2536 2537 private void testJpegCallbackStartPreviewByCamera(int cameraId) throws Exception { 2538 initializeMessageLooper(cameraId); 2539 mCamera.startPreview(); 2540 mCamera.takePicture(mShutterCallback, mRawPictureCallback, new JpegStartPreviewCallback()); 2541 waitForSnapshotDone(); 2542 terminateMessageLooper(); 2543 assertTrue(mJpegPictureCallbackResult); 2544 } 2545 2546 private final class JpegStartPreviewCallback implements PictureCallback { 2547 public void onPictureTaken(byte[] rawData, Camera camera) { 2548 try { 2549 camera.startPreview(); 2550 mJpegPictureCallbackResult = true; 2551 } catch (Exception e) { 2552 } 2553 mSnapshotDone.open(); 2554 } 2555 } 2556 2557 @UiThreadTest 2558 public void testRecordingHint() throws Exception { 2559 int nCameras = Camera.getNumberOfCameras(); 2560 for (int id = 0; id < nCameras; id++) { 2561 Log.v(TAG, "Camera id=" + id); 2562 testRecordingHintByCamera(id); 2563 } 2564 } 2565 2566 private void testRecordingHintByCamera(int cameraId) throws Exception { 2567 initializeMessageLooper(cameraId); 2568 Parameters parameters = mCamera.getParameters(); 2569 2570 SurfaceHolder holder = getActivity().getSurfaceView().getHolder(); 2571 CamcorderProfile profile = CamcorderProfile.get(cameraId, 2572 CamcorderProfile.QUALITY_LOW); 2573 2574 setPreviewSizeByProfile(parameters, profile); 2575 2576 // Test recording videos and taking pictures when the hint is off and on. 2577 for (int i = 0; i < 2; i++) { 2578 parameters.setRecordingHint(i == 0 ? false : true); 2579 mCamera.setParameters(parameters); 2580 mCamera.startPreview(); 2581 recordVideoSimple(profile, holder); 2582 mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback); 2583 waitForSnapshotDone(); 2584 assertTrue(mJpegPictureCallbackResult); 2585 } 2586 2587 // Can change recording hint when the preview is active. 2588 mCamera.startPreview(); 2589 parameters.setRecordingHint(false); 2590 mCamera.setParameters(parameters); 2591 parameters.setRecordingHint(true); 2592 mCamera.setParameters(parameters); 2593 terminateMessageLooper(); 2594 } 2595 2596 private void recordVideoSimple(CamcorderProfile profile, 2597 SurfaceHolder holder) throws Exception { 2598 mCamera.unlock(); 2599 MediaRecorder recorder = new MediaRecorder(); 2600 try { 2601 recorder.setCamera(mCamera); 2602 recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); 2603 recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 2604 recorder.setProfile(profile); 2605 recorder.setOutputFile("/dev/null"); 2606 recorder.setPreviewDisplay(holder.getSurface()); 2607 recorder.prepare(); 2608 recorder.start(); 2609 Thread.sleep(2000); 2610 recorder.stop(); 2611 } finally { 2612 recorder.release(); 2613 mCamera.lock(); 2614 } 2615 } 2616 2617 @UiThreadTest 2618 public void testAutoExposureLock() throws Exception { 2619 int nCameras = Camera.getNumberOfCameras(); 2620 for (int id = 0; id < nCameras; id++) { 2621 Log.v(TAG, "Camera id=" + id); 2622 initializeMessageLooper(id); 2623 Parameters parameters = mCamera.getParameters(); 2624 boolean aeLockSupported = parameters.isAutoExposureLockSupported(); 2625 if (aeLockSupported) { 2626 subtestLockCommon(AUTOEXPOSURE_LOCK); 2627 subtestLockAdditionalAE(); 2628 } 2629 terminateMessageLooper(); 2630 } 2631 } 2632 2633 @UiThreadTest 2634 public void testAutoWhiteBalanceLock() throws Exception { 2635 int nCameras = Camera.getNumberOfCameras(); 2636 for (int id = 0; id < nCameras; id++) { 2637 Log.v(TAG, "Camera id=" + id); 2638 initializeMessageLooper(id); 2639 Parameters parameters = mCamera.getParameters(); 2640 boolean awbLockSupported = parameters.isAutoWhiteBalanceLockSupported(); 2641 if (awbLockSupported) { 2642 subtestLockCommon(AUTOWHITEBALANCE_LOCK); 2643 subtestLockAdditionalAWB(); 2644 } 2645 terminateMessageLooper(); 2646 } 2647 } 2648 2649 @UiThreadTest 2650 public void test3ALockInteraction() throws Exception { 2651 int nCameras = Camera.getNumberOfCameras(); 2652 for (int id = 0; id < nCameras; id++) { 2653 Log.v(TAG, "Camera id=" + id); 2654 initializeMessageLooper(id); 2655 Parameters parameters = mCamera.getParameters(); 2656 boolean locksSupported = 2657 parameters.isAutoWhiteBalanceLockSupported() && 2658 parameters.isAutoExposureLockSupported(); 2659 if (locksSupported) { 2660 subtestLockInteractions(); 2661 } 2662 terminateMessageLooper(); 2663 } 2664 } 2665 2666 private void subtestLockCommon(int type) { 2667 // Verify lock is not set on open() 2668 assert3ALockState("Lock not released after open()", type, false); 2669 2670 // Verify lock can be set, unset before preview 2671 set3ALockState(true, type); 2672 assert3ALockState("Lock could not be set before 1st preview!", 2673 type, true); 2674 2675 set3ALockState(false, type); 2676 assert3ALockState("Lock could not be unset before 1st preview!", 2677 type, false); 2678 2679 // Verify preview start does not set lock 2680 mCamera.startPreview(); 2681 assert3ALockState("Lock state changed by preview start!", type, false); 2682 2683 // Verify lock can be set, unset during preview 2684 set3ALockState(true, type); 2685 assert3ALockState("Lock could not be set during preview!", type, true); 2686 2687 set3ALockState(false, type); 2688 assert3ALockState("Lock could not be unset during preview!", 2689 type, false); 2690 2691 // Verify lock is not cleared by stop preview 2692 set3ALockState(true, type); 2693 mCamera.stopPreview(); 2694 assert3ALockState("Lock was cleared by stopPreview!", type, true); 2695 2696 // Verify that preview start does not clear lock 2697 set3ALockState(true, type); 2698 mCamera.startPreview(); 2699 assert3ALockState("Lock state changed by preview start!", type, true); 2700 2701 // Verify that taking a picture does not clear the lock 2702 set3ALockState(true, type); 2703 mCamera.takePicture(mShutterCallback, mRawPictureCallback, 2704 mJpegPictureCallback); 2705 waitForSnapshotDone(); 2706 assert3ALockState("Lock state was cleared by takePicture!", type, true); 2707 2708 mCamera.startPreview(); 2709 Parameters parameters = mCamera.getParameters(); 2710 for (String focusMode: parameters.getSupportedFocusModes()) { 2711 // TODO: Test this for other focus modes as well, once agreement is 2712 // reached on which ones it should apply to 2713 if (!Parameters.FOCUS_MODE_AUTO.equals(focusMode) ) { 2714 continue; 2715 } 2716 2717 parameters.setFocusMode(focusMode); 2718 mCamera.setParameters(parameters); 2719 2720 // Verify that autoFocus does not change the lock 2721 set3ALockState(false, type); 2722 mCamera.autoFocus(mAutoFocusCallback); 2723 assert3ALockState("Lock was set by autoFocus in mode: " + focusMode, type, false); 2724 assertTrue(waitForFocusDone()); 2725 assert3ALockState("Lock was set by autoFocus in mode: " + focusMode, type, false); 2726 2727 // Verify that cancelAutoFocus does not change the lock 2728 mCamera.cancelAutoFocus(); 2729 assert3ALockState("Lock was set by cancelAutoFocus!", type, false); 2730 2731 // Verify that autoFocus does not change the lock 2732 set3ALockState(true, type); 2733 mCamera.autoFocus(mAutoFocusCallback); 2734 assert3ALockState("Lock was cleared by autoFocus in mode: " + focusMode, type, true); 2735 assertTrue(waitForFocusDone()); 2736 assert3ALockState("Lock was cleared by autoFocus in mode: " + focusMode, type, true); 2737 2738 // Verify that cancelAutoFocus does not change the lock 2739 mCamera.cancelAutoFocus(); 2740 assert3ALockState("Lock was cleared by cancelAutoFocus!", type, true); 2741 } 2742 mCamera.stopPreview(); 2743 } 2744 2745 private void subtestLockAdditionalAE() { 2746 // Verify that exposure compensation can be used while 2747 // AE lock is active 2748 mCamera.startPreview(); 2749 Parameters parameters = mCamera.getParameters(); 2750 parameters.setAutoExposureLock(true); 2751 mCamera.setParameters(parameters); 2752 parameters.setExposureCompensation(parameters.getMaxExposureCompensation()); 2753 mCamera.setParameters(parameters); 2754 parameters = mCamera.getParameters(); 2755 assertTrue("Could not adjust exposure compensation with AE locked!", 2756 parameters.getExposureCompensation() == 2757 parameters.getMaxExposureCompensation() ); 2758 2759 parameters.setExposureCompensation(parameters.getMinExposureCompensation()); 2760 mCamera.setParameters(parameters); 2761 parameters = mCamera.getParameters(); 2762 assertTrue("Could not adjust exposure compensation with AE locked!", 2763 parameters.getExposureCompensation() == 2764 parameters.getMinExposureCompensation() ); 2765 mCamera.stopPreview(); 2766 } 2767 2768 private void subtestLockAdditionalAWB() { 2769 // Verify that switching AWB modes clears AWB lock 2770 mCamera.startPreview(); 2771 Parameters parameters = mCamera.getParameters(); 2772 String firstWb = null; 2773 for ( String wbMode: parameters.getSupportedWhiteBalance() ) { 2774 if (firstWb == null) { 2775 firstWb = wbMode; 2776 } 2777 parameters.setWhiteBalance(firstWb); 2778 mCamera.setParameters(parameters); 2779 parameters.setAutoWhiteBalanceLock(true); 2780 mCamera.setParameters(parameters); 2781 2782 parameters.setWhiteBalance(wbMode); 2783 mCamera.setParameters(parameters); 2784 2785 if (firstWb == wbMode) { 2786 assert3ALockState("AWB lock was cleared when WB mode was unchanged!", 2787 AUTOWHITEBALANCE_LOCK, true); 2788 } else { 2789 assert3ALockState("Changing WB mode did not clear AWB lock!", 2790 AUTOWHITEBALANCE_LOCK, false); 2791 } 2792 } 2793 mCamera.stopPreview(); 2794 } 2795 2796 private void subtestLockInteractions() { 2797 // Verify that toggling AE does not change AWB lock state 2798 set3ALockState(false, AUTOWHITEBALANCE_LOCK); 2799 set3ALockState(false, AUTOEXPOSURE_LOCK); 2800 2801 set3ALockState(true, AUTOEXPOSURE_LOCK); 2802 assert3ALockState("Changing AE lock affected AWB lock!", 2803 AUTOWHITEBALANCE_LOCK, false); 2804 2805 set3ALockState(false, AUTOEXPOSURE_LOCK); 2806 assert3ALockState("Changing AE lock affected AWB lock!", 2807 AUTOWHITEBALANCE_LOCK, false); 2808 2809 set3ALockState(true, AUTOWHITEBALANCE_LOCK); 2810 2811 set3ALockState(true, AUTOEXPOSURE_LOCK); 2812 assert3ALockState("Changing AE lock affected AWB lock!", 2813 AUTOWHITEBALANCE_LOCK, true); 2814 2815 set3ALockState(false, AUTOEXPOSURE_LOCK); 2816 assert3ALockState("Changing AE lock affected AWB lock!", 2817 AUTOWHITEBALANCE_LOCK, true); 2818 2819 // Verify that toggling AWB does not change AE lock state 2820 set3ALockState(false, AUTOWHITEBALANCE_LOCK); 2821 set3ALockState(false, AUTOEXPOSURE_LOCK); 2822 2823 set3ALockState(true, AUTOWHITEBALANCE_LOCK); 2824 assert3ALockState("Changing AWB lock affected AE lock!", 2825 AUTOEXPOSURE_LOCK, false); 2826 2827 set3ALockState(false, AUTOWHITEBALANCE_LOCK); 2828 assert3ALockState("Changing AWB lock affected AE lock!", 2829 AUTOEXPOSURE_LOCK, false); 2830 2831 set3ALockState(true, AUTOEXPOSURE_LOCK); 2832 2833 set3ALockState(true, AUTOWHITEBALANCE_LOCK); 2834 assert3ALockState("Changing AWB lock affected AE lock!", 2835 AUTOEXPOSURE_LOCK, true); 2836 2837 set3ALockState(false, AUTOWHITEBALANCE_LOCK); 2838 assert3ALockState("Changing AWB lock affected AE lock!", 2839 AUTOEXPOSURE_LOCK, true); 2840 } 2841 2842 private void assert3ALockState(String msg, int type, boolean state) { 2843 Parameters parameters = mCamera.getParameters(); 2844 switch (type) { 2845 case AUTOEXPOSURE_LOCK: 2846 assertTrue(msg, state == parameters.getAutoExposureLock()); 2847 break; 2848 case AUTOWHITEBALANCE_LOCK: 2849 assertTrue(msg, state == parameters.getAutoWhiteBalanceLock()); 2850 break; 2851 default: 2852 assertTrue("Unknown lock type " + type, false); 2853 break; 2854 } 2855 } 2856 2857 private void set3ALockState(boolean state, int type) { 2858 Parameters parameters = mCamera.getParameters(); 2859 switch (type) { 2860 case AUTOEXPOSURE_LOCK: 2861 parameters.setAutoExposureLock(state); 2862 break; 2863 case AUTOWHITEBALANCE_LOCK: 2864 parameters.setAutoWhiteBalanceLock(state); 2865 break; 2866 default: 2867 assertTrue("Unknown lock type "+type, false); 2868 break; 2869 } 2870 mCamera.setParameters(parameters); 2871 } 2872 2873 @UiThreadTest 2874 public void testFaceDetection() throws Exception { 2875 int nCameras = Camera.getNumberOfCameras(); 2876 for (int id = 0; id < nCameras; id++) { 2877 Log.v(TAG, "Camera id=" + id); 2878 testFaceDetectionByCamera(id); 2879 } 2880 } 2881 2882 private void testFaceDetectionByCamera(int cameraId) throws Exception { 2883 final int FACE_DETECTION_TEST_DURATION = 3000; 2884 initializeMessageLooper(cameraId); 2885 mCamera.startPreview(); 2886 Parameters parameters = mCamera.getParameters(); 2887 int maxNumOfFaces = parameters.getMaxNumDetectedFaces(); 2888 assertTrue(maxNumOfFaces >= 0); 2889 if (maxNumOfFaces == 0) { 2890 try { 2891 mCamera.startFaceDetection(); 2892 fail("Should throw an exception if face detection is not supported."); 2893 } catch (IllegalArgumentException e) { 2894 // expected 2895 } 2896 terminateMessageLooper(); 2897 return; 2898 } 2899 2900 mCamera.startFaceDetection(); 2901 try { 2902 mCamera.startFaceDetection(); 2903 fail("Starting face detection twice should throw an exception"); 2904 } catch (RuntimeException e) { 2905 // expected 2906 } 2907 FaceListener listener = new FaceListener(); 2908 mCamera.setFaceDetectionListener(listener); 2909 // Sleep some time so the camera has chances to detect faces. 2910 Thread.sleep(FACE_DETECTION_TEST_DURATION); 2911 // The face callback runs in another thread. Release the camera and stop 2912 // the looper. So we do not access the face array from two threads at 2913 // the same time. 2914 terminateMessageLooper(); 2915 2916 // Check if the optional fields are supported. 2917 boolean optionalFieldSupported = false; 2918 Face firstFace = null; 2919 for (Face[] faces: listener.mFacesArray) { 2920 for (Face face: faces) { 2921 if (face != null) firstFace = face; 2922 } 2923 } 2924 if (firstFace != null) { 2925 if (firstFace.id != -1 || firstFace.leftEye != null 2926 || firstFace.rightEye != null || firstFace.mouth != null) { 2927 optionalFieldSupported = true; 2928 } 2929 } 2930 2931 // Verify the faces array. 2932 for (Face[] faces: listener.mFacesArray) { 2933 testFaces(faces, maxNumOfFaces, optionalFieldSupported); 2934 } 2935 2936 // After taking a picture, face detection should be started again. 2937 // Also make sure autofocus move callback is supported. 2938 initializeMessageLooper(cameraId); 2939 mCamera.setAutoFocusMoveCallback(mAutoFocusMoveCallback); 2940 mCamera.startPreview(); 2941 mCamera.startFaceDetection(); 2942 mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback); 2943 waitForSnapshotDone(); 2944 mCamera.startPreview(); 2945 mCamera.startFaceDetection(); 2946 terminateMessageLooper(); 2947 } 2948 2949 private class FaceListener implements FaceDetectionListener { 2950 public ArrayList<Face[]> mFacesArray = new ArrayList<Face[]>(); 2951 2952 @Override 2953 public void onFaceDetection(Face[] faces, Camera camera) { 2954 mFacesArray.add(faces); 2955 } 2956 } 2957 2958 private void testFaces(Face[] faces, int maxNumOfFaces, 2959 boolean optionalFieldSupported) { 2960 Rect bounds = new Rect(-1000, -1000, 1000, 1000); 2961 assertNotNull(faces); 2962 assertTrue(faces.length <= maxNumOfFaces); 2963 for (int i = 0; i < faces.length; i++) { 2964 Face face = faces[i]; 2965 Rect rect = face.rect; 2966 // Check the bounds. 2967 assertNotNull(rect); 2968 assertTrue(rect.width() > 0); 2969 assertTrue(rect.height() > 0); 2970 assertTrue("Coordinates out of bounds. rect=" + rect, 2971 bounds.contains(rect) || Rect.intersects(bounds, rect)); 2972 2973 // Check the score. 2974 assertTrue(face.score >= 1 && face.score <= 100); 2975 2976 // Check id, left eye, right eye, and the mouth. 2977 // Optional fields should be all valid or none of them. 2978 if (!optionalFieldSupported) { 2979 assertEquals(-1, face.id); 2980 assertNull(face.leftEye); 2981 assertNull(face.rightEye); 2982 assertNull(face.mouth); 2983 } else { 2984 assertTrue(face.id != -1); 2985 assertNotNull(face.leftEye); 2986 assertNotNull(face.rightEye); 2987 assertNotNull(face.mouth); 2988 assertTrue(bounds.contains(face.leftEye.x, face.leftEye.y)); 2989 assertTrue(bounds.contains(face.rightEye.x, face.rightEye.y)); 2990 assertTrue(bounds.contains(face.mouth.x, face.mouth.y)); 2991 // ID should be unique. 2992 if (i != faces.length - 1) { 2993 assertTrue(face.id != faces[i + 1].id); 2994 } 2995 } 2996 } 2997 } 2998 2999 @UiThreadTest 3000 public void testVideoSnapshot() throws Exception { 3001 int nCameras = Camera.getNumberOfCameras(); 3002 for (int id = 0; id < nCameras; id++) { 3003 Log.v(TAG, "Camera id=" + id); 3004 testVideoSnapshotByCamera(id); 3005 } 3006 } 3007 3008 private static final int[] mCamcorderProfileList = { 3009 CamcorderProfile.QUALITY_2160P, 3010 CamcorderProfile.QUALITY_1080P, 3011 CamcorderProfile.QUALITY_480P, 3012 CamcorderProfile.QUALITY_720P, 3013 CamcorderProfile.QUALITY_CIF, 3014 CamcorderProfile.QUALITY_HIGH, 3015 CamcorderProfile.QUALITY_LOW, 3016 CamcorderProfile.QUALITY_QCIF, 3017 CamcorderProfile.QUALITY_QVGA, 3018 }; 3019 3020 private void testVideoSnapshotByCamera(int cameraId) throws Exception { 3021 initializeMessageLooper(cameraId); 3022 Camera.Parameters parameters = mCamera.getParameters(); 3023 terminateMessageLooper(); 3024 if (!parameters.isVideoSnapshotSupported()) { 3025 return; 3026 } 3027 3028 SurfaceHolder holder = getActivity().getSurfaceView().getHolder(); 3029 3030 for (int profileId: mCamcorderProfileList) { 3031 if (!CamcorderProfile.hasProfile(cameraId, profileId)) { 3032 continue; 3033 } 3034 initializeMessageLooper(cameraId); 3035 // Set the preview size. 3036 CamcorderProfile profile = CamcorderProfile.get(cameraId, 3037 profileId); 3038 setPreviewSizeByProfile(parameters, profile); 3039 3040 // Set the biggest picture size. 3041 Size biggestSize = mCamera.new Size(-1, -1); 3042 for (Size size: parameters.getSupportedPictureSizes()) { 3043 if (biggestSize.width < size.width) { 3044 biggestSize = size; 3045 } 3046 } 3047 parameters.setPictureSize(biggestSize.width, biggestSize.height); 3048 3049 mCamera.setParameters(parameters); 3050 mCamera.startPreview(); 3051 mCamera.unlock(); 3052 MediaRecorder recorder = new MediaRecorder(); 3053 try { 3054 recorder.setCamera(mCamera); 3055 recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); 3056 recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 3057 recorder.setProfile(profile); 3058 recorder.setOutputFile("/dev/null"); 3059 recorder.setPreviewDisplay(holder.getSurface()); 3060 recorder.prepare(); 3061 recorder.start(); 3062 subtestTakePictureByCamera(true, 3063 profile.videoFrameWidth, profile.videoFrameHeight); 3064 testJpegExifByCamera(true); 3065 testJpegThumbnailSizeByCamera(true, 3066 profile.videoFrameWidth, profile.videoFrameHeight); 3067 Thread.sleep(2000); 3068 recorder.stop(); 3069 } finally { 3070 recorder.release(); 3071 mCamera.lock(); 3072 } 3073 mCamera.stopPreview(); 3074 terminateMessageLooper(); 3075 } 3076 } 3077 3078 public void testPreviewCallbackWithPicture() throws Exception { 3079 int nCameras = Camera.getNumberOfCameras(); 3080 for (int id = 0; id < nCameras; id++) { 3081 Log.v(TAG, "Camera id=" + id); 3082 testPreviewCallbackWithPictureByCamera(id); 3083 } 3084 } 3085 3086 private void testPreviewCallbackWithPictureByCamera(int cameraId) 3087 throws Exception { 3088 initializeMessageLooper(cameraId); 3089 3090 SimplePreviewStreamCb callback = new SimplePreviewStreamCb(1); 3091 mCamera.setPreviewCallback(callback); 3092 3093 Log.v(TAG, "Starting preview"); 3094 mCamera.startPreview(); 3095 3096 // Wait until callbacks are flowing 3097 for (int i = 0; i < 30; i++) { 3098 assertTrue("testPreviewCallbackWithPicture: Not receiving preview callbacks!", 3099 mPreviewDone.block( WAIT_FOR_COMMAND_TO_COMPLETE ) ); 3100 mPreviewDone.close(); 3101 } 3102 3103 // Now take a picture 3104 Log.v(TAG, "Taking picture now"); 3105 3106 Size pictureSize = mCamera.getParameters().getPictureSize(); 3107 mCamera.takePicture(mShutterCallback, mRawPictureCallback, 3108 mJpegPictureCallback); 3109 3110 waitForSnapshotDone(); 3111 3112 assertTrue("Shutter callback not received", mShutterCallbackResult); 3113 assertTrue("Raw picture callback not received", mRawPictureCallbackResult); 3114 assertTrue("Jpeg picture callback not received", mJpegPictureCallbackResult); 3115 assertNotNull(mJpegData); 3116 BitmapFactory.Options bmpOptions = new BitmapFactory.Options(); 3117 bmpOptions.inJustDecodeBounds = true; 3118 BitmapFactory.decodeByteArray(mJpegData, 0, mJpegData.length, bmpOptions); 3119 assertEquals(pictureSize.width, bmpOptions.outWidth); 3120 assertEquals(pictureSize.height, bmpOptions.outHeight); 3121 3122 // Restart preview, confirm callbacks still happen 3123 Log.v(TAG, "Restarting preview"); 3124 mCamera.startPreview(); 3125 3126 for (int i = 0; i < 30; i++) { 3127 assertTrue("testPreviewCallbackWithPicture: Not receiving preview callbacks!", 3128 mPreviewDone.block( WAIT_FOR_COMMAND_TO_COMPLETE ) ); 3129 mPreviewDone.close(); 3130 } 3131 3132 mCamera.stopPreview(); 3133 3134 terminateMessageLooper(); 3135 } 3136 3137 public void testEnableShutterSound() throws Exception { 3138 int nCameras = Camera.getNumberOfCameras(); 3139 for (int id = 0; id < nCameras; id++) { 3140 Log.v(TAG, "Camera id=" + id); 3141 testEnableShutterSoundByCamera(id); 3142 } 3143 } 3144 3145 private void testEnableShutterSoundByCamera(int id) throws Exception { 3146 CameraInfo info = new CameraInfo(); 3147 3148 Camera.getCameraInfo(id, info); 3149 3150 initializeMessageLooper(id); 3151 3152 boolean result; 3153 Log.v(TAG, "testEnableShutterSoundByCamera: canDisableShutterSound: " + 3154 info.canDisableShutterSound); 3155 result = mCamera.enableShutterSound(false); 3156 assertTrue(result == info.canDisableShutterSound); 3157 result = mCamera.enableShutterSound(true); 3158 assertTrue(result); 3159 3160 terminateMessageLooper(); 3161 } 3162 3163 public void testCameraExternalConnected() { 3164 if (getActivity().getPackageManager(). 3165 hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL) ) { 3166 int nCameras = Camera.getNumberOfCameras(); 3167 assertTrue("Devices with external camera support must have a camera connected for " + 3168 "testing", 3169 nCameras > 0); 3170 for (int id = 0; id < nCameras; id++) { 3171 try { 3172 Camera c = Camera.open(id); 3173 c.release(); 3174 } catch (Throwable e) { 3175 throw new AssertionError("Devices with external camera support must " + 3176 "have all listed cameras be connected and openable for testing", e); 3177 } 3178 } 3179 } 3180 } 3181 3182 } 3183