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