aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Hoisie <hoisie@google.com>2024-04-26 00:39:59 -0700
committerCopybara-Service <copybara-worker@google.com>2024-04-26 00:40:46 -0700
commit41a9904a946afa40cd4b623ec088e9d018c0cb03 (patch)
treef49d0f3d9e0723849726f3e6fc4cb336c5a4b9e6
parentb551e5049d6c88c79fa5e51150aa546dd49d78aa (diff)
downloadrobolectric-41a9904a946afa40cd4b623ec088e9d018c0cb03.tar.gz
Fix HW rendering in Android V
ShadowNativeBaseRecordingCanvas was missing the `callNativeMethodsByDefault` annotation param, which meant that all the native methods were no-ops in Android V. Add some additional tests to capture this issue. PiperOrigin-RevId: 628318882
-rw-r--r--integration_tests/nativegraphics/src/test/java/org/robolectric/integrationtests/nativegraphics/HardwareAcceleratedActivityRenderTest.java66
-rw-r--r--integration_tests/nativegraphics/src/test/java/org/robolectric/integrationtests/nativegraphics/ShadowNativeHardwareRendererTest.java46
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeBaseRecordingCanvas.java1
3 files changed, 102 insertions, 11 deletions
diff --git a/integration_tests/nativegraphics/src/test/java/org/robolectric/integrationtests/nativegraphics/HardwareAcceleratedActivityRenderTest.java b/integration_tests/nativegraphics/src/test/java/org/robolectric/integrationtests/nativegraphics/HardwareAcceleratedActivityRenderTest.java
index 3828aa087..7f8e26578 100644
--- a/integration_tests/nativegraphics/src/test/java/org/robolectric/integrationtests/nativegraphics/HardwareAcceleratedActivityRenderTest.java
+++ b/integration_tests/nativegraphics/src/test/java/org/robolectric/integrationtests/nativegraphics/HardwareAcceleratedActivityRenderTest.java
@@ -1,29 +1,73 @@
package org.robolectric.integrationtests.nativegraphics;
import static android.os.Build.VERSION_CODES.S;
+import static com.google.common.truth.Truth.assertThat;
import android.app.Activity;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.PixelCopy;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
import android.view.WindowManager;
+import android.widget.FrameLayout;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(minSdk = S)
public class HardwareAcceleratedActivityRenderTest {
@Test
- public void setupHardwareAcceleratedActivity() {
- // This will exercise much of the HardwareRenderer / RenderNode / RecordingCanvas native code.
- ActivityController<Activity> controller = Robolectric.buildActivity(Activity.class);
- controller
- .get()
- .getWindow()
- .setFlags(
- WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
- WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
- controller.setup();
+ public void hardwareAcceleratedActivity_setup() throws Exception {
+ // Setting up an Activity is a smoke test that exercises much of the HardwareRenderer /
+ // RenderNode / RecordingCanvas native code.
+ Robolectric.setupActivity(HardwareAcceleratedActivity.class);
+ }
+
+ @Test
+ public void hardwareAcceleratedActivity_pixelCopy() throws Exception {
+ System.setProperty("robolectric.pixelCopyRenderMode", "hardware");
+ try {
+ HardwareAcceleratedActivity activity =
+ Robolectric.setupActivity(HardwareAcceleratedActivity.class);
+ Window window = activity.getWindow();
+ View decorView = window.getDecorView();
+ Bitmap bitmap =
+ Bitmap.createBitmap(decorView.getWidth(), decorView.getHeight(), Bitmap.Config.ARGB_8888);
+ CountDownLatch latch = new CountDownLatch(1);
+ PixelCopy.request(
+ window, bitmap, copyResult -> latch.countDown(), new Handler(Looper.getMainLooper()));
+ latch.await(1, TimeUnit.SECONDS);
+ assertThat(bitmap.getPixel(100, 100)).isEqualTo(Color.RED);
+ } finally {
+ System.clearProperty("robolectric.pixelCopyRenderMode");
+ }
+ }
+
+ static class HardwareAcceleratedActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // TODO(hoisie): manually setting these flags should not be required. Robolectric should
+ // set them automatically by default (they have been default since ICS).
+ getWindow()
+ .setFlags(
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+ FrameLayout frameLayout = new FrameLayout(this);
+ frameLayout.setLayoutParams(
+ new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ frameLayout.setBackgroundColor(Color.RED);
+ setContentView(frameLayout);
+ }
}
}
diff --git a/integration_tests/nativegraphics/src/test/java/org/robolectric/integrationtests/nativegraphics/ShadowNativeHardwareRendererTest.java b/integration_tests/nativegraphics/src/test/java/org/robolectric/integrationtests/nativegraphics/ShadowNativeHardwareRendererTest.java
index 2b6c48d7b..89d8e675c 100644
--- a/integration_tests/nativegraphics/src/test/java/org/robolectric/integrationtests/nativegraphics/ShadowNativeHardwareRendererTest.java
+++ b/integration_tests/nativegraphics/src/test/java/org/robolectric/integrationtests/nativegraphics/ShadowNativeHardwareRendererTest.java
@@ -1,9 +1,21 @@
package org.robolectric.integrationtests.nativegraphics;
import static android.os.Build.VERSION_CODES.Q;
+import static android.os.Build.VERSION_CODES.S;
+import static com.google.common.truth.Truth.assertThat;
+import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.HardwareRenderer;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.RecordingCanvas;
+import android.graphics.RenderNode;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageReader;
import android.view.Choreographer;
+import android.view.Surface;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@@ -24,4 +36,38 @@ public class ShadowNativeHardwareRendererTest {
// HardwareRenderer.nHackySetRTAnimationsEnabled. Ensure that RNG is loaded if this happens.
var unused = Choreographer.getInstance();
}
+
+ @Test
+ @Config(minSdk = S)
+ public void imageReader_readsRenderedDisplayList() {
+ int width = 100;
+ int height = 100;
+
+ try (ImageReader imageReader =
+ ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 1)) {
+ HardwareRenderer renderer = new HardwareRenderer();
+ RenderNode displayList = createDisplayList(width, height);
+ Surface surface = imageReader.getSurface();
+ renderer.setSurface(surface);
+ Image nativeImage = imageReader.acquireNextImage();
+ renderer.setContentRoot(displayList);
+ renderer.createRenderRequest().syncAndDraw();
+ 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);
+ }
+ }
+
+ private static RenderNode createDisplayList(int width, int height) {
+ RenderNode renderNode = new RenderNode("RedNode");
+ 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();
+ return renderNode;
+ }
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeBaseRecordingCanvas.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeBaseRecordingCanvas.java
index 005b51905..b87bbe40d 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeBaseRecordingCanvas.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowNativeBaseRecordingCanvas.java
@@ -21,6 +21,7 @@ import org.robolectric.versioning.AndroidVersions.U;
value = BaseRecordingCanvas.class,
minSdk = Q,
shadowPicker = Picker.class,
+ callNativeMethodsByDefault = true,
isInAndroidSdk = false)
public class ShadowNativeBaseRecordingCanvas extends ShadowNativeCanvas {