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