Merge "Destroy layers and flush layers cache when a window is destroyed."
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index d561484..ac0abc3 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -277,14 +277,25 @@
     ///////////////////////////////////////////////////////////////////////////
 
     /**
+     * Must match Caches::FlushMode values
+     * 
      * @see #flushCaches(int) 
      */
-    public static final int FLUSH_CACHES_MODERATE = 0;
+    public static final int FLUSH_CACHES_LAYERS = 0;
+    
+    /**
+     * Must match Caches::FlushMode values
+     * 
+     * @see #flushCaches(int) 
+     */
+    public static final int FLUSH_CACHES_MODERATE = 1;
 
     /**
+     * Must match Caches::FlushMode values
+     * 
      * @see #flushCaches(int) 
      */
-    public static final int FLUSH_CACHES_FULL = 1;
+    public static final int FLUSH_CACHES_FULL = 2;
 
     /**
      * Flush caches to reclaim as much memory as possible. The amount of memory
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index 078222b..c987f48 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -38,7 +38,7 @@
 class GLES20RecordingCanvas extends GLES20Canvas implements Poolable<GLES20RecordingCanvas> {
     // The recording canvas pool should be large enough to handle a deeply nested
     // view hierarchy because display lists are generated recursively.
-    private static final int POOL_LIMIT = 50;
+    private static final int POOL_LIMIT = 25;
 
     private static final Pool<GLES20RecordingCanvas> sPool = Pools.synchronizedPool(
             Pools.finitePool(new PoolableManager<GLES20RecordingCanvas>() {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d2476af..5404e3a 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -140,6 +140,13 @@
     abstract void updateSurface(SurfaceHolder holder) throws Surface.OutOfResourcesException;
 
     /**
+     * Destoys the layers used by the specified view hierarchy.
+     * 
+     * @param view The root of the view hierarchy
+     */
+    abstract void destroyLayers(View view);
+
+    /**
      * This method should be invoked whenever the current hardware renderer
      * context should be reset. 
      */
@@ -622,18 +629,8 @@
                         + "from multiple threads");
             }
 
-            /*
-             *  The window size has changed, so we need to create a new
-             *  surface.
-             */
-            if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
-                /*
-                 * Unbind and destroy the old EGL surface, if
-                 * there is one.
-                 */
-                sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-                sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
-            }
+            // In case we need to destroy an existing surface
+            destroySurface();
 
             // Create an EGL surface we can render into.
             mEglSurface = sEgl.eglCreateWindowSurface(sEglDisplay, sEglConfig, holder, null);
@@ -693,15 +690,21 @@
 
             mDestroyed = true;
 
-            sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-            sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+            destroySurface();
 
-            mEglSurface = null;
             mGl = null;
 
             setEnabled(false);
         }
 
+        void destroySurface() {
+            if (mEglSurface != null && mEglSurface != EGL_NO_SURFACE) {
+                sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+                sEgl.eglDestroySurface(sEglDisplay, mEglSurface);
+                mEglSurface = null;
+            }
+        }
+
         @Override
         void invalidate() {
             // Cancels any existing buffer to ensure we'll get a buffer
@@ -921,6 +924,34 @@
             return ((GLES20TextureLayer) layer).getSurfaceTexture();
         }
 
+        @Override
+        void destroyLayers(View view) {
+            if (view != null && isEnabled()) {
+                checkCurrent();
+                destroyHardwareLayer(view);
+                GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
+            }
+        }
+
+        private void destroyHardwareLayer(View view) {
+            view.destroyLayer();
+            if (view instanceof ViewGroup) {
+                ViewGroup group = (ViewGroup) view;
+
+                int count = group.getChildCount();
+                for (int i = 0; i < count; i++) {
+                    destroyHardwareLayer(group.getChildAt(i));
+                }
+            }
+        }
+
+        static HardwareRenderer create(boolean translucent) {
+            if (GLES20Canvas.isAvailable()) {
+                return new Gl20Renderer(translucent);
+            }
+            return null;
+        }
+
         static void trimMemory(int level) {
             if (sEgl == null || sEglConfig == null) return;
 
@@ -950,12 +981,5 @@
                     break;
             }
         }
-
-        static HardwareRenderer create(boolean translucent) {
-            if (GLES20Canvas.isAvailable()) {
-                return new Gl20Renderer(translucent);
-            }
-            return null;
-        }
     }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8c41b9f..5dcb84f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9230,10 +9230,7 @@
 
         destroyDrawingCache();
 
-        if (mHardwareLayer != null) {
-            mHardwareLayer.destroy();
-            mHardwareLayer = null;
-        }
+        destroyLayer();
 
         if (mDisplayList != null) {
             mDisplayList.invalidate();
@@ -9605,21 +9602,10 @@
         // Destroy any previous software drawing cache if needed
         switch (mLayerType) {
             case LAYER_TYPE_HARDWARE:
-                if (mHardwareLayer != null) {
-                    mHardwareLayer.destroy();
-                    mHardwareLayer = null;
-                }
+                destroyLayer();
                 // fall through - unaccelerated views may use software layer mechanism instead
             case LAYER_TYPE_SOFTWARE:
-                if (mDrawingCache != null) {
-                    mDrawingCache.recycle();
-                    mDrawingCache = null;
-                }
-
-                if (mUnscaledDrawingCache != null) {
-                    mUnscaledDrawingCache.recycle();
-                    mUnscaledDrawingCache = null;
-                }
+                destroyDrawingCache();
                 break;
             default:
                 break;
@@ -9745,6 +9731,13 @@
         return mHardwareLayer;
     }
 
+    void destroyLayer() {
+        if (mHardwareLayer != null) {
+            mHardwareLayer.destroy();
+            mHardwareLayer = null;
+        }
+    }
+
     /**
      * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call
      * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 54e02a7..76e16a9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -541,6 +541,13 @@
         }
     }
 
+    private void destroyHardwareResources() {
+        if (mAttachInfo.mHardwareRenderer.isEnabled()) {
+            mAttachInfo.mHardwareRenderer.destroyLayers(mView);
+        }
+        mAttachInfo.mHardwareRenderer.destroy(false);
+    }
+
     private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
         mAttachInfo.mHardwareAccelerated = false;
         mAttachInfo.mHardwareAccelerationRequested = false;
@@ -872,7 +879,7 @@
             host.dispatchWindowVisibilityChanged(viewVisibility);
             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
                 if (mAttachInfo.mHardwareRenderer != null) {
-                    mAttachInfo.mHardwareRenderer.destroy(false);
+                    destroyHardwareResources();
                 }                
             }
             if (viewVisibility == View.GONE) {
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 7114b6a..c5858e9 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -173,13 +173,15 @@
             gradientCache.clear();
             // fall through
         case kFlushMode_Moderate:
-            layerCache.clear();
             pathCache.clear();
             roundRectShapeCache.clear();
             circleShapeCache.clear();
             ovalShapeCache.clear();
             rectShapeCache.clear();
             arcShapeCache.clear();
+            // fall through
+        case kFlushMode_Layers:
+            layerCache.clear();
             break;
     }
 }
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 76dff4b..cdcbf21 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -101,7 +101,8 @@
 
 public:
     enum FlushMode {
-        kFlushMode_Moderate = 0,
+        kFlushMode_Layers = 0,
+        kFlushMode_Moderate,
         kFlushMode_Full
     };
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 8157631..a3d346d 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -37,7 +37,7 @@
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
 
-#define MIN_WRITER_SIZE 16384
+#define MIN_WRITER_SIZE 4096
 
 // Debug
 #if DEBUG_DISPLAY_LIST