Redesign  the free texture function.

Change-Id: I1216560b1a4dfbf559423b11ab390d3539997dd5
diff --git a/new3d/src/com/android/gallery3d/app/ViewImage.java b/new3d/src/com/android/gallery3d/app/ViewImage.java
index e77ab06..196f3ba 100644
--- a/new3d/src/com/android/gallery3d/app/ViewImage.java
+++ b/new3d/src/com/android/gallery3d/app/ViewImage.java
@@ -47,7 +47,9 @@
     @Override
     protected void onPause() {
         super.onPause();
-        mImageViewer.releaseTiles();
+        synchronized (mGLRootView) {
+            mImageViewer.close();
+        }
         mGLRootView.onPause();
     }
 
diff --git a/new3d/src/com/android/gallery3d/ui/GLCanvas.java b/new3d/src/com/android/gallery3d/ui/GLCanvas.java
index 677bf94..9ca64b0 100644
--- a/new3d/src/com/android/gallery3d/ui/GLCanvas.java
+++ b/new3d/src/com/android/gallery3d/ui/GLCanvas.java
@@ -3,8 +3,6 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 
-import java.util.Collection;
-
 import javax.microedition.khronos.opengles.GL11;
 
 //
@@ -101,9 +99,6 @@
     // Return a texture copied from the specified rectangle.
     public BasicTexture copyTexture(int x, int y, int width, int height);
 
-    // TODO: Remove this or document it.
-    public void releaseTextures(Collection<? extends BasicTexture> c);
-
     // Gets the underlying GL instance. This is used only when direct access to
     // GL is needed.
     public GL11 getGLInstance();
@@ -111,4 +106,13 @@
     // Binds the texture to the canvas for the following drawing calls. This
     // function should only be called in Texture.
     public void bindTexture(int id);
+
+    // 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.
+    public boolean unloadTexture(BasicTexture texture);
+
+    // Delete the textures in GL side. This function should only be called in
+    // GL thread.
+    public void deleteRecycledTextures();
 }
diff --git a/new3d/src/com/android/gallery3d/ui/GLCanvasImp.java b/new3d/src/com/android/gallery3d/ui/GLCanvasImp.java
index 1b516e9..1c6e35d 100644
--- a/new3d/src/com/android/gallery3d/ui/GLCanvasImp.java
+++ b/new3d/src/com/android/gallery3d/ui/GLCanvasImp.java
@@ -9,7 +9,6 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
-import java.util.Collection;
 import java.util.Stack;
 
 import javax.microedition.khronos.opengles.GL10;
@@ -29,6 +28,7 @@
 
     private final GL11 mGL;
 
+    private final int mTextureId[] = new int[1];
     private final float mMatrixValues[] = new float[16];
 
     private final float mUvBuffer[] = new float[VERTEX_BUFFER_SIZE];
@@ -59,6 +59,7 @@
     private RectF mDrawTextureSourceRect = new RectF();
     private Rect mDrawTextureTargetRect = new Rect();
     private float[] mTempMatrix = new float[32];
+    private final IntArray mUnboundIds = new IntArray();
 
     GLCanvasImp(GL11 gl) {
         mGL = gl;
@@ -759,13 +760,19 @@
         mUvPointer.put(buffer, 0, 8).position(0);
     }
 
-    public void releaseTextures(Collection<? extends BasicTexture> c) {
-        IntArray array = new IntArray();
-        for (BasicTexture t : c) {
-            if (t.isLoaded(this)) array.add(t.mId);
-        }
-        if (array.size() > 0) {
-            mGL.glDeleteTextures(array.size(), array.toArray(null), 0);
+    public boolean unloadTexture(BasicTexture t) {
+        if (!t.isLoaded(this)) return false;
+        mUnboundIds.add(t.mId);
+        t.mGL = null;
+        t.mState = BasicTexture.STATE_UNLOADED;
+        return true;
+    }
+
+    public void deleteRecycledTextures() {
+        IntArray ids = mUnboundIds;
+        if (ids.size() > 0) {
+            mGL.glDeleteTextures(ids.size(), ids.getInternelArray(), 0);
+            ids.clear();
         }
     }
 
diff --git a/new3d/src/com/android/gallery3d/ui/GLRootView.java b/new3d/src/com/android/gallery3d/ui/GLRootView.java
index a14f441..e387f30 100644
--- a/new3d/src/com/android/gallery3d/ui/GLRootView.java
+++ b/new3d/src/com/android/gallery3d/ui/GLRootView.java
@@ -54,7 +54,7 @@
     private static final int FLAG_NEED_LAYOUT = 2;
 
     private GL11 mGL;
-    private GLCanvas mCanvas;
+    private GLCanvasImp mCanvas;
 
     private GLView mContentView;
     private DisplayMetrics mDisplayMetrics;
@@ -203,6 +203,9 @@
             ++mFrameCount;
         }
 
+        // release the unbound textures
+        mCanvas.deleteRecycledTextures();
+
         mRenderRequested = false;
 
         if ((mFlags & FLAG_NEED_LAYOUT) != 0) layoutContentPane();
diff --git a/new3d/src/com/android/gallery3d/ui/GridSlotAdapter.java b/new3d/src/com/android/gallery3d/ui/GridSlotAdapter.java
index 110509c..c2c9079 100644
--- a/new3d/src/com/android/gallery3d/ui/GridSlotAdapter.java
+++ b/new3d/src/com/android/gallery3d/ui/GridSlotAdapter.java
@@ -93,17 +93,14 @@
             mSlotIndex = slotIndex;
         }
 
-        @Override
         public void onImageCanceled(MediaItem abstractMediaItem, int type) {
             // Do nothing
         }
 
-        @Override
         public void onImageError(MediaItem item, int type, Throwable error) {
             // Do nothing
         }
 
-        @Override
         public void onImageReady(MediaItem item, int type, Bitmap bitmap) {
             MyDisplayItem displayItem = mItemMap.get(mSlotIndex);
             displayItem.updateContent(new BitmapTexture(bitmap));
diff --git a/new3d/src/com/android/gallery3d/ui/ImageViewer.java b/new3d/src/com/android/gallery3d/ui/ImageViewer.java
index 5a063cd..39a739a 100644
--- a/new3d/src/com/android/gallery3d/ui/ImageViewer.java
+++ b/new3d/src/com/android/gallery3d/ui/ImageViewer.java
@@ -11,13 +11,9 @@
 import android.view.MotionEvent;
 import android.view.ScaleGestureDetector;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
 
 public class ImageViewer extends GLView {
     private static final String TAG = "ImageViewer";
@@ -191,39 +187,20 @@
         invalidate();
     }
 
-    public void releaseTiles() {
-        GLRootView root = getGLRootView();
-        FutureTask<Void> task = new FutureTask<Void>(new ReleaseTiles());
-        synchronized (root) {
-            root.queueEvent(task);
-            try {
-                task.get();
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-            } catch (ExecutionException e) {
-                Log.e(TAG, "release tiles fail", e);
-            }
+    public void close() {
+        GLCanvas canvas = getGLRootView().getCanvas();
+        for (TileTexture texture : mActiveTiles.values()) {
+            canvas.unloadTexture(texture);
+            texture.recycle();
         }
-    }
-
-    private class ReleaseTiles implements Callable<Void> {
-        public Void call() throws Exception {
-            ArrayList<TileTexture> tiles = new ArrayList<TileTexture>();
-            tiles.addAll(mActiveTiles.values());
-            mActiveTiles.clear();
-
-            TileTexture tile = mRecycledHead;
-            while (tile != null) {
-                tiles.add(tile);
-                tile = tile.mNextFree;
-            }
-            mRecycledHead = null;
-            GLRootView root = getGLRootView();
-            if (root != null) {
-                root.getCanvas().releaseTextures(tiles);
-            }
-            return null;
+        mActiveTiles.clear();
+        TileTexture tile = mRecycledHead;
+        while (tile != null) {
+            canvas.unloadTexture(tile);
+            tile.recycle();
+            tile = tile.mNextFree;
         }
+        mRecycledHead = null;
     }
 
     @Override
diff --git a/new3d/src/com/android/gallery3d/ui/IntArray.java b/new3d/src/com/android/gallery3d/ui/IntArray.java
index f9e2dfc..2b5a985 100644
--- a/new3d/src/com/android/gallery3d/ui/IntArray.java
+++ b/new3d/src/com/android/gallery3d/ui/IntArray.java
@@ -26,4 +26,13 @@
         System.arraycopy(mData, 0, result, 0, mSize);
         return result;
     }
+
+    public int[] getInternelArray() {
+        return mData;
+    }
+
+    public void clear() {
+        mSize = 0;
+        if (mData.length != INIT_CAPACITY) mData = new int[INIT_CAPACITY];
+    }
 }
diff --git a/new3d/src/com/android/gallery3d/ui/MediaSetSlotAdapter.java b/new3d/src/com/android/gallery3d/ui/MediaSetSlotAdapter.java
index a19abf3..067954d 100644
--- a/new3d/src/com/android/gallery3d/ui/MediaSetSlotAdapter.java
+++ b/new3d/src/com/android/gallery3d/ui/MediaSetSlotAdapter.java
@@ -136,17 +136,14 @@
             mItemIndex = itemIndex;
         }
 
-        @Override
         public void onImageCanceled(MediaItem abstractMediaItem, int type) {
             // Do nothing
         }
 
-        @Override
         public void onImageError(MediaItem item, int type, Throwable error) {
             // Do nothing
         }
 
-        @Override
         public void onImageReady(MediaItem item, int type, Bitmap bitmap) {
             MyDisplayItem[] items = mItemsetMap.get(mSlotIndex);
             items[mItemIndex].updateContent(new BitmapTexture(bitmap));