Cancel layer update when a layer is about to be destroyed
Bug #9310706

Change-Id: I73eea6314c326f15a979617e3a05b525935f0d3f
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 831b914..1f35c1d 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -163,6 +163,11 @@
     }
 
     @Override
+    void cancelLayerUpdate(HardwareLayer layer) {
+        nCancelLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer);
+    }
+
+    @Override
     void flushLayerUpdates() {
         nFlushLayerUpdates(mRenderer);
     }
@@ -191,6 +196,7 @@
     private static native void nClearLayerUpdates(int renderer);
     private static native void nFlushLayerUpdates(int renderer);
     private static native void nPushLayerUpdate(int renderer, int layer);
+    private static native void nCancelLayerUpdate(int renderer, int layer);
 
     ///////////////////////////////////////////////////////////////////////////
     // Canvas management
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 88b0986..259e1cd 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -202,6 +202,19 @@
     abstract void pushLayerUpdate(HardwareLayer layer);
 
     /**
+     * Cancels a queued layer update. If the specified layer was not
+     * queued for update, this method has no effect.
+     *
+     * @param layer The layer whose update to cancel
+     *
+     * @see #pushLayerUpdate(HardwareLayer)
+     * @see #clearLayerUpdates()
+     *
+     * @hide
+     */
+    abstract void cancelLayerUpdate(HardwareLayer layer);
+
+    /**
      * Immediately executes all enqueued layer updates.
      *
      * @see #pushLayerUpdate(HardwareLayer)
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 4bbf1a6..03428c7 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -451,10 +451,21 @@
      * @param layer The hardware layer that needs an update
      *
      * @see #flushLayerUpdates()
+     * @see #cancelLayerUpdate(HardwareLayer)
      */
     abstract void pushLayerUpdate(HardwareLayer layer);
 
     /**
+     * Cancels a queued layer update. If the specified layer was not
+     * queued for update, this method has no effect.
+     *
+     * @param layer The layer whose update to cancel
+     *
+     * @see #pushLayerUpdate(HardwareLayer)
+     */
+    abstract void cancelLayerUpdate(HardwareLayer layer);
+
+    /**
      * Forces all enqueued layer updates to be executed immediately.
      *
      * @see #pushLayerUpdate(HardwareLayer)
@@ -2133,6 +2144,11 @@
         }
 
         @Override
+        void cancelLayerUpdate(HardwareLayer layer) {
+            mGlCanvas.cancelLayerUpdate(layer);
+        }
+
+        @Override
         void flushLayerUpdates() {
             mGlCanvas.flushLayerUpdates();
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c246cd4..525b58f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12709,6 +12709,8 @@
             if (info != null && info.mHardwareRenderer != null &&
                     info.mHardwareRenderer.isEnabled() &&
                     (valid || info.mHardwareRenderer.validate())) {
+
+                info.mHardwareRenderer.cancelLayerUpdate(mHardwareLayer);
                 mHardwareLayer.destroy();
                 mHardwareLayer = null;
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index f3592a3..a2f7dbe 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -911,6 +911,11 @@
     renderer->pushLayerUpdate(layer);
 }
 
+static void android_view_GLES20Canvas_cancelLayerUpdate(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer, Layer* layer) {
+    renderer->cancelLayerUpdate(layer);
+}
+
 static void android_view_GLES20Canvas_clearLayerUpdates(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer) {
     renderer->clearLayerUpdates();
@@ -1095,6 +1100,7 @@
     { "nClearLayerUpdates",      "(I)V",       (void*) android_view_GLES20Canvas_clearLayerUpdates },
     { "nFlushLayerUpdates",      "(I)V",       (void*) android_view_GLES20Canvas_flushLayerUpdates },
     { "nPushLayerUpdate",        "(II)V",      (void*) android_view_GLES20Canvas_pushLayerUpdate },
+    { "nCancelLayerUpdate",      "(II)V",      (void*) android_view_GLES20Canvas_cancelLayerUpdate },
 
     { "nSetTextureLayerTransform", "(II)V",    (void*) android_view_GLES20Canvas_setTextureLayerTransform },
 
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 7c22bbb..f409d3e 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -213,6 +213,16 @@
     deferredUpdateScheduled = false;
 }
 
+void Layer::cancelDefer() {
+    renderer = NULL;
+    displayList = NULL;
+    deferredUpdateScheduled = false;
+    if (deferredList) {
+        delete deferredList;
+        deferredList = NULL;
+    }
+}
+
 void Layer::flush() {
     if (deferredList) {
         renderer->setViewport(layer.getWidth(), layer.getHeight());
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 326b25a..ebd5543 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -245,6 +245,7 @@
     }
 
     void defer();
+    void cancelDefer();
     void flush();
     void render();
 
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index a0709af..6be0146 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -155,9 +155,7 @@
                     victim->layer.getHeight());
         }
 
-        layer->deferredUpdateScheduled = false;
-        layer->renderer = NULL;
-        layer->displayList = NULL;
+        layer->cancelDefer();
 
         LayerEntry entry(layer);
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 05f43a9..a704b3d 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -655,6 +655,18 @@
     }
 }
 
+void OpenGLRenderer::cancelLayerUpdate(Layer* layer) {
+    if (layer) {
+        for (int i = mLayerUpdates.size() - 1; i >= 0; i--) {
+            if (mLayerUpdates.itemAt(i) == layer) {
+                mLayerUpdates.removeAt(i);
+                mCaches.resourceCache.decrementRefcount(layer);
+                break;
+            }
+        }
+    }
+}
+
 void OpenGLRenderer::clearLayerUpdates() {
     size_t count = mLayerUpdates.size();
     if (count > 0) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 5b7f90d..18d39ef 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -217,6 +217,7 @@
     virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
 
     ANDROID_API void pushLayerUpdate(Layer* layer);
+    ANDROID_API void cancelLayerUpdate(Layer* layer);
     ANDROID_API void clearLayerUpdates();
     ANDROID_API void flushLayerUpdates();