package com.robotium.solo; import java.nio.IntBuffer; import java.util.concurrent.CountDownLatch; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.graphics.Bitmap; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView.Renderer; import android.view.View; /** * Used to wrap and replace the renderer to gain access to the gl context. * * @author Per-Erik Bergman, bergman@uncle.se * */ class GLRenderWrapper implements Renderer { private Renderer renderer; private int width; private int height; private final GLSurfaceView view; private CountDownLatch latch; private boolean takeScreenshot = true; private int glVersion; /** * Constructs this object. * * @param view the current glSurfaceView * @param renderer the renderer to wrap * @param latch the count down latch */ public GLRenderWrapper(GLSurfaceView view, Renderer renderer, CountDownLatch latch) { this.view = view; this.renderer = renderer; this.latch = latch; this.width = view.getWidth(); this.height = view.getHeight(); Integer out = new Reflect(view).field("mEGLContextClientVersion") .out(Integer.class); if ( out != null ) { this.glVersion = out.intValue(); } else { this.glVersion = -1; this.takeScreenshot = false; } } @Override /* * (non-Javadoc) * @see android.opengl.GLSurfaceView.Renderer#onSurfaceCreated(javax.microedition.khronos.opengles.GL10, javax.microedition.khronos.egl.EGLConfig) */ public void onSurfaceCreated(GL10 gl, EGLConfig config) { renderer.onSurfaceCreated(gl, config); } @Override /* * (non-Javadoc) * @see android.opengl.GLSurfaceView.Renderer#onSurfaceChanged(javax.microedition.khronos.opengles.GL10, int, int) */ public void onSurfaceChanged(GL10 gl, int width, int height) { this.width = width; this.height = height; renderer.onSurfaceChanged(gl, width, height); } @Override /* * (non-Javadoc) * @see android.opengl.GLSurfaceView.Renderer#onDrawFrame(javax.microedition.khronos.opengles.GL10) */ public void onDrawFrame(GL10 gl) { renderer.onDrawFrame(gl); if (takeScreenshot) { Bitmap screenshot = null; if (glVersion >= 2) { screenshot = savePixels(0, 0, width, height); } else { screenshot = savePixels(0, 0, width, height, gl); } new Reflect(view).field("mDrawingCache").type(View.class) .in(screenshot); latch.countDown(); takeScreenshot = false; } } /** * Tell the wrapper to take a screen shot */ public void setTakeScreenshot() { takeScreenshot = true; } /** * Set the count down latch */ public void setLatch(CountDownLatch latch) { this.latch = latch; } /** * Extract the bitmap from OpenGL * * @param x the start column * @param y the start line * @param w the width of the bitmap * @param h the height of the bitmap */ private Bitmap savePixels(int x, int y, int w, int h) { int b[] = new int[w * (y + h)]; int bt[] = new int[w * h]; IntBuffer ib = IntBuffer.wrap(b); ib.position(0); GLES20.glReadPixels(x, 0, w, y + h, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ib); for (int i = 0, k = 0; i < h; i++, k++) { // remember, that OpenGL bitmap is incompatible with Android bitmap // and so, some correction need. for (int j = 0; j < w; j++) { int pix = b[i * w + j]; int pb = (pix >> 16) & 0xff; int pr = (pix << 16) & 0x00ff0000; int pix1 = (pix & 0xff00ff00) | pr | pb; bt[(h - k - 1) * w + j] = pix1; } } Bitmap sb = Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888); return sb; } /** * Extract the bitmap from OpenGL * * @param x the start column * @param y the start line * @param w the width of the bitmap * @param h the height of the bitmap * @param gl the current GL reference */ private static Bitmap savePixels(int x, int y, int w, int h, GL10 gl) { int b[] = new int[w * (y + h)]; int bt[] = new int[w * h]; IntBuffer ib = IntBuffer.wrap(b); ib.position(0); gl.glReadPixels(x, 0, w, y + h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib); for (int i = 0, k = 0; i < h; i++, k++) { // remember, that OpenGL bitmap is incompatible with Android bitmap // and so, some correction need. for (int j = 0; j < w; j++) { int pix = b[i * w + j]; int pb = (pix >> 16) & 0xff; int pr = (pix << 16) & 0x00ff0000; int pix1 = (pix & 0xff00ff00) | pr | pb; bt[(h - k - 1) * w + j] = pix1; } } Bitmap sb = Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888); return sb; } }