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