Instantiate GLCanvas rather than reinitialize current GLCanvas.

 GLCanvas was being used as a singleton when it really should
 allow separate instances for correctness.

Change-Id: I650884e843a4a78997b70826f6012ae19b8df549
diff --git a/src/com/android/gallery3d/glrenderer/ExtTexture.java b/src/com/android/gallery3d/glrenderer/ExtTexture.java
index b1fbd19..af76300 100644
--- a/src/com/android/gallery3d/glrenderer/ExtTexture.java
+++ b/src/com/android/gallery3d/glrenderer/ExtTexture.java
@@ -22,8 +22,8 @@
 
     private int mTarget;
 
-    public ExtTexture(int target) {
-        GLId glId = GLCanvas.getGLId();
+    public ExtTexture(GLCanvas canvas, int target) {
+        GLId glId = canvas.getGLId();
         mId = glId.generateTexture();
         mTarget = target;
     }
diff --git a/src/com/android/gallery3d/glrenderer/GLCanvas.java b/src/com/android/gallery3d/glrenderer/GLCanvas.java
index 5e319f8..4cf1689 100644
--- a/src/com/android/gallery3d/glrenderer/GLCanvas.java
+++ b/src/com/android/gallery3d/glrenderer/GLCanvas.java
@@ -20,83 +20,56 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 
-import com.android.gallery3d.common.ApiHelper;
-
-import javax.microedition.khronos.opengles.GL11;
-
 //
 // GLCanvas gives a convenient interface to draw using OpenGL.
 //
 // When a rectangle is specified in this interface, it means the region
 // [x, x+width) * [y, y+height)
 //
-public abstract class GLCanvas {
+public interface GLCanvas {
     public enum Blending {
         Additive, Mix,
     }
 
-    private static GLCanvas sInstance = instantiateCanvas();
-    private static GLId sGLId = instantiateGLId();
-
-    public static GLId getGLId() {
-        return sGLId;
-    }
-
-    public static GLCanvas getInstance() {
-        return sInstance;
-    }
-
-    private static GLId instantiateGLId() {
-        return ApiHelper.HAS_GLES20_REQUIRED ? (GLES20Canvas) sInstance : new GLIdImpl();
-    }
-
-    private static GLCanvas instantiateCanvas() {
-        return ApiHelper.HAS_GLES20_REQUIRED ? new GLES20Canvas() : new GLES11Canvas();
-    }
-
-    public static int getEGLContextClientVersion() {
-        return ApiHelper.HAS_GLES20_REQUIRED ? 2 : 1;
-    }
-
-    public abstract void initialize(GL11 gl);
+    public GLId getGLId();
 
     // Tells GLCanvas the size of the underlying GL surface. This should be
     // called before first drawing and when the size of GL surface is changed.
     // This is called by GLRoot and should not be called by the clients
     // who only want to draw on the GLCanvas. Both width and height must be
     // nonnegative.
-    public abstract void setSize(int width, int height);
+    public void setSize(int width, int height);
 
     // Clear the drawing buffers. This should only be used by GLRoot.
-    public abstract void clearBuffer();
+    public void clearBuffer();
 
-    public abstract void clearBuffer(float[] argb);
+    public void clearBuffer(float[] argb);
 
     // Sets and gets the current alpha, alpha must be in [0, 1].
-    public abstract void setAlpha(float alpha);
+    public void setAlpha(float alpha);
 
-    public abstract float getAlpha();
+    public float getAlpha();
 
     // (current alpha) = (current alpha) * alpha
-    public abstract void multiplyAlpha(float alpha);
+    public void multiplyAlpha(float alpha);
 
     // Change the current transform matrix.
-    public abstract void translate(float x, float y, float z);
+    public void translate(float x, float y, float z);
 
-    public abstract void translate(float x, float y);
+    public void translate(float x, float y);
 
-    public abstract void scale(float sx, float sy, float sz);
+    public void scale(float sx, float sy, float sz);
 
-    public abstract void rotate(float angle, float x, float y, float z);
+    public void rotate(float angle, float x, float y, float z);
 
-    public abstract void multiplyMatrix(float[] mMatrix, int offset);
+    public void multiplyMatrix(float[] mMatrix, int offset);
 
     // Pushes the configuration state (matrix, and alpha) onto
     // a private stack.
-    public abstract void save();
+    public void save();
 
     // Same as save(), but only save those specified in saveFlags.
-    public abstract void save(int saveFlags);
+    public void save(int saveFlags);
 
     public static final int SAVE_FLAG_ALL = 0xFFFFFFFF;
     public static final int SAVE_FLAG_ALPHA = 0x01;
@@ -107,65 +80,64 @@
     // alpha, and clip). This call balances a previous call to save(), and is
     // used to remove all modifications to the configuration state since the
     // last save call.
-    public abstract void restore();
+    public void restore();
 
     // Draws a line using the specified paint from (x1, y1) to (x2, y2).
     // (Both end points are included).
-    public abstract void drawLine(float x1, float y1, float x2, float y2, GLPaint paint);
+    public void drawLine(float x1, float y1, float x2, float y2, GLPaint paint);
 
     // Draws a rectangle using the specified paint from (x1, y1) to (x2, y2).
     // (Both end points are included).
-    public abstract void drawRect(float x1, float y1, float x2, float y2, GLPaint paint);
+    public void drawRect(float x1, float y1, float x2, float y2, GLPaint paint);
 
     // Fills the specified rectangle with the specified color.
-    public abstract void fillRect(float x, float y, float width, float height, int color);
+    public void fillRect(float x, float y, float width, float height, int color);
 
     // Draws a texture to the specified rectangle.
-    public abstract void drawTexture(
-            BasicTexture texture, int x, int y, int width, int height);
+    public void drawTexture(BasicTexture texture, int x, int y, int width, int height);
 
-    public abstract void drawMesh(BasicTexture tex, int x, int y, int xyBuffer,
+    public void drawMesh(BasicTexture tex, int x, int y, int xyBuffer,
             int uvBuffer, int indexBuffer, int indexCount);
 
     // Draws the source rectangle part of the texture to the target rectangle.
-    public abstract void drawTexture(BasicTexture texture, RectF source, RectF target);
+    public void drawTexture(BasicTexture texture, RectF source, RectF target);
 
     // Draw a texture with a specified texture transform.
-    public abstract void drawTexture(BasicTexture texture, float[] mTextureTransform,
+    public void drawTexture(BasicTexture texture, float[] mTextureTransform,
                 int x, int y, int w, int h);
 
     // Draw two textures to the specified rectangle. The actual texture used is
     // from * (1 - ratio) + to * ratio
     // The two textures must have the same size.
-    public abstract void drawMixed(BasicTexture from, int toColor,
+    public void drawMixed(BasicTexture from, int toColor,
             float ratio, int x, int y, int w, int h);
 
     // Draw a region of a texture and a specified color to the specified
     // rectangle. The actual color used is from * (1 - ratio) + to * ratio.
     // The region of the texture is defined by parameter "src". The target
     // rectangle is specified by parameter "target".
-    public abstract void drawMixed(BasicTexture from, int toColor,
+    public void drawMixed(BasicTexture from, int toColor,
             float ratio, RectF src, RectF target);
 
     // Unloads the specified texture from the canvas. The resource allocated
     // to draw the texture will be released. The specified texture will return
     // to the unloaded state. This function should be called only from
     // BasicTexture or its descendant
-    public abstract boolean unloadTexture(BasicTexture texture);
+    public boolean unloadTexture(BasicTexture texture);
 
     // Delete the specified buffer object, similar to unloadTexture.
-    public abstract void deleteBuffer(int bufferId);
+    public void deleteBuffer(int bufferId);
 
     // Delete the textures and buffers in GL side. This function should only be
     // called in the GL thread.
-    public abstract void deleteRecycledResources();
+    public void deleteRecycledResources();
 
     // Dump statistics information and clear the counters. For debug only.
-    public abstract void dumpStatisticsAndClear();
+    public void dumpStatisticsAndClear();
 
-    public abstract void beginRenderTarget(RawTexture texture);
+    public void beginRenderTarget(RawTexture texture);
 
-    public abstract void endRenderTarget();
+    public void endRenderTarget();
 
     /**
      * Sets texture parameters to use GL_CLAMP_TO_EDGE for both
@@ -175,7 +147,7 @@
      *
      * @param texture The texture to set parameters on.
      */
-    public abstract void setTextureParameters(BasicTexture texture);
+    public void setTextureParameters(BasicTexture texture);
 
     /**
      * Initializes the texture to a size by calling texImage2D on it.
@@ -184,7 +156,7 @@
      * @param format The texture format (e.g. GL_RGBA)
      * @param type The texture type (e.g. GL_UNSIGNED_BYTE)
      */
-    public abstract void initializeTextureSize(BasicTexture texture, int format, int type);
+    public void initializeTextureSize(BasicTexture texture, int format, int type);
 
     /**
      * Initializes the texture to a size by calling texImage2D on it.
@@ -192,7 +164,7 @@
      * @param texture The texture to initialize the size.
      * @param bitmap The bitmap to initialize the bitmap with.
      */
-    public abstract void initializeTexture(BasicTexture texture, Bitmap bitmap);
+    public void initializeTexture(BasicTexture texture, Bitmap bitmap);
 
     /**
      * Calls glTexSubImage2D to upload a bitmap to the texture.
@@ -205,8 +177,7 @@
      * @param format The texture format (e.g. GL_RGBA)
      * @param type The texture type (e.g. GL_UNSIGNED_BYTE)
      */
-    public abstract void texSubImage2D(BasicTexture texture, int xOffset, int yOffset,
-            Bitmap bitmap,
+    public void texSubImage2D(BasicTexture texture, int xOffset, int yOffset, Bitmap bitmap,
             int format, int type);
 
     /**
@@ -215,7 +186,7 @@
      * @param buffer The buffer to upload
      * @return The buffer ID that was generated.
      */
-    public abstract int uploadBuffer(java.nio.FloatBuffer buffer);
+    public int uploadBuffer(java.nio.FloatBuffer buffer);
 
     /**
      * Generates buffers and uploads the element array buffer data.
@@ -223,36 +194,36 @@
      * @param buffer The buffer to upload
      * @return The buffer ID that was generated.
      */
-    public abstract int uploadBuffer(java.nio.ByteBuffer buffer);
+    public int uploadBuffer(java.nio.ByteBuffer buffer);
 
     /**
      * Sets the blending algorithm if a texture is not opaque.
      *
      * @param blending Either mixing (overlay) or adding a texture.
      */
-    public abstract void setBlending(Blending blending);
+    public void setBlending(Blending blending);
 
     /**
      * Enable stencil test
      */
-    public abstract void enableStencil();
+    public void enableStencil();
 
     /**
      * Disable stencil.
      */
-    public abstract void disableStencil();
+    public void disableStencil();
 
     /**
      * Clears the stencil so that a new stencil can be generated.
      */
-    public abstract void clearStencilBuffer();
+    public void clearStencilBuffer();
 
     /**
      * Start/stop updating the stencil buffer.
      *
      * @param update True if the stencil should be updated, false otherwise.
      */
-    public abstract void updateStencil(boolean update);
+    public void updateStencil(boolean update);
 
     /**
      * Changes how the stencil buffer is used.
@@ -261,13 +232,13 @@
      *            changed. If false, the area inside the stencil can be drawn to
      *            as well.
      */
-    public abstract void drawOnlyOutsideStencil(boolean onlyOutside);
+    public void drawOnlyOutsideStencil(boolean onlyOutside);
 
     /**
      * After LightCycle makes GL calls, this method is called to restore the GL
      * configuration to the one expected by GLCanvas.
      */
-    public abstract void recoverFromLightCycle();
+    public void recoverFromLightCycle();
 
     /**
      * Gets the bounds given by x, y, width, and height as well as the internal
@@ -280,5 +251,5 @@
      * @param width The width of the input rectangle.
      * @param height The height of the input rectangle.
      */
-    public abstract void getBounds(Rect bounds, int x, int y, int width, int height);
+    public void getBounds(Rect bounds, int x, int y, int width, int height);
 }
diff --git a/src/com/android/gallery3d/glrenderer/GLES11Canvas.java b/src/com/android/gallery3d/glrenderer/GLES11Canvas.java
index e4f7d1a..a4ffa2a 100644
--- a/src/com/android/gallery3d/glrenderer/GLES11Canvas.java
+++ b/src/com/android/gallery3d/glrenderer/GLES11Canvas.java
@@ -40,7 +40,7 @@
 import javax.microedition.khronos.opengles.GL11Ext;
 import javax.microedition.khronos.opengles.GL11ExtensionPack;
 
-public class GLES11Canvas extends GLCanvas {
+public class GLES11Canvas implements GLCanvas {
     @SuppressWarnings("unused")
     private static final String TAG = "GLCanvasImp";
 
@@ -95,7 +95,34 @@
     int mCountTextureRect;
     int mCountTextureOES;
 
-    GLES11Canvas() {
+    private static GLId mGLId = new GLES11IdImpl();
+
+    public GLES11Canvas(GL11 gl) {
+        mGL = gl;
+        mGLState = new GLState(gl);
+        // First create an nio buffer, then create a VBO from it.
+        int size = BOX_COORDINATES.length * Float.SIZE / Byte.SIZE;
+        FloatBuffer xyBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer();
+        xyBuffer.put(BOX_COORDINATES, 0, BOX_COORDINATES.length).position(0);
+
+        int[] name = new int[1];
+        mGLId.glGenBuffers(1, name, 0);
+        mBoxCoords = name[0];
+
+        gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBoxCoords);
+        gl.glBufferData(GL11.GL_ARRAY_BUFFER, xyBuffer.capacity() * (Float.SIZE / Byte.SIZE),
+                xyBuffer, GL11.GL_STATIC_DRAW);
+
+        gl.glVertexPointer(2, GL11.GL_FLOAT, 0, 0);
+        gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
+
+        // Enable the texture coordinate array for Texture 1
+        gl.glClientActiveTexture(GL11.GL_TEXTURE1);
+        gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
+        gl.glClientActiveTexture(GL11.GL_TEXTURE0);
+        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
+
+        // mMatrixValues and mAlpha will be initialized in setSize()
     }
 
     @Override
@@ -148,37 +175,6 @@
     }
 
     @Override
-    public void initialize(GL11 gl) {
-        mGL = gl;
-        mGLState = new GLState(gl);
-        // First create an nio buffer, then create a VBO from it.
-        int size = BOX_COORDINATES.length * Float.SIZE / Byte.SIZE;
-        FloatBuffer xyBuffer = allocateDirectNativeOrderBuffer(size).asFloatBuffer();
-        xyBuffer.put(BOX_COORDINATES, 0, BOX_COORDINATES.length).position(0);
-
-        int[] name = new int[1];
-        GLId glId = getGLId();
-        glId.glGenBuffers(1, name, 0);
-        mBoxCoords = name[0];
-
-        gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, mBoxCoords);
-        gl.glBufferData(GL11.GL_ARRAY_BUFFER,
-                xyBuffer.capacity() * (Float.SIZE / Byte.SIZE),
-                xyBuffer, GL11.GL_STATIC_DRAW);
-
-        gl.glVertexPointer(2, GL11.GL_FLOAT, 0, 0);
-        gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
-
-        // Enable the texture coordinate array for Texture 1
-        gl.glClientActiveTexture(GL11.GL_TEXTURE1);
-        gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
-        gl.glClientActiveTexture(GL11.GL_TEXTURE0);
-        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
-
-        // mMatrixValues and mAlpha will be initialized in setSize()
-    }
-
-    @Override
     public void drawRect(float x, float y, float width, float height, GLPaint paint) {
         GL11 gl = mGL;
 
@@ -751,15 +747,14 @@
     public void deleteRecycledResources() {
         synchronized (mUnboundTextures) {
             IntArray ids = mUnboundTextures;
-            GLId glId = getGLId();
             if (ids.size() > 0) {
-                glId.glDeleteTextures(mGL, ids.size(), ids.getInternalArray(), 0);
+                mGLId.glDeleteTextures(mGL, ids.size(), ids.getInternalArray(), 0);
                 ids.clear();
             }
 
             ids = mDeleteBuffers;
             if (ids.size() > 0) {
-                glId.glDeleteBuffers(mGL, ids.size(), ids.getInternalArray(), 0);
+                mGLId.glDeleteBuffers(mGL, ids.size(), ids.getInternalArray(), 0);
                 ids.clear();
             }
         }
@@ -860,8 +855,7 @@
         GL11ExtensionPack gl11ep = (GL11ExtensionPack) mGL;
 
         if (mTargetTexture == null && texture != null) {
-            GLId glId = getGLId();
-            glId.glGenBuffers(1, mFrameBuffer, 0);
+            mGLId.glGenBuffers(1, mFrameBuffer, 0);
             gl11ep.glBindFramebufferOES(
                     GL11ExtensionPack.GL_FRAMEBUFFER_OES, mFrameBuffer[0]);
         }
@@ -990,8 +984,7 @@
 
     private int uploadBuffer(Buffer buf, int elementSize) {
         int[] bufferIds = new int[1];
-        GLId glId = getGLId();
-        glId.glGenBuffers(bufferIds.length, bufferIds, 0);
+        mGLId.glGenBuffers(bufferIds.length, bufferIds, 0);
         int bufferId = bufferIds[0];
         mGL.glBindBuffer(GL11.GL_ARRAY_BUFFER, bufferId);
         mGL.glBufferData(GL11.GL_ARRAY_BUFFER, buf.capacity() * elementSize, buf,
@@ -1047,4 +1040,9 @@
     public void getBounds(Rect bounds, int x, int y, int width, int height) {
         // This is only required for GLES20
     }
+
+    @Override
+    public GLId getGLId() {
+        return mGLId;
+    }
 }
diff --git a/src/com/android/gallery3d/glrenderer/GLIdImpl.java b/src/com/android/gallery3d/glrenderer/GLES11IdImpl.java
similarity index 97%
rename from src/com/android/gallery3d/glrenderer/GLIdImpl.java
rename to src/com/android/gallery3d/glrenderer/GLES11IdImpl.java
index 92aa58e..e479373 100644
--- a/src/com/android/gallery3d/glrenderer/GLIdImpl.java
+++ b/src/com/android/gallery3d/glrenderer/GLES11IdImpl.java
@@ -22,7 +22,7 @@
  * Open GL ES 1.1 implementation for generating and destroying texture IDs and
  * buffer IDs
  */
-public class GLIdImpl implements GLId {
+public class GLES11IdImpl implements GLId {
     private static int sNextId = 1;
     // Mutex for sNextId
     private static Object sLock = new Object();
diff --git a/src/com/android/gallery3d/glrenderer/GLES20Canvas.java b/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
index c1f8164..80f861b 100644
--- a/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
+++ b/src/com/android/gallery3d/glrenderer/GLES20Canvas.java
@@ -33,10 +33,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 
-import javax.microedition.khronos.opengles.GL11;
-import javax.microedition.khronos.opengles.GL11ExtensionPack;
-
-public class GLES20Canvas extends GLCanvas implements GLId {
+public class GLES20Canvas implements GLCanvas {
     // ************** Constants **********************
     private static final String TAG = GLES20Canvas.class.getSimpleName();
     private static final int FLOAT_SIZE = Float.SIZE / Byte.SIZE;
@@ -269,15 +266,14 @@
     private final float[] mTempTextureMatrix = new float[MATRIX_SIZE];
     private final int[] mTempIntArray = new int[1];
 
+    private static final GLId mGLId = new GLES20IdImpl();
+
     public GLES20Canvas() {
         Matrix.setIdentityM(mTempTextureMatrix, 0);
         Matrix.setIdentityM(mMatrices, mCurrentMatrixIndex);
         mAlphas[mCurrentAlphaIndex] = 1f;
         mTargetTextures.add(null);
-    }
 
-    @Override
-    public void initialize(GL11 gl) {
         FloatBuffer boxBuffer = createBuffer(BOX_COORDINATES);
         mBoxCoordinates = uploadBuffer(boxBuffer);
 
@@ -813,13 +809,13 @@
         synchronized (mUnboundTextures) {
             IntArray ids = mUnboundTextures;
             if (mUnboundTextures.size() > 0) {
-                glDeleteTextures(null, ids.size(), ids.getInternalArray(), 0);
+                mGLId.glDeleteTextures(null, ids.size(), ids.getInternalArray(), 0);
                 ids.clear();
             }
 
             ids = mDeleteBuffers;
             if (ids.size() > 0) {
-                glDeleteBuffers(null, ids.size(), ids.getInternalArray(), 0);
+                mGLId.glDeleteBuffers(null, ids.size(), ids.getInternalArray(), 0);
                 ids.clear();
             }
         }
@@ -957,7 +953,7 @@
     }
 
     private int uploadBuffer(Buffer buffer, int elementSize) {
-        glGenBuffers(1, mTempIntArray, 0);
+        mGLId.glGenBuffers(1, mTempIntArray, 0);
         checkError();
         int bufferId = mTempIntArray[0];
         GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId);
@@ -993,36 +989,6 @@
         checkError();
     }
 
-    @Override
-    public int generateTexture() {
-        GLES20.glGenTextures(1, mTempIntArray, 0);
-        checkError();
-        return mTempIntArray[0];
-    }
-
-    @Override
-    public void glGenBuffers(int n, int[] buffers, int offset) {
-        GLES20.glGenBuffers(n, buffers, offset);
-        checkError();
-    }
-
-    @Override
-    public void glDeleteTextures(GL11 gl, int n, int[] textures, int offset) {
-        GLES20.glDeleteTextures(n, textures, offset);
-        checkError();
-    }
-
-    @Override
-    public void glDeleteBuffers(GL11 gl, int n, int[] buffers, int offset) {
-        GLES20.glDeleteBuffers(n, buffers, offset);
-        checkError();
-    }
-
-    @Override
-    public void glDeleteFramebuffers(GL11ExtensionPack gl11ep, int n, int[] buffers, int offset) {
-        GLES20.glDeleteFramebuffers(n, buffers, offset);
-        checkError();
-    }
 
     @Override
     public void enableStencil() {
@@ -1094,4 +1060,9 @@
         bounds.bottom = Math.round(mTempMatrix[MATRIX_SIZE + 5]);
         bounds.sort();
     }
+
+    @Override
+    public GLId getGLId() {
+        return mGLId;
+    }
 }
diff --git a/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java b/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java
new file mode 100644
index 0000000..6cd7149
--- /dev/null
+++ b/src/com/android/gallery3d/glrenderer/GLES20IdImpl.java
@@ -0,0 +1,42 @@
+package com.android.gallery3d.glrenderer;
+
+import android.opengl.GLES20;
+
+import javax.microedition.khronos.opengles.GL11;
+import javax.microedition.khronos.opengles.GL11ExtensionPack;
+
+public class GLES20IdImpl implements GLId {
+    private final int[] mTempIntArray = new int[1];
+
+    @Override
+    public int generateTexture() {
+        GLES20.glGenTextures(1, mTempIntArray, 0);
+        GLES20Canvas.checkError();
+        return mTempIntArray[0];
+    }
+
+    @Override
+    public void glGenBuffers(int n, int[] buffers, int offset) {
+        GLES20.glGenBuffers(n, buffers, offset);
+        GLES20Canvas.checkError();
+    }
+
+    @Override
+    public void glDeleteTextures(GL11 gl, int n, int[] textures, int offset) {
+        GLES20.glDeleteTextures(n, textures, offset);
+        GLES20Canvas.checkError();
+    }
+
+
+    @Override
+    public void glDeleteBuffers(GL11 gl, int n, int[] buffers, int offset) {
+        GLES20.glDeleteBuffers(n, buffers, offset);
+        GLES20Canvas.checkError();
+    }
+
+    @Override
+    public void glDeleteFramebuffers(GL11ExtensionPack gl11ep, int n, int[] buffers, int offset) {
+        GLES20.glDeleteFramebuffers(n, buffers, offset);
+        GLES20Canvas.checkError();
+    }
+}
diff --git a/src/com/android/gallery3d/glrenderer/RawTexture.java b/src/com/android/gallery3d/glrenderer/RawTexture.java
index 73f2c49..7453899 100644
--- a/src/com/android/gallery3d/glrenderer/RawTexture.java
+++ b/src/com/android/gallery3d/glrenderer/RawTexture.java
@@ -36,7 +36,7 @@
     }
 
     protected void prepare(GLCanvas canvas) {
-        GLId glId = GLCanvas.getGLId();
+        GLId glId = canvas.getGLId();
         mId = glId.generateTexture();
         canvas.initializeTextureSize(this, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE);
         canvas.setTextureParameters(this);
diff --git a/src/com/android/gallery3d/glrenderer/UploadedTexture.java b/src/com/android/gallery3d/glrenderer/UploadedTexture.java
index ee55736..f41a979 100644
--- a/src/com/android/gallery3d/glrenderer/UploadedTexture.java
+++ b/src/com/android/gallery3d/glrenderer/UploadedTexture.java
@@ -222,7 +222,7 @@
                 Assert.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
 
                 // Upload the bitmap to a new texture.
-                mId = GLCanvas.getGLId().generateTexture();
+                mId = canvas.getGLId().generateTexture();
                 canvas.setTextureParameters(this);
 
                 if (bWidth == texWidth && bHeight == texHeight) {
diff --git a/src/com/android/gallery3d/ui/GLRootView.java b/src/com/android/gallery3d/ui/GLRootView.java
index 755e107..775e4a5 100644
--- a/src/com/android/gallery3d/ui/GLRootView.java
+++ b/src/com/android/gallery3d/ui/GLRootView.java
@@ -35,6 +35,8 @@
 import com.android.gallery3d.common.Utils;
 import com.android.gallery3d.glrenderer.BasicTexture;
 import com.android.gallery3d.glrenderer.GLCanvas;
+import com.android.gallery3d.glrenderer.GLES11Canvas;
+import com.android.gallery3d.glrenderer.GLES20Canvas;
 import com.android.gallery3d.glrenderer.UploadedTexture;
 import com.android.gallery3d.util.GalleryUtils;
 import com.android.gallery3d.util.MotionEventHelper;
@@ -120,7 +122,7 @@
         super(context, attrs);
         mFlags |= FLAG_INITIALIZED;
         setBackgroundDrawable(null);
-        setEGLContextClientVersion(GLCanvas.getEGLContextClientVersion());
+        setEGLContextClientVersion(ApiHelper.HAS_GLES20_REQUIRED ? 2 : 1);
         setEGLConfigChooser(mEglConfigChooser);
         setRenderer(this);
         if (ApiHelper.USE_888_PIXEL_FORMAT) {
@@ -287,8 +289,7 @@
         mRenderLock.lock();
         try {
             mGL = gl;
-            mCanvas = GLCanvas.getInstance();
-            mCanvas.initialize(gl);
+            mCanvas = ApiHelper.HAS_GLES20_REQUIRED ? new GLES20Canvas() : new GLES11Canvas(gl);
             BasicTexture.invalidateAllTextures();
         } finally {
             mRenderLock.unlock();
diff --git a/src/com/android/gallery3d/ui/GalleryEGLConfigChooser.java b/src/com/android/gallery3d/ui/GalleryEGLConfigChooser.java
index 4cf3edb..f7673bc 100644
--- a/src/com/android/gallery3d/ui/GalleryEGLConfigChooser.java
+++ b/src/com/android/gallery3d/ui/GalleryEGLConfigChooser.java
@@ -18,7 +18,6 @@
 import android.opengl.GLSurfaceView.EGLConfigChooser;
 
 import com.android.gallery3d.common.ApiHelper;
-import com.android.gallery3d.glrenderer.GLCanvas;
 
 import javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGLConfig;
@@ -73,7 +72,7 @@
         int[] numConfig = new int[1];
 
         int configSpec[];
-        if (GLCanvas.getEGLContextClientVersion() == 2) {
+        if (ApiHelper.HAS_GLES20_REQUIRED) {
             configSpec = ApiHelper.USE_888_PIXEL_FORMAT ? mConfig2Spec888 : mConfig2Spec565;
         } else {
             configSpec = ApiHelper.USE_888_PIXEL_FORMAT ? mConfigSpec888 : mConfigSpec565;
diff --git a/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java b/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java
index ef8959c..18121e6 100644
--- a/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java
+++ b/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java
@@ -42,8 +42,8 @@
     public SurfaceTextureScreenNail() {
     }
 
-    public void acquireSurfaceTexture() {
-        mExtTexture = new ExtTexture(GL_TEXTURE_EXTERNAL_OES);
+    public void acquireSurfaceTexture(GLCanvas canvas) {
+        mExtTexture = new ExtTexture(canvas, GL_TEXTURE_EXTERNAL_OES);
         mExtTexture.setSize(mWidth, mHeight);
         mSurfaceTexture = new SurfaceTexture(mExtTexture.getId());
         setDefaultBufferSize(mSurfaceTexture, mWidth, mHeight);
diff --git a/tests/src/com/android/gallery3d/glrenderer/GLCanvasTest.java b/tests/src/com/android/gallery3d/glrenderer/GLCanvasTest.java
index c42f97d..b1e6d5b 100644
--- a/tests/src/com/android/gallery3d/glrenderer/GLCanvasTest.java
+++ b/tests/src/com/android/gallery3d/glrenderer/GLCanvasTest.java
@@ -19,10 +19,6 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
-import com.android.gallery3d.glrenderer.GLCanvas;
-import com.android.gallery3d.glrenderer.GLES11Canvas;
-import com.android.gallery3d.glrenderer.GLPaint;
-
 import junit.framework.TestCase;
 
 import java.util.Arrays;
@@ -43,8 +39,7 @@
     @SmallTest
     public void testSetSize() {
         GL11 glStub = new GLStub();
-        GLCanvas canvas = new GLES11Canvas();
-        canvas.initialize(glStub);
+        GLCanvas canvas = new GLES11Canvas(glStub);
         canvas.setSize(100, 200);
         canvas.setSize(1000, 100);
         try {
@@ -62,8 +57,7 @@
 
     private static class ClearBufferTest extends GLMock {
         void run() {
-            GLCanvas canvas = new GLES11Canvas();
-            canvas.initialize(this);
+            GLCanvas canvas = new GLES11Canvas(this);
             assertEquals(0, mGLClearCalled);
             canvas.clearBuffer();
             assertEquals(GL10.GL_COLOR_BUFFER_BIT, mGLClearMask);
@@ -85,8 +79,7 @@
                 0x7F010101, 0xFEFEFDFC, 0x017F8081, 0x027F8081, 0x2ADE4C4D
             };
 
-            GLCanvas canvas = new GLES11Canvas();
-            canvas.initialize(this);
+            GLCanvas canvas = new GLES11Canvas(this);
             canvas.setSize(400, 300);
             // Test one color to make sure blend function is set.
             assertEquals(0, mGLColorCalled);
@@ -114,8 +107,7 @@
     @SmallTest
     public void testSetGetMultiplyAlpha() {
         GL11 glStub = new GLStub();
-        GLCanvas canvas = new GLES11Canvas();
-        canvas.initialize(glStub);
+        GLCanvas canvas = new GLES11Canvas(glStub);
 
         canvas.setAlpha(1f);
         assertEquals(1f, canvas.getAlpha());
@@ -154,8 +146,7 @@
 
     private static class AlphaTest extends GLMock {
         void run() {
-            GLCanvas canvas = new GLES11Canvas();
-            canvas.initialize(this);
+            GLCanvas canvas = new GLES11Canvas(this);
             canvas.setSize(400, 300);
 
             assertEquals(0, mGLColorCalled);
@@ -197,8 +188,7 @@
         }
 
         void run() {
-            GLCanvas canvas = new GLES11Canvas();
-            canvas.initialize(this);
+            GLCanvas canvas = new GLES11Canvas(this);
             canvas.setSize(400, 300);
             canvas.drawLine(2, 7, 1, 8, newColorPaint(0) /* color */);
             assertTrue(mGLVertexArrayEnabled);
@@ -242,8 +232,7 @@
         }
 
         void run() {
-            GLCanvas canvas = new GLES11Canvas();
-            canvas.initialize(this);
+            GLCanvas canvas = new GLES11Canvas(this);
             canvas.setSize(400, 300);
             canvas.fillRect(2, 7, 1, 8, 0 /* color */);
             assertTrue(mGLVertexArrayEnabled);
@@ -305,8 +294,7 @@
         }
 
         void run() {
-            GLCanvas canvas = new GLES11Canvas();
-            canvas.initialize(this);
+            GLCanvas canvas = new GLES11Canvas(this);
             canvas.setSize(40, 50);
             int color = 0;
 
diff --git a/tests/src/com/android/gallery3d/glrenderer/TextureTest.java b/tests/src/com/android/gallery3d/glrenderer/TextureTest.java
index b13a333..956d894 100644
--- a/tests/src/com/android/gallery3d/glrenderer/TextureTest.java
+++ b/tests/src/com/android/gallery3d/glrenderer/TextureTest.java
@@ -69,8 +69,7 @@
     @SmallTest
     public void testBasicTexture() {
         GL11 glStub = new GLStub();
-        GLCanvas canvas = new GLES11Canvas();
-        canvas.initialize(glStub);
+        GLCanvas canvas = new GLES11Canvas(glStub);
         MyBasicTexture texture = new MyBasicTexture(canvas, 47);
 
         assertEquals(47, texture.getId());
@@ -90,8 +89,7 @@
         assertTrue(texture.isLoaded());
 
         // For a different GL, it's not loaded.
-        GLCanvas canvas2 = new GLES11Canvas();
-        canvas2.initialize(glStub);
+        GLCanvas canvas2 = new GLES11Canvas(glStub);
         assertFalse(texture.isLoaded());
 
         assertEquals(0, texture.mOnBindCalled);
@@ -145,8 +143,7 @@
     @SmallTest
     public void testUploadedTexture() {
         GL11 glStub = new GLStub();
-        GLCanvas canvas = new GLES11Canvas();
-        canvas.initialize(glStub);
+        GLCanvas canvas = new GLES11Canvas(glStub);
         MyUploadedTexture texture = new MyUploadedTexture();
 
         // draw it and the bitmap should be fetched.
diff --git a/tests/src/com/android/gallery3d/ui/GLCanvasStub.java b/tests/src/com/android/gallery3d/ui/GLCanvasStub.java
index d6bbc3d..da4c5c4 100644
--- a/tests/src/com/android/gallery3d/ui/GLCanvasStub.java
+++ b/tests/src/com/android/gallery3d/ui/GLCanvasStub.java
@@ -22,6 +22,7 @@
 
 import com.android.gallery3d.glrenderer.BasicTexture;
 import com.android.gallery3d.glrenderer.GLCanvas;
+import com.android.gallery3d.glrenderer.GLId;
 import com.android.gallery3d.glrenderer.GLPaint;
 import com.android.gallery3d.glrenderer.RawTexture;
 
@@ -30,7 +31,7 @@
 
 import javax.microedition.khronos.opengles.GL11;
 
-public class GLCanvasStub extends GLCanvas {
+public class GLCanvasStub implements GLCanvas {
     @Override
     public void setSize(int width, int height) {}
     @Override
@@ -165,12 +166,13 @@
     public void drawOnlyOutsideStencil(boolean onlyOutside) {
     }
     @Override
-    public void initialize(GL11 gl) {
-    }
-    @Override
     public void recoverFromLightCycle() {
     }
     @Override
     public void getBounds(Rect bounds, int x, int y, int width, int height) {
     }
+    @Override
+    public GLId getGLId() {
+        return null;
+    }
 }