1 /* 2 * Copyright (C) 2016 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.view.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotEquals; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertTrue; 23 import static org.mockito.Mockito.mock; 24 import static org.mockito.Mockito.when; 25 26 import android.app.Instrumentation; 27 import android.content.Context; 28 import android.content.pm.ActivityInfo; 29 import android.graphics.Bitmap; 30 import android.graphics.Bitmap.Config; 31 import android.graphics.Canvas; 32 import android.graphics.Color; 33 import android.graphics.ColorSpace; 34 import android.graphics.Paint; 35 import android.graphics.PixelFormat; 36 import android.graphics.Rect; 37 import android.graphics.SurfaceTexture; 38 import android.hardware.HardwareBuffer; 39 import android.media.Image; 40 import android.media.ImageReader; 41 import android.media.ImageWriter; 42 import android.os.Debug; 43 import android.util.Half; 44 import android.util.Log; 45 import android.view.PixelCopy; 46 import android.view.Surface; 47 import android.view.View; 48 import android.view.Window; 49 import android.view.WindowManager; 50 import android.view.cts.util.BitmapDumper; 51 import android.view.cts.util.DisableFixedToUserRotationRule; 52 53 import androidx.test.InstrumentationRegistry; 54 import androidx.test.filters.LargeTest; 55 import androidx.test.filters.MediumTest; 56 import androidx.test.rule.ActivityTestRule; 57 import androidx.test.runner.AndroidJUnit4; 58 59 import com.android.compatibility.common.util.SynchronousPixelCopy; 60 61 import org.junit.Assert; 62 import org.junit.Before; 63 import org.junit.Rule; 64 import org.junit.Test; 65 import org.junit.rules.TestName; 66 import org.junit.rules.TestRule; 67 import org.junit.runner.Description; 68 import org.junit.runner.RunWith; 69 import org.junit.runners.model.Statement; 70 71 import java.io.File; 72 import java.nio.ByteBuffer; 73 import java.nio.ByteOrder; 74 import java.util.concurrent.CountDownLatch; 75 import java.util.concurrent.TimeUnit; 76 import java.util.function.Function; 77 78 @MediumTest 79 @RunWith(AndroidJUnit4.class) 80 public class PixelCopyTest { 81 private static final String TAG = "PixelCopyTests"; 82 83 @Rule 84 public DisableFixedToUserRotationRule mDisableFixedToUserRotationRule = 85 new DisableFixedToUserRotationRule(); 86 87 @Rule 88 public ActivityTestRule<PixelCopyGLProducerCtsActivity> mGLSurfaceViewActivityRule = 89 new ActivityTestRule<>(PixelCopyGLProducerCtsActivity.class, false, false); 90 91 @Rule 92 public ActivityTestRule<PixelCopyVideoSourceActivity> mVideoSourceActivityRule = 93 new ActivityTestRule<>(PixelCopyVideoSourceActivity.class, false, false); 94 95 @Rule 96 public ActivityTestRule<PixelCopyViewProducerActivity> mWindowSourceActivityRule = 97 new ActivityTestRule<>(PixelCopyViewProducerActivity.class, false, false); 98 99 @Rule 100 public ActivityTestRule<PixelCopyWideGamutViewProducerActivity> 101 mWideGamutWindowSourceActivityRule = new ActivityTestRule<>( 102 PixelCopyWideGamutViewProducerActivity.class, false, false); 103 104 @Rule 105 public ActivityTestRule<PixelCopyViewProducerDialogActivity> mDialogSourceActivityRule = 106 new ActivityTestRule<>(PixelCopyViewProducerDialogActivity.class, false, false); 107 108 @Rule 109 public SurfaceTextureRule mSurfaceRule = new SurfaceTextureRule(); 110 111 @Rule 112 public TestName mTestName = new TestName(); 113 114 private Instrumentation mInstrumentation; 115 private SynchronousPixelCopy mCopyHelper; 116 117 @Before setup()118 public void setup() { 119 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 120 assertNotNull(mInstrumentation); 121 mCopyHelper = new SynchronousPixelCopy(); 122 } 123 124 @Test(expected = IllegalArgumentException.class) testNullDest()125 public void testNullDest() { 126 Bitmap dest = null; 127 mCopyHelper.request(mSurfaceRule.getSurface(), dest); 128 } 129 130 @Test(expected = IllegalArgumentException.class) testRecycledDest()131 public void testRecycledDest() { 132 Bitmap dest = Bitmap.createBitmap(5, 5, Config.ARGB_8888); 133 dest.recycle(); 134 mCopyHelper.request(mSurfaceRule.getSurface(), dest); 135 } 136 137 @Test testNoSourceData()138 public void testNoSourceData() { 139 Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888); 140 int result = mCopyHelper.request(mSurfaceRule.getSurface(), dest); 141 assertEquals(PixelCopy.ERROR_SOURCE_NO_DATA, result); 142 } 143 144 @Test(expected = IllegalArgumentException.class) testEmptySourceRectSurface()145 public void testEmptySourceRectSurface() { 146 Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888); 147 mCopyHelper.request(mSurfaceRule.getSurface(), new Rect(), dest); 148 } 149 150 @Test(expected = IllegalArgumentException.class) testEmptySourceRectWindow()151 public void testEmptySourceRectWindow() { 152 Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888); 153 mCopyHelper.request(mock(Window.class), new Rect(), dest); 154 } 155 156 @Test(expected = IllegalArgumentException.class) testInvalidSourceRectSurface()157 public void testInvalidSourceRectSurface() { 158 Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888); 159 mCopyHelper.request(mSurfaceRule.getSurface(), new Rect(10, 10, 0, 0), dest); 160 } 161 162 @Test(expected = IllegalArgumentException.class) testInvalidSourceRectWindow()163 public void testInvalidSourceRectWindow() { 164 Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888); 165 mCopyHelper.request(mock(Window.class), new Rect(10, 10, 0, 0), dest); 166 } 167 168 @Test(expected = IllegalArgumentException.class) testNoDecorView()169 public void testNoDecorView() { 170 Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888); 171 Window mockWindow = mock(Window.class); 172 mCopyHelper.request(mockWindow, dest); 173 } 174 175 @Test(expected = IllegalArgumentException.class) testNoViewRoot()176 public void testNoViewRoot() { 177 Bitmap dest = Bitmap.createBitmap(5, 5, Bitmap.Config.ARGB_8888); 178 Window mockWindow = mock(Window.class); 179 View view = new View(mInstrumentation.getTargetContext()); 180 when(mockWindow.peekDecorView()).thenReturn(view); 181 mCopyHelper.request(mockWindow, dest); 182 } 183 waitForGlProducerActivity()184 private PixelCopyGLProducerCtsActivity waitForGlProducerActivity() { 185 CountDownLatch swapFence = new CountDownLatch(2); 186 187 PixelCopyGLProducerCtsActivity activity = 188 mGLSurfaceViewActivityRule.launchActivity(null); 189 activity.setSwapFence(swapFence); 190 191 try { 192 while (!swapFence.await(5, TimeUnit.MILLISECONDS)) { 193 activity.getView().requestRender(); 194 } 195 } catch (InterruptedException ex) { 196 Assert.fail("Interrupted, error=" + ex.getMessage()); 197 } 198 return activity; 199 } 200 201 @Test testGlProducerFullsize()202 public void testGlProducerFullsize() { 203 PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity(); 204 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 205 int result = mCopyHelper.request(activity.getView(), bitmap); 206 assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); 207 assertEquals(100, bitmap.getWidth()); 208 assertEquals(100, bitmap.getHeight()); 209 assertEquals(Config.ARGB_8888, bitmap.getConfig()); 210 assertBitmapQuadColor(bitmap, 211 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 212 } 213 214 @Test testGlProducerCropTopLeft()215 public void testGlProducerCropTopLeft() { 216 PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity(); 217 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 218 int result = mCopyHelper.request(activity.getView(), new Rect(0, 0, 50, 50), bitmap); 219 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 220 assertBitmapQuadColor(bitmap, 221 Color.RED, Color.RED, Color.RED, Color.RED); 222 } 223 224 @Test testGlProducerCropCenter()225 public void testGlProducerCropCenter() { 226 PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity(); 227 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 228 int result = mCopyHelper.request(activity.getView(), new Rect(25, 25, 75, 75), bitmap); 229 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 230 assertBitmapQuadColor(bitmap, 231 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 232 } 233 234 @Test testGlProducerCropBottomHalf()235 public void testGlProducerCropBottomHalf() { 236 PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity(); 237 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 238 int result = mCopyHelper.request(activity.getView(), new Rect(0, 50, 100, 100), bitmap); 239 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 240 assertBitmapQuadColor(bitmap, 241 Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK); 242 } 243 244 @Test testGlProducerCropClamping()245 public void testGlProducerCropClamping() { 246 PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity(); 247 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 248 int result = mCopyHelper.request(activity.getView(), new Rect(50, -50, 150, 50), bitmap); 249 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 250 assertBitmapQuadColor(bitmap, 251 Color.GREEN, Color.GREEN, Color.GREEN, Color.GREEN); 252 } 253 254 @Test testGlProducerScaling()255 public void testGlProducerScaling() { 256 // Since we only sample mid-pixel of each qudrant, filtering 257 // quality isn't tested 258 PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity(); 259 Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888); 260 int result = mCopyHelper.request(activity.getView(), bitmap); 261 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 262 // Make sure nothing messed with the bitmap 263 assertEquals(20, bitmap.getWidth()); 264 assertEquals(20, bitmap.getHeight()); 265 assertEquals(Config.ARGB_8888, bitmap.getConfig()); 266 assertBitmapQuadColor(bitmap, 267 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 268 } 269 270 @Test testReuseBitmap()271 public void testReuseBitmap() { 272 // Since we only sample mid-pixel of each qudrant, filtering 273 // quality isn't tested 274 PixelCopyGLProducerCtsActivity activity = waitForGlProducerActivity(); 275 Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888); 276 int result = mCopyHelper.request(activity.getView(), bitmap); 277 // Make sure nothing messed with the bitmap 278 assertEquals(20, bitmap.getWidth()); 279 assertEquals(20, bitmap.getHeight()); 280 assertEquals(Config.ARGB_8888, bitmap.getConfig()); 281 assertBitmapQuadColor(bitmap, 282 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 283 int generationId = bitmap.getGenerationId(); 284 result = mCopyHelper.request(activity.getView(), bitmap); 285 // Make sure nothing messed with the bitmap 286 assertEquals(20, bitmap.getWidth()); 287 assertEquals(20, bitmap.getHeight()); 288 assertEquals(Config.ARGB_8888, bitmap.getConfig()); 289 assertBitmapQuadColor(bitmap, 290 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 291 assertNotEquals(generationId, bitmap.getGenerationId()); 292 } 293 waitForWindowProducerActivity()294 private Window waitForWindowProducerActivity() { 295 PixelCopyViewProducerActivity activity = 296 mWindowSourceActivityRule.launchActivity(null); 297 activity.waitForFirstDrawCompleted(10, TimeUnit.SECONDS); 298 return activity.getWindow(); 299 } 300 makeWindowRect(int left, int top, int right, int bottom)301 private Rect makeWindowRect(int left, int top, int right, int bottom) { 302 Rect r = new Rect(left, top, right, bottom); 303 mWindowSourceActivityRule.getActivity().normalizedToSurface(r); 304 return r; 305 } 306 307 @Test testWindowProducer()308 public void testWindowProducer() { 309 Bitmap bitmap; 310 Window window = waitForWindowProducerActivity(); 311 PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); 312 do { 313 Rect src = makeWindowRect(0, 0, 100, 100); 314 bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.ARGB_8888); 315 int result = mCopyHelper.request(window, src, bitmap); 316 assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); 317 assertEquals(Config.ARGB_8888, bitmap.getConfig()); 318 assertBitmapQuadColor(bitmap, 319 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 320 assertBitmapEdgeColor(bitmap, Color.YELLOW); 321 } while (activity.rotate()); 322 } 323 324 @Test testWindowProducerCropTopLeft()325 public void testWindowProducerCropTopLeft() { 326 Window window = waitForWindowProducerActivity(); 327 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 328 PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); 329 do { 330 int result = mCopyHelper.request(window, makeWindowRect(0, 0, 50, 50), bitmap); 331 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 332 assertBitmapQuadColor(bitmap, 333 Color.RED, Color.RED, Color.RED, Color.RED); 334 } while (activity.rotate()); 335 } 336 337 @Test testWindowProducerCropCenter()338 public void testWindowProducerCropCenter() { 339 Window window = waitForWindowProducerActivity(); 340 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 341 PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); 342 do { 343 int result = mCopyHelper.request(window, makeWindowRect(25, 25, 75, 75), bitmap); 344 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 345 assertBitmapQuadColor(bitmap, 346 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 347 } while (activity.rotate()); 348 } 349 350 @Test testWindowProducerCropBottomHalf()351 public void testWindowProducerCropBottomHalf() { 352 Window window = waitForWindowProducerActivity(); 353 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 354 PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); 355 do { 356 int result = mCopyHelper.request(window, makeWindowRect(0, 50, 100, 100), bitmap); 357 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 358 assertBitmapQuadColor(bitmap, 359 Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK); 360 } while (activity.rotate()); 361 } 362 363 @Test testWindowProducerScaling()364 public void testWindowProducerScaling() { 365 // Since we only sample mid-pixel of each qudrant, filtering 366 // quality isn't tested 367 Window window = waitForWindowProducerActivity(); 368 Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888); 369 PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); 370 do { 371 int result = mCopyHelper.request(window, bitmap); 372 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 373 // Make sure nothing messed with the bitmap 374 assertEquals(20, bitmap.getWidth()); 375 assertEquals(20, bitmap.getHeight()); 376 assertEquals(Config.ARGB_8888, bitmap.getConfig()); 377 assertBitmapQuadColor(bitmap, 378 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 379 } while (activity.rotate()); 380 } 381 382 @Test testWindowProducerCopyToRGBA16F()383 public void testWindowProducerCopyToRGBA16F() { 384 Window window = waitForWindowProducerActivity(); 385 PixelCopyViewProducerActivity activity = mWindowSourceActivityRule.getActivity(); 386 387 Bitmap bitmap; 388 do { 389 Rect src = makeWindowRect(0, 0, 100, 100); 390 bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16); 391 int result = mCopyHelper.request(window, src, bitmap); 392 // On OpenGL ES 2.0 devices a copy to RGBA_F16 can fail because there's 393 // not support for float textures 394 if (result != PixelCopy.ERROR_DESTINATION_INVALID) { 395 assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); 396 assertEquals(Config.RGBA_F16, bitmap.getConfig()); 397 assertBitmapQuadColor(bitmap, 398 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 399 assertBitmapEdgeColor(bitmap, Color.YELLOW); 400 } 401 } while (activity.rotate()); 402 } 403 waitForWideGamutWindowProducerActivity()404 private Window waitForWideGamutWindowProducerActivity() { 405 PixelCopyWideGamutViewProducerActivity activity = 406 mWideGamutWindowSourceActivityRule.launchActivity(null); 407 activity.waitForFirstDrawCompleted(10, TimeUnit.SECONDS); 408 return activity.getWindow(); 409 } 410 makeWideGamutWindowRect(int left, int top, int right, int bottom)411 private Rect makeWideGamutWindowRect(int left, int top, int right, int bottom) { 412 Rect r = new Rect(left, top, right, bottom); 413 mWideGamutWindowSourceActivityRule.getActivity().offsetForContent(r); 414 return r; 415 } 416 417 @Test testWideGamutWindowProducerCopyToRGBA8888()418 public void testWideGamutWindowProducerCopyToRGBA8888() { 419 Window window = waitForWideGamutWindowProducerActivity(); 420 assertEquals( 421 ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT, window.getAttributes().getColorMode()); 422 423 // Early out if the device does not support wide color gamut rendering 424 if (!window.isWideColorGamut()) { 425 return; 426 } 427 428 PixelCopyWideGamutViewProducerActivity activity = 429 mWideGamutWindowSourceActivityRule.getActivity(); 430 431 Bitmap bitmap; 432 do { 433 Rect src = makeWideGamutWindowRect(0, 0, 128, 128); 434 bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.ARGB_8888); 435 int result = mCopyHelper.request(window, src, bitmap); 436 437 assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); 438 assertEquals(Config.ARGB_8888, bitmap.getConfig()); 439 440 assertEquals("Top left", Color.RED, bitmap.getPixel(32, 32)); 441 assertEquals("Top right", Color.GREEN, bitmap.getPixel(96, 32)); 442 assertEquals("Bottom left", Color.BLUE, bitmap.getPixel(32, 96)); 443 assertEquals("Bottom right", Color.YELLOW, bitmap.getPixel(96, 96)); 444 } while (activity.rotate()); 445 } 446 447 @Test testWideGamutWindowProducerCopyToRGBA16F()448 public void testWideGamutWindowProducerCopyToRGBA16F() { 449 Window window = waitForWideGamutWindowProducerActivity(); 450 assertEquals( 451 ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT, window.getAttributes().getColorMode()); 452 453 // Early out if the device does not support wide color gamut rendering 454 if (!window.isWideColorGamut()) { 455 return; 456 } 457 458 PixelCopyWideGamutViewProducerActivity activity = 459 mWideGamutWindowSourceActivityRule.getActivity(); 460 final WindowManager windowManager = (WindowManager) activity.getSystemService( 461 Context.WINDOW_SERVICE); 462 final ColorSpace colorSpace = windowManager.getDefaultDisplay() 463 .getPreferredWideGamutColorSpace(); 464 final ColorSpace.Connector proPhotoToDisplayWideColorSpace = ColorSpace.connect( 465 ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB), colorSpace); 466 final ColorSpace.Connector displayWideColorSpaceToExtendedSrgb = ColorSpace.connect( 467 colorSpace, ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); 468 469 final float[] intermediateRed = proPhotoToDisplayWideColorSpace.transform(1.0f, 0.0f, 0.0f); 470 final float[] intermediateGreen = proPhotoToDisplayWideColorSpace 471 .transform(0.0f, 1.0f, 0.0f); 472 final float[] intermediateBlue = proPhotoToDisplayWideColorSpace 473 .transform(0.0f, 0.0f, 1.0f); 474 final float[] intermediateYellow = proPhotoToDisplayWideColorSpace 475 .transform(1.0f, 1.0f, 0.0f); 476 477 final float[] expectedRed = displayWideColorSpaceToExtendedSrgb.transform(intermediateRed); 478 final float[] expectedGreen = displayWideColorSpaceToExtendedSrgb 479 .transform(intermediateGreen); 480 final float[] expectedBlue = displayWideColorSpaceToExtendedSrgb 481 .transform(intermediateBlue); 482 final float[] expectedYellow = displayWideColorSpaceToExtendedSrgb 483 .transform(intermediateYellow); 484 485 Bitmap bitmap; 486 int i = 0; 487 do { 488 Rect src = makeWideGamutWindowRect(0, 0, 128, 128); 489 bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16, true, 490 ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); 491 int result = mCopyHelper.request(window, src, bitmap); 492 493 assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); 494 assertEquals(Config.RGBA_F16, bitmap.getConfig()); 495 496 ByteBuffer dst = ByteBuffer.allocateDirect(bitmap.getAllocationByteCount()); 497 bitmap.copyPixelsToBuffer(dst); 498 dst.rewind(); 499 dst.order(ByteOrder.LITTLE_ENDIAN); 500 501 // ProPhoto RGB red in scRGB-nl 502 assertEqualsRgba16f("Top left", bitmap, 32, 32, dst, expectedRed[0], 503 expectedRed[1], expectedRed[2], 1.0f); 504 // ProPhoto RGB green in scRGB-nl 505 assertEqualsRgba16f("Top right", bitmap, 96, 32, dst, expectedGreen[0], 506 expectedGreen[1], expectedGreen[2], 1.0f); 507 // ProPhoto RGB blue in scRGB-nl 508 assertEqualsRgba16f("Bottom left", bitmap, 32, 96, dst, expectedBlue[0], 509 expectedBlue[1], expectedBlue[2], 1.0f); 510 // ProPhoto RGB yellow in scRGB-nl 511 assertEqualsRgba16f("Bottom right", bitmap, 96, 96, dst, expectedYellow[0], 512 expectedYellow[1], expectedYellow[2], 1.0f); 513 } while (activity.rotate()); 514 } 515 waitForDialogProducerActivity()516 private Window waitForDialogProducerActivity() { 517 PixelCopyViewProducerActivity activity = 518 mDialogSourceActivityRule.launchActivity(null); 519 activity.waitForFirstDrawCompleted(10, TimeUnit.SECONDS); 520 return activity.getWindow(); 521 } 522 makeDialogRect(int left, int top, int right, int bottom)523 private Rect makeDialogRect(int left, int top, int right, int bottom) { 524 Rect r = new Rect(left, top, right, bottom); 525 mDialogSourceActivityRule.getActivity().normalizedToSurface(r); 526 return r; 527 } 528 529 @Test testDialogProducer()530 public void testDialogProducer() { 531 Bitmap bitmap; 532 Window window = waitForDialogProducerActivity(); 533 PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); 534 do { 535 Rect src = makeDialogRect(0, 0, 100, 100); 536 bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.ARGB_8888); 537 int result = mCopyHelper.request(window, src, bitmap); 538 assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); 539 assertEquals(Config.ARGB_8888, bitmap.getConfig()); 540 assertBitmapQuadColor(bitmap, 541 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 542 assertBitmapEdgeColor(bitmap, Color.YELLOW); 543 } while (activity.rotate()); 544 } 545 546 @Test testDialogProducerCropTopLeft()547 public void testDialogProducerCropTopLeft() { 548 Window window = waitForDialogProducerActivity(); 549 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 550 PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); 551 do { 552 int result = mCopyHelper.request(window, makeDialogRect(0, 0, 50, 50), bitmap); 553 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 554 assertBitmapQuadColor(bitmap, 555 Color.RED, Color.RED, Color.RED, Color.RED); 556 } while (activity.rotate()); 557 } 558 559 @Test testDialogProducerCropCenter()560 public void testDialogProducerCropCenter() { 561 Window window = waitForDialogProducerActivity(); 562 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 563 PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); 564 do { 565 int result = mCopyHelper.request(window, makeDialogRect(25, 25, 75, 75), bitmap); 566 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 567 assertBitmapQuadColor(bitmap, 568 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 569 } while (activity.rotate()); 570 } 571 572 @Test testDialogProducerCropBottomHalf()573 public void testDialogProducerCropBottomHalf() { 574 Window window = waitForDialogProducerActivity(); 575 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 576 PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); 577 do { 578 int result = mCopyHelper.request(window, makeDialogRect(0, 50, 100, 100), bitmap); 579 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 580 assertBitmapQuadColor(bitmap, 581 Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK); 582 } while (activity.rotate()); 583 } 584 585 @Test testDialogProducerScaling()586 public void testDialogProducerScaling() { 587 // Since we only sample mid-pixel of each qudrant, filtering 588 // quality isn't tested 589 Window window = waitForDialogProducerActivity(); 590 Bitmap bitmap = Bitmap.createBitmap(20, 20, Config.ARGB_8888); 591 PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); 592 do { 593 int result = mCopyHelper.request(window, bitmap); 594 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, result); 595 // Make sure nothing messed with the bitmap 596 assertEquals(20, bitmap.getWidth()); 597 assertEquals(20, bitmap.getHeight()); 598 assertEquals(Config.ARGB_8888, bitmap.getConfig()); 599 assertBitmapQuadColor(bitmap, 600 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 601 } while (activity.rotate()); 602 } 603 604 @Test testDialogProducerCopyToRGBA16F()605 public void testDialogProducerCopyToRGBA16F() { 606 Window window = waitForDialogProducerActivity(); 607 PixelCopyViewProducerActivity activity = mDialogSourceActivityRule.getActivity(); 608 609 Bitmap bitmap; 610 do { 611 Rect src = makeDialogRect(0, 0, 100, 100); 612 bitmap = Bitmap.createBitmap(src.width(), src.height(), Config.RGBA_F16); 613 int result = mCopyHelper.request(window, src, bitmap); 614 // On OpenGL ES 2.0 devices a copy to RGBA_F16 can fail because there's 615 // not support for float textures 616 if (result != PixelCopy.ERROR_DESTINATION_INVALID) { 617 assertEquals("Fullsize copy request failed", PixelCopy.SUCCESS, result); 618 assertEquals(Config.RGBA_F16, bitmap.getConfig()); 619 assertBitmapQuadColor(bitmap, 620 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 621 assertBitmapEdgeColor(bitmap, Color.YELLOW); 622 } 623 } while (activity.rotate()); 624 } 625 assertEqualsRgba16f(String message, Bitmap bitmap, int x, int y, ByteBuffer dst, float r, float g, float b, float a)626 private static void assertEqualsRgba16f(String message, Bitmap bitmap, int x, int y, 627 ByteBuffer dst, float r, float g, float b, float a) { 628 int index = y * bitmap.getRowBytes() + (x << 3); 629 short cR = dst.getShort(index); 630 short cG = dst.getShort(index + 2); 631 short cB = dst.getShort(index + 4); 632 short cA = dst.getShort(index + 6); 633 634 assertEquals(message, r, Half.toFloat(cR), 0.01); 635 assertEquals(message, g, Half.toFloat(cG), 0.01); 636 assertEquals(message, b, Half.toFloat(cB), 0.01); 637 assertEquals(message, a, Half.toFloat(cA), 0.01); 638 } 639 runGcAndFinalizersSync()640 private static void runGcAndFinalizersSync() { 641 Runtime.getRuntime().gc(); 642 Runtime.getRuntime().runFinalization(); 643 644 final CountDownLatch fence = new CountDownLatch(1); 645 new Object() { 646 @Override 647 protected void finalize() throws Throwable { 648 try { 649 fence.countDown(); 650 } finally { 651 super.finalize(); 652 } 653 } 654 }; 655 try { 656 do { 657 Runtime.getRuntime().gc(); 658 Runtime.getRuntime().runFinalization(); 659 } while (!fence.await(100, TimeUnit.MILLISECONDS)); 660 } catch (InterruptedException ex) { 661 throw new RuntimeException(ex); 662 } 663 } 664 665 private static File sProcSelfFd = new File("/proc/self/fd"); getFdCount()666 private static int getFdCount() { 667 return sProcSelfFd.listFiles().length; 668 } 669 assertNotLeaking(int iteration, Debug.MemoryInfo start, Debug.MemoryInfo end)670 private static void assertNotLeaking(int iteration, 671 Debug.MemoryInfo start, Debug.MemoryInfo end) { 672 Debug.getMemoryInfo(end); 673 assertNotEquals(0, start.getTotalPss()); 674 assertNotEquals(0, end.getTotalPss()); 675 if (end.getTotalPss() - start.getTotalPss() > 5000 /* kB */) { 676 runGcAndFinalizersSync(); 677 Debug.getMemoryInfo(end); 678 if (end.getTotalPss() - start.getTotalPss() > 7000 /* kB */) { 679 // Guarded by if so we don't continually generate garbage for the 680 // assertion string. 681 assertEquals("Memory leaked, iteration=" + iteration, 682 start.getTotalPss(), end.getTotalPss(), 683 7000 /* kb */); 684 } 685 } 686 } 687 runNotLeakingTest(Runnable test)688 private static void runNotLeakingTest(Runnable test) { 689 Debug.MemoryInfo meminfoStart = new Debug.MemoryInfo(); 690 Debug.MemoryInfo meminfoEnd = new Debug.MemoryInfo(); 691 int fdCount = -1; 692 // Do a warmup to reach steady-state memory usage 693 for (int i = 0; i < 50; i++) { 694 test.run(); 695 } 696 runGcAndFinalizersSync(); 697 Debug.getMemoryInfo(meminfoStart); 698 fdCount = getFdCount(); 699 // Now run the test 700 for (int i = 0; i < 2000; i++) { 701 if (i % 100 == 5) { 702 assertNotLeaking(i, meminfoStart, meminfoEnd); 703 final int curFdCount = getFdCount(); 704 if (curFdCount - fdCount > 10) { 705 Assert.fail(String.format("FDs leaked. Expected=%d, current=%d, iteration=%d", 706 fdCount, curFdCount, i)); 707 } 708 } 709 test.run(); 710 } 711 assertNotLeaking(2000, meminfoStart, meminfoEnd); 712 final int curFdCount = getFdCount(); 713 if (curFdCount - fdCount > 10) { 714 Assert.fail(String.format("FDs leaked. Expected=%d, current=%d", fdCount, curFdCount)); 715 } 716 } 717 718 @Test 719 @LargeTest testNotLeaking()720 public void testNotLeaking() { 721 try { 722 CountDownLatch swapFence = new CountDownLatch(2); 723 724 PixelCopyGLProducerCtsActivity activity = 725 mGLSurfaceViewActivityRule.launchActivity(null); 726 activity.setSwapFence(swapFence); 727 728 while (!swapFence.await(5, TimeUnit.MILLISECONDS)) { 729 activity.getView().requestRender(); 730 } 731 732 // Test a fullsize copy 733 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 734 735 runNotLeakingTest(() -> { 736 int result = mCopyHelper.request(activity.getView(), bitmap); 737 assertEquals("Copy request failed", PixelCopy.SUCCESS, result); 738 // Make sure nothing messed with the bitmap 739 assertEquals(100, bitmap.getWidth()); 740 assertEquals(100, bitmap.getHeight()); 741 assertEquals(Config.ARGB_8888, bitmap.getConfig()); 742 assertBitmapQuadColor(bitmap, 743 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 744 }); 745 746 } catch (InterruptedException e) { 747 Assert.fail("Interrupted, error=" + e.getMessage()); 748 } 749 } 750 751 @Test testVideoProducer()752 public void testVideoProducer() throws InterruptedException { 753 PixelCopyVideoSourceActivity activity = 754 mVideoSourceActivityRule.launchActivity(null); 755 if (!activity.canPlayVideo()) { 756 Log.i(TAG, "Skipping testVideoProducer, video codec isn't supported"); 757 return; 758 } 759 // This returns when the video has been prepared and playback has 760 // been started, it doesn't necessarily means a frame has actually been 761 // produced. There sadly isn't a callback for that. 762 // So we'll try for up to 900ms after this event to acquire a frame, otherwise 763 // it's considered a timeout. 764 activity.waitForPlaying(); 765 assertTrue("Failed to start video playback", activity.canPlayVideo()); 766 Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888); 767 int copyResult = PixelCopy.ERROR_SOURCE_NO_DATA; 768 for (int i = 0; i < 30; i++) { 769 copyResult = mCopyHelper.request(activity.getVideoView(), bitmap); 770 if (copyResult != PixelCopy.ERROR_SOURCE_NO_DATA) { 771 break; 772 } 773 Thread.sleep(30); 774 } 775 assertEquals(PixelCopy.SUCCESS, copyResult); 776 // A large threshold is used because decoder accuracy is covered in the 777 // media CTS tests, so we are mainly interested in verifying that rotation 778 // and YUV->RGB conversion were handled properly. 779 assertBitmapQuadColor(bitmap, Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, 30); 780 781 // Test that cropping works. 782 copyResult = mCopyHelper.request(activity.getVideoView(), new Rect(0, 0, 50, 50), bitmap); 783 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, copyResult); 784 assertBitmapQuadColor(bitmap, 785 Color.RED, Color.RED, Color.RED, Color.RED, 30); 786 787 copyResult = mCopyHelper.request(activity.getVideoView(), new Rect(50, 0, 100, 50), bitmap); 788 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, copyResult); 789 assertBitmapQuadColor(bitmap, 790 Color.GREEN, Color.GREEN, Color.GREEN, Color.GREEN, 30); 791 792 copyResult = mCopyHelper.request(activity.getVideoView(), new Rect(0, 50, 50, 100), bitmap); 793 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, copyResult); 794 assertBitmapQuadColor(bitmap, 795 Color.BLUE, Color.BLUE, Color.BLUE, Color.BLUE, 30); 796 797 copyResult = mCopyHelper.request(activity.getVideoView(), new Rect(50, 50, 100, 100), bitmap); 798 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, copyResult); 799 assertBitmapQuadColor(bitmap, 800 Color.BLACK, Color.BLACK, Color.BLACK, Color.BLACK, 30); 801 802 803 copyResult = mCopyHelper.request(activity.getVideoView(), new Rect(25, 25, 75, 75), bitmap); 804 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, copyResult); 805 assertBitmapQuadColor(bitmap, 806 Color.RED, Color.GREEN, Color.BLUE, Color.BLACK, 30); 807 808 copyResult = mCopyHelper.request(activity.getVideoView(), new Rect(0, 50, 100, 100), bitmap); 809 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, copyResult); 810 assertBitmapQuadColor(bitmap, 811 Color.BLUE, Color.BLACK, Color.BLUE, Color.BLACK, 30); 812 813 // Test that clamping works 814 copyResult = mCopyHelper.request(activity.getVideoView(), new Rect(50, -50, 150, 50), bitmap); 815 assertEquals("Scaled copy request failed", PixelCopy.SUCCESS, copyResult); 816 assertBitmapQuadColor(bitmap, 817 Color.GREEN, Color.GREEN, Color.GREEN, Color.GREEN, 30); 818 } 819 820 @Test testBufferQueueCrop()821 public void testBufferQueueCrop() throws InterruptedException { 822 ImageReader reader = ImageReader.newInstance(100, 100, PixelFormat.RGBA_8888, 1, 823 HardwareBuffer.USAGE_CPU_WRITE_OFTEN | HardwareBuffer.USAGE_CPU_READ_OFTEN 824 | HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE); 825 ImageWriter writer = ImageWriter.newInstance(reader.getSurface(), 1); 826 Image image = writer.dequeueInputImage(); 827 Image.Plane plane = image.getPlanes()[0]; 828 Bitmap bitmap = Bitmap.createBitmap(plane.getRowStride() / 4, 829 image.getHeight(), Bitmap.Config.ARGB_8888); 830 Canvas canvas = new Canvas(bitmap); 831 Paint paint = new Paint(); 832 paint.setAntiAlias(false); 833 canvas.drawColor(Color.MAGENTA); 834 canvas.translate(20f, 70f); 835 paint.setColor(Color.RED); 836 canvas.drawRect(0f, 0f, 10f, 10f, paint); 837 paint.setColor(Color.GREEN); 838 canvas.drawRect(10f, 0f, 20f, 10f, paint); 839 paint.setColor(Color.BLUE); 840 canvas.drawRect(0f, 10f, 10f, 20f, paint); 841 paint.setColor(Color.BLACK); 842 canvas.drawRect(10f, 10f, 20f, 20f, paint); 843 bitmap.copyPixelsToBuffer(plane.getBuffer()); 844 image.setCropRect(new Rect(20, 70, 40, 90)); 845 writer.queueInputImage(image); 846 847 // implicit size 848 Bitmap result = Bitmap.createBitmap(20, 20, Config.ARGB_8888); 849 int status = mCopyHelper.request(reader.getSurface(), result); 850 assertEquals("Copy request failed", PixelCopy.SUCCESS, status); 851 assertBitmapQuadColor(result, Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 852 853 // specified size 854 result = Bitmap.createBitmap(20, 20, Config.ARGB_8888); 855 status = mCopyHelper.request(reader.getSurface(), new Rect(0, 0, 20, 20), result); 856 assertEquals("Copy request failed", PixelCopy.SUCCESS, status); 857 assertBitmapQuadColor(result, Color.RED, Color.GREEN, Color.BLUE, Color.BLACK); 858 } 859 getPixelFloatPos(Bitmap bitmap, float xpos, float ypos)860 private static int getPixelFloatPos(Bitmap bitmap, float xpos, float ypos) { 861 return bitmap.getPixel((int) (bitmap.getWidth() * xpos), (int) (bitmap.getHeight() * ypos)); 862 } 863 assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight, int bottomLeft, int bottomRight)864 private void assertBitmapQuadColor(Bitmap bitmap, 865 int topLeft, int topRight, int bottomLeft, int bottomRight) { 866 assertBitmapQuadColor(mTestName.getMethodName(), "PixelCopyTest", bitmap, 867 topLeft, topRight, bottomLeft, bottomRight); 868 } 869 assertBitmapQuadColor(String testName, String className, Bitmap bitmap, int topLeft, int topRight, int bottomLeft, int bottomRight)870 public static void assertBitmapQuadColor(String testName, String className, Bitmap bitmap, 871 int topLeft, int topRight, int bottomLeft, int bottomRight) { 872 try { 873 // Just quickly sample 4 pixels in the various regions. 874 assertEquals("Top left " + Integer.toHexString(topLeft) + ", actual= " 875 + Integer.toHexString(getPixelFloatPos(bitmap, .25f, .25f)), 876 topLeft, getPixelFloatPos(bitmap, .25f, .25f)); 877 assertEquals("Top right", topRight, getPixelFloatPos(bitmap, .75f, .25f)); 878 assertEquals("Bottom left", bottomLeft, getPixelFloatPos(bitmap, .25f, .75f)); 879 assertEquals("Bottom right", bottomRight, getPixelFloatPos(bitmap, .75f, .75f)); 880 881 // and some closer to the center point, to ensure that our quadrants are even 882 float below = .45f; 883 float above = .55f; 884 assertEquals("Top left II " + Integer.toHexString(topLeft) + ", actual= " 885 + Integer.toHexString(getPixelFloatPos(bitmap, below, below)), 886 topLeft, getPixelFloatPos(bitmap, below, below)); 887 assertEquals("Top right II", topRight, getPixelFloatPos(bitmap, above, below)); 888 assertEquals("Bottom left II", bottomLeft, getPixelFloatPos(bitmap, below, above)); 889 assertEquals("Bottom right II", bottomRight, getPixelFloatPos(bitmap, above, above)); 890 } catch (AssertionError err) { 891 BitmapDumper.dumpBitmap(bitmap, testName, className); 892 throw err; 893 } 894 } 895 assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight, int bottomLeft, int bottomRight, int threshold)896 private void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight, 897 int bottomLeft, int bottomRight, int threshold) { 898 Function<Float, Integer> getX = (Float x) -> (int) (bitmap.getWidth() * x); 899 Function<Float, Integer> getY = (Float y) -> (int) (bitmap.getHeight() * y); 900 901 // Just quickly sample 4 pixels in the various regions. 902 assertBitmapColor("Top left", bitmap, topLeft, 903 getX.apply(.25f), getY.apply(.25f), threshold); 904 assertBitmapColor("Top right", bitmap, topRight, 905 getX.apply(.75f), getY.apply(.25f), threshold); 906 assertBitmapColor("Bottom left", bitmap, bottomLeft, 907 getX.apply(.25f), getY.apply(.75f), threshold); 908 assertBitmapColor("Bottom right", bitmap, bottomRight, 909 getX.apply(.75f), getY.apply(.75f), threshold); 910 911 float below = .4f; 912 float above = .6f; 913 assertBitmapColor("Top left II", bitmap, topLeft, 914 getX.apply(below), getY.apply(below), threshold); 915 assertBitmapColor("Top right II", bitmap, topRight, 916 getX.apply(above), getY.apply(below), threshold); 917 assertBitmapColor("Bottom left II", bitmap, bottomLeft, 918 getX.apply(below), getY.apply(above), threshold); 919 assertBitmapColor("Bottom right II", bitmap, bottomRight, 920 getX.apply(above), getY.apply(above), threshold); 921 } 922 assertBitmapEdgeColor(Bitmap bitmap, int edgeColor)923 private void assertBitmapEdgeColor(Bitmap bitmap, int edgeColor) { 924 // Just quickly sample a few pixels on the edge and assert 925 // they are edge color, then assert that just inside the edge is a different color 926 assertBitmapColor("Top edge", bitmap, edgeColor, bitmap.getWidth() / 2, 1); 927 assertBitmapNotColor("Top edge", bitmap, edgeColor, bitmap.getWidth() / 2, 2); 928 929 assertBitmapColor("Left edge", bitmap, edgeColor, 1, bitmap.getHeight() / 2); 930 assertBitmapNotColor("Left edge", bitmap, edgeColor, 2, bitmap.getHeight() / 2); 931 932 assertBitmapColor("Bottom edge", bitmap, edgeColor, 933 bitmap.getWidth() / 2, bitmap.getHeight() - 2); 934 assertBitmapNotColor("Bottom edge", bitmap, edgeColor, 935 bitmap.getWidth() / 2, bitmap.getHeight() - 3); 936 937 assertBitmapColor("Right edge", bitmap, edgeColor, 938 bitmap.getWidth() - 2, bitmap.getHeight() / 2); 939 assertBitmapNotColor("Right edge", bitmap, edgeColor, 940 bitmap.getWidth() - 3, bitmap.getHeight() / 2); 941 } 942 pixelsAreSame(int ideal, int given, int threshold)943 private static boolean pixelsAreSame(int ideal, int given, int threshold) { 944 int error = Math.abs(Color.red(ideal) - Color.red(given)); 945 error += Math.abs(Color.green(ideal) - Color.green(given)); 946 error += Math.abs(Color.blue(ideal) - Color.blue(given)); 947 return (error < threshold); 948 } 949 fail(Bitmap bitmap, String message)950 private void fail(Bitmap bitmap, String message) { 951 BitmapDumper.dumpBitmap(bitmap, mTestName.getMethodName(), "PixelCopyTest"); 952 Assert.fail(message); 953 } 954 assertBitmapColor(String debug, Bitmap bitmap, int color, int x, int y)955 private void assertBitmapColor(String debug, Bitmap bitmap, int color, int x, int y) { 956 assertBitmapColor(debug, bitmap, color, x, y, 10); 957 } 958 assertBitmapColor(String debug, Bitmap bitmap, int color, int x, int y, int threshold)959 private void assertBitmapColor(String debug, Bitmap bitmap, int color, int x, int y, 960 int threshold) { 961 int pixel = bitmap.getPixel(x, y); 962 if (!pixelsAreSame(color, pixel, threshold)) { 963 fail(bitmap, debug + "; expected=" + Integer.toHexString(color) + ", actual=" 964 + Integer.toHexString(pixel)); 965 } 966 } 967 assertBitmapNotColor(String debug, Bitmap bitmap, int color, int x, int y)968 private void assertBitmapNotColor(String debug, Bitmap bitmap, int color, int x, int y) { 969 int pixel = bitmap.getPixel(x, y); 970 if (pixelsAreSame(color, pixel, 10)) { 971 fail(bitmap, debug + "; actual=" + Integer.toHexString(pixel) 972 + " shouldn't have matched " + Integer.toHexString(color)); 973 } 974 } 975 976 private static class SurfaceTextureRule implements TestRule { 977 private SurfaceTexture mSurfaceTexture = null; 978 private Surface mSurface = null; 979 createIfNecessary()980 private void createIfNecessary() { 981 mSurfaceTexture = new SurfaceTexture(false); 982 mSurface = new Surface(mSurfaceTexture); 983 } 984 getSurface()985 public Surface getSurface() { 986 createIfNecessary(); 987 return mSurface; 988 } 989 990 @Override apply(Statement base, Description description)991 public Statement apply(Statement base, Description description) { 992 return new CreateSurfaceTextureStatement(base); 993 } 994 995 private class CreateSurfaceTextureStatement extends Statement { 996 997 private final Statement mBase; 998 CreateSurfaceTextureStatement(Statement base)999 public CreateSurfaceTextureStatement(Statement base) { 1000 mBase = base; 1001 } 1002 1003 @Override evaluate()1004 public void evaluate() throws Throwable { 1005 try { 1006 mBase.evaluate(); 1007 } finally { 1008 try { 1009 if (mSurface != null) mSurface.release(); 1010 } catch (Throwable t) {} 1011 try { 1012 if (mSurfaceTexture != null) mSurfaceTexture.release(); 1013 } catch (Throwable t) {} 1014 } 1015 } 1016 } 1017 } 1018 } 1019