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