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>