Better implementation to clear display lists

Change-Id: I58f9af4bae70a8117db1455a50c0c5daf19b2f4a
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 06927a7..1dabad2 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -28,13 +28,6 @@
  * @hide 
  */
 public abstract class DisplayList {
-    private final Runnable mInvalidate = new Runnable() {
-        @Override
-        public void run() {
-            invalidate();
-        }
-    };
-
     /**
      * Flag used when calling
      * {@link HardwareCanvas#drawDisplayList(DisplayList, int, int, android.graphics.Rect, int)}.
@@ -66,13 +59,6 @@
     public abstract void invalidate();
 
     /**
-     * Posts a call to {@link #invalidate()} in the specified handler.
-     */
-    final void postInvalidate(Handler handler) {
-        handler.post(mInvalidate);
-    }
-
-    /**
      * Returns whether the display list is currently usable. If this returns false,
      * the display list should be re-recorded prior to replaying it.
      *
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 82bdd00..cb73856 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9974,12 +9974,16 @@
 
         destroyLayer();
 
-        if (mDisplayList != null) {
-            mDisplayList.postInvalidate(mAttachInfo.mHandler);
-        }
-
         if (mAttachInfo != null) {
+            if (mDisplayList != null) {
+                mAttachInfo.mViewRootImpl.invalidateDisplayList(mDisplayList);
+            }
             mAttachInfo.mViewRootImpl.cancelInvalidate(this);
+        } else {
+            if (mDisplayList != null) {
+                // Should never happen
+                mDisplayList.invalidate();
+            }
         }
 
         mCurrentAnimation = null;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4472f8c..04ad649 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -117,6 +117,8 @@
     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
     private static final boolean DEBUG_FPS = false;
 
+    private static final boolean USE_RENDER_THREAD = false;
+    
     /**
      * Set this system property to true to force the view hierarchy to render
      * at 60 Hz. This can be used to measure the potential framerate.
@@ -300,6 +302,8 @@
     private long mFpsPrevTime = -1;
     private int mFpsNumFrames;
 
+    private final ArrayList<DisplayList> mDisplayLists = new ArrayList<DisplayList>(24);
+    
     /**
      * see {@link #playSoundEffect(int)}
      */
@@ -402,23 +406,27 @@
      *         false otherwise
      */
     private static boolean isRenderThreadRequested(Context context) {
-        synchronized (sRenderThreadQueryLock) {
-            if (!sRenderThreadQueried) {
-                final PackageManager packageManager = context.getPackageManager();
-                final String packageName = context.getApplicationInfo().packageName;
-                try {
-                    ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
-                            PackageManager.GET_META_DATA);
-                    if (applicationInfo.metaData != null) {
-                        sUseRenderThread = applicationInfo.metaData.getBoolean(
-                                "android.graphics.renderThread", false);
+        if (USE_RENDER_THREAD) {
+            synchronized (sRenderThreadQueryLock) {
+                if (!sRenderThreadQueried) {
+                    final PackageManager packageManager = context.getPackageManager();
+                    final String packageName = context.getApplicationInfo().packageName;
+                    try {
+                        ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
+                                PackageManager.GET_META_DATA);
+                        if (applicationInfo.metaData != null) {
+                            sUseRenderThread = applicationInfo.metaData.getBoolean(
+                                    "android.graphics.renderThread", false);
+                        }
+                    } catch (PackageManager.NameNotFoundException e) {
+                    } finally {
+                        sRenderThreadQueried = true;
                     }
-                } catch (PackageManager.NameNotFoundException e) {
-                } finally {
-                    sRenderThreadQueried = true;
                 }
+                return sUseRenderThread;
             }
-            return sUseRenderThread;
+        } else {
+            return false;
         }
     }
 
@@ -690,7 +698,7 @@
                     return;
                 }
 
-                boolean renderThread = isRenderThreadRequested(context);
+                final boolean renderThread = isRenderThreadRequested(context);
                 if (renderThread) {
                     Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated");
                 }
@@ -2210,6 +2218,17 @@
         }
     }
 
+    void invalidateDisplayLists() {
+        final ArrayList<DisplayList> displayLists = mDisplayLists;
+        final int count = displayLists.size();
+
+        for (int i = 0; i < count; i++) {
+            displayLists.get(i).invalidate();
+        }
+
+        displayLists.clear();
+    }
+
     boolean scrollToRectOrFocus(Rect rectangle, boolean immediate) {
         final View.AttachInfo attachInfo = mAttachInfo;
         final Rect ci = attachInfo.mContentInsets;
@@ -2516,6 +2535,7 @@
     private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 22;
     private final static int MSG_PROCESS_INPUT_EVENTS = 23;
     private final static int MSG_DISPATCH_SCREEN_STATE = 24;
+    private final static int MSG_INVALIDATE_DISPLAY_LIST = 25;
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -2567,6 +2587,10 @@
                     return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT";
                 case MSG_PROCESS_INPUT_EVENTS:
                     return "MSG_PROCESS_INPUT_EVENTS";
+                case MSG_DISPATCH_SCREEN_STATE:
+                    return "MSG_DISPATCH_SCREEN_STATE";
+                case MSG_INVALIDATE_DISPLAY_LIST:
+                    return "MSG_INVALIDATE_DISPLAY_LIST";
             }
             return super.getMessageName(message);
         }
@@ -2777,9 +2801,13 @@
                     handleScreenStateChange(msg.arg1 == 1);
                 }
             } break;
+            case MSG_INVALIDATE_DISPLAY_LIST: {
+                invalidateDisplayLists();
+            } break;
             }
         }
     }
+
     final ViewRootHandler mHandler = new ViewRootHandler();
 
     /**
@@ -4136,6 +4164,14 @@
         mInvalidateOnAnimationRunnable.addViewRect(info);
     }
 
+    public void invalidateDisplayList(DisplayList displayList) {
+        mDisplayLists.add(displayList);
+
+        mHandler.removeMessages(MSG_INVALIDATE_DISPLAY_LIST);
+        Message msg = mHandler.obtainMessage(MSG_INVALIDATE_DISPLAY_LIST);
+        mHandler.sendMessage(msg);
+    }
+    
     public void cancelInvalidate(View view) {
         mHandler.removeMessages(MSG_INVALIDATE, view);
         // fixme: might leak the AttachInfo.InvalidateInfo objects instead of returning