1 /* 2 * Copyright (C) 2014 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.camera2.cts.testcases; 18 19 import static android.hardware.camera2.cts.CameraTestUtils.*; 20 import static com.android.ex.camera2.blocking.BlockingStateCallback.*; 21 22 import android.content.Context; 23 import android.graphics.ImageFormat; 24 import android.graphics.Rect; 25 import android.hardware.cts.helpers.CameraParameterizedTestCase; 26 import android.hardware.camera2.CameraCaptureSession; 27 import android.hardware.camera2.CameraCaptureSession.CaptureCallback; 28 import android.hardware.camera2.CameraCharacteristics; 29 import android.hardware.camera2.CameraDevice; 30 import android.hardware.camera2.CameraManager; 31 import android.hardware.camera2.CaptureRequest; 32 import android.hardware.camera2.params.InputConfiguration; 33 import android.hardware.camera2.params.OutputConfiguration; 34 import android.hardware.camera2.params.SessionConfiguration; 35 import android.util.Size; 36 import android.hardware.camera2.cts.Camera2ParameterizedTestCase; 37 import android.hardware.camera2.cts.CameraTestUtils; 38 import android.hardware.camera2.cts.helpers.CameraErrorCollector; 39 import android.hardware.camera2.cts.helpers.StaticMetadata; 40 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel; 41 import android.media.Image; 42 import android.media.Image.Plane; 43 import android.media.ImageReader; 44 import android.os.Handler; 45 import android.os.HandlerThread; 46 import android.test.AndroidTestCase; 47 import android.util.Log; 48 import android.view.Surface; 49 import android.view.WindowManager; 50 import androidx.test.InstrumentationRegistry; 51 52 import com.android.ex.camera2.blocking.BlockingSessionCallback; 53 import com.android.ex.camera2.blocking.BlockingStateCallback; 54 55 import java.io.File; 56 import java.nio.ByteBuffer; 57 import java.util.ArrayList; 58 import java.util.Arrays; 59 import java.util.HashMap; 60 import java.util.List; 61 62 import org.junit.Ignore; 63 import org.junit.Test; 64 65 // TODO: Can we de-duplicate this with Camera2AndroidBasicTestCase keeping in mind CtsVerifier ? 66 public class Camera2AndroidTestCase extends Camera2ParameterizedTestCase { 67 private static final String TAG = "Camera2AndroidTestCase"; 68 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 69 70 // Default capture size: VGA size is required by CDD. 71 protected static final Size DEFAULT_CAPTURE_SIZE = new Size(640, 480); 72 protected static final int CAPTURE_WAIT_TIMEOUT_MS = 7000; 73 74 protected CameraDevice mCamera; 75 protected CameraCaptureSession mCameraSession; 76 protected BlockingSessionCallback mCameraSessionListener; 77 protected BlockingStateCallback mCameraListener; 78 // include both standalone camera IDs and "hidden" physical camera IDs 79 protected String[] mAllCameraIds; 80 protected HashMap<String, StaticMetadata> mAllStaticInfo; 81 protected ImageReader mReader; 82 protected Surface mReaderSurface; 83 protected Handler mHandler; 84 protected HandlerThread mHandlerThread; 85 protected StaticMetadata mStaticInfo; 86 protected CameraErrorCollector mCollector; 87 protected List<Size> mOrderedPreviewSizes; // In descending order. 88 protected List<Size> mOrderedVideoSizes; // In descending order. 89 protected List<Size> mOrderedStillSizes; // In descending order. 90 protected String mDebugFileNameBase; 91 92 protected WindowManager mWindowManager; 93 94 /** 95 * Set up the camera2 test case required environments, including CameraManager, 96 * HandlerThread, Camera IDs, and CameraStateCallback etc. 97 */ 98 @Override setUp()99 public void setUp() throws Exception { 100 setUp(false); 101 } 102 103 /** 104 * Set up the camera2 test case required environments, including CameraManager, 105 * HandlerThread, Camera IDs, and CameraStateCallback etc. 106 * @param useAll whether all camera ids are to be used for system camera tests 107 */ setUp(boolean useAll)108 public void setUp(boolean useAll) throws Exception { 109 super.setUp(useAll); 110 mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 111 112 mHandlerThread = new HandlerThread(TAG); 113 mHandlerThread.start(); 114 mHandler = new Handler(mHandlerThread.getLooper()); 115 mCameraListener = new BlockingStateCallback(); 116 mCollector = new CameraErrorCollector(); 117 118 File filesDir = mContext.getPackageManager().isInstantApp() 119 ? mContext.getFilesDir() 120 : mContext.getExternalFilesDir(null); 121 122 mDebugFileNameBase = filesDir.getPath(); 123 124 mAllStaticInfo = new HashMap<String, StaticMetadata>(); 125 List<String> hiddenPhysicalIds = new ArrayList<>(); 126 for (String cameraId : mCameraIdsUnderTest) { 127 CameraCharacteristics props = mCameraManager.getCameraCharacteristics(cameraId); 128 StaticMetadata staticMetadata = new StaticMetadata(props, 129 CheckLevel.ASSERT, /*collector*/null); 130 mAllStaticInfo.put(cameraId, staticMetadata); 131 132 for (String physicalId : props.getPhysicalCameraIds()) { 133 if (!Arrays.asList(mCameraIdsUnderTest).contains(physicalId) && 134 !hiddenPhysicalIds.contains(physicalId)) { 135 hiddenPhysicalIds.add(physicalId); 136 props = mCameraManager.getCameraCharacteristics(physicalId); 137 staticMetadata = new StaticMetadata( 138 mCameraManager.getCameraCharacteristics(physicalId), 139 CheckLevel.ASSERT, /*collector*/null); 140 mAllStaticInfo.put(physicalId, staticMetadata); 141 } 142 } 143 } 144 mAllCameraIds = new String[mCameraIdsUnderTest.length + hiddenPhysicalIds.size()]; 145 System.arraycopy(mCameraIdsUnderTest, 0, mAllCameraIds, 0, mCameraIdsUnderTest.length); 146 for (int i = 0; i < hiddenPhysicalIds.size(); i++) { 147 mAllCameraIds[mCameraIdsUnderTest.length + i] = hiddenPhysicalIds.get(i); 148 } 149 } 150 151 @Override tearDown()152 public void tearDown() throws Exception { 153 try { 154 if (mHandlerThread != null) { 155 mHandlerThread.quitSafely(); 156 } 157 mHandler = null; 158 closeDefaultImageReader(); 159 160 if (mCollector != null) { 161 mCollector.verify(); 162 } 163 } catch (Throwable e) { 164 // When new Exception(e) is used, exception info will be printed twice. 165 throw new Exception(e.getMessage()); 166 } finally { 167 super.tearDown(); 168 } 169 } 170 171 /** 172 * Start capture with given {@link #CaptureRequest}. 173 * 174 * @param request The {@link #CaptureRequest} to be captured. 175 * @param repeating If the capture is single capture or repeating. 176 * @param listener The {@link #CaptureCallback} camera device used to notify callbacks. 177 * @param handler The handler camera device used to post callbacks. 178 */ startCapture(CaptureRequest request, boolean repeating, CaptureCallback listener, Handler handler)179 protected void startCapture(CaptureRequest request, boolean repeating, 180 CaptureCallback listener, Handler handler) throws Exception { 181 if (VERBOSE) Log.v(TAG, "Starting capture from device"); 182 183 if (repeating) { 184 mCameraSession.setRepeatingRequest(request, listener, handler); 185 } else { 186 mCameraSession.capture(request, listener, handler); 187 } 188 } 189 190 /** 191 * Stop the current active capture. 192 * 193 * @param fast When it is true, {@link CameraDevice#flush} is called, the stop capture 194 * could be faster. 195 */ stopCapture(boolean fast)196 protected void stopCapture(boolean fast) throws Exception { 197 if (VERBOSE) Log.v(TAG, "Stopping capture"); 198 199 if (fast) { 200 /** 201 * Flush is useful for canceling long exposure single capture, it also could help 202 * to make the streaming capture stop sooner. 203 */ 204 mCameraSession.abortCaptures(); 205 mCameraSessionListener.getStateWaiter(). 206 waitForState(BlockingSessionCallback.SESSION_READY, CAMERA_IDLE_TIMEOUT_MS); 207 } else { 208 mCameraSession.close(); 209 mCameraSessionListener.getStateWaiter(). 210 waitForState(BlockingSessionCallback.SESSION_CLOSED, CAMERA_IDLE_TIMEOUT_MS); 211 } 212 } 213 214 /** 215 * Open a {@link #CameraDevice camera device} and get the StaticMetadata for a given camera id. 216 * The default mCameraListener is used to wait for states. 217 * 218 * @param cameraId The id of the camera device to be opened. 219 */ openDevice(String cameraId)220 protected void openDevice(String cameraId) throws Exception { 221 openDevice(cameraId, mCameraListener); 222 } 223 224 /** 225 * Open a {@link #CameraDevice} and get the StaticMetadata for a given camera id and listener. 226 * 227 * @param cameraId The id of the camera device to be opened. 228 * @param listener The {@link #BlockingStateCallback} used to wait for states. 229 */ openDevice(String cameraId, BlockingStateCallback listener)230 protected void openDevice(String cameraId, BlockingStateCallback listener) throws Exception { 231 mCamera = CameraTestUtils.openCamera( 232 mCameraManager, cameraId, listener, mHandler); 233 mCollector.setCameraId(cameraId); 234 mStaticInfo = mAllStaticInfo.get(cameraId); 235 if (mStaticInfo.isColorOutputSupported()) { 236 mOrderedPreviewSizes = getSupportedPreviewSizes( 237 cameraId, mCameraManager, 238 getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND)); 239 mOrderedVideoSizes = getSupportedVideoSizes(cameraId, mCameraManager, PREVIEW_SIZE_BOUND); 240 mOrderedStillSizes = getSupportedStillSizes(cameraId, mCameraManager, null); 241 } 242 243 if (VERBOSE) { 244 Log.v(TAG, "Camera " + cameraId + " is opened"); 245 } 246 } 247 248 /** 249 * Create a {@link #CameraCaptureSession} using the currently open camera. 250 * 251 * @param outputSurfaces The set of output surfaces to configure for this session 252 */ createSession(List<Surface> outputSurfaces)253 protected void createSession(List<Surface> outputSurfaces) throws Exception { 254 mCameraSessionListener = new BlockingSessionCallback(); 255 mCameraSession = CameraTestUtils.configureCameraSession(mCamera, outputSurfaces, 256 mCameraSessionListener, mHandler); 257 } 258 259 /** 260 * Create a reprocessable {@link #CameraCaptureSession} using the currently open camera. 261 * 262 * @param inputConfiguration The inputConfiguration for this session 263 * @param outputSurfaces The set of output surfaces to configure for this session 264 */ createReprocessableSession(InputConfiguration inputConfig, List<Surface> outputSurfaces)265 protected void createReprocessableSession(InputConfiguration inputConfig, 266 List<Surface> outputSurfaces) throws Exception { 267 mCameraSessionListener = new BlockingSessionCallback(); 268 mCameraSession = CameraTestUtils.configureReprocessableCameraSession( 269 mCamera, inputConfig, outputSurfaces, mCameraSessionListener, mHandler); 270 } 271 272 /** 273 * Create a {@link #CameraCaptureSession} using the currently open camera with 274 * OutputConfigurations. 275 * 276 * @param outputSurfaces The set of output surfaces to configure for this session 277 */ createSessionByConfigs(List<OutputConfiguration> outputConfigs)278 protected void createSessionByConfigs(List<OutputConfiguration> outputConfigs) throws Exception { 279 mCameraSessionListener = new BlockingSessionCallback(); 280 mCameraSession = CameraTestUtils.configureCameraSessionWithConfig(mCamera, outputConfigs, 281 mCameraSessionListener, mHandler); 282 } 283 284 /** 285 * Close a {@link #CameraDevice camera device} and clear the associated StaticInfo field for a 286 * given camera id. The default mCameraListener is used to wait for states. 287 * <p> 288 * This function must be used along with the {@link #openDevice} for the 289 * same camera id. 290 * </p> 291 * 292 * @param cameraId The id of the {@link #CameraDevice camera device} to be closed. 293 */ closeDevice(String cameraId)294 protected void closeDevice(String cameraId) { 295 closeDevice(cameraId, mCameraListener); 296 } 297 298 /** 299 * Close a {@link #CameraDevice camera device} and clear the associated StaticInfo field for a 300 * given camera id and listener. 301 * <p> 302 * This function must be used along with the {@link #openDevice} for the 303 * same camera id. 304 * </p> 305 * 306 * @param cameraId The id of the camera device to be closed. 307 * @param listener The BlockingStateCallback used to wait for states. 308 */ closeDevice(String cameraId, BlockingStateCallback listener)309 protected void closeDevice(String cameraId, BlockingStateCallback listener) { 310 if (mCamera != null) { 311 if (!cameraId.equals(mCamera.getId())) { 312 throw new IllegalStateException("Try to close a device that is not opened yet"); 313 } 314 mCamera.close(); 315 listener.waitForState(STATE_CLOSED, CAMERA_CLOSE_TIMEOUT_MS); 316 mCamera = null; 317 mCameraSession = null; 318 mCameraSessionListener = null; 319 mStaticInfo = null; 320 mOrderedPreviewSizes = null; 321 mOrderedVideoSizes = null; 322 mOrderedStillSizes = null; 323 324 if (VERBOSE) { 325 Log.v(TAG, "Camera " + cameraId + " is closed"); 326 } 327 } 328 } 329 330 /** 331 * Create an {@link ImageReader} object and get the surface. 332 * <p> 333 * This function creates {@link ImageReader} object and surface, then assign 334 * to the default {@link mReader} and {@link mReaderSurface}. It closes the 335 * current default active {@link ImageReader} if it exists. 336 * </p> 337 * 338 * @param size The size of this ImageReader to be created. 339 * @param format The format of this ImageReader to be created 340 * @param maxNumImages The max number of images that can be acquired 341 * simultaneously. 342 * @param listener The listener used by this ImageReader to notify 343 * callbacks. 344 */ createDefaultImageReader(Size size, int format, int maxNumImages, ImageReader.OnImageAvailableListener listener)345 protected void createDefaultImageReader(Size size, int format, int maxNumImages, 346 ImageReader.OnImageAvailableListener listener) throws Exception { 347 closeDefaultImageReader(); 348 349 mReader = createImageReader(size, format, maxNumImages, listener); 350 mReaderSurface = mReader.getSurface(); 351 if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString()); 352 } 353 354 /** 355 * Create an {@link ImageReader} object and get the surface. 356 * <p> 357 * This function creates {@link ImageReader} object and surface, then assign 358 * to the default {@link mReader} and {@link mReaderSurface}. It closes the 359 * current default active {@link ImageReader} if it exists. 360 * </p> 361 * 362 * @param size The size of this ImageReader to be created. 363 * @param format The format of this ImageReader to be created 364 * @param maxNumImages The max number of images that can be acquired 365 * simultaneously. 366 * @param usage The usage flag of the ImageReader 367 * @param listener The listener used by this ImageReader to notify 368 * callbacks. 369 */ createDefaultImageReader(Size size, int format, int maxNumImages, long usage, ImageReader.OnImageAvailableListener listener)370 protected void createDefaultImageReader(Size size, int format, int maxNumImages, long usage, 371 ImageReader.OnImageAvailableListener listener) throws Exception { 372 closeDefaultImageReader(); 373 374 mReader = createImageReader(size, format, maxNumImages, usage, listener); 375 mReaderSurface = mReader.getSurface(); 376 if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString()); 377 } 378 379 /** 380 * Create an {@link ImageReader} object. 381 * 382 * <p>This function creates image reader object for given format, maxImages, and size.</p> 383 * 384 * @param size The size of this ImageReader to be created. 385 * @param format The format of this ImageReader to be created 386 * @param maxNumImages The max number of images that can be acquired simultaneously. 387 * @param listener The listener used by this ImageReader to notify callbacks. 388 */ 389 createImageReader(Size size, int format, int maxNumImages, ImageReader.OnImageAvailableListener listener)390 protected ImageReader createImageReader(Size size, int format, int maxNumImages, 391 ImageReader.OnImageAvailableListener listener) throws Exception { 392 393 ImageReader reader = null; 394 reader = ImageReader.newInstance(size.getWidth(), size.getHeight(), 395 format, maxNumImages); 396 397 reader.setOnImageAvailableListener(listener, mHandler); 398 if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString()); 399 return reader; 400 } 401 402 /** 403 * Create an {@link ImageReader} object. 404 * 405 * <p>This function creates image reader object for given format, maxImages, usage and size.</p> 406 * 407 * @param size The size of this ImageReader to be created. 408 * @param format The format of this ImageReader to be created 409 * @param maxNumImages The max number of images that can be acquired simultaneously. 410 * @param usage The usage flag of the ImageReader 411 * @param listener The listener used by this ImageReader to notify callbacks. 412 */ 413 createImageReader(Size size, int format, int maxNumImages, long usage, ImageReader.OnImageAvailableListener listener)414 protected ImageReader createImageReader(Size size, int format, int maxNumImages, long usage, 415 ImageReader.OnImageAvailableListener listener) throws Exception { 416 ImageReader reader = null; 417 reader = ImageReader.newInstance(size.getWidth(), size.getHeight(), 418 format, maxNumImages, usage); 419 420 reader.setOnImageAvailableListener(listener, mHandler); 421 if (VERBOSE) Log.v(TAG, "Created ImageReader size " + size.toString()); 422 return reader; 423 } 424 425 /** 426 * Close the pending images then close current default {@link ImageReader} object. 427 */ closeDefaultImageReader()428 protected void closeDefaultImageReader() { 429 closeImageReader(mReader); 430 mReader = null; 431 mReaderSurface = null; 432 } 433 434 /** 435 * Close an image reader instance. 436 * 437 * @param reader 438 */ closeImageReader(ImageReader reader)439 protected void closeImageReader(ImageReader reader) { 440 if (reader != null) { 441 try { 442 // Close all possible pending images first. 443 Image image = reader.acquireLatestImage(); 444 if (image != null) { 445 image.close(); 446 } 447 } finally { 448 reader.close(); 449 reader = null; 450 } 451 } 452 } 453 checkImageReaderSessionConfiguration(String msg)454 protected void checkImageReaderSessionConfiguration(String msg) throws Exception { 455 checkImageReaderSessionConfiguration(msg, /*physicalCameraId*/null); 456 } 457 checkImageReaderSessionConfiguration(String msg, String physicalCameraId)458 protected void checkImageReaderSessionConfiguration(String msg, String physicalCameraId) 459 throws Exception { 460 List<OutputConfiguration> outputConfigs = new ArrayList<OutputConfiguration>(); 461 OutputConfiguration config = new OutputConfiguration(mReaderSurface); 462 if (physicalCameraId != null) { 463 config.setPhysicalCameraId(physicalCameraId); 464 } 465 outputConfigs.add(config); 466 checkSessionConfigurationSupported(mCamera, mHandler, outputConfigs, /*inputConfig*/ null, 467 SessionConfiguration.SESSION_REGULAR, /*expectedResult*/ true, msg); 468 } 469 prepareCaptureRequest()470 protected CaptureRequest prepareCaptureRequest() throws Exception { 471 return prepareCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 472 } 473 prepareCaptureRequest(int template)474 protected CaptureRequest prepareCaptureRequest(int template) throws Exception { 475 List<Surface> outputSurfaces = new ArrayList<Surface>(); 476 Surface surface = mReader.getSurface(); 477 assertNotNull("Fail to get surface from ImageReader", surface); 478 outputSurfaces.add(surface); 479 return prepareCaptureRequestForSurfaces(outputSurfaces, template) 480 .build(); 481 } 482 prepareCaptureRequestForSurfaces(List<Surface> surfaces, int template)483 protected CaptureRequest.Builder prepareCaptureRequestForSurfaces(List<Surface> surfaces, 484 int template) 485 throws Exception { 486 createSession(surfaces); 487 488 CaptureRequest.Builder captureBuilder = 489 mCamera.createCaptureRequest(template); 490 assertNotNull("Fail to get captureRequest", captureBuilder); 491 for (Surface surface : surfaces) { 492 captureBuilder.addTarget(surface); 493 } 494 495 return captureBuilder; 496 } 497 prepareCaptureRequestForConfigs( List<OutputConfiguration> outputConfigs, int template)498 protected CaptureRequest.Builder prepareCaptureRequestForConfigs( 499 List<OutputConfiguration> outputConfigs, int template) throws Exception { 500 createSessionByConfigs(outputConfigs); 501 502 CaptureRequest.Builder captureBuilder = 503 mCamera.createCaptureRequest(template); 504 assertNotNull("Fail to get captureRequest", captureBuilder); 505 for (OutputConfiguration config : outputConfigs) { 506 for (Surface s : config.getSurfaces()) { 507 captureBuilder.addTarget(s); 508 } 509 } 510 511 return captureBuilder; 512 } 513 514 /** 515 * Test the invalid Image access: accessing a closed image must result in 516 * {@link IllegalStateException}. 517 * 518 * @param closedImage The closed image. 519 * @param closedBuffer The ByteBuffer from a closed Image. buffer invalid 520 * access will be skipped if it is null. 521 */ imageInvalidAccessTestAfterClose(Image closedImage, Plane closedPlane, ByteBuffer closedBuffer)522 protected void imageInvalidAccessTestAfterClose(Image closedImage, 523 Plane closedPlane, ByteBuffer closedBuffer) { 524 if (closedImage == null) { 525 throw new IllegalArgumentException(" closedImage must be non-null"); 526 } 527 if (closedBuffer != null && !closedBuffer.isDirect()) { 528 throw new IllegalArgumentException("The input ByteBuffer should be direct ByteBuffer"); 529 } 530 531 if (closedPlane != null) { 532 // Plane#getBuffer test 533 try { 534 closedPlane.getBuffer(); // An ISE should be thrown here. 535 fail("Image should throw IllegalStateException when calling getBuffer" 536 + " after the image is closed"); 537 } catch (IllegalStateException e) { 538 // Expected. 539 } 540 541 // Plane#getPixelStride test 542 try { 543 closedPlane.getPixelStride(); // An ISE should be thrown here. 544 fail("Image should throw IllegalStateException when calling getPixelStride" 545 + " after the image is closed"); 546 } catch (IllegalStateException e) { 547 // Expected. 548 } 549 550 // Plane#getRowStride test 551 try { 552 closedPlane.getRowStride(); // An ISE should be thrown here. 553 fail("Image should throw IllegalStateException when calling getRowStride" 554 + " after the image is closed"); 555 } catch (IllegalStateException e) { 556 // Expected. 557 } 558 } 559 560 // ByteBuffer access test 561 if (closedBuffer != null) { 562 try { 563 closedBuffer.get(); // An ISE should be thrown here. 564 fail("Image should throw IllegalStateException when accessing a byte buffer" 565 + " after the image is closed"); 566 } catch (IllegalStateException e) { 567 // Expected. 568 } 569 } 570 571 // Image#getFormat test 572 try { 573 closedImage.getFormat(); 574 fail("Image should throw IllegalStateException when calling getFormat" 575 + " after the image is closed"); 576 } catch (IllegalStateException e) { 577 // Expected. 578 } 579 580 // Image#getWidth test 581 try { 582 closedImage.getWidth(); 583 fail("Image should throw IllegalStateException when calling getWidth" 584 + " after the image is closed"); 585 } catch (IllegalStateException e) { 586 // Expected. 587 } 588 589 // Image#getHeight test 590 try { 591 closedImage.getHeight(); 592 fail("Image should throw IllegalStateException when calling getHeight" 593 + " after the image is closed"); 594 } catch (IllegalStateException e) { 595 // Expected. 596 } 597 598 // Image#getTimestamp test 599 try { 600 closedImage.getTimestamp(); 601 fail("Image should throw IllegalStateException when calling getTimestamp" 602 + " after the image is closed"); 603 } catch (IllegalStateException e) { 604 // Expected. 605 } 606 607 // Image#getTimestamp test 608 try { 609 closedImage.getTimestamp(); 610 fail("Image should throw IllegalStateException when calling getTimestamp" 611 + " after the image is closed"); 612 } catch (IllegalStateException e) { 613 // Expected. 614 } 615 616 // Image#getCropRect test 617 try { 618 closedImage.getCropRect(); 619 fail("Image should throw IllegalStateException when calling getCropRect" 620 + " after the image is closed"); 621 } catch (IllegalStateException e) { 622 // Expected. 623 } 624 625 // Image#setCropRect test 626 try { 627 Rect rect = new Rect(); 628 closedImage.setCropRect(rect); 629 fail("Image should throw IllegalStateException when calling setCropRect" 630 + " after the image is closed"); 631 } catch (IllegalStateException e) { 632 // Expected. 633 } 634 635 // Image#getPlanes test 636 try { 637 closedImage.getPlanes(); 638 fail("Image should throw IllegalStateException when calling getPlanes" 639 + " after the image is closed"); 640 } catch (IllegalStateException e) { 641 // Expected. 642 } 643 } 644 } 645