Implement full View.buildLayer

 Bug: 17152292

Change-Id: Ia3cc2aadf72fe14517f50762fc634794df51ad5a
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 8c9b819..de90899 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -349,6 +349,8 @@
      */
     abstract HardwareLayer createTextureLayer();
 
+    abstract void buildLayer(RenderNode node);
+
     abstract boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap);
 
     /**
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index f9333d5..50341fc 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -332,6 +332,11 @@
     }
 
     @Override
+    void buildLayer(RenderNode node) {
+        nBuildLayer(mNativeProxy, node.getNativeDisplayList());
+    }
+
+    @Override
     boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
         return nCopyLayerInto(mNativeProxy,
                 layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
@@ -468,6 +473,7 @@
 
     private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
     private static native long nCreateTextureLayer(long nativeProxy);
+    private static native void nBuildLayer(long nativeProxy, long node);
     private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
     private static native void nPushLayerUpdate(long nativeProxy, long layer);
     private static native void nCancelLayerUpdate(long nativeProxy, long layer);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3adc41a..0d98d60 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13640,11 +13640,10 @@
 
         switch (mLayerType) {
             case LAYER_TYPE_HARDWARE:
-                // The only part of a hardware layer we can build in response to
-                // this call is to ensure the display list is up to date.
-                // The actual rendering of the display list into the layer must
-                // be done at playback time
                 updateDisplayListIfDirty();
+                if (attachInfo.mHardwareRenderer != null && mRenderNode.isValid()) {
+                    attachInfo.mHardwareRenderer.buildLayer(mRenderNode);
+                }
                 break;
             case LAYER_TYPE_SOFTWARE:
                 buildDrawingCache(true);
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index d183d8e..4e3419a 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -264,6 +264,13 @@
     return reinterpret_cast<jlong>(layer);
 }
 
+static void android_view_ThreadedRenderer_buildLayer(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong nodePtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    RenderNode* node = reinterpret_cast<RenderNode*>(nodePtr);
+    proxy->buildLayer(node);
+}
+
 static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -367,6 +374,7 @@
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
+    { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
     { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
     { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
     { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index e673b0d..5922135 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -244,6 +244,29 @@
     thread.renderState().invokeFunctor(functor, mode, NULL);
 }
 
+void CanvasContext::buildLayer(RenderNode* node) {
+    ATRACE_CALL();
+    if (!mEglManager.hasEglContext() || !mCanvas) {
+        return;
+    }
+    requireGlContext();
+    // buildLayer() will leave the tree in an unknown state, so we must stop drawing
+    stopDrawing();
+
+    TreeInfo info(TreeInfo::MODE_FULL, mRenderThread.renderState());
+    info.frameTimeMs = mRenderThread.timeLord().frameTimeMs();
+    info.damageAccumulator = &mDamageAccumulator;
+    info.renderer = mCanvas;
+    node->prepareTree(info);
+    SkRect ignore;
+    mDamageAccumulator.finish(&ignore);
+    // Tickle the GENERIC property on node to mark it as dirty for damaging
+    // purposes when the frame is actually drawn
+    node->setPropertyFieldsDirty(RenderNode::GENERIC);
+
+    mCanvas->flushLayerUpdates();
+}
+
 bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
     requireGlContext();
     layer->apply();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 2a01027..0cbed6f 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -65,6 +65,7 @@
     // IFrameCallback, Chroreographer-driven frame callback entry point
     virtual void doFrame();
 
+    void buildLayer(RenderNode* node);
     bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
 
     void destroyHardwareResources();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index d9b96f6c..405ce24 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -284,6 +284,18 @@
     return layer;
 }
 
+CREATE_BRIDGE2(buildLayer, CanvasContext* context, RenderNode* node) {
+    args->context->buildLayer(args->node);
+    return NULL;
+}
+
+void RenderProxy::buildLayer(RenderNode* node) {
+    SETUP_TASK(buildLayer);
+    args->context = mContext;
+    args->node = node;
+    postAndWait(task);
+}
+
 CREATE_BRIDGE3(copyLayerInto, CanvasContext* context, DeferredLayerUpdater* layer,
         SkBitmap* bitmap) {
     bool success = args->context->copyLayerInto(args->layer, args->bitmap);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 28d0173..eea3674 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -81,6 +81,7 @@
     static void enqueueDestroyLayer(Layer* layer);
     ANDROID_API DeferredLayerUpdater* createDisplayListLayer(int width, int height);
     ANDROID_API DeferredLayerUpdater* createTextureLayer();
+    ANDROID_API void buildLayer(RenderNode* node);
     ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
     ANDROID_API void pushLayerUpdate(DeferredLayerUpdater* layer);
     ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer);