Skip to content

Commit

Permalink
Merge "Merge branch 'upstream-google' into try_merge_upstream" into m…
Browse files Browse the repository at this point in the history
…ain am: 339a78f am: bd9bd58

Original change: https://android-review.googlesource.com/c/platform/external/robolectric/+/3131713

Change-Id: I2e77e679a4e3e050755ab89262433547c4d6848b
Signed-off-by: Automerger Merge Worker <[email protected]>
  • Loading branch information
Treehugger Robot authored and android-build-merge-worker-robot committed Jun 13, 2024
2 parents 946b77d + bd9bd58 commit 032e499
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import static android.os.Build.VERSION_CODES.Q;
import static android.os.Build.VERSION_CODES.R;
import static com.google.common.base.StandardSystemProperty.OS_NAME;
import static com.google.common.truth.Truth.assertThat;
import static org.robolectric.util.reflector.Reflector.reflector;

import android.annotation.ColorInt;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.HardwareRenderer;
Expand All @@ -17,6 +19,9 @@
import android.media.ImageReader;
import android.view.Choreographer;
import android.view.Surface;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.Locale;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
Expand Down Expand Up @@ -56,33 +61,113 @@ public void imageReader_readsRenderedDisplayList() {
try (ImageReader imageReader =
ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 1)) {
HardwareRenderer renderer = new HardwareRenderer();
RenderNode displayList = createDisplayList(width, height);
RenderNode renderNode = new RenderNode("RedNode");
renderNode.setPosition(0, 0, width, height);
RecordingCanvas canvas = renderNode.beginRecording();
canvas.drawColor(Color.RED);
renderNode.endRecording();
Surface surface = imageReader.getSurface();
renderer.setSurface(surface);
Image nativeImage = imageReader.acquireNextImage();
renderer.setContentRoot(displayList);
renderer.setContentRoot(renderNode);
renderer.createRenderRequest().syncAndDraw();
Image nativeImage = imageReader.acquireNextImage();
Plane[] planes = nativeImage.getPlanes();
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(planes[0].getBuffer());
surface.release();
assertThat(bitmap.getPixel(50, 50)).isEqualTo(Color.RED);
assertThat(Integer.toHexString(bitmap.getPixel(50, 50)))
.isEqualTo(Integer.toHexString(Color.RED));
}
}

@Test
public void hardwareRenderer_drawDisplayList_validateARGB() {
int pw = 320;
int ph = 470;

try (ImageReader imageReader = ImageReader.newInstance(pw, ph, PixelFormat.RGBA_8888, 1)) {
// Note on pixel format:
// - ImageReader is configured as RGBA_8888 above.
// - However the native libs/hwui/pipeline/skia/SkiaHostPipeline.cpp always treats
// the buffer as BGRA_8888 on Linux and Windows, or RGBA_8888 n Mac.

HardwareRenderer renderer = new HardwareRenderer();
RenderNode displayList = createDisplayList(pw, ph);

Surface surface = imageReader.getSurface();
renderer.setSurface(surface);
Image nativeImage = imageReader.acquireNextImage();
renderer.setContentRoot(displayList);
renderer.createRenderRequest().syncAndDraw();

int[] dstImageData = new int[pw * ph];
Plane[] planes = nativeImage.getPlanes();
IntBuffer buff = planes[0].getBuffer().order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
buff.get(dstImageData);

// The image drawn is here:
// https://gist.github.com/hoisie/2c78e5e86ce335f7c5a2431f72a92888#file-hw_render-png

// Check that the pixel at (0, 0) is white.
assertThat(Integer.toHexString(dstImageData[0])).isEqualTo("ffffffff");
if (isMac()) {
// Check for red pixels in ABGR format on Mac.
assertThat(Integer.toHexString(dstImageData[1])).isEqualTo("ff0000ff");
assertThat(Integer.toHexString(dstImageData[2])).isEqualTo("ff0000ff");
} else {
// Check for red pixels in ARGB format on Linux/Windows.
assertThat(Integer.toHexString(dstImageData[1])).isEqualTo("ffff0000");
assertThat(Integer.toHexString(dstImageData[2])).isEqualTo("ffff0000");
}
surface.release();
}
}

/**
* This function draws three overlapping rectangles: a red one in the top left quadrant, a green
* on centered in the middle, and a blue one in the bottom right quadrant. Each of the rectangles
* has a shadow, and the bottom right one also has a round corner. It also contains a white point
* at the top left.
*
* <p>You can see the image drawn here:
* https://gist.github.com/hoisie/2c78e5e86ce335f7c5a2431f72a92888#file-hw_render-png
*/
private static RenderNode createDisplayList(int width, int height) {
RenderNode renderNode = new RenderNode("RedNode");
RenderNode renderNode = new RenderNode("MyRenderNode");
renderNode.setPosition(0, 0, width, height);
RecordingCanvas canvas = renderNode.beginRecording();
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawRect(0, 0, width, height, paint);
renderNode.endRecording();
// TODO(hoisie): simplify this drawing logic.
int w4 = width / 4;
int h4 = height / 4;
try {
// Draw a red rectangle in the top left quadrant.
canvas.drawRect(0, 0, 2 * w4, 2 * h4, createPaint(Color.RED));
// Draw a green rectangle in the center.
canvas.drawRect(w4, h4, 3 * w4, 3 * h4, createPaint(Color.GREEN));
// Draw a rounded blue rectangle in the bottom right quadrant.
canvas.drawRoundRect(
2 * w4, 2 * h4, width, height, width / 10f, height / 10f, createPaint(Color.BLUE));
// Draw a white point at the top left.
canvas.drawPoint(0.5f, 0.5f, createPaint(Color.WHITE));
} finally {
renderNode.endRecording();
}
return renderNode;
}

private static Paint createPaint(@ColorInt int color) {
Paint paint = new Paint();
paint.setColor(color);
paint.setShadowLayer(20.f, 5.f, 5.f, color & 0xCFFFFFFF);
return paint;
}

@ForType(HardwareRenderer.class)
interface HardwareRendererReflector {
void setWideGamut(boolean wideGamut);
}

private static boolean isMac() {
return OS_NAME.value().toLowerCase(Locale.ROOT).contains("mac");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package org.robolectric.shadows;

import static android.os.Build.VERSION_CODES.Q;
import static com.google.common.truth.Truth.assertThat;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.media.Image;
import android.media.ImageReader;
import android.view.Surface;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

/**
* Test for {@link org.robolectric.shadows.ShadowNativeImageReader} and {@link
* org.robolectric.shadows.ShadowNativeImageReaderSurfaceImage}.
*/
@Config(minSdk = Q)
@RunWith(RobolectricTestRunner.class)
public class ShadowNativeImageReaderTest {

private static final int SX = 320;
private static final int SY = 320;

@Test
public void test_imageReader_newInstance_validateHasSurface() {
try (ImageReader imageReader = ImageReader.newInstance(SX, SY, PixelFormat.RGBA_8888, 1)) {

assertThat(imageReader).isNotNull();
Surface surface = imageReader.getSurface();
try {
assertThat(surface).isNotNull();
assertThat(surface.getClass().getSimpleName()).doesNotContain("Fake");
assertThat(surface.isValid()).isTrue();
} finally {
surface.release();
}
}
}

@Test
public void test_imageReader_getSurface_acquireNextImage() {
try (ImageReader imageReader = ImageReader.newInstance(SX, SY, PixelFormat.RGBA_8888, 1)) {

Surface surface = imageReader.getSurface();
try {
assertThat(surface).isNotNull();
// Note: do not call surface.lockCanvas(), it is not implemented on the JNI side.

try (Image image = imageReader.acquireNextImage()) {
assertThat(image).isNotNull();
assertThat(image.getFormat()).isEqualTo(PixelFormat.RGBA_8888);
assertThat(image.getWidth()).isEqualTo(320);
assertThat(image.getHeight()).isEqualTo(320);
assertThat(image.getPlanes()).hasLength(1);
}
} finally {
surface.release();
}
}
}

@Test
public void test_imageReader_getSurface_lockCanvas() {
try (ImageReader imageReader = ImageReader.newInstance(SX, SY, PixelFormat.RGBA_8888, 1)) {
Surface surface = imageReader.getSurface();
Canvas canvas = surface.lockCanvas(new Rect(0, 0, SX, SY));
surface.unlockCanvasAndPost(canvas);
}
}

@Test
public void testGetHardwareBuffer() throws Exception {
ImageReader reader = ImageReader.newInstance(1, 1, PixelFormat.RGBA_8888, 1);
Surface surface = reader.getSurface();
Canvas canvas = surface.lockHardwareCanvas();
canvas.drawColor(Color.RED);
surface.unlockCanvasAndPost(canvas);
Image image = reader.acquireNextImage();
assertThat(image).isNotNull();
HardwareBuffer buffer = image.getHardwareBuffer();
// TODO(hoisie): buffer should not be null, but fixing it will require an implementation of
// HardwareBuffer on host libandroid_runtime.
assertThat(buffer).isNull();
}
}

0 comments on commit 032e499

Please sign in to comment.