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