Merge "Use LayoutlibRenderer for rendering" into main
diff --git a/.idea/libraries/framework_jar.xml b/.idea/libraries/framework_jar.xml
index 82af4c5..37e4754 100644
--- a/.idea/libraries/framework_jar.xml
+++ b/.idea/libraries/framework_jar.xml
@@ -1,7 +1,7 @@
 <component name="libraryTable">
   <library name="framework.jar">
     <CLASSES>
-      <root url="jar://$PROJECT_DIR$/../../out/soong/.intermediates/frameworks/layoutlib/temp_layoutlib/linux_glibc_common/gen/temp_layoutlib.jar!/" />
+      <root url="file://$PROJECT_DIR$/../../out/soong/.intermediates/frameworks/layoutlib/temp_layoutlib/linux_glibc_common" />
     </CLASSES>
     <JAVADOC />
     <SOURCES>
@@ -10,5 +10,7 @@
       <root url="file://$PROJECT_DIR$/../../libcore/luni/src/main/java" />
       <root url="file://$PROJECT_DIR$/../../libcore/dalvik/src/main/java" />
     </SOURCES>
+    <jarDirectory
+        url="file://$PROJECT_DIR$/../../out/soong/.intermediates/frameworks/layoutlib/temp_layoutlib/linux_glibc_common" recursive="true" />
   </library>
 </component>
\ No newline at end of file
diff --git a/.idea/runConfigurations/Create.xml b/.idea/runConfigurations/Create.xml
index 68f4a03..af69537 100644
--- a/.idea/runConfigurations/Create.xml
+++ b/.idea/runConfigurations/Create.xml
@@ -1,9 +1,10 @@
 <component name="ProjectRunConfigurationManager">
   <configuration default="false" name="Create" type="Application" factoryName="Application" singleton="true">
-    <option name="ALTERNATIVE_JRE_PATH" value="$PROJECT_DIR$/../../prebuilts/jdk/jdk9/linux-x86" />
+    <option name="ALTERNATIVE_JRE_PATH" value="jbr-21" />
+    <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
     <option name="MAIN_CLASS_NAME" value="com.android.tools.layoutlib.create.Main" />
     <module name="create" />
-    <option name="PROGRAM_PARAMETERS" value="--create-stub out/soong/.temp/temp_layoutlib.jar out/soong/.intermediates/prebuilts/misc/common/atf/atf-prebuilt-jars-502584086/linux_glibc_common/combined/atf-prebuilt-jars-502584086.jar out/soong/.intermediates/external/icu/android_icu4j/core-icu4j-for-host/android_common/withres/core-icu4j-for-host.jar out/soong/.intermediates/libcore/core-libart/android_common/javac/core-libart.jar out/soong/.intermediates/frameworks/base/framework-all/android_common/combined/framework-all.jar out/soong/.intermediates/frameworks/base/ext/android_common/withres/ext.jar out/soong/.intermediates/external/icu/icu4j/icu4j-icudata-jarjar/linux_glibc_common/jarjar/icu4j-icudata-jarjar.jar out/soong/.intermediates/external/icu/icu4j/icu4j-icutzdata-jarjar/linux_glibc_common/jarjar/icu4j-icutzdata-jarjar.jar out/soong/.intermediates/frameworks/base/packages/SystemUI/monet/monet/android_common/combined/monet.jar" />
+    <option name="PROGRAM_PARAMETERS" value="--create-stub out/soong/.temp/temp_layoutlib.jar out/soong/.intermediates/prebuilts/misc/common/atf/atf-prebuilt-jars-557133692/linux_glibc_common/combined/atf-prebuilt-jars-557133692.jar out/soong/.intermediates/external/icu/android_icu4j/core-icu4j-for-host/android_common/withres/core-icu4j-for-host.jar out/soong/.intermediates/libcore/core-libart/android_common/combined/core-libart.jar out/soong/.intermediates/frameworks/base/framework-all/android_common/combined/framework-all.jar out/soong/.intermediates/frameworks/base/ext/android_common/withres/ext.jar out/soong/.intermediates/external/icu/icu4j/icu4j-icudata-jarjar/linux_glibc_common/jarjar/icu4j-icudata-jarjar.jar out/soong/.intermediates/external/icu/icu4j/icu4j-icutzdata-jarjar/linux_glibc_common/jarjar/icu4j-icutzdata-jarjar.jar out/soong/.intermediates/frameworks/libs/systemui/monet/monet/android_common/combined/monet.jar" />
     <option name="VM_PARAMETERS" value="-ea" />
     <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/../.." />
     <RunnerSettings RunnerId="Debug">
diff --git a/bridge/src/android/view/LayoutlibRenderer.java b/bridge/src/android/view/LayoutlibRenderer.java
index c127a5c..fa8894a 100644
--- a/bridge/src/android/view/LayoutlibRenderer.java
+++ b/bridge/src/android/view/LayoutlibRenderer.java
@@ -16,14 +16,23 @@
 
 package android.view;
 
+import com.android.internal.lang.System_Delegate;
+
 import android.content.Context;
 import android.graphics.BlendMode;
 import android.graphics.RecordingCanvas;
 
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
 public class LayoutlibRenderer extends ThreadedRenderer {
 
     private float scaleX = 1.0f;
     private float scaleY = 1.0f;
+    @SuppressWarnings("unused") // Used by native code
+    private long mNativeContext;
+    /** Buffer in which the rendering will be drawn */
+    private ByteBuffer mBuffer;
 
     LayoutlibRenderer(Context context, boolean translucent, String name) {
         super(context, translucent, name);
@@ -34,6 +43,8 @@
         if (rootView == null) {
             return;
         }
+        // Animations require mDrawingTime to be set to animate
+        rootView.mAttachInfo.mDrawingTime = System_Delegate.currentTimeMillis();
         this.draw(viewGroup, rootView.mAttachInfo,
                 new DrawCallbacks() {
                     @Override
@@ -54,5 +65,43 @@
     public void setScale(float scaleX, float scaleY) {
         this.scaleX = scaleX;
         this.scaleY = scaleY;
+        invalidateRoot();
     }
+
+    /**
+     * Prepares the renderer for drawing
+     */
+    public void setup(int width, int height, View rootView) {
+        ViewRootImpl viewRoot =  rootView.mAttachInfo.mViewRootImpl;
+        if (viewRoot == null) {
+            return;
+        }
+
+        // If the surface associated with the ViewRootImpl is not valid,
+        // create a new one.
+        if (!viewRoot.mSurface.isValid()) {
+            Surface surface = nativeCreateSurface();
+            viewRoot.mSurface.transferFrom(surface);
+        }
+
+        // Create a new buffer to draw the image in, making sure that it is following the native
+        // ordering to work on all platforms.
+        mBuffer = nativeCreateBuffer(width, height);
+        mBuffer.order(ByteOrder.nativeOrder());
+
+        setup(width, height, rootView.mAttachInfo, viewRoot.mWindowAttributes.surfaceInsets);
+        setSurface(viewRoot.mSurface);
+    }
+
+    public ByteBuffer getBuffer() {
+        return mBuffer;
+    }
+
+    public void reset() {
+        mBuffer = null;
+    }
+
+    private native Surface nativeCreateSurface();
+
+    private native ByteBuffer nativeCreateBuffer(int width, int height);
 }
diff --git a/bridge/src/android/media/ImageReader_Delegate.java b/bridge/src/android/view/TextureView_Delegate.java
similarity index 62%
rename from bridge/src/android/media/ImageReader_Delegate.java
rename to bridge/src/android/view/TextureView_Delegate.java
index 0ff1ce7..0a2abe1 100644
--- a/bridge/src/android/media/ImageReader_Delegate.java
+++ b/bridge/src/android/view/TextureView_Delegate.java
@@ -14,11 +14,18 @@
  * limitations under the License.
  */
 
-package android.media;
+package android.view;
 
-public class ImageReader_Delegate {
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
-    static void nativeClassInit() {
-        // Call ImageReader.nativeClassInit(); in layoutlib implicitly before using ImageReader
+import android.graphics.TextureLayer;
+
+public class TextureView_Delegate {
+    @LayoutlibDelegate
+    static TextureLayer getTextureLayer(TextureView thisTextureView) {
+        /*
+         * Currently layoutlib does not support TextureLayers (no OpenGL)
+         */
+        return null;
     }
 }
diff --git a/common/src/com/android/tools/layoutlib/create/NativeConfig.java b/common/src/com/android/tools/layoutlib/create/NativeConfig.java
index 3b94d25..04b881c 100644
--- a/common/src/com/android/tools/layoutlib/create/NativeConfig.java
+++ b/common/src/com/android/tools/layoutlib/create/NativeConfig.java
@@ -25,6 +25,7 @@
     private NativeConfig() {}
 
     public final static String[] DEFERRED_STATIC_INITIALIZER_CLASSES = new String [] {
+            "android.graphics.PathIterator",
             "android.graphics.Typeface",
     };
 
@@ -119,6 +120,7 @@
             "android.view.PointerIcon#loadResource",
             "android.view.SurfaceControl#nativeCreateTransaction",
             "android.view.SurfaceControl#nativeGetNativeTransactionFinalizer",
+            "android.view.TextureView#getTextureLayer",
             "android.view.VelocityTracker#obtain",
             "android.view.View#dispatchDetachedFromWindow",
             "android.view.View#draw",
@@ -165,6 +167,7 @@
             "android.text.AndroidCharacter",
             "android.util.Log",
             "android.view.MotionEvent",
+            "android.view.Surface",
             "com.android.internal.util.VirtualRefBasePtr",
             "libcore.util.NativeAllocationRegistry",
     };
@@ -186,6 +189,7 @@
             "android.graphics.FontFamily",
             "android.graphics.Gainmap",
             "android.graphics.Graphics",
+            "android.graphics.HardwareRenderer",
             "android.graphics.ImageDecoder",
             "android.graphics.Interpolator",
             "android.graphics.MaskFilter",
@@ -194,6 +198,7 @@
             "android.graphics.Paint",
             "android.graphics.Path",
             "android.graphics.PathEffect",
+            "android.graphics.PathIterator",
             "android.graphics.PathMeasure",
             "android.graphics.Picture",
             "android.graphics.RecordingCanvas",
diff --git a/create/create.iml b/create/create.iml
index bbf099f..5c7d27a 100644
--- a/create/create.iml
+++ b/create/create.iml
@@ -10,27 +10,11 @@
     </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
-    <orderEntry type="module-library">
-      <library name="asm-9.6">
-        <CLASSES>
-          <root url="jar://$MODULE_DIR$/../../../out/soong/.intermediates/prebuilts/misc/common/asm/asm-9.6/linux_glibc_common/combined/asm-9.6.jar!/" />
-        </CLASSES>
-        <JAVADOC />
-        <SOURCES />
-      </library>
-    </orderEntry>
-    <orderEntry type="module-library">
-      <library name="asm-commons-9.6">
-        <CLASSES>
-          <root url="jar://$MODULE_DIR$/../../../out/soong/.intermediates/prebuilts/misc/common/asm/asm-commons-9.6/linux_glibc_common/combined/asm-commons-9.6.jar!/" />
-        </CLASSES>
-        <JAVADOC />
-        <SOURCES />
-      </library>
-    </orderEntry>
     <orderEntry type="library" scope="TEST" name="junit" level="project" />
     <orderEntry type="module" module-name="common" />
     <orderEntry type="library" name="guava" level="project" />
+    <orderEntry type="library" name="ow2-asm" level="project" />
+    <orderEntry type="library" name="ow2-asm-commons" level="project" />
     <orderEntry type="library" scope="TEST" name="hamcrest" level="project" />
     <orderEntry type="module-library" scope="RUNTIME">
       <library>
@@ -80,12 +64,21 @@
     <orderEntry type="module-library" scope="RUNTIME">
       <library>
         <CLASSES>
-          <root url="jar://$MODULE_DIR$/../../../out/soong/.intermediates/prebuilts/misc/common/atf/atf-prebuilt-jars-502584086/linux_glibc_common/combined/atf-prebuilt-jars-502584086.jar!/" />
+          <root url="jar://$MODULE_DIR$/../../../out/soong/.intermediates/prebuilts/misc/common/atf/atf-prebuilt-jars-557133692/linux_glibc_common/combined/atf-prebuilt-jars-557133692.jar!/" />
         </CLASSES>
         <JAVADOC />
         <SOURCES />
       </library>
     </orderEntry>
     <orderEntry type="library" scope="RUNTIME" name="libprotobuf-java-lite" level="project" />
+    <orderEntry type="module-library" scope="RUNTIME">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../out/soong/.intermediates/frameworks/libs/systemui/monet/monet/android_common/combined/monet.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
   </component>
 </module>
diff --git a/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index dbdce8d..e625d24 100644
--- a/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -145,7 +145,6 @@
         new SystemCurrentTimeMillisReplacer(),
         new LinkedHashMapEldestReplacer(),
         new ContextGetClassLoaderReplacer(),
-        new ImageReaderNativeInitReplacer(),
         new NativeInitPathReplacer(),
         new AdaptiveIconMaskReplacer(),
         new ActivityThreadInAnimationReplacer(),
@@ -362,7 +361,6 @@
         "android.graphics.Path#nInit",
         "android.graphics.Typeface$Builder#createAssetUid",
         "android.hardware.input.InputManagerGlobal#<init>",
-        "android.media.ImageReader#nativeClassInit",
         "android.view.ViewRootImpl#getRootMeasureSpec",
     };
 
@@ -507,23 +505,6 @@
         }
     }
 
-    /**
-     * This is to replace a static call to a dummy, so that ImageReader can be loaded and accessed
-     * during JNI loading
-     */
-    public static class ImageReaderNativeInitReplacer implements MethodReplacer {
-        @Override
-        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
-            return "android/media/ImageReader".equals(owner) && name.equals("nativeClassInit");
-        }
-
-        @Override
-        public void replace(MethodInformation mi) {
-            mi.owner = "android/media/ImageReader_Delegate";
-            mi.opcode = Opcodes.INVOKESTATIC;
-        }
-    }
-
     private static class LocaleGetDefaultReplacer implements MethodReplacer {
 
         @Override
diff --git a/jni/android_view_LayoutlibRenderer.cpp b/jni/android_view_LayoutlibRenderer.cpp
new file mode 100644
index 0000000..ed70149
--- /dev/null
+++ b/jni/android_view_LayoutlibRenderer.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/BufferQueue.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <ui/GraphicBuffer.h>
+
+#include "android_runtime/android_view_Surface.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
+
+namespace android {
+
+jfieldID gNativeContextFieldId;
+
+/**
+ * Class to store information needed by the Layoutlib renderer
+ */
+class JNILayoutlibRendererContext : public RefBase {
+public:
+    ~JNILayoutlibRendererContext() override {
+        if (mBufferConsumer != nullptr) {
+            mBufferConsumer.clear();
+        }
+    }
+
+    void setBufferConsumer(const sp<IGraphicBufferConsumer>& consumer) {
+        mBufferConsumer = consumer;
+    }
+
+    IGraphicBufferConsumer* getBufferConsumer() {
+        return mBufferConsumer.get();
+    }
+
+private:
+    sp<IGraphicBufferConsumer> mBufferConsumer;
+};
+
+static jobject android_view_LayoutlibRenderer_createSurface(JNIEnv* env, jobject thiz) {
+    sp<IGraphicBufferProducer> gbProducer;
+    sp<IGraphicBufferConsumer> gbConsumer;
+    BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
+
+    // Save the IGraphicBufferConsumer in the context so that it can be reused for buffer creation
+    sp<JNILayoutlibRendererContext> newCtx = sp<JNILayoutlibRendererContext>::make();
+    newCtx->setBufferConsumer(gbConsumer);
+    auto* const currentCtx = reinterpret_cast<JNILayoutlibRendererContext*>(
+            env->GetLongField(thiz, gNativeContextFieldId));
+    if (newCtx != nullptr) {
+        // Create a strong reference to the new context to avoid it being destroyed
+        newCtx->incStrong((void*)android_view_LayoutlibRenderer_createSurface);
+    }
+    if (currentCtx != nullptr) {
+        // Delete the reference to the previous context as it is not needed and can be destroyed
+        currentCtx->decStrong((void*)android_view_LayoutlibRenderer_createSurface);
+    }
+    env->SetLongField(thiz, gNativeContextFieldId, reinterpret_cast<jlong>(newCtx.get()));
+
+    return android_view_Surface_createFromIGraphicBufferProducer(env, gbProducer);
+}
+
+static jobject android_view_LayoutlibRenderer_createBuffer(JNIEnv* env, jobject thiz, jint width,
+                                                           jint height) {
+    auto* ctx = reinterpret_cast<JNILayoutlibRendererContext*>(
+            env->GetLongField(thiz, gNativeContextFieldId));
+    if (ctx == nullptr) {
+        jniThrowException(env, "java/lang/IllegalStateException", "No surface has been created");
+        return nullptr;
+    }
+
+    IGraphicBufferConsumer* bufferConsumer = ctx->getBufferConsumer();
+    bufferConsumer->setDefaultBufferSize(width, height);
+    auto* bufferItem = new BufferItem();
+    bufferConsumer->acquireBuffer(bufferItem, 0);
+    sp<GraphicBuffer> buffer = bufferItem->mGraphicBuffer;
+
+    int bytesPerPixel = 4;
+    uint32_t dataSize = buffer->getStride() * buffer->getHeight() * bytesPerPixel;
+
+    void* pData = nullptr;
+    buffer->lockAsync(0, Rect::EMPTY_RECT, &pData, 0);
+
+    jobject byteBuffer = env->NewDirectByteBuffer(pData, dataSize);
+    return byteBuffer;
+}
+
+static const JNINativeMethod gMethods[] = {
+        {"nativeCreateSurface", "()Landroid/view/Surface;",
+         (void*)android_view_LayoutlibRenderer_createSurface},
+        {"nativeCreateBuffer", "(II)Ljava/nio/ByteBuffer;",
+         (void*)android_view_LayoutlibRenderer_createBuffer},
+};
+
+int register_android_view_LayoutlibRenderer(JNIEnv* env) {
+    jclass layoutlibRendererClass = FindClassOrDie(env, "android/view/LayoutlibRenderer");
+    gNativeContextFieldId = GetFieldIDOrDie(env, layoutlibRendererClass, "mNativeContext", "J");
+
+    return RegisterMethodsOrDie(env, "android/view/LayoutlibRenderer", gMethods, NELEM(gMethods));
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/validator/validator.iml b/validator/validator.iml
index 094889e..bbc7b6c 100644
--- a/validator/validator.iml
+++ b/validator/validator.iml
@@ -12,7 +12,6 @@
     <orderEntry type="library" name="layoutlib_api-prebuilt" level="project" />
     <orderEntry type="module" module-name="common" />
     <orderEntry type="library" name="guava" level="project" />
-    <orderEntry type="library" scope="TEST" name="hamcrest" level="project" />
     <orderEntry type="library" name="jsoup" level="project" />
     <orderEntry type="library" name="libprotobuf-java-lite" level="project" />
   </component>