Add ability for hierarchyviewer to output displaylist info

Clicking on a node in hierarchyviewer1 and hierarchyviewer2 and then
clicking the new "Dump DisplayList" button will cause the display
list for the selected node (including its children) to be output into
logcat.

Change-Id: Id32f62569ad1ab4d533bc62987f3a7390c1bb4e6
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 984102a..2b79a76 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -261,6 +261,13 @@
     private static native boolean nDrawDisplayList(int renderer, int displayList,
             int width, int height, Rect dirty);
 
+    @Override
+    void outputDisplayList(DisplayList displayList) {
+        nOutputDisplayList(mRenderer, ((GLES20DisplayList) displayList).mNativeDisplayList);
+    }
+
+    private static native void nOutputDisplayList(int renderer, int displayList);
+
     ///////////////////////////////////////////////////////////////////////////
     // Hardware layer
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index caa7b74..23b3abc 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -64,6 +64,14 @@
     abstract boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty);
 
     /**
+     * Outputs the specified display list to the log. This method exists for use by
+     * tools to output display lists for selected nodes to the log.
+     *
+     * @param displayList The display list to be logged.
+     */
+    abstract void outputDisplayList(DisplayList displayList);
+
+    /**
      * Draws the specified layer onto this canvas.
      *
      * @param layer The layer to composite on this canvas
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 881cb76..3b351b1 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -375,6 +375,7 @@
     private static final String REMOTE_COMMAND_REQUEST_LAYOUT = "REQUEST_LAYOUT";
     private static final String REMOTE_PROFILE = "PROFILE";
     private static final String REMOTE_COMMAND_CAPTURE_LAYERS = "CAPTURE_LAYERS";
+    private static final String REMOTE_COMMAND_OUTPUT_DISPLAYLIST = "OUTPUT_DISPLAYLIST";
 
     private static HashMap<Class<?>, Field[]> sFieldsForClasses;
     private static HashMap<Class<?>, Method[]> sMethodsForClasses;
@@ -885,6 +886,8 @@
             final String[] params = parameters.split(" ");
             if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) {
                 capture(view, clientStream, params[0]);
+            } else if (REMOTE_COMMAND_OUTPUT_DISPLAYLIST.equalsIgnoreCase(command)) {
+                outputDisplayList(view, params[0]);
             } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) {
                 invalidate(view, params[0]);
             } else if (REMOTE_COMMAND_REQUEST_LAYOUT.equalsIgnoreCase(command)) {
@@ -1156,6 +1159,11 @@
         }
     }
 
+    private static void outputDisplayList(View root, String parameter) throws IOException {
+        final View view = findView(root, parameter);
+        view.getViewRoot().outputDisplayList(view);
+    }
+
     private static void capture(View root, final OutputStream clientStream, String parameter)
             throws IOException {
 
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index f02daba..e662b9e 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -1507,6 +1507,20 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    void outputDisplayList(View view) {
+        if (mAttachInfo != null && mAttachInfo.mHardwareCanvas != null) {
+
+            HardwareCanvas canvas = (HardwareCanvas) mAttachInfo.mHardwareCanvas;
+            DisplayList displayList = view.getDisplayList();
+            if (displayList != null) {
+                canvas.outputDisplayList(displayList);
+            }
+        }
+    }
+
     private void draw(boolean fullRedrawNeeded) {
         Surface surface = mSurface;
         if (surface == null || !surface.isValid()) {
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index f929a0e..d43a27f 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -519,6 +519,11 @@
     return redraw;
 }
 
+static void android_view_GLES20Canvas_outputDisplayList(JNIEnv* env,
+        jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList) {
+    renderer->outputDisplayList(displayList);
+}
+
 // ----------------------------------------------------------------------------
 // Layers
 // ----------------------------------------------------------------------------
@@ -714,7 +719,7 @@
     { "nGetDisplayListRenderer", "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListRenderer },
     { "nDrawDisplayList",        "(IIIILandroid/graphics/Rect;)Z",
                                                (void*) android_view_GLES20Canvas_drawDisplayList },
-
+    { "nOutputDisplayList",      "(II)V",      (void*) android_view_GLES20Canvas_outputDisplayList },
     { "nInterrupt",              "(I)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(I)V",       (void*) android_view_GLES20Canvas_resume },
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 34dda9a..f8582d8 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -177,6 +177,331 @@
 void DisplayList::init() {
 }
 
+/**
+ * This function is a simplified version of replay(), where we simply retrieve and log the
+ * display list. This function should remain in sync with the replay() function.
+ */
+void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) {
+    TextContainer text;
+
+    uint32_t count = (level + 1) * 2;
+    char indent[count + 1];
+    for (uint32_t i = 0; i < count; i++) {
+        indent[i] = ' ';
+    }
+    indent[count] = '\0';
+    LOGD("%sStart display list (%p)", (char*) indent + 2, this);
+
+    int saveCount = renderer.getSaveCount() - 1;
+
+    mReader.rewind();
+
+    while (!mReader.eof()) {
+        int op = mReader.readInt();
+
+        switch (op) {
+            case DrawGLFunction: {
+                Functor *functor = (Functor *) getInt();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
+            }
+            break;
+            case Save: {
+                int rendererNum = getInt();
+                LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
+            }
+            break;
+            case Restore: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case RestoreToCount: {
+                int restoreCount = saveCount + getInt();
+                LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
+            }
+            break;
+            case SaveLayer: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                SkPaint* paint = getPaint();
+                int flags = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
+                    OP_NAMES[op], f1, f2, f3, f4, paint, flags);
+            }
+            break;
+            case SaveLayerAlpha: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                int alpha = getInt();
+                int flags = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
+                    OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
+            }
+            break;
+            case Translate: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], f1, f2);
+            }
+            break;
+            case Rotate: {
+                float rotation = getFloat();
+                LOGD("%s%s %.2f", (char*) indent, OP_NAMES[op], rotation);
+            }
+            break;
+            case Scale: {
+                float sx = getFloat();
+                float sy = getFloat();
+                LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
+            }
+            break;
+            case Skew: {
+                float sx = getFloat();
+                float sy = getFloat();
+                LOGD("%s%s %.2f, %.2f", (char*) indent, OP_NAMES[op], sx, sy);
+            }
+            break;
+            case SetMatrix: {
+                SkMatrix* matrix = getMatrix();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+            }
+            break;
+            case ConcatMatrix: {
+                SkMatrix* matrix = getMatrix();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], matrix);
+            }
+            break;
+            case ClipRect: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                int regionOp = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
+                    f1, f2, f3, f4, regionOp);
+            }
+            break;
+            case DrawDisplayList: {
+                DisplayList* displayList = getDisplayList();
+                uint32_t width = getUInt();
+                uint32_t height = getUInt();
+                LOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
+                    displayList, width, height, level + 1);
+                renderer.outputDisplayList(displayList, level + 1);
+            }
+            break;
+            case DrawLayer: {
+                Layer* layer = (Layer*) getInt();
+                float x = getFloat();
+                float y = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    layer, x, y, paint);
+            }
+            break;
+            case DrawBitmap: {
+                SkBitmap* bitmap = getBitmap();
+                float x = getFloat();
+                float y = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    bitmap, x, y, paint);
+            }
+            break;
+            case DrawBitmapMatrix: {
+                SkBitmap* bitmap = getBitmap();
+                SkMatrix* matrix = getMatrix();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
+                    bitmap, matrix, paint);
+            }
+            break;
+            case DrawBitmapRect: {
+                SkBitmap* bitmap = getBitmap();
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                float f5 = getFloat();
+                float f6 = getFloat();
+                float f7 = getFloat();
+                float f8 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
+            }
+            break;
+            case DrawBitmapMesh: {
+                int verticesCount = 0;
+                uint32_t colorsCount = 0;
+                SkBitmap* bitmap = getBitmap();
+                uint32_t meshWidth = getInt();
+                uint32_t meshHeight = getInt();
+                float* vertices = getFloats(verticesCount);
+                bool hasColors = getInt();
+                int* colors = hasColors ? getInts(colorsCount) : NULL;
+                SkPaint* paint = getPaint();
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case DrawPatch: {
+                int32_t* xDivs = NULL;
+                int32_t* yDivs = NULL;
+                uint32_t* colors = NULL;
+                uint32_t xDivsCount = 0;
+                uint32_t yDivsCount = 0;
+                int8_t numColors = 0;
+                SkBitmap* bitmap = getBitmap();
+                xDivs = getInts(xDivsCount);
+                yDivs = getInts(yDivsCount);
+                colors = getUInts(numColors);
+                DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+                getFloat();
+                getFloat();
+                getFloat();
+                getFloat();
+                getPaint();
+            }
+            break;
+            case DrawColor: {
+                int color = getInt();
+                int xferMode = getInt();
+                LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
+            }
+            break;
+            case DrawRect: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    f1, f2, f3, f4, paint);
+            }
+            break;
+            case DrawRoundRect: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                float f5 = getFloat();
+                float f6 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
+            }
+            break;
+            case DrawCircle: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, paint);
+            }
+            break;
+            case DrawOval: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
+            }
+            break;
+            case DrawArc: {
+                float f1 = getFloat();
+                float f2 = getFloat();
+                float f3 = getFloat();
+                float f4 = getFloat();
+                float f5 = getFloat();
+                float f6 = getFloat();
+                int i1 = getInt();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
+                    (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
+            }
+            break;
+            case DrawPath: {
+                SkPath* path = getPath();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint);
+            }
+            break;
+            case DrawLines: {
+                int count = 0;
+                float* points = getFloats(count);
+                SkPaint* paint = getPaint();
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case DrawPoints: {
+                int count = 0;
+                float* points = getFloats(count);
+                SkPaint* paint = getPaint();
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case DrawText: {
+                getText(&text);
+                int count = getInt();
+                float x = getFloat();
+                float y = getFloat();
+                SkPaint* paint = getPaint();
+                LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
+                    text.text(), text.length(), count, x, y, paint);
+            }
+            break;
+            case ResetShader: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case SetupShader: {
+                SkiaShader* shader = getShader();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], shader);
+            }
+            break;
+            case ResetColorFilter: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case SetupColorFilter: {
+                SkiaColorFilter *colorFilter = getColorFilter();
+                LOGD("%s%s %p", (char*) indent, OP_NAMES[op], colorFilter);
+            }
+            break;
+            case ResetShadow: {
+                LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+            }
+            break;
+            case SetupShadow: {
+                float radius = getFloat();
+                float dx = getFloat();
+                float dy = getFloat();
+                int color = getInt();
+                LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
+                    radius, dx, dy, color);
+            }
+            break;
+            default:
+                LOGD("Display List error: op not handled: %s%s",
+                    (char*) indent, OP_NAMES[op]);
+                break;
+        }
+    }
+
+    LOGD("%sDone", (char*) indent + 2);
+}
+
+/**
+ * Changes to replay(), specifically those involving opcode or parameter changes, should be mimicked
+ * in the output() function, since that function processes the same list of opcodes for the
+ * purposes of logging display list info for a given view.
+ */
 bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) {
     bool needsInvalidate = false;
     TextContainer text;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index b782103..dcf2cf2 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -107,6 +107,8 @@
 
     bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
 
+    void output(OpenGLRenderer& renderer, uint32_t level = 0);
+
     static void outputLogBuffer(int fd);
 
 private:
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6f751e8..f6a21d4 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1185,6 +1185,12 @@
     return false;
 }
 
+void OpenGLRenderer::outputDisplayList(DisplayList* displayList, uint32_t level) {
+    if (displayList) {
+        displayList->output(*this, level);
+    }
+}
+
 void OpenGLRenderer::drawAlphaBitmap(Texture* texture, float left, float top, SkPaint* paint) {
     int alpha;
     SkXfermode::Mode mode;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index b5c37c2..271e4b1 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -98,6 +98,7 @@
 
     virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
             Rect& dirty, uint32_t level = 0);
+    virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
     virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
diff --git a/services/java/com/android/server/wm/ViewServer.java b/services/java/com/android/server/wm/ViewServer.java
index cebd5e7..9fb35b9 100644
--- a/services/java/com/android/server/wm/ViewServer.java
+++ b/services/java/com/android/server/wm/ViewServer.java
@@ -49,7 +49,7 @@
     // Debug facility
     private static final String LOG_TAG = "ViewServer";
 
-    private static final String VALUE_PROTOCOL_VERSION = "3";
+    private static final String VALUE_PROTOCOL_VERSION = "4";
     private static final String VALUE_SERVER_VERSION = "4";
 
     // Protocol commands