Add basic Robolectric support for EGL14
PiperOrigin-RevId: 373284290
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowEGL14Test.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowEGL14Test.java
new file mode 100644
index 0000000..e5d5c9d
--- /dev/null
+++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowEGL14Test.java
@@ -0,0 +1,66 @@
+package org.robolectric.shadows;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.opengl.EGL14;
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.os.Build.VERSION_CODES;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+
+/** Unit tests for {@link ShadowEGL14Test} */
+@RunWith(AndroidJUnit4.class)
+@Config(minSdk = VERSION_CODES.LOLLIPOP)
+public final class ShadowEGL14Test {
+ @Test
+ public void eglGetDisplay() {
+ assertThat(EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY)).isNotNull();
+ }
+
+ @Test
+ public void eglChooseConfig() {
+ EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] numConfig = new int[1];
+ assertThat(EGL14.eglChooseConfig(display, new int[0], 0, configs, 0, 1, numConfig, 0)).isTrue();
+ assertThat(numConfig[0]).isGreaterThan(0);
+ assertThat(configs[0]).isNotNull();
+ }
+
+ @Test
+ public void eglCreateContext_v2() {
+ EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+ int[] attribList = {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE};
+ EGLContext context = EGL14.eglCreateContext(display, createEglConfig(), null, attribList, 0);
+ assertThat(context).isNotNull();
+ int[] values = new int[1];
+ EGL14.eglQueryContext(display, context, EGL14.EGL_CONTEXT_CLIENT_VERSION, values, 0);
+ assertThat(values[0]).isEqualTo(2);
+ }
+
+ @Test
+ public void eglCreatePbufferSurface() {
+ EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+ assertThat(EGL14.eglCreatePbufferSurface(display, createEglConfig(), new int[0], 0))
+ .isNotNull();
+ }
+
+ @Test
+ public void eglCreateWindowSurface() {
+ EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+ assertThat(EGL14.eglCreateWindowSurface(display, createEglConfig(), null, new int[0], 0))
+ .isNotNull();
+ }
+
+ private EGLConfig createEglConfig() {
+ EGLDisplay display = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] numConfig = new int[1];
+ EGL14.eglChooseConfig(display, new int[0], 0, configs, 0, 1, numConfig, 0);
+ return configs[0];
+ }
+}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEGL14.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEGL14.java
new file mode 100644
index 0000000..475607a
--- /dev/null
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowEGL14.java
@@ -0,0 +1,133 @@
+package org.robolectric.shadows;
+
+import android.opengl.EGL14;
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLSurface;
+import android.os.Build.VERSION_CODES;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.util.ReflectionHelpers;
+import org.robolectric.util.ReflectionHelpers.ClassParameter;
+
+/** Shadow for EGL14. Currently doesn't handle real graphics work, but avoids crashing when run. */
+@Implements(value = EGL14.class, minSdk = VERSION_CODES.LOLLIPOP)
+public class ShadowEGL14 {
+ private static final long UNUSED_HANDLE_ID = 43L;
+
+ @Implementation
+ protected static EGLDisplay eglGetDisplay(int displayId) {
+ return createEglDisplay();
+ }
+
+ @Implementation
+ protected static boolean eglInitialize(
+ EGLDisplay dpy, int[] major, int majorOffset, int[] minor, int minorOffset) {
+ return true;
+ }
+
+ @Implementation
+ protected static boolean eglChooseConfig(
+ EGLDisplay dpy,
+ int[] attribList,
+ int attribListOffset,
+ EGLConfig[] configs,
+ int configsOffset,
+ int configSize,
+ int[] numConfig,
+ int numConfigOffset) {
+ configs[configsOffset] = createEglConfig();
+ numConfig[numConfigOffset] = 1;
+ return true;
+ }
+
+ @Implementation
+ protected static EGLContext eglCreateContext(
+ EGLDisplay dpy, EGLConfig config, EGLContext shareContext, int[] attribList, int offset) {
+ int majorVersion = getAttribValue(attribList, EGL14.EGL_CONTEXT_CLIENT_VERSION);
+ switch (majorVersion) {
+ case 2:
+ case 3:
+ return createEglContext(majorVersion);
+ default:
+ break;
+ }
+ return EGL14.EGL_NO_CONTEXT;
+ }
+
+ @Implementation
+ protected static boolean eglQueryContext(
+ EGLDisplay dpy, EGLContext ctx, int attribute, int[] value, int offset) {
+ value[offset] = 0;
+ switch (attribute) {
+ case EGL14.EGL_CONTEXT_CLIENT_VERSION:
+ // We stored the version in the handle field when we created the context.
+ value[offset] = (int) ctx.getNativeHandle();
+ break;
+ default:
+ // Use default output set above switch.
+ }
+ return true;
+ }
+
+ @Implementation
+ protected static EGLSurface eglCreatePbufferSurface(
+ EGLDisplay dpy, EGLConfig config, int[] attribList, int offset) {
+ return createEglSurface();
+ }
+
+ @Implementation
+ protected static EGLSurface eglCreateWindowSurface(
+ EGLDisplay dpy, EGLConfig config, Object win, int[] attribList, int offset) {
+ return createEglSurface();
+ }
+
+ @Implementation
+ protected static boolean eglMakeCurrent(
+ EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
+ return true;
+ }
+
+ @Implementation
+ protected static boolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
+ return true;
+ }
+
+ @Implementation
+ protected static int eglGetError() {
+ return EGL14.EGL_SUCCESS;
+ }
+
+ private static EGLDisplay createEglDisplay() {
+ return ReflectionHelpers.callConstructor(
+ EGLDisplay.class, ClassParameter.from(long.class, UNUSED_HANDLE_ID));
+ }
+
+ private static EGLConfig createEglConfig() {
+ return ReflectionHelpers.callConstructor(
+ EGLConfig.class, ClassParameter.from(long.class, UNUSED_HANDLE_ID));
+ }
+
+ private static EGLContext createEglContext(int version) {
+ // As a hack store the version number in the unused handle ID so we can retrieve it later
+ // if the caller queries a context.
+ return ReflectionHelpers.callConstructor(
+ EGLContext.class, ClassParameter.from(long.class, version));
+ }
+
+ private static EGLSurface createEglSurface() {
+ return ReflectionHelpers.callConstructor(
+ EGLSurface.class, ClassParameter.from(long.class, UNUSED_HANDLE_ID));
+ }
+
+ private static int getAttribValue(int[] attribList, int attribute) {
+ int attribValue = 0;
+ for (int i = 0; i < attribList.length; i += 2) {
+ if (attribList[i] == attribute) {
+ attribValue = attribList[i + 1];
+ }
+ }
+ return attribValue;
+ }
+}