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