Add display lists caching.

Change-Id: Iac3a248a81ed8cb076a83ef9d186b8ebba685b4c
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 96066b7..3b10437 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1250,12 +1250,12 @@
      */
     private static final int[][] VIEW_STATE_SETS;
 
-    static final int VIEW_STATE_WINDOW_FOCUSED = 1<<0;
-    static final int VIEW_STATE_SELECTED = 1<<1;
-    static final int VIEW_STATE_FOCUSED = 1<<2;
-    static final int VIEW_STATE_ENABLED = 1<<3;
-    static final int VIEW_STATE_PRESSED = 1<<4;
-    static final int VIEW_STATE_ACTIVATED = 1<<5;
+    static final int VIEW_STATE_WINDOW_FOCUSED = 1;
+    static final int VIEW_STATE_SELECTED = 1 << 1;
+    static final int VIEW_STATE_FOCUSED = 1 << 2;
+    static final int VIEW_STATE_ENABLED = 1 << 3;
+    static final int VIEW_STATE_PRESSED = 1 << 4;
+    static final int VIEW_STATE_ACTIVATED = 1 << 5;
 
     static final int[] VIEW_STATE_IDS = new int[] {
         R.attr.state_window_focused,    VIEW_STATE_WINDOW_FOCUSED,
@@ -1268,28 +1268,23 @@
 
     static {
         int[] orderedIds = new int[VIEW_STATE_IDS.length];
-        for (int i=0; i<R.styleable.ViewDrawableStates.length; i++) {
+        for (int i = 0; i < R.styleable.ViewDrawableStates.length; i++) {
             int viewState = R.styleable.ViewDrawableStates[i];
-            for (int j=0; j<VIEW_STATE_IDS.length; j+=2) {
+            for (int j = 0; j<VIEW_STATE_IDS.length; j += 2) {
                 if (VIEW_STATE_IDS[j] == viewState) {
-                    orderedIds[i*2] = viewState;
-                    orderedIds[i*2+1] = VIEW_STATE_IDS[j+1];
+                    orderedIds[i * 2] = viewState;
+                    orderedIds[i * 2 + 1] = VIEW_STATE_IDS[j + 1];
                 }
             }
         }
-        final int NUM_BITS = VIEW_STATE_IDS.length/2;
-        VIEW_STATE_SETS = new int[1<<NUM_BITS][];
-        for (int i=0; i<VIEW_STATE_SETS.length; i++) {
+        final int NUM_BITS = VIEW_STATE_IDS.length / 2;
+        VIEW_STATE_SETS = new int[1 << NUM_BITS][];
+        for (int i = 0; i < VIEW_STATE_SETS.length; i++) {
             int numBits = Integer.bitCount(i);
             int[] set = new int[numBits];
             int pos = 0;
-            for (int j=0; j<orderedIds.length; j+=2) {
-                if ((i&orderedIds[j+1]) != 0) {
-                    if (false) {
-                        Log.i("View", "Index #" + i + " @ ordered #" + j
-                                + " resid=0x" + Integer.toHexString(orderedIds[j])
-                                + " mask " + orderedIds[j+1]);
-                    }
+            for (int j = 0; j < orderedIds.length; j += 2) {
+                if ((i & orderedIds[j+1]) != 0) {
                     set[pos++] = orderedIds[j];
                 }
             }
@@ -1958,6 +1953,7 @@
 
     private Bitmap mDrawingCache;
     private Bitmap mUnscaledDrawingCache;
+    private DisplayList mDisplayList;
 
     /**
      * When this view has focus and the next focus is {@link #FOCUS_LEFT},
@@ -7317,6 +7313,64 @@
     }
 
     /**
+     * <p>Returns a display list that can be used to draw this view again
+     * without executing its draw method.</p>
+     * 
+     * @return A DisplayList ready to replay, or null if caching is not enabled.
+     */
+    DisplayList getDisplayList() {
+        if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) {
+            return null;
+        }
+        
+        if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
+            return null;
+        }
+
+        if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED &&
+                ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mDisplayList == null)) {
+
+            if (mDisplayList != null) {
+                mDisplayList.destroy();
+            }
+
+            mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList();
+
+            final HardwareCanvas canvas = mDisplayList.start();
+            try {
+                int width = mRight - mLeft;
+                int height = mBottom - mTop;
+
+                canvas.setViewport(width, height);
+                canvas.onPreDraw();
+
+                final int restoreCount = canvas.save();
+
+                mPrivateFlags |= DRAWN;
+                mPrivateFlags |= DRAWING_CACHE_VALID;
+    
+                // Fast path for layouts with no backgrounds
+                if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+                    mPrivateFlags &= ~DIRTY_MASK;
+                    dispatchDraw(canvas);
+                } else {
+                    draw(canvas);
+                }
+    
+                canvas.restoreToCount(restoreCount);
+            } finally {
+                canvas.onPostDraw();
+
+                mDisplayList.end();
+
+                canvas.destroy();                
+            }
+        }
+
+        return mDisplayList;
+    }
+
+    /**
      * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>
      * 
      * @return A non-scaled bitmap representing this view or null if cache is disabled.
@@ -7383,6 +7437,10 @@
             mUnscaledDrawingCache.recycle();
             mUnscaledDrawingCache = null;
         }
+        if (mDisplayList != null) {
+            mDisplayList.destroy();
+            mDisplayList = null;
+        }
     }
 
     /**
@@ -10167,7 +10225,8 @@
         IBinder mPanelParentWindowToken;
         Surface mSurface;
 
-        boolean mHardwareAccelerated;        
+        boolean mHardwareAccelerated;
+        HardwareRenderer mHardwareRenderer;
         
         /**
          * Scale factor used by the compatibility mode