resolve merge conflicts of 3e58f1bd447be6231bbb93f2578b2f221f1dd7fd to master-layoutlib-native

Change-Id: Ib11be12d12de2aa434ccc763fda58c055dc00c5a
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
deleted file mode 100644
index 3b31283..0000000
--- a/.idea/inspectionProfiles/profiles_settings.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<component name="InspectionProjectProfileManager">
-  <settings>
-    <option name="PROJECT_PROFILE" value="Project Default" />
-    <option name="USE_PROJECT_PROFILE" value="true" />
-    <version value="1.0" />
-  </settings>
-</component>
\ No newline at end of file
diff --git a/.idea/libraries/framework_jar.xml b/.idea/libraries/framework_jar.xml
index 2ad7916..82af4c5 100644
--- a/.idea/libraries/framework_jar.xml
+++ b/.idea/libraries/framework_jar.xml
@@ -8,6 +8,7 @@
       <root url="file://$PROJECT_DIR$/../base/core/java" />
       <root url="file://$PROJECT_DIR$/../base/graphics/java" />
       <root url="file://$PROJECT_DIR$/../../libcore/luni/src/main/java" />
+      <root url="file://$PROJECT_DIR$/../../libcore/dalvik/src/main/java" />
     </SOURCES>
   </library>
 </component>
\ No newline at end of file
diff --git a/.idea/libraries/truth_0_42.xml b/.idea/libraries/truth_0_42.xml
new file mode 100644
index 0000000..8a10cf8
--- /dev/null
+++ b/.idea/libraries/truth_0_42.xml
@@ -0,0 +1,9 @@
+<component name="libraryTable">
+  <library name="truth-0.42">
+    <CLASSES>
+      <root url="jar://$PROJECT_DIR$/../../prebuilts/tools/common/m2/repository/com/google/truth/truth/0.42/truth-0.42.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 22a2093..b40be7a 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -13,7 +13,7 @@
     <option name="myDefaultNotNull" value="android.annotation.NonNull" />
     <option name="myNullables">
       <value>
-        <list size="13">
+        <list size="15">
           <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
           <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
           <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
@@ -26,13 +26,15 @@
           <item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
           <item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
           <item index="11" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
-          <item index="12" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.Nullable" />
+          <item index="12" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
+          <item index="13" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
+          <item index="14" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
         </list>
       </value>
     </option>
     <option name="myNotNulls">
       <value>
-        <list size="12">
+        <list size="14">
           <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
           <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
           <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
@@ -44,7 +46,9 @@
           <item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
           <item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
           <item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
-          <item index="11" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.NonNull" />
+          <item index="11" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
+          <item index="12" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
+          <item index="13" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
         </list>
       </value>
     </option>
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 5210215..5b018bb 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -5,6 +5,7 @@
       <module fileurl="file://$PROJECT_DIR$/bridge/bridge.iml" filepath="$PROJECT_DIR$/bridge/bridge.iml" />
       <module fileurl="file://$PROJECT_DIR$/common/common.iml" filepath="$PROJECT_DIR$/common/common.iml" />
       <module fileurl="file://$PROJECT_DIR$/create/create.iml" filepath="$PROJECT_DIR$/create/create.iml" />
+      <module fileurl="file://$PROJECT_DIR$/delegates/delegates.iml" filepath="$PROJECT_DIR$/delegates/delegates.iml" />
       <module fileurl="file://$PROJECT_DIR$/remote/client/remote client.iml" filepath="$PROJECT_DIR$/remote/client/remote client.iml" group="remote" />
       <module fileurl="file://$PROJECT_DIR$/remote/common/remote common.iml" filepath="$PROJECT_DIR$/remote/common/remote common.iml" group="remote" />
       <module fileurl="file://$PROJECT_DIR$/remote/server/remote server.iml" filepath="$PROJECT_DIR$/remote/server/remote server.iml" group="remote" />
diff --git a/.idea/runConfigurations/Bridge_quick.xml b/.idea/runConfigurations/Bridge_quick.xml
index e9797b0..b8e7a7a 100644
--- a/.idea/runConfigurations/Bridge_quick.xml
+++ b/.idea/runConfigurations/Bridge_quick.xml
@@ -1,7 +1,6 @@
 <component name="ProjectRunConfigurationManager">
   <configuration default="false" name="Bridge quick" type="JUnit" factoryName="JUnit">
     <module name="bridge" />
-    <useClassPathOnly />
     <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
     <option name="ALTERNATIVE_JRE_PATH" value="11" />
     <option name="MAIN_CLASS_NAME" value="" />
@@ -11,13 +10,10 @@
     <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
     <patterns>
       <pattern testClass="com.android.layoutlib.bridge.TestDelegates" />
-      <pattern testClass="android.graphics.Matrix_DelegateTest" />
       <pattern testClass="com.android.layoutlib.bridge.android.BridgeXmlBlockParserTest" />
     </patterns>
     <RunnerSettings RunnerId="Run" />
     <ConfigurationWrapper RunnerId="Run" />
-    <method v="2">
-      <option name="Make" enabled="true" />
-    </method>
+    <method v="2" />
   </configuration>
 </component>
\ No newline at end of file
diff --git a/.idea/runConfigurations/Create.xml b/.idea/runConfigurations/Create.xml
index a3fd3a1..8fa90ff 100644
--- a/.idea/runConfigurations/Create.xml
+++ b/.idea/runConfigurations/Create.xml
@@ -4,7 +4,7 @@
     <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/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar out/host/common/obj/JAVA_LIBRARIES/icu4j-icudata-jarjar_intermediates/classes.jar out/host/common/obj/JAVA_LIBRARIES/icu4j-icutzdata-jarjar_intermediates/classes.jar" />
+    <option name="PROGRAM_PARAMETERS" value="--create-stub out/soong/.temp/temp_layoutlib.jar out/soong/.intermediates/libcore/core-libart/android_common/withres/core-libart.jar out/soong/.intermediates/frameworks/base/framework/android_common/jarjar/framework.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" />
     <option name="VM_PARAMETERS" value="-ea" />
     <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/../.." />
     <RunnerSettings RunnerId="Debug">
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index c80f219..df496fd 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -1,7 +1,40 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
+  <component name="IssueNavigationConfiguration">
+    <option name="links">
+      <list>
+        <IssueNavigationLink>
+          <option name="issueRegexp" value="\bb/(\d+)(#\w+)?\b" />
+          <option name="linkRegexp" value="https://buganizer.corp.google.com/issues/$1$2" />
+        </IssueNavigationLink>
+        <IssueNavigationLink>
+          <option name="issueRegexp" value="\b(?:BUG=|FIXED=)(\d+)\b" />
+          <option name="linkRegexp" value="https://buganizer.corp.google.com/issues/$1" />
+        </IssueNavigationLink>
+        <IssueNavigationLink>
+          <option name="issueRegexp" value="\b(?:cl/|cr/|OCL=|DIFFBASE=|ROLLBACK_OF=)(\d+)\b" />
+          <option name="linkRegexp" value="https://critique.corp.google.com/$1" />
+        </IssueNavigationLink>
+        <IssueNavigationLink>
+          <option name="issueRegexp" value="\bomg/(\d+)\b" />
+          <option name="linkRegexp" value="https://omg.corp.google.com/$1" />
+        </IssueNavigationLink>
+        <IssueNavigationLink>
+          <option name="issueRegexp" value="\b(?:go/|goto/)([^,.&lt;&gt;()&quot;\s]+(?:[.,][^,.&lt;&gt;()&quot;\s]+)*)" />
+          <option name="linkRegexp" value="https://goto.google.com/$1" />
+        </IssueNavigationLink>
+        <IssueNavigationLink>
+          <option name="issueRegexp" value="\bcs/([^\s]+[\w$])" />
+          <option name="linkRegexp" value="https://cs.corp.google.com/search/?q=$1" />
+        </IssueNavigationLink>
+        <IssueNavigationLink>
+          <option name="issueRegexp" value="(LINT\.IfChange)|(LINT\.ThenChange)" />
+          <option name="linkRegexp" value="https://goto.google.com/ifthisthenthatlint" />
+        </IssueNavigationLink>
+      </list>
+    </option>
+  </component>
   <component name="VcsDirectoryMappings">
     <mapping directory="$PROJECT_DIR$" vcs="Git" />
   </component>
-</project>
-
+</project>
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index b38baa2..5b760e6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -35,3 +35,13 @@
     ],
     cmd: "rm -f $(out) && $(location layoutlib_create) --create-stub $(out) $(in)",
 }
+
+java_genrule_host {
+    name: "layoutlib-native-delegates",
+    tools: ["layoutlib_create"],
+    out: ["layoutlib-native-delegates.jar"],
+    srcs: [
+        ":framework{.jar}",
+    ],
+    cmd: "rm -f $(out) && $(location layoutlib_create) --create-native-only-delegates $(out) $(in)",
+}
diff --git a/bridge/Android.bp b/bridge/Android.bp
index 629c75f..4cb5e4b 100644
--- a/bridge/Android.bp
+++ b/bridge/Android.bp
@@ -31,6 +31,7 @@
         "temp_layoutlib",
         "ninepatch-prebuilt",
         "layoutlib-common",
+        "layoutlib-common-delegates",
         "layoutlib-validator",
         "sdk-common",
     ],
@@ -60,6 +61,8 @@
         "tools-common-prebuilt",
         "ninepatch-prebuilt",
         "layoutlib-common",
+        "layoutlib-common-delegates",
+        "layoutlib-native-delegates",
         "layoutlib-validator",
         "sdk-common",
     ],
diff --git a/bridge/bridge.iml b/bridge/bridge.iml
index c9ce012..8c4858f 100644
--- a/bridge/bridge.iml
+++ b/bridge/bridge.iml
@@ -70,6 +70,7 @@
       </library>
     </orderEntry>
     <orderEntry type="library" scope="TEST" name="hamcrest" level="project" />
+    <orderEntry type="module" module-name="delegates" />
     <orderEntry type="module-library">
       <library name="ninepatch-prebuilt">
         <CLASSES>
diff --git a/bridge/resources/icons/shadow-b.png b/bridge/resources/icons/shadow-b.png
deleted file mode 100644
index 68f4f4b..0000000
--- a/bridge/resources/icons/shadow-b.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow-bl.png b/bridge/resources/icons/shadow-bl.png
deleted file mode 100644
index ee7dbe8..0000000
--- a/bridge/resources/icons/shadow-bl.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow-br.png b/bridge/resources/icons/shadow-br.png
deleted file mode 100644
index c45ad77..0000000
--- a/bridge/resources/icons/shadow-br.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow-l.png b/bridge/resources/icons/shadow-l.png
deleted file mode 100644
index 77d0bd0..0000000
--- a/bridge/resources/icons/shadow-l.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow-r.png b/bridge/resources/icons/shadow-r.png
deleted file mode 100644
index 4af7a33..0000000
--- a/bridge/resources/icons/shadow-r.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow-tl.png b/bridge/resources/icons/shadow-tl.png
deleted file mode 100644
index 424fb36..0000000
--- a/bridge/resources/icons/shadow-tl.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow-tr.png b/bridge/resources/icons/shadow-tr.png
deleted file mode 100644
index 1fd0c77..0000000
--- a/bridge/resources/icons/shadow-tr.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow2-b.png b/bridge/resources/icons/shadow2-b.png
deleted file mode 100644
index 963973e..0000000
--- a/bridge/resources/icons/shadow2-b.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow2-bl.png b/bridge/resources/icons/shadow2-bl.png
deleted file mode 100644
index 7612487..0000000
--- a/bridge/resources/icons/shadow2-bl.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow2-br.png b/bridge/resources/icons/shadow2-br.png
deleted file mode 100644
index 8e20252..0000000
--- a/bridge/resources/icons/shadow2-br.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow2-l.png b/bridge/resources/icons/shadow2-l.png
deleted file mode 100644
index 2db18a0..0000000
--- a/bridge/resources/icons/shadow2-l.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow2-r.png b/bridge/resources/icons/shadow2-r.png
deleted file mode 100644
index 8e026f1..0000000
--- a/bridge/resources/icons/shadow2-r.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow2-tl.png b/bridge/resources/icons/shadow2-tl.png
deleted file mode 100644
index a8045ed..0000000
--- a/bridge/resources/icons/shadow2-tl.png
+++ /dev/null
Binary files differ
diff --git a/bridge/resources/icons/shadow2-tr.png b/bridge/resources/icons/shadow2-tr.png
deleted file mode 100644
index 590373c..0000000
--- a/bridge/resources/icons/shadow2-tr.png
+++ /dev/null
Binary files differ
diff --git a/bridge/src/android/animation/AnimationThread.java b/bridge/src/android/animation/AnimationThread.java
deleted file mode 100644
index ce2aec7..0000000
--- a/bridge/src/android/animation/AnimationThread.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.animation;
-
-import com.android.ide.common.rendering.api.IAnimationListener;
-import com.android.ide.common.rendering.api.RenderSession;
-import com.android.ide.common.rendering.api.Result;
-import com.android.ide.common.rendering.api.Result.Status;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.RenderSessionImpl;
-
-import android.os.Handler;
-import android.os.Handler_Delegate;
-import android.os.Message;
-
-import java.util.PriorityQueue;
-import java.util.Queue;
-
-/**
- * Abstract animation thread.
- * <p/>
- * This does not actually start an animation, instead it fakes a looper that will play whatever
- * animation is sending messages to its own {@link Handler}.
- * <p/>
- * Classes should implement {@link #preAnimation()} and {@link #postAnimation()}.
- * <p/>
- * If {@link #preAnimation()} does not start an animation somehow then the thread doesn't do
- * anything.
- *
- */
-public abstract class AnimationThread extends Thread {
-
-    private static class MessageBundle implements Comparable<MessageBundle> {
-        final Handler mTarget;
-        final Message mMessage;
-        final long mUptimeMillis;
-
-        MessageBundle(Handler target, Message message, long uptimeMillis) {
-            mTarget = target;
-            mMessage = message;
-            mUptimeMillis = uptimeMillis;
-        }
-
-        @Override
-        public int compareTo(MessageBundle bundle) {
-            if (mUptimeMillis < bundle.mUptimeMillis) {
-                return -1;
-            }
-            return 1;
-        }
-    }
-
-    private final RenderSessionImpl mSession;
-
-    private Queue<MessageBundle> mQueue = new PriorityQueue<MessageBundle>();
-    private final IAnimationListener mListener;
-
-    public AnimationThread(RenderSessionImpl scene, String threadName,
-            IAnimationListener listener) {
-        super(threadName);
-        mSession = scene;
-        mListener = listener;
-    }
-
-    public abstract Result preAnimation();
-    public abstract void postAnimation();
-
-    @Override
-    public void run() {
-        Bridge.prepareThread();
-        try {
-            /* FIXME: The ANIMATION_FRAME message no longer exists.  Instead, the
-             * animation timing loop is completely based on a Choreographer objects
-             * that schedules animation and drawing frames.  The animation handler is
-             * no longer even a handler; it is just a Runnable enqueued on the Choreographer.
-            Handler_Delegate.setCallback(new IHandlerCallback() {
-                @Override
-                public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
-                    if (msg.what == ValueAnimator.ANIMATION_START ||
-                            msg.what == ValueAnimator.ANIMATION_FRAME) {
-                        mQueue.add(new MessageBundle(handler, msg, uptimeMillis));
-                    } else {
-                        // just ignore.
-                    }
-                }
-            });
-            */
-
-            // call out to the pre-animation work, which should start an animation or more.
-            Result result = preAnimation();
-            if (result.isSuccess() == false) {
-                mListener.done(result);
-            }
-
-            // loop the animation
-            RenderSession session = mSession.getSession();
-            do {
-                // check early.
-                if (mListener.isCanceled()) {
-                    break;
-                }
-
-                // get the next message.
-                MessageBundle bundle = mQueue.poll();
-                if (bundle == null) {
-                    break;
-                }
-
-                // sleep enough for this bundle to be on time
-                long currentTime = System.currentTimeMillis();
-                if (currentTime < bundle.mUptimeMillis) {
-                    try {
-                        sleep(bundle.mUptimeMillis - currentTime);
-                    } catch (InterruptedException e) {
-                        // FIXME log/do something/sleep again?
-                        e.printStackTrace();
-                    }
-                }
-
-                // check after sleeping.
-                if (mListener.isCanceled()) {
-                    break;
-                }
-
-                // ready to do the work, acquire the scene.
-                result = mSession.acquire(250);
-                if (result.isSuccess() == false) {
-                    mListener.done(result);
-                    return;
-                }
-
-                // process the bundle. If the animation is not finished, this will enqueue
-                // the next message, so mQueue will have another one.
-                try {
-                    // check after acquiring in case it took a while.
-                    if (mListener.isCanceled()) {
-                        break;
-                    }
-
-                    bundle.mTarget.handleMessage(bundle.mMessage);
-                    if (mSession.render(false /*freshRender*/).isSuccess()) {
-                        mListener.onNewFrame(session);
-                    }
-                } finally {
-                    mSession.release();
-                }
-            } while (mListener.isCanceled() == false && mQueue.size() > 0);
-
-            mListener.done(Status.SUCCESS.createResult());
-
-        } catch (Throwable throwable) {
-            // can't use Bridge.getLog() as the exception might be thrown outside
-            // of an acquire/release block.
-            mListener.done(Status.ERROR_UNKNOWN.createResult("Error playing animation", throwable));
-
-        } finally {
-            postAnimation();
-            Handler_Delegate.setCallback(null);
-            Bridge.cleanupThread();
-        }
-    }
-}
diff --git a/bridge/src/android/animation/PropertyValuesHolder_Delegate.java b/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
deleted file mode 100644
index 556a063..0000000
--- a/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.animation;
-
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Delegate implementing the native methods of android.animation.PropertyValuesHolder
- *
- * Through the layoutlib_create tool, the original native methods of PropertyValuesHolder have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
- * around to map int to instance of the delegate.
- *
- * The main goal of this class' methods are to provide a native way to access setters and getters
- * on some object. We override these methods to use reflection since the original reflection
- * implementation of the PropertyValuesHolder won't be able to access protected methods.
- *
- */
-public class PropertyValuesHolder_Delegate {
-    // This code is copied from android.animation.PropertyValuesHolder and must be kept in sync
-    // We try several different types when searching for appropriate setter/getter functions.
-    // The caller may have supplied values in a type that does not match the setter/getter
-    // functions (such as the integers 0 and 1 to represent floating point values for alpha).
-    // Also, the use of generics in constructors means that we end up with the Object versions
-    // of primitive types (Float vs. float). But most likely, the setter/getter functions
-    // will take primitive types instead.
-    // So we supply an ordered array of other types to try before giving up.
-    private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class,
-            Double.class, Integer.class};
-    private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class,
-            Float.class, Double.class};
-
-    private static final Object sMethodIndexLock = new Object();
-    private static final Map<Long, Method> ID_TO_METHOD = new HashMap<Long, Method>();
-    private static final Map<String, Long> METHOD_NAME_TO_ID = new HashMap<String, Long>();
-    private static long sNextId = 1;
-
-    private static long registerMethod(Class<?> targetClass, String methodName, Class[] types,
-            int nArgs) {
-        // Encode the number of arguments in the method name
-        String methodIndexName = String.format("%1$s.%2$s#%3$d", targetClass.getSimpleName(),
-                methodName, nArgs);
-        synchronized (sMethodIndexLock) {
-            Long methodId = METHOD_NAME_TO_ID.get(methodIndexName);
-
-            if (methodId != null) {
-                // The method was already registered, check whether the class loader has changed
-                Method method = ID_TO_METHOD.get(methodId);
-                if (targetClass.equals(method.getDeclaringClass())) {
-                    return methodId;
-                }
-            }
-
-            Class[] args = new Class[nArgs];
-            Method method = null;
-            for (Class typeVariant : types) {
-                for (int i = 0; i < nArgs; i++) {
-                    args[i] = typeVariant;
-                }
-                try {
-                    method = targetClass.getDeclaredMethod(methodName, args);
-                } catch (NoSuchMethodException ignore) {
-                }
-            }
-
-            if (method != null) {
-                if (methodId == null) {
-                    methodId = sNextId++;
-                }
-                ID_TO_METHOD.put(methodId, method);
-                METHOD_NAME_TO_ID.put(methodIndexName, methodId);
-
-                return methodId;
-            }
-        }
-
-        // Method not found
-        return 0;
-    }
-
-    private static void callMethod(Object target, long methodID, Object... args) {
-        Method method = ID_TO_METHOD.get(methodID);
-        assert method != null;
-
-        try {
-            method.setAccessible(true);
-            method.invoke(target, args);
-        } catch (IllegalAccessException | InvocationTargetException e) {
-            Bridge.getLog().error(null, "Unable to update property during animation", e, null,
-                    null);
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetIntMethod(Class<?> targetClass, String methodName) {
-        return nGetMultipleIntMethod(targetClass, methodName, 1);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetFloatMethod(Class<?> targetClass, String methodName) {
-        return nGetMultipleFloatMethod(targetClass, methodName, 1);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetMultipleIntMethod(Class<?> targetClass, String methodName,
-            int numParams) {
-        return registerMethod(targetClass, methodName, INTEGER_VARIANTS, numParams);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetMultipleFloatMethod(Class<?> targetClass, String methodName,
-            int numParams) {
-        return registerMethod(targetClass, methodName, FLOAT_VARIANTS, numParams);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nCallIntMethod(Object target, long methodID, int arg) {
-        callMethod(target, methodID, arg);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nCallFloatMethod(Object target, long methodID, float arg) {
-        callMethod(target, methodID, arg);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nCallTwoIntMethod(Object target, long methodID, int arg1,
-            int arg2) {
-        callMethod(target, methodID, arg1, arg2);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nCallFourIntMethod(Object target, long methodID, int arg1,
-            int arg2, int arg3, int arg4) {
-        callMethod(target, methodID, arg1, arg2, arg3, arg4);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nCallMultipleIntMethod(Object target, long methodID,
-            int[] args) {
-        assert args != null;
-
-        // Box parameters
-        Object[] params = new Object[args.length];
-        for (int i = 0; i < args.length; i++) {
-            params[i] = args;
-        }
-        callMethod(target, methodID, params);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nCallTwoFloatMethod(Object target, long methodID, float arg1,
-            float arg2) {
-        callMethod(target, methodID, arg1, arg2);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nCallFourFloatMethod(Object target, long methodID, float arg1,
-            float arg2, float arg3, float arg4) {
-        callMethod(target, methodID, arg1, arg2, arg3, arg4);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nCallMultipleFloatMethod(Object target, long methodID,
-            float[] args) {
-        assert args != null;
-
-        // Box parameters
-        Object[] params = new Object[args.length];
-        for (int i = 0; i < args.length; i++) {
-            params[i] = args;
-        }
-        callMethod(target, methodID, params);
-    }
-
-    public static void clearCaches() {
-        ID_TO_METHOD.clear();
-        METHOD_NAME_TO_ID.clear();
-    }
-}
diff --git a/bridge/src/android/content/res/AssetManager_Delegate.java b/bridge/src/android/content/res/AssetManager_Delegate.java
index c27df09..a2d9058 100644
--- a/bridge/src/android/content/res/AssetManager_Delegate.java
+++ b/bridge/src/android/content/res/AssetManager_Delegate.java
@@ -75,4 +75,8 @@
         // AssetManager requires this not to be null
         return new String[0];
     }
+
+    @LayoutlibDelegate
+    /*package*/ static void createSystemAssetsInZygoteLocked(boolean reinitialize,
+            String frameworkPath) { }
 }
diff --git a/bridge/src/android/content/res/Resources_Delegate.java b/bridge/src/android/content/res/Resources_Delegate.java
index 2689acd..7f502a9 100644
--- a/bridge/src/android/content/res/Resources_Delegate.java
+++ b/bridge/src/android/content/res/Resources_Delegate.java
@@ -25,7 +25,6 @@
 import com.android.ide.common.rendering.api.PluralsResourceValue;
 import com.android.ide.common.rendering.api.RenderResources;
 import com.android.ide.common.rendering.api.ResourceNamespace;
-import com.android.ide.common.rendering.api.ResourceNamespace.Resolver;
 import com.android.ide.common.rendering.api.ResourceReference;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.ResourceValueImpl;
@@ -37,7 +36,6 @@
 import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.ResourceHelper;
 import com.android.layoutlib.bridge.util.NinePatchInputStream;
-import com.android.ninepatch.NinePatch;
 import com.android.resources.ResourceType;
 import com.android.resources.ResourceUrl;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
@@ -1026,11 +1024,8 @@
             if (stream == null) {
                 throw new NotFoundException(path);
             }
-            // If it's a nine-patch return a custom input stream so that
-            // other methods (mainly bitmap factory) can detect it's a 9-patch
-            // and actually load it as a 9-patch instead of a normal bitmap.
-            if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
-                return new NinePatchInputStream(stream);
+            if (path.endsWith(".9.png")) {
+                stream = new NinePatchInputStream(stream, path);
             }
             return stream;
         } catch (IOException e) {
diff --git a/bridge/src/android/graphics/BaseCanvas_Delegate.java b/bridge/src/android/graphics/BaseCanvas_Delegate.java
deleted file mode 100644
index 5a9236c..0000000
--- a/bridge/src/android/graphics/BaseCanvas_Delegate.java
+++ /dev/null
@@ -1,815 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.layoutlib.bridge.impl.GcSnapshot;
-import com.android.layoutlib.bridge.impl.PorterDuffUtility;
-import com.android.ninepatch.NinePatchChunk;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.Nullable;
-import android.text.TextUtils;
-import android.util.imagepool.ImagePool;
-import android.util.imagepool.ImagePoolProvider;
-
-import java.awt.Composite;
-import java.awt.Graphics2D;
-import java.awt.PaintContext;
-import java.awt.RenderingHints;
-import java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Arc2D;
-import java.awt.geom.Area;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.DataBuffer;
-
-public class BaseCanvas_Delegate {
-    // ---- delegate manager ----
-    protected static DelegateManager<BaseCanvas_Delegate> sManager =
-            new DelegateManager<>(BaseCanvas_Delegate.class);
-
-    // ---- delegate helper data ----
-    private final static boolean[] sBoolOut = new boolean[1];
-
-
-    // ---- delegate data ----
-    protected Bitmap_Delegate mBitmap;
-    protected GcSnapshot mSnapshot;
-
-    // ---- Public Helper methods ----
-
-    protected BaseCanvas_Delegate(Bitmap_Delegate bitmap) {
-        mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap);
-    }
-
-    protected BaseCanvas_Delegate() {
-        mSnapshot = GcSnapshot.createDefaultSnapshot(null /*image*/);
-    }
-
-    /**
-     * Disposes of the {@link Graphics2D} stack.
-     */
-    protected void dispose() {
-        mSnapshot.dispose();
-    }
-
-    /**
-     * Returns the current {@link Graphics2D} used to draw.
-     */
-    public GcSnapshot getSnapshot() {
-        return mSnapshot;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawBitmap(long nativeCanvas, long bitmapHandle, float left, float top,
-            long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity) {
-        // get the delegate from the native int.
-        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmapHandle);
-        if (bitmapDelegate == null) {
-            return;
-        }
-
-        BufferedImage image = bitmapDelegate.getImage();
-        float right = left + image.getWidth();
-        float bottom = top + image.getHeight();
-
-        drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
-                0, 0, image.getWidth(), image.getHeight(),
-                (int)left, (int)top, (int)right, (int)bottom);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawBitmap(long nativeCanvas, long bitmapHandle, float srcLeft,
-            float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, long nativePaintOrZero, int screenDensity,
-            int bitmapDensity) {
-        // get the delegate from the native int.
-        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmapHandle);
-        if (bitmapDelegate == null) {
-            return;
-        }
-
-        drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, (int) srcLeft, (int) srcTop,
-                (int) srcRight, (int) srcBottom, (int) dstLeft, (int) dstTop, (int) dstRight,
-                (int) dstBottom);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawBitmap(long nativeCanvas, int[] colors, int offset, int stride,
-            final float x, final float y, int width, int height, boolean hasAlpha,
-            long nativePaintOrZero) {
-        // create a temp BufferedImage containing the content.
-        final ImagePool.Image image = ImagePoolProvider.get().acquire(width, height,
-                hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
-        image.setRGB(0, 0, width, height, colors, offset, stride);
-
-        draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/,
-                (graphics, paint) -> {
-                    if (paint != null && paint.isFilterBitmap()) {
-                        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
-                                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
-                    }
-
-                    image.drawImage(graphics, (int) x, (int) y, null);
-                });
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawColor(long nativeCanvas, final int color, final int mode) {
-        // get the delegate from the native int.
-        BaseCanvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        final int w = canvasDelegate.mBitmap.getImage().getWidth();
-        final int h = canvasDelegate.mBitmap.getImage().getHeight();
-        draw(nativeCanvas, (graphics, paint) -> {
-            // reset its transform just in case
-            graphics.setTransform(new AffineTransform());
-
-            // set the color
-            graphics.setColor(new java.awt.Color(color, true /*alpha*/));
-
-            Composite composite = PorterDuffUtility.getComposite(
-                    PorterDuffUtility.getPorterDuffMode(mode), 0xFF);
-            if (composite != null) {
-                graphics.setComposite(composite);
-            }
-
-            graphics.fillRect(0, 0, w, h);
-        });
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawColor(long nativeCanvas, long nativeColorSpace, long color,
-            int mode) {
-        nDrawColor(nativeCanvas, Color.toArgb(color), mode);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawPaint(long nativeCanvas, long paint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawPaint is not supported.", null,null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawPoint(long nativeCanvas, float x, float y,
-            long nativePaint) {
-        // TODO: need to support the attribute (e.g. stroke width) of paint
-        draw(nativeCanvas, nativePaint, false /*compositeOnly*/, false /*forceSrcMode*/,
-                (graphics, paintDelegate) -> graphics.fillRect((int)x, (int)y, 1, 1));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawPoints(long nativeCanvas, float[] pts, int offset, int count,
-            long nativePaint) {
-        if (offset < 0 || count < 0 || offset + count > pts.length) {
-            throw new IllegalArgumentException("Invalid argument set");
-        }
-        // ignore the last point if the count is odd (It means it is not paired).
-        count = (count >> 1) << 1;
-        for (int i = offset; i < offset + count; i += 2) {
-            nDrawPoint(nativeCanvas, pts[i], pts[i + 1], nativePaint);
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawLine(long nativeCanvas,
-            final float startX, final float startY, final float stopX, final float stopY,
-            long paint) {
-        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
-                (graphics, paintDelegate) -> graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawLines(long nativeCanvas,
-            final float[] pts, final int offset, final int count,
-            long nativePaint) {
-        draw(nativeCanvas, nativePaint, false /*compositeOnly*/,
-                false /*forceSrcMode*/, (graphics, paintDelegate) -> {
-                    for (int i = 0; i < count; i += 4) {
-                        graphics.drawLine((int) pts[i + offset], (int) pts[i + offset + 1],
-                                (int) pts[i + offset + 2], (int) pts[i + offset + 3]);
-                    }
-                });
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawRect(long nativeCanvas,
-            final float left, final float top, final float right, final float bottom, long paint) {
-
-        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
-                (graphics, paintDelegate) -> {
-                    int style = paintDelegate.getStyle();
-
-                    // draw
-                    if (style == Paint.Style.FILL.nativeInt ||
-                            style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                        graphics.fillRect((int)left, (int)top,
-                                (int)(right-left), (int)(bottom-top));
-                    }
-
-                    if (style == Paint.Style.STROKE.nativeInt ||
-                            style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                        graphics.drawRect((int)left, (int)top,
-                                (int)(right-left), (int)(bottom-top));
-                    }
-                });
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawOval(long nativeCanvas, final float left,
-            final float top, final float right, final float bottom, long paint) {
-        if (right > left && bottom > top) {
-            draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
-                    (graphics, paintDelegate) -> {
-                        int style = paintDelegate.getStyle();
-
-                        // draw
-                        if (style == Paint.Style.FILL.nativeInt ||
-                                style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                            graphics.fillOval((int)left, (int)top,
-                                    (int)(right - left), (int)(bottom - top));
-                        }
-
-                        if (style == Paint.Style.STROKE.nativeInt ||
-                                style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                            graphics.drawOval((int)left, (int)top,
-                                    (int)(right - left), (int)(bottom - top));
-                        }
-                    });
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawCircle(long nativeCanvas,
-            float cx, float cy, float radius, long paint) {
-        nDrawOval(nativeCanvas,
-                cx - radius, cy - radius, cx + radius, cy + radius,
-                paint);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawArc(long nativeCanvas,
-            final float left, final float top, final float right, final float bottom,
-            final float startAngle, final float sweep,
-            final boolean useCenter, long paint) {
-        if (right > left && bottom > top) {
-            draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
-                    (graphics, paintDelegate) -> {
-                        int style = paintDelegate.getStyle();
-
-                        Arc2D.Float arc = new Arc2D.Float(
-                                left, top, right - left, bottom - top,
-                                -startAngle, -sweep,
-                                useCenter ? Arc2D.PIE : Arc2D.OPEN);
-
-                        // draw
-                        if (style == Paint.Style.FILL.nativeInt ||
-                                style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                            graphics.fill(arc);
-                        }
-
-                        if (style == Paint.Style.STROKE.nativeInt ||
-                                style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                            graphics.draw(arc);
-                        }
-                    });
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawRoundRect(long nativeCanvas,
-            final float left, final float top, final float right, final float bottom,
-            final float rx, final float ry, long paint) {
-        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
-                (graphics, paintDelegate) -> {
-                    int style = paintDelegate.getStyle();
-
-                    // draw
-                    if (style == Paint.Style.FILL.nativeInt ||
-                            style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                        graphics.fillRoundRect(
-                                (int)left, (int)top,
-                                (int)(right - left), (int)(bottom - top),
-                                2 * (int)rx, 2 * (int)ry);
-                    }
-
-                    if (style == Paint.Style.STROKE.nativeInt ||
-                            style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                        graphics.drawRoundRect(
-                                (int)left, (int)top,
-                                (int)(right - left), (int)(bottom - top),
-                                2 * (int)rx, 2 * (int)ry);
-                    }
-                });
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawDoubleRoundRect(long nativeCanvas, float outerLeft,
-            float outerTop, float outerRight, float outerBottom, float outerRx, float outerRy,
-            float innerLeft, float innerTop, float innerRight, float innerBottom, float innerRx,
-            float innerRy, long nativePaint) {
-        nDrawDoubleRoundRect(nativeCanvas, outerLeft, outerTop, outerRight, outerBottom,
-                new float[]{outerRx, outerRy, outerRx, outerRy, outerRx, outerRy, outerRx, outerRy},
-                innerLeft, innerTop, innerRight, innerBottom,
-                new float[]{innerRx, innerRy, innerRx, innerRy, innerRx, innerRy, innerRx, innerRy},
-                nativePaint);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawDoubleRoundRect(long nativeCanvas, float outerLeft,
-            float outerTop, float outerRight, float outerBottom, float[] outerRadii,
-            float innerLeft, float innerTop, float innerRight, float innerBottom,
-            float[] innerRadii, long nativePaint) {
-        draw(nativeCanvas, nativePaint, false /*compositeOnly*/, false /*forceSrcMode*/,
-                (graphics, paintDelegate) -> {
-                    RoundRectangle innerRect = new RoundRectangle(innerLeft, innerTop,
-                            innerRight - innerLeft, innerBottom - innerTop, innerRadii);
-                    RoundRectangle outerRect = new RoundRectangle(outerLeft, outerTop,
-                            outerRight - outerLeft, outerBottom - outerTop, outerRadii);
-
-                    int style = paintDelegate.getStyle();
-
-                    // draw
-                    if (style == Paint.Style.STROKE.nativeInt ||
-                            style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                        graphics.draw(innerRect);
-                        graphics.draw(outerRect);
-                    }
-
-                    if (style == Paint.Style.FILL.nativeInt ||
-                            style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                        Area outerArea = new Area(outerRect);
-                        Area innerArea = new Area(innerRect);
-                        outerArea.subtract(innerArea);
-                        graphics.fill(outerArea);
-                    }
-                });
-    }
-
-    @LayoutlibDelegate
-    public static void nDrawPath(long nativeCanvas, long path, long paint) {
-        final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
-                (graphics, paintDelegate) -> {
-                    Shape shape = pathDelegate.getJavaShape();
-                    Rectangle2D bounds = shape.getBounds2D();
-                    if (bounds.isEmpty()) {
-                        // Apple JRE 1.6 doesn't like drawing empty shapes.
-                        // http://b.android.com/178278
-
-                        if (pathDelegate.isEmpty()) {
-                            // This means that the path doesn't have any lines or curves so
-                            // nothing to draw.
-                            return;
-                        }
-
-                        // The stroke width is not consider for the size of the bounds so,
-                        // for example, a horizontal line, would be considered as an empty
-                        // rectangle.
-                        // If the strokeWidth is not 0, we use it to consider the size of the
-                        // path as well.
-                        float strokeWidth = paintDelegate.getStrokeWidth();
-                        if (strokeWidth <= 0.0f) {
-                            return;
-                        }
-                        bounds.setRect(bounds.getX(), bounds.getY(),
-                                Math.max(strokeWidth, bounds.getWidth()),
-                                Math.max(strokeWidth, bounds.getHeight()));
-                    }
-
-                    int style = paintDelegate.getStyle();
-
-                    if (style == Paint.Style.FILL.nativeInt ||
-                            style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                        graphics.fill(shape);
-                    }
-
-                    if (style == Paint.Style.STROKE.nativeInt ||
-                            style == Paint.Style.FILL_AND_STROKE.nativeInt) {
-                        graphics.draw(shape);
-                    }
-                });
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawRegion(long nativeCanvas, long nativeRegion,
-            long nativePaint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Some canvas paths may not be drawn", null, null, null);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawNinePatch(long nativeCanvas, long nativeBitmap, long ninePatch,
-            final float dstLeft, final float dstTop, final float dstRight, final float dstBottom,
-            long nativePaintOrZero, final int screenDensity, final int bitmapDensity) {
-
-        // get the delegate from the native int.
-        final Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmap);
-        if (bitmapDelegate == null) {
-            return;
-        }
-
-        byte[] c = NinePatch_Delegate.getChunk(ninePatch);
-        if (c == null) {
-            // not a 9-patch?
-            BufferedImage image = bitmapDelegate.getImage();
-            drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero, 0, 0, image.getWidth(),
-                    image.getHeight(), (int) dstLeft, (int) dstTop, (int) dstRight,
-                    (int) dstBottom);
-            return;
-        }
-
-        final NinePatchChunk chunkObject = NinePatch_Delegate.getChunk(c);
-        if (chunkObject == null) {
-            return;
-        }
-
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        // this one can be null
-        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);
-
-        canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() {
-            @Override
-            public void draw(Graphics2D graphics, Paint_Delegate paint) {
-                chunkObject.draw(bitmapDelegate.getImage(), graphics, (int) dstLeft, (int) dstTop,
-                        (int) (dstRight - dstLeft), (int) (dstBottom - dstTop), screenDensity,
-                        bitmapDensity);
-            }
-        }, paintDelegate, true, false);
-
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawBitmapMatrix(long nCanvas, long bitmapHandle,
-            long nMatrix, long nPaint) {
-        // get the delegate from the native int.
-        BaseCanvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        // get the delegate from the native int, which can be null
-        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
-
-        // get the delegate from the native int.
-        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmapHandle);
-        if (bitmapDelegate == null) {
-            return;
-        }
-
-        final BufferedImage image = getImageToDraw(bitmapDelegate, paintDelegate, sBoolOut);
-
-        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
-        if (matrixDelegate == null) {
-            return;
-        }
-
-        final AffineTransform mtx = matrixDelegate.getAffineTransform();
-
-        canvasDelegate.getSnapshot().draw((graphics, paint) -> {
-            if (paint != null && paint.isFilterBitmap()) {
-                graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
-                        RenderingHints.VALUE_INTERPOLATION_BILINEAR);
-            }
-
-            //FIXME add support for canvas, screen and bitmap densities.
-            graphics.drawImage(image, mtx, null);
-        }, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawBitmapMesh(long nCanvas, long bitmapHandle,
-            int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors,
-            int colorOffset, long nPaint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawBitmapMesh is not supported.", null, null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawVertices(long nCanvas, int mode, int n,
-            float[] verts, int vertOffset,
-            float[] texs, int texOffset,
-            int[] colors, int colorOffset,
-            short[] indices, int indexOffset,
-            int indexCount, long nPaint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawVertices is not supported.", null, null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawText(long nativeCanvas, char[] text, int index, int count,
-            float startX, float startY, int flags, long paint) {
-        drawText(nativeCanvas, text, index, count, startX, startY, flags,
-                paint);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawText(long nativeCanvas, String text,
-            int start, int end, float x, float y, final int flags, long paint) {
-        int count = end - start;
-        char[] buffer = TemporaryBuffer.obtain(count);
-        TextUtils.getChars(text, start, end, buffer, 0);
-
-        nDrawText(nativeCanvas, buffer, 0, count, x, y, flags, paint);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawTextRun(long nativeCanvas, String text,
-            int start, int end, int contextStart, int contextEnd,
-            float x, float y, boolean isRtl, long paint) {
-        int count = end - start;
-        char[] buffer = TemporaryBuffer.obtain(count);
-        TextUtils.getChars(text, start, end, buffer, 0);
-
-        drawText(nativeCanvas, buffer, 0, count, x, y, isRtl ? Paint.BIDI_RTL : Paint.BIDI_LTR,
-                paint);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawTextRun(long nativeCanvas, char[] text,
-            int start, int count, int contextStart, int contextCount,
-            float x, float y, boolean isRtl, long paint,
-            long nativeMeasuredText) {
-        drawText(nativeCanvas, text, start, count, x, y, isRtl ? Paint.BIDI_RTL : Paint.BIDI_LTR, paint);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawTextOnPath(long nativeCanvas,
-            char[] text, int index,
-            int count, long path,
-            float hOffset,
-            float vOffset, int bidiFlags,
-            long paint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawTextOnPath is not supported.", null, null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nDrawTextOnPath(long nativeCanvas,
-            String text, long path,
-            float hOffset,
-            float vOffset,
-            int bidiFlags, long paint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawTextOnPath is not supported.", null, null, null /*data*/);
-    }
-
-    // ---- Private delegate/helper methods ----
-
-    /**
-     * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint.
-     * <p>Note that the drawable may actually be executed several times if there are
-     * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}.
-     */
-    private static void draw(long nCanvas, long nPaint, boolean compositeOnly, boolean forceSrcMode,
-            GcSnapshot.Drawable drawable) {
-        // get the delegate from the native int.
-        BaseCanvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        // get the paint which can be null if nPaint is 0;
-        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
-
-        canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode);
-    }
-
-    /**
-     * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided
-     * to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}.
-     * <p>Note that the drawable may actually be executed several times if there are
-     * layers involved (see {@link #saveLayer(RectF, Paint_Delegate, int)}.
-     */
-    private static void draw(long nCanvas, GcSnapshot.Drawable drawable) {
-        // get the delegate from the native int.
-        BaseCanvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        canvasDelegate.mSnapshot.draw(drawable);
-    }
-
-    private static void drawText(long nativeCanvas, final char[] text, final int index,
-            final int count, final float startX, final float startY, final int bidiFlags,
-            long paint) {
-
-        draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
-                (graphics, paintDelegate) -> {
-                    // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
-                    // Any change to this method should be reflected in Paint.measureText
-
-                    // Paint.TextAlign indicates how the text is positioned relative to X.
-                    // LEFT is the default and there's nothing to do.
-                    float x = startX;
-                    int limit = index + count;
-                    if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
-                        RectF bounds =
-                                paintDelegate.measureText(text, index, count, null, 0, bidiFlags);
-                        float m = bounds.right - bounds.left;
-                        if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
-                            x -= m / 2;
-                        } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
-                            x -= m;
-                        }
-                    }
-
-                    new BidiRenderer(graphics, paintDelegate, text).setRenderLocation(x,
-                            startY).renderText(index, limit, bidiFlags, null, 0, true);
-                });
-    }
-
-    private static void drawBitmap(long nativeCanvas, Bitmap_Delegate bitmap,
-            long nativePaintOrZero, final int sleft, final int stop, final int sright,
-            final int sbottom, final int dleft, final int dtop, final int dright,
-            final int dbottom) {
-        // get the delegate from the native int.
-        BaseCanvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        // get the paint, which could be null if the int is 0
-        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);
-
-        final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut);
-
-        draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0],
-                (graphics, paint) -> {
-                    if (paint != null && paint.isFilterBitmap()) {
-                        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
-                                RenderingHints.VALUE_INTERPOLATION_BILINEAR);
-                    }
-
-                    //FIXME add support for canvas, screen and bitmap densities.
-                    graphics.drawImage(image, dleft, dtop, dright, dbottom, sleft, stop, sright,
-                            sbottom, null);
-                });
-    }
-
-    /**
-     * Returns a BufferedImage ready for drawing, based on the bitmap and paint delegate.
-     * The image returns, through a 1-size boolean array, whether the drawing code should
-     * use a SRC composite no matter what the paint says.
-     *
-     * @param bitmap the bitmap
-     * @param paint the paint that will be used to draw
-     * @param forceSrcMode whether the composite will have to be SRC
-     * @return the image to draw
-     */
-    private static BufferedImage getImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint,
-            boolean[] forceSrcMode) {
-        BufferedImage image = bitmap.getImage();
-        forceSrcMode[0] = false;
-
-        // if the bitmap config is alpha_8, then we erase all color value from it
-        // before drawing it or apply the texture from the shader if present.
-        if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) {
-            Shader_Delegate shader = paint.getShader();
-            java.awt.Paint javaPaint = null;
-            if (shader instanceof BitmapShader_Delegate) {
-                javaPaint = shader.getJavaPaint();
-            }
-
-            fixAlpha8Bitmap(image, javaPaint);
-        } else if (!bitmap.hasAlpha()) {
-            // hasAlpha is merely a rendering hint. There can in fact be alpha values
-            // in the bitmap but it should be ignored at drawing time.
-            // There is two ways to do this:
-            // - override the composite to be SRC. This can only be used if the composite
-            //   was going to be SRC or SRC_OVER in the first place
-            // - Create a different bitmap to draw in which all the alpha channel values is set
-            //   to 0xFF.
-            if (paint != null) {
-                PorterDuff.Mode mode = PorterDuff.intToMode(paint.getPorterDuffMode());
-
-                forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER || mode == PorterDuff.Mode.SRC;
-            }
-
-            // if we can't force SRC mode, then create a temp bitmap of TYPE_RGB
-            if (!forceSrcMode[0]) {
-                image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF);
-            }
-        }
-
-        return image;
-    }
-
-    /**
-     * This method will apply the correct color to the passed "only alpha" image. Colors on the
-     * passed image will be destroyed.
-     * If the passed javaPaint is null, the color will be set to 0. If a paint is passed, it will
-     * be used to obtain the color that will be applied.
-     * <p/>
-     * This will destroy the passed image color channel.
-     */
-    private static void fixAlpha8Bitmap(final BufferedImage image,
-            @Nullable java.awt.Paint javaPaint) {
-        int w = image.getWidth();
-        int h = image.getHeight();
-
-        DataBuffer texture = null;
-        if (javaPaint != null) {
-            PaintContext context = javaPaint.createContext(ColorModel.getRGBdefault(), null, null,
-                    new AffineTransform(), null);
-            texture = context.getRaster(0, 0, w, h).getDataBuffer();
-        }
-
-        int[] argb = new int[w * h];
-        image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
-
-        final int length = argb.length;
-        for (int i = 0; i < length; i++) {
-            argb[i] &= 0xFF000000;
-            if (texture != null) {
-                argb[i] |= texture.getElem(i) & 0x00FFFFFF;
-            }
-        }
-
-        image.setRGB(0, 0, w, h, argb, 0, w);
-    }
-
-    protected int save(int saveFlags) {
-        // get the current save count
-        int count = mSnapshot.size();
-
-        mSnapshot = mSnapshot.save(saveFlags);
-
-        // return the old save count
-        return count;
-    }
-
-    protected int saveLayerAlpha(RectF rect, int alpha, int saveFlags) {
-        Paint_Delegate paint = new Paint_Delegate();
-        paint.setAlpha(alpha);
-        return saveLayer(rect, paint, saveFlags);
-    }
-
-    protected int saveLayer(RectF rect, Paint_Delegate paint, int saveFlags) {
-        // get the current save count
-        int count = mSnapshot.size();
-
-        mSnapshot = mSnapshot.saveLayer(rect, paint, saveFlags);
-
-        // return the old save count
-        return count;
-    }
-
-    /**
-     * Restores the {@link GcSnapshot} to <var>saveCount</var>
-     * @param saveCount the saveCount
-     */
-    protected void restoreTo(int saveCount) {
-        mSnapshot = mSnapshot.restoreTo(saveCount);
-    }
-
-    /**
-     * Restores the top {@link GcSnapshot}
-     */
-    protected void restore() {
-        mSnapshot = mSnapshot.restore();
-    }
-
-    protected boolean clipRect(float left, float top, float right, float bottom, int regionOp) {
-        return mSnapshot.clipRect(left, top, right, bottom, regionOp);
-    }
-}
diff --git a/bridge/src/android/graphics/BidiRenderer.java b/bridge/src/android/graphics/BidiRenderer.java
deleted file mode 100644
index 40d350b..0000000
--- a/bridge/src/android/graphics/BidiRenderer.java
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.Paint_Delegate.FontInfo;
-import android.icu.lang.UScriptRun;
-import android.icu.text.Bidi;
-import android.icu.text.BidiRun;
-
-import java.awt.Font;
-import java.awt.Graphics2D;
-import java.awt.Toolkit;
-import java.awt.font.FontRenderContext;
-import java.awt.font.GlyphVector;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Render the text by breaking it into various scripts and using the right font for each script.
- * Can be used to measure the text without actually drawing it.
- */
-@SuppressWarnings("deprecation")
-public class BidiRenderer {
-    private static final String JETBRAINS_VENDOR_ID = "JetBrains s.r.o";
-    private static final String JAVA_VENDOR = System.getProperty("java.vendor");
-    /** When scaleX is bigger than this, we need to apply the workaround for http://b.android.com/211659 */
-    private static final double SCALEX_WORKAROUND_LIMIT = 9;
-
-    private static class ScriptRun {
-        private final int start;
-        private final int limit;
-        private final Font font;
-
-        private ScriptRun(int start, int limit, @NonNull Font font) {
-            this.start = start;
-            this.limit = limit;
-            this.font = font;
-        }
-    }
-
-    private final Graphics2D mGraphics;
-    private final Paint_Delegate mPaint;
-    private char[] mText;
-    // Bounds of the text drawn so far.
-    private RectF mBounds;
-    private float mBaseline;
-    private final Bidi mBidi = new Bidi();
-
-
-    /**
-     * @param graphics May be null.
-     * @param paint The Paint to use to get the fonts. Should not be null.
-     * @param text Unidirectional text. Should not be null.
-     */
-    public BidiRenderer(Graphics2D graphics, Paint_Delegate paint, char[] text) {
-        assert (paint != null);
-        mGraphics = graphics;
-        mPaint = paint;
-        mText = text;
-        mBounds = new RectF();
-    }
-
-    /**
-     *
-     * @param x The x-coordinate of the left edge of where the text should be drawn on the given
-     *            graphics.
-     * @param y The y-coordinate at which to draw the text on the given mGraphics.
-     *
-     */
-    public BidiRenderer setRenderLocation(float x, float y) {
-        mBounds.set(x, y, x, y);
-        mBaseline = y;
-        return this;
-    }
-
-    /**
-     * Perform Bidi Analysis on the text and then render it.
-     * <p/>
-     * To skip the analysis and render unidirectional text, see {@link
-     * #renderText(int, int, boolean, float[], int, boolean)}
-     */
-    public RectF renderText(int start, int limit, int bidiFlags, float[] advances,
-            int advancesIndex, boolean draw) {
-        mBidi.setPara(Arrays.copyOfRange(mText, start, limit), (byte)getIcuFlags(bidiFlags), null);
-        mText = mBidi.getText();
-        for (int i = 0; i < mBidi.countRuns(); i++) {
-            BidiRun visualRun = mBidi.getVisualRun(i);
-            boolean isRtl = visualRun.getDirection() == Bidi.RTL;
-            renderText(visualRun.getStart(), visualRun.getLimit(), isRtl, advances,
-                    advancesIndex, draw);
-        }
-        return mBounds;
-    }
-
-    /**
-     * Render unidirectional text.
-     * <p/>
-     * This method can also be used to measure the width of the text without actually drawing it.
-     * <p/>
-     * @param start index of the first character
-     * @param limit index of the first character that should not be rendered.
-     * @param isRtl is the text right-to-left
-     * @param advances If not null, then advances for each character to be rendered are returned
-     *            here.
-     * @param advancesIndex index into advances from where the advances need to be filled.
-     * @param draw If true and {@code graphics} is not null, draw the rendered text on the graphics
-     *            at the given co-ordinates
-     * @return A rectangle specifying the bounds of the text drawn.
-     */
-    public RectF renderText(int start, int limit, boolean isRtl, float[] advances,
-            int advancesIndex, boolean draw) {
-        // We break the text into scripts and then select font based on it and then render each of
-        // the script runs.
-        for (ScriptRun run : getScriptRuns(mText, start, limit, mPaint.getFonts())) {
-            int flag = Font.LAYOUT_NO_LIMIT_CONTEXT | Font.LAYOUT_NO_START_CONTEXT;
-            flag |= isRtl ? Font.LAYOUT_RIGHT_TO_LEFT : Font.LAYOUT_LEFT_TO_RIGHT;
-            renderScript(run.start, run.limit, run.font, flag, advances, advancesIndex, draw);
-            advancesIndex += run.limit - run.start;
-        }
-        return mBounds;
-    }
-
-    /**
-     * Render a script run to the right of the bounds passed. Use the preferred font to render as
-     * much as possible. This also implements a fallback mechanism to render characters that cannot
-     * be drawn using the preferred font.
-     */
-    private void renderScript(int start, int limit, Font preferredFont, int flag,
-            float[] advances, int advancesIndex, boolean draw) {
-        if (mPaint.getFonts().size() == 0 || preferredFont == null) {
-            return;
-        }
-
-        while (start < limit) {
-            int canDisplayUpTo = preferredFont.canDisplayUpTo(mText, start, limit);
-            if (canDisplayUpTo == -1) {
-                // We can draw all characters in the text.
-                render(start, limit, preferredFont, flag, advances, advancesIndex, draw);
-                return;
-            }
-            if (canDisplayUpTo > start) {
-                // We can draw something.
-                render(start, canDisplayUpTo, preferredFont, flag, advances, advancesIndex, draw);
-                advancesIndex += canDisplayUpTo - start;
-                start = canDisplayUpTo;
-            } else {
-                // We can display everything with the preferred font. Search for the font that
-                // allows us to display the maximum number of chars
-                List<FontInfo> fontInfos = mPaint.getFonts();
-                Font bestFont = null;
-                int highestUpTo = canDisplayUpTo;
-                //noinspection ForLoopReplaceableByForEach
-                for (int i = 0; i < fontInfos.size(); i++) {
-                    Font font = fontInfos.get(i).mFont;
-
-                    if (preferredFont == font) {
-                        // We know this font won't work since we've already tested it at the
-                        // beginning of the loop
-                        continue;
-                    }
-
-                    if (font == null) {
-                        logFontWarning();
-                        continue;
-                    }
-
-                    canDisplayUpTo = font.canDisplayUpTo(mText, start, limit);
-                    if (canDisplayUpTo == -1) {
-                        // This font can dis
-                        highestUpTo = limit;
-                        bestFont = font;
-                        break;
-                    } else if (canDisplayUpTo > highestUpTo) {
-                        highestUpTo = canDisplayUpTo;
-                        bestFont = font;
-                        // Keep searching in case there is a font that allows to display even
-                        // more text
-                    }
-                }
-
-                if (bestFont != null) {
-                    render(start, highestUpTo, bestFont, flag, advances, advancesIndex, draw);
-                    advancesIndex += highestUpTo - start;
-                    start = highestUpTo;
-                } else {
-                    int charCount = Character.isHighSurrogate(mText[start]) ? 2 : 1;
-
-                    // No font can display this char. Use the preferred font and skip this char.
-                    // The char will most probably appear as a box or a blank space. We could,
-                    // probably, use some heuristics and break the character into the base
-                    // character and diacritics and then draw it, but it's probably not worth the
-                    // effort.
-                    render(start, start + charCount, preferredFont, flag, advances, advancesIndex,
-                            draw);
-                    start += charCount;
-                    advancesIndex += charCount;
-                }
-            }
-        }
-    }
-
-    private static void logFontWarning() {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_BROKEN,
-                "Some fonts could not be loaded. The rendering may not be perfect.", null, null,
-                null);
-    }
-
-    /**
-     * Renders the text to the right of the bounds with the given font.
-     * @param font The font to render the text with.
-     */
-    private void render(int start, int limit, Font font, int flag, float[] advances,
-            int advancesIndex, boolean draw) {
-        FontRenderContext frc = mGraphics != null ? mGraphics.getFontRenderContext() :
-                    Toolkit.getDefaultToolkit().getFontMetrics(font).getFontRenderContext();
-
-        boolean frcIsAntialiased = frc.isAntiAliased();
-        boolean useAntialiasing = mPaint.isAntiAliased();
-
-        if (frcIsAntialiased) {
-            if (!useAntialiasing) {
-                // The context has antialiasing enabled but the paint does not. We need to
-                // disable it
-                frc = new FontRenderContext(font.getTransform(), false,
-                        frc.usesFractionalMetrics());
-            } else {
-                // In this case both the paint and the context antialising match but we need
-                // to check for a bug in the JDK
-                // Workaround for http://b.android.com/211659 (disable antialiasing)
-                if (font.isTransformed()) {
-                    AffineTransform transform = font.getTransform();
-                    if (transform.getScaleX() >= SCALEX_WORKAROUND_LIMIT &&
-                            JETBRAINS_VENDOR_ID.equals(JAVA_VENDOR)) {
-                        frc = new FontRenderContext(transform, false, frc.usesFractionalMetrics());
-                    }
-                }
-            }
-        } else if (useAntialiasing) {
-            // The context does not have antialiasing enabled but the paint does. We need to
-            // enable it unless we need to avoid the JDK bug
-
-            AffineTransform transform = font.getTransform();
-            // Workaround for http://b.android.com/211659 (disable antialiasing)
-            if (transform.getScaleX() < SCALEX_WORKAROUND_LIMIT ||
-                    !JETBRAINS_VENDOR_ID.equals(JAVA_VENDOR)) {
-                frc = new FontRenderContext(font.getTransform(), true, frc.usesFractionalMetrics());
-            }
-        }
-
-        GlyphVector gv = font.layoutGlyphVector(frc, mText, start, limit, flag);
-        int ng = gv.getNumGlyphs();
-        int[] ci = gv.getGlyphCharIndices(0, ng, null);
-        if (advances != null) {
-            for (int i = 0; i < ng; i++) {
-                if (mText[ci[i]] == '\uFEFF') {
-                    // Workaround for bug in JetBrains JDK
-                    // where the character \uFEFF is associated a glyph with non-zero width
-                    continue;
-                }
-                int adv_idx = advancesIndex + ci[i];
-                advances[adv_idx] += gv.getGlyphMetrics(i).getAdvanceX();
-            }
-        }
-        if (draw && mGraphics != null) {
-            mGraphics.drawGlyphVector(gv, mBounds.right, mBaseline);
-        }
-
-        // Update the bounds.
-        Rectangle2D awtBounds = gv.getLogicalBounds();
-        // If the width of the bounds is zero, no text had been drawn earlier. Hence, use the
-        // coordinates from the bounds as an offset.
-        if (Math.abs(mBounds.right - mBounds.left) == 0) {
-            mBounds = awtRectToAndroidRect(awtBounds, mBounds.right, mBaseline, mBounds);
-        } else {
-            mBounds.union(awtRectToAndroidRect(awtBounds, mBounds.right, mBaseline, null));
-        }
-    }
-
-    // --- Static helper methods ---
-
-    private static RectF awtRectToAndroidRect(Rectangle2D awtRec, float offsetX, float offsetY,
-            @Nullable RectF destination) {
-        float left = (float) awtRec.getX();
-        float top = (float) awtRec.getY();
-        float right = (float) (left + awtRec.getWidth());
-        float bottom = (float) (top + awtRec.getHeight());
-        if (destination != null) {
-            destination.set(left, top, right, bottom);
-        } else {
-            destination = new RectF(left, top, right, bottom);
-        }
-        destination.offset(offsetX, offsetY);
-        return destination;
-    }
-
-    private static List<ScriptRun> getScriptRuns(char[] text, int start, int limit, List<FontInfo> fonts) {
-        LinkedList<ScriptRun> scriptRuns = new LinkedList<>();
-
-        int count = limit - start;
-        UScriptRun uScriptRun = new UScriptRun(text, start, count);
-        while (uScriptRun.next()) {
-            int scriptStart = uScriptRun.getScriptStart();
-            int scriptLimit = uScriptRun.getScriptLimit();
-            ScriptRun run = new ScriptRun(
-                    scriptStart, scriptLimit,
-                    getScriptFont(text, scriptStart, scriptLimit, fonts));
-            scriptRuns.add(run);
-        }
-        return scriptRuns;
-    }
-
-    // TODO: Replace this method with one which returns the font based on the scriptCode.
-    @NonNull
-    private static Font getScriptFont(char[] text, int start, int limit, List<FontInfo> fonts) {
-        if (fonts.isEmpty()) {
-            logFontWarning();
-            // Fallback font in case no font can be loaded
-            return Font.getFont(Font.SERIF);
-        }
-
-        // From all the fonts, select the one that can display the highest number of characters
-        Font bestFont = fonts.get(0).mFont;
-        int bestFontCount = 0;
-        for (FontInfo fontInfo : fonts) {
-            int count = fontInfo.mFont.canDisplayUpTo(text, start, limit);
-            if (count == -1) {
-                // This font can display everything, return this one
-                return fontInfo.mFont;
-            }
-
-            if (count > bestFontCount) {
-                bestFontCount = count;
-                bestFont = fontInfo.mFont;
-            }
-        }
-
-        return bestFont;
-    }
-
-    private static int getIcuFlags(int bidiFlag) {
-        switch (bidiFlag) {
-            case Paint.BIDI_LTR:
-            case Paint.BIDI_FORCE_LTR:
-                return Bidi.DIRECTION_LEFT_TO_RIGHT;
-            case Paint.BIDI_RTL:
-            case Paint.BIDI_FORCE_RTL:
-                return Bidi.DIRECTION_RIGHT_TO_LEFT;
-            case Paint.BIDI_DEFAULT_LTR:
-                return Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
-            case Paint.BIDI_DEFAULT_RTL:
-                return Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT;
-            default:
-                assert false;
-                return Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/BitmapFactory_Delegate.java b/bridge/src/android/graphics/BitmapFactory_Delegate.java
deleted file mode 100644
index 7a12d38..0000000
--- a/bridge/src/android/graphics/BitmapFactory_Delegate.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.ninepatch.NinePatchChunk;
-import com.android.resources.Density;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.Nullable;
-import com.android.layoutlib.bridge.util.NinePatchInputStream;
-import android.graphics.BitmapFactory.Options;
-import android.graphics.Bitmap_Delegate.BitmapCreateFlags;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.EnumSet;
-import java.util.Set;
-
-/**
- * Delegate implementing the native methods of android.graphics.BitmapFactory
- *
- * Through the layoutlib_create tool, the original native methods of BitmapFactory have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
- * around to map int to instance of the delegate.
- *
- */
-/*package*/ class BitmapFactory_Delegate {
-
-    // ------ Native Delegates ------
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage,
-            @Nullable Rect padding, @Nullable Options opts, long inBitmapHandle,
-            long colorSpaceHandle) {
-        Bitmap bm = null;
-
-        Density density = Density.MEDIUM;
-        Set<BitmapCreateFlags> bitmapCreateFlags = EnumSet.of(BitmapCreateFlags.MUTABLE);
-        if (opts != null) {
-            density = Density.getEnum(opts.inDensity);
-            if (opts.inPremultiplied) {
-                bitmapCreateFlags.add(BitmapCreateFlags.PREMULTIPLIED);
-            }
-            opts.inScaled = false;
-        }
-
-        try {
-            if (is instanceof NinePatchInputStream) {
-                NinePatchInputStream npis = (NinePatchInputStream) is;
-                npis.disableFakeMarkSupport();
-
-                // load the bitmap as a nine patch
-                com.android.ninepatch.NinePatch ninePatch = com.android.ninepatch.NinePatch.load(
-                        npis, true /*is9Patch*/, false /*convert*/);
-
-                // get the bitmap and chunk objects.
-                NinePatchChunk chunk = ninePatch.getChunk();
-                bm = Bitmap_Delegate.createBitmap(ninePatch.getImage(),
-                        NinePatch_Delegate.serialize(chunk), bitmapCreateFlags, density);
-
-                if (padding != null) {
-                    // read the padding
-                    int[] paddingArray = chunk.getPadding();
-                    padding.left = paddingArray[0];
-                    padding.top = paddingArray[1];
-                    padding.right = paddingArray[2];
-                    padding.bottom = paddingArray[3];
-                }
-            } else {
-                // load the bitmap directly.
-                bm = Bitmap_Delegate.createBitmap(is, bitmapCreateFlags, density);
-            }
-        } catch (IOException e) {
-            Bridge.getLog().error(null, "Failed to load image", e, null, null);
-        }
-
-        return bm;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
-            Rect padding, Options opts, long inBitmapHandle, long colorSpaceHandle) {
-        if (opts != null) {
-            opts.inBitmap = null;
-        }
-        return null;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeDecodeAsset(long asset, Rect padding, Options opts,
-            long inBitmapHandle, long colorSpaceHandle) {
-        if (opts != null) {
-            opts.inBitmap = null;
-        }
-        return null;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeDecodeByteArray(byte[] data, int offset,
-            int length, Options opts, long inBitmapHandle, long colorSpaceHandle) {
-        if (opts != null) {
-            opts.inBitmap = null;
-        }
-        return null;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeIsSeekable(FileDescriptor fd) {
-        return true;
-    }
-
-    /**
-     * Set the newly decoded bitmap's density based on the Options.
-     *
-     * Copied from {@link BitmapFactory#setDensityFromOptions(Bitmap, Options)}.
-     */
-    @LayoutlibDelegate
-    /*package*/ static void setDensityFromOptions(Bitmap outputBitmap, Options opts) {
-        if (outputBitmap == null || opts == null) return;
-
-        final int density = opts.inDensity;
-        if (density != 0) {
-            outputBitmap.setDensity(density);
-            final int targetDensity = opts.inTargetDensity;
-            if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
-                return;
-            }
-
-            // --- Change from original implementation begins ---
-            // LayoutLib doesn't scale the nine patch when decoding it. Hence, don't change the
-            // density of the source bitmap in case of ninepatch.
-
-            if (opts.inScaled) {
-            // --- Change from original implementation ends. ---
-                outputBitmap.setDensity(targetDensity);
-            }
-        } else if (opts.inBitmap != null) {
-            // bitmap was reused, ensure density is reset
-            outputBitmap.setDensity(Bitmap.getDefaultDensity());
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/BitmapShader_Delegate.java b/bridge/src/android/graphics/BitmapShader_Delegate.java
deleted file mode 100644
index e763824..0000000
--- a/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.Shader.TileMode;
-
-import java.awt.PaintContext;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.NoninvertibleTransformException;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.ColorModel;
-import java.awt.image.DataBufferInt;
-import java.awt.image.Raster;
-import java.awt.image.SampleModel;
-
-/**
- * Delegate implementing the native methods of android.graphics.BitmapShader
- *
- * Through the layoutlib_create tool, the original native methods of BitmapShader have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original BitmapShader class.
- *
- * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
- * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
- *
- * @see Shader_Delegate
- *
- */
-public class BitmapShader_Delegate extends Shader_Delegate {
-
-    // ---- delegate data ----
-    private java.awt.Paint mJavaPaint;
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public java.awt.Paint getJavaPaint() {
-        return mJavaPaint;
-    }
-
-    @Override
-    public boolean isSupported() {
-        return true;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        // no message since isSupported returns true;
-        return null;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(long nativeMatrix, long bitmapHandle,
-            int shaderTileModeX, int shaderTileModeY) {
-        Bitmap_Delegate bitmap = Bitmap_Delegate.getDelegate(bitmapHandle);
-        if (bitmap == null) {
-            return 0;
-        }
-
-        BitmapShader_Delegate newDelegate = new BitmapShader_Delegate(nativeMatrix,
-                bitmap.getImage(),
-                Shader_Delegate.getTileMode(shaderTileModeX),
-                Shader_Delegate.getTileMode(shaderTileModeY));
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-
-    private BitmapShader_Delegate(long matrix, BufferedImage image,
-            TileMode tileModeX, TileMode tileModeY) {
-        super(matrix);
-        mJavaPaint = new BitmapShaderPaint(image, tileModeX, tileModeY);
-    }
-
-    private class BitmapShaderPaint implements java.awt.Paint {
-        private final BufferedImage mImage;
-        private final TileMode mTileModeX;
-        private final TileMode mTileModeY;
-
-        BitmapShaderPaint(BufferedImage image,
-                TileMode tileModeX, TileMode tileModeY) {
-            mImage = image;
-            mTileModeX = tileModeX;
-            mTileModeY = tileModeY;
-        }
-
-        @Override
-        public PaintContext createContext(ColorModel colorModel, Rectangle deviceBounds,
-                Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) {
-            AffineTransform canvasMatrix;
-            try {
-                canvasMatrix = xform.createInverse();
-            } catch (NoninvertibleTransformException e) {
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in BitmapShader", e, null, null /*data*/);
-                canvasMatrix = new AffineTransform();
-            }
-
-            AffineTransform localMatrix = getLocalMatrix();
-            try {
-                localMatrix = localMatrix.createInverse();
-            } catch (NoninvertibleTransformException e) {
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in BitmapShader", e, null, null /*data*/);
-                localMatrix = new AffineTransform();
-            }
-
-            if (!colorModel.isCompatibleRaster(mImage.getRaster())) {
-                // Fallback to the default ARGB color model
-                colorModel = ColorModel.getRGBdefault();
-            }
-
-            return new BitmapShaderContext(canvasMatrix, localMatrix, colorModel);
-        }
-
-        private class BitmapShaderContext implements PaintContext {
-
-            private final AffineTransform mCanvasMatrix;
-            private final AffineTransform mLocalMatrix;
-            private final ColorModel mColorModel;
-
-            public BitmapShaderContext(
-                    AffineTransform canvasMatrix,
-                    AffineTransform localMatrix,
-                    ColorModel colorModel) {
-                mCanvasMatrix = canvasMatrix;
-                mLocalMatrix = localMatrix;
-                mColorModel = colorModel;
-            }
-
-            @Override
-            public void dispose() {
-            }
-
-            @Override
-            public ColorModel getColorModel() {
-                return mColorModel;
-            }
-
-            @Override
-            public Raster getRaster(int x, int y, int w, int h) {
-                BufferedImage image = new BufferedImage(
-                    mColorModel, mColorModel.createCompatibleWritableRaster(w, h),
-                    mColorModel.isAlphaPremultiplied(), null);
-
-                int[] data = new int[w*h];
-
-                int index = 0;
-                float[] pt1 = new float[2];
-                float[] pt2 = new float[2];
-                for (int iy = 0 ; iy < h ; iy++) {
-                    for (int ix = 0 ; ix < w ; ix++) {
-                        // handle the canvas transform
-                        pt1[0] = x + ix;
-                        pt1[1] = y + iy;
-                        mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
-
-                        // handle the local matrix.
-                        pt1[0] = pt2[0];
-                        pt1[1] = pt2[1];
-                        mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
-
-                        data[index++] = getColor(pt2[0], pt2[1]);
-                    }
-                }
-
-                DataBufferInt dataBuffer = new DataBufferInt(data, data.length);
-                SampleModel colorModel = mColorModel.createCompatibleSampleModel(w, h);
-                return Raster.createWritableRaster(colorModel, dataBuffer, null);
-            }
-        }
-
-        /**
-         * Returns a color for an arbitrary point.
-         */
-        private int getColor(float fx, float fy) {
-            int x = getCoordinate(Math.round(fx), mImage.getWidth(), mTileModeX);
-            int y = getCoordinate(Math.round(fy), mImage.getHeight(), mTileModeY);
-
-            return mImage.getRGB(x, y);
-        }
-
-        private int getCoordinate(int i, int size, TileMode mode) {
-            if (i < 0) {
-                switch (mode) {
-                    case CLAMP:
-                        i = 0;
-                        break;
-                    case REPEAT:
-                        i = size - 1 - (-i % size);
-                        break;
-                    case MIRROR:
-                        // this is the same as the positive side, just make the value positive
-                        // first.
-                        i = -i;
-                        int count = i / size;
-                        i = i % size;
-
-                        if ((count % 2) == 1) {
-                            i = size - 1 - i;
-                        }
-                        break;
-                }
-            } else if (i >= size) {
-                switch (mode) {
-                    case CLAMP:
-                        i = size - 1;
-                        break;
-                    case REPEAT:
-                        i = i % size;
-                        break;
-                    case MIRROR:
-                        int count = i / size;
-                        i = i % size;
-
-                        if ((count % 2) == 1) {
-                            i = size - 1 - i;
-                        }
-                        break;
-                }
-            }
-
-            return i;
-        }
-
-
-        @Override
-        public int getTransparency() {
-            return java.awt.Paint.TRANSLUCENT;
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/Bitmap_Delegate.java b/bridge/src/android/graphics/Bitmap_Delegate.java
deleted file mode 100644
index bfd00c5..0000000
--- a/bridge/src/android/graphics/Bitmap_Delegate.java
+++ /dev/null
@@ -1,760 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.AssetRepository;
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.ide.common.rendering.api.RenderResources;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.android.BridgeContext;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.layoutlib.bridge.impl.RenderAction;
-import com.android.resources.Density;
-import com.android.resources.ResourceType;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.Nullable;
-import android.graphics.Bitmap.Config;
-import android.hardware.HardwareBuffer;
-import android.os.Parcel;
-
-import java.awt.Graphics2D;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.Buffer;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.Set;
-
-import javax.imageio.ImageIO;
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-import static android.content.res.AssetManager.ACCESS_STREAMING;
-
-/**
- * Delegate implementing the native methods of android.graphics.Bitmap
- *
- * Through the layoutlib_create tool, the original native methods of Bitmap have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original Bitmap class.
- *
- * @see DelegateManager
- *
- */
-public final class Bitmap_Delegate {
-
-    public enum BitmapCreateFlags {
-        NONE, PREMULTIPLIED, MUTABLE
-    }
-
-    // ---- delegate manager ----
-    private static final DelegateManager<Bitmap_Delegate> sManager =
-            new DelegateManager<>(Bitmap_Delegate.class);
-    private static long sFinalizer = -1;
-
-    // ---- delegate helper data ----
-
-    // ---- delegate data ----
-    private final Config mConfig;
-    private final BufferedImage mImage;
-    private boolean mHasAlpha = true;
-    private boolean mHasMipMap = false;      // TODO: check the default.
-    private boolean mIsPremultiplied = true;
-    private int mGenerationId = 0;
-    private boolean mIsMutable;
-
-
-    // ---- Public Helper methods ----
-
-    /**
-     * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
-     */
-    public static Bitmap_Delegate getDelegate(long native_bitmap) {
-        return sManager.getDelegate(native_bitmap);
-    }
-
-    /**
-     * Creates and returns a {@link Bitmap} initialized with the given stream content.
-     *
-     * @param input the stream from which to read the bitmap content
-     * @param isMutable whether the bitmap is mutable
-     * @param density the density associated with the bitmap
-     *
-     * @see Bitmap#isMutable()
-     * @see Bitmap#getDensity()
-     */
-    public static Bitmap createBitmap(@Nullable InputStream input, boolean isMutable,
-            Density density) throws IOException {
-        return createBitmap(input, getPremultipliedBitmapCreateFlags(isMutable), density);
-    }
-
-    /**
-     * Creates and returns a {@link Bitmap} initialized with the given file content.
-     *
-     * @param input the file from which to read the bitmap content
-     * @param density the density associated with the bitmap
-     *
-     * @see Bitmap#isPremultiplied()
-     * @see Bitmap#isMutable()
-     * @see Bitmap#getDensity()
-     */
-    static Bitmap createBitmap(@Nullable InputStream input, Set<BitmapCreateFlags> createFlags,
-            Density density) throws IOException {
-        // create a delegate with the content of the file.
-        BufferedImage image = input == null ? null : ImageIO.read(input);
-        if (image == null) {
-            // There was a problem decoding the image, or the decoder isn't registered. Webp maybe.
-            // Replace with a broken image icon.
-            BridgeContext currentContext = RenderAction.getCurrentContext();
-            if (currentContext != null) {
-                RenderResources resources = currentContext.getRenderResources();
-                ResourceValue broken = resources.getResolvedResource(
-                        BridgeContext.createFrameworkResourceReference(
-                                ResourceType.DRAWABLE, "ic_menu_report_image"));
-                AssetRepository assetRepository = currentContext.getAssets().getAssetRepository();
-                try (InputStream stream =
-                        assetRepository.openNonAsset(0, broken.getValue(), ACCESS_STREAMING)) {
-                    if (stream != null) {
-                        image = ImageIO.read(stream);
-                    }
-                }
-            }
-        }
-        Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ARGB_8888);
-        delegate.mIsMutable = createFlags.contains(BitmapCreateFlags.MUTABLE);
-
-        return createBitmap(delegate, createFlags, density.getDpiValue(), null);
-    }
-
-    /**
-     * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
-     *
-     * @param image the bitmap content
-     * @param isMutable whether the bitmap is mutable
-     * @param density the density associated with the bitmap
-     *
-     * @see Bitmap#isMutable()
-     * @see Bitmap#getDensity()
-     */
-    public static Bitmap createBitmap(BufferedImage image, boolean isMutable, Density density) {
-        return createBitmap(image, getPremultipliedBitmapCreateFlags(isMutable), density);
-    }
-
-    /**
-     * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
-     *
-     * @param image the bitmap content
-     * @param density the density associated with the bitmap
-     *
-     * @see Bitmap#isPremultiplied()
-     * @see Bitmap#isMutable()
-     * @see Bitmap#getDensity()
-     */
-    public static Bitmap createBitmap(BufferedImage image, Set<BitmapCreateFlags> createFlags,
-            Density density) {
-        return createBitmap(image, null, createFlags, density);
-    }
-
-    /**
-     * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
-     *
-     * @param image the bitmap content
-     * @param ninePatchChunk serialized ninepatch data
-     * @param density the density associated with the bitmap
-     *
-     * @see Bitmap#isPremultiplied()
-     * @see Bitmap#isMutable()
-     * @see Bitmap#getDensity()
-     */
-    public static Bitmap createBitmap(BufferedImage image, byte[] ninePatchChunk,
-            Set<BitmapCreateFlags> createFlags, Density density) {
-        // create a delegate with the given image.
-        Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ARGB_8888);
-        delegate.mIsMutable = createFlags.contains(BitmapCreateFlags.MUTABLE);
-
-        return createBitmap(delegate, createFlags, density.getDpiValue(), ninePatchChunk);
-    }
-
-    private static int getBufferedImageType() {
-        return BufferedImage.TYPE_INT_ARGB;
-    }
-
-    /**
-     * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
-     */
-    public BufferedImage getImage() {
-        return mImage;
-    }
-
-    /**
-     * Returns the Android bitmap config. Note that this not the config of the underlying
-     * Java2D bitmap.
-     */
-    public Config getConfig() {
-        return mConfig;
-    }
-
-    /**
-     * Returns the hasAlpha rendering hint
-     * @return true if the bitmap alpha should be used at render time
-     */
-    public boolean hasAlpha() {
-        return mHasAlpha && mConfig != Config.RGB_565;
-    }
-
-    /**
-     * Update the generationId.
-     *
-     * @see Bitmap#getGenerationId()
-     */
-    public void change() {
-        mGenerationId++;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
-            int height, int nativeConfig, boolean isMutable, long nativeColorSpace) {
-        int imageType = getBufferedImageType();
-
-        // create the image
-        BufferedImage image = new BufferedImage(width, height, imageType);
-
-        if (colors != null) {
-            image.setRGB(0, 0, width, height, colors, offset, stride);
-        }
-
-        // create a delegate with the content of the stream.
-        Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.nativeToConfig(nativeConfig));
-        delegate.mIsMutable = isMutable;
-
-        return createBitmap(delegate, getPremultipliedBitmapCreateFlags(isMutable),
-                            Bitmap.getDefaultDensity(), null);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeCopy(long srcBitmap, int nativeConfig, boolean isMutable) {
-        Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(srcBitmap);
-        if (srcBmpDelegate == null) {
-            return null;
-        }
-
-        BufferedImage srcImage = srcBmpDelegate.getImage();
-
-        int width = srcImage.getWidth();
-        int height = srcImage.getHeight();
-
-        int imageType = getBufferedImageType();
-
-        // create the image
-        BufferedImage image = new BufferedImage(width, height, imageType);
-
-        // copy the source image into the image.
-        int[] argb = new int[width * height];
-        srcImage.getRGB(0, 0, width, height, argb, 0, width);
-        image.setRGB(0, 0, width, height, argb, 0, width);
-
-        // create a delegate with the content of the stream.
-        Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.nativeToConfig(nativeConfig));
-        delegate.mIsMutable = isMutable;
-
-        return createBitmap(delegate, getPremultipliedBitmapCreateFlags(isMutable),
-                Bitmap.getDefaultDensity(), null);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeCopyAshmem(long nativeSrcBitmap) {
-        // Unused method; no implementation provided.
-        assert false;
-        return null;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeCopyAshmemConfig(long nativeSrcBitmap, int nativeConfig) {
-        // Unused method; no implementation provided.
-        assert false;
-        return null;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeGetNativeFinalizer() {
-        synchronized (Bitmap_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor);
-            }
-            return sFinalizer;
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeRecycle(long nativeBitmap) {
-        // In our case recycle() is a no-op. We will let the finalizer to dispose the bitmap.
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeReconfigure(long nativeBitmap, int width, int height,
-            int config, boolean isPremultiplied) {
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "Bitmap.reconfigure() is not supported", null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeCompress(long nativeBitmap, int format, int quality,
-            OutputStream stream, byte[] tempStorage) {
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "Bitmap.compress() is not supported", null, null /*data*/);
-        return true;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeErase(long nativeBitmap, int color) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return;
-        }
-
-        BufferedImage image = delegate.mImage;
-
-        Graphics2D g = image.createGraphics();
-        try {
-            g.setColor(new java.awt.Color(color, true));
-
-            g.fillRect(0, 0, image.getWidth(), image.getHeight());
-        } finally {
-            g.dispose();
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeErase(long nativeBitmap, long colorSpacePtr, long color) {
-        nativeErase(nativeBitmap, Color.toArgb(color));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nativeRowBytes(long nativeBitmap) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return 0;
-        }
-
-        return delegate.mImage.getWidth();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nativeConfig(long nativeBitmap) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return 0;
-        }
-
-        return delegate.mConfig.nativeInt;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeHasAlpha(long nativeBitmap) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        return delegate == null || delegate.mHasAlpha;
-
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeHasMipMap(long nativeBitmap) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        return delegate == null || delegate.mHasMipMap;
-
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nativeGetPixel(long nativeBitmap, int x, int y) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return 0;
-        }
-
-        return delegate.mImage.getRGB(x, y);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeGetColor(long nativeBitmap, int x, int y) {
-        return nativeGetPixel(nativeBitmap, x, y);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeGetPixels(long nativeBitmap, int[] pixels, int offset,
-            int stride, int x, int y, int width, int height) {
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.getImage().getRGB(x, y, width, height, pixels, offset, stride);
-    }
-
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeSetPixel(long nativeBitmap, int x, int y, int color) {
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.getImage().setRGB(x, y, color);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeSetPixels(long nativeBitmap, int[] colors, int offset,
-            int stride, int x, int y, int width, int height) {
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.getImage().setRGB(x, y, width, height, colors, offset, stride);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeCopyPixelsToBuffer(long nativeBitmap, Buffer dst) {
-        // FIXME implement native delegate
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Bitmap.copyPixelsToBuffer is not supported.", null, null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeCopyPixelsFromBuffer(long nb, Buffer src) {
-        // FIXME implement native delegate
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Bitmap.copyPixelsFromBuffer is not supported.", null, null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nativeGenerationId(long nativeBitmap) {
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return 0;
-        }
-
-        return delegate.mGenerationId;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeCreateFromParcel(Parcel p) {
-        // This is only called by Bitmap.CREATOR (Parcelable.Creator<Bitmap>), which is only
-        // used during aidl call so really this should not be called.
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "AIDL is not suppored, and therefore Bitmaps cannot be created from parcels.",
-                null, null /*data*/);
-        return null;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeWriteToParcel(long nativeBitmap, int density, Parcel p) {
-        // This is only called when sending a bitmap through aidl, so really this should not
-        // be called.
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "AIDL is not suppored, and therefore Bitmaps cannot be written to parcels.",
-                null, null /*data*/);
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeExtractAlpha(long nativeBitmap, long nativePaint,
-            int[] offsetXY) {
-        Bitmap_Delegate bitmap = sManager.getDelegate(nativeBitmap);
-        if (bitmap == null) {
-            return null;
-        }
-
-        // get the paint which can be null if nativePaint is 0.
-        Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint);
-
-        if (paint != null && paint.getMaskFilter() != null) {
-            Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MASKFILTER,
-                    "MaskFilter not supported in Bitmap.extractAlpha",
-                    null, null, null /*data*/);
-        }
-
-        int alpha = paint != null ? paint.getAlpha() : 0xFF;
-        BufferedImage image = createCopy(bitmap.getImage(), BufferedImage.TYPE_INT_ARGB, alpha);
-
-        // create the delegate. The actual Bitmap config is only an alpha channel
-        Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ALPHA_8);
-        delegate.mIsMutable = true;
-
-        // the density doesn't matter, it's set by the Java method.
-        return createBitmap(delegate, EnumSet.of(BitmapCreateFlags.MUTABLE),
-                Density.DEFAULT_DENSITY /*density*/, null);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeIsPremultiplied(long nativeBitmap) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        return delegate != null && delegate.mIsPremultiplied;
-
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeSetPremultiplied(long nativeBitmap, boolean isPremul) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mIsPremultiplied = isPremul;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeSetHasAlpha(long nativeBitmap, boolean hasAlpha,
-            boolean isPremul) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mHasAlpha = hasAlpha;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeSetHasMipMap(long nativeBitmap, boolean hasMipMap) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mHasMipMap = hasMipMap;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeSameAs(long nb0, long nb1) {
-        Bitmap_Delegate delegate1 = sManager.getDelegate(nb0);
-        if (delegate1 == null) {
-            return false;
-        }
-
-        Bitmap_Delegate delegate2 = sManager.getDelegate(nb1);
-        if (delegate2 == null) {
-            return false;
-        }
-
-        BufferedImage image1 = delegate1.getImage();
-        BufferedImage image2 = delegate2.getImage();
-        if (delegate1.mConfig != delegate2.mConfig ||
-                image1.getWidth() != image2.getWidth() ||
-                image1.getHeight() != image2.getHeight()) {
-            return false;
-        }
-
-        // get the internal data
-        int w = image1.getWidth();
-        int h = image2.getHeight();
-        int[] argb1 = new int[w*h];
-        int[] argb2 = new int[w*h];
-
-        image1.getRGB(0, 0, w, h, argb1, 0, w);
-        image2.getRGB(0, 0, w, h, argb2, 0, w);
-
-        // compares
-        if (delegate1.mConfig == Config.ALPHA_8) {
-            // in this case we have to manually compare the alpha channel as the rest is garbage.
-            final int length = w*h;
-            for (int i = 0 ; i < length ; i++) {
-                if ((argb1[i] & 0xFF000000) != (argb2[i] & 0xFF000000)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        return Arrays.equals(argb1, argb2);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nativeGetAllocationByteCount(long nativeBitmap) {
-        // get the delegate from the native int.
-        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
-        if (delegate == null) {
-            return 0;
-        }
-        int size = nativeRowBytes(nativeBitmap) * delegate.mImage.getHeight();
-        return size < 0 ? Integer.MAX_VALUE : size;
-
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativePrepareToDraw(long nativeBitmap) {
-        // do nothing as Bitmap_Delegate does not have caches
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeCopyPreserveInternalConfig(long nativeBitmap) {
-        Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(nativeBitmap);
-        if (srcBmpDelegate == null) {
-            return null;
-        }
-
-        BufferedImage srcImage = srcBmpDelegate.getImage();
-
-        // create the image
-        BufferedImage image = new BufferedImage(srcImage.getColorModel(), srcImage.copyData(null),
-                srcImage.isAlphaPremultiplied(), null);
-
-        // create a delegate with the content of the stream.
-        Bitmap_Delegate delegate = new Bitmap_Delegate(image, srcBmpDelegate.getConfig());
-        delegate.mIsMutable = srcBmpDelegate.mIsMutable;
-
-        return createBitmap(delegate, EnumSet.of(BitmapCreateFlags.NONE),
-                Bitmap.getDefaultDensity(), null);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static Bitmap nativeWrapHardwareBufferBitmap(HardwareBuffer buffer,
-            long nativeColorSpace) {
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "Bitmap.nativeWrapHardwareBufferBitmap() is not supported", null, null, null);
-        return null;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeIsSRGB(long nativeBitmap) {
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "Color spaces are not supported", null, null /*data*/);
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static ColorSpace nativeComputeColorSpace(long nativePtr) {
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "Color spaces are not supported", null, null /*data*/);
-        return null;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeSetColorSpace(long nativePtr, long nativeColorSpace) {
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "Color spaces are not supported", null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeIsSRGBLinear(long nativePtr) {
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "Color spaces are not supported", null, null /*data*/);
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeSetImmutable(long nativePtr) {
-        Bitmap_Delegate bmpDelegate = sManager.getDelegate(nativePtr);
-        if (bmpDelegate == null) {
-            return;
-        }
-        bmpDelegate.mIsMutable = false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeIsImmutable(long nativePtr) {
-        Bitmap_Delegate bmpDelegate = sManager.getDelegate(nativePtr);
-        if (bmpDelegate == null) {
-            return false;
-        }
-        return !bmpDelegate.mIsMutable;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static HardwareBuffer nativeGetHardwareBuffer(long nativeBitmap) {
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "HardwareBuffer is not supported", null, null /*data*/);
-        return null;
-    }
-
-    // ---- Private delegate/helper methods ----
-
-    private Bitmap_Delegate(BufferedImage image, Config config) {
-        mImage = image;
-        mConfig = config;
-    }
-
-    private static Bitmap createBitmap(Bitmap_Delegate delegate,
-            Set<BitmapCreateFlags> createFlags, int density, byte[] ninePatchChunk) {
-        // get its native_int
-        long nativeInt = sManager.addNewDelegate(delegate);
-
-        int width = delegate.mImage.getWidth();
-        int height = delegate.mImage.getHeight();
-        boolean isPremultiplied = createFlags.contains(BitmapCreateFlags.PREMULTIPLIED);
-
-        // and create/return a new Bitmap with it
-        return new Bitmap(nativeInt, width, height, density, isPremultiplied,
-                ninePatchChunk, null /* layoutBounds */, true /* fromMalloc */);
-    }
-
-    private static Set<BitmapCreateFlags> getPremultipliedBitmapCreateFlags(boolean isMutable) {
-        Set<BitmapCreateFlags> createFlags = EnumSet.of(BitmapCreateFlags.PREMULTIPLIED);
-        if (isMutable) {
-            createFlags.add(BitmapCreateFlags.MUTABLE);
-        }
-        return createFlags;
-    }
-
-    /**
-     * Creates and returns a copy of a given BufferedImage.
-     * <p/>
-     * if alpha is different than 255, then it is applied to the alpha channel of each pixel.
-     *
-     * @param image the image to copy
-     * @param imageType the type of the new image
-     * @param alpha an optional alpha modifier
-     * @return a new BufferedImage
-     */
-    /*package*/ static BufferedImage createCopy(BufferedImage image, int imageType, int alpha) {
-        int w = image.getWidth();
-        int h = image.getHeight();
-
-        BufferedImage result = new BufferedImage(w, h, imageType);
-
-        int[] argb = new int[w * h];
-        image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
-
-        if (alpha != 255) {
-            final int length = argb.length;
-            for (int i = 0 ; i < length; i++) {
-                int a = (argb[i] >>> 24 * alpha) / 255;
-                argb[i] = (a << 24) | (argb[i] & 0x00FFFFFF);
-            }
-        }
-
-        result.setRGB(0, 0, w, h, argb, 0, w);
-
-        return result;
-    }
-
-}
diff --git a/bridge/src/android/graphics/BlendComposite.java b/bridge/src/android/graphics/BlendComposite.java
deleted file mode 100644
index 5cc964a..0000000
--- a/bridge/src/android/graphics/BlendComposite.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.graphics;
-
-import java.awt.Composite;
-import java.awt.CompositeContext;
-import java.awt.RenderingHints;
-import java.awt.image.ColorModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.Raster;
-import java.awt.image.WritableRaster;
-
-/*
- * (non-Javadoc)
- * The class is adapted from a demo tool for Blending Modes written by
- * Romain Guy (romainguy@android.com). The tool is available at
- * http://www.curious-creature.org/2006/09/20/new-blendings-modes-for-java2d/
- *
- * This class has been adapted for applying color filters. When applying color filters, the src
- * image should not extend beyond the dest image, but in our implementation of the filters, it does.
- * To compensate for the effect, we recompute the alpha value of the src image before applying
- * the color filter as it should have been applied.
- */
-public final class BlendComposite implements Composite {
-    public enum BlendingMode {
-        MULTIPLY(),
-        SCREEN(),
-        DARKEN(),
-        LIGHTEN(),
-        OVERLAY(),
-        ADD();
-
-        private final BlendComposite mComposite;
-
-        BlendingMode() {
-            mComposite = new BlendComposite(this);
-        }
-
-        BlendComposite getBlendComposite() {
-            return mComposite;
-        }
-    }
-
-    private float alpha;
-    private BlendingMode mode;
-
-    private BlendComposite(BlendingMode mode) {
-        this(mode, 1.0f);
-    }
-
-    private BlendComposite(BlendingMode mode, float alpha) {
-        this.mode = mode;
-        setAlpha(alpha);
-    }
-
-    public static BlendComposite getInstance(BlendingMode mode) {
-        return mode.getBlendComposite();
-    }
-
-    public static BlendComposite getInstance(BlendingMode mode, float alpha) {
-        if (alpha > 0.9999f) {
-            return getInstance(mode);
-        }
-        return new BlendComposite(mode, alpha);
-    }
-
-    public float getAlpha() {
-        return alpha;
-    }
-
-    public BlendingMode getMode() {
-        return mode;
-    }
-
-    private void setAlpha(float alpha) {
-        if (alpha < 0.0f || alpha > 1.0f) {
-            assert false : "alpha must be comprised between 0.0f and 1.0f";
-            alpha = Math.min(alpha, 1.0f);
-            alpha = Math.max(alpha, 0.0f);
-        }
-
-        this.alpha = alpha;
-    }
-
-    @Override
-    public int hashCode() {
-        return Float.floatToIntBits(alpha) * 31 + mode.ordinal();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof BlendComposite)) {
-            return false;
-        }
-
-        BlendComposite bc = (BlendComposite) obj;
-
-        return mode == bc.mode && alpha == bc.alpha;
-    }
-
-    public CompositeContext createContext(ColorModel srcColorModel,
-                                          ColorModel dstColorModel,
-                                          RenderingHints hints) {
-        return new BlendingContext(this);
-    }
-
-    private static final class BlendingContext implements CompositeContext {
-        private final Blender blender;
-        private final BlendComposite composite;
-
-        private BlendingContext(BlendComposite composite) {
-            this.composite = composite;
-            this.blender = Blender.getBlenderFor(composite);
-        }
-
-        public void dispose() {
-        }
-
-        public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
-            if (src.getSampleModel().getDataType() != DataBuffer.TYPE_INT ||
-                dstIn.getSampleModel().getDataType() != DataBuffer.TYPE_INT ||
-                dstOut.getSampleModel().getDataType() != DataBuffer.TYPE_INT) {
-                throw new IllegalStateException(
-                        "Source and destination must store pixels as INT.");
-            }
-
-            int width = Math.min(src.getWidth(), dstIn.getWidth());
-            int height = Math.min(src.getHeight(), dstIn.getHeight());
-
-            float alpha = composite.getAlpha();
-
-            int[] srcPixel = new int[4];
-            int[] dstPixel = new int[4];
-            int[] result = new int[4];
-            int[] srcPixels = new int[width];
-            int[] dstPixels = new int[width];
-
-            for (int y = 0; y < height; y++) {
-                dstIn.getDataElements(0, y, width, 1, dstPixels);
-                if (alpha != 0) {
-                    src.getDataElements(0, y, width, 1, srcPixels);
-                    for (int x = 0; x < width; x++) {
-                        // pixels are stored as INT_ARGB
-                        // our arrays are [R, G, B, A]
-                        int pixel = srcPixels[x];
-                        srcPixel[0] = (pixel >> 16) & 0xFF;
-                        srcPixel[1] = (pixel >>  8) & 0xFF;
-                        srcPixel[2] = (pixel      ) & 0xFF;
-                        srcPixel[3] = (pixel >> 24) & 0xFF;
-
-                        pixel = dstPixels[x];
-                        dstPixel[0] = (pixel >> 16) & 0xFF;
-                        dstPixel[1] = (pixel >>  8) & 0xFF;
-                        dstPixel[2] = (pixel      ) & 0xFF;
-                        dstPixel[3] = (pixel >> 24) & 0xFF;
-
-                        // ---- Modified from original ----
-                        // recompute src pixel for transparency.
-                        srcPixel[3] *= dstPixel[3] / 0xFF;
-                        // ---- Modification ends ----
-
-                        result = blender.blend(srcPixel, dstPixel, result);
-
-                        // mixes the result with the opacity
-                        if (alpha == 1) {
-                            dstPixels[x] = (result[3] & 0xFF) << 24 |
-                                           (result[0] & 0xFF) << 16 |
-                                           (result[1] & 0xFF) <<  8 |
-                                           result[2] & 0xFF;
-                        } else {
-                            dstPixels[x] =
-                                    ((int) (dstPixel[3] + (result[3] - dstPixel[3]) * alpha) & 0xFF) << 24 |
-                                    ((int) (dstPixel[0] + (result[0] - dstPixel[0]) * alpha) & 0xFF) << 16 |
-                                    ((int) (dstPixel[1] + (result[1] - dstPixel[1]) * alpha) & 0xFF) <<  8 |
-                                    (int) (dstPixel[2] + (result[2] - dstPixel[2]) * alpha) & 0xFF;
-                        }
-
-                    }
-            }
-                dstOut.setDataElements(0, y, width, 1, dstPixels);
-            }
-        }
-    }
-
-    private static abstract class Blender {
-        public abstract int[] blend(int[] src, int[] dst, int[] result);
-
-        public static Blender getBlenderFor(BlendComposite composite) {
-            switch (composite.getMode()) {
-                case ADD:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 4; i++) {
-                                result[i] = Math.min(255, src[i] + dst[i]);
-                            }
-                            return result;
-                        }
-                    };
-                case DARKEN:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 3; i++) {
-                                result[i] = Math.min(src[i], dst[i]);
-                            }
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
-                case LIGHTEN:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 3; i++) {
-                                result[i] = Math.max(src[i], dst[i]);
-                            }
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
-                case MULTIPLY:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 3; i++) {
-                                result[i] = (src[i] * dst[i]) >> 8;
-                            }
-                            result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255);
-                            return result;
-                        }
-                    };
-                case OVERLAY:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            for (int i = 0; i < 3; i++) {
-                                result[i] = dst[i] < 128 ? dst[i] * src[i] >> 7 :
-                                    255 - ((255 - dst[i]) * (255 - src[i]) >> 7);
-                            }
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
-                case SCREEN:
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            result[0] = 255 - ((255 - src[0]) * (255 - dst[0]) >> 8);
-                            result[1] = 255 - ((255 - src[1]) * (255 - dst[1]) >> 8);
-                            result[2] = 255 - ((255 - src[2]) * (255 - dst[2]) >> 8);
-                            result[3] = Math.min(255, src[3] + dst[3]);
-                            return result;
-                        }
-                    };
-                default:
-                    assert false : "Blender not implement for " + composite.getMode().name();
-
-                    // Ignore the blend
-                    return new Blender() {
-                        @Override
-                        public int[] blend(int[] src, int[] dst, int[] result) {
-                            result[0] = dst[0];
-                            result[1] = dst[1];
-                            result[2] = dst[2];
-                            result[3] = dst[3];
-                            return result;
-                        }
-                    };
-            }
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/BlendModeColorFilter_Delegate.java b/bridge/src/android/graphics/BlendModeColorFilter_Delegate.java
deleted file mode 100644
index fc25903..0000000
--- a/bridge/src/android/graphics/BlendModeColorFilter_Delegate.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.BlendModeColorFilter
- *
- * Through the layoutlib_create tool, the original native methods of BlendModeColorFilter have
- * been replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original PorterDuffColorFilter class.
- *
- * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the Shader classes will be added to the manager
- * owned by {@link ColorFilter_Delegate}.
- *
- * @see ColorFilter_Delegate
- *
- */
-public class BlendModeColorFilter_Delegate extends ColorFilter_Delegate {
-
-    @Override
-    public String getSupportMessage() {
-        return "BlendMode Color Filters are not supported.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long native_CreateBlendModeFilter(int srcColor, int blendmode) {
-        return PorterDuffColorFilter_Delegate.native_CreateBlendModeFilter(srcColor, blendmode);
-    }
-}
diff --git a/bridge/src/android/graphics/BlurMaskFilter_Delegate.java b/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
deleted file mode 100644
index d2569c7..0000000
--- a/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.BlurMaskFilter
- *
- * Through the layoutlib_create tool, the original native methods of BlurMaskFilter have
- * been replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original BlurMaskFilter class.
- *
- * Because this extends {@link MaskFilter_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the Shader classes will be added to the manager
- * owned by {@link MaskFilter_Delegate}.
- *
- * @see MaskFilter_Delegate
- *
- */
-public class BlurMaskFilter_Delegate extends MaskFilter_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Blur Mask Filters are not supported.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeConstructor(float radius, int style) {
-        BlurMaskFilter_Delegate newDelegate = new BlurMaskFilter_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/Canvas_Delegate.java b/bridge/src/android/graphics/Canvas_Delegate.java
deleted file mode 100644
index 19e88b6..0000000
--- a/bridge/src/android/graphics/Canvas_Delegate.java
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.layoutlib.bridge.impl.GcSnapshot;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.Bitmap.Config;
-
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.geom.AffineTransform;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-
-/**
- * Delegate implementing the native methods of android.graphics.Canvas
- *
- * Through the layoutlib_create tool, the original native methods of Canvas have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original Canvas class.
- *
- * @see DelegateManager
- *
- */
-public final class Canvas_Delegate extends BaseCanvas_Delegate {
-
-    // ---- delegate manager ----
-    private static long sFinalizer = -1;
-
-    private DrawFilter_Delegate mDrawFilter = null;
-
-    // ---- Public Helper methods ----
-
-    /**
-     * Returns the native delegate associated to a given {@link Canvas} object.
-     */
-    public static Canvas_Delegate getDelegate(Canvas canvas) {
-        return (Canvas_Delegate) sManager.getDelegate(canvas.getNativeCanvasWrapper());
-    }
-
-    /**
-     * Returns the native delegate associated to a given an int referencing a {@link Canvas} object.
-     */
-    public static Canvas_Delegate getDelegate(long native_canvas) {
-        return (Canvas_Delegate) sManager.getDelegate(native_canvas);
-    }
-
-    /**
-     * Returns the current {@link Graphics2D} used to draw.
-     */
-    public GcSnapshot getSnapshot() {
-        return mSnapshot;
-    }
-
-    /**
-     * Returns the {@link DrawFilter} delegate or null if none have been set.
-     *
-     * @return the delegate or null.
-     */
-    public DrawFilter_Delegate getDrawFilter() {
-        return mDrawFilter;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static void nFreeCaches() {
-        // nothing to be done here.
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nFreeTextLayoutCaches() {
-        // nothing to be done here yet.
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nInitRaster(long bitmapHandle) {
-        if (bitmapHandle > 0) {
-            // get the Bitmap from the int
-            Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmapHandle);
-
-            // create a new Canvas_Delegate with the given bitmap and return its new native int.
-            Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
-
-            return sManager.addNewDelegate(newDelegate);
-        }
-
-        // create a new Canvas_Delegate and return its new native int.
-        Canvas_Delegate newDelegate = new Canvas_Delegate();
-
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    @LayoutlibDelegate
-    public static void nSetBitmap(long canvas, long bitmapHandle) {
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
-        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmapHandle);
-        if (canvasDelegate == null || bitmapDelegate == null) {
-            return;
-        }
-        canvasDelegate.mBitmap = bitmapDelegate;
-        canvasDelegate.mSnapshot = GcSnapshot.createDefaultSnapshot(bitmapDelegate);
-    }
-
-    @LayoutlibDelegate
-    public static boolean nIsOpaque(long nativeCanvas) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return false;
-        }
-
-        return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
-    }
-
-    @LayoutlibDelegate
-    public static int nGetWidth(long nativeCanvas) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return 0;
-        }
-
-        return canvasDelegate.mBitmap.getImage().getWidth();
-    }
-
-    @LayoutlibDelegate
-    public static int nGetHeight(long nativeCanvas) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return 0;
-        }
-
-        return canvasDelegate.mBitmap.getImage().getHeight();
-    }
-
-    @LayoutlibDelegate
-    public static int nSave(long nativeCanvas, int saveFlags) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return 0;
-        }
-
-        return canvasDelegate.save(saveFlags);
-    }
-
-    @LayoutlibDelegate
-    public static int nSaveLayer(long nativeCanvas, float l,
-                                               float t, float r, float b,
-                                               long paint, int layerFlags) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return 0;
-        }
-
-        Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
-
-        return canvasDelegate.saveLayer(new RectF(l, t, r, b),
-                paintDelegate, layerFlags);
-    }
-
-    @LayoutlibDelegate
-    public static int nSaveUnclippedLayer(long nativeCanvas, int l, int t, int r, int b) {
-        return nSaveLayer(nativeCanvas, l, t, r, b, 0, 0);
-    }
-
-    @LayoutlibDelegate
-    public static int nSaveLayerAlpha(long nativeCanvas, float l,
-                                                    float t, float r, float b,
-                                                    int alpha, int layerFlags) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return 0;
-        }
-
-        return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags);
-    }
-
-    @LayoutlibDelegate
-    public static void nRestoreUnclippedLayer(long nativeCanvas, int saveCount,
-            long nativePaint) {
-        nRestoreToCount(nativeCanvas, saveCount);
-    }
-
-    @LayoutlibDelegate
-    public static boolean nRestore(long nativeCanvas) {
-        // FIXME: implement throwOnUnderflow.
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return false;
-        }
-
-        canvasDelegate.restore();
-        return true;
-    }
-
-    @LayoutlibDelegate
-    public static void nRestoreToCount(long nativeCanvas, int saveCount) {
-        // FIXME: implement throwOnUnderflow.
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        canvasDelegate.restoreTo(saveCount);
-    }
-
-    @LayoutlibDelegate
-    public static int nGetSaveCount(long nativeCanvas) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return 0;
-        }
-
-        return canvasDelegate.getSnapshot().size();
-    }
-
-    @LayoutlibDelegate
-   public static void nTranslate(long nativeCanvas, float dx, float dy) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        canvasDelegate.getSnapshot().translate(dx, dy);
-    }
-
-    @LayoutlibDelegate
-       public static void nScale(long nativeCanvas, float sx, float sy) {
-            // get the delegate from the native int.
-            Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-            if (canvasDelegate == null) {
-                return;
-            }
-
-            canvasDelegate.getSnapshot().scale(sx, sy);
-        }
-
-    @LayoutlibDelegate
-    public static void nRotate(long nativeCanvas, float degrees) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
-    }
-
-    @LayoutlibDelegate
-   public static void nSkew(long nativeCanvas, float kx, float ky) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        // get the current top graphics2D object.
-        GcSnapshot g = canvasDelegate.getSnapshot();
-
-        // get its current matrix
-        AffineTransform currentTx = g.getTransform();
-        // get the AffineTransform for the given skew.
-        float[] mtx = Matrix_Delegate.getSkew(kx, ky);
-        AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
-
-        // combine them so that the given matrix is applied after.
-        currentTx.preConcatenate(matrixTx);
-
-        // give it to the graphics2D as a new matrix replacing all previous transform
-        g.setTransform(currentTx);
-    }
-
-    @LayoutlibDelegate
-    public static void nConcat(long nCanvas, long nMatrix) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
-        if (matrixDelegate == null) {
-            return;
-        }
-
-        // get the current top graphics2D object.
-        GcSnapshot snapshot = canvasDelegate.getSnapshot();
-
-        // get its current matrix
-        AffineTransform currentTx = snapshot.getTransform();
-        // get the AffineTransform of the given matrix
-        AffineTransform matrixTx = matrixDelegate.getAffineTransform();
-
-        // combine them so that the given matrix is applied after.
-        currentTx.concatenate(matrixTx);
-
-        // give it to the graphics2D as a new matrix replacing all previous transform
-        snapshot.setTransform(currentTx);
-    }
-
-    @LayoutlibDelegate
-    public static void nSetMatrix(long nCanvas, long nMatrix) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
-        if (matrixDelegate == null) {
-            return;
-        }
-
-        // get the current top graphics2D object.
-        GcSnapshot snapshot = canvasDelegate.getSnapshot();
-
-        // get the AffineTransform of the given matrix
-        AffineTransform matrixTx = matrixDelegate.getAffineTransform();
-
-        // give it to the graphics2D as a new matrix replacing all previous transform
-        snapshot.setTransform(matrixTx);
-
-        if (matrixDelegate.hasPerspective()) {
-            assert false;
-            Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MATRIX_AFFINE,
-                    "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " +
-                    "supports affine transformations.", null, null, null /*data*/);
-        }
-    }
-
-    @LayoutlibDelegate
-    public static boolean nClipRect(long nCanvas,
-                                                  float left, float top,
-                                                  float right, float bottom,
-                                                  int regionOp) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nCanvas);
-        if (canvasDelegate == null) {
-            return false;
-        }
-
-        return canvasDelegate.clipRect(left, top, right, bottom, regionOp);
-    }
-
-    @LayoutlibDelegate
-    public static boolean nClipPath(long nativeCanvas,
-                                                  long nativePath,
-                                                  int regionOp) {
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return true;
-        }
-
-        Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath);
-        if (pathDelegate == null) {
-            return true;
-        }
-
-        return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp);
-    }
-
-    @LayoutlibDelegate
-    public static void nSetDrawFilter(long nativeCanvas, long nativeFilter) {
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter);
-
-        if (canvasDelegate.mDrawFilter != null && !canvasDelegate.mDrawFilter.isSupported()) {
-            Bridge.getLog().fidelityWarning(ILayoutLog.TAG_DRAWFILTER,
-                    canvasDelegate.mDrawFilter.getSupportMessage(), null, null, null /*data*/);
-        }
-    }
-
-    @LayoutlibDelegate
-    public static boolean nGetClipBounds(long nativeCanvas,
-                                                       Rect bounds) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(nativeCanvas);
-        if (canvasDelegate == null) {
-            return false;
-        }
-
-        Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds();
-        if (rect != null && !rect.isEmpty()) {
-            bounds.left = rect.x;
-            bounds.top = rect.y;
-            bounds.right = rect.x + rect.width;
-            bounds.bottom = rect.y + rect.height;
-            return true;
-        }
-
-        return false;
-    }
-
-    @LayoutlibDelegate
-    public static void nGetMatrix(long canvas, long matrix) {
-        // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
-        if (canvasDelegate == null) {
-            return;
-        }
-
-        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
-        if (matrixDelegate == null) {
-            return;
-        }
-
-        AffineTransform transform = canvasDelegate.getSnapshot().getTransform();
-        matrixDelegate.set(Matrix_Delegate.makeValues(transform));
-    }
-
-    @LayoutlibDelegate
-    public static boolean nQuickReject(long nativeCanvas, long path) {
-        // FIXME properly implement quickReject
-        return false;
-    }
-
-    @LayoutlibDelegate
-    public static boolean nQuickReject(long nativeCanvas,
-                                                     float left, float top,
-                                                     float right, float bottom) {
-        // FIXME properly implement quickReject
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetNativeFinalizer() {
-        synchronized (Canvas_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(nativePtr -> {
-                    Canvas_Delegate delegate = Canvas_Delegate.getDelegate(nativePtr);
-                    if (delegate != null) {
-                        delegate.dispose();
-                    }
-                    sManager.removeJavaReferenceFor(nativePtr);
-                });
-            }
-        }
-        return sFinalizer;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetCompatibilityVersion(int apiLevel) {
-        // Unsupported by layoutlib, do nothing
-    }
-
-    private Canvas_Delegate(Bitmap_Delegate bitmap) {
-        super(bitmap);
-    }
-
-    private Canvas_Delegate() {
-        super();
-    }
-}
-
diff --git a/bridge/src/android/graphics/ColorFilter_Delegate.java b/bridge/src/android/graphics/ColorFilter_Delegate.java
deleted file mode 100644
index 84424bc..0000000
--- a/bridge/src/android/graphics/ColorFilter_Delegate.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.Graphics2D;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.ColorFilter
- *
- * Through the layoutlib_create tool, the original native methods of ColorFilter have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original ColorFilter class.
- *
- * This also serve as a base class for all ColorFilter delegate classes.
- *
- * @see DelegateManager
- *
- */
-public abstract class ColorFilter_Delegate {
-
-    // ---- delegate manager ----
-    protected static final DelegateManager<ColorFilter_Delegate> sManager =
-            new DelegateManager<ColorFilter_Delegate>(ColorFilter_Delegate.class);
-    private static long sFinalizer = -1;
-
-    // ---- delegate helper data ----
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    public static ColorFilter_Delegate getDelegate(long nativeShader) {
-        return sManager.getDelegate(nativeShader);
-    }
-
-    public abstract String getSupportMessage();
-
-    public boolean isSupported() {
-        return false;
-    }
-
-    public void applyFilter(Graphics2D g, int width, int height) {
-        // This should never be called directly. If supported, the sub class should override this.
-        assert false;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeGetFinalizer() {
-        synchronized (ColorFilter_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
-                        sManager::removeJavaReferenceFor);
-            }
-        }
-        return sFinalizer;
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
deleted file mode 100644
index 6739484..0000000
--- a/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.ColorMatrixColorFilter
- *
- * Through the layoutlib_create tool, the original native methods of ColorMatrixColorFilter have
- * been replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original ColorMatrixColorFilter class.
- *
- * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the Shader classes will be added to the manager
- * owned by {@link ColorFilter_Delegate}.
- *
- * @see ColorFilter_Delegate
- *
- */
-public class ColorMatrixColorFilter_Delegate extends ColorFilter_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public String getSupportMessage() {
-        return "ColorMatrix Color Filters are not supported.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeColorMatrixFilter(float[] array) {
-        ColorMatrixColorFilter_Delegate newDelegate = new ColorMatrixColorFilter_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/ColorSpace_Rgb_Delegate.java b/bridge/src/android/graphics/ColorSpace_Rgb_Delegate.java
deleted file mode 100644
index 3637055..0000000
--- a/bridge/src/android/graphics/ColorSpace_Rgb_Delegate.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.ColorSpace
- *
- * Through the layoutlib_create tool, the original native methods of ColorSpace have been replaced
- * by calls to methods of the same name in this delegate class.
- */
-public class ColorSpace_Rgb_Delegate {
-
-    // ---- delegate manager ----
-    private static final DelegateManager<ColorSpace_Rgb_Delegate> sManager =
-            new DelegateManager<>(ColorSpace_Rgb_Delegate.class);
-    private static long sFinalizer = -1;
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeGetNativeFinalizer() {
-        synchronized (ColorSpace_Rgb_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor);
-            }
-        }
-        return sFinalizer;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(float a, float b, float c, float d,
-            float e, float f, float g, float[] xyz) {
-        // Layoutlib does not support color spaces, but a native object is required
-        // for ColorSpace$Rgb. This creates an empty delegate for it.
-        return sManager.addNewDelegate(new ColorSpace_Rgb_Delegate());
-    }
-}
diff --git a/bridge/src/android/graphics/Color_Delegate.java b/bridge/src/android/graphics/Color_Delegate.java
deleted file mode 100644
index afd24f0..0000000
--- a/bridge/src/android/graphics/Color_Delegate.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics;
-
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.Color
- *
- * Through the layoutlib_create tool, the original native methods of Color have been replaced
- * by calls to methods of the same name in this delegate class.
- */
-public class Color_Delegate {
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeRGBToHSV(int red, int greed, int blue, float hsv[]) {
-        java.awt.Color.RGBtoHSB(red, greed, blue, hsv);
-        hsv[0] = hsv[0] * 360;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nativeHSVToColor(int alpha, float hsv[]) {
-        java.awt.Color rgb = new java.awt.Color(java.awt.Color.HSBtoRGB(hsv[0] / 360, pin(hsv[1]), pin(hsv[2])));
-        return Color.argb(alpha, rgb.getRed(), rgb.getGreen(), rgb.getBlue());
-    }
-
-    private static float pin(float value) {
-        return Math.max(0, Math.min(1, value));
-    }
-}
diff --git a/bridge/src/android/graphics/ComposePathEffect_Delegate.java b/bridge/src/android/graphics/ComposePathEffect_Delegate.java
deleted file mode 100644
index bc3df7d..0000000
--- a/bridge/src/android/graphics/ComposePathEffect_Delegate.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.Stroke;
-
-/**
- * Delegate implementing the native methods of android.graphics.ComposePathEffect
- *
- * Through the layoutlib_create tool, the original native methods of ComposePathEffect have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original ComposePathEffect class.
- *
- * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
- * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
- *
- * @see PathEffect_Delegate
- *
- */
-public class ComposePathEffect_Delegate extends PathEffect_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public Stroke getStroke(Paint_Delegate paint) {
-        // FIXME
-        return null;
-    }
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Compose Path Effects are not supported in Layout Preview mode.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(long outerpe, long innerpe) {
-        ComposePathEffect_Delegate newDelegate = new ComposePathEffect_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/ComposeShader_Delegate.java b/bridge/src/android/graphics/ComposeShader_Delegate.java
deleted file mode 100644
index ab37968..0000000
--- a/bridge/src/android/graphics/ComposeShader_Delegate.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.Paint;
-
-/**
- * Delegate implementing the native methods of android.graphics.ComposeShader
- *
- * Through the layoutlib_create tool, the original native methods of ComposeShader have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original ComposeShader class.
- *
- * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
- * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
- *
- * @see Shader_Delegate
- *
- */
-public class ComposeShader_Delegate extends Shader_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public Paint getJavaPaint() {
-        // FIXME
-        return null;
-    }
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Compose Shaders are not supported in Layout Preview mode.";
-    }
-
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(long nativeMatrix, long native_shaderA,
-            long native_shaderB, int native_mode) {
-        // FIXME not supported yet.
-        ComposeShader_Delegate newDelegate = new ComposeShader_Delegate(nativeMatrix);
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-
-    // ---- Private delegate/helper methods ----
-
-    private ComposeShader_Delegate(long nativeMatrix) {
-        super(nativeMatrix);
-    }
-}
diff --git a/bridge/src/android/graphics/CornerPathEffect_Delegate.java b/bridge/src/android/graphics/CornerPathEffect_Delegate.java
deleted file mode 100644
index 73745c3..0000000
--- a/bridge/src/android/graphics/CornerPathEffect_Delegate.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.Stroke;
-
-/**
- * Delegate implementing the native methods of android.graphics.CornerPathEffect
- *
- * Through the layoutlib_create tool, the original native methods of CornerPathEffect have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original CornerPathEffect class.
- *
- * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
- * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
- *
- * @see PathEffect_Delegate
- *
- */
-public class CornerPathEffect_Delegate extends PathEffect_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public Stroke getStroke(Paint_Delegate paint) {
-        // FIXME
-        return null;
-    }
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Corner Path Effects are not supported in Layout Preview mode.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(float radius) {
-        CornerPathEffect_Delegate newDelegate = new CornerPathEffect_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/DashPathEffect_Delegate.java b/bridge/src/android/graphics/DashPathEffect_Delegate.java
deleted file mode 100644
index 881afde..0000000
--- a/bridge/src/android/graphics/DashPathEffect_Delegate.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.BasicStroke;
-import java.awt.Stroke;
-
-/**
- * Delegate implementing the native methods of android.graphics.DashPathEffect
- *
- * Through the layoutlib_create tool, the original native methods of DashPathEffect have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original DashPathEffect class.
- *
- * Because this extends {@link PathEffect_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
- * {@link PathEffect_Delegate}.
- *
- * @see PathEffect_Delegate
- *
- */
-public final class DashPathEffect_Delegate extends PathEffect_Delegate {
-
-    // ---- delegate data ----
-
-    private final float[] mIntervals;
-    private final float mPhase;
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public Stroke getStroke(Paint_Delegate paint) {
-        return new BasicStroke(
-                paint.getStrokeWidth(),
-                paint.getJavaCap(),
-                paint.getJavaJoin(),
-                paint.getJavaStrokeMiter(),
-                mIntervals,
-                mPhase);
-    }
-
-    @Override
-    public boolean isSupported() {
-        return true;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        // no message since isSupported returns true;
-        return null;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(float intervals[], float phase) {
-        DashPathEffect_Delegate newDelegate = new DashPathEffect_Delegate(intervals, phase);
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-
-    private DashPathEffect_Delegate(float intervals[], float phase) {
-        mIntervals = new float[intervals.length];
-        System.arraycopy(intervals, 0, mIntervals, 0, intervals.length);
-        mPhase = phase;
-    }
-}
-
diff --git a/bridge/src/android/graphics/DiscretePathEffect_Delegate.java b/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
deleted file mode 100644
index 46109f3..0000000
--- a/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.Stroke;
-
-/**
- * Delegate implementing the native methods of android.graphics.DiscretePathEffect
- *
- * Through the layoutlib_create tool, the original native methods of DiscretePathEffect have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original DiscretePathEffect class.
- *
- * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
- * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
- *
- * @see PathEffect_Delegate
- *
- */
-public class DiscretePathEffect_Delegate extends PathEffect_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public Stroke getStroke(Paint_Delegate paint) {
-        // FIXME
-        return null;
-    }
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Discrete Path Effects are not supported in Layout Preview mode.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(float length, float deviation) {
-        DiscretePathEffect_Delegate newDelegate = new DiscretePathEffect_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/DrawFilter_Delegate.java b/bridge/src/android/graphics/DrawFilter_Delegate.java
deleted file mode 100644
index 2e10740..0000000
--- a/bridge/src/android/graphics/DrawFilter_Delegate.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.DrawFilter
- *
- * Through the layoutlib_create tool, the original native methods of DrawFilter have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original DrawFilter class.
- *
- * This also serve as a base class for all DrawFilter delegate classes.
- *
- * @see DelegateManager
- *
- */
-public abstract class DrawFilter_Delegate {
-
-    // ---- delegate manager ----
-    protected static final DelegateManager<DrawFilter_Delegate> sManager =
-            new DelegateManager<DrawFilter_Delegate>(DrawFilter_Delegate.class);
-
-    // ---- delegate helper data ----
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    public static DrawFilter_Delegate getDelegate(long nativeDrawFilter) {
-        return sManager.getDelegate(nativeDrawFilter);
-    }
-
-    public abstract boolean isSupported();
-    public abstract String getSupportMessage();
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeDestructor(long nativeDrawFilter) {
-        sManager.removeJavaReferenceFor(nativeDrawFilter);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java b/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
deleted file mode 100644
index e5040cc..0000000
--- a/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.EmbossMaskFilter
- *
- * Through the layoutlib_create tool, the original native methods of EmbossMaskFilter have
- * been replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original EmbossMaskFilter class.
- *
- * Because this extends {@link MaskFilter_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the Shader classes will be added to the manager
- * owned by {@link MaskFilter_Delegate}.
- *
- * @see MaskFilter_Delegate
- *
- */
-public class EmbossMaskFilter_Delegate extends MaskFilter_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Emboss Mask Filters are not supported.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeConstructor(float[] direction, float ambient,
-            float specular, float blurRadius) {
-        EmbossMaskFilter_Delegate newDelegate = new EmbossMaskFilter_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/FontFamily_Delegate.java b/bridge/src/android/graphics/FontFamily_Delegate.java
deleted file mode 100644
index a452aae..0000000
--- a/bridge/src/android/graphics/FontFamily_Delegate.java
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.fonts.FontVariationAxis;
-
-import java.awt.Font;
-import java.awt.FontFormatException;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Scanner;
-import java.util.Set;
-import java.util.logging.Logger;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-import static android.graphics.Typeface.RESOLVE_BY_FONT_TABLE;
-import static android.graphics.Typeface_Delegate.SYSTEM_FONTS;
-
-/**
- * Delegate implementing the native methods of android.graphics.FontFamily
- *
- * Through the layoutlib_create tool, the original native methods of FontFamily have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original FontFamily class.
- *
- * @see DelegateManager
- */
-public class FontFamily_Delegate {
-
-    public static final int DEFAULT_FONT_WEIGHT = 400;
-    public static final int BOLD_FONT_WEIGHT_DELTA = 300;
-    public static final int BOLD_FONT_WEIGHT = 700;
-
-    private static final String FONT_SUFFIX_ITALIC = "Italic.ttf";
-    private static final String FN_ALL_FONTS_LIST = "fontsInSdk.txt";
-    private static final String EXTENSION_OTF = ".otf";
-
-    private static final int CACHE_SIZE = 10;
-    // The cache has a drawback that if the font file changed after the font object was created,
-    // we will not update it.
-    private static final Map<String, FontInfo> sCache =
-            new LinkedHashMap<String, FontInfo>(CACHE_SIZE) {
-        @Override
-        protected boolean removeEldestEntry(Map.Entry<String, FontInfo> eldest) {
-            return size() > CACHE_SIZE;
-        }
-
-        @Override
-        public FontInfo put(String key, FontInfo value) {
-            // renew this entry.
-            FontInfo removed = remove(key);
-            super.put(key, value);
-            return removed;
-        }
-    };
-
-    /**
-     * A class associating {@link Font} with its metadata.
-     */
-    public static final class FontInfo {
-        @Nullable
-        public Font mFont;
-        public int mWeight;
-        public boolean mIsItalic;
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-            FontInfo fontInfo = (FontInfo) o;
-            return mWeight == fontInfo.mWeight && mIsItalic == fontInfo.mIsItalic;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(mWeight, mIsItalic);
-        }
-
-        @Override
-        public String toString() {
-            return "FontInfo{" + "mWeight=" + mWeight + ", mIsItalic=" + mIsItalic + '}';
-        }
-    }
-
-    // ---- delegate manager ----
-    private static final DelegateManager<FontFamily_Delegate> sManager =
-            new DelegateManager<FontFamily_Delegate>(FontFamily_Delegate.class);
-    private static long sFamilyFinalizer = -1;
-
-    // ---- delegate helper data ----
-    private static String sFontLocation;
-    private static final List<FontFamily_Delegate> sPostInitDelegate = new
-            ArrayList<FontFamily_Delegate>();
-    private static Set<String> SDK_FONTS;
-
-
-    // ---- delegate data ----
-
-    // Order does not really matter but we use a LinkedHashMap to get reproducible results across
-    // render calls
-    private Map<FontInfo, Font> mFonts = new LinkedHashMap<>();
-
-    /**
-     * The variant of the Font Family - compact or elegant.
-     * <p/>
-     * 0 is unspecified, 1 is compact and 2 is elegant. This needs to be kept in sync with values in
-     * android.graphics.FontFamily
-     *
-     * @see Paint#setElegantTextHeight(boolean)
-     */
-    private FontVariant mVariant;
-    // List of runnables to process fonts after sFontLoader is initialized.
-    private List<Runnable> mPostInitRunnables = new ArrayList<Runnable>();
-    /** @see #isValid() */
-    private boolean mValid = false;
-
-
-    // ---- Public helper class ----
-
-    public enum FontVariant {
-        // The order needs to be kept in sync with android.graphics.FontFamily.
-        NONE, COMPACT, ELEGANT
-    }
-
-    // ---- Public Helper methods ----
-
-    public static FontFamily_Delegate getDelegate(long nativeFontFamily) {
-        return sManager.getDelegate(nativeFontFamily);
-    }
-
-    public static synchronized void setFontLocation(String fontLocation) {
-        sFontLocation = fontLocation;
-        // init list of bundled fonts.
-        File allFonts = new File(fontLocation, FN_ALL_FONTS_LIST);
-        // Current number of fonts is 103. Use the next round number to leave scope for more fonts
-        // in the future.
-        Set<String> allFontsList = new HashSet<>(128);
-        Scanner scanner = null;
-        try {
-            scanner = new Scanner(allFonts);
-            while (scanner.hasNext()) {
-                String name = scanner.next();
-                // Skip font configuration files.
-                if (!name.endsWith(".xml")) {
-                    allFontsList.add(name);
-                }
-            }
-        } catch (FileNotFoundException e) {
-            Bridge.getLog().error(ILayoutLog.TAG_BROKEN,
-                    "Unable to load the list of fonts. Try re-installing the SDK Platform from the SDK Manager.",
-                    e, null, null);
-        } finally {
-            if (scanner != null) {
-                scanner.close();
-            }
-        }
-        SDK_FONTS = Collections.unmodifiableSet(allFontsList);
-        for (FontFamily_Delegate fontFamily : sPostInitDelegate) {
-            fontFamily.init();
-        }
-        sPostInitDelegate.clear();
-    }
-
-    @Nullable
-    public Font getFont(int desiredWeight, boolean isItalic) {
-        FontInfo desiredStyle = new FontInfo();
-        desiredStyle.mWeight = desiredWeight;
-        desiredStyle.mIsItalic = isItalic;
-
-        Font cachedFont = mFonts.get(desiredStyle);
-        if (cachedFont != null) {
-            return cachedFont;
-        }
-
-        FontInfo bestFont = null;
-
-        if (mFonts.size() == 1) {
-            // No need to compute the match since we only have one candidate
-            bestFont = mFonts.keySet().iterator().next();
-        } else {
-            int bestMatch = Integer.MAX_VALUE;
-
-            for (FontInfo font : mFonts.keySet()) {
-                int match = computeMatch(font, desiredStyle);
-                if (match < bestMatch) {
-                    bestMatch = match;
-                    bestFont = font;
-                    if (bestMatch == 0) {
-                        break;
-                    }
-                }
-            }
-        }
-
-        if (bestFont == null) {
-            return null;
-        }
-
-
-        // Derive the font as required and add it to the list of Fonts.
-        deriveFont(bestFont, desiredStyle);
-        addFont(desiredStyle);
-        return desiredStyle.mFont;
-    }
-
-    public FontVariant getVariant() {
-        return mVariant;
-    }
-
-    /**
-     * Returns if the FontFamily should contain any fonts. If this returns true and
-     * {@link #getFont(int, boolean)} returns an empty list, it means that an error occurred while
-     * loading the fonts. However, some fonts are deliberately skipped, for example they are not
-     * bundled with the SDK. In such a case, this method returns false.
-     */
-    public boolean isValid() {
-        return mValid;
-    }
-
-    private static Font loadFont(String path) {
-        if (path.startsWith(SYSTEM_FONTS) ) {
-            String relativePath = path.substring(SYSTEM_FONTS.length());
-            File f = new File(sFontLocation, relativePath);
-
-            try {
-                return Font.createFont(Font.TRUETYPE_FONT, f);
-            } catch (Exception e) {
-                if (path.endsWith(EXTENSION_OTF) && e instanceof FontFormatException) {
-                    // If we aren't able to load an Open Type font, don't log a warning just yet.
-                    // We wait for a case where font is being used. Only then we try to log the
-                    // warning.
-                    return null;
-                }
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_BROKEN,
-                        String.format("Unable to load font %1$s", relativePath),
-                        e, null, null);
-            }
-        } else {
-            Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                    "Only platform fonts located in " + SYSTEM_FONTS + "can be loaded.",
-                    null, null, null);
-        }
-
-        return null;
-    }
-
-    @Nullable
-    public static String getFontLocation() {
-        return sFontLocation;
-    }
-
-    // ---- delegate methods ----
-    @LayoutlibDelegate
-    /*package*/ static boolean addFont(FontFamily thisFontFamily, String path, int ttcIndex,
-            FontVariationAxis[] axes, int weight, int italic) {
-        if (thisFontFamily.mBuilderPtr == 0) {
-            assert false : "Unable to call addFont after freezing.";
-            return false;
-        }
-        final FontFamily_Delegate delegate = getDelegate(thisFontFamily.mBuilderPtr);
-        return delegate != null && delegate.addFont(path, ttcIndex, weight, italic);
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nInitBuilder(String lang, int variant) {
-        // TODO: support lang. This is required for japanese locale.
-        FontFamily_Delegate delegate = new FontFamily_Delegate();
-        // variant can be 0, 1 or 2.
-        assert variant < 3;
-        delegate.mVariant = FontVariant.values()[variant];
-        if (sFontLocation != null) {
-            delegate.init();
-        } else {
-            sPostInitDelegate.add(delegate);
-        }
-        return sManager.addNewDelegate(delegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreateFamily(long builderPtr) {
-        return builderPtr;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetFamilyReleaseFunc() {
-        synchronized (FontFamily_Delegate.class) {
-            if (sFamilyFinalizer == -1) {
-                sFamilyFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
-                        sManager::removeJavaReferenceFor);
-            }
-        }
-        return sFamilyFinalizer;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nAddFont(long builderPtr, ByteBuffer font, int ttcIndex,
-            int weight, int isItalic) {
-        assert false : "The only client of this method has been overridden.";
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nAddFontWeightStyle(long builderPtr, ByteBuffer font,
-            int ttcIndex, int weight, int isItalic) {
-        assert false : "The only client of this method has been overridden.";
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddAxisValue(long builderPtr, int tag, float value) {
-        assert false : "The only client of this method has been overridden.";
-    }
-
-    static boolean addFont(long builderPtr, final String path, final int weight,
-            final boolean isItalic) {
-        final FontFamily_Delegate delegate = getDelegate(builderPtr);
-        int italic = isItalic ? 1 : 0;
-        if (delegate != null) {
-            if (sFontLocation == null) {
-                delegate.mPostInitRunnables.add(() -> delegate.addFont(path, weight, italic));
-                return true;
-            }
-            return delegate.addFont(path, weight, italic);
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetBuilderReleaseFunc() {
-        // Layoutlib uses the same reference for the builder and the font family,
-        // so it should not release that reference at the builder stage.
-        return -1;
-    }
-
-    // ---- private helper methods ----
-
-    private void init() {
-        for (Runnable postInitRunnable : mPostInitRunnables) {
-            postInitRunnable.run();
-        }
-        mPostInitRunnables = null;
-    }
-
-    private boolean addFont(final String path, int ttcIndex, int weight, int italic) {
-        // FIXME: support ttc fonts. Hack JRE??
-        if (sFontLocation == null) {
-            mPostInitRunnables.add(() -> addFont(path, weight, italic));
-            return true;
-        }
-        return addFont(path, weight, italic);
-    }
-
-     private boolean addFont(@NonNull String path) {
-         return addFont(path, DEFAULT_FONT_WEIGHT, path.endsWith(FONT_SUFFIX_ITALIC) ? 1 : RESOLVE_BY_FONT_TABLE);
-     }
-
-    private boolean addFont(@NonNull String path, int weight, int italic) {
-        if (path.startsWith(SYSTEM_FONTS) &&
-                !SDK_FONTS.contains(path.substring(SYSTEM_FONTS.length()))) {
-            Logger.getLogger(FontFamily_Delegate.class.getSimpleName()).warning("Unable to load font " + path);
-            return mValid = false;
-        }
-        // Set valid to true, even if the font fails to load.
-        mValid = true;
-        Font font = loadFont(path);
-        if (font == null) {
-            return false;
-        }
-        FontInfo fontInfo = new FontInfo();
-        fontInfo.mFont = font;
-        fontInfo.mWeight = weight;
-        fontInfo.mIsItalic = italic == RESOLVE_BY_FONT_TABLE ? font.isItalic() : italic == 1;
-        addFont(fontInfo);
-        return true;
-    }
-
-    private boolean addFont(@NonNull FontInfo fontInfo) {
-        return mFonts.putIfAbsent(fontInfo, fontInfo.mFont) == null;
-    }
-
-    /**
-     * Compute matching metric between two styles - 0 is an exact match.
-     */
-    public static int computeMatch(@NonNull FontInfo font1, @NonNull FontInfo font2) {
-        int score = Math.abs(font1.mWeight / 100 - font2.mWeight / 100);
-        if (font1.mIsItalic != font2.mIsItalic) {
-            score += 2;
-        }
-        return score;
-    }
-
-    /**
-     * Try to derive a font from {@code srcFont} for the style in {@code outFont}.
-     * <p/>
-     * {@code outFont} is updated to reflect the style of the derived font.
-     * @param srcFont the source font
-     * @param outFont contains the desired font style. Updated to contain the derived font and
-     *                its style
-     */
-    public static void deriveFont(@NonNull FontInfo srcFont, @NonNull FontInfo outFont) {
-        int desiredWeight = outFont.mWeight;
-        int srcWeight = srcFont.mWeight;
-        assert srcFont.mFont != null;
-        Font derivedFont = srcFont.mFont;
-        int derivedStyle = 0;
-        // Embolden the font if required.
-        if (desiredWeight >= BOLD_FONT_WEIGHT && desiredWeight - srcWeight > BOLD_FONT_WEIGHT_DELTA / 2) {
-            derivedStyle |= Font.BOLD;
-            srcWeight += BOLD_FONT_WEIGHT_DELTA;
-        }
-        // Italicize the font if required.
-        if (outFont.mIsItalic && !srcFont.mIsItalic) {
-            derivedStyle |= Font.ITALIC;
-        } else if (outFont.mIsItalic != srcFont.mIsItalic) {
-            // The desired font is plain, but the src font is italics. We can't convert it back. So
-            // we update the value to reflect the true style of the font we're deriving.
-            outFont.mIsItalic = srcFont.mIsItalic;
-        }
-
-        if (derivedStyle != 0) {
-            derivedFont = derivedFont.deriveFont(derivedStyle);
-        }
-
-        outFont.mFont = derivedFont;
-        outFont.mWeight = srcWeight;
-        // No need to update mIsItalics, as it's already been handled above.
-    }
-}
diff --git a/bridge/src/android/graphics/Gradient_Delegate.java b/bridge/src/android/graphics/Gradient_Delegate.java
deleted file mode 100644
index 8aed4b4..0000000
--- a/bridge/src/android/graphics/Gradient_Delegate.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import android.graphics.Shader.TileMode;
-
-import java.util.Arrays;
-
-/**
- * Base class for true Gradient shader delegate.
- */
-public abstract class Gradient_Delegate extends Shader_Delegate {
-
-    protected final int[] mColors;
-    protected final float[] mPositions;
-
-    @Override
-    public boolean isSupported() {
-        // all gradient shaders are supported.
-        return true;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        // all gradient shaders are supported, no need for a gradient support
-        return null;
-    }
-
-    /**
-     * Creates the base shader and do some basic test on the parameters.
-     *
-     * @param nativeMatrix reference to the shader's native transformation matrix
-     * @param colors The colors to be distributed along the gradient line
-     * @param positions May be null. The relative positions [0..1] of each
-     *            corresponding color in the colors array. If this is null, the
-     *            the colors are distributed evenly along the gradient line.
-     */
-    protected Gradient_Delegate(long nativeMatrix, long[] colors, float[] positions) {
-        super(nativeMatrix);
-        assert colors.length >= 2 : "needs >= 2 number of colors";
-
-        if (positions == null) {
-            float spacing = 1.f / (colors.length - 1);
-            positions = new float[colors.length];
-            positions[0] = 0.f;
-            positions[colors.length - 1] = 1.f;
-            for (int i = 1; i < colors.length - 1; i++) {
-                positions[i] = spacing * i;
-            }
-        } else {
-            assert colors.length == positions.length :
-                    "color and position " + "arrays must be of equal length";
-            positions[0] = Math.min(Math.max(0, positions[0]), 1);
-            for (int i = 1; i < positions.length; i++) {
-                positions[i] = Math.min(Math.max(positions[i-1], positions[i]), 1);
-            }
-        }
-
-        mColors = Arrays.stream(colors).mapToInt(Color::toArgb).toArray();
-        mPositions = positions;
-    }
-
-    /**
-     * Base class for (Java) Gradient Paints. This handles computing the gradient colors based
-     * on the color and position lists, as well as the {@link TileMode}
-     *
-     */
-    protected abstract static class GradientPaint implements java.awt.Paint {
-        private final static int GRADIENT_SIZE = 100;
-
-        private final int[] mColors;
-        private final float[] mPositions;
-        private final TileMode mTileMode;
-        private int[] mGradient;
-
-        protected GradientPaint(int[] colors, float[] positions, TileMode tileMode) {
-            mColors = colors;
-            mPositions = positions;
-            mTileMode = tileMode;
-        }
-
-        @Override
-        public int getTransparency() {
-            return java.awt.Paint.TRANSLUCENT;
-        }
-
-        /**
-         * Pre-computes the colors for the gradient. This must be called once before any call
-         * to {@link #getGradientColor(float)}
-         */
-        protected void precomputeGradientColors() {
-            if (mGradient == null) {
-                // actually create an array with an extra size, so that we can really go
-                // from 0 to SIZE (100%), or currentPos in the loop below will never equal 1.0
-                mGradient = new int[GRADIENT_SIZE+1];
-
-                int prevPos = 0;
-                int nextPos = 1;
-                for (int i  = 0 ; i <= GRADIENT_SIZE ; i++) {
-                    // compute current position
-                    float currentPos = (float)i/GRADIENT_SIZE;
-
-                    if (currentPos < mPositions[0]) {
-                        mGradient[i] = mColors[0];
-                        continue;
-                    }
-
-                    while (nextPos < mPositions.length && currentPos >= mPositions[nextPos]) {
-                        prevPos = nextPos++;
-                    }
-
-                    if (nextPos == mPositions.length || currentPos == prevPos) {
-                        mGradient[i] = mColors[prevPos];
-                    } else {
-                        float percent = (currentPos - mPositions[prevPos]) /
-                                (mPositions[nextPos] - mPositions[prevPos]);
-
-                        mGradient[i] = computeColor(mColors[prevPos], mColors[nextPos], percent);
-                    }
-                }
-            }
-        }
-
-        /**
-         * Returns the color based on the position in the gradient.
-         * <var>pos</var> can be anything, even &lt; 0 or &gt; > 1, as the gradient
-         * will use {@link TileMode} value to convert it into a [0,1] value.
-         */
-        protected int getGradientColor(float pos) {
-            if (pos < 0.f) {
-                if (mTileMode != null) {
-                    switch (mTileMode) {
-                        case CLAMP:
-                            pos = 0.f;
-                            break;
-                        case REPEAT:
-                            // remove the integer part to stay in the [0,1] range.
-                            // we also need to invert the value from [-1,0] to [0, 1]
-                            pos = pos - (float)Math.floor(pos);
-                            break;
-                        case MIRROR:
-                            // this is the same as the positive side, just make the value positive
-                            // first.
-                            pos = Math.abs(pos);
-
-                            // get the integer and the decimal part
-                            int intPart = (int)Math.floor(pos);
-                            pos = pos - intPart;
-                            // 0 -> 1 : normal order
-                            // 1 -> 2: mirrored
-                            // etc..
-                            // this means if the intpart is odd we invert
-                            if ((intPart % 2) == 1) {
-                                pos = 1.f - pos;
-                            }
-                            break;
-                    }
-                } else {
-                    pos = 0.0f;
-                }
-            } else if (pos > 1f) {
-                if (mTileMode != null) {
-                    switch (mTileMode) {
-                        case CLAMP:
-                            pos = 1.f;
-                            break;
-                        case REPEAT:
-                            // remove the integer part to stay in the [0,1] range
-                            pos = pos - (float)Math.floor(pos);
-                            break;
-                        case MIRROR:
-                            // get the integer and the decimal part
-                            int intPart = (int)Math.floor(pos);
-                            pos = pos - intPart;
-                            // 0 -> 1 : normal order
-                            // 1 -> 2: mirrored
-                            // etc..
-                            // this means if the intpart is odd we invert
-                            if ((intPart % 2) == 1) {
-                                pos = 1.f - pos;
-                            }
-                            break;
-                    }
-                } else {
-                    pos = 1.0f;
-                }
-            }
-
-            int index = (int)((pos * GRADIENT_SIZE) + .5);
-
-            return mGradient[index];
-        }
-
-        /**
-         * Returns the color between c1, and c2, based on the percent of the distance
-         * between c1 and c2.
-         */
-        private int computeColor(int c1, int c2, float percent) {
-            int a = computeChannel((c1 >> 24) & 0xFF, (c2 >> 24) & 0xFF, percent);
-            int r = computeChannel((c1 >> 16) & 0xFF, (c2 >> 16) & 0xFF, percent);
-            int g = computeChannel((c1 >>  8) & 0xFF, (c2 >>  8) & 0xFF, percent);
-            int b = computeChannel((c1      ) & 0xFF, (c2      ) & 0xFF, percent);
-            return a << 24 | r << 16 | g << 8 | b;
-        }
-
-        /**
-         * Returns the channel value between 2 values based on the percent of the distance between
-         * the 2 values..
-         */
-        private int computeChannel(int c1, int c2, float percent) {
-            return c1 + (int)((percent * (c2-c1)) + .5);
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/HardwareRenderer_ProcessInitializer_Delegate.java b/bridge/src/android/graphics/HardwareRenderer_ProcessInitializer_Delegate.java
new file mode 100644
index 0000000..88c034b
--- /dev/null
+++ b/bridge/src/android/graphics/HardwareRenderer_ProcessInitializer_Delegate.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.graphics;
+
+public class HardwareRenderer_ProcessInitializer_Delegate {
+    public static void initSched(long renderProxy) {
+        /*
+         * This is done in order to prevent NullPointerException when creating HardwareRenderer in
+         * layoutlib
+         */
+    }
+}
diff --git a/bridge/src/android/graphics/ImageDecoder.java b/bridge/src/android/graphics/ImageDecoder.java
deleted file mode 100644
index eefdb2e..0000000
--- a/bridge/src/android/graphics/ImageDecoder.java
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-package android.graphics;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.content.res.AssetManager.AssetInputStream;
-import android.content.res.Resources;
-import android.graphics.drawable.AnimatedImageDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.BitmapDrawable;
-import android.net.Uri;
-import android.util.DisplayMetrics;
-import android.util.Size;
-import android.util.TypedValue;
-
-import java.nio.ByteBuffer;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.ArrayIndexOutOfBoundsException;
-import java.lang.AutoCloseable;
-import java.lang.NullPointerException;
-import java.lang.annotation.Retention;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-/**
- *  Class for decoding images as {@link Bitmap}s or {@link Drawable}s.
- */
-public final class ImageDecoder implements AutoCloseable {
-
-    /**
-     *  Source of the encoded image data.
-     */
-    public static abstract class Source {
-        private Source() {}
-
-        /* @hide */
-        @Nullable
-        Resources getResources() { return null; }
-
-        /* @hide */
-        int getDensity() { return Bitmap.DENSITY_NONE; }
-
-        /* @hide */
-        int computeDstDensity() {
-            Resources res = getResources();
-            if (res == null) {
-                return Bitmap.getDefaultDensity();
-            }
-
-            return res.getDisplayMetrics().densityDpi;
-        }
-
-        /* @hide */
-        @NonNull
-        abstract ImageDecoder createImageDecoder() throws IOException;
-    };
-
-    private static class ByteArraySource extends Source {
-        ByteArraySource(@NonNull byte[] data, int offset, int length) {
-            mData = data;
-            mOffset = offset;
-            mLength = length;
-        };
-        private final byte[] mData;
-        private final int    mOffset;
-        private final int    mLength;
-
-        @Override
-        public ImageDecoder createImageDecoder() throws IOException {
-            return new ImageDecoder();
-        }
-    }
-
-    private static class ByteBufferSource extends Source {
-        ByteBufferSource(@NonNull ByteBuffer buffer) {
-            mBuffer = buffer;
-        }
-        private final ByteBuffer mBuffer;
-
-        @Override
-        public ImageDecoder createImageDecoder() throws IOException {
-            return new ImageDecoder();
-        }
-    }
-
-    private static class ContentResolverSource extends Source {
-        ContentResolverSource(@NonNull ContentResolver resolver, @NonNull Uri uri) {
-            mResolver = resolver;
-            mUri = uri;
-        }
-
-        private final ContentResolver mResolver;
-        private final Uri mUri;
-
-        @Override
-        public ImageDecoder createImageDecoder() throws IOException {
-            return new ImageDecoder();
-        }
-    }
-
-    /**
-     * For backwards compatibility, this does *not* close the InputStream.
-     */
-    private static class InputStreamSource extends Source {
-        InputStreamSource(Resources res, InputStream is, int inputDensity) {
-            if (is == null) {
-                throw new IllegalArgumentException("The InputStream cannot be null");
-            }
-            mResources = res;
-            mInputStream = is;
-            mInputDensity = res != null ? inputDensity : Bitmap.DENSITY_NONE;
-        }
-
-        final Resources mResources;
-        InputStream mInputStream;
-        final int mInputDensity;
-
-        @Override
-        public Resources getResources() { return mResources; }
-
-        @Override
-        public int getDensity() { return mInputDensity; }
-
-        @Override
-        public ImageDecoder createImageDecoder() throws IOException {
-            return new ImageDecoder();
-        }
-    }
-
-    /**
-     * Takes ownership of the AssetInputStream.
-     *
-     * @hide
-     */
-    public static class AssetInputStreamSource extends Source {
-        public AssetInputStreamSource(@NonNull AssetInputStream ais,
-                @NonNull Resources res, @NonNull TypedValue value) {
-            mAssetInputStream = ais;
-            mResources = res;
-
-            if (value.density == TypedValue.DENSITY_DEFAULT) {
-                mDensity = DisplayMetrics.DENSITY_DEFAULT;
-            } else if (value.density != TypedValue.DENSITY_NONE) {
-                mDensity = value.density;
-            } else {
-                mDensity = Bitmap.DENSITY_NONE;
-            }
-        }
-
-        private AssetInputStream mAssetInputStream;
-        private final Resources  mResources;
-        private final int        mDensity;
-
-        @Override
-        public Resources getResources() { return mResources; }
-
-        @Override
-        public int getDensity() {
-            return mDensity;
-        }
-
-        @Override
-        public ImageDecoder createImageDecoder() throws IOException {
-            return new ImageDecoder();
-        }
-    }
-
-    private static class ResourceSource extends Source {
-        ResourceSource(@NonNull Resources res, int resId) {
-            mResources = res;
-            mResId = resId;
-            mResDensity = Bitmap.DENSITY_NONE;
-        }
-
-        final Resources mResources;
-        final int       mResId;
-        int             mResDensity;
-
-        @Override
-        public Resources getResources() { return mResources; }
-
-        @Override
-        public int getDensity() { return mResDensity; }
-
-        @Override
-        public ImageDecoder createImageDecoder() throws IOException {
-            return new ImageDecoder();
-        }
-    }
-
-    private static class FileSource extends Source {
-        FileSource(@NonNull File file) {
-            mFile = file;
-        }
-
-        private final File mFile;
-
-        @Override
-        public ImageDecoder createImageDecoder() throws IOException {
-            return new ImageDecoder();
-        }
-    }
-
-    /**
-     *  Contains information about the encoded image.
-     */
-    public static class ImageInfo {
-        private ImageDecoder mDecoder;
-
-        private ImageInfo(@NonNull ImageDecoder decoder) {
-            mDecoder = decoder;
-        }
-
-        /**
-         * Size of the image, without scaling or cropping.
-         */
-        @NonNull
-        public Size getSize() {
-            return new Size(0, 0);
-        }
-
-        /**
-         * The mimeType of the image.
-         */
-        @NonNull
-        public String getMimeType() {
-            return "";
-        }
-
-        /**
-         * Whether the image is animated.
-         *
-         * <p>Calling {@link #decodeDrawable} will return an
-         * {@link AnimatedImageDrawable}.</p>
-         */
-        public boolean isAnimated() {
-            return mDecoder.mAnimated;
-        }
-    };
-
-    /**
-     *  Thrown if the provided data is incomplete.
-     */
-    public static class IncompleteException extends IOException {};
-
-    /**
-     *  Optional listener supplied to {@link #decodeDrawable} or
-     *  {@link #decodeBitmap}.
-     */
-    public interface OnHeaderDecodedListener {
-        /**
-         *  Called when the header is decoded and the size is known.
-         *
-         *  @param decoder allows changing the default settings of the decode.
-         *  @param info Information about the encoded image.
-         *  @param source that created the decoder.
-         */
-        void onHeaderDecoded(@NonNull ImageDecoder decoder,
-                @NonNull ImageInfo info, @NonNull Source source);
-
-    };
-
-    /**
-     *  An Exception was thrown reading the {@link Source}.
-     */
-    public static final int ERROR_SOURCE_EXCEPTION  = 1;
-
-    /**
-     *  The encoded data was incomplete.
-     */
-    public static final int ERROR_SOURCE_INCOMPLETE = 2;
-
-    /**
-     *  The encoded data contained an error.
-     */
-    public static final int ERROR_SOURCE_ERROR      = 3;
-
-    @Retention(SOURCE)
-    public @interface Error {}
-
-    /**
-     *  Optional listener supplied to the ImageDecoder.
-     *
-     *  Without this listener, errors will throw {@link java.io.IOException}.
-     */
-    public interface OnPartialImageListener {
-        /**
-         *  Called when there is only a partial image to display.
-         *
-         *  If decoding is interrupted after having decoded a partial image,
-         *  this listener lets the client know that and allows them to
-         *  optionally finish the rest of the decode/creation process to create
-         *  a partial {@link Drawable}/{@link Bitmap}.
-         *
-         *  @param error indicating what interrupted the decode.
-         *  @param source that had the error.
-         *  @return True to create and return a {@link Drawable}/{@link Bitmap}
-         *      with partial data. False (which is the default) to abort the
-         *      decode and throw {@link java.io.IOException}.
-         */
-        boolean onPartialImage(@Error int error, @NonNull Source source);
-    }
-
-    private boolean mAnimated;
-    private Rect mOutPaddingRect;
-
-    public ImageDecoder() {
-        mAnimated = true; // This is too avoid throwing an exception in AnimatedImageDrawable
-    }
-
-    /**
-     * Create a new {@link Source} from an asset.
-     * @hide
-     *
-     * @param res the {@link Resources} object containing the image data.
-     * @param resId resource ID of the image data.
-     *      // FIXME: Can be an @DrawableRes?
-     * @return a new Source object, which can be passed to
-     *      {@link #decodeDrawable} or {@link #decodeBitmap}.
-     */
-    @NonNull
-    public static Source createSource(@NonNull Resources res, int resId)
-    {
-        return new ResourceSource(res, resId);
-    }
-
-    /**
-     * Create a new {@link Source} from a {@link android.net.Uri}.
-     *
-     * @param cr to retrieve from.
-     * @param uri of the image file.
-     * @return a new Source object, which can be passed to
-     *      {@link #decodeDrawable} or {@link #decodeBitmap}.
-     */
-    @NonNull
-    public static Source createSource(@NonNull ContentResolver cr,
-            @NonNull Uri uri) {
-        return new ContentResolverSource(cr, uri);
-    }
-
-    /**
-     * Create a new {@link Source} from a byte array.
-     *
-     * @param data byte array of compressed image data.
-     * @param offset offset into data for where the decoder should begin
-     *      parsing.
-     * @param length number of bytes, beginning at offset, to parse.
-     * @throws NullPointerException if data is null.
-     * @throws ArrayIndexOutOfBoundsException if offset and length are
-     *      not within data.
-     * @hide
-     */
-    @NonNull
-    public static Source createSource(@NonNull byte[] data, int offset,
-            int length) throws ArrayIndexOutOfBoundsException {
-        if (offset < 0 || length < 0 || offset >= data.length ||
-                offset + length > data.length) {
-            throw new ArrayIndexOutOfBoundsException(
-                    "invalid offset/length!");
-        }
-        return new ByteArraySource(data, offset, length);
-    }
-
-    /**
-     * See {@link #createSource(byte[], int, int).
-     * @hide
-     */
-    @NonNull
-    public static Source createSource(@NonNull byte[] data) {
-        return createSource(data, 0, data.length);
-    }
-
-    /**
-     * Create a new {@link Source} from a {@link java.nio.ByteBuffer}.
-     *
-     * <p>The returned {@link Source} effectively takes ownership of the
-     * {@link java.nio.ByteBuffer}; i.e. no other code should modify it after
-     * this call.</p>
-     *
-     * Decoding will start from {@link java.nio.ByteBuffer#position()}. The
-     * position after decoding is undefined.
-     */
-    @NonNull
-    public static Source createSource(@NonNull ByteBuffer buffer) {
-        return new ByteBufferSource(buffer);
-    }
-
-    /**
-     * Internal API used to generate bitmaps for use by Drawables (i.e. BitmapDrawable)
-     * @hide
-     */
-    public static Source createSource(Resources res, InputStream is) {
-        return new InputStreamSource(res, is, Bitmap.getDefaultDensity());
-    }
-
-    /**
-     * Internal API used to generate bitmaps for use by Drawables (i.e. BitmapDrawable)
-     * @hide
-     */
-    public static Source createSource(Resources res, InputStream is, int density) {
-        return new InputStreamSource(res, is, density);
-    }
-
-    /**
-     * Create a new {@link Source} from a {@link java.io.File}.
-     */
-    @NonNull
-    public static Source createSource(@NonNull File file) {
-        return new FileSource(file);
-    }
-
-    /**
-     *  Return the width and height of a given sample size.
-     *
-     *  <p>This takes an input that functions like
-     *  {@link BitmapFactory.Options#inSampleSize}. It returns a width and
-     *  height that can be acheived by sampling the encoded image. Other widths
-     *  and heights may be supported, but will require an additional (internal)
-     *  scaling step. Such internal scaling is *not* supported with
-     *  {@link #setRequireUnpremultiplied} set to {@code true}.</p>
-     *
-     *  @param sampleSize Sampling rate of the encoded image.
-     *  @return {@link android.util.Size} of the width and height after
-     *      sampling.
-     */
-    @NonNull
-    public Size getSampledSize(int sampleSize) {
-        return new Size(0, 0);
-    }
-
-    // Modifiers
-    /**
-     *  Resize the output to have the following size.
-     *
-     *  @param width must be greater than 0.
-     *  @param height must be greater than 0.
-     */
-    public void setResize(int width, int height) {
-    }
-
-    /**
-     *  Resize based on a sample size.
-     *
-     *  <p>This has the same effect as passing the result of
-     *  {@link #getSampledSize} to {@link #setResize(int, int)}.</p>
-     *
-     *  @param sampleSize Sampling rate of the encoded image.
-     */
-    public void setResize(int sampleSize) {
-    }
-
-    // These need to stay in sync with ImageDecoder.cpp's Allocator enum.
-    /**
-     *  Use the default allocation for the pixel memory.
-     *
-     *  Will typically result in a {@link Bitmap.Config#HARDWARE}
-     *  allocation, but may be software for small images. In addition, this will
-     *  switch to software when HARDWARE is incompatible, e.g.
-     *  {@link #setMutable}, {@link #setAsAlphaMask}.
-     */
-    public static final int ALLOCATOR_DEFAULT = 0;
-
-    /**
-     *  Use a software allocation for the pixel memory.
-     *
-     *  Useful for drawing to a software {@link Canvas} or for
-     *  accessing the pixels on the final output.
-     */
-    public static final int ALLOCATOR_SOFTWARE = 1;
-
-    /**
-     *  Use shared memory for the pixel memory.
-     *
-     *  Useful for sharing across processes.
-     */
-    public static final int ALLOCATOR_SHARED_MEMORY = 2;
-
-    /**
-     *  Require a {@link Bitmap.Config#HARDWARE} {@link Bitmap}.
-     *
-     *  When this is combined with incompatible options, like
-     *  {@link #setMutable} or {@link #setAsAlphaMask}, {@link #decodeDrawable}
-     *  / {@link #decodeBitmap} will throw an
-     *  {@link java.lang.IllegalStateException}.
-     */
-    public static final int ALLOCATOR_HARDWARE = 3;
-
-    /** @hide **/
-    @Retention(SOURCE)
-    public @interface Allocator {};
-
-    /**
-     *  Choose the backing for the pixel memory.
-     *
-     *  This is ignored for animated drawables.
-     *
-     *  @param allocator Type of allocator to use.
-     */
-    public void setAllocator(@Allocator int allocator) { }
-
-    /**
-     *  Specify whether the {@link Bitmap} should have unpremultiplied pixels.
-     *
-     *  By default, ImageDecoder will create a {@link Bitmap} with
-     *  premultiplied pixels, which is required for drawing with the
-     *  {@link android.view.View} system (i.e. to a {@link Canvas}). Calling
-     *  this method with a value of {@code true} will result in
-     *  {@link #decodeBitmap} returning a {@link Bitmap} with unpremultiplied
-     *  pixels. See {@link Bitmap#isPremultiplied}. This is incompatible with
-     *  {@link #decodeDrawable}; attempting to decode an unpremultiplied
-     *  {@link Drawable} will throw an {@link java.lang.IllegalStateException}.
-     */
-    public ImageDecoder setRequireUnpremultiplied(boolean requireUnpremultiplied) {
-        return this;
-    }
-
-    /**
-     *  Modify the image after decoding and scaling.
-     *
-     *  <p>This allows adding effects prior to returning a {@link Drawable} or
-     *  {@link Bitmap}. For a {@code Drawable} or an immutable {@code Bitmap},
-     *  this is the only way to process the image after decoding.</p>
-     *
-     *  <p>If set on a nine-patch image, the nine-patch data is ignored.</p>
-     *
-     *  <p>For an animated image, the drawing commands drawn on the
-     *  {@link Canvas} will be recorded immediately and then applied to each
-     *  frame.</p>
-     */
-    public void setPostProcessor(@Nullable PostProcessor p) { }
-
-    /**
-     *  Set (replace) the {@link OnPartialImageListener} on this object.
-     *
-     *  Will be called if there is an error in the input. Without one, a
-     *  partial {@link Bitmap} will be created.
-     */
-    public void setOnPartialImageListener(@Nullable OnPartialImageListener l) { }
-
-    /**
-     *  Crop the output to {@code subset} of the (possibly) scaled image.
-     *
-     *  <p>{@code subset} must be contained within the size set by
-     *  {@link #setResize} or the bounds of the image if setResize was not
-     *  called. Otherwise an {@link IllegalStateException} will be thrown by
-     *  {@link #decodeDrawable}/{@link #decodeBitmap}.</p>
-     *
-     *  <p>NOT intended as a replacement for
-     *  {@link BitmapRegionDecoder#decodeRegion}. This supports all formats,
-     *  but merely crops the output.</p>
-     */
-    public void setCrop(@Nullable Rect subset) { }
-
-    /**
-     *  Set a Rect for retrieving nine patch padding.
-     *
-     *  If the image is a nine patch, this Rect will be set to the padding
-     *  rectangle during decode. Otherwise it will not be modified.
-     *
-     *  @hide
-     */
-    public void setOutPaddingRect(@NonNull Rect outPadding) {
-        mOutPaddingRect = outPadding;
-    }
-
-    /**
-     *  Specify whether the {@link Bitmap} should be mutable.
-     *
-     *  <p>By default, a {@link Bitmap} created will be immutable, but that can
-     *  be changed with this call.</p>
-     *
-     *  <p>Mutable Bitmaps are incompatible with {@link #ALLOCATOR_HARDWARE},
-     *  because {@link Bitmap.Config#HARDWARE} Bitmaps cannot be mutable.
-     *  Attempting to combine them will throw an
-     *  {@link java.lang.IllegalStateException}.</p>
-     *
-     *  <p>Mutable Bitmaps are also incompatible with {@link #decodeDrawable},
-     *  which would require retrieving the Bitmap from the returned Drawable in
-     *  order to modify. Attempting to decode a mutable {@link Drawable} will
-     *  throw an {@link java.lang.IllegalStateException}.</p>
-     */
-    public ImageDecoder setMutable(boolean mutable) {
-        return this;
-    }
-
-    /**
-     *  Specify whether to potentially save RAM at the expense of quality.
-     *
-     *  Setting this to {@code true} may result in a {@link Bitmap} with a
-     *  denser {@link Bitmap.Config}, depending on the image. For example, for
-     *  an opaque {@link Bitmap}, this may result in a {@link Bitmap.Config}
-     *  with no alpha information.
-     */
-    public ImageDecoder setPreferRamOverQuality(boolean preferRamOverQuality) {
-        return this;
-    }
-
-    /**
-     *  Specify whether to potentially treat the output as an alpha mask.
-     *
-     *  <p>If this is set to {@code true} and the image is encoded in a format
-     *  with only one channel, treat that channel as alpha. Otherwise this call has
-     *  no effect.</p>
-     *
-     *  <p>setAsAlphaMask is incompatible with {@link #ALLOCATOR_HARDWARE}. Trying to
-     *  combine them will result in {@link #decodeDrawable}/
-     *  {@link #decodeBitmap} throwing an
-     *  {@link java.lang.IllegalStateException}.</p>
-     */
-    public ImageDecoder setAsAlphaMask(boolean asAlphaMask) {
-        return this;
-    }
-
-    @Override
-    public void close() {
-    }
-
-    /**
-     *  Create a {@link Drawable} from a {@code Source}.
-     *
-     *  @param src representing the encoded image.
-     *  @param listener for learning the {@link ImageInfo} and changing any
-     *      default settings on the {@code ImageDecoder}. If not {@code null},
-     *      this will be called on the same thread as {@code decodeDrawable}
-     *      before that method returns.
-     *  @return Drawable for displaying the image.
-     *  @throws IOException if {@code src} is not found, is an unsupported
-     *      format, or cannot be decoded for any reason.
-     */
-    @NonNull
-    public static Drawable decodeDrawable(@NonNull Source src,
-            @Nullable OnHeaderDecodedListener listener) throws IOException {
-        Bitmap bitmap = decodeBitmap(src, listener);
-        return new BitmapDrawable(src.getResources(), bitmap);
-    }
-
-    /**
-     * See {@link #decodeDrawable(Source, OnHeaderDecodedListener)}.
-     */
-    @NonNull
-    public static Drawable decodeDrawable(@NonNull Source src)
-            throws IOException {
-        return decodeDrawable(src, null);
-    }
-
-    /**
-     *  Create a {@link Bitmap} from a {@code Source}.
-     *
-     *  @param src representing the encoded image.
-     *  @param listener for learning the {@link ImageInfo} and changing any
-     *      default settings on the {@code ImageDecoder}. If not {@code null},
-     *      this will be called on the same thread as {@code decodeBitmap}
-     *      before that method returns.
-     *  @return Bitmap containing the image.
-     *  @throws IOException if {@code src} is not found, is an unsupported
-     *      format, or cannot be decoded for any reason.
-     */
-    @NonNull
-    public static Bitmap decodeBitmap(@NonNull Source src,
-            @Nullable OnHeaderDecodedListener listener) throws IOException {
-        TypedValue value = new TypedValue();
-        value.density = src.getDensity();
-        ImageDecoder decoder = src.createImageDecoder();
-        if (listener != null) {
-            listener.onHeaderDecoded(decoder, new ImageInfo(decoder), src);
-        }
-        return BitmapFactory.decodeResourceStream(src.getResources(), value,
-                ((InputStreamSource) src).mInputStream, decoder.mOutPaddingRect, null);
-    }
-
-    /**
-     *  See {@link #decodeBitmap(Source, OnHeaderDecodedListener)}.
-     */
-    @NonNull
-    public static Bitmap decodeBitmap(@NonNull Source src) throws IOException {
-        return decodeBitmap(src, null);
-    }
-
-    public static final class DecodeException extends IOException {
-        /**
-         *  An Exception was thrown reading the {@link Source}.
-         */
-        public static final int SOURCE_EXCEPTION  = 1;
-
-        /**
-         *  The encoded data was incomplete.
-         */
-        public static final int SOURCE_INCOMPLETE = 2;
-
-        /**
-         *  The encoded data contained an error.
-         */
-        public static final int SOURCE_MALFORMED_DATA      = 3;
-
-        @Error final int mError;
-        @NonNull final Source mSource;
-
-        DecodeException(@Error int error, @Nullable Throwable cause, @NonNull Source source) {
-            super(errorMessage(error, cause), cause);
-            mError = error;
-            mSource = source;
-        }
-
-        /**
-         * Private method called by JNI.
-         */
-        @SuppressWarnings("unused")
-        DecodeException(@Error int error, @Nullable String msg, @Nullable Throwable cause,
-                @NonNull Source source) {
-            super(msg + errorMessage(error, cause), cause);
-            mError = error;
-            mSource = source;
-        }
-
-        /**
-         *  Retrieve the reason that decoding was interrupted.
-         *
-         *  <p>If the error is {@link #SOURCE_EXCEPTION}, the underlying
-         *  {@link java.lang.Throwable} can be retrieved with
-         *  {@link java.lang.Throwable#getCause}.</p>
-         */
-        @Error
-        public int getError() {
-            return mError;
-        }
-
-        /**
-         *  Retrieve the {@link Source Source} that was interrupted.
-         *
-         *  <p>This can be used for equality checking to find the Source which
-         *  failed to completely decode.</p>
-         */
-        @NonNull
-        public Source getSource() {
-            return mSource;
-        }
-
-        private static String errorMessage(@Error int error, @Nullable Throwable cause) {
-            switch (error) {
-                case SOURCE_EXCEPTION:
-                    return "Exception in input: " + cause;
-                case SOURCE_INCOMPLETE:
-                    return "Input was incomplete.";
-                case SOURCE_MALFORMED_DATA:
-                    return "Input contained an error.";
-                default:
-                    return "";
-            }
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/ImageDecoder_Delegate.java b/bridge/src/android/graphics/ImageDecoder_Delegate.java
new file mode 100644
index 0000000..4eebc9d
--- /dev/null
+++ b/bridge/src/android/graphics/ImageDecoder_Delegate.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.util.NinePatchInputStream;
+import com.android.ninepatch.GraphicsUtilities;
+import com.android.ninepatch.NinePatch;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.annotation.NonNull;
+import android.graphics.Bitmap.Config;
+import android.graphics.ImageDecoder.InputStreamSource;
+import android.graphics.ImageDecoder.OnHeaderDecodedListener;
+import android.graphics.ImageDecoder.Source;
+
+import java.awt.image.BufferedImage;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ImageDecoder_Delegate {
+
+    @LayoutlibDelegate
+    /*package*/ static Bitmap decodeBitmapImpl(@NonNull Source src,
+            @NonNull OnHeaderDecodedListener listener) throws IOException {
+        InputStream stream = src instanceof InputStreamSource ?
+                ((InputStreamSource) src).mInputStream : null;
+        Bitmap bm = ImageDecoder.decodeBitmapImpl_Original(src, listener);
+        if (stream instanceof NinePatchInputStream && bm.getNinePatchChunk() == null) {
+            stream = new FileInputStream(((NinePatchInputStream) stream).getPath());
+            NinePatch ninePatch = NinePatch.load(stream, true /*is9Patch*/, false /* convert */);
+            BufferedImage image = ninePatch.getImage();
+
+            // width and height of the nine patch without the special border.
+            int width = image.getWidth();
+            int height = image.getHeight();
+
+            // Get pixel data from image independently of its type.
+            int[] imageData = GraphicsUtilities.getPixels(image, 0, 0, width, height, null);
+
+            bm = Bitmap.createBitmap(imageData, width, height, Config.ARGB_8888);
+
+            bm.setDensity(src.getDensity());
+            bm.setNinePatchChunk(ninePatch.getChunk().getSerializedChunk());
+        }
+        return bm;
+    }
+}
diff --git a/bridge/src/android/graphics/LayoutlibRenderer.java b/bridge/src/android/graphics/LayoutlibRenderer.java
new file mode 100644
index 0000000..e96c790
--- /dev/null
+++ b/bridge/src/android/graphics/LayoutlibRenderer.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.graphics;
+
+import android.annotation.Nullable;
+
+public class LayoutlibRenderer extends HardwareRenderer {
+
+    private float scaleX = 1.0f;
+    private float scaleY = 1.0f;
+
+    /**
+     * We are overriding this method in order to call {@link Canvas#enableZ} (for shadows) and set
+     * the scale
+     */
+    @Override
+    public void setContentRoot(@Nullable RenderNode content) {
+        RecordingCanvas canvas = mRootNode.beginRecording();
+        canvas.scale(scaleX, scaleY);
+        canvas.enableZ();
+        // This way we clear the native image buffer before drawing
+        canvas.drawColor(0, BlendMode.CLEAR);
+        if (content != null) {
+            canvas.drawRenderNode(content);
+        }
+        canvas.disableZ();
+        mRootNode.endRecording();
+    }
+
+    public void setScale(float scaleX, float scaleY) {
+        this.scaleX = scaleX;
+        this.scaleY = scaleY;
+    }
+}
diff --git a/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/bridge/src/android/graphics/LightingColorFilter_Delegate.java
deleted file mode 100644
index 0dd9703..0000000
--- a/bridge/src/android/graphics/LightingColorFilter_Delegate.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.LightingColorFilter
- *
- * Through the layoutlib_create tool, the original native methods of LightingColorFilter have
- * been replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original LightingColorFilter class.
- *
- * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the Shader classes will be added to the manager
- * owned by {@link ColorFilter_Delegate}.
- *
- * @see ColorFilter_Delegate
- *
- */
-public class LightingColorFilter_Delegate extends ColorFilter_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public String getSupportMessage() {
-        return "Lighting Color Filters are not supported.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long native_CreateLightingFilter(int mul, int add) {
-        LightingColorFilter_Delegate newDelegate = new LightingColorFilter_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/LinearGradient_Delegate.java b/bridge/src/android/graphics/LinearGradient_Delegate.java
deleted file mode 100644
index 4574dd7..0000000
--- a/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.Shader.TileMode;
-
-import java.awt.image.ColorModel;
-import java.awt.image.DataBufferInt;
-import java.awt.image.Raster;
-import java.awt.image.SampleModel;
-
-/**
- * Delegate implementing the native methods of android.graphics.LinearGradient
- *
- * Through the layoutlib_create tool, the original native methods of LinearGradient have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original LinearGradient class.
- *
- * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
- * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
- *
- * @see Shader_Delegate
- *
- */
-public final class LinearGradient_Delegate extends Gradient_Delegate {
-
-    // ---- delegate data ----
-    private java.awt.Paint mJavaPaint;
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public java.awt.Paint getJavaPaint() {
-        return mJavaPaint;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(LinearGradient thisGradient, long matrix,
-            float x0, float y0, float x1, float y1, long[] colors, float[] positions,
-            int tileMode, long colorSpaceHandle) {
-        LinearGradient_Delegate newDelegate = new LinearGradient_Delegate(matrix, x0, y0,
-                x1, y1, colors, positions, Shader_Delegate.getTileMode(tileMode));
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-
-    /**
-     * Create a shader that draws a linear gradient along a line.
-     *
-     * @param nativeMatrix reference to the shader's native transformation matrix
-     * @param x0 The x-coordinate for the start of the gradient line
-     * @param y0 The y-coordinate for the start of the gradient line
-     * @param x1 The x-coordinate for the end of the gradient line
-     * @param y1 The y-coordinate for the end of the gradient line
-     * @param colors The colors to be distributed along the gradient line
-     * @param positions May be null. The relative positions [0..1] of each
-     *            corresponding color in the colors array. If this is null, the
-     *            the colors are distributed evenly along the gradient line.
-     * @param tile The Shader tiling mode
-     */
-    private LinearGradient_Delegate(long nativeMatrix, float x0, float y0, float x1,
-            float y1, long[] colors, float[] positions, TileMode tile) {
-        super(nativeMatrix, colors, positions);
-        mJavaPaint = new LinearGradientPaint(x0, y0, x1, y1, mColors, mPositions, tile);
-    }
-
-    // ---- Custom Java Paint ----
-    /**
-     * Linear Gradient (Java) Paint able to handle more than 2 points, as
-     * {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile
-     * modes.
-     */
-    private class LinearGradientPaint extends GradientPaint {
-
-        private final float mX0;
-        private final float mY0;
-        private final float mDx;
-        private final float mDy;
-        private final float mDSize2;
-
-        public LinearGradientPaint(float x0, float y0, float x1, float y1, int[] colors,
-                float[] positions, TileMode tile) {
-            super(colors, positions, tile);
-            mX0 = x0;
-            mY0 = y0;
-            mDx = x1 - x0;
-            mDy = y1 - y0;
-            mDSize2 = mDx * mDx + mDy * mDy;
-        }
-
-        @Override
-        public java.awt.PaintContext createContext(
-                java.awt.image.ColorModel      colorModel,
-                java.awt.Rectangle             deviceBounds,
-                java.awt.geom.Rectangle2D      userBounds,
-                java.awt.geom.AffineTransform  xform,
-                java.awt.RenderingHints        hints) {
-            precomputeGradientColors();
-
-            java.awt.geom.AffineTransform canvasMatrix;
-            try {
-                canvasMatrix = xform.createInverse();
-            } catch (java.awt.geom.NoninvertibleTransformException e) {
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in LinearGradient", e, null, null /*data*/);
-                canvasMatrix = new java.awt.geom.AffineTransform();
-            }
-
-            java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
-            try {
-                localMatrix = localMatrix.createInverse();
-            } catch (java.awt.geom.NoninvertibleTransformException e) {
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in LinearGradient", e, null, null /*data*/);
-                localMatrix = new java.awt.geom.AffineTransform();
-            }
-
-            return new LinearGradientPaintContext(canvasMatrix, localMatrix, colorModel);
-        }
-
-        private class LinearGradientPaintContext implements java.awt.PaintContext {
-
-            private final java.awt.geom.AffineTransform mCanvasMatrix;
-            private final java.awt.geom.AffineTransform mLocalMatrix;
-            private final java.awt.image.ColorModel mColorModel;
-
-            private LinearGradientPaintContext(
-                    java.awt.geom.AffineTransform canvasMatrix,
-                    java.awt.geom.AffineTransform localMatrix,
-                    java.awt.image.ColorModel colorModel) {
-                mCanvasMatrix = canvasMatrix;
-                mLocalMatrix = localMatrix;
-                mColorModel = colorModel.hasAlpha() ? colorModel : ColorModel.getRGBdefault();
-            }
-
-            @Override
-            public void dispose() {
-            }
-
-            @Override
-            public java.awt.image.ColorModel getColorModel() {
-                return mColorModel;
-            }
-
-            @Override
-            public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
-                int[] data = new int[w*h];
-
-                int index = 0;
-                float[] pt1 = new float[2];
-                float[] pt2 = new float[2];
-                for (int iy = 0 ; iy < h ; iy++) {
-                    for (int ix = 0 ; ix < w ; ix++) {
-                        // handle the canvas transform
-                        pt1[0] = x + ix;
-                        pt1[1] = y + iy;
-                        mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
-
-                        // handle the local matrix.
-                        pt1[0] = pt2[0];
-                        pt1[1] = pt2[1];
-                        mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
-
-                        data[index++] = getColor(pt2[0], pt2[1]);
-                    }
-                }
-
-                DataBufferInt dataBuffer = new DataBufferInt(data, data.length);
-                SampleModel colorModel = mColorModel.createCompatibleSampleModel(w, h);
-                return Raster.createWritableRaster(colorModel, dataBuffer, null);
-            }
-        }
-
-        /**
-         * Returns a color for an arbitrary point.
-         */
-        private int getColor(float x, float y) {
-            float pos;
-            if (mDx == 0) {
-                pos = (y - mY0) / mDy;
-            } else if (mDy == 0) {
-                pos = (x - mX0) / mDx;
-            } else {
-                // find the x position on the gradient vector.
-                float _x = (mDx*mDy*(y-mY0) + mDy*mDy*mX0 + mDx*mDx*x) / mDSize2;
-                // from it get the position relative to the vector
-                pos = (_x - mX0) / mDx;
-            }
-
-            return getGradientColor(pos);
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/MaskFilter_Delegate.java b/bridge/src/android/graphics/MaskFilter_Delegate.java
deleted file mode 100644
index e726c59..0000000
--- a/bridge/src/android/graphics/MaskFilter_Delegate.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.MaskFilter
- *
- * Through the layoutlib_create tool, the original native methods of MaskFilter have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original MaskFilter class.
- *
- * This also serve as a base class for all MaskFilter delegate classes.
- *
- * @see DelegateManager
- *
- */
-public abstract class MaskFilter_Delegate {
-
-    // ---- delegate manager ----
-    protected static final DelegateManager<MaskFilter_Delegate> sManager =
-            new DelegateManager<MaskFilter_Delegate>(MaskFilter_Delegate.class);
-
-    // ---- delegate helper data ----
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    public static MaskFilter_Delegate getDelegate(long nativeShader) {
-        return sManager.getDelegate(nativeShader);
-    }
-
-    public abstract boolean isSupported();
-    public abstract String getSupportMessage();
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeDestructor(long native_filter) {
-        sManager.removeJavaReferenceFor(native_filter);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/Matrix_Delegate.java b/bridge/src/android/graphics/Matrix_Delegate.java
deleted file mode 100644
index d0a0adc..0000000
--- a/bridge/src/android/graphics/Matrix_Delegate.java
+++ /dev/null
@@ -1,1084 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.Matrix.ScaleToFit;
-
-import java.awt.geom.AffineTransform;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.Matrix
- *
- * Through the layoutlib_create tool, the original native methods of Matrix have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original Matrix class.
- *
- * @see DelegateManager
- *
- */
-public final class Matrix_Delegate {
-
-    private final static int MATRIX_SIZE = 9;
-
-    // ---- delegate manager ----
-    private static final DelegateManager<Matrix_Delegate> sManager =
-            new DelegateManager<Matrix_Delegate>(Matrix_Delegate.class);
-    private static long sFinalizer = -1;
-
-    // ---- delegate data ----
-    private float mValues[] = new float[MATRIX_SIZE];
-
-    // ---- Public Helper methods ----
-
-    public static Matrix_Delegate getDelegate(long native_instance) {
-        return sManager.getDelegate(native_instance);
-    }
-
-    /**
-     * Returns an {@link AffineTransform} matching the given Matrix.
-     */
-    public static AffineTransform getAffineTransform(Matrix m) {
-        Matrix_Delegate delegate = sManager.getDelegate(m.ni());
-        if (delegate == null) {
-            return null;
-        }
-
-        return delegate.getAffineTransform();
-    }
-
-    public static boolean hasPerspective(Matrix m) {
-        Matrix_Delegate delegate = sManager.getDelegate(m.ni());
-        if (delegate == null) {
-            return false;
-        }
-
-        return delegate.hasPerspective();
-    }
-
-    /**
-     * Sets the content of the matrix with the content of another matrix.
-     */
-    public void set(Matrix_Delegate matrix) {
-        System.arraycopy(matrix.mValues, 0, mValues, 0, MATRIX_SIZE);
-    }
-
-    /**
-     * Sets the content of the matrix with the content of another matrix represented as an array
-     * of values.
-     */
-    public void set(float[] values) {
-        System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE);
-    }
-
-    /**
-     * Resets the matrix to be the identity matrix.
-     */
-    public void reset() {
-        reset(mValues);
-    }
-
-    /**
-     * Returns whether or not the matrix is identity.
-     */
-    public boolean isIdentity() {
-        for (int i = 0, k = 0; i < 3; i++) {
-            for (int j = 0; j < 3; j++, k++) {
-                if (mValues[k] != ((i==j) ? 1 : 0)) {
-                    return false;
-                }
-            }
-        }
-
-        return true;
-    }
-
-    private static float[] setValues(AffineTransform matrix, float[] values) {
-        values[0] = (float) matrix.getScaleX();
-        values[1] = (float) matrix.getShearX();
-        values[2] = (float) matrix.getTranslateX();
-        values[3] = (float) matrix.getShearY();
-        values[4] = (float) matrix.getScaleY();
-        values[5] = (float) matrix.getTranslateY();
-        values[6] = 0.f;
-        values[7] = 0.f;
-        values[8] = 1.f;
-
-        return values;
-    }
-
-    public static float[] makeValues(AffineTransform matrix) {
-        return setValues(matrix, new float[MATRIX_SIZE]);
-    }
-
-    public static Matrix_Delegate make(AffineTransform matrix) {
-        return new Matrix_Delegate(makeValues(matrix));
-    }
-
-    public boolean mapRect(RectF dst, RectF src) {
-        // array with 4 corners
-        float[] corners = new float[] {
-                src.left, src.top,
-                src.right, src.top,
-                src.right, src.bottom,
-                src.left, src.bottom,
-        };
-
-        // apply the transform to them.
-        mapPoints(corners);
-
-        // now put the result in the rect. We take the min/max of Xs and min/max of Ys
-        dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
-        dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
-
-        dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
-        dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
-
-
-        return (computeTypeMask() & kRectStaysRect_Mask) != 0;
-    }
-
-
-    /**
-     * Returns an {@link AffineTransform} matching the matrix.
-     */
-    public AffineTransform getAffineTransform() {
-        return getAffineTransform(mValues);
-    }
-
-    public boolean hasPerspective() {
-        return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1);
-    }
-
-
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreate(long native_src_or_zero) {
-        // create the delegate
-        Matrix_Delegate newDelegate = new Matrix_Delegate();
-
-        // copy from values if needed.
-        if (native_src_or_zero > 0) {
-            Matrix_Delegate oldDelegate = sManager.getDelegate(native_src_or_zero);
-            if (oldDelegate != null) {
-                System.arraycopy(
-                        oldDelegate.mValues, 0,
-                        newDelegate.mValues, 0,
-                        MATRIX_SIZE);
-            }
-        }
-
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nIsIdentity(long native_object) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return false;
-        }
-
-        return d.isIdentity();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nIsAffine(long native_object) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return true;
-        }
-
-        return (d.computeTypeMask() & kPerspective_Mask) == 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nRectStaysRect(long native_object) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return true;
-        }
-
-        return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nReset(long native_object) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        reset(d.mValues);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSet(long native_object, long other) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        Matrix_Delegate src = sManager.getDelegate(other);
-        if (src == null) {
-            return;
-        }
-
-        System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetTranslate(long native_object, float dx, float dy) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        setTranslate(d.mValues, dx, dy);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetScale(long native_object, float sx, float sy,
-            float px, float py) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        d.mValues = getScale(sx, sy, px, py);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetScale(long native_object, float sx, float sy) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        d.mValues[0] = sx;
-        d.mValues[1] = 0;
-        d.mValues[2] = 0;
-        d.mValues[3] = 0;
-        d.mValues[4] = sy;
-        d.mValues[5] = 0;
-        d.mValues[6] = 0;
-        d.mValues[7] = 0;
-        d.mValues[8] = 1;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetRotate(long native_object, float degrees, float px, float py) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        d.mValues = getRotate(degrees, px, py);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetRotate(long native_object, float degrees) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        setRotate(d.mValues, degrees);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue,
-            float px, float py) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        // TODO: do it in one pass
-
-        // translate so that the pivot is in 0,0
-        setTranslate(d.mValues, -px, -py);
-
-        // scale
-        d.postTransform(getRotate(sinValue, cosValue));
-        // translate back the pivot
-        d.postTransform(getTranslate(px, py));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetSinCos(long native_object, float sinValue, float cosValue) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        setRotate(d.mValues, sinValue, cosValue);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetSkew(long native_object, float kx, float ky,
-            float px, float py) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        d.mValues = getSkew(kx, ky, px, py);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetSkew(long native_object, float kx, float ky) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        d.mValues[0] = 1;
-        d.mValues[1] = kx;
-        d.mValues[2] = -0;
-        d.mValues[3] = ky;
-        d.mValues[4] = 1;
-        d.mValues[5] = 0;
-        d.mValues[6] = 0;
-        d.mValues[7] = 0;
-        d.mValues[8] = 1;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetConcat(long native_object, long a, long b) {
-        if (a == native_object) {
-            nPreConcat(native_object, b);
-            return;
-        } else if (b == native_object) {
-            nPostConcat(native_object, a);
-            return;
-        }
-
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        Matrix_Delegate a_mtx = sManager.getDelegate(a);
-        Matrix_Delegate b_mtx = sManager.getDelegate(b);
-        if (d != null && a_mtx != null && b_mtx != null) {
-            multiply(d.mValues, a_mtx.mValues, b_mtx.mValues);
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPreTranslate(long native_object, float dx, float dy) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.preTransform(getTranslate(dx, dy));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPreScale(long native_object, float sx, float sy,
-            float px, float py) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.preTransform(getScale(sx, sy, px, py));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPreScale(long native_object, float sx, float sy) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.preTransform(getScale(sx, sy));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPreRotate(long native_object, float degrees,
-            float px, float py) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.preTransform(getRotate(degrees, px, py));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPreRotate(long native_object, float degrees) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-
-            double rad = Math.toRadians(degrees);
-            float sin = (float) Math.sin(rad);
-            float cos = (float) Math.cos(rad);
-
-            d.preTransform(getRotate(sin, cos));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPreSkew(long native_object, float kx, float ky,
-            float px, float py) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.preTransform(getSkew(kx, ky, px, py));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPreSkew(long native_object, float kx, float ky) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.preTransform(getSkew(kx, ky));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPreConcat(long native_object, long other_matrix) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        Matrix_Delegate other = sManager.getDelegate(other_matrix);
-        if (d != null && other != null) {
-            d.preTransform(other.mValues);
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPostTranslate(long native_object, float dx, float dy) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.postTransform(getTranslate(dx, dy));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPostScale(long native_object, float sx, float sy,
-            float px, float py) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.postTransform(getScale(sx, sy, px, py));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPostScale(long native_object, float sx, float sy) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.postTransform(getScale(sx, sy));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPostRotate(long native_object, float degrees,
-            float px, float py) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.postTransform(getRotate(degrees, px, py));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPostRotate(long native_object, float degrees) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.postTransform(getRotate(degrees));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPostSkew(long native_object, float kx, float ky,
-            float px, float py) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.postTransform(getSkew(kx, ky, px, py));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPostSkew(long native_object, float kx, float ky) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d != null) {
-            d.postTransform(getSkew(kx, ky));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nPostConcat(long native_object, long other_matrix) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        Matrix_Delegate other = sManager.getDelegate(other_matrix);
-        if (d != null && other != null) {
-            d.postTransform(other.mValues);
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetRectToRect(long native_object, RectF src,
-            RectF dst, int stf) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return false;
-        }
-
-        if (src.isEmpty()) {
-            reset(d.mValues);
-            return false;
-        }
-
-        if (dst.isEmpty()) {
-            d.mValues[0] = d.mValues[1] = d.mValues[2] = d.mValues[3] = d.mValues[4] = d.mValues[5]
-               = d.mValues[6] = d.mValues[7] = 0;
-            d.mValues[8] = 1;
-        } else {
-            float    tx, sx = dst.width() / src.width();
-            float    ty, sy = dst.height() / src.height();
-            boolean  xLarger = false;
-
-            if (stf != ScaleToFit.FILL.nativeInt) {
-                if (sx > sy) {
-                    xLarger = true;
-                    sx = sy;
-                } else {
-                    sy = sx;
-                }
-            }
-
-            tx = dst.left - src.left * sx;
-            ty = dst.top - src.top * sy;
-            if (stf == ScaleToFit.CENTER.nativeInt || stf == ScaleToFit.END.nativeInt) {
-                float diff;
-
-                if (xLarger) {
-                    diff = dst.width() - src.width() * sy;
-                } else {
-                    diff = dst.height() - src.height() * sy;
-                }
-
-                if (stf == ScaleToFit.CENTER.nativeInt) {
-                    diff = diff / 2;
-                }
-
-                if (xLarger) {
-                    tx += diff;
-                } else {
-                    ty += diff;
-                }
-            }
-
-            d.mValues[0] = sx;
-            d.mValues[4] = sy;
-            d.mValues[2] = tx;
-            d.mValues[5] = ty;
-            d.mValues[1]  = d.mValues[3] = d.mValues[6] = d.mValues[7] = 0;
-
-        }
-        // shared cleanup
-        d.mValues[8] = 1;
-        return true;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetPolyToPoly(long native_object, float[] src, int srcIndex,
-            float[] dst, int dstIndex, int pointCount) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Matrix.setPolyToPoly is not supported.",
-                null, null, null /*data*/);
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nInvert(long native_object, long inverse) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return false;
-        }
-
-        Matrix_Delegate inv_mtx = sManager.getDelegate(inverse);
-        if (inv_mtx == null) {
-            return false;
-        }
-
-        float det = d.mValues[0] * (d.mValues[4] * d.mValues[8] - d.mValues[5] * d.mValues[7])
-                  + d.mValues[1] * (d.mValues[5] * d.mValues[6] - d.mValues[3] * d.mValues[8])
-                  + d.mValues[2] * (d.mValues[3] * d.mValues[7] - d.mValues[4] * d.mValues[6]);
-
-        if (det == 0.0) {
-            return false;
-        }
-
-        inv_mtx.mValues[0] = (d.mValues[4] * d.mValues[8] - d.mValues[5] * d.mValues[7]) / det;
-        inv_mtx.mValues[1] = (d.mValues[2] * d.mValues[7] - d.mValues[1] * d.mValues[8]) / det;
-        inv_mtx.mValues[2] = (d.mValues[1] * d.mValues[5] - d.mValues[2] * d.mValues[4]) / det;
-        inv_mtx.mValues[3] = (d.mValues[5] * d.mValues[6] - d.mValues[3] * d.mValues[8]) / det;
-        inv_mtx.mValues[4] = (d.mValues[0] * d.mValues[8] - d.mValues[2] * d.mValues[6]) / det;
-        inv_mtx.mValues[5] = (d.mValues[2] * d.mValues[3] - d.mValues[0] * d.mValues[5]) / det;
-        inv_mtx.mValues[6] = (d.mValues[3] * d.mValues[7] - d.mValues[4] * d.mValues[6]) / det;
-        inv_mtx.mValues[7] = (d.mValues[1] * d.mValues[6] - d.mValues[0] * d.mValues[7]) / det;
-        inv_mtx.mValues[8] = (d.mValues[0] * d.mValues[4] - d.mValues[1] * d.mValues[3]) / det;
-
-        return true;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nMapPoints(long native_object, float[] dst, int dstIndex,
-            float[] src, int srcIndex, int ptCount, boolean isPts) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        if (isPts) {
-            d.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
-        } else {
-            d.mapVectors(dst, dstIndex, src, srcIndex, ptCount);
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nMapRect(long native_object, RectF dst, RectF src) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return false;
-        }
-
-        return d.mapRect(dst, src);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nMapRadius(long native_object, float radius) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return 0.f;
-        }
-
-        float[] src = new float[] { radius, 0.f, 0.f, radius };
-        d.mapVectors(src, 0, src, 0, 2);
-
-        float l1 = (float) Math.hypot(src[0], src[1]);
-        float l2 = (float) Math.hypot(src[2], src[3]);
-        return (float) Math.sqrt(l1 * l2);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nGetValues(long native_object, float[] values) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        System.arraycopy(d.mValues, 0, values, 0, MATRIX_SIZE);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetValues(long native_object, float[] values) {
-        Matrix_Delegate d = sManager.getDelegate(native_object);
-        if (d == null) {
-            return;
-        }
-
-        System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nEquals(long native_a, long native_b) {
-        Matrix_Delegate a = sManager.getDelegate(native_a);
-        if (a == null) {
-            return false;
-        }
-
-        Matrix_Delegate b = sManager.getDelegate(native_b);
-        if (b == null) {
-            return false;
-        }
-
-        for (int i = 0 ; i < MATRIX_SIZE ; i++) {
-            if (a.mValues[i] != b.mValues[i]) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetNativeFinalizer() {
-        synchronized (Matrix_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor);
-            }
-        }
-        return sFinalizer;
-    }
-
-    // ---- Private helper methods ----
-
-    /*package*/ static AffineTransform getAffineTransform(float[] matrix) {
-        // the AffineTransform constructor takes the value in a different order
-        // for a matrix [ 0 1 2 ]
-        //              [ 3 4 5 ]
-        // the order is 0, 3, 1, 4, 2, 5...
-        return new AffineTransform(
-                matrix[0], matrix[3], matrix[1],
-                matrix[4], matrix[2], matrix[5]);
-    }
-
-    /**
-     * Reset a matrix to the identity
-     */
-    private static void reset(float[] mtx) {
-        for (int i = 0, k = 0; i < 3; i++) {
-            for (int j = 0; j < 3; j++, k++) {
-                mtx[k] = ((i==j) ? 1 : 0);
-            }
-        }
-    }
-
-    @SuppressWarnings("unused")
-    private final static int kIdentity_Mask      = 0;
-    private final static int kTranslate_Mask     = 0x01;  //!< set if the matrix has translation
-    private final static int kScale_Mask         = 0x02;  //!< set if the matrix has X or Y scale
-    private final static int kAffine_Mask        = 0x04;  //!< set if the matrix skews or rotates
-    private final static int kPerspective_Mask   = 0x08;  //!< set if the matrix is in perspective
-    private final static int kRectStaysRect_Mask = 0x10;
-    @SuppressWarnings("unused")
-    private final static int kUnknown_Mask       = 0x80;
-
-    @SuppressWarnings("unused")
-    private final static int kAllMasks           = kTranslate_Mask |
-                                                   kScale_Mask |
-                                                   kAffine_Mask |
-                                                   kPerspective_Mask |
-                                                   kRectStaysRect_Mask;
-
-    // these guys align with the masks, so we can compute a mask from a variable 0/1
-    @SuppressWarnings("unused")
-    private final static int kTranslate_Shift = 0;
-    @SuppressWarnings("unused")
-    private final static int kScale_Shift = 1;
-    @SuppressWarnings("unused")
-    private final static int kAffine_Shift = 2;
-    @SuppressWarnings("unused")
-    private final static int kPerspective_Shift = 3;
-    private final static int kRectStaysRect_Shift = 4;
-
-    private int computeTypeMask() {
-        int mask = 0;
-
-        if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) {
-            mask |= kPerspective_Mask;
-        }
-
-        if (mValues[2] != 0. || mValues[5] != 0.) {
-            mask |= kTranslate_Mask;
-        }
-
-        float m00 = mValues[0];
-        float m01 = mValues[1];
-        float m10 = mValues[3];
-        float m11 = mValues[4];
-
-        if (m01 != 0. || m10 != 0.) {
-            mask |= kAffine_Mask;
-        }
-
-        if (m00 != 1. || m11 != 1.) {
-            mask |= kScale_Mask;
-        }
-
-        if ((mask & kPerspective_Mask) == 0) {
-            // map non-zero to 1
-            int im00 = m00 != 0 ? 1 : 0;
-            int im01 = m01 != 0 ? 1 : 0;
-            int im10 = m10 != 0 ? 1 : 0;
-            int im11 = m11 != 0 ? 1 : 0;
-
-            // record if the (p)rimary and (s)econdary diagonals are all 0 or
-            // all non-zero (answer is 0 or 1)
-            int dp0 = (im00 | im11) ^ 1;  // true if both are 0
-            int dp1 = im00 & im11;        // true if both are 1
-            int ds0 = (im01 | im10) ^ 1;  // true if both are 0
-            int ds1 = im01 & im10;        // true if both are 1
-
-            // return 1 if primary is 1 and secondary is 0 or
-            // primary is 0 and secondary is 1
-            mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift;
-        }
-
-        return mask;
-    }
-
-    private Matrix_Delegate() {
-        reset();
-    }
-
-    private Matrix_Delegate(float[] values) {
-        System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE);
-    }
-
-    /**
-     * Adds the given transformation to the current Matrix
-     * <p/>This in effect does this = this*matrix
-     * @param matrix
-     */
-    private void postTransform(float[] matrix) {
-        float[] tmp = new float[9];
-        multiply(tmp, mValues, matrix);
-        mValues = tmp;
-    }
-
-    /**
-     * Adds the given transformation to the current Matrix
-     * <p/>This in effect does this = matrix*this
-     * @param matrix
-     */
-    private void preTransform(float[] matrix) {
-        float[] tmp = new float[9];
-        multiply(tmp, matrix, mValues);
-        mValues = tmp;
-    }
-
-    /**
-     * Apply this matrix to the array of 2D points specified by src, and write
-      * the transformed points into the array of points specified by dst. The
-      * two arrays represent their "points" as pairs of floats [x, y].
-      *
-      * @param dst   The array of dst points (x,y pairs)
-      * @param dstIndex The index of the first [x,y] pair of dst floats
-      * @param src   The array of src points (x,y pairs)
-      * @param srcIndex The index of the first [x,y] pair of src floats
-      * @param pointCount The number of points (x,y pairs) to transform
-      */
-
-     private void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
-                           int pointCount) {
-         final int count = pointCount * 2;
-
-         float[] tmpDest = dst;
-         boolean inPlace = dst == src;
-         if (inPlace) {
-             tmpDest = new float[dstIndex + count];
-         }
-
-         for (int i = 0 ; i < count ; i += 2) {
-             // just in case we are doing in place, we better put this in temp vars
-             float x = mValues[0] * src[i + srcIndex] +
-                       mValues[1] * src[i + srcIndex + 1] +
-                       mValues[2];
-             float y = mValues[3] * src[i + srcIndex] +
-                       mValues[4] * src[i + srcIndex + 1] +
-                       mValues[5];
-
-             tmpDest[i + dstIndex]     = x;
-             tmpDest[i + dstIndex + 1] = y;
-         }
-
-         if (inPlace) {
-             System.arraycopy(tmpDest, dstIndex, dst, dstIndex, count);
-         }
-     }
-
-     /**
-      * Apply this matrix to the array of 2D points, and write the transformed
-      * points back into the array
-      *
-      * @param pts The array [x0, y0, x1, y1, ...] of points to transform.
-      */
-
-     private void mapPoints(float[] pts) {
-         mapPoints(pts, 0, pts, 0, pts.length >> 1);
-     }
-
-     private void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount) {
-         if (hasPerspective()) {
-             // transform the (0,0) point
-             float[] origin = new float[] { 0.f, 0.f};
-             mapPoints(origin);
-
-             // translate the vector data as points
-             mapPoints(dst, dstIndex, src, srcIndex, ptCount);
-
-             // then substract the transformed origin.
-             final int count = ptCount * 2;
-             for (int i = 0 ; i < count ; i += 2) {
-                 dst[dstIndex + i] = dst[dstIndex + i] - origin[0];
-                 dst[dstIndex + i + 1] = dst[dstIndex + i + 1] - origin[1];
-             }
-         } else {
-             // make a copy of the matrix
-             Matrix_Delegate copy = new Matrix_Delegate(mValues);
-
-             // remove the translation
-             setTranslate(copy.mValues, 0, 0);
-
-             // map the content as points.
-             copy.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
-         }
-     }
-
-    /**
-     * multiply two matrices and store them in a 3rd.
-     * <p/>This in effect does dest = a*b
-     * dest cannot be the same as a or b.
-     */
-     /*package*/ static void multiply(float dest[], float[] a, float[] b) {
-        // first row
-        dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6];
-        dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7];
-        dest[2] = b[0] * a[2] + b[1] * a[5] + b[2] * a[8];
-
-        // 2nd row
-        dest[3] = b[3] * a[0] + b[4] * a[3] + b[5] * a[6];
-        dest[4] = b[3] * a[1] + b[4] * a[4] + b[5] * a[7];
-        dest[5] = b[3] * a[2] + b[4] * a[5] + b[5] * a[8];
-
-        // 3rd row
-        dest[6] = b[6] * a[0] + b[7] * a[3] + b[8] * a[6];
-        dest[7] = b[6] * a[1] + b[7] * a[4] + b[8] * a[7];
-        dest[8] = b[6] * a[2] + b[7] * a[5] + b[8] * a[8];
-    }
-
-    /**
-     * Returns a matrix that represents a given translate
-     * @param dx
-     * @param dy
-     * @return
-     */
-    /*package*/ static float[] getTranslate(float dx, float dy) {
-        return setTranslate(new float[9], dx, dy);
-    }
-
-    /*package*/ static float[] setTranslate(float[] dest, float dx, float dy) {
-        dest[0] = 1;
-        dest[1] = 0;
-        dest[2] = dx;
-        dest[3] = 0;
-        dest[4] = 1;
-        dest[5] = dy;
-        dest[6] = 0;
-        dest[7] = 0;
-        dest[8] = 1;
-        return dest;
-    }
-
-    /*package*/ static float[] getScale(float sx, float sy) {
-        return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 };
-    }
-
-    /**
-     * Returns a matrix that represents the given scale info.
-     * @param sx
-     * @param sy
-     * @param px
-     * @param py
-     */
-    /*package*/ static float[] getScale(float sx, float sy, float px, float py) {
-        float[] tmp = new float[9];
-        float[] tmp2 = new float[9];
-
-        // TODO: do it in one pass
-
-        // translate tmp so that the pivot is in 0,0
-        setTranslate(tmp, -px, -py);
-
-        // scale into tmp2
-        multiply(tmp2, tmp, getScale(sx, sy));
-
-        // translate back the pivot back into tmp
-        multiply(tmp, tmp2, getTranslate(px, py));
-
-        return tmp;
-    }
-
-
-    /*package*/ static float[] getRotate(float degrees) {
-        double rad = Math.toRadians(degrees);
-        float sin = (float)Math.sin(rad);
-        float cos = (float)Math.cos(rad);
-
-        return getRotate(sin, cos);
-    }
-
-    /*package*/ static float[] getRotate(float sin, float cos) {
-        return setRotate(new float[9], sin, cos);
-    }
-
-    /*package*/ static float[] setRotate(float[] dest, float degrees) {
-        double rad = Math.toRadians(degrees);
-        float sin = (float)Math.sin(rad);
-        float cos = (float)Math.cos(rad);
-
-        return setRotate(dest, sin, cos);
-    }
-
-    /*package*/ static float[] setRotate(float[] dest, float sin, float cos) {
-        dest[0] = cos;
-        dest[1] = -sin;
-        dest[2] = 0;
-        dest[3] = sin;
-        dest[4] = cos;
-        dest[5] = 0;
-        dest[6] = 0;
-        dest[7] = 0;
-        dest[8] = 1;
-        return dest;
-    }
-
-    /*package*/ static float[] getRotate(float degrees, float px, float py) {
-        float[] tmp = new float[9];
-        float[] tmp2 = new float[9];
-
-        // TODO: do it in one pass
-
-        // translate so that the pivot is in 0,0
-        setTranslate(tmp, -px, -py);
-
-        // rotate into tmp2
-        double rad = Math.toRadians(degrees);
-        float cos = (float)Math.cos(rad);
-        float sin = (float)Math.sin(rad);
-        multiply(tmp2, tmp, getRotate(sin, cos));
-
-        // translate back the pivot back into tmp
-        multiply(tmp, tmp2, getTranslate(px, py));
-
-        return tmp;
-    }
-
-    /*package*/ static float[] getSkew(float kx, float ky) {
-        return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 };
-    }
-
-    /*package*/ static float[] getSkew(float kx, float ky, float px, float py) {
-        float[] tmp = new float[9];
-        float[] tmp2 = new float[9];
-
-        // TODO: do it in one pass
-
-        // translate so that the pivot is in 0,0
-        setTranslate(tmp, -px, -py);
-
-        // skew into tmp2
-        multiply(tmp2, tmp, new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
-        // translate back the pivot back into tmp
-        multiply(tmp, tmp2, getTranslate(px, py));
-
-        return tmp;
-    }
-}
diff --git a/bridge/src/android/graphics/NinePatch_Delegate.java b/bridge/src/android/graphics/NinePatch_Delegate.java
deleted file mode 100644
index 28e682b..0000000
--- a/bridge/src/android/graphics/NinePatch_Delegate.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.ninepatch.NinePatchChunk;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.drawable.NinePatchDrawable;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.lang.ref.SoftReference;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Delegate implementing the native methods of android.graphics.NinePatch
- *
- * Through the layoutlib_create tool, the original native methods of NinePatch have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
- * around to map int to instance of the delegate.
- *
- */
-public final class NinePatch_Delegate {
-
-    // ---- delegate manager ----
-    private static final DelegateManager<NinePatch_Delegate> sManager =
-            new DelegateManager<>(NinePatch_Delegate.class);
-
-    // ---- delegate helper data ----
-    /**
-     * Cache map for {@link NinePatchChunk}.
-     * When the chunks are created they are serialized into a byte[], and both are put
-     * in the cache, using a {@link SoftReference} for the chunk. The default Java classes
-     * for {@link NinePatch} and {@link NinePatchDrawable} only reference to the byte[] data, and
-     * provide this for drawing.
-     * Using the cache map allows us to not have to deserialize the byte[] back into a
-     * {@link NinePatchChunk} every time a rendering is done.
-     */
-    private final static Map<byte[], SoftReference<NinePatchChunk>> sChunkCache = new HashMap<>();
-
-    // ---- delegate data ----
-    private byte[] chunk;
-
-
-    // ---- Public Helper methods ----
-
-    /**
-     * Serializes the given chunk.
-     *
-     * @return the serialized data for the chunk.
-     */
-    public static byte[] serialize(NinePatchChunk chunk) {
-        // serialize the chunk to get a byte[]
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        ObjectOutputStream oos = null;
-        try {
-            oos = new ObjectOutputStream(baos);
-            oos.writeObject(chunk);
-        } catch (IOException e) {
-            Bridge.getLog().error(null, "Failed to serialize NinePatchChunk.", e, null,
-                    null /*data*/);
-            return null;
-        } finally {
-            if (oos != null) {
-                try {
-                    oos.close();
-                } catch (IOException ignored) {
-                }
-            }
-        }
-
-        // get the array and add it to the cache
-        byte[] array = baos.toByteArray();
-        sChunkCache.put(array, new SoftReference<>(chunk));
-        return array;
-    }
-
-    /**
-     * Returns a {@link NinePatchChunk} object for the given serialized representation.
-     *
-     * If the chunk is present in the cache then the object from the cache is returned, otherwise
-     * the array is deserialized into a {@link NinePatchChunk} object.
-     *
-     * @param array the serialized representation of the chunk.
-     * @return the NinePatchChunk or null if deserialization failed.
-     */
-    public static NinePatchChunk getChunk(byte[] array) {
-        SoftReference<NinePatchChunk> chunkRef = sChunkCache.get(array);
-        NinePatchChunk chunk = chunkRef == null ? null : chunkRef.get();
-        if (chunk == null) {
-            ByteArrayInputStream bais = new ByteArrayInputStream(array);
-            try (ObjectInputStream ois = new ObjectInputStream(bais)) {
-                chunk = (NinePatchChunk) ois.readObject();
-
-                // put back the chunk in the cache
-                if (chunk != null) {
-                    sChunkCache.put(array, new SoftReference<>(chunk));
-                }
-            } catch (IOException e) {
-                Bridge.getLog().error(ILayoutLog.TAG_BROKEN,
-                        "Failed to deserialize NinePatchChunk content.", e, null, null /*data*/);
-                return null;
-            } catch (ClassNotFoundException e) {
-                Bridge.getLog().error(ILayoutLog.TAG_BROKEN,
-                        "Failed to deserialize NinePatchChunk class.", e, null, null /*data*/);
-                return null;
-            }
-        }
-
-        return chunk;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static boolean isNinePatchChunk(byte[] chunk) {
-        NinePatchChunk chunkObject = getChunk(chunk);
-        return chunkObject != null;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long validateNinePatchChunk(byte[] chunk) {
-        // the default JNI implementation only checks that the byte[] has the same
-        // size as the C struct it represent. Since we cannot do the same check (serialization
-        // will return different size depending on content), we do nothing.
-        NinePatch_Delegate newDelegate = new NinePatch_Delegate();
-        newDelegate.chunk = chunk;
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeFinalize(long nativeNinePatch) {
-        NinePatch_Delegate delegate = sManager.getDelegate(nativeNinePatch);
-        if (delegate != null && delegate.chunk != null) {
-            sChunkCache.remove(delegate.chunk);
-        }
-        sManager.removeJavaReferenceFor(nativeNinePatch);
-    }
-
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeGetTransparentRegion(long bitmapHandle, long chunk,
-            Rect location) {
-        return 0;
-    }
-
-    static byte[] getChunk(long nativeNinePatch) {
-        NinePatch_Delegate delegate = sManager.getDelegate(nativeNinePatch);
-        if (delegate != null) {
-            return delegate.chunk;
-        }
-        return null;
-    }
-
-    public static void clearCache() {
-        sChunkCache.clear();
-    }
-}
diff --git a/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java b/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
deleted file mode 100644
index fa20746..0000000
--- a/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.PaintFlagsDrawFilter
- *
- * Through the layoutlib_create tool, the original native methods of PaintFlagsDrawFilter have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original PaintFlagsDrawFilter class.
- *
- * Because this extends {@link DrawFilter_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the DrawFilter classes will be added to the manager owned by
- * {@link DrawFilter_Delegate}.
- *
- * @see DrawFilter_Delegate
- *
- */
-public class PaintFlagsDrawFilter_Delegate extends DrawFilter_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Paint Flags Draw Filters are not supported.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeConstructor(int clearBits, int setBits) {
-        PaintFlagsDrawFilter_Delegate newDelegate = new PaintFlagsDrawFilter_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/Paint_Delegate.java b/bridge/src/android/graphics/Paint_Delegate.java
deleted file mode 100644
index f6c6d71..0000000
--- a/bridge/src/android/graphics/Paint_Delegate.java
+++ /dev/null
@@ -1,1373 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.FontFamily_Delegate.FontVariant;
-import android.graphics.Paint.FontMetrics;
-import android.graphics.Paint.FontMetricsInt;
-import android.text.TextUtils;
-
-import java.awt.BasicStroke;
-import java.awt.Font;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.Toolkit;
-import java.awt.geom.AffineTransform;
-import java.util.Collections;
-import java.util.List;
-import java.util.Locale;
-import java.util.Objects;
-import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.Paint
- *
- * Through the layoutlib_create tool, the original native methods of Paint have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original Paint class.
- *
- * @see DelegateManager
- *
- */
-public class Paint_Delegate {
-    private static final float DEFAULT_TEXT_SIZE = 20.f;
-    private static final float DEFAULT_TEXT_SCALE_X = 1.f;
-    private static final float DEFAULT_TEXT_SKEW_X = 0.f;
-
-    /**
-     * Class associating a {@link Font} and its {@link java.awt.FontMetrics}.
-     */
-    /*package*/ static final class FontInfo {
-        final Font mFont;
-        final java.awt.FontMetrics mMetrics;
-
-        FontInfo(@NonNull Font font, @NonNull java.awt.FontMetrics fontMetrics) {
-            this.mFont = font;
-            this.mMetrics = fontMetrics;
-        }
-    }
-
-    // ---- delegate manager ----
-    private static final DelegateManager<Paint_Delegate> sManager =
-            new DelegateManager<>(Paint_Delegate.class);
-    private static long sFinalizer = -1;
-
-    // ---- delegate helper data ----
-
-    // This list can contain null elements.
-    @Nullable
-    private List<FontInfo> mFonts;
-
-    // ---- delegate data ----
-    private int mFlags;
-    private int mColor;
-    private int mStyle;
-    private int mCap;
-    private int mJoin;
-    private int mTextAlign;
-    private Typeface_Delegate mTypeface;
-    private float mStrokeWidth;
-    private float mStrokeMiter;
-    private float mTextSize;
-    private float mTextScaleX;
-    private float mTextSkewX;
-    private int mHintingMode = Paint.HINTING_ON;
-    private int mStartHyphenEdit;
-    private int mEndHyphenEdit;
-    private float mLetterSpacing;  // not used in actual text rendering.
-    private float mWordSpacing;  // not used in actual text rendering.
-    // Variant of the font. A paint's variant can only be compact or elegant.
-    private FontVariant mFontVariant = FontVariant.COMPACT;
-
-    private int mPorterDuffMode = Xfermode.DEFAULT;
-    private ColorFilter_Delegate mColorFilter;
-    private Shader_Delegate mShader;
-    private PathEffect_Delegate mPathEffect;
-    private MaskFilter_Delegate mMaskFilter;
-
-    @SuppressWarnings("FieldCanBeLocal") // Used to store the locale for future use
-    private Locale mLocale = Locale.getDefault();
-
-    // ---- Public Helper methods ----
-
-    @Nullable
-    public static Paint_Delegate getDelegate(long native_paint) {
-        return sManager.getDelegate(native_paint);
-    }
-
-    /**
-     * Returns the list of {@link Font} objects.
-     */
-    @NonNull
-    public List<FontInfo> getFonts() {
-        Typeface_Delegate typeface = mTypeface;
-        if (typeface == null) {
-            if (Typeface.sDefaultTypeface == null) {
-                return Collections.emptyList();
-            }
-
-            typeface = Typeface_Delegate.getDelegate(Typeface.sDefaultTypeface.native_instance);
-        }
-
-        if (mFonts != null) {
-            return mFonts;
-        }
-
-        // Apply an optional transformation for skew and scale
-        AffineTransform affineTransform = mTextScaleX != 1.0 || mTextSkewX != 0 ?
-                new AffineTransform(mTextScaleX, mTextSkewX, 0, 1, 0, 0) :
-                null;
-
-        List<FontInfo> infoList = StreamSupport.stream(typeface.getFonts(mFontVariant).spliterator
-                (), false)
-                .filter(Objects::nonNull)
-                .map(font -> getFontInfo(font, mTextSize, affineTransform))
-                .collect(Collectors.toList());
-        mFonts = Collections.unmodifiableList(infoList);
-
-        return mFonts;
-    }
-
-    public boolean isAntiAliased() {
-        return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0;
-    }
-
-    public boolean isFilterBitmap() {
-        return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0;
-    }
-
-    public int getStyle() {
-        return mStyle;
-    }
-
-    public int getColor() {
-        return mColor;
-    }
-
-    public int getAlpha() {
-        return mColor >>> 24;
-    }
-
-    public void setAlpha(int alpha) {
-        mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
-    }
-
-    public int getTextAlign() {
-        return mTextAlign;
-    }
-
-    public float getStrokeWidth() {
-        return mStrokeWidth;
-    }
-
-    /**
-     * returns the value of stroke miter needed by the java api.
-     */
-    public float getJavaStrokeMiter() {
-        return mStrokeMiter;
-    }
-
-    public int getJavaCap() {
-        switch (Paint.sCapArray[mCap]) {
-            case BUTT:
-                return BasicStroke.CAP_BUTT;
-            case ROUND:
-                return BasicStroke.CAP_ROUND;
-            default:
-            case SQUARE:
-                return BasicStroke.CAP_SQUARE;
-        }
-    }
-
-    public int getJavaJoin() {
-        switch (Paint.sJoinArray[mJoin]) {
-            default:
-            case MITER:
-                return BasicStroke.JOIN_MITER;
-            case ROUND:
-                return BasicStroke.JOIN_ROUND;
-            case BEVEL:
-                return BasicStroke.JOIN_BEVEL;
-        }
-    }
-
-    public Stroke getJavaStroke() {
-        if (mPathEffect != null) {
-            if (mPathEffect.isSupported()) {
-                Stroke stroke = mPathEffect.getStroke(this);
-                assert stroke != null;
-                //noinspection ConstantConditions
-                if (stroke != null) {
-                    return stroke;
-                }
-            } else {
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_PATHEFFECT,
-                        mPathEffect.getSupportMessage(),
-                        null, null, null /*data*/);
-            }
-        }
-
-        // if no custom stroke as been set, set the default one.
-        return new BasicStroke(
-                    getStrokeWidth(),
-                    getJavaCap(),
-                    getJavaJoin(),
-                    getJavaStrokeMiter());
-    }
-
-    /**
-     * Returns the {@link PorterDuff.Mode} as an int
-     */
-    public int getPorterDuffMode() {
-        return mPorterDuffMode;
-    }
-
-    /**
-     * Returns the {@link ColorFilter} delegate or null if none have been set
-     *
-     * @return the delegate or null.
-     */
-    public ColorFilter_Delegate getColorFilter() {
-        return mColorFilter;
-    }
-
-    public void setColorFilter(long colorFilterPtr) {
-        mColorFilter = ColorFilter_Delegate.getDelegate(colorFilterPtr);
-    }
-
-    public void setShader(long shaderPtr) {
-        mShader = Shader_Delegate.getDelegate(shaderPtr);
-    }
-
-    /**
-     * Returns the {@link Shader} delegate or null if none have been set
-     *
-     * @return the delegate or null.
-     */
-    public Shader_Delegate getShader() {
-        return mShader;
-    }
-
-    /**
-     * Returns the {@link MaskFilter} delegate or null if none have been set
-     *
-     * @return the delegate or null.
-     */
-    public MaskFilter_Delegate getMaskFilter() {
-        return mMaskFilter;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetFlags(long nativePaint) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 0;
-        }
-
-        return delegate.mFlags;
-    }
-
-
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetFlags(long nativePaint, int flags) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mFlags = flags;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetFilterBitmap(long nativePaint, boolean filter) {
-        setFlag(nativePaint, Paint.FILTER_BITMAP_FLAG, filter);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetHinting(long nativePaint) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return Paint.HINTING_ON;
-        }
-
-        return delegate.mHintingMode;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetHinting(long nativePaint, int mode) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mHintingMode = mode;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetAntiAlias(long nativePaint, boolean aa) {
-        setFlag(nativePaint, Paint.ANTI_ALIAS_FLAG, aa);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetSubpixelText(long nativePaint,
-            boolean subpixelText) {
-        setFlag(nativePaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetUnderlineText(long nativePaint,
-            boolean underlineText) {
-        setFlag(nativePaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetStrikeThruText(long nativePaint,
-            boolean strikeThruText) {
-        setFlag(nativePaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetFakeBoldText(long nativePaint,
-            boolean fakeBoldText) {
-        setFlag(nativePaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetDither(long nativePaint, boolean dither) {
-        setFlag(nativePaint, Paint.DITHER_FLAG, dither);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetLinearText(long nativePaint, boolean linearText) {
-        setFlag(nativePaint, Paint.LINEAR_TEXT_FLAG, linearText);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetColor(long paintPtr, long colorSpaceHandle, long color) {
-        Paint_Delegate delegate = sManager.getDelegate(paintPtr);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mColor = Color.toArgb(color);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetColor(long paintPtr, int color) {
-        Paint_Delegate delegate = sManager.getDelegate(paintPtr);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mColor = color;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetAlpha(long nativePaint, int a) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.setAlpha(a);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetStrokeWidth(long nativePaint) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 1.f;
-        }
-
-        return delegate.mStrokeWidth;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetStrokeWidth(long nativePaint, float width) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mStrokeWidth = width;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetStrokeMiter(long nativePaint) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 1.f;
-        }
-
-        return delegate.mStrokeMiter;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetStrokeMiter(long nativePaint, float miter) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mStrokeMiter = miter;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetShadowLayer(long paintPtr,
-            float radius, float dx, float dy, long colorSpaceHandle,
-            long shadowColor) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Paint.setShadowLayer is not supported.", null, null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nHasShadowLayer(long paint) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Paint.hasShadowLayer is not supported.", null, null, null /*data*/);
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nIsElegantTextHeight(long nativePaint) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        return delegate != null && delegate.mFontVariant == FontVariant.ELEGANT;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetElegantTextHeight(long nativePaint,
-            boolean elegant) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mFontVariant = elegant ? FontVariant.ELEGANT : FontVariant.COMPACT;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetTextSize(long nativePaint) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 1.f;
-        }
-
-        return delegate.mTextSize;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetTextSize(long nativePaint, float textSize) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-
-        if (delegate.mTextSize != textSize) {
-            delegate.mTextSize = textSize;
-            delegate.invalidateFonts();
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetTextScaleX(long nativePaint) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 1.f;
-        }
-
-        return delegate.mTextScaleX;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetTextScaleX(long nativePaint, float scaleX) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-
-        if (delegate.mTextScaleX != scaleX) {
-            delegate.mTextScaleX = scaleX;
-            delegate.invalidateFonts();
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetTextSkewX(long nativePaint) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 1.f;
-        }
-
-        return delegate.mTextSkewX;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetTextSkewX(long nativePaint, float skewX) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-
-        if (delegate.mTextSkewX != skewX) {
-            delegate.mTextSkewX = skewX;
-            delegate.invalidateFonts();
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nAscent(long nativePaint) {
-        // get the delegate
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 0;
-        }
-
-        List<FontInfo> fonts = delegate.getFonts();
-        if (fonts.size() > 0) {
-            java.awt.FontMetrics javaMetrics = fonts.get(0).mMetrics;
-            // Android expects negative ascent so we invert the value from Java.
-            return - javaMetrics.getAscent();
-        }
-
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nDescent(long nativePaint) {
-        // get the delegate
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 0;
-        }
-
-        List<FontInfo> fonts = delegate.getFonts();
-        if (fonts.size() > 0) {
-            java.awt.FontMetrics javaMetrics = fonts.get(0).mMetrics;
-            return javaMetrics.getDescent();
-        }
-
-        return 0;
-
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetFontMetrics(long nativePaint,
-            FontMetrics metrics) {
-        // get the delegate
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 0;
-        }
-
-        return delegate.getFontMetrics(metrics);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetFontMetricsInt(long nativePaint, FontMetricsInt fmi) {
-        // get the delegate
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 0;
-        }
-
-        List<FontInfo> fonts = delegate.getFonts();
-        if (fonts.size() > 0) {
-            java.awt.FontMetrics javaMetrics = fonts.get(0).mMetrics;
-            if (fmi != null) {
-                // Android expects negative ascent so we invert the value from Java.
-                fmi.top = (int)(- javaMetrics.getMaxAscent() * 1.15);
-                fmi.ascent = - javaMetrics.getAscent();
-                fmi.descent = javaMetrics.getDescent();
-                fmi.bottom = (int)(javaMetrics.getMaxDescent() * 1.15);
-                fmi.leading = javaMetrics.getLeading();
-            }
-
-            return javaMetrics.getHeight();
-        }
-
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nBreakText(long nativePaint, char[] text,
-            int index, int count, float maxWidth, int bidiFlags, float[] measuredWidth) {
-
-        // get the delegate
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 0;
-        }
-
-        int inc = count > 0 ? 1 : -1;
-
-        int measureIndex = 0;
-        for (int i = index; i != index + count; i += inc, measureIndex++) {
-            int start, end;
-            if (i < index) {
-                start = i;
-                end = index;
-            } else {
-                start = index;
-                end = i;
-            }
-
-            // measure from start to end
-            RectF bounds = delegate.measureText(text, start, end - start + 1, null, 0, bidiFlags);
-            float res = bounds.right - bounds.left;
-
-            if (measuredWidth != null) {
-                measuredWidth[measureIndex] = res;
-            }
-
-            if (res > maxWidth) {
-                // we should not return this char index, but since it's 0-based
-                // and we need to return a count, we simply return measureIndex;
-                return measureIndex;
-            }
-
-        }
-
-        return measureIndex;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nBreakText(long nativePaint, String text, boolean measureForwards,
-            float maxWidth, int bidiFlags, float[] measuredWidth) {
-        return nBreakText(nativePaint, text.toCharArray(), 0, text.length(),
-                maxWidth, bidiFlags, measuredWidth);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nInit() {
-        Paint_Delegate newDelegate = new Paint_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nInitWithPaint(long paint) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(paint);
-        if (delegate == null) {
-            return 0;
-        }
-
-        Paint_Delegate newDelegate = new Paint_Delegate(delegate);
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nReset(long native_object) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.reset();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSet(long native_dst, long native_src) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
-        if (delegate_dst == null) {
-            return;
-        }
-
-        // get the delegate from the native int.
-        Paint_Delegate delegate_src = sManager.getDelegate(native_src);
-        if (delegate_src == null) {
-            return;
-        }
-
-        delegate_dst.set(delegate_src);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetStyle(long native_object) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return 0;
-        }
-
-        return delegate.mStyle;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetStyle(long native_object, int style) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mStyle = style;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetStrokeCap(long native_object) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return 0;
-        }
-
-        return delegate.mCap;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetStrokeCap(long native_object, int cap) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mCap = cap;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetStrokeJoin(long native_object) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return 0;
-        }
-
-        return delegate.mJoin;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetStrokeJoin(long native_object, int join) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mJoin = join;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nGetFillPath(long native_object, long src, long dst) {
-        Paint_Delegate paint = sManager.getDelegate(native_object);
-        if (paint == null) {
-            return false;
-        }
-
-        Path_Delegate srcPath = Path_Delegate.getDelegate(src);
-        if (srcPath == null) {
-            return true;
-        }
-
-        Path_Delegate dstPath = Path_Delegate.getDelegate(dst);
-        if (dstPath == null) {
-            return true;
-        }
-
-        Stroke stroke = paint.getJavaStroke();
-        Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape());
-
-        dstPath.setJavaShape(strokeShape);
-
-        // FIXME figure out the return value?
-        return true;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nSetShader(long native_object, long shader) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return shader;
-        }
-
-        delegate.mShader = Shader_Delegate.getDelegate(shader);
-
-        return shader;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nSetColorFilter(long native_object, long filter) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return filter;
-        }
-
-        delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);
-
-        // Log warning if it's not supported.
-        if (delegate.mColorFilter != null && !delegate.mColorFilter.isSupported()) {
-            Bridge.getLog().fidelityWarning(ILayoutLog.TAG_COLORFILTER,
-                    delegate.mColorFilter.getSupportMessage(), null, null, null /*data*/);
-        }
-
-        return filter;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetXfermode(long native_object, int xfermode) {
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return;
-        }
-        delegate.mPorterDuffMode = xfermode;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nSetPathEffect(long native_object, long effect) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return effect;
-        }
-
-        delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect);
-
-        return effect;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nSetMaskFilter(long native_object, long maskfilter) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return maskfilter;
-        }
-
-        delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter);
-
-        // since none of those are supported, display a fidelity warning right away
-        if (delegate.mMaskFilter != null && !delegate.mMaskFilter.isSupported()) {
-            Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MASKFILTER,
-                    delegate.mMaskFilter.getSupportMessage(), null, null, null /*data*/);
-        }
-
-        return maskfilter;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetTypeface(long native_object, long typeface) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return;
-        }
-
-        Typeface_Delegate typefaceDelegate = Typeface_Delegate.getDelegate(typeface);
-        if (delegate.mTypeface != typefaceDelegate) {
-            delegate.mTypeface = typefaceDelegate;
-            delegate.invalidateFonts();
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetTextAlign(long native_object) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return 0;
-        }
-
-        return delegate.mTextAlign;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetTextAlign(long native_object, int align) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.mTextAlign = align;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nSetTextLocales(long native_object, String locale) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return 0;
-        }
-
-        delegate.setTextLocale(locale);
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetTextLocalesByMinikinLocaleListId(long paintPtr,
-            int mMinikinLangListId) {
-        // FIXME
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetTextAdvances(long native_object, char[] text, int index,
-            int count, int contextIndex, int contextCount,
-            int bidiFlags, float[] advances, int advancesIndex) {
-
-        if (advances != null)
-            for (int i = advancesIndex; i< advancesIndex+count; i++)
-                advances[i]=0;
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(native_object);
-        if (delegate == null) {
-            return 0.f;
-        }
-
-        RectF bounds = delegate.measureText(text, index, count, advances, advancesIndex, bidiFlags);
-        return bounds.right - bounds.left;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetTextAdvances(long native_object, String text, int start, int end,
-            int contextStart, int contextEnd, int bidiFlags, float[] advances, int advancesIndex) {
-        // FIXME: support contextStart and contextEnd
-        int count = end - start;
-        char[] buffer = TemporaryBuffer.obtain(count);
-        TextUtils.getChars(text, start, end, buffer, 0);
-
-        return nGetTextAdvances(native_object, buffer, 0, count,
-                contextStart, contextEnd - contextStart, bidiFlags, advances, advancesIndex);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, char[] text,
-            int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Paint.getTextRunCursor is not supported.", null, null, null /*data*/);
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetTextRunCursor(Paint paint, long native_object, String text,
-            int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Paint.getTextRunCursor is not supported.", null, null, null /*data*/);
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nGetTextPath(long native_object, int bidiFlags, char[] text,
-            int index, int count, float x, float y, long path) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Paint.getTextPath is not supported.", null, null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nGetTextPath(long native_object, int bidiFlags, String text, int start,
-            int end, float x, float y, long path) {
-        // FIXME
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Paint.getTextPath is not supported.", null, null, null /*data*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nGetStringBounds(long nativePaint, String text, int start, int end,
-            int bidiFlags, Rect bounds) {
-        nGetCharArrayBounds(nativePaint, text.toCharArray(), start,
-                end - start, bidiFlags, bounds);
-    }
-
-    @LayoutlibDelegate
-    public static void nGetCharArrayBounds(long nativePaint, char[] text, int index,
-            int count, int bidiFlags, Rect bounds) {
-
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-
-        delegate.measureText(text, index, count, null, 0, bidiFlags).roundOut(bounds);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetNativeFinalizer() {
-        synchronized (Paint_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
-                        sManager::removeJavaReferenceFor);
-            }
-        }
-        return sFinalizer;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetLetterSpacing(long nativePaint) {
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 0;
-        }
-        return delegate.mLetterSpacing;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetLetterSpacing(long nativePaint, float letterSpacing) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_TEXT_RENDERING,
-                "Paint.setLetterSpacing() not supported.", null, null, null);
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-        delegate.mLetterSpacing = letterSpacing;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetWordSpacing(long nativePaint) {
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 0;
-        }
-        return delegate.mWordSpacing;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetWordSpacing(long nativePaint, float wordSpacing) {
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-        delegate.mWordSpacing = wordSpacing;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetFontFeatureSettings(long nativePaint, String settings) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_TEXT_RENDERING,
-                "Paint.setFontFeatureSettings() not supported.", null, null, null);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetStartHyphenEdit(long nativePaint) {
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 0;
-        }
-        return delegate.mStartHyphenEdit;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetStartHyphenEdit(long nativePaint, int hyphen) {
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-        delegate.mStartHyphenEdit = hyphen;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetEndHyphenEdit(long nativePaint) {
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return 0;
-        }
-        return delegate.mEndHyphenEdit;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetEndHyphenEdit(long nativePaint, int hyphen) {
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-        delegate.mEndHyphenEdit = hyphen;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nHasGlyph(long nativePaint, int bidiFlags, String string) {
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return false;
-        }
-        if (string.length() == 0) {
-            return false;
-        }
-        if (string.length() > 1) {
-            Bridge.getLog().fidelityWarning(ILayoutLog.TAG_TEXT_RENDERING,
-                    "Paint.hasGlyph() is not supported for ligatures.", null, null, null);
-            return false;
-        }
-
-        char c = string.charAt(0);
-        for (Font font : delegate.mTypeface.getFonts(delegate.mFontVariant)) {
-            if (font.canDisplay(c)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetRunAdvance(long nativePaint, @NonNull char[] text, int start,
-            int end, int contextStart, int contextEnd,
-            boolean isRtl, int offset) {
-        int count = end - start;
-        float[] advances = new float[count];
-        int bidiFlags = isRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR;
-        nGetTextAdvances(nativePaint, text, start, count, contextStart,
-                contextEnd - contextStart, bidiFlags, advances, 0);
-        int startOffset = offset - start;  // offset from start.
-        float sum = 0;
-        for (int i = 0; i < startOffset; i++) {
-            sum += advances[i];
-        }
-        return sum;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetOffsetForAdvance(long nativePaint, char[] text, int start,
-            int end, int contextStart, int contextEnd, boolean isRtl, float advance) {
-        int count = end - start;
-        float[] advances = new float[count];
-        int bidiFlags = isRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR;
-        nGetTextAdvances(nativePaint, text, start, count, contextStart,
-                contextEnd - contextStart, bidiFlags, advances, 0);
-        float sum = 0;
-        int i;
-        for (i = 0; i < count && sum < advance; i++) {
-            sum += advances[i];
-        }
-        float distanceToI = sum - advance;
-        float distanceToIMinus1 = advance - (sum - advances[i]);
-        return distanceToI > distanceToIMinus1 ? i : i - 1;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetUnderlinePosition(long paintPtr) {
-        return (1.0f / 9.0f) * nGetTextSize(paintPtr);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetUnderlineThickness(long paintPtr) {
-        return (1.0f / 18.0f) * nGetTextSize(paintPtr);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetStrikeThruPosition(long paintPtr) {
-        return (-79.0f / 252.0f) * nGetTextSize(paintPtr);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetStrikeThruThickness(long paintPtr) {
-        return (1.0f / 18.0f) * nGetTextSize(paintPtr);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nEqualsForTextMeasurement(long leftPaintPtr, long rightPaintPtr) {
-        return leftPaintPtr == rightPaintPtr;
-    }
-
-    // ---- Private delegate/helper methods ----
-
-    /*package*/ Paint_Delegate() {
-        reset();
-    }
-
-    private Paint_Delegate(Paint_Delegate paint) {
-        set(paint);
-    }
-
-    private void set(Paint_Delegate paint) {
-        mFlags = paint.mFlags;
-        mColor = paint.mColor;
-        mStyle = paint.mStyle;
-        mCap = paint.mCap;
-        mJoin = paint.mJoin;
-        mTextAlign = paint.mTextAlign;
-
-        if (mTypeface != paint.mTypeface) {
-            mTypeface = paint.mTypeface;
-            invalidateFonts();
-        }
-
-        if (mTextSize != paint.mTextSize) {
-            mTextSize = paint.mTextSize;
-            invalidateFonts();
-        }
-
-        if (mTextScaleX != paint.mTextScaleX) {
-            mTextScaleX = paint.mTextScaleX;
-            invalidateFonts();
-        }
-
-        if (mTextSkewX != paint.mTextSkewX) {
-            mTextSkewX = paint.mTextSkewX;
-            invalidateFonts();
-        }
-
-        mStrokeWidth = paint.mStrokeWidth;
-        mStrokeMiter = paint.mStrokeMiter;
-        mPorterDuffMode = paint.mPorterDuffMode;
-        mColorFilter = paint.mColorFilter;
-        mShader = paint.mShader;
-        mPathEffect = paint.mPathEffect;
-        mMaskFilter = paint.mMaskFilter;
-        mHintingMode = paint.mHintingMode;
-    }
-
-    private void reset() {
-        Typeface_Delegate defaultTypeface =
-                Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance);
-
-        mFlags = Paint.HIDDEN_DEFAULT_PAINT_FLAGS;
-        mColor = 0xFF000000;
-        mStyle = Paint.Style.FILL.nativeInt;
-        mCap = Paint.Cap.BUTT.nativeInt;
-        mJoin = Paint.Join.MITER.nativeInt;
-        mTextAlign = 0;
-
-        if (mTypeface != defaultTypeface) {
-            mTypeface = defaultTypeface;
-            invalidateFonts();
-        }
-
-        mStrokeWidth = 1.f;
-        mStrokeMiter = 4.f;
-
-        if (mTextSize != DEFAULT_TEXT_SIZE) {
-            mTextSize = DEFAULT_TEXT_SIZE;
-            invalidateFonts();
-        }
-
-        if (mTextScaleX != DEFAULT_TEXT_SCALE_X) {
-            mTextScaleX = DEFAULT_TEXT_SCALE_X;
-            invalidateFonts();
-        }
-
-        if (mTextSkewX != DEFAULT_TEXT_SKEW_X) {
-            mTextSkewX = DEFAULT_TEXT_SKEW_X;
-            invalidateFonts();
-        }
-
-        mPorterDuffMode = Xfermode.DEFAULT;
-        mColorFilter = null;
-        mShader = null;
-        mPathEffect = null;
-        mMaskFilter = null;
-        mHintingMode = Paint.HINTING_ON;
-    }
-
-    private void invalidateFonts() {
-        mFonts = null;
-    }
-
-    @Nullable
-    private static FontInfo getFontInfo(@Nullable Font font, float textSize,
-            @Nullable AffineTransform transform) {
-        if (font == null) {
-            return null;
-        }
-
-        Font transformedFont = font.deriveFont(textSize);
-        if (transform != null) {
-            // TODO: support skew
-            transformedFont = transformedFont.deriveFont(transform);
-        }
-
-        // The metrics here don't have anti-aliasing set.
-        return new FontInfo(transformedFont,
-                Toolkit.getDefaultToolkit().getFontMetrics(transformedFont));
-    }
-
-    /*package*/ RectF measureText(char[] text, int index, int count, float[] advances,
-            int advancesIndex, int bidiFlags) {
-        return new BidiRenderer(null, this, text)
-                .renderText(index, index + count, bidiFlags, advances, advancesIndex, false);
-    }
-
-    /*package*/ RectF measureText(char[] text, int index, int count, float[] advances,
-            int advancesIndex, boolean isRtl) {
-        return new BidiRenderer(null, this, text)
-                .renderText(index, index + count, isRtl, advances, advancesIndex, false);
-    }
-
-    private float getFontMetrics(FontMetrics metrics) {
-        List<FontInfo> fonts = getFonts();
-        if (fonts.size() > 0) {
-            java.awt.FontMetrics javaMetrics = fonts.get(0).mMetrics;
-            if (metrics != null) {
-                // Android expects negative ascent so we invert the value from Java.
-                metrics.top = - javaMetrics.getMaxAscent();
-                metrics.ascent = - javaMetrics.getAscent();
-                metrics.descent = javaMetrics.getDescent();
-                metrics.bottom = javaMetrics.getMaxDescent();
-                metrics.leading = javaMetrics.getLeading();
-            }
-
-            return javaMetrics.getHeight();
-        }
-
-        return 0;
-    }
-
-    private void setTextLocale(String locale) {
-        mLocale = new Locale(locale);
-    }
-
-    private static void setFlag(long nativePaint, int flagMask, boolean flagValue) {
-        // get the delegate from the native int.
-        Paint_Delegate delegate = sManager.getDelegate(nativePaint);
-        if (delegate == null) {
-            return;
-        }
-
-        if (flagValue) {
-            delegate.mFlags |= flagMask;
-        } else {
-            delegate.mFlags &= ~flagMask;
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/PathDashPathEffect_Delegate.java b/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
deleted file mode 100644
index fd9ba62..0000000
--- a/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.Stroke;
-
-/**
- * Delegate implementing the native methods of android.graphics.PathDashPathEffect
- *
- * Through the layoutlib_create tool, the original native methods of PathDashPathEffect have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original PathDashPathEffect class.
- *
- * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
- * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
- *
- * @see PathEffect_Delegate
- *
- */
-public class PathDashPathEffect_Delegate extends PathEffect_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public Stroke getStroke(Paint_Delegate paint) {
-        // FIXME
-        return null;
-    }
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Path Dash Path Effects are not supported in Layout Preview mode.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(long native_path, float advance, float phase,
-            int native_style) {
-        PathDashPathEffect_Delegate newDelegate = new PathDashPathEffect_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/PathEffect_Delegate.java b/bridge/src/android/graphics/PathEffect_Delegate.java
deleted file mode 100644
index 000481e..0000000
--- a/bridge/src/android/graphics/PathEffect_Delegate.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.Stroke;
-
-/**
- * Delegate implementing the native methods of android.graphics.PathEffect
- *
- * Through the layoutlib_create tool, the original native methods of PathEffect have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original PathEffect class.
- *
- * This also serve as a base class for all PathEffect delegate classes.
- *
- * @see DelegateManager
- *
- */
-public abstract class PathEffect_Delegate {
-
-    // ---- delegate manager ----
-    protected static final DelegateManager<PathEffect_Delegate> sManager =
-            new DelegateManager<PathEffect_Delegate>(PathEffect_Delegate.class);
-
-    // ---- delegate helper data ----
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    public static PathEffect_Delegate getDelegate(long nativeShader) {
-        return sManager.getDelegate(nativeShader);
-    }
-
-    public abstract Stroke getStroke(Paint_Delegate paint);
-    public abstract boolean isSupported();
-    public abstract String getSupportMessage();
-
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeDestructor(long native_patheffect) {
-        sManager.removeJavaReferenceFor(native_patheffect);
-    }
-
-    // ---- Private delegate/helper methods ----
-
-}
diff --git a/bridge/src/android/graphics/PathMeasure_Delegate.java b/bridge/src/android/graphics/PathMeasure_Delegate.java
deleted file mode 100644
index 83a4ff1..0000000
--- a/bridge/src/android/graphics/PathMeasure_Delegate.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.layoutlib.bridge.util.CachedPathIteratorFactory;
-import com.android.layoutlib.bridge.util.CachedPathIteratorFactory.CachedPathIterator;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.geom.PathIterator;
-
-/**
- * Delegate implementing the native methods of {@link android.graphics.PathMeasure}
- * <p/>
- * Through the layoutlib_create tool, the original native methods of PathMeasure have been
- * replaced by
- * calls to methods of the same name in this delegate class.
- * <p/>
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between it
- * and the original PathMeasure class.
- *
- * @see DelegateManager
- */
-public final class PathMeasure_Delegate {
-
-    // ---- delegate manager ----
-    private static final DelegateManager<PathMeasure_Delegate> sManager =
-            new DelegateManager<PathMeasure_Delegate>(PathMeasure_Delegate.class);
-
-    // ---- delegate data ----
-    private CachedPathIteratorFactory mOriginalPathIterator;
-
-    private long mNativePath;
-
-
-    private PathMeasure_Delegate(long native_path, boolean forceClosed) {
-        mNativePath = native_path;
-        if (native_path != 0) {
-            if (forceClosed) {
-                // Copy the path and call close
-                native_path = Path_Delegate.nInit(native_path);
-                Path_Delegate.nClose(native_path);
-            }
-
-            Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
-            mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape()
-                    .getPathIterator(null));
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long native_create(long native_path, boolean forceClosed) {
-        return sManager.addNewDelegate(new PathMeasure_Delegate(native_path, forceClosed));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void native_destroy(long native_instance) {
-        sManager.removeJavaReferenceFor(native_instance);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean native_getPosTan(long native_instance, float distance, float pos[],
-            float tan[]) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "PathMeasure.getPostTan is not supported.", null, null, null);
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean native_getMatrix(long native_instance, float distance, long
-            native_matrix, int flags) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "PathMeasure.getMatrix is not supported.", null, null, null);
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean native_nextContour(long native_instance) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "PathMeasure.nextContour is not supported.", null, null, null);
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void native_setPath(long native_instance, long native_path, boolean
-            forceClosed) {
-        PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
-        assert pathMeasure != null;
-
-        if (native_path != 0) {
-            if (forceClosed) {
-                // Copy the path and call close
-                native_path = Path_Delegate.nInit(native_path);
-                Path_Delegate.nClose(native_path);
-            }
-
-            Path_Delegate pathDelegate = Path_Delegate.getDelegate(native_path);
-            pathMeasure.mOriginalPathIterator = new CachedPathIteratorFactory(pathDelegate.getJavaShape()
-                    .getPathIterator(null));
-        }
-
-        pathMeasure.mNativePath = native_path;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float native_getLength(long native_instance) {
-        PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
-        assert pathMeasure != null;
-
-        if (pathMeasure.mOriginalPathIterator == null) {
-            return 0;
-        }
-
-        return pathMeasure.mOriginalPathIterator.iterator().getTotalLength();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean native_isClosed(long native_instance) {
-        PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
-        assert pathMeasure != null;
-
-        Path_Delegate path = Path_Delegate.getDelegate(pathMeasure.mNativePath);
-        if (path == null) {
-            return false;
-        }
-
-        int type = 0;
-        float segment[] = new float[6];
-        for (PathIterator pi = path.getJavaShape().getPathIterator(null); !pi.isDone(); pi.next()) {
-            type = pi.currentSegment(segment);
-        }
-
-        // A path is a closed path if the last element is SEG_CLOSE
-        return type == PathIterator.SEG_CLOSE;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean native_getSegment(long native_instance, float startD, float stopD,
-            long native_dst_path, boolean startWithMoveTo) {
-        if (startD < 0) {
-            startD = 0;
-        }
-
-        if (startD >= stopD) {
-            return false;
-        }
-
-        PathMeasure_Delegate pathMeasure = sManager.getDelegate(native_instance);
-        assert pathMeasure != null;
-
-        CachedPathIterator iterator = pathMeasure.mOriginalPathIterator.iterator();
-        float accLength = startD;
-        boolean isZeroLength = true; // Whether the output has zero length or not
-        float[] points = new float[6];
-
-        iterator.jumpToSegment(accLength);
-        while (!iterator.isDone() && (stopD - accLength > 0.1f)) {
-            int type = iterator.currentSegment(points, stopD - accLength);
-
-            if (accLength - iterator.getCurrentSegmentLength() <= stopD) {
-                if (startWithMoveTo) {
-                    startWithMoveTo = false;
-
-                    // If this segment is a MOVETO, then we just use that one. If not, then we issue
-                    // a first moveto
-                    if (type != PathIterator.SEG_MOVETO) {
-                        float[] lastPoint = new float[2];
-                        iterator.getCurrentSegmentEnd(lastPoint);
-                        Path_Delegate.nMoveTo(native_dst_path, lastPoint[0], lastPoint[1]);
-                    }
-                }
-
-                isZeroLength = isZeroLength && iterator.getCurrentSegmentLength() > 0;
-                switch (type) {
-                    case PathIterator.SEG_MOVETO:
-                        Path_Delegate.nMoveTo(native_dst_path, points[0], points[1]);
-                        break;
-                    case PathIterator.SEG_LINETO:
-                        Path_Delegate.nLineTo(native_dst_path, points[0], points[1]);
-                        break;
-                    case PathIterator.SEG_CLOSE:
-                        Path_Delegate.nClose(native_dst_path);
-                        break;
-                    case PathIterator.SEG_CUBICTO:
-                        Path_Delegate.nCubicTo(native_dst_path, points[0], points[1],
-                                points[2], points[3],
-                                points[4], points[5]);
-                        break;
-                    case PathIterator.SEG_QUADTO:
-                        Path_Delegate.nQuadTo(native_dst_path, points[0], points[1],
-                                points[2],
-                                points[3]);
-                        break;
-                    default:
-                        assert false;
-                }
-            }
-
-            accLength += iterator.getCurrentSegmentLength();
-            iterator.next();
-        }
-
-        return !isZeroLength;
-    }
-}
diff --git a/bridge/src/android/graphics/Path_Delegate.java b/bridge/src/android/graphics/Path_Delegate.java
deleted file mode 100644
index 88f2815..0000000
--- a/bridge/src/android/graphics/Path_Delegate.java
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.NonNull;
-import android.graphics.Path.Direction;
-import android.graphics.Path.FillType;
-
-import java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Arc2D;
-import java.awt.geom.Area;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.Path2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.RoundRectangle2D;
-import java.util.ArrayList;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.Path
- *
- * Through the layoutlib_create tool, the original native methods of Path have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original Path class.
- *
- * @see DelegateManager
- *
- */
-public final class Path_Delegate {
-
-    // ---- delegate manager ----
-    private static final DelegateManager<Path_Delegate> sManager =
-            new DelegateManager<Path_Delegate>(Path_Delegate.class);
-
-    private static final float EPSILON = 1e-4f;
-
-    private static long sFinalizer = -1;
-
-    // ---- delegate data ----
-    private FillType mFillType = FillType.WINDING;
-    private Path2D mPath = new Path2D.Double();
-
-    private float mLastX = 0;
-    private float mLastY = 0;
-
-    // true if the path contains does not contain a curve or line.
-    private boolean mCachedIsEmpty = true;
-
-    // ---- Public Helper methods ----
-
-    public static Path_Delegate getDelegate(long nPath) {
-        return sManager.getDelegate(nPath);
-    }
-
-    public Path2D getJavaShape() {
-        return mPath;
-    }
-
-    public void setJavaShape(Shape shape) {
-        reset();
-        mPath.append(shape, false /*connect*/);
-    }
-
-    public void reset() {
-        mPath.reset();
-        mLastX = 0;
-        mLastY = 0;
-    }
-
-    public void setPathIterator(PathIterator iterator) {
-        reset();
-        mPath.append(iterator, false /*connect*/);
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nInit() {
-        // create the delegate
-        Path_Delegate newDelegate = new Path_Delegate();
-
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nInit(long nPath) {
-        // create the delegate
-        Path_Delegate newDelegate = new Path_Delegate();
-
-        // get the delegate to copy, which could be null if nPath is 0
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate != null) {
-            newDelegate.set(pathDelegate);
-        }
-
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nReset(long nPath) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.reset();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nRewind(long nPath) {
-        // call out to reset since there's nothing to optimize in
-        // terms of data structs.
-        nReset(nPath);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSet(long native_dst, long nSrc) {
-        Path_Delegate pathDstDelegate = sManager.getDelegate(native_dst);
-        if (pathDstDelegate == null) {
-            return;
-        }
-
-        Path_Delegate pathSrcDelegate = sManager.getDelegate(nSrc);
-        if (pathSrcDelegate == null) {
-            return;
-        }
-
-        pathDstDelegate.set(pathSrcDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nIsConvex(long nPath) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Path.isConvex is not supported.", null, null, null);
-        return true;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetFillType(long nPath) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return 0;
-        }
-
-        return pathDelegate.mFillType.nativeInt;
-    }
-
-    @LayoutlibDelegate
-    public static void nSetFillType(long nPath, int ft) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.setFillType(Path.sFillTypeArray[ft]);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nIsEmpty(long nPath) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        return pathDelegate == null || pathDelegate.isEmpty();
-
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nIsRect(long nPath, RectF rect) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return false;
-        }
-
-        // create an Area that can test if the path is a rect
-        Area area = new Area(pathDelegate.mPath);
-        if (area.isRectangular()) {
-            if (rect != null) {
-                pathDelegate.fillBounds(rect);
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nComputeBounds(long nPath, RectF bounds) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.fillBounds(bounds);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nIncReserve(long nPath, int extraPtCount) {
-        // since we use a java2D path, there's no way to pre-allocate new points,
-        // so we do nothing.
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nMoveTo(long nPath, float x, float y) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.moveTo(x, y);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nRMoveTo(long nPath, float dx, float dy) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.rMoveTo(dx, dy);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nLineTo(long nPath, float x, float y) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.lineTo(x, y);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nRLineTo(long nPath, float dx, float dy) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.rLineTo(dx, dy);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nQuadTo(long nPath, float x1, float y1, float x2, float y2) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.quadTo(x1, y1, x2, y2);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nRQuadTo(long nPath, float dx1, float dy1, float dx2, float dy2) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.rQuadTo(dx1, dy1, dx2, dy2);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nCubicTo(long nPath, float x1, float y1,
-            float x2, float y2, float x3, float y3) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.cubicTo(x1, y1, x2, y2, x3, y3);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nRCubicTo(long nPath, float x1, float y1,
-            float x2, float y2, float x3, float y3) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.rCubicTo(x1, y1, x2, y2, x3, y3);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nArcTo(long nPath, float left, float top, float right,
-            float bottom,
-                    float startAngle, float sweepAngle, boolean forceMoveTo) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.arcTo(left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nClose(long nPath) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.close();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddRect(long nPath,
-            float left, float top, float right, float bottom, int dir) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.addRect(left, top, right, bottom, dir);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddOval(long nPath, float left, float top, float right,
-            float bottom, int dir) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.mPath.append(new Ellipse2D.Float(
-                left, top, right - left, bottom - top), false);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddCircle(long nPath, float x, float y, float radius, int dir) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        // because x/y is the center of the circle, need to offset this by the radius
-        pathDelegate.mPath.append(new Ellipse2D.Float(
-                x - radius, y - radius, radius * 2, radius * 2), false);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddArc(long nPath, float left, float top, float right,
-            float bottom, float startAngle, float sweepAngle) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        // because x/y is the center of the circle, need to offset this by the radius
-        pathDelegate.mPath.append(new Arc2D.Float(
-                left, top, right - left, bottom - top,
-                -startAngle, -sweepAngle, Arc2D.OPEN), false);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddRoundRect(long nPath, float left, float top, float right,
-            float bottom, float rx, float ry, int dir) {
-
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.mPath.append(new RoundRectangle2D.Float(
-                left, top, right - left, bottom - top, rx * 2, ry * 2), false);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddRoundRect(long nPath, float left, float top, float right,
-            float bottom, float[] radii, int dir) {
-
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        float[] cornerDimensions = new float[radii.length];
-        for (int i = 0; i < radii.length; i++) {
-            cornerDimensions[i] = 2 * radii[i];
-        }
-        pathDelegate.mPath.append(new RoundRectangle(left, top, right - left, bottom - top,
-                cornerDimensions), false);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddPath(long nPath, long src, float dx, float dy) {
-        addPath(nPath, src, AffineTransform.getTranslateInstance(dx, dy));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddPath(long nPath, long src) {
-        addPath(nPath, src, null /*transform*/);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddPath(long nPath, long src, long matrix) {
-        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
-        if (matrixDelegate == null) {
-            return;
-        }
-
-        addPath(nPath, src, matrixDelegate.getAffineTransform());
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nOffset(long nPath, float dx, float dy) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.offset(dx, dy);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetLastPoint(long nPath, float dx, float dy) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.mLastX = dx;
-        pathDelegate.mLastY = dy;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nTransform(long nPath, long matrix,
-                                                long dst_path) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
-        if (matrixDelegate == null) {
-            return;
-        }
-
-        // this can be null if dst_path is 0
-        Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
-
-        pathDelegate.transform(matrixDelegate, dstDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nTransform(long nPath, long matrix) {
-        nTransform(nPath, matrix, 0);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nOp(long nPath1, long nPath2, int op, long result) {
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED, "Path.op() not supported", null, null);
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetFinalizer() {
-        synchronized (Path_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
-                        sManager::removeJavaReferenceFor);
-            }
-        }
-        return sFinalizer;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float[] nApproximate(long nPath, float error) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return null;
-        }
-        // Get a FlatteningIterator
-        PathIterator iterator = pathDelegate.getJavaShape().getPathIterator(null, error);
-
-        float segment[] = new float[6];
-        float totalLength = 0;
-        ArrayList<Point2D.Float> points = new ArrayList<Point2D.Float>();
-        Point2D.Float previousPoint = null;
-        while (!iterator.isDone()) {
-            int type = iterator.currentSegment(segment);
-            Point2D.Float currentPoint = new Point2D.Float(segment[0], segment[1]);
-            // MoveTo shouldn't affect the length
-            if (previousPoint != null && type != PathIterator.SEG_MOVETO) {
-                totalLength += currentPoint.distance(previousPoint);
-            }
-            previousPoint = currentPoint;
-            points.add(currentPoint);
-            iterator.next();
-        }
-
-        int nPoints = points.size();
-        float[] result = new float[nPoints * 3];
-        previousPoint = null;
-        // Distance that we've covered so far. Used to calculate the fraction of the path that
-        // we've covered up to this point.
-        float walkedDistance = .0f;
-        for (int i = 0; i < nPoints; i++) {
-            Point2D.Float point = points.get(i);
-            float distance = previousPoint != null ? (float) previousPoint.distance(point) : .0f;
-            walkedDistance += distance;
-            result[i * 3] = walkedDistance / totalLength;
-            result[i * 3 + 1] = point.x;
-            result[i * 3 + 2] = point.y;
-
-            previousPoint = point;
-        }
-
-        return result;
-    }
-
-    // ---- Private helper methods ----
-
-    private void set(Path_Delegate delegate) {
-        mPath.reset();
-        setFillType(delegate.mFillType);
-        mPath.append(delegate.mPath, false /*connect*/);
-    }
-
-    private void setFillType(FillType fillType) {
-        mFillType = fillType;
-        mPath.setWindingRule(getWindingRule(fillType));
-    }
-
-    /**
-     * Returns the Java2D winding rules matching a given Android {@link FillType}.
-     * @param type the android fill type
-     * @return the matching java2d winding rule.
-     */
-    private static int getWindingRule(FillType type) {
-        switch (type) {
-            case WINDING:
-            case INVERSE_WINDING:
-                return GeneralPath.WIND_NON_ZERO;
-            case EVEN_ODD:
-            case INVERSE_EVEN_ODD:
-                return GeneralPath.WIND_EVEN_ODD;
-
-            default:
-                assert false;
-                return GeneralPath.WIND_NON_ZERO;
-        }
-    }
-
-    @NonNull
-    private static Direction getDirection(int direction) {
-        for (Direction d : Direction.values()) {
-            if (direction == d.nativeInt) {
-                return d;
-            }
-        }
-
-        assert false;
-        return null;
-    }
-
-    public static void addPath(long destPath, long srcPath, AffineTransform transform) {
-        Path_Delegate destPathDelegate = sManager.getDelegate(destPath);
-        if (destPathDelegate == null) {
-            return;
-        }
-
-        Path_Delegate srcPathDelegate = sManager.getDelegate(srcPath);
-        if (srcPathDelegate == null) {
-            return;
-        }
-
-        if (transform != null) {
-            destPathDelegate.mPath.append(
-                    srcPathDelegate.mPath.getPathIterator(transform), false);
-        } else {
-            destPathDelegate.mPath.append(srcPathDelegate.mPath, false);
-        }
-    }
-
-
-    /**
-     * Returns whether the path already contains any points.
-     * Note that this is different to
-     * {@link #isEmpty} because if all elements are {@link PathIterator#SEG_MOVETO},
-     * {@link #isEmpty} will return true while hasPoints will return false.
-     */
-    public boolean hasPoints() {
-        return !mPath.getPathIterator(null).isDone();
-    }
-
-    /**
-     * Returns whether the path is empty (contains no lines or curves).
-     * @see Path#isEmpty
-     */
-    public boolean isEmpty() {
-        if (!mCachedIsEmpty) {
-            return false;
-        }
-
-        float[] coords = new float[6];
-        mCachedIsEmpty = Boolean.TRUE;
-        for (PathIterator it = mPath.getPathIterator(null); !it.isDone(); it.next()) {
-            int type = it.currentSegment(coords);
-            if (type != PathIterator.SEG_MOVETO) {
-                // Once we know that the path is not empty, we do not need to check again unless
-                // Path#reset is called.
-                mCachedIsEmpty = false;
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Fills the given {@link RectF} with the path bounds.
-     * @param bounds the RectF to be filled.
-     */
-    public void fillBounds(RectF bounds) {
-        Rectangle2D rect = mPath.getBounds2D();
-        bounds.left = (float)rect.getMinX();
-        bounds.right = (float)rect.getMaxX();
-        bounds.top = (float)rect.getMinY();
-        bounds.bottom = (float)rect.getMaxY();
-    }
-
-    /**
-     * Set the beginning of the next contour to the point (x,y).
-     *
-     * @param x The x-coordinate of the start of a new contour
-     * @param y The y-coordinate of the start of a new contour
-     */
-    public void moveTo(float x, float y) {
-        mPath.moveTo(mLastX = x, mLastY = y);
-    }
-
-    /**
-     * Set the beginning of the next contour relative to the last point on the
-     * previous contour. If there is no previous contour, this is treated the
-     * same as moveTo().
-     *
-     * @param dx The amount to add to the x-coordinate of the end of the
-     *           previous contour, to specify the start of a new contour
-     * @param dy The amount to add to the y-coordinate of the end of the
-     *           previous contour, to specify the start of a new contour
-     */
-    public void rMoveTo(float dx, float dy) {
-        dx += mLastX;
-        dy += mLastY;
-        mPath.moveTo(mLastX = dx, mLastY = dy);
-    }
-
-    /**
-     * Add a line from the last point to the specified point (x,y).
-     * If no moveTo() call has been made for this contour, the first point is
-     * automatically set to (0,0).
-     *
-     * @param x The x-coordinate of the end of a line
-     * @param y The y-coordinate of the end of a line
-     */
-    public void lineTo(float x, float y) {
-        if (!hasPoints()) {
-            mPath.moveTo(mLastX = 0, mLastY = 0);
-        }
-        mPath.lineTo(mLastX = x, mLastY = y);
-    }
-
-    /**
-     * Same as lineTo, but the coordinates are considered relative to the last
-     * point on this contour. If there is no previous point, then a moveTo(0,0)
-     * is inserted automatically.
-     *
-     * @param dx The amount to add to the x-coordinate of the previous point on
-     *           this contour, to specify a line
-     * @param dy The amount to add to the y-coordinate of the previous point on
-     *           this contour, to specify a line
-     */
-    public void rLineTo(float dx, float dy) {
-        if (!hasPoints()) {
-            mPath.moveTo(mLastX = 0, mLastY = 0);
-        }
-
-        if (Math.abs(dx) < EPSILON && Math.abs(dy) < EPSILON) {
-            // The delta is so small that this shouldn't generate a line
-            return;
-        }
-
-        dx += mLastX;
-        dy += mLastY;
-        mPath.lineTo(mLastX = dx, mLastY = dy);
-    }
-
-    /**
-     * Add a quadratic bezier from the last point, approaching control point
-     * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
-     * this contour, the first point is automatically set to (0,0).
-     *
-     * @param x1 The x-coordinate of the control point on a quadratic curve
-     * @param y1 The y-coordinate of the control point on a quadratic curve
-     * @param x2 The x-coordinate of the end point on a quadratic curve
-     * @param y2 The y-coordinate of the end point on a quadratic curve
-     */
-    public void quadTo(float x1, float y1, float x2, float y2) {
-        mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2);
-    }
-
-    /**
-     * Same as quadTo, but the coordinates are considered relative to the last
-     * point on this contour. If there is no previous point, then a moveTo(0,0)
-     * is inserted automatically.
-     *
-     * @param dx1 The amount to add to the x-coordinate of the last point on
-     *            this contour, for the control point of a quadratic curve
-     * @param dy1 The amount to add to the y-coordinate of the last point on
-     *            this contour, for the control point of a quadratic curve
-     * @param dx2 The amount to add to the x-coordinate of the last point on
-     *            this contour, for the end point of a quadratic curve
-     * @param dy2 The amount to add to the y-coordinate of the last point on
-     *            this contour, for the end point of a quadratic curve
-     */
-    public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
-        if (!hasPoints()) {
-            mPath.moveTo(mLastX = 0, mLastY = 0);
-        }
-        dx1 += mLastX;
-        dy1 += mLastY;
-        dx2 += mLastX;
-        dy2 += mLastY;
-        mPath.quadTo(dx1, dy1, mLastX = dx2, mLastY = dy2);
-    }
-
-    /**
-     * Add a cubic bezier from the last point, approaching control points
-     * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
-     * made for this contour, the first point is automatically set to (0,0).
-     *
-     * @param x1 The x-coordinate of the 1st control point on a cubic curve
-     * @param y1 The y-coordinate of the 1st control point on a cubic curve
-     * @param x2 The x-coordinate of the 2nd control point on a cubic curve
-     * @param y2 The y-coordinate of the 2nd control point on a cubic curve
-     * @param x3 The x-coordinate of the end point on a cubic curve
-     * @param y3 The y-coordinate of the end point on a cubic curve
-     */
-    public void cubicTo(float x1, float y1, float x2, float y2,
-                        float x3, float y3) {
-        if (!hasPoints()) {
-            mPath.moveTo(0, 0);
-        }
-        mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3);
-    }
-
-    /**
-     * Same as cubicTo, but the coordinates are considered relative to the
-     * current point on this contour. If there is no previous point, then a
-     * moveTo(0,0) is inserted automatically.
-     */
-    public void rCubicTo(float dx1, float dy1, float dx2, float dy2,
-                         float dx3, float dy3) {
-        if (!hasPoints()) {
-            mPath.moveTo(mLastX = 0, mLastY = 0);
-        }
-        dx1 += mLastX;
-        dy1 += mLastY;
-        dx2 += mLastX;
-        dy2 += mLastY;
-        dx3 += mLastX;
-        dy3 += mLastY;
-        mPath.curveTo(dx1, dy1, dx2, dy2, mLastX = dx3, mLastY = dy3);
-    }
-
-    /**
-     * Append the specified arc to the path as a new contour. If the start of
-     * the path is different from the path's current last point, then an
-     * automatic lineTo() is added to connect the current contour to the
-     * start of the arc. However, if the path is empty, then we call moveTo()
-     * with the first point of the arc. The sweep angle is tread mod 360.
-     *
-     * @param left        The left of oval defining shape and size of the arc
-     * @param top         The top of oval defining shape and size of the arc
-     * @param right       The right of oval defining shape and size of the arc
-     * @param bottom      The bottom of oval defining shape and size of the arc
-     * @param startAngle  Starting angle (in degrees) where the arc begins
-     * @param sweepAngle  Sweep angle (in degrees) measured clockwise, treated
-     *                    mod 360.
-     * @param forceMoveTo If true, always begin a new contour with the arc
-     */
-    public void arcTo(float left, float top, float right, float bottom, float startAngle,
-            float sweepAngle,
-            boolean forceMoveTo) {
-        Arc2D arc = new Arc2D.Float(left, top, right - left, bottom - top, -startAngle,
-                -sweepAngle, Arc2D.OPEN);
-        mPath.append(arc, true /*connect*/);
-
-        resetLastPointFromPath();
-    }
-
-    /**
-     * Close the current contour. If the current point is not equal to the
-     * first point of the contour, a line segment is automatically added.
-     */
-    public void close() {
-        mPath.closePath();
-    }
-
-    private void resetLastPointFromPath() {
-        Point2D last = mPath.getCurrentPoint();
-        mLastX = (float) last.getX();
-        mLastY = (float) last.getY();
-    }
-
-    /**
-     * Add a closed rectangle contour to the path
-     *
-     * @param left   The left side of a rectangle to add to the path
-     * @param top    The top of a rectangle to add to the path
-     * @param right  The right side of a rectangle to add to the path
-     * @param bottom The bottom of a rectangle to add to the path
-     * @param dir    The direction to wind the rectangle's contour
-     */
-    public void addRect(float left, float top, float right, float bottom,
-                        int dir) {
-        moveTo(left, top);
-
-        Direction direction = getDirection(dir);
-
-        switch (direction) {
-            case CW:
-                lineTo(right, top);
-                lineTo(right, bottom);
-                lineTo(left, bottom);
-                break;
-            case CCW:
-                lineTo(left, bottom);
-                lineTo(right, bottom);
-                lineTo(right, top);
-                break;
-        }
-
-        close();
-
-        resetLastPointFromPath();
-    }
-
-    /**
-     * Offset the path by (dx,dy), returning true on success
-     *
-     * @param dx  The amount in the X direction to offset the entire path
-     * @param dy  The amount in the Y direction to offset the entire path
-     */
-    public void offset(float dx, float dy) {
-        GeneralPath newPath = new GeneralPath();
-
-        PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
-
-        newPath.append(iterator, false /*connect*/);
-        mPath = newPath;
-    }
-
-    /**
-     * Transform the points in this path by matrix, and write the answer
-     * into dst. If dst is null, then the the original path is modified.
-     *
-     * @param matrix The matrix to apply to the path
-     * @param dst    The transformed path is written here. If dst is null,
-     *               then the the original path is modified
-     */
-    public void transform(Matrix_Delegate matrix, Path_Delegate dst) {
-        if (matrix.hasPerspective()) {
-            assert false;
-            Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MATRIX_AFFINE,
-                    "android.graphics.Path#transform() only " +
-                    "supports affine transformations.", null, null, null /*data*/);
-        }
-
-        GeneralPath newPath = new GeneralPath();
-
-        PathIterator iterator = mPath.getPathIterator(matrix.getAffineTransform());
-
-        newPath.append(iterator, false /*connect*/);
-
-        if (dst != null) {
-            dst.mPath = newPath;
-        } else {
-            mPath = newPath;
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
deleted file mode 100644
index 0dc6f61..0000000
--- a/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.PorterDuff.Mode;
-
-import java.awt.Graphics2D;
-import java.awt.image.BufferedImage;
-
-import static com.android.layoutlib.bridge.impl.PorterDuffUtility.getComposite;
-import static com.android.layoutlib.bridge.impl.PorterDuffUtility.getPorterDuffMode;
-
-/**
- * Delegate implementing the native methods of android.graphics.PorterDuffColorFilter
- *
- * Through the layoutlib_create tool, the original native methods of PorterDuffColorFilter have
- * been replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original PorterDuffColorFilter class.
- *
- * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
- * {@link DelegateManager}, as all the Shader classes will be added to the manager
- * owned by {@link ColorFilter_Delegate}.
- *
- * @see ColorFilter_Delegate
- *
- */
-public class PorterDuffColorFilter_Delegate extends ColorFilter_Delegate {
-
-    // ---- delegate data ----
-
-    private final java.awt.Color mSrcColor;
-    private final Mode mMode;
-
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public boolean isSupported() {
-        return true;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "PorterDuff Color Filter is not supported for mode: " + mMode.name() + ".";
-    }
-
-    @Override
-    public void applyFilter(Graphics2D g, int width, int height) {
-        g.setComposite(getComposite(mMode, 0xFF));
-        g.setColor(mSrcColor);
-        g.fillRect(0, 0, width, height);
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long native_CreateBlendModeFilter(int srcColor, int porterDuffMode) {
-        PorterDuffColorFilter_Delegate newDelegate =
-                new PorterDuffColorFilter_Delegate(srcColor, porterDuffMode);
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-
-    // ---- Private delegate/helper methods ----
-
-    private PorterDuffColorFilter_Delegate(int srcColor, int mode) {
-        mSrcColor = new java.awt.Color(srcColor, true /* hasAlpha */);
-        mMode = getCompatibleMode(getPorterDuffMode(mode));
-    }
-
-    // For filtering the colors, the src image should contain the "color" only for pixel values
-    // which are not transparent in the target image. But, we are using a simple rectangular image
-    // completely filled with color. Hence some Composite rules do not apply as intended. However,
-    // in such cases, they can usually be mapped to some other mode, which produces an approximately
-    // equivalent result.
-    private Mode getCompatibleMode(Mode mode) {
-        Mode m = mode;
-        // Modes that are directly supported:
-        // CLEAR, DST, SRC_IN, DST_IN, DST_OUT, SRC_ATOP, DARKEN, LIGHTEN, MULTIPLY, SCREEN,
-        // ADD, OVERLAY
-        switch (mode) {
-        // Modes that can be mapped to one of the supported modes.
-        case SRC:
-            m = Mode.SRC_IN;
-            break;
-        case SRC_OVER:
-            m = Mode.SRC_ATOP;
-            break;
-        case DST_OVER:
-            m = Mode.DST;
-            break;
-        case SRC_OUT:
-            m = Mode.CLEAR;
-            break;
-        case DST_ATOP:
-            m = Mode.DST_IN;
-            break;
-        case XOR:
-            m = Mode.DST_OUT;
-            break;
-        }
-        return m;
-    }
-}
diff --git a/bridge/src/android/graphics/RadialGradient_Delegate.java b/bridge/src/android/graphics/RadialGradient_Delegate.java
deleted file mode 100644
index 4a18219..0000000
--- a/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.Shader.TileMode;
-
-import java.awt.image.ColorModel;
-import java.awt.image.DataBufferInt;
-import java.awt.image.Raster;
-import java.awt.image.SampleModel;
-
-/**
- * Delegate implementing the native methods of android.graphics.RadialGradient
- *
- * Through the layoutlib_create tool, the original native methods of RadialGradient have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original RadialGradient class.
- *
- * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
- * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
- *
- * @see Shader_Delegate
- *
- */
-public class RadialGradient_Delegate extends Gradient_Delegate {
-
-    // ---- delegate data ----
-    private java.awt.Paint mJavaPaint;
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public java.awt.Paint getJavaPaint() {
-        return mJavaPaint;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(long matrix, float x, float y, float radius,
-            long[] colors, float[] positions, int tileMode, long colorSpaceHandle) {
-        RadialGradient_Delegate newDelegate = new RadialGradient_Delegate(matrix, x, y, radius,
-                colors, positions, Shader_Delegate.getTileMode(tileMode));
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-
-    /**
-     * Create a shader that draws a radial gradient given the center and radius.
-     *
-     * @param nativeMatrix reference to the shader's native transformation matrix
-     * @param x The x-coordinate of the center of the radius
-     * @param y The y-coordinate of the center of the radius
-     * @param radius Must be positive. The radius of the circle for this
-     *            gradient
-     * @param colors The colors to be distributed between the center and edge of
-     *            the circle
-     * @param positions May be NULL. The relative position of each corresponding
-     *            color in the colors array. If this is NULL, the the colors are
-     *            distributed evenly between the center and edge of the circle.
-     * @param tile The Shader tiling mode
-     */
-    private RadialGradient_Delegate(long nativeMatrix, float x, float y, float radius,
-            long[] colors, float[] positions, TileMode tile) {
-        super(nativeMatrix, colors, positions);
-        mJavaPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
-    }
-
-    private class RadialGradientPaint extends GradientPaint {
-
-        private final float mX;
-        private final float mY;
-        private final float mRadius;
-
-        public RadialGradientPaint(float x, float y, float radius,
-                int[] colors, float[] positions, TileMode mode) {
-            super(colors, positions, mode);
-            mX = x;
-            mY = y;
-            mRadius = radius;
-        }
-
-        @Override
-        public java.awt.PaintContext createContext(
-                java.awt.image.ColorModel     colorModel,
-                java.awt.Rectangle            deviceBounds,
-                java.awt.geom.Rectangle2D     userBounds,
-                java.awt.geom.AffineTransform xform,
-                java.awt.RenderingHints       hints) {
-            precomputeGradientColors();
-
-            java.awt.geom.AffineTransform canvasMatrix;
-            try {
-                canvasMatrix = xform.createInverse();
-            } catch (java.awt.geom.NoninvertibleTransformException e) {
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in RadialGradient", e, null, null /*data*/);
-                canvasMatrix = new java.awt.geom.AffineTransform();
-            }
-
-            java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
-            try {
-                localMatrix = localMatrix.createInverse();
-            } catch (java.awt.geom.NoninvertibleTransformException e) {
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in RadialGradient", e, null, null /*data*/);
-                localMatrix = new java.awt.geom.AffineTransform();
-            }
-
-            return new RadialGradientPaintContext(canvasMatrix, localMatrix, colorModel);
-        }
-
-        private class RadialGradientPaintContext implements java.awt.PaintContext {
-
-            private final java.awt.geom.AffineTransform mCanvasMatrix;
-            private final java.awt.geom.AffineTransform mLocalMatrix;
-            private final java.awt.image.ColorModel mColorModel;
-
-            public RadialGradientPaintContext(
-                    java.awt.geom.AffineTransform canvasMatrix,
-                    java.awt.geom.AffineTransform localMatrix,
-                    java.awt.image.ColorModel colorModel) {
-                mCanvasMatrix = canvasMatrix;
-                mLocalMatrix = localMatrix;
-                mColorModel = colorModel.hasAlpha() ? colorModel : ColorModel.getRGBdefault();
-            }
-
-            @Override
-            public void dispose() {
-            }
-
-            @Override
-            public java.awt.image.ColorModel getColorModel() {
-                return mColorModel;
-            }
-
-            @Override
-            public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
-                int[] data = new int[w*h];
-
-                // compute distance from each point to the center, and figure out the distance from
-                // it.
-                int index = 0;
-                float[] pt1 = new float[2];
-                float[] pt2 = new float[2];
-
-                for (int iy = 0 ; iy < h ; iy++) {
-                    for (int ix = 0 ; ix < w ; ix++) {
-                        // handle the canvas transform
-                        pt1[0] = x + ix;
-                        pt1[1] = y + iy;
-                        mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
-
-                        // handle the local matrix
-                        pt1[0] = pt2[0];
-                        pt1[1] = pt2[1];
-                        mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
-
-                        float _x = pt2[0] - mX;
-                        float _y = pt2[1] - mY;
-                        float distance = (float) Math.hypot(_x, _y);
-
-                        data[index++] = getGradientColor(distance / mRadius);
-                    }
-                }
-
-                DataBufferInt dataBuffer = new DataBufferInt(data, data.length);
-                SampleModel colorModel = mColorModel.createCompatibleSampleModel(w, h);
-                return Raster.createWritableRaster(colorModel, dataBuffer, null);
-            }
-
-        }
-    }
-
-}
diff --git a/bridge/src/android/graphics/Region_Delegate.java b/bridge/src/android/graphics/Region_Delegate.java
deleted file mode 100644
index 254e825..0000000
--- a/bridge/src/android/graphics/Region_Delegate.java
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.os.Parcel;
-
-import java.awt.Rectangle;
-import java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Area;
-import java.awt.geom.Rectangle2D;
-
-/**
- * Delegate implementing the native methods of android.graphics.Region
- *
- * Through the layoutlib_create tool, the original native methods of Region have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original Region class.
- *
- * This also serve as a base class for all Region delegate classes.
- *
- * @see DelegateManager
- *
- */
-public class Region_Delegate {
-
-    // ---- delegate manager ----
-    protected static final DelegateManager<Region_Delegate> sManager =
-            new DelegateManager<Region_Delegate>(Region_Delegate.class);
-
-    // ---- delegate helper data ----
-
-    // ---- delegate data ----
-    private Area mArea = new Area();
-
-    // ---- Public Helper methods ----
-
-    public static Region_Delegate getDelegate(long nativeShader) {
-        return sManager.getDelegate(nativeShader);
-    }
-
-    public Area getJavaArea() {
-        return mArea;
-    }
-
-    /**
-     * Combines two {@link Shape} into another one (actually an {@link Area}), according
-     * to the given {@link Region.Op}.
-     *
-     * If the Op is not one that combines two shapes, then this return null
-     *
-     * @param shape1 the firt shape to combine which can be null if there's no original clip.
-     * @param shape2 the 2nd shape to combine
-     * @param regionOp the operande for the combine
-     * @return a new area or null.
-     */
-    public static Area combineShapes(Shape shape1, Shape shape2, int regionOp) {
-        if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
-            // if shape1 is null (empty), then the result is null.
-            if (shape1 == null) {
-                return null;
-            }
-
-            // result is always a new area.
-            Area result = new Area(shape1);
-            result.subtract(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
-            return result;
-
-        } else if (regionOp == Region.Op.INTERSECT.nativeInt) {
-            // if shape1 is null, then the result is simply shape2.
-            if (shape1 == null) {
-                return new Area(shape2);
-            }
-
-            // result is always a new area.
-            Area result = new Area(shape1);
-            result.intersect(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
-            return result;
-
-        } else if (regionOp == Region.Op.UNION.nativeInt) {
-            // if shape1 is null, then the result is simply shape2.
-            if (shape1 == null) {
-                return new Area(shape2);
-            }
-
-            // result is always a new area.
-            Area result = new Area(shape1);
-            result.add(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
-            return result;
-
-        } else if (regionOp == Region.Op.XOR.nativeInt) {
-            // if shape1 is null, then the result is simply shape2
-            if (shape1 == null) {
-                return new Area(shape2);
-            }
-
-            // result is always a new area.
-            Area result = new Area(shape1);
-            result.exclusiveOr(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
-            return result;
-
-        } else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) {
-            // result is always a new area.
-            Area result = new Area(shape2);
-
-            if (shape1 != null) {
-                result.subtract(shape1 instanceof Area ? (Area) shape1 : new Area(shape1));
-            }
-
-            return result;
-        }
-
-        return null;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static boolean isEmpty(Region thisRegion) {
-        Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
-        if (regionDelegate == null) {
-            return true;
-        }
-
-        return regionDelegate.mArea.isEmpty();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean isRect(Region thisRegion) {
-        Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
-        if (regionDelegate == null) {
-            return true;
-        }
-
-        return regionDelegate.mArea.isRectangular();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean isComplex(Region thisRegion) {
-        Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
-        if (regionDelegate == null) {
-            return true;
-        }
-
-        return regionDelegate.mArea.isSingular() == false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean contains(Region thisRegion, int x, int y) {
-        Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
-        if (regionDelegate == null) {
-            return false;
-        }
-
-        return regionDelegate.mArea.contains(x, y);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean quickContains(Region thisRegion,
-            int left, int top, int right, int bottom) {
-        Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
-        if (regionDelegate == null) {
-            return false;
-        }
-
-        return regionDelegate.mArea.isRectangular() &&
-                regionDelegate.mArea.contains(left, top, right - left, bottom - top);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean quickReject(Region thisRegion,
-            int left, int top, int right, int bottom) {
-        Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
-        if (regionDelegate == null) {
-            return false;
-        }
-
-        return regionDelegate.mArea.isEmpty() ||
-                regionDelegate.mArea.intersects(left, top, right - left, bottom - top) == false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean quickReject(Region thisRegion, Region rgn) {
-        Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
-        if (regionDelegate == null) {
-            return false;
-        }
-
-        Region_Delegate targetRegionDelegate = sManager.getDelegate(rgn.mNativeRegion);
-        if (targetRegionDelegate == null) {
-            return false;
-        }
-
-        return regionDelegate.mArea.isEmpty() ||
-                regionDelegate.mArea.getBounds().intersects(
-                        targetRegionDelegate.mArea.getBounds()) == false;
-
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void translate(Region thisRegion, int dx, int dy, Region dst) {
-        Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
-        if (regionDelegate == null) {
-            return;
-        }
-
-        Region_Delegate targetRegionDelegate = sManager.getDelegate(dst.mNativeRegion);
-        if (targetRegionDelegate == null) {
-            return;
-        }
-
-        if (regionDelegate.mArea.isEmpty()) {
-            targetRegionDelegate.mArea = new Area();
-        } else {
-            targetRegionDelegate.mArea = new Area(regionDelegate.mArea);
-            AffineTransform mtx = new AffineTransform();
-            mtx.translate(dx, dy);
-            targetRegionDelegate.mArea.transform(mtx);
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void scale(Region thisRegion, float scale, Region dst) {
-        Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
-        if (regionDelegate == null) {
-            return;
-        }
-
-        Region_Delegate targetRegionDelegate = sManager.getDelegate(dst.mNativeRegion);
-        if (targetRegionDelegate == null) {
-            return;
-        }
-
-        if (regionDelegate.mArea.isEmpty()) {
-            targetRegionDelegate.mArea = new Area();
-        } else {
-            targetRegionDelegate.mArea = new Area(regionDelegate.mArea);
-            AffineTransform mtx = new AffineTransform();
-            mtx.scale(scale, scale);
-            targetRegionDelegate.mArea.transform(mtx);
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeConstructor() {
-        Region_Delegate newDelegate = new Region_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeDestructor(long native_region) {
-        sManager.removeJavaReferenceFor(native_region);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeSetRegion(long native_dst, long native_src) {
-        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
-        if (dstRegion == null) {
-            return;
-        }
-
-        Region_Delegate srcRegion = sManager.getDelegate(native_src);
-        if (srcRegion == null) {
-            return;
-        }
-
-        dstRegion.mArea.reset();
-        dstRegion.mArea.add(srcRegion.mArea);
-
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeSetRect(long native_dst,
-            int left, int top, int right, int bottom) {
-        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
-        if (dstRegion == null) {
-            return true;
-        }
-
-        dstRegion.mArea = new Area(new Rectangle2D.Float(left, top, right - left, bottom - top));
-        return dstRegion.mArea.getBounds().isEmpty() == false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeSetPath(long native_dst, long native_path, long native_clip) {
-        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
-        if (dstRegion == null) {
-            return true;
-        }
-
-        Path_Delegate path = Path_Delegate.getDelegate(native_path);
-        if (path == null) {
-            return true;
-        }
-
-        dstRegion.mArea = new Area(path.getJavaShape());
-
-        Region_Delegate clip = sManager.getDelegate(native_clip);
-        if (clip != null) {
-            dstRegion.mArea.subtract(clip.getJavaArea());
-        }
-
-        return dstRegion.mArea.getBounds().isEmpty() == false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeGetBounds(long native_region, Rect rect) {
-        Region_Delegate region = sManager.getDelegate(native_region);
-        if (region == null) {
-            return true;
-        }
-
-        Rectangle bounds = region.mArea.getBounds();
-        if (bounds.isEmpty()) {
-            rect.left = rect.top = rect.right = rect.bottom = 0;
-            return false;
-        }
-
-        rect.left = bounds.x;
-        rect.top = bounds.y;
-        rect.right = bounds.x + bounds.width;
-        rect.bottom = bounds.y + bounds.height;
-        return true;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeGetBoundaryPath(long native_region, long native_path) {
-        Region_Delegate region = sManager.getDelegate(native_region);
-        if (region == null) {
-            return false;
-        }
-
-        Path_Delegate path = Path_Delegate.getDelegate(native_path);
-        if (path == null) {
-            return false;
-        }
-
-        if (region.mArea.isEmpty()) {
-            path.reset();
-            return false;
-        }
-
-        path.setPathIterator(region.mArea.getPathIterator(new AffineTransform()));
-        return true;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeOp(long native_dst,
-            int left, int top, int right, int bottom, int op) {
-        Region_Delegate region = sManager.getDelegate(native_dst);
-        if (region == null) {
-            return false;
-        }
-
-        region.mArea = combineShapes(region.mArea,
-                new Rectangle2D.Float(left, top, right - left, bottom - top), op);
-
-        assert region.mArea != null;
-        if (region.mArea != null) {
-            region.mArea = new Area();
-        }
-
-        return region.mArea.getBounds().isEmpty() == false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeOp(long native_dst, Rect rect, long native_region, int op) {
-        Region_Delegate region = sManager.getDelegate(native_dst);
-        if (region == null) {
-            return false;
-        }
-
-        region.mArea = combineShapes(region.mArea,
-                new Rectangle2D.Float(rect.left, rect.top, rect.width(), rect.height()), op);
-
-        assert region.mArea != null;
-        if (region.mArea != null) {
-            region.mArea = new Area();
-        }
-
-        return region.mArea.getBounds().isEmpty() == false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeOp(long native_dst,
-            long native_region1, long native_region2, int op) {
-        Region_Delegate dstRegion = sManager.getDelegate(native_dst);
-        if (dstRegion == null) {
-            return true;
-        }
-
-        Region_Delegate region1 = sManager.getDelegate(native_region1);
-        if (region1 == null) {
-            return false;
-        }
-
-        Region_Delegate region2 = sManager.getDelegate(native_region2);
-        if (region2 == null) {
-            return false;
-        }
-
-        dstRegion.mArea = combineShapes(region1.mArea, region2.mArea, op);
-
-        assert dstRegion.mArea != null;
-        if (dstRegion.mArea != null) {
-            dstRegion.mArea = new Area();
-        }
-
-        return dstRegion.mArea.getBounds().isEmpty() == false;
-
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreateFromParcel(Parcel p) {
-        // This is only called by Region.CREATOR (Parcelable.Creator<Region>), which is only
-        // used during aidl call so really this should not be called.
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "AIDL is not suppored, and therefore Regions cannot be created from parcels.",
-                null, null /*data*/);
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeWriteToParcel(long native_region,
-                                                      Parcel p) {
-        // This is only called when sending a region through aidl, so really this should not
-        // be called.
-        Bridge.getLog().error(ILayoutLog.TAG_UNSUPPORTED,
-                "AIDL is not suppored, and therefore Regions cannot be written to parcels.",
-                null, null /*data*/);
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nativeEquals(long native_r1, long native_r2) {
-        Region_Delegate region1 = sManager.getDelegate(native_r1);
-        if (region1 == null) {
-            return false;
-        }
-
-        Region_Delegate region2 = sManager.getDelegate(native_r2);
-        if (region2 == null) {
-            return false;
-        }
-
-        return region1.mArea.equals(region2.mArea);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static String nativeToString(long native_region) {
-        Region_Delegate region = sManager.getDelegate(native_region);
-        if (region == null) {
-            return "not found";
-        }
-
-        return region.mArea.toString();
-    }
-
-    // ---- Private delegate/helper methods ----
-
-}
diff --git a/bridge/src/android/graphics/RenderNode_Delegate.java b/bridge/src/android/graphics/RenderNode_Delegate.java
deleted file mode 100644
index ae08b00..0000000
--- a/bridge/src/android/graphics/RenderNode_Delegate.java
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-/**
- * Delegate implementing the native methods of {@link RenderNode}
- * <p/>
- * Through the layoutlib_create tool, some native methods of RenderNode have been replaced by calls
- * to methods of the same name in this delegate class.
- *
- * @see DelegateManager
- */
-public class RenderNode_Delegate {
-
-
-    // ---- delegate manager ----
-    private static final DelegateManager<RenderNode_Delegate> sManager =
-            new DelegateManager<RenderNode_Delegate>(RenderNode_Delegate.class);
-    private static long sFinalizer = -1;
-
-    private float mLift;
-    private float mTranslationX;
-    private float mTranslationY;
-    private float mTranslationZ;
-    private float mRotation;
-    private float mScaleX = 1;
-    private float mScaleY = 1;
-    private float mPivotX;
-    private float mPivotY;
-    private boolean mPivotExplicitlySet;
-    private int mLeft;
-    private int mRight;
-    private int mTop;
-    private int mBottom;
-    @SuppressWarnings("UnusedDeclaration")
-    private String mName;
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreate(String name) {
-        RenderNode_Delegate renderNodeDelegate = new RenderNode_Delegate();
-        renderNodeDelegate.mName = name;
-        return sManager.addNewDelegate(renderNodeDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetNativeFinalizer() {
-        synchronized (RenderNode_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor);
-            }
-        }
-        return sFinalizer;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetElevation(long renderNode, float lift) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && delegate.mLift != lift) {
-            delegate.mLift = lift;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetElevation(long renderNode) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null) {
-            return delegate.mLift;
-        }
-        return 0f;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetTranslationX(long renderNode, float translationX) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && delegate.mTranslationX != translationX) {
-            delegate.mTranslationX = translationX;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetTranslationX(long renderNode) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null) {
-            return delegate.mTranslationX;
-        }
-        return 0f;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetTranslationY(long renderNode, float translationY) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && delegate.mTranslationY != translationY) {
-            delegate.mTranslationY = translationY;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetTranslationY(long renderNode) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null) {
-            return delegate.mTranslationY;
-        }
-        return 0f;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetTranslationZ(long renderNode, float translationZ) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && delegate.mTranslationZ != translationZ) {
-            delegate.mTranslationZ = translationZ;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetTranslationZ(long renderNode) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null) {
-            return delegate.mTranslationZ;
-        }
-        return 0f;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetRotation(long renderNode, float rotation) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && delegate.mRotation != rotation) {
-            delegate.mRotation = rotation;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetRotation(long renderNode) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null) {
-            return delegate.mRotation;
-        }
-        return 0f;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void getMatrix(RenderNode renderNode, Matrix outMatrix) {
-        outMatrix.reset();
-        if (renderNode != null) {
-            float rotation = renderNode.getRotationZ();
-            float translationX = renderNode.getTranslationX();
-            float translationY = renderNode.getTranslationY();
-            float pivotX = renderNode.getPivotX();
-            float pivotY = renderNode.getPivotY();
-            float scaleX = renderNode.getScaleX();
-            float scaleY = renderNode.getScaleY();
-
-            outMatrix.setTranslate(translationX, translationY);
-            outMatrix.preRotate(rotation, pivotX, pivotY);
-            outMatrix.preScale(scaleX, scaleY, pivotX, pivotY);
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetLeft(long renderNode, int left) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && delegate.mLeft != left) {
-            delegate.mLeft = left;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetTop(long renderNode, int top) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && delegate.mTop != top) {
-            delegate.mTop = top;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetRight(long renderNode, int right) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && delegate.mRight != right) {
-            delegate.mRight = right;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetBottom(long renderNode, int bottom) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && delegate.mBottom != bottom) {
-            delegate.mBottom = bottom;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetLeftTopRightBottom(long renderNode, int left, int top, int right,
-            int bottom) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && (delegate.mLeft != left || delegate.mTop != top || delegate
-                .mRight != right || delegate.mBottom != bottom)) {
-            delegate.mLeft = left;
-            delegate.mTop = top;
-            delegate.mRight = right;
-            delegate.mBottom = bottom;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nIsPivotExplicitlySet(long renderNode) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        return delegate != null && delegate.mPivotExplicitlySet;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetPivotX(long renderNode, float pivotX) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null) {
-            delegate.mPivotX = pivotX;
-            delegate.mPivotExplicitlySet = true;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetPivotX(long renderNode) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null) {
-            if (delegate.mPivotExplicitlySet) {
-                return delegate.mPivotX;
-            } else {
-                return (delegate.mRight - delegate.mLeft) / 2.0f;
-            }
-        }
-        return 0f;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetPivotY(long renderNode, float pivotY) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null) {
-            delegate.mPivotY = pivotY;
-            delegate.mPivotExplicitlySet = true;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetPivotY(long renderNode) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null) {
-            if (delegate.mPivotExplicitlySet) {
-                return delegate.mPivotY;
-            } else {
-                return (delegate.mBottom - delegate.mTop) / 2.0f;
-            }
-        }
-        return 0f;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetScaleX(long renderNode, float scaleX) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && delegate.mScaleX != scaleX) {
-            delegate.mScaleX = scaleX;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetScaleX(long renderNode) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null) {
-            return delegate.mScaleX;
-        }
-        return 0f;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nSetScaleY(long renderNode, float scaleY) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null && delegate.mScaleY != scaleY) {
-            delegate.mScaleY = scaleY;
-            return true;
-        }
-        return false;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetScaleY(long renderNode) {
-        RenderNode_Delegate delegate = sManager.getDelegate(renderNode);
-        if (delegate != null) {
-            return delegate.mScaleY;
-        }
-        return 0f;
-    }
-}
diff --git a/bridge/src/android/graphics/RoundRectangle.java b/bridge/src/android/graphics/RoundRectangle.java
deleted file mode 100644
index 736f03e..0000000
--- a/bridge/src/android/graphics/RoundRectangle.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-package android.graphics;
-
-import java.awt.geom.AffineTransform;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.RectangularShape;
-import java.awt.geom.RoundRectangle2D;
-import java.util.EnumSet;
-import java.util.NoSuchElementException;
-
-/**
- * Defines a rectangle with rounded corners, where the sizes of the corners
- * are potentially different.
- */
-public class RoundRectangle extends RectangularShape {
-    public double x;
-    public double y;
-    public double width;
-    public double height;
-    public double ulWidth;
-    public double ulHeight;
-    public double urWidth;
-    public double urHeight;
-    public double lrWidth;
-    public double lrHeight;
-    public double llWidth;
-    public double llHeight;
-
-    private enum Zone {
-        CLOSE_OUTSIDE,
-        CLOSE_INSIDE,
-        MIDDLE,
-        FAR_INSIDE,
-        FAR_OUTSIDE
-    }
-
-    private final EnumSet<Zone> close = EnumSet.of(Zone.CLOSE_OUTSIDE, Zone.CLOSE_INSIDE);
-    private final EnumSet<Zone> far = EnumSet.of(Zone.FAR_OUTSIDE, Zone.FAR_INSIDE);
-
-    /**
-     * @param cornerDimensions array of 8 floating-point number corresponding to the width and
-     * the height of each corner in the following order: upper-left, upper-right, lower-right,
-     * lower-left. It assumes for the size the same convention as {@link RoundRectangle2D}, that
-     * is that the width and height of a corner correspond to the total width and height of the
-     * ellipse that corner is a quarter of.
-     */
-    public RoundRectangle(float x, float y, float width, float height, float[] cornerDimensions) {
-        assert cornerDimensions.length == 8 : "The array of corner dimensions must have eight " +
-                    "elements";
-
-        this.x = x;
-        this.y = y;
-        this.width = width;
-        this.height = height;
-
-        float[] dimensions = cornerDimensions.clone();
-        // If a value is negative, the corresponding corner is squared
-        for (int i = 0; i < dimensions.length; i += 2) {
-            if (dimensions[i] < 0 || dimensions[i + 1] < 0) {
-                dimensions[i] = 0;
-                dimensions[i + 1] = 0;
-            }
-        }
-
-        double topCornerWidth = (dimensions[0] + dimensions[2]) / 2d;
-        double bottomCornerWidth = (dimensions[4] + dimensions[6]) / 2d;
-        double leftCornerHeight = (dimensions[1] + dimensions[7]) / 2d;
-        double rightCornerHeight = (dimensions[3] + dimensions[5]) / 2d;
-
-        // Rescale the corner dimensions if they are bigger than the rectangle
-        double scale = Math.min(1.0, width / topCornerWidth);
-        scale = Math.min(scale, width / bottomCornerWidth);
-        scale = Math.min(scale, height / leftCornerHeight);
-        scale = Math.min(scale, height / rightCornerHeight);
-
-        this.ulWidth = dimensions[0] * scale;
-        this.ulHeight = dimensions[1] * scale;
-        this.urWidth = dimensions[2] * scale;
-        this.urHeight = dimensions[3] * scale;
-        this.lrWidth = dimensions[4] * scale;
-        this.lrHeight = dimensions[5] * scale;
-        this.llWidth = dimensions[6] * scale;
-        this.llHeight = dimensions[7] * scale;
-    }
-
-    @Override
-    public double getX() {
-        return x;
-    }
-
-    @Override
-    public double getY() {
-        return y;
-    }
-
-    @Override
-    public double getWidth() {
-        return width;
-    }
-
-    @Override
-    public double getHeight() {
-        return height;
-    }
-
-    @Override
-    public boolean isEmpty() {
-        return (width <= 0d) || (height <= 0d);
-    }
-
-    @Override
-    public void setFrame(double x, double y, double w, double h) {
-        this.x = x;
-        this.y = y;
-        this.width = w;
-        this.height = h;
-    }
-
-    @Override
-    public Rectangle2D getBounds2D() {
-        return new Rectangle2D.Double(x, y, width, height);
-    }
-
-    @Override
-    public boolean contains(double x, double y) {
-        if (isEmpty()) {
-            return false;
-        }
-
-        double x0 = getX();
-        double y0 = getY();
-        double x1 = x0 + getWidth();
-        double y1 = y0 + getHeight();
-        // Check for trivial rejection - point is outside bounding rectangle
-        if (x < x0 || y < y0 || x >= x1 || y >= y1) {
-            return false;
-        }
-
-        double insideTopX0 = x0 + ulWidth / 2d;
-        double insideLeftY0 = y0 + ulHeight / 2d;
-        if (x < insideTopX0 && y < insideLeftY0) {
-            // In the upper-left corner
-            return isInsideCorner(x - insideTopX0, y - insideLeftY0, ulWidth / 2d, ulHeight / 2d);
-        }
-
-        double insideTopX1 = x1 - urWidth / 2d;
-        double insideRightY0 = y0 + urHeight / 2d;
-        if (x > insideTopX1 && y < insideRightY0) {
-            // In the upper-right corner
-            return isInsideCorner(x - insideTopX1, y - insideRightY0, urWidth / 2d, urHeight / 2d);
-        }
-
-        double insideBottomX1 = x1 - lrWidth / 2d;
-        double insideRightY1 = y1 - lrHeight / 2d;
-        if (x > insideBottomX1 && y > insideRightY1) {
-            // In the lower-right corner
-            return isInsideCorner(x - insideBottomX1, y - insideRightY1, lrWidth / 2d,
-                    lrHeight / 2d);
-        }
-
-        double insideBottomX0 = x0 + llWidth / 2d;
-        double insideLeftY1 = y1 - llHeight / 2d;
-        if (x < insideBottomX0 && y > insideLeftY1) {
-            // In the lower-left corner
-            return isInsideCorner(x - insideBottomX0, y - insideLeftY1, llWidth / 2d,
-                    llHeight / 2d);
-        }
-
-        // In the central part of the rectangle
-        return true;
-    }
-
-    private boolean isInsideCorner(double x, double y, double width, double height) {
-        double squareDist = height * height * x * x + width * width * y * y;
-        return squareDist <= width * width * height * height;
-    }
-
-    private Zone classify(double coord, double side1, double arcSize1, double side2,
-            double arcSize2) {
-        if (coord < side1) {
-            return Zone.CLOSE_OUTSIDE;
-        } else if (coord < side1 + arcSize1) {
-            return Zone.CLOSE_INSIDE;
-        } else if (coord < side2 - arcSize2) {
-            return Zone.MIDDLE;
-        } else if (coord < side2) {
-            return Zone.FAR_INSIDE;
-        } else {
-            return Zone.FAR_OUTSIDE;
-        }
-    }
-
-    public boolean intersects(double x, double y, double w, double h) {
-        if (isEmpty() || w <= 0 || h <= 0) {
-            return false;
-        }
-        double x0 = getX();
-        double y0 = getY();
-        double x1 = x0 + getWidth();
-        double y1 = y0 + getHeight();
-        // Check for trivial rejection - bounding rectangles do not intersect
-        if (x + w <= x0 || x >= x1 || y + h <= y0 || y >= y1) {
-            return false;
-        }
-
-        double maxLeftCornerWidth = Math.max(ulWidth, llWidth) / 2d;
-        double maxRightCornerWidth = Math.max(urWidth, lrWidth) / 2d;
-        double maxUpperCornerHeight = Math.max(ulHeight, urHeight) / 2d;
-        double maxLowerCornerHeight = Math.max(llHeight, lrHeight) / 2d;
-        Zone x0class = classify(x, x0, maxLeftCornerWidth, x1, maxRightCornerWidth);
-        Zone x1class = classify(x + w, x0, maxLeftCornerWidth, x1, maxRightCornerWidth);
-        Zone y0class = classify(y, y0, maxUpperCornerHeight, y1, maxLowerCornerHeight);
-        Zone y1class = classify(y + h, y0, maxUpperCornerHeight, y1, maxLowerCornerHeight);
-
-        // Trivially accept if any point is inside inner rectangle
-        if (x0class == Zone.MIDDLE || x1class == Zone.MIDDLE || y0class == Zone.MIDDLE || y1class == Zone.MIDDLE) {
-            return true;
-        }
-        // Trivially accept if either edge spans inner rectangle
-        if ((close.contains(x0class) && far.contains(x1class)) || (close.contains(y0class) &&
-                far.contains(y1class))) {
-            return true;
-        }
-
-        // Since neither edge spans the center, then one of the corners
-        // must be in one of the rounded edges.  We detect this case if
-        // a [xy]0class is 3 or a [xy]1class is 1.  One of those two cases
-        // must be true for each direction.
-        // We now find a "nearest point" to test for being inside a rounded
-        // corner.
-        if (x1class == Zone.CLOSE_INSIDE && y1class == Zone.CLOSE_INSIDE) {
-            // Potentially in upper-left corner
-            x = x + w - x0 - ulWidth / 2d;
-            y = y + h - y0 - ulHeight / 2d;
-            return x > 0 || y > 0 || isInsideCorner(x, y, ulWidth / 2d, ulHeight / 2d);
-        }
-        if (x1class == Zone.CLOSE_INSIDE) {
-            // Potentially in lower-left corner
-            x = x + w - x0 - llWidth / 2d;
-            y = y - y1 + llHeight / 2d;
-            return x > 0 || y < 0 || isInsideCorner(x, y, llWidth / 2d, llHeight / 2d);
-        }
-        if (y1class == Zone.CLOSE_INSIDE) {
-            //Potentially in the upper-right corner
-            x = x - x1 + urWidth / 2d;
-            y = y + h - y0 - urHeight / 2d;
-            return x < 0 || y > 0 || isInsideCorner(x, y, urWidth / 2d, urHeight / 2d);
-        }
-        // Potentially in the lower-right corner
-        x = x - x1 + lrWidth / 2d;
-        y = y - y1 + lrHeight / 2d;
-        return x < 0 || y < 0 || isInsideCorner(x, y, lrWidth / 2d, lrHeight / 2d);
-    }
-
-    @Override
-    public boolean contains(double x, double y, double w, double h) {
-        if (isEmpty() || w <= 0 || h <= 0) {
-            return false;
-        }
-        return (contains(x, y) &&
-                contains(x + w, y) &&
-                contains(x, y + h) &&
-                contains(x + w, y + h));
-    }
-
-    @Override
-    public PathIterator getPathIterator(final AffineTransform at) {
-        return new PathIterator() {
-            int index;
-
-            // ArcIterator.btan(Math.PI/2)
-            public static final double CtrlVal = 0.5522847498307933;
-            private final double ncv = 1.0 - CtrlVal;
-
-            // Coordinates of control points for Bezier curves approximating the straight lines
-            // and corners of the rounded rectangle.
-            private final double[][] ctrlpts = {
-                    {0.0, 0.0, 0.0, ulHeight},
-                    {0.0, 0.0, 1.0, -llHeight},
-                    {0.0, 0.0, 1.0, -llHeight * ncv, 0.0, ncv * llWidth, 1.0, 0.0, 0.0, llWidth,
-                            1.0, 0.0},
-                    {1.0, -lrWidth, 1.0, 0.0},
-                    {1.0, -lrWidth * ncv, 1.0, 0.0, 1.0, 0.0, 1.0, -lrHeight * ncv, 1.0, 0.0, 1.0,
-                            -lrHeight},
-                    {1.0, 0.0, 0.0, urHeight},
-                    {1.0, 0.0, 0.0, ncv * urHeight, 1.0, -urWidth * ncv, 0.0, 0.0, 1.0, -urWidth,
-                            0.0, 0.0},
-                    {0.0, ulWidth, 0.0, 0.0},
-                    {0.0, ncv * ulWidth, 0.0, 0.0, 0.0, 0.0, 0.0, ncv * ulHeight, 0.0, 0.0, 0.0,
-                            ulHeight},
-                    {}
-            };
-            private final int[] types = {
-                    SEG_MOVETO,
-                    SEG_LINETO, SEG_CUBICTO,
-                    SEG_LINETO, SEG_CUBICTO,
-                    SEG_LINETO, SEG_CUBICTO,
-                    SEG_LINETO, SEG_CUBICTO,
-                    SEG_CLOSE,
-            };
-
-            @Override
-            public int getWindingRule() {
-                return WIND_NON_ZERO;
-            }
-
-            @Override
-            public boolean isDone() {
-                return index >= ctrlpts.length;
-            }
-
-            @Override
-            public void next() {
-                index++;
-            }
-
-            @Override
-            public int currentSegment(float[] coords) {
-                if (isDone()) {
-                    throw new NoSuchElementException("roundrect iterator out of bounds");
-                }
-                int nc = 0;
-                double ctrls[] = ctrlpts[index];
-                for (int i = 0; i < ctrls.length; i += 4) {
-                    coords[nc++] = (float) (x + ctrls[i] * width + ctrls[i + 1] / 2d);
-                    coords[nc++] = (float) (y + ctrls[i + 2] * height + ctrls[i + 3] / 2d);
-                }
-                if (at != null) {
-                    at.transform(coords, 0, coords, 0, nc / 2);
-                }
-                return types[index];
-            }
-
-            @Override
-            public int currentSegment(double[] coords) {
-                if (isDone()) {
-                    throw new NoSuchElementException("roundrect iterator out of bounds");
-                }
-                int nc = 0;
-                double ctrls[] = ctrlpts[index];
-                for (int i = 0; i < ctrls.length; i += 4) {
-                    coords[nc++] = x + ctrls[i] * width + ctrls[i + 1] / 2d;
-                    coords[nc++] = y + ctrls[i + 2] * height + ctrls[i + 3] / 2d;
-                }
-                if (at != null) {
-                    at.transform(coords, 0, coords, 0, nc / 2);
-                }
-                return types[index];
-            }
-        };
-    }
-}
diff --git a/bridge/src/android/graphics/Shader_Delegate.java b/bridge/src/android/graphics/Shader_Delegate.java
deleted file mode 100644
index d606e2d..0000000
--- a/bridge/src/android/graphics/Shader_Delegate.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.Shader.TileMode;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-/**
- * Delegate implementing the native methods of android.graphics.Shader
- *
- * Through the layoutlib_create tool, the original native methods of Shader have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original Shader class.
- *
- * This also serve as a base class for all Shader delegate classes.
- *
- * @see DelegateManager
- *
- */
-public abstract class Shader_Delegate {
-
-    // ---- delegate manager ----
-    protected static final DelegateManager<Shader_Delegate> sManager =
-            new DelegateManager<Shader_Delegate>(Shader_Delegate.class);
-    private static long sFinalizer = -1;
-
-    // ---- delegate helper data ----
-
-    // ---- delegate data ----
-    private Matrix_Delegate mLocalMatrix = null;
-    private float mAlpha = 1.0f;
-
-    // ---- Public Helper methods ----
-
-    public static Shader_Delegate getDelegate(long nativeShader) {
-        return sManager.getDelegate(nativeShader);
-    }
-
-    /**
-     * Returns the {@link TileMode} matching the given int.
-     * @param tileMode the tile mode int value
-     * @return the TileMode enum.
-     */
-    public static TileMode getTileMode(int tileMode) {
-        for (TileMode tm : TileMode.values()) {
-            if (tm.nativeInt == tileMode) {
-                return tm;
-            }
-        }
-
-        assert false;
-        return TileMode.CLAMP;
-    }
-
-    public abstract java.awt.Paint getJavaPaint();
-    public abstract boolean isSupported();
-    public abstract String getSupportMessage();
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeGetFinalizer() {
-        synchronized (Shader_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
-                        sManager::removeJavaReferenceFor);
-            }
-        }
-        return sFinalizer;
-    }
-
-    // ---- Private delegate/helper methods ----
-
-    protected Shader_Delegate(long nativeMatrix) {
-        setLocalMatrix(nativeMatrix);
-    }
-
-    public void setLocalMatrix(long nativeMatrix) {
-        mLocalMatrix = Matrix_Delegate.getDelegate(nativeMatrix);
-    }
-
-    protected java.awt.geom.AffineTransform getLocalMatrix() {
-        if (mLocalMatrix != null) {
-            return mLocalMatrix.getAffineTransform();
-        }
-
-        return new java.awt.geom.AffineTransform();
-    }
-
-    public void setAlpha(float alpha) {
-        mAlpha = alpha;
-    }
-
-    public float getAlpha() {
-        return mAlpha;
-    }
-}
diff --git a/bridge/src/android/graphics/SumPathEffect_Delegate.java b/bridge/src/android/graphics/SumPathEffect_Delegate.java
deleted file mode 100644
index 6d2e9b4..0000000
--- a/bridge/src/android/graphics/SumPathEffect_Delegate.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.Stroke;
-
-/**
- * Delegate implementing the native methods of android.graphics.SumPathEffect
- *
- * Through the layoutlib_create tool, the original native methods of SumPathEffect have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original SumPathEffect class.
- *
- * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
- * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
- *
- * @see PathEffect_Delegate
- *
- */
-public class SumPathEffect_Delegate extends PathEffect_Delegate {
-
-    // ---- delegate data ----
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public Stroke getStroke(Paint_Delegate paint) {
-        // FIXME
-        return null;
-    }
-
-    @Override
-    public boolean isSupported() {
-        return false;
-    }
-
-    @Override
-    public String getSupportMessage() {
-        return "Sum Path Effects are not supported in Layout Preview mode.";
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(long first, long second) {
-        SumPathEffect_Delegate newDelegate = new SumPathEffect_Delegate();
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-}
diff --git a/bridge/src/android/graphics/SweepGradient_Delegate.java b/bridge/src/android/graphics/SweepGradient_Delegate.java
deleted file mode 100644
index 01ef140..0000000
--- a/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package android.graphics;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.awt.image.DataBufferInt;
-import java.awt.image.Raster;
-import java.awt.image.SampleModel;
-
-/**
- * Delegate implementing the native methods of android.graphics.SweepGradient
- *
- * Through the layoutlib_create tool, the original native methods of SweepGradient have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original SweepGradient class.
- *
- * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
- * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
- *
- * @see Shader_Delegate
- *
- */
-public class SweepGradient_Delegate extends Gradient_Delegate {
-
-    // ---- delegate data ----
-    private java.awt.Paint mJavaPaint;
-
-    // ---- Public Helper methods ----
-
-    @Override
-    public java.awt.Paint getJavaPaint() {
-        return mJavaPaint;
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreate(long matrix, float x, float y, long[] colors,
-            float[] positions, long colorSpaceHandle) {
-        SweepGradient_Delegate newDelegate = new SweepGradient_Delegate(matrix, x, y, colors,
-                positions);
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    // ---- Private delegate/helper methods ----
-
-    /**
-     * A subclass of Shader that draws a sweep gradient around a center point.
-     *
-     * @param nativeMatrix reference to the shader's native transformation matrix
-     * @param cx       The x-coordinate of the center
-     * @param cy       The y-coordinate of the center
-     * @param colors   The colors to be distributed between around the center.
-     *                 There must be at least 2 colors in the array.
-     * @param positions May be NULL. The relative position of
-     *                 each corresponding color in the colors array, beginning
-     *                 with 0 and ending with 1.0. If the values are not
-     *                 monotonic, the drawing may produce unexpected results.
-     *                 If positions is NULL, then the colors are automatically
-     *                 spaced evenly.
-     */
-    private SweepGradient_Delegate(long nativeMatrix, float cx, float cy,
-            long[] colors, float[] positions) {
-        super(nativeMatrix, colors, positions);
-        mJavaPaint = new SweepGradientPaint(cx, cy, mColors, mPositions);
-    }
-
-    private class SweepGradientPaint extends GradientPaint {
-
-        private final float mCx;
-        private final float mCy;
-
-        public SweepGradientPaint(float cx, float cy, int[] colors,
-                float[] positions) {
-            super(colors, positions, null /*tileMode*/);
-            mCx = cx;
-            mCy = cy;
-        }
-
-        @Override
-        public java.awt.PaintContext createContext(
-                java.awt.image.ColorModel     colorModel,
-                java.awt.Rectangle            deviceBounds,
-                java.awt.geom.Rectangle2D     userBounds,
-                java.awt.geom.AffineTransform xform,
-                java.awt.RenderingHints       hints) {
-            precomputeGradientColors();
-
-            java.awt.geom.AffineTransform canvasMatrix;
-            try {
-                canvasMatrix = xform.createInverse();
-            } catch (java.awt.geom.NoninvertibleTransformException e) {
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in SweepGradient", e, null, null /*data*/);
-                canvasMatrix = new java.awt.geom.AffineTransform();
-            }
-
-            java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
-            try {
-                localMatrix = localMatrix.createInverse();
-            } catch (java.awt.geom.NoninvertibleTransformException e) {
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in SweepGradient", e, null, null /*data*/);
-                localMatrix = new java.awt.geom.AffineTransform();
-            }
-
-            return new SweepGradientPaintContext(canvasMatrix, localMatrix, colorModel);
-        }
-
-        private class SweepGradientPaintContext implements java.awt.PaintContext {
-
-            private final java.awt.geom.AffineTransform mCanvasMatrix;
-            private final java.awt.geom.AffineTransform mLocalMatrix;
-            private final java.awt.image.ColorModel mColorModel;
-
-            public SweepGradientPaintContext(
-                    java.awt.geom.AffineTransform canvasMatrix,
-                    java.awt.geom.AffineTransform localMatrix,
-                    java.awt.image.ColorModel colorModel) {
-                mCanvasMatrix = canvasMatrix;
-                mLocalMatrix = localMatrix;
-                mColorModel = colorModel;
-            }
-
-            @Override
-            public void dispose() {
-            }
-
-            @Override
-            public java.awt.image.ColorModel getColorModel() {
-                return mColorModel;
-            }
-
-            @Override
-            public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
-
-                int[] data = new int[w*h];
-
-                // compute angle from each point to the center, and figure out the distance from
-                // it.
-                int index = 0;
-                float[] pt1 = new float[2];
-                float[] pt2 = new float[2];
-                for (int iy = 0 ; iy < h ; iy++) {
-                    for (int ix = 0 ; ix < w ; ix++) {
-                        // handle the canvas transform
-                        pt1[0] = x + ix;
-                        pt1[1] = y + iy;
-                        mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
-
-                        // handle the local matrix
-                        pt1[0] = pt2[0] - mCx;
-                        pt1[1] = pt2[1] - mCy;
-                        mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
-
-                        float dx = pt2[0];
-                        float dy = pt2[1];
-
-                        float angle;
-                        if (dx == 0) {
-                            angle = (float) (dy < 0 ? 3 * Math.PI / 2 : Math.PI / 2);
-                        } else if (dy == 0) {
-                            angle = (float) (dx < 0 ? Math.PI : 0);
-                        } else {
-                            angle = (float) Math.atan(dy / dx);
-                            if (dx > 0) {
-                                if (dy < 0) {
-                                    angle += Math.PI * 2;
-                                }
-                            } else {
-                                angle += Math.PI;
-                            }
-                        }
-
-                        // convert to 0-1. value and get color
-                        data[index++] = getGradientColor((float) (angle / (2 * Math.PI)));
-                    }
-                }
-
-                DataBufferInt dataBuffer = new DataBufferInt(data, data.length);
-                SampleModel colorModel = mColorModel.createCompatibleSampleModel(w, h);
-                return Raster.createWritableRaster(colorModel, dataBuffer, null);
-            }
-
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/Typeface_Delegate.java b/bridge/src/android/graphics/Typeface_Delegate.java
index 6c0ab20..81b2c90 100644
--- a/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/bridge/src/android/graphics/Typeface_Delegate.java
@@ -33,23 +33,10 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.FontResourcesParser;
-import android.graphics.FontFamily_Delegate.FontVariant;
-import android.graphics.fonts.FontFamily_Builder_Delegate;
-import android.graphics.fonts.FontVariationAxis;
 
-import java.awt.Font;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Spliterator;
-import java.util.Spliterators;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
 
 /**
  * Delegate implementing the native methods of android.graphics.Typeface
@@ -64,174 +51,6 @@
  * @see DelegateManager
  */
 public final class Typeface_Delegate {
-
-    public static final String SYSTEM_FONTS = "/system/fonts/";
-
-    public static final Map<String, FontFamily_Delegate[]> sGenericNativeFamilies = new HashMap<>();
-
-    // ---- delegate manager ----
-    private static final DelegateManager<Typeface_Delegate> sManager =
-            new DelegateManager<>(Typeface_Delegate.class);
-    private static long sFinalizer = -1;
-
-    // ---- delegate data ----
-    private static long sDefaultTypeface;
-    @NonNull
-    private final FontFamily_Delegate[] mFontFamilies;  // the reference to FontFamily_Delegate.
-    @NonNull
-    private final FontFamily_Builder_Delegate[] mFontFamilyBuilders;  // the reference to
-    // FontFamily_Builder_Delegate.
-    /** @see Font#getStyle() */
-    private final int mStyle;
-    private final int mWeight;
-
-
-    // ---- Public Helper methods ----
-
-    private Typeface_Delegate(@NonNull FontFamily_Delegate[] fontFamilies,
-            @NonNull FontFamily_Builder_Delegate[] fontFamilyBuilders, int style,
-            int weight) {
-        mFontFamilies = fontFamilies;
-        mFontFamilyBuilders = fontFamilyBuilders;
-        mStyle = style;
-        mWeight = weight;
-    }
-
-    public static Typeface_Delegate getDelegate(long nativeTypeface) {
-        return sManager.getDelegate(nativeTypeface);
-    }
-
-    // ---- native methods ----
-
-    @LayoutlibDelegate
-    /*package*/ static synchronized long nativeCreateFromTypeface(long native_instance, int style) {
-        Typeface_Delegate delegate = sManager.getDelegate(native_instance);
-        if (delegate == null) {
-            delegate = sManager.getDelegate(sDefaultTypeface);
-        }
-        if (delegate == null) {
-            return 0;
-        }
-
-        return sManager.addNewDelegate(
-                new Typeface_Delegate(delegate.mFontFamilies, delegate.mFontFamilyBuilders, style,
-                        delegate.mWeight));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreateFromTypefaceWithExactStyle(long native_instance, int weight,
-            boolean italic) {
-        Typeface_Delegate delegate = sManager.getDelegate(native_instance);
-        if (delegate == null) {
-            delegate = sManager.getDelegate(sDefaultTypeface);
-        }
-        if (delegate == null) {
-            return 0;
-        }
-
-        int style = weight >= 600 ? (italic ? Typeface.BOLD_ITALIC : Typeface.BOLD) :
-                (italic ? Typeface.ITALIC : Typeface.NORMAL);
-        return sManager.addNewDelegate(
-                new Typeface_Delegate(delegate.mFontFamilies, delegate.mFontFamilyBuilders, style,
-                        weight));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static synchronized long nativeCreateFromTypefaceWithVariation(long native_instance,
-            List<FontVariationAxis> axes) {
-        long newInstance = nativeCreateFromTypeface(native_instance, 0);
-
-        if (newInstance != 0) {
-            Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                    "nativeCreateFromTypefaceWithVariation is not supported", null, null, null);
-        }
-        return newInstance;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static synchronized int[] nativeGetSupportedAxes(long native_instance) {
-        // nativeCreateFromTypefaceWithVariation is not supported so we do not keep the axes
-        return null;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeCreateWeightAlias(long native_instance, int weight) {
-        Typeface_Delegate delegate = sManager.getDelegate(native_instance);
-        if (delegate == null) {
-            delegate = sManager.getDelegate(sDefaultTypeface);
-        }
-        if (delegate == null) {
-            return 0;
-        }
-        Typeface_Delegate weightAlias =
-                new Typeface_Delegate(delegate.mFontFamilies, delegate.mFontFamilyBuilders,
-                        delegate.mStyle,
-                        weight);
-        return sManager.addNewDelegate(weightAlias);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static synchronized long nativeCreateFromArray(long[] familyArray, int weight,
-            int italic) {
-        List<FontFamily_Delegate> fontFamilies = new ArrayList<>();
-        List<FontFamily_Builder_Delegate> fontFamilyBuilders = new ArrayList<>();
-        for (long aFamilyArray : familyArray) {
-            try {
-                fontFamilies.add(FontFamily_Delegate.getDelegate(aFamilyArray));
-            } catch (ClassCastException e) {
-                fontFamilyBuilders.add(FontFamily_Builder_Delegate.getDelegate(aFamilyArray));
-            }
-        }
-        if (weight == Typeface.RESOLVE_BY_FONT_TABLE) {
-            weight = 400;
-        }
-        if (italic == Typeface.RESOLVE_BY_FONT_TABLE) {
-            italic = 0;
-        }
-        int style = weight >= 600 ? (italic == 1 ? Typeface.BOLD_ITALIC : Typeface.BOLD) :
-                (italic == 1 ? Typeface.ITALIC : Typeface.NORMAL);
-        Typeface_Delegate delegate =
-                new Typeface_Delegate(fontFamilies.toArray(new FontFamily_Delegate[0]),
-                fontFamilyBuilders.toArray(new FontFamily_Builder_Delegate[0]),
-                style, weight);
-        return sManager.addNewDelegate(delegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeGetReleaseFunc() {
-        synchronized (Typeface_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
-                        sManager::removeJavaReferenceFor);
-            }
-        }
-        return sFinalizer;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nativeGetStyle(long native_instance) {
-        Typeface_Delegate delegate = sManager.getDelegate(native_instance);
-        if (delegate == null) {
-            return 0;
-        }
-
-        return delegate.mStyle;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeSetDefault(long native_instance) {
-        sDefaultTypeface = native_instance;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nativeGetWeight(long native_instance) {
-        Typeface_Delegate delegate = sManager.getDelegate(native_instance);
-        if (delegate == null) {
-            return 0;
-        }
-        return delegate.mWeight;
-    }
-
     /**
      * Loads a single font or font family from disk
      */
@@ -266,8 +85,8 @@
                             FontResourcesParser.parse(blockParser, context.getResources());
                     typeface = Typeface.createFromResources(entry, context.getAssets(), path);
                 } catch (XmlPullParserException | IOException e) {
-                    Bridge.getLog().error(null, "Failed to parse file " + path, e, null, null /*data
-                    */);
+                    Bridge.getLog().error(null, "Failed to parse file " + path, e, null,
+                            null /*data*/);
                 } finally {
                     blockParser.ensurePopped();
                 }
@@ -303,125 +122,4 @@
     /*package*/ static Typeface create(Typeface family, int style, boolean isItalic) {
         return Typeface.create_Original(family, style, isItalic);
     }
-
-    @LayoutlibDelegate
-    /*package*/ static void nativeRegisterGenericFamily(String str, long nativePtr) {
-        Typeface_Delegate delegate = sManager.getDelegate(nativePtr);
-        if (delegate == null) {
-            return;
-        }
-        sGenericNativeFamilies.put(str, delegate.mFontFamilies);
-    }
-
-    // ---- Private delegate/helper methods ----
-
-    /**
-     * Return an Iterable of fonts that match the style and variant. The list is ordered
-     * according to preference of fonts.
-     * <p>
-     * The Iterator may contain null when the font failed to load. If null is reached when trying to
-     * render with this list of fonts, then a warning should be logged letting the user know that
-     * some font failed to load.
-     *
-     * @param variant The variant preferred. Can only be {@link FontVariant#COMPACT} or {@link
-     * FontVariant#ELEGANT}
-     */
-    @NonNull
-    public Iterable<Font> getFonts(final FontVariant variant) {
-        assert variant != FontVariant.NONE;
-
-        return new FontsIterator(mFontFamilies, mFontFamilyBuilders, variant, mWeight, mStyle);
-    }
-
-    private static class FontsIterator implements Iterator<Font>, Iterable<Font> {
-        private final FontFamily_Delegate[] fontFamilies;
-        private final FontFamily_Builder_Delegate[] fontFamilyBuilders;
-        private final int weight;
-        private final boolean isItalic;
-        private final FontVariant variant;
-
-        private int index = 0;
-
-        private FontsIterator(@NonNull FontFamily_Delegate[] fontFamilies,
-                @NonNull FontFamily_Builder_Delegate[] fontFamilyBuilders,
-                @NonNull FontVariant variant, int weight, int style) {
-            // Calculate the required weight based on style and weight of this typeface.
-            int boldExtraWeight =
-                    ((style & Font.BOLD) == 0 ? 0 : FontFamily_Delegate.BOLD_FONT_WEIGHT_DELTA);
-            this.weight = Math.min(Math.max(100, weight + 50 + boldExtraWeight), 1000);
-            this.isItalic = (style & Font.ITALIC) != 0;
-            this.fontFamilies = fontFamilies;
-            this.fontFamilyBuilders = fontFamilyBuilders;
-            this.variant = variant;
-        }
-
-        @Override
-        public boolean hasNext() {
-            return index < (fontFamilies.length + fontFamilyBuilders.length);
-        }
-
-        @Override
-        @Nullable
-        public Font next() {
-            Font font;
-            FontVariant ffdVariant;
-            if (index < fontFamilies.length) {
-                FontFamily_Delegate ffd = fontFamilies[index++];
-                if (ffd == null || !ffd.isValid()) {
-                    return null;
-                }
-                font = ffd.getFont(weight, isItalic);
-                ffdVariant = ffd.getVariant();
-            } else {
-                FontFamily_Builder_Delegate ffd = fontFamilyBuilders[index++ - fontFamilies.length];
-                if (ffd == null) {
-                    return null;
-                }
-                font = ffd.getFont(weight, isItalic);
-                ffdVariant = ffd.getVariant();
-            }
-
-            if (font == null) {
-                // The FontFamily is valid but doesn't contain any matching font. This means
-                // that the font failed to load. We add null to the list of fonts. Don't throw
-                // the warning just yet. If this is a non-english font, we don't want to warn
-                // users who are trying to render only english text.
-                return null;
-            }
-
-            if (ffdVariant == FontVariant.NONE || ffdVariant == variant) {
-                return font;
-            }
-
-            // We cannot open each font and get locales supported, etc to match the fonts.
-            // As a workaround, we hardcode certain assumptions like Elegant and Compact
-            // always appear in pairs.
-            if (index < fontFamilies.length) {
-                assert index < fontFamilies.length - 1;
-                FontFamily_Delegate ffd2 = fontFamilies[index++];
-                assert ffd2 != null;
-
-                return ffd2.getFont(weight, isItalic);
-            } else {
-                assert index < fontFamilies.length + fontFamilyBuilders.length - 1;
-                FontFamily_Builder_Delegate ffd2 = fontFamilyBuilders[index++ - fontFamilies.length];
-                assert ffd2 != null;
-
-                return ffd2.getFont(weight, isItalic);
-            }
-        }
-
-        @NonNull
-        @Override
-        public Iterator<Font> iterator() {
-            return this;
-        }
-
-        @Override
-        public Spliterator<Font> spliterator() {
-            return Spliterators.spliterator(iterator(),
-                    fontFamilies.length + fontFamilyBuilders.length,
-                    Spliterator.IMMUTABLE | Spliterator.SIZED);
-        }
-    }
-}
+}
\ No newline at end of file
diff --git a/bridge/src/android/graphics/animation/NativeInterpolatorFactory_Delegate.java b/bridge/src/android/graphics/animation/NativeInterpolatorFactory_Delegate.java
deleted file mode 100644
index 38ad602..0000000
--- a/bridge/src/android/graphics/animation/NativeInterpolatorFactory_Delegate.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-package android.graphics.animation;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.Path;
-import android.util.MathUtils;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AnticipateInterpolator;
-import android.view.animation.AnticipateOvershootInterpolator;
-import android.view.animation.BaseInterpolator;
-import android.view.animation.BounceInterpolator;
-import android.view.animation.CycleInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.OvershootInterpolator;
-import android.view.animation.PathInterpolator;
-
-/**
- * Delegate used to provide new implementation of a select few methods of {@link
- * NativeInterpolatorFactory}
- * <p>
- * Through the layoutlib_create tool, the original  methods of NativeInterpolatorFactory have
- * been replaced by calls to methods of the same name in this delegate class.
- */
-@SuppressWarnings("unused")
-public class NativeInterpolatorFactory_Delegate {
-    private static final DelegateManager<Interpolator> sManager = new DelegateManager<>
-            (Interpolator.class);
-
-    public static Interpolator getDelegate(long nativePtr) {
-        return sManager.getDelegate(nativePtr);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long createAccelerateDecelerateInterpolator() {
-        return sManager.addNewDelegate(new AccelerateDecelerateInterpolator());
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long createAccelerateInterpolator(float factor) {
-        return sManager.addNewDelegate(new AccelerateInterpolator(factor));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long createAnticipateInterpolator(float tension) {
-        return sManager.addNewDelegate(new AnticipateInterpolator(tension));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long createAnticipateOvershootInterpolator(float tension) {
-        return sManager.addNewDelegate(new AnticipateOvershootInterpolator(tension));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long createBounceInterpolator() {
-        return sManager.addNewDelegate(new BounceInterpolator());
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long createCycleInterpolator(float cycles) {
-        return sManager.addNewDelegate(new CycleInterpolator(cycles));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long createDecelerateInterpolator(float factor) {
-        return sManager.addNewDelegate(new DecelerateInterpolator(factor));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long createLinearInterpolator() {
-        return sManager.addNewDelegate(new LinearInterpolator());
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long createOvershootInterpolator(float tension) {
-        return sManager.addNewDelegate(new OvershootInterpolator(tension));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long createPathInterpolator(float[] x, float[] y) {
-        Path path = new Path();
-        path.moveTo(x[0], y[0]);
-        for (int i = 1; i < x.length; i++) {
-            path.lineTo(x[i], y[i]);
-        }
-        return sManager.addNewDelegate(new PathInterpolator(path));
-    }
-
-    private static class LutInterpolator extends BaseInterpolator {
-        private final float[] mValues;
-        private final int mSize;
-
-        private LutInterpolator(float[] values) {
-            mValues = values;
-            mSize = mValues.length;
-        }
-
-        @Override
-        public float getInterpolation(float input) {
-            float lutpos = input * (mSize - 1);
-            if (lutpos >= (mSize - 1)) {
-                return mValues[mSize - 1];
-            }
-
-            int ipart = (int) lutpos;
-            float weight = lutpos - ipart;
-
-            int i1 = ipart;
-            int i2 = Math.min(i1 + 1, mSize - 1);
-
-            assert i1 >= 0 && i2 >= 0 : "Negatives in the interpolation";
-
-            return MathUtils.lerp(mValues[i1], mValues[i2], weight);
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long createLutInterpolator(float[] values) {
-        return sManager.addNewDelegate(new LutInterpolator(values));
-    }
-}
diff --git a/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java b/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java
index 9c272fa..92f4ab8 100644
--- a/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java
+++ b/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java
@@ -1,7 +1,7 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2019 The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License") {}
+ * 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
  *
@@ -16,283 +16,30 @@
 
 package android.graphics.drawable;
 
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.animation.NativeInterpolatorFactory_Delegate;
+import android.graphics.Canvas;
 import android.graphics.drawable.AnimatedVectorDrawable.VectorDrawableAnimatorRT;
-import android.graphics.drawable.VectorDrawable_Delegate.VFullPath_Delegate;
-import android.graphics.drawable.VectorDrawable_Delegate.VGroup_Delegate;
-import android.graphics.drawable.VectorDrawable_Delegate.VNativeObject;
-import android.graphics.drawable.VectorDrawable_Delegate.VPathRenderer_Delegate;
 
-import java.util.ArrayList;
-import java.util.function.Consumer;
-
-/**
- * Delegate used to provide new implementation of a select few methods of {@link
- * AnimatedVectorDrawable}
- * <p>
- * Through the layoutlib_create tool, the original  methods of AnimatedVectorDrawable have been
- * replaced by calls to methods of the same name in this delegate class.
- */
-@SuppressWarnings("unused")
 public class AnimatedVectorDrawable_Delegate {
-    private static DelegateManager<AnimatorSetHolder> sAnimatorSets = new
-            DelegateManager<>(AnimatorSetHolder.class);
-    private static DelegateManager<PropertySetter> sHolders = new
-            DelegateManager<>(PropertySetter.class);
-
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreateAnimatorSet() {
-        return sAnimatorSets.addNewDelegate(new AnimatorSetHolder());
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetVectorDrawableTarget(long animatorPtr, long vectorDrawablePtr) {
-        // TODO: implement
-    }
-    @LayoutlibDelegate
-    /*package*/ static void nAddAnimator(long setPtr, long propertyValuesHolder,
-            long nativeInterpolator, long startDelay, long duration, int repeatCount,
-            int repeatMode) {
-        PropertySetter holder = sHolders.getDelegate(propertyValuesHolder);
-        if (holder == null || holder.getValues() == null) {
-            return;
-        }
-
-        ObjectAnimator animator = new ObjectAnimator();
-        animator.setValues(holder.getValues());
-        animator.setInterpolator(
-                NativeInterpolatorFactory_Delegate.getDelegate(nativeInterpolator));
-        animator.setStartDelay(startDelay);
-        animator.setDuration(duration);
-        animator.setRepeatCount(repeatCount);
-        animator.setRepeatMode(repeatMode);
-        animator.setTarget(holder);
-        animator.setPropertyName(holder.getValues().getPropertyName());
-
-        AnimatorSetHolder set = sAnimatorSets.getDelegate(setPtr);
-        assert set != null;
-        set.addAnimator(animator);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreateGroupPropertyHolder(long nativePtr, int propertyId,
-            float startValue, float endValue) {
-        VGroup_Delegate group = VNativeObject.getDelegate(nativePtr);
-        Consumer<Float> setter = group.getPropertySetter(propertyId);
-
-        return sHolders.addNewDelegate(FloatPropertySetter.of(setter, startValue,
-                endValue));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreatePathDataPropertyHolder(long nativePtr, long startValuePtr,
-            long endValuePtr) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED, "AnimatedVectorDrawable path " +
-                "animations are not supported.", null, null, null);
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreatePathColorPropertyHolder(long nativePtr, int propertyId,
-            int startValue, int endValue) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(nativePtr);
-        Consumer<Integer> setter = path.getIntPropertySetter(propertyId);
-
-        return sHolders.addNewDelegate(IntPropertySetter.of(setter, startValue,
-                endValue));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreatePathPropertyHolder(long nativePtr, int propertyId,
-            float startValue, float endValue) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(nativePtr);
-        Consumer<Float> setter = path.getFloatPropertySetter(propertyId);
-
-        return sHolders.addNewDelegate(FloatPropertySetter.of(setter, startValue,
-                endValue));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
-            float endValue) {
-        VPathRenderer_Delegate renderer = VNativeObject.getDelegate(nativePtr);
-
-        return sHolders.addNewDelegate(FloatPropertySetter.of(renderer::setRootAlpha,
-                startValue,
-                endValue));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetPropertyHolderData(long nativePtr, float[] data, int length) {
-        PropertySetter setter = sHolders.getDelegate(nativePtr);
-        assert setter != null;
-
-        setter.setValues(data);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetPropertyHolderData(long nativePtr, int[] data, int length) {
-        PropertySetter setter = sHolders.getDelegate(nativePtr);
-        assert setter != null;
-
-        setter.setValues(data);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id) {
-        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
-        assert animatorSet != null;
-
-        animatorSet.start();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id) {
-        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
-        assert animatorSet != null;
-
-        animatorSet.reverse();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nEnd(long animatorSetPtr) {
-        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
-        assert animatorSet != null;
-
-        animatorSet.end();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nReset(long animatorSetPtr) {
-        AnimatorSetHolder animatorSet = sAnimatorSets.getDelegate(animatorSetPtr);
-        assert animatorSet != null;
-
-        animatorSet.end();
-        animatorSet.start();
-    }
-
-    private static class AnimatorSetHolder {
-        private ArrayList<Animator> mAnimators = new ArrayList<>();
-        private AnimatorSet mAnimatorSet = null;
-
-        private void addAnimator(@NonNull Animator animator) {
-            mAnimators.add(animator);
-        }
-
-        private void ensureAnimatorSet() {
-            if (mAnimatorSet == null) {
-                mAnimatorSet = new AnimatorSet();
-                mAnimatorSet.playTogether(mAnimators);
-            }
-        }
-
-        private void start() {
-            ensureAnimatorSet();
-
-            mAnimatorSet.start();
-        }
-
-        private void end() {
-            mAnimatorSet.end();
-        }
-
-        private void reset() {
-            end();
-            start();
-        }
-
-        private void reverse() {
-            mAnimatorSet.reverse();
-        }
-    }
 
     /**
-     * Class that allows setting a value and holds the range of values for the given property.
-     *
-     * @param <T> the type of the property
+     * We would like to do the same as in {@link AnimatedVectorDrawable#draw}, but bypass the
+     * {@link Canvas#isHardwareAccelerated} check and call
+     * {@link AnimatedVectorDrawable#forceAnimationOnUI}. We need this for the callbacks to be
+     * properly set up so that {@link AnimatedVectorDrawable} receives property updates.
+     * TODO (b/141682855): Figure out how to properly manage this in the hardware accelerated case
      */
-    private static class PropertySetter<T> {
-        final Consumer<T> mValueSetter;
-        private PropertyValuesHolder mValues;
-
-        private PropertySetter(@NonNull Consumer<T> valueSetter) {
-            mValueSetter = valueSetter;
+    @LayoutlibDelegate
+    static void draw(AnimatedVectorDrawable thisDrawable, Canvas canvas) {
+        if (thisDrawable.mAnimatorSet instanceof VectorDrawableAnimatorRT) {
+            // If we have SW canvas and the RT animation is waiting to start, We need to fallback
+            // to UI thread animation for AVD.
+            if (!thisDrawable.mAnimatorSet.isRunning() &&
+                    ((VectorDrawableAnimatorRT)thisDrawable.mAnimatorSet).mPendingAnimationActions.size() > 0) {
+                thisDrawable.forceAnimationOnUI();
+            }
         }
-
-        /**
-         * Method to set an {@link Integer} value for this property. The default implementation of
-         * this method doesn't do anything. This method is accessed via reflection by the
-         * PropertyValuesHolder.
-         */
-        public void setIntValue(Integer value) {
-        }
-
-        /**
-         * Method to set an {@link Integer} value for this property. The default implementation of
-         * this method doesn't do anything. This method is accessed via reflection by the
-         * PropertyValuesHolder.
-         */
-        public void setFloatValue(Float value) {
-        }
-
-        void setValues(float... values) {
-            mValues = PropertyValuesHolder.ofFloat("floatValue", values);
-        }
-
-        @Nullable
-        PropertyValuesHolder getValues() {
-            return mValues;
-        }
-
-        void setValues(int... values) {
-            mValues = PropertyValuesHolder.ofInt("intValue", values);
-        }
-    }
-
-    private static class IntPropertySetter extends PropertySetter<Integer> {
-        private IntPropertySetter(Consumer<Integer> valueSetter) {
-            super(valueSetter);
-        }
-
-        private static PropertySetter of(Consumer<Integer> valueSetter, int... values) {
-            PropertySetter setter = new IntPropertySetter(valueSetter);
-            setter.setValues(values);
-
-            return setter;
-        }
-
-        public void setIntValue(Integer value) {
-            mValueSetter.accept(value);
-        }
-    }
-
-    private static class FloatPropertySetter extends PropertySetter<Float> {
-        private FloatPropertySetter(Consumer<Float> valueSetter) {
-            super(valueSetter);
-        }
-
-        private static PropertySetter of(Consumer<Float> valueSetter, float... values) {
-            PropertySetter setter = new FloatPropertySetter(valueSetter);
-            setter.setValues(values);
-
-            return setter;
-        }
-
-        public void setFloatValue(Float value) {
-            mValueSetter.accept(value);
-        }
-
+        thisDrawable.draw_Original(canvas);
     }
 }
diff --git a/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java b/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java
deleted file mode 100644
index fc848d9..0000000
--- a/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-package android.graphics.drawable;
-
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.Canvas;
-import android.graphics.drawable.AnimatedVectorDrawable.VectorDrawableAnimatorRT;
-
-public class AnimatedVectorDrawable_VectorDrawableAnimatorRT_Delegate {
-    @LayoutlibDelegate
-    /*package*/ static boolean useLastSeenTarget(VectorDrawableAnimatorRT thisDrawableAnimator) {
-        return true;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void onDraw(VectorDrawableAnimatorRT thisDrawableAnimator, Canvas canvas) {
-        // Do not attempt to record as we are not using a DisplayListCanvas
-    }
-}
diff --git a/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorUI_Delegate.java b/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorUI_Delegate.java
new file mode 100644
index 0000000..b21b372
--- /dev/null
+++ b/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_VectorDrawableAnimatorUI_Delegate.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package android.graphics.drawable;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.animation.AnimationHandler;
+import android.graphics.Canvas;
+import android.graphics.drawable.AnimatedVectorDrawable.VectorDrawableAnimatorUI;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link
+ * AnimatedVectorDrawable}
+ * <p>
+ * Through the layoutlib_create tool, the original  methods of AnimatedVectorDrawable have been
+ * replaced by calls to methods of the same name in this delegate class.
+ */
+@SuppressWarnings("unused")
+public class AnimatedVectorDrawable_VectorDrawableAnimatorUI_Delegate {
+
+    public static long sFrameTime;
+
+    @LayoutlibDelegate
+    /*package*/ static void onDraw(VectorDrawableAnimatorUI thisDrawableAnimator, Canvas canvas) {
+        thisDrawableAnimator.onDraw_Original(canvas);
+        AnimationHandler handler = AnimationHandler.getInstance();
+        if (thisDrawableAnimator.mSet.mLastFrameTime < 0) {
+            handler.doAnimationFrame(0);
+        }
+        handler.doAnimationFrame(sFrameTime);
+    }
+}
diff --git a/bridge/src/android/graphics/drawable/GradientDrawable_Delegate.java b/bridge/src/android/graphics/drawable/GradientDrawable_Delegate.java
deleted file mode 100644
index a3ad2aa..0000000
--- a/bridge/src/android/graphics/drawable/GradientDrawable_Delegate.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-package android.graphics.drawable;
-
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.Path;
-import android.graphics.drawable.GradientDrawable.GradientState;
-
-import java.lang.reflect.Field;
-
-/**
- * Delegate implementing the native methods of {@link GradientDrawable}
- *
- * Through the layoutlib_create tool, the original native methods of GradientDrawable have been
- * replaced by calls to methods of the same name in this delegate class.
- */
-public class GradientDrawable_Delegate {
-
-    /**
-     * The ring can be built either by drawing full circles, or by drawing arcs in case the
-     * circle isn't complete. LayoutLib cannot handle drawing full circles (requires path
-     * subtraction). So, if we need to draw full circles, we switch to drawing 99% circle.
-     */
-    @LayoutlibDelegate
-    /*package*/ static Path buildRing(GradientDrawable thisDrawable, GradientState st) {
-        boolean useLevel = st.mUseLevelForShape;
-        int level = thisDrawable.getLevel();
-        // 10000 is the max level. See android.graphics.drawable.Drawable#getLevel()
-        float sweep = useLevel ? (360.0f * level / 10000.0f) : 360f;
-        Field mLevel = null;
-        if (sweep >= 360 || sweep <= -360) {
-            st.mUseLevelForShape = true;
-            // Use reflection to set the value of the field to prevent setting the drawable to
-            // dirty again.
-            try {
-                mLevel = Drawable.class.getDeclaredField("mLevel");
-                mLevel.setAccessible(true);
-                mLevel.setInt(thisDrawable, 9999);  // set to one less than max.
-            } catch (NoSuchFieldException e) {
-                // The field has been removed in a recent framework change. Fall back to old
-                // buggy behaviour.
-            } catch (IllegalAccessException e) {
-                // We've already set the field to be accessible.
-                assert false;
-            }
-        }
-        Path path = thisDrawable.buildRing_Original(st);
-        st.mUseLevelForShape = useLevel;
-        if (mLevel != null) {
-            try {
-                mLevel.setInt(thisDrawable, level);
-            } catch (IllegalAccessException e) {
-                assert false;
-            }
-        }
-        return path;
-    }
-}
diff --git a/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
deleted file mode 100644
index 828df6b..0000000
--- a/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
+++ /dev/null
@@ -1,1299 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-package android.graphics.drawable;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.NonNull;
-import android.content.res.Resources;
-import android.content.res.Resources.Theme;
-import android.content.res.TypedArray;
-import android.graphics.BaseCanvas_Delegate;
-import android.graphics.Canvas_Delegate;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Paint.Cap;
-import android.graphics.Paint.Join;
-import android.graphics.Paint_Delegate;
-import android.graphics.Path;
-import android.graphics.Path.FillType;
-import android.graphics.PathMeasure;
-import android.graphics.Path_Delegate;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.Region.Op;
-import android.graphics.Shader_Delegate;
-import android.util.ArrayMap;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.MathUtils;
-import android.util.PathParser_Delegate;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-import java.util.ArrayList;
-import java.util.function.Consumer;
-
-import static android.graphics.Canvas.CLIP_SAVE_FLAG;
-import static android.graphics.Canvas.MATRIX_SAVE_FLAG;
-import static android.graphics.Paint.Cap.BUTT;
-import static android.graphics.Paint.Cap.ROUND;
-import static android.graphics.Paint.Cap.SQUARE;
-import static android.graphics.Paint.Join.BEVEL;
-import static android.graphics.Paint.Join.MITER;
-import static android.graphics.Paint.Style;
-
-/**
- * Delegate used to provide new implementation of a select few methods of {@link VectorDrawable}
- * <p>
- * Through the layoutlib_create tool, the original  methods of VectorDrawable have been replaced by
- * calls to methods of the same name in this delegate class.
- */
-@SuppressWarnings("unused")
-public class VectorDrawable_Delegate {
-    private static final String LOGTAG = VectorDrawable_Delegate.class.getSimpleName();
-    private static final boolean DBG_VECTOR_DRAWABLE = false;
-
-    private static final DelegateManager<VNativeObject> sPathManager =
-            new DelegateManager<>(VNativeObject.class);
-
-    private static long addNativeObject(VNativeObject object) {
-        long ptr = sPathManager.addNewDelegate(object);
-        object.setNativePtr(ptr);
-
-        return ptr;
-    }
-
-    /**
-     * Obtains styled attributes from the theme, if available, or unstyled resources if the theme is
-     * null.
-     */
-    private static TypedArray obtainAttributes(
-            Resources res, Theme theme, AttributeSet set, int[] attrs) {
-        if (theme == null) {
-            return res.obtainAttributes(set, attrs);
-        }
-        return theme.obtainStyledAttributes(set, attrs, 0, 0);
-    }
-
-    private static int applyAlpha(int color, float alpha) {
-        int alphaBytes = Color.alpha(color);
-        color &= 0x00FFFFFF;
-        color |= ((int) (alphaBytes * alpha)) << 24;
-        return color;
-    }
-
-    @LayoutlibDelegate
-    static long nCreateTree(long rootGroupPtr) {
-        return addNativeObject(new VPathRenderer_Delegate(rootGroupPtr));
-    }
-
-    @LayoutlibDelegate
-    static long nCreateTreeFromCopy(long rendererToCopyPtr, long rootGroupPtr) {
-        VPathRenderer_Delegate rendererToCopy = VNativeObject.getDelegate(rendererToCopyPtr);
-        return addNativeObject(new VPathRenderer_Delegate(rendererToCopy,
-                rootGroupPtr));
-    }
-
-    @LayoutlibDelegate
-    static void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
-            float viewportHeight) {
-        VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
-        nativePathRenderer.mViewportWidth = viewportWidth;
-        nativePathRenderer.mViewportHeight = viewportHeight;
-    }
-
-    @LayoutlibDelegate
-    static boolean nSetRootAlpha(long rendererPtr, float alpha) {
-        VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
-        nativePathRenderer.setRootAlpha(alpha);
-
-        return true;
-    }
-
-    @LayoutlibDelegate
-    static float nGetRootAlpha(long rendererPtr) {
-        VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
-
-        return nativePathRenderer.getRootAlpha();
-    }
-
-    @LayoutlibDelegate
-    static void nSetAntiAlias(long rendererPtr, boolean aa) {
-        VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
-        nativePathRenderer.setAntiAlias(aa);
-    }
-
-    @LayoutlibDelegate
-    static void nSetAllowCaching(long rendererPtr, boolean allowCaching) {
-        // ignored
-    }
-
-    @LayoutlibDelegate
-    static int nDraw(long rendererPtr, long canvasWrapperPtr,
-            long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache) {
-        VPathRenderer_Delegate nativePathRenderer = VNativeObject.getDelegate(rendererPtr);
-
-        Canvas_Delegate.nSave(canvasWrapperPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
-        Canvas_Delegate.nClipRect(canvasWrapperPtr,
-                bounds.left, bounds.top, bounds.right, bounds.bottom,
-                Region.Op.INTERSECT.nativeInt);
-        Canvas_Delegate.nTranslate(canvasWrapperPtr, bounds.left, bounds.top);
-
-        if (needsMirroring) {
-            Canvas_Delegate.nTranslate(canvasWrapperPtr, bounds.width(), 0);
-            Canvas_Delegate.nScale(canvasWrapperPtr, -1.0f, 1.0f);
-        }
-
-        // At this point, canvas has been translated to the right position.
-        // And we use this bound for the destination rect for the drawBitmap, so
-        // we offset to (0, 0);
-        bounds.offsetTo(0, 0);
-        nativePathRenderer.draw(canvasWrapperPtr, colorFilterPtr, bounds.width(), bounds.height());
-
-        Canvas_Delegate.nRestore(canvasWrapperPtr);
-
-        return bounds.width() * bounds.height();
-    }
-
-    @LayoutlibDelegate
-    static long nCreateFullPath() {
-        return addNativeObject(new VFullPath_Delegate());
-    }
-
-    @LayoutlibDelegate
-    static long nCreateFullPath(long nativeFullPathPtr) {
-        VFullPath_Delegate original = VNativeObject.getDelegate(nativeFullPathPtr);
-        return addNativeObject(new VFullPath_Delegate(original));
-    }
-
-    @LayoutlibDelegate
-    static boolean nGetFullPathProperties(long pathPtr, byte[] propertiesData,
-            int length) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-
-        ByteBuffer properties = ByteBuffer.wrap(propertiesData);
-        properties.order(ByteOrder.nativeOrder());
-
-        properties.putFloat(VFullPath_Delegate.STROKE_WIDTH_INDEX * 4, path.getStrokeWidth());
-        properties.putInt(VFullPath_Delegate.STROKE_COLOR_INDEX * 4, path.getStrokeColor());
-        properties.putFloat(VFullPath_Delegate.STROKE_ALPHA_INDEX * 4, path.getStrokeAlpha());
-        properties.putInt(VFullPath_Delegate.FILL_COLOR_INDEX * 4, path.getFillColor());
-        properties.putFloat(VFullPath_Delegate.FILL_ALPHA_INDEX * 4, path.getStrokeAlpha());
-        properties.putFloat(VFullPath_Delegate.TRIM_PATH_START_INDEX * 4, path.getTrimPathStart());
-        properties.putFloat(VFullPath_Delegate.TRIM_PATH_END_INDEX * 4, path.getTrimPathEnd());
-        properties.putFloat(VFullPath_Delegate.TRIM_PATH_OFFSET_INDEX * 4,
-                path.getTrimPathOffset());
-        properties.putInt(VFullPath_Delegate.STROKE_LINE_CAP_INDEX * 4, path.getStrokeLineCap());
-        properties.putInt(VFullPath_Delegate.STROKE_LINE_JOIN_INDEX * 4, path.getStrokeLineJoin());
-        properties.putFloat(VFullPath_Delegate.STROKE_MITER_LIMIT_INDEX * 4,
-                path.getStrokeMiterlimit());
-        properties.putInt(VFullPath_Delegate.FILL_TYPE_INDEX * 4, path.getFillType());
-
-        return true;
-    }
-
-    @LayoutlibDelegate
-    static void nUpdateFullPathProperties(long pathPtr, float strokeWidth,
-            int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
-            float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
-            int strokeLineJoin, int fillType) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-
-        path.setStrokeWidth(strokeWidth);
-        path.setStrokeColor(strokeColor);
-        path.setStrokeAlpha(strokeAlpha);
-        path.setFillColor(fillColor);
-        path.setFillAlpha(fillAlpha);
-        path.setTrimPathStart(trimPathStart);
-        path.setTrimPathEnd(trimPathEnd);
-        path.setTrimPathOffset(trimPathOffset);
-        path.setStrokeMiterlimit(strokeMiterLimit);
-        path.setStrokeLineCap(strokeLineCap);
-        path.setStrokeLineJoin(strokeLineJoin);
-        path.setFillType(fillType);
-    }
-
-    @LayoutlibDelegate
-    static void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-
-        path.setFillGradient(fillGradientPtr);
-    }
-
-    @LayoutlibDelegate
-    static void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-
-        path.setStrokeGradient(strokeGradientPtr);
-    }
-
-    @LayoutlibDelegate
-    static long nCreateClipPath() {
-        return addNativeObject(new VClipPath_Delegate());
-    }
-
-    @LayoutlibDelegate
-    static long nCreateClipPath(long clipPathPtr) {
-        VClipPath_Delegate original = VNativeObject.getDelegate(clipPathPtr);
-        return addNativeObject(new VClipPath_Delegate(original));
-    }
-
-    @LayoutlibDelegate
-    static long nCreateGroup() {
-        return addNativeObject(new VGroup_Delegate());
-    }
-
-    @LayoutlibDelegate
-    static long nCreateGroup(long groupPtr) {
-        VGroup_Delegate original = VNativeObject.getDelegate(groupPtr);
-        return addNativeObject(new VGroup_Delegate(original, new ArrayMap<>()));
-    }
-
-    @LayoutlibDelegate
-    static void nSetName(long nodePtr, String name) {
-        VNativeObject group = VNativeObject.getDelegate(nodePtr);
-        group.setName(name);
-    }
-
-    @LayoutlibDelegate
-    static boolean nGetGroupProperties(long groupPtr, float[] propertiesData,
-            int length) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-
-        FloatBuffer properties = FloatBuffer.wrap(propertiesData);
-
-        properties.put(VGroup_Delegate.ROTATE_INDEX, group.getRotation());
-        properties.put(VGroup_Delegate.PIVOT_X_INDEX, group.getPivotX());
-        properties.put(VGroup_Delegate.PIVOT_Y_INDEX, group.getPivotY());
-        properties.put(VGroup_Delegate.SCALE_X_INDEX, group.getScaleX());
-        properties.put(VGroup_Delegate.SCALE_Y_INDEX, group.getScaleY());
-        properties.put(VGroup_Delegate.TRANSLATE_X_INDEX, group.getTranslateX());
-        properties.put(VGroup_Delegate.TRANSLATE_Y_INDEX, group.getTranslateY());
-
-        return true;
-    }
-    @LayoutlibDelegate
-    static void nUpdateGroupProperties(long groupPtr, float rotate, float pivotX,
-            float pivotY, float scaleX, float scaleY, float translateX, float translateY) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-
-        group.setRotation(rotate);
-        group.setPivotX(pivotX);
-        group.setPivotY(pivotY);
-        group.setScaleX(scaleX);
-        group.setScaleY(scaleY);
-        group.setTranslateX(translateX);
-        group.setTranslateY(translateY);
-    }
-
-    @LayoutlibDelegate
-    static void nAddChild(long groupPtr, long nodePtr) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        group.mChildren.add(VNativeObject.getDelegate(nodePtr));
-    }
-
-    @LayoutlibDelegate
-    static void nSetPathString(long pathPtr, String pathString, int length) {
-        VPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        path.setPathData(PathParser_Delegate.createNodesFromPathData(pathString));
-    }
-
-    /**
-     * The setters and getters below for paths and groups are here temporarily, and will be removed
-     * once the animation in AVD is replaced with RenderNodeAnimator, in which case the animation
-     * will modify these properties in native. By then no JNI hopping would be necessary for VD
-     * during animation, and these setters and getters will be obsolete.
-     */
-    // Setters and getters during animation.
-    @LayoutlibDelegate
-    static float nGetRotation(long groupPtr) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        return group.getRotation();
-    }
-
-    @LayoutlibDelegate
-    static void nSetRotation(long groupPtr, float rotation) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        group.setRotation(rotation);
-    }
-
-    @LayoutlibDelegate
-    static float nGetPivotX(long groupPtr) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        return group.getPivotX();
-    }
-
-    @LayoutlibDelegate
-    static void nSetPivotX(long groupPtr, float pivotX) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        group.setPivotX(pivotX);
-    }
-
-    @LayoutlibDelegate
-    static float nGetPivotY(long groupPtr) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        return group.getPivotY();
-    }
-
-    @LayoutlibDelegate
-    static void nSetPivotY(long groupPtr, float pivotY) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        group.setPivotY(pivotY);
-    }
-
-    @LayoutlibDelegate
-    static float nGetScaleX(long groupPtr) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        return group.getScaleX();
-    }
-
-    @LayoutlibDelegate
-    static void nSetScaleX(long groupPtr, float scaleX) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        group.setScaleX(scaleX);
-    }
-
-    @LayoutlibDelegate
-    static float nGetScaleY(long groupPtr) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        return group.getScaleY();
-    }
-
-    @LayoutlibDelegate
-    static void nSetScaleY(long groupPtr, float scaleY) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        group.setScaleY(scaleY);
-    }
-
-    @LayoutlibDelegate
-    static float nGetTranslateX(long groupPtr) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        return group.getTranslateX();
-    }
-
-    @LayoutlibDelegate
-    static void nSetTranslateX(long groupPtr, float translateX) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        group.setTranslateX(translateX);
-    }
-
-    @LayoutlibDelegate
-    static float nGetTranslateY(long groupPtr) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        return group.getTranslateY();
-    }
-
-    @LayoutlibDelegate
-    static void nSetTranslateY(long groupPtr, float translateY) {
-        VGroup_Delegate group = VNativeObject.getDelegate(groupPtr);
-        group.setTranslateY(translateY);
-    }
-
-    @LayoutlibDelegate
-    static void nSetPathData(long pathPtr, long pathDataPtr) {
-        VPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        path.setPathData(PathParser_Delegate.getDelegate(pathDataPtr).getPathDataNodes());
-    }
-
-    @LayoutlibDelegate
-    static float nGetStrokeWidth(long pathPtr) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        return path.getStrokeWidth();
-    }
-
-    @LayoutlibDelegate
-    static void nSetStrokeWidth(long pathPtr, float width) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        path.setStrokeWidth(width);
-    }
-
-    @LayoutlibDelegate
-    static int nGetStrokeColor(long pathPtr) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        return path.getStrokeColor();
-    }
-
-    @LayoutlibDelegate
-    static void nSetStrokeColor(long pathPtr, int strokeColor) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        path.setStrokeColor(strokeColor);
-    }
-
-    @LayoutlibDelegate
-    static float nGetStrokeAlpha(long pathPtr) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        return path.getStrokeAlpha();
-    }
-
-    @LayoutlibDelegate
-    static void nSetStrokeAlpha(long pathPtr, float alpha) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        path.setStrokeAlpha(alpha);
-    }
-
-    @LayoutlibDelegate
-    static int nGetFillColor(long pathPtr) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        return path.getFillColor();
-    }
-
-    @LayoutlibDelegate
-    static void nSetFillColor(long pathPtr, int fillColor) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        path.setFillColor(fillColor);
-    }
-
-    @LayoutlibDelegate
-    static float nGetFillAlpha(long pathPtr) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        return path.getFillAlpha();
-    }
-
-    @LayoutlibDelegate
-    static void nSetFillAlpha(long pathPtr, float fillAlpha) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        path.setFillAlpha(fillAlpha);
-    }
-
-    @LayoutlibDelegate
-    static float nGetTrimPathStart(long pathPtr) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        return path.getTrimPathStart();
-    }
-
-    @LayoutlibDelegate
-    static void nSetTrimPathStart(long pathPtr, float trimPathStart) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        path.setTrimPathStart(trimPathStart);
-    }
-
-    @LayoutlibDelegate
-    static float nGetTrimPathEnd(long pathPtr) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        return path.getTrimPathEnd();
-    }
-
-    @LayoutlibDelegate
-    static void nSetTrimPathEnd(long pathPtr, float trimPathEnd) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        path.setTrimPathEnd(trimPathEnd);
-    }
-
-    @LayoutlibDelegate
-    static float nGetTrimPathOffset(long pathPtr) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        return path.getTrimPathOffset();
-    }
-
-    @LayoutlibDelegate
-    static void nSetTrimPathOffset(long pathPtr, float trimPathOffset) {
-        VFullPath_Delegate path = VNativeObject.getDelegate(pathPtr);
-        path.setTrimPathOffset(trimPathOffset);
-    }
-
-    /**
-     * Base class for all the internal Delegates that does two functions:
-     * <ol>
-     *     <li>Serves as base class to store all the delegates in one {@link DelegateManager}
-     *     <li>Provides setName for all the classes. {@link VPathRenderer_Delegate} does actually
-     *     not need it
-     * </ol>
-     */
-    abstract static class VNativeObject {
-        long mNativePtr = 0;
-
-        @NonNull
-        static <T> T getDelegate(long nativePtr) {
-            //noinspection unchecked
-            T vNativeObject = (T) sPathManager.getDelegate(nativePtr);
-
-            assert vNativeObject != null;
-            return vNativeObject;
-        }
-
-        abstract void setName(String name);
-
-        void setNativePtr(long nativePtr) {
-            mNativePtr = nativePtr;
-        }
-
-        /**
-         * Method to explicitly dispose native objects
-         */
-        void dispose() {
-        }
-    }
-
-    private static class VClipPath_Delegate extends VPath_Delegate {
-        private VClipPath_Delegate() {
-            // Empty constructor.
-        }
-
-        private VClipPath_Delegate(VClipPath_Delegate copy) {
-            super(copy);
-        }
-
-        @Override
-        public boolean isClipPath() {
-            return true;
-        }
-    }
-
-    static class VFullPath_Delegate extends VPath_Delegate {
-        // These constants need to be kept in sync with their values in VectorDrawable.VFullPath
-        private static final int STROKE_WIDTH_INDEX = 0;
-        private static final int STROKE_COLOR_INDEX = 1;
-        private static final int STROKE_ALPHA_INDEX = 2;
-        private static final int FILL_COLOR_INDEX = 3;
-        private static final int FILL_ALPHA_INDEX = 4;
-        private static final int TRIM_PATH_START_INDEX = 5;
-        private static final int TRIM_PATH_END_INDEX = 6;
-        private static final int TRIM_PATH_OFFSET_INDEX = 7;
-        private static final int STROKE_LINE_CAP_INDEX = 8;
-        private static final int STROKE_LINE_JOIN_INDEX = 9;
-        private static final int STROKE_MITER_LIMIT_INDEX = 10;
-        private static final int FILL_TYPE_INDEX = 11;
-
-        private static final int LINECAP_BUTT = 0;
-        private static final int LINECAP_ROUND = 1;
-        private static final int LINECAP_SQUARE = 2;
-
-        private static final int LINEJOIN_MITER = 0;
-        private static final int LINEJOIN_ROUND = 1;
-        private static final int LINEJOIN_BEVEL = 2;
-
-        @NonNull
-        public Consumer<Float> getFloatPropertySetter(int propertyIdx) {
-            switch (propertyIdx) {
-                case STROKE_WIDTH_INDEX:
-                    return this::setStrokeWidth;
-                case STROKE_ALPHA_INDEX:
-                    return this::setStrokeAlpha;
-                case FILL_ALPHA_INDEX:
-                    return this::setFillAlpha;
-                case TRIM_PATH_START_INDEX:
-                    return this::setTrimPathStart;
-                case TRIM_PATH_END_INDEX:
-                    return this::setTrimPathEnd;
-                case TRIM_PATH_OFFSET_INDEX:
-                    return this::setTrimPathOffset;
-            }
-
-            assert false : ("Invalid VFullPath_Delegate property index " + propertyIdx);
-            return t -> {};
-        }
-
-        @NonNull
-        public Consumer<Integer> getIntPropertySetter(int propertyIdx) {
-            switch (propertyIdx) {
-                case STROKE_COLOR_INDEX:
-                    return this::setStrokeColor;
-                case FILL_COLOR_INDEX:
-                    return this::setFillColor;
-            }
-
-            assert false : ("Invalid VFullPath_Delegate property index " + propertyIdx);
-            return t -> {};
-        }
-
-        /////////////////////////////////////////////////////
-        // Variables below need to be copied (deep copy if applicable) for mutation.
-
-        int mStrokeColor = Color.TRANSPARENT;
-        float mStrokeWidth = 0;
-
-        int mFillColor = Color.TRANSPARENT;
-        long mStrokeGradient = 0;
-        long mFillGradient = 0;
-        float mStrokeAlpha = 1.0f;
-        float mFillAlpha = 1.0f;
-        float mTrimPathStart = 0;
-        float mTrimPathEnd = 1;
-        float mTrimPathOffset = 0;
-
-        Cap mStrokeLineCap = BUTT;
-        Join mStrokeLineJoin = MITER;
-        float mStrokeMiterlimit = 4;
-
-        int mFillType = 0; // WINDING(0) is the default value. See Path.FillType
-
-        private VFullPath_Delegate() {
-            // Empty constructor.
-        }
-
-        private VFullPath_Delegate(VFullPath_Delegate copy) {
-            super(copy);
-
-            mStrokeColor = copy.mStrokeColor;
-            mStrokeWidth = copy.mStrokeWidth;
-            mStrokeAlpha = copy.mStrokeAlpha;
-            mFillColor = copy.mFillColor;
-            mFillAlpha = copy.mFillAlpha;
-            mTrimPathStart = copy.mTrimPathStart;
-            mTrimPathEnd = copy.mTrimPathEnd;
-            mTrimPathOffset = copy.mTrimPathOffset;
-
-            mStrokeLineCap = copy.mStrokeLineCap;
-            mStrokeLineJoin = copy.mStrokeLineJoin;
-            mStrokeMiterlimit = copy.mStrokeMiterlimit;
-
-            mStrokeGradient = copy.mStrokeGradient;
-            mFillGradient = copy.mFillGradient;
-            mFillType = copy.mFillType;
-        }
-
-        private int getStrokeLineCap() {
-            switch (mStrokeLineCap) {
-                case BUTT:
-                    return LINECAP_BUTT;
-                case ROUND:
-                    return LINECAP_ROUND;
-                case SQUARE:
-                    return LINECAP_SQUARE;
-                default:
-                    assert false;
-            }
-
-            return -1;
-        }
-
-        private void setStrokeLineCap(int cap) {
-            switch (cap) {
-                case LINECAP_BUTT:
-                    mStrokeLineCap = BUTT;
-                    break;
-                case LINECAP_ROUND:
-                    mStrokeLineCap = ROUND;
-                    break;
-                case LINECAP_SQUARE:
-                    mStrokeLineCap = SQUARE;
-                    break;
-                default:
-                    assert false;
-            }
-        }
-
-        private int getStrokeLineJoin() {
-            switch (mStrokeLineJoin) {
-                case MITER:
-                    return LINEJOIN_MITER;
-                case ROUND:
-                    return LINEJOIN_ROUND;
-                case BEVEL:
-                    return LINEJOIN_BEVEL;
-                default:
-                    assert false;
-            }
-
-            return -1;
-        }
-
-        private void setStrokeLineJoin(int join) {
-            switch (join) {
-                case LINEJOIN_BEVEL:
-                    mStrokeLineJoin = BEVEL;
-                    break;
-                case LINEJOIN_MITER:
-                    mStrokeLineJoin = MITER;
-                    break;
-                case LINEJOIN_ROUND:
-                    mStrokeLineJoin = Join.ROUND;
-                    break;
-                default:
-                    assert false;
-            }
-        }
-
-        private int getStrokeColor() {
-            return mStrokeColor;
-        }
-
-        private void setStrokeColor(int strokeColor) {
-            mStrokeColor = strokeColor;
-        }
-
-        private float getStrokeWidth() {
-            return mStrokeWidth;
-        }
-
-        private void setStrokeWidth(float strokeWidth) {
-            mStrokeWidth = strokeWidth;
-        }
-
-        private float getStrokeAlpha() {
-            return mStrokeAlpha;
-        }
-
-        private void setStrokeAlpha(float strokeAlpha) {
-            mStrokeAlpha = strokeAlpha;
-        }
-
-        private int getFillColor() {
-            return mFillColor;
-        }
-
-        private void setFillColor(int fillColor) {
-            mFillColor = fillColor;
-        }
-
-        private float getFillAlpha() {
-            return mFillAlpha;
-        }
-
-        private void setFillAlpha(float fillAlpha) {
-            mFillAlpha = fillAlpha;
-        }
-
-        private float getTrimPathStart() {
-            return mTrimPathStart;
-        }
-
-        private void setTrimPathStart(float trimPathStart) {
-            mTrimPathStart = trimPathStart;
-        }
-
-        private float getTrimPathEnd() {
-            return mTrimPathEnd;
-        }
-
-        private void setTrimPathEnd(float trimPathEnd) {
-            mTrimPathEnd = trimPathEnd;
-        }
-
-        private float getTrimPathOffset() {
-            return mTrimPathOffset;
-        }
-
-        private void setTrimPathOffset(float trimPathOffset) {
-            mTrimPathOffset = trimPathOffset;
-        }
-
-        private void setStrokeMiterlimit(float limit) {
-            mStrokeMiterlimit = limit;
-        }
-
-        private float getStrokeMiterlimit() {
-            return mStrokeMiterlimit;
-        }
-
-        private void setStrokeGradient(long gradientPtr) {
-            mStrokeGradient = gradientPtr;
-        }
-
-        private void setFillGradient(long gradientPtr) {
-            mFillGradient = gradientPtr;
-        }
-
-        private void setFillType(int fillType) {
-            mFillType = fillType;
-        }
-
-        private int getFillType() {
-            return mFillType;
-        }
-    }
-
-    static class VGroup_Delegate extends VNativeObject {
-        // This constants need to be kept in sync with their definitions in VectorDrawable.Group
-        private static final int ROTATE_INDEX = 0;
-        private static final int PIVOT_X_INDEX = 1;
-        private static final int PIVOT_Y_INDEX = 2;
-        private static final int SCALE_X_INDEX = 3;
-        private static final int SCALE_Y_INDEX = 4;
-        private static final int TRANSLATE_X_INDEX = 5;
-        private static final int TRANSLATE_Y_INDEX = 6;
-
-        public Consumer<Float> getPropertySetter(int propertyIdx) {
-            switch (propertyIdx) {
-                case ROTATE_INDEX:
-                    return this::setRotation;
-                case PIVOT_X_INDEX:
-                    return this::setPivotX;
-                case PIVOT_Y_INDEX:
-                    return this::setPivotY;
-                case SCALE_X_INDEX:
-                    return this::setScaleX;
-                case SCALE_Y_INDEX:
-                    return this::setScaleY;
-                case TRANSLATE_X_INDEX:
-                    return this::setTranslateX;
-                case TRANSLATE_Y_INDEX:
-                    return this::setTranslateY;
-            }
-
-            assert false : ("Invalid VGroup_Delegate property index " + propertyIdx);
-            return t -> {};
-        }
-
-        /////////////////////////////////////////////////////
-        // Variables below need to be copied (deep copy if applicable) for mutation.
-        final ArrayList<Object> mChildren = new ArrayList<>();
-        // mStackedMatrix is only used temporarily when drawing, it combines all
-        // the parents' local matrices with the current one.
-        private final Matrix mStackedMatrix = new Matrix();
-        // mLocalMatrix is updated based on the update of transformation information,
-        // either parsed from the XML or by animation.
-        private final Matrix mLocalMatrix = new Matrix();
-        private float mRotate = 0;
-        private float mPivotX = 0;
-        private float mPivotY = 0;
-        private float mScaleX = 1;
-        private float mScaleY = 1;
-        private float mTranslateX = 0;
-        private float mTranslateY = 0;
-        private int mChangingConfigurations;
-        private String mGroupName = null;
-
-        private VGroup_Delegate(VGroup_Delegate copy, ArrayMap<String, Object> targetsMap) {
-            mRotate = copy.mRotate;
-            mPivotX = copy.mPivotX;
-            mPivotY = copy.mPivotY;
-            mScaleX = copy.mScaleX;
-            mScaleY = copy.mScaleY;
-            mTranslateX = copy.mTranslateX;
-            mTranslateY = copy.mTranslateY;
-            mGroupName = copy.mGroupName;
-            mChangingConfigurations = copy.mChangingConfigurations;
-            if (mGroupName != null) {
-                targetsMap.put(mGroupName, this);
-            }
-
-            mLocalMatrix.set(copy.mLocalMatrix);
-        }
-
-        private VGroup_Delegate() {
-        }
-
-        private void updateLocalMatrix() {
-            // The order we apply is the same as the
-            // RenderNode.cpp::applyViewPropertyTransforms().
-            mLocalMatrix.reset();
-            mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
-            mLocalMatrix.postScale(mScaleX, mScaleY);
-            mLocalMatrix.postRotate(mRotate, 0, 0);
-            mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
-        }
-
-        /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
-        private float getRotation() {
-            return mRotate;
-        }
-
-        private void setRotation(float rotation) {
-            if (rotation != mRotate) {
-                mRotate = rotation;
-                updateLocalMatrix();
-            }
-        }
-
-        private float getPivotX() {
-            return mPivotX;
-        }
-
-        private void setPivotX(float pivotX) {
-            if (pivotX != mPivotX) {
-                mPivotX = pivotX;
-                updateLocalMatrix();
-            }
-        }
-
-        private float getPivotY() {
-            return mPivotY;
-        }
-
-        private void setPivotY(float pivotY) {
-            if (pivotY != mPivotY) {
-                mPivotY = pivotY;
-                updateLocalMatrix();
-            }
-        }
-
-        private float getScaleX() {
-            return mScaleX;
-        }
-
-        private void setScaleX(float scaleX) {
-            if (scaleX != mScaleX) {
-                mScaleX = scaleX;
-                updateLocalMatrix();
-            }
-        }
-
-        private float getScaleY() {
-            return mScaleY;
-        }
-
-        private void setScaleY(float scaleY) {
-            if (scaleY != mScaleY) {
-                mScaleY = scaleY;
-                updateLocalMatrix();
-            }
-        }
-
-        private float getTranslateX() {
-            return mTranslateX;
-        }
-
-        private void setTranslateX(float translateX) {
-            if (translateX != mTranslateX) {
-                mTranslateX = translateX;
-                updateLocalMatrix();
-            }
-        }
-
-        private float getTranslateY() {
-            return mTranslateY;
-        }
-
-        private void setTranslateY(float translateY) {
-            if (translateY != mTranslateY) {
-                mTranslateY = translateY;
-                updateLocalMatrix();
-            }
-        }
-
-        @Override
-        public void setName(String name) {
-            mGroupName = name;
-        }
-
-        @Override
-        protected void dispose() {
-            mChildren.stream().filter(child -> child instanceof VNativeObject).forEach(child
-                    -> {
-                VNativeObject nativeObject = (VNativeObject) child;
-                if (nativeObject.mNativePtr != 0) {
-                    sPathManager.removeJavaReferenceFor(nativeObject.mNativePtr);
-                    nativeObject.mNativePtr = 0;
-                }
-                nativeObject.dispose();
-            });
-            mChildren.clear();
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            super.finalize();
-        }
-    }
-
-    public static class VPath_Delegate extends VNativeObject {
-        protected PathParser_Delegate.PathDataNode[] mNodes = null;
-        String mPathName;
-        int mChangingConfigurations;
-
-        public VPath_Delegate() {
-            // Empty constructor.
-        }
-
-        public VPath_Delegate(VPath_Delegate copy) {
-            mPathName = copy.mPathName;
-            mChangingConfigurations = copy.mChangingConfigurations;
-            mNodes = copy.mNodes != null ? PathParser_Delegate.deepCopyNodes(copy.mNodes) : null;
-        }
-
-        public void toPath(Path path) {
-            path.reset();
-            if (mNodes != null) {
-                PathParser_Delegate.PathDataNode.nodesToPath(mNodes,
-                        Path_Delegate.getDelegate(path.mNativePath));
-            }
-        }
-
-        @Override
-        public void setName(String name) {
-            mPathName = name;
-        }
-
-        public boolean isClipPath() {
-            return false;
-        }
-
-        private void setPathData(PathParser_Delegate.PathDataNode[] nodes) {
-            if (!PathParser_Delegate.canMorph(mNodes, nodes)) {
-                // This should not happen in the middle of animation.
-                mNodes = PathParser_Delegate.deepCopyNodes(nodes);
-            } else {
-                PathParser_Delegate.updateNodes(mNodes, nodes);
-            }
-        }
-
-        @Override
-        void dispose() {
-            mNodes = null;
-        }
-    }
-
-    static class VPathRenderer_Delegate extends VNativeObject {
-        /* Right now the internal data structure is organized as a tree.
-         * Each node can be a group node, or a path.
-         * A group node can have groups or paths as children, but a path node has
-         * no children.
-         * One example can be:
-         *                 Root Group
-         *                /    |     \
-         *           Group    Path    Group
-         *          /     \             |
-         *         Path   Path         Path
-         *
-         */
-        // Variables that only used temporarily inside the draw() call, so there
-        // is no need for deep copying.
-        private final Path mPath;
-        private final Path mRenderPath;
-        private final Matrix mFinalPathMatrix = new Matrix();
-        private final long mRootGroupPtr;
-        private float mViewportWidth = 0;
-        private float mViewportHeight = 0;
-        private float mRootAlpha = 1.0f;
-        private Paint mStrokePaint;
-        private Paint mFillPaint;
-        private PathMeasure mPathMeasure;
-        private boolean mAntiAlias = true;
-
-        private VPathRenderer_Delegate(long rootGroupPtr) {
-            mRootGroupPtr = rootGroupPtr;
-            mPath = new Path();
-            mRenderPath = new Path();
-        }
-
-        private VPathRenderer_Delegate(VPathRenderer_Delegate rendererToCopy,
-                long rootGroupPtr) {
-            this(rootGroupPtr);
-            mViewportWidth = rendererToCopy.mViewportWidth;
-            mViewportHeight = rendererToCopy.mViewportHeight;
-            mRootAlpha = rendererToCopy.mRootAlpha;
-        }
-
-        private float getRootAlpha() {
-            return mRootAlpha;
-        }
-
-        void setRootAlpha(float alpha) {
-            mRootAlpha = alpha;
-        }
-
-        private void drawGroupTree(VGroup_Delegate currentGroup, Matrix currentMatrix,
-                long canvasPtr, int w, int h, long filterPtr) {
-            // Calculate current group's matrix by preConcat the parent's and
-            // and the current one on the top of the stack.
-            // Basically the Mfinal = Mviewport * M0 * M1 * M2;
-            // Mi the local matrix at level i of the group tree.
-            currentGroup.mStackedMatrix.set(currentMatrix);
-            currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
-
-            // Save the current clip information, which is local to this group.
-            Canvas_Delegate.nSave(canvasPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
-            // Draw the group tree in the same order as the XML file.
-            for (int i = 0; i < currentGroup.mChildren.size(); i++) {
-                Object child = currentGroup.mChildren.get(i);
-                if (child instanceof VGroup_Delegate) {
-                    VGroup_Delegate childGroup = (VGroup_Delegate) child;
-                    drawGroupTree(childGroup, currentGroup.mStackedMatrix,
-                            canvasPtr, w, h, filterPtr);
-                } else if (child instanceof VPath_Delegate) {
-                    VPath_Delegate childPath = (VPath_Delegate) child;
-                    drawPath(currentGroup, childPath, canvasPtr, w, h, filterPtr);
-                }
-            }
-            Canvas_Delegate.nRestore(canvasPtr);
-        }
-
-        public void draw(long canvasPtr, long filterPtr, int w, int h) {
-            // Traverse the tree in pre-order to draw.
-            drawGroupTree(VNativeObject.getDelegate(mRootGroupPtr), Matrix.IDENTITY_MATRIX, canvasPtr, w, h, filterPtr);
-        }
-
-        private void drawPath(VGroup_Delegate VGroup, VPath_Delegate VPath, long canvasPtr,
-                int w,
-                int h,
-                long filterPtr) {
-            final float scaleX = w / mViewportWidth;
-            final float scaleY = h / mViewportHeight;
-            final float minScale = Math.min(scaleX, scaleY);
-            final Matrix groupStackedMatrix = VGroup.mStackedMatrix;
-
-            mFinalPathMatrix.set(groupStackedMatrix);
-            mFinalPathMatrix.postScale(scaleX, scaleY);
-
-            final float matrixScale = getMatrixScale(groupStackedMatrix);
-            if (matrixScale == 0) {
-                // When either x or y is scaled to 0, we don't need to draw anything.
-                return;
-            }
-            VPath.toPath(mPath);
-            final Path path = mPath;
-
-            mRenderPath.reset();
-
-            if (VPath.isClipPath()) {
-                mRenderPath.setFillType(FillType.WINDING);
-                mRenderPath.addPath(path, mFinalPathMatrix);
-                Canvas_Delegate.nClipPath(canvasPtr, mRenderPath.mNativePath, Op
-                        .INTERSECT.nativeInt);
-            } else {
-                VFullPath_Delegate fullPath = (VFullPath_Delegate) VPath;
-                if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) {
-                    float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f;
-                    float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f;
-
-                    if (mPathMeasure == null) {
-                        mPathMeasure = new PathMeasure();
-                    }
-                    mPathMeasure.setPath(mPath, false);
-
-                    float len = mPathMeasure.getLength();
-                    start = start * len;
-                    end = end * len;
-                    path.reset();
-                    if (start > end) {
-                        mPathMeasure.getSegment(start, len, path, true);
-                        mPathMeasure.getSegment(0f, end, path, true);
-                    } else {
-                        mPathMeasure.getSegment(start, end, path, true);
-                    }
-                    path.rLineTo(0, 0); // fix bug in measure
-                }
-                mRenderPath.addPath(path, mFinalPathMatrix);
-
-                if (fullPath.mFillColor != Color.TRANSPARENT) {
-                    if (mFillPaint == null) {
-                        mFillPaint = new Paint();
-                        mFillPaint.setStyle(Style.FILL);
-                        mFillPaint.setAntiAlias(mAntiAlias);
-                    }
-
-                    final Paint fillPaint = mFillPaint;
-                    fillPaint.setColor(applyAlpha(applyAlpha(fullPath.mFillColor, fullPath
-                      .mFillAlpha), getRootAlpha()));
-                    Paint_Delegate fillPaintDelegate = Paint_Delegate.getDelegate(fillPaint
-                            .getNativeInstance());
-                    // mFillPaint can not be null at this point so we will have a delegate
-                    assert fillPaintDelegate != null;
-                    fillPaintDelegate.setColorFilter(filterPtr);
-
-                    Shader_Delegate shaderDelegate =
-                            Shader_Delegate.getDelegate(fullPath.mFillGradient);
-                    if (shaderDelegate != null) {
-                        // If there is a shader, apply the local transformation to make sure
-                        // the gradient is transformed to match the viewport
-                        shaderDelegate.setLocalMatrix(mFinalPathMatrix.ni());
-                        shaderDelegate.setAlpha(fullPath.mFillAlpha);
-                    }
-
-                    fillPaintDelegate.setShader(fullPath.mFillGradient);
-                    Path_Delegate.nSetFillType(mRenderPath.mNativePath, fullPath.mFillType);
-                    BaseCanvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, fillPaint
-                            .getNativeInstance());
-                    if (shaderDelegate != null) {
-                        // Remove the local matrix
-                        shaderDelegate.setLocalMatrix(0);
-                    }
-                }
-
-                if (fullPath.mStrokeColor != Color.TRANSPARENT) {
-                    if (mStrokePaint == null) {
-                        mStrokePaint = new Paint();
-                        mStrokePaint.setStyle(Style.STROKE);
-                        mStrokePaint.setAntiAlias(mAntiAlias);
-                    }
-
-                    final Paint strokePaint = mStrokePaint;
-                    if (fullPath.mStrokeLineJoin != null) {
-                        strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin);
-                    }
-
-                    if (fullPath.mStrokeLineCap != null) {
-                        strokePaint.setStrokeCap(fullPath.mStrokeLineCap);
-                    }
-
-                    strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
-                    strokePaint.setColor(applyAlpha(applyAlpha(fullPath.mStrokeColor, fullPath
-                      .mStrokeAlpha), getRootAlpha()));
-                    Paint_Delegate strokePaintDelegate = Paint_Delegate.getDelegate(strokePaint
-                            .getNativeInstance());
-                    // mStrokePaint can not be null at this point so we will have a delegate
-                    assert strokePaintDelegate != null;
-                    strokePaintDelegate.setColorFilter(filterPtr);
-                    final float finalStrokeScale = minScale * matrixScale;
-                    strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale);
-                    Shader_Delegate strokeShaderDelegate =
-                            Shader_Delegate.getDelegate(fullPath.mStrokeGradient);
-                    if (strokeShaderDelegate != null) {
-                        strokeShaderDelegate.setAlpha(fullPath.mStrokeAlpha);
-                    }
-                    strokePaintDelegate.setShader(fullPath.mStrokeGradient);
-                    BaseCanvas_Delegate.nDrawPath(canvasPtr, mRenderPath.mNativePath, strokePaint
-                            .getNativeInstance());
-                }
-            }
-        }
-
-        private float getMatrixScale(Matrix groupStackedMatrix) {
-            // Given unit vectors A = (0, 1) and B = (1, 0).
-            // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
-            // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
-            // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
-            // If  max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
-            //
-            // For non-skew case, which is most of the cases, matrix scale is computing exactly the
-            // scale on x and y axis, and take the minimal of these two.
-            // For skew case, an unit square will mapped to a parallelogram. And this function will
-            // return the minimal height of the 2 bases.
-            float[] unitVectors = new float[]{0, 1, 1, 0};
-            groupStackedMatrix.mapVectors(unitVectors);
-            float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]);
-            float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]);
-            float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1],
-                    unitVectors[2], unitVectors[3]);
-            float maxScale = MathUtils.max(scaleX, scaleY);
-
-            float matrixScale = 0;
-            if (maxScale > 0) {
-                matrixScale = MathUtils.abs(crossProduct) / maxScale;
-            }
-            if (DBG_VECTOR_DRAWABLE) {
-                Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale);
-            }
-            return matrixScale;
-        }
-
-        private void setAntiAlias(boolean aa) {
-            mAntiAlias = aa;
-        }
-
-        @Override
-        public void setName(String name) {
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            // The mRootGroupPtr is not explicitly freed by anything in the VectorDrawable so we
-            // need to free it here.
-            VNativeObject nativeObject = sPathManager.getDelegate(mRootGroupPtr);
-            sPathManager.removeJavaReferenceFor(mRootGroupPtr);
-            assert nativeObject != null;
-            nativeObject.dispose();
-
-            super.finalize();
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/fonts/FontFamily_Builder_Delegate.java b/bridge/src/android/graphics/fonts/FontFamily_Builder_Delegate.java
deleted file mode 100644
index 018329d..0000000
--- a/bridge/src/android/graphics/fonts/FontFamily_Builder_Delegate.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics.fonts;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.FontFamily_Delegate.FontInfo;
-import android.graphics.FontFamily_Delegate.FontVariant;
-import android.graphics.Paint;
-
-import java.awt.Font;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.nio.ByteBuffer;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-import static android.graphics.FontFamily_Delegate.computeMatch;
-import static android.graphics.FontFamily_Delegate.deriveFont;
-
-/**
- * Delegate implementing the native methods of android.graphics.fonts.FontFamily$Builder
- * <p>
- * Through the layoutlib_create tool, the original native methods of FontFamily$Builder have been
- * replaced by calls to methods of the same name in this delegate class.
- * <p>
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between it
- * and the original FontFamily$Builder class.
- *
- * @see DelegateManager
- */
-public class FontFamily_Builder_Delegate {
-    private static final DelegateManager<FontFamily_Builder_Delegate> sBuilderManager =
-            new DelegateManager<>(FontFamily_Builder_Delegate.class);
-
-    private static long sFontFamilyFinalizer = -1;
-
-    // Order does not really matter but we use a LinkedHashMap to get reproducible results across
-    // render calls
-    private Map<FontInfo, Font> mFonts = new LinkedHashMap<>();
-    /**
-     * The variant of the Font Family - compact or elegant.
-     * <p/>
-     * 0 is unspecified, 1 is compact and 2 is elegant. This needs to be kept in sync with values in
-     * android.graphics.FontFamily
-     *
-     * @see Paint#setElegantTextHeight(boolean)
-     */
-    private FontVariant mVariant;
-    private boolean mIsCustomFallback;
-
-    @LayoutlibDelegate
-    /*package*/ static long nInitBuilder() {
-        return sBuilderManager.addNewDelegate(new FontFamily_Builder_Delegate());
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddFont(long builderPtr, long fontPtr) {
-        FontFamily_Builder_Delegate familyBuilder = sBuilderManager.getDelegate(builderPtr);
-        Font_Builder_Delegate fontBuilder = Font_Builder_Delegate.sBuilderManager.getDelegate(fontPtr);
-        if (familyBuilder == null || fontBuilder == null) {
-            return;
-        }
-        Font font;
-        if (fontBuilder.filePath.equals("")) {
-            font = loadFontBuffer(fontBuilder.mBuffer);
-
-        } else {
-            font = loadFontPath(fontBuilder.filePath);
-        }
-        if (font != null) {
-            familyBuilder.addFont(font, fontBuilder.mWeight, fontBuilder.mItalic);
-        }
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nBuild(long builderPtr, String langTags, int variant,
-            boolean isCustomFallback) {
-        FontFamily_Builder_Delegate builder = sBuilderManager.getDelegate(builderPtr);
-        if (builder != null) {
-            assert variant < 3;
-            builder.mVariant = FontVariant.values()[variant];
-            builder.mIsCustomFallback = isCustomFallback;
-        }
-        return builderPtr;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetReleaseNativeFamily() {
-        synchronized (Font_Builder_Delegate.class) {
-            if (sFontFamilyFinalizer == -1) {
-                sFontFamilyFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
-                        sBuilderManager::removeJavaReferenceFor);
-            }
-        }
-        return sFontFamilyFinalizer;
-    }
-
-    public static FontFamily_Builder_Delegate getDelegate(long nativeFontFamily) {
-        return sBuilderManager.getDelegate(nativeFontFamily);
-    }
-
-    @Nullable
-    public Font getFont(int desiredWeight, boolean isItalic) {
-        FontInfo desiredStyle = new FontInfo();
-        desiredStyle.mWeight = desiredWeight;
-        desiredStyle.mIsItalic = isItalic;
-
-        Font cachedFont = mFonts.get(desiredStyle);
-        if (cachedFont != null) {
-            return cachedFont;
-        }
-
-        FontInfo bestFont = null;
-
-        if (mFonts.size() == 1) {
-            // No need to compute the match since we only have one candidate
-            bestFont = mFonts.keySet().iterator().next();
-        } else {
-            int bestMatch = Integer.MAX_VALUE;
-
-            for (FontInfo font : mFonts.keySet()) {
-                int match = computeMatch(font, desiredStyle);
-                if (match < bestMatch) {
-                    bestMatch = match;
-                    bestFont = font;
-                    if (bestMatch == 0) {
-                        break;
-                    }
-                }
-            }
-        }
-
-        if (bestFont == null) {
-            return null;
-        }
-
-
-        // Derive the font as required and add it to the list of Fonts.
-        deriveFont(bestFont, desiredStyle);
-        addFont(desiredStyle);
-        return desiredStyle.mFont;
-    }
-
-    public FontVariant getVariant() {
-        return mVariant;
-    }
-
-    // ---- private helper methods ----
-
-    private void addFont(@NonNull Font font, int weight, boolean italic) {
-        FontInfo fontInfo = new FontInfo();
-        fontInfo.mFont = font;
-        fontInfo.mWeight = weight;
-        fontInfo.mIsItalic = italic;
-        addFont(fontInfo);
-    }
-
-    private void addFont(@NonNull FontInfo fontInfo) {
-        mFonts.putIfAbsent(fontInfo, fontInfo.mFont);
-    }
-
-    private static Font loadFontBuffer(@NonNull ByteBuffer buffer) {
-        try {
-            byte[] byteArray = new byte[buffer.limit()];
-            buffer.rewind();
-            buffer.get(byteArray);
-            return Font.createFont(Font.TRUETYPE_FONT, new ByteArrayInputStream(byteArray));
-        } catch (Exception e) {
-            Bridge.getLog().fidelityWarning(ILayoutLog.TAG_BROKEN, "Unable to load font",
-                    e, null, null);
-        }
-
-        return null;
-    }
-
-    private static Font loadFontPath(@NonNull String path) {
-        try {
-            File file = new File(path);
-            return Font.createFont(Font.TRUETYPE_FONT, file);
-        } catch (Exception e) {
-            Bridge.getLog().fidelityWarning(ILayoutLog.TAG_BROKEN, "Unable to load font",
-                    e, null, null);
-        }
-
-        return null;
-    }
-}
diff --git a/bridge/src/android/graphics/fonts/Font_Builder_Delegate.java b/bridge/src/android/graphics/fonts/Font_Builder_Delegate.java
index 0d3ce3f..490659b 100644
--- a/bridge/src/android/graphics/fonts/Font_Builder_Delegate.java
+++ b/bridge/src/android/graphics/fonts/Font_Builder_Delegate.java
@@ -16,8 +16,6 @@
 
 package android.graphics.fonts;
 
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 
@@ -31,8 +29,6 @@
 import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
 
-import libcore.util.NativeAllocationRegistry_Delegate;
-
 /**
  * Delegate implementing the native methods of android.graphics.fonts.Font$Builder
  * <p>
@@ -46,20 +42,6 @@
  * @see DelegateManager
  */
 public class Font_Builder_Delegate {
-    protected static final DelegateManager<Font_Builder_Delegate> sBuilderManager =
-            new DelegateManager<>(Font_Builder_Delegate.class);
-    private static long sFontFinalizer = -1;
-
-    protected ByteBuffer mBuffer;
-    protected int mWeight;
-    protected boolean mItalic;
-    protected int mTtcIndex;
-    protected String filePath;
-
-    @LayoutlibDelegate
-    /*package*/ static long nInitBuilder() {
-        return sBuilderManager.addNewDelegate(new Font_Builder_Delegate());
-    }
 
     @LayoutlibDelegate
     /*package*/ static ByteBuffer createBuffer(@NonNull AssetManager am, @NonNull String path,
@@ -80,35 +62,4 @@
             return buffer;
         }
     }
-
-    @LayoutlibDelegate
-    /*package*/ static void nAddAxis(long builderPtr, int tag, float value) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Font$Builder.nAddAxis is not supported.", null, null, null);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nBuild(long builderPtr, ByteBuffer buffer, String filePath, int weight,
-            boolean italic, int ttcIndex) {
-        Font_Builder_Delegate font = sBuilderManager.getDelegate(builderPtr);
-        if (font != null) {
-            font.mBuffer = buffer;
-            font.mWeight = weight;
-            font.mItalic = italic;
-            font.mTtcIndex = ttcIndex;
-            font.filePath = filePath;
-        }
-        return builderPtr;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetReleaseNativeFont() {
-        synchronized (Font_Builder_Delegate.class) {
-            if (sFontFinalizer == -1) {
-                sFontFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
-                        sBuilderManager::removeJavaReferenceFor);
-            }
-        }
-        return sFontFinalizer;
-    }
 }
diff --git a/bridge/src/android/graphics/fonts/SystemFonts_Delegate.java b/bridge/src/android/graphics/fonts/SystemFonts_Delegate.java
deleted file mode 100644
index 3f3e065..0000000
--- a/bridge/src/android/graphics/fonts/SystemFonts_Delegate.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics.fonts;
-
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.text.FontConfig;
-
-import java.io.File;
-import java.util.Map;
-
-import static android.graphics.FontFamily_Delegate.getFontLocation;
-
-/**
- * Delegate implementing the native methods of android.graphics.fonts.SystemFonts
- * <p>
- * Through the layoutlib_create tool, the original native methods of SystemFonts have been
- * replaced by calls to methods of the same name in this delegate class.
- * <p>
- * This class behaves like the original native implementation, but in Java, keeping previously
- * native data into its own objects and mapping them to int that are sent back and forth between it
- * and the original SystemFonts class.
- *
- * @see DelegateManager
- */
-public class SystemFonts_Delegate {
-
-    @LayoutlibDelegate
-    /*package*/ static FontConfig getSystemFontConfigInternal(
-            String fontsXml,
-            String systemFontDir,
-            String oemXml,
-            String productFontDir,
-            Map<String, File> updatableFontMap) {
-        Bridge.sIsTypefaceInitialized = true;
-        return SystemFonts.getSystemFontConfigInternal_Original(
-                getFontLocation() + "/standard/fonts.xml", getFontLocation() + "/",
-                null, null, updatableFontMap, 0, 0);
-    }
-}
diff --git a/bridge/src/android/graphics/text/BaseLineBreaker.java b/bridge/src/android/graphics/text/BaseLineBreaker.java
deleted file mode 100644
index 61fa216..0000000
--- a/bridge/src/android/graphics/text/BaseLineBreaker.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics.text;
-
-import android.annotation.NonNull;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-// Based on the native implementation of LineBreaker in
-// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
-public abstract class BaseLineBreaker {
-
-    protected static final int TAB_MASK   = 0x20000000;  // keep in sync with StaticLayout
-
-    protected final @NonNull List<Primitive> mPrimitives;
-    protected final @NonNull
-    LineWidth mLineWidth;
-    protected final @NonNull
-    TabStops mTabStops;
-
-    public BaseLineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
-            @NonNull TabStops tabStops) {
-        mPrimitives = Collections.unmodifiableList(primitives);
-        mLineWidth = lineWidth;
-        mTabStops = tabStops;
-    }
-
-    public abstract Result computeBreaks();
-
-    public static class Result {
-        List<Integer> mLineBreakOffset = new ArrayList<>();
-        List<Float> mLineWidths = new ArrayList<>();
-        List<Float> mLineAscents = new ArrayList<>();
-        List<Float> mLineDescents = new ArrayList<>();
-        List<Integer> mLineFlags = new ArrayList<>();
-    }
-}
diff --git a/bridge/src/android/graphics/text/GreedyLineBreaker.java b/bridge/src/android/graphics/text/GreedyLineBreaker.java
deleted file mode 100644
index 940e235..0000000
--- a/bridge/src/android/graphics/text/GreedyLineBreaker.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics.text;
-
-import android.annotation.NonNull;
-import android.graphics.text.Primitive.PrimitiveType;
-
-import java.util.List;
-
-import static android.graphics.text.Primitive.PrimitiveType.PENALTY_INFINITY;
-
-// Based on the native implementation of GreedyLineBreaker in
-// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
-public class GreedyLineBreaker extends BaseLineBreaker {
-
-    public GreedyLineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
-            @NonNull TabStops tabStops) {
-        super(primitives, lineWidth, tabStops);
-    }
-
-    @Override
-    public Result computeBreaks() {
-        int lineNum = 0;
-        float width = 0, printedWidth = 0;
-        boolean breakFound = false, goodBreakFound = false;
-        int breakIndex = 0, goodBreakIndex = 0;
-        float breakWidth = 0, goodBreakWidth = 0;
-        int firstTabIndex = Integer.MAX_VALUE;
-
-        float maxWidth = mLineWidth.getLineWidth(lineNum);
-
-        int numPrimitives = mPrimitives.size();
-        Result result = new Result();
-        // greedily fit as many characters as possible on each line
-        // loop over all primitives, and choose the best break point
-        // (if possible, a break point without splitting a word)
-        // after going over the maximum length
-        for (int i = 0; i < numPrimitives; i++) {
-            Primitive p = mPrimitives.get(i);
-
-            // update the current line width
-            if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
-                width += p.width;
-                if (p.type == PrimitiveType.BOX) {
-                    printedWidth = width;
-                }
-            } else if (p.type == PrimitiveType.VARIABLE) {
-                width = mTabStops.width(width);
-                // keep track of first tab character in the region we are examining
-                // so we can determine whether or not a line contains a tab
-                firstTabIndex = Math.min(firstTabIndex, i);
-            }
-
-            // find the best break point for the characters examined so far
-            if (printedWidth > maxWidth) {
-                //noinspection StatementWithEmptyBody
-                if (breakFound || goodBreakFound) {
-                    if (goodBreakFound) {
-                        // a true line break opportunity existed in the characters examined so far,
-                        // so there is no need to split a word
-                        i = goodBreakIndex; // no +1 because of i++
-                        lineNum++;
-                        maxWidth = mLineWidth.getLineWidth(lineNum);
-                        result.mLineBreakOffset.add(mPrimitives.get(goodBreakIndex).location);
-                        result.mLineWidths.add(goodBreakWidth);
-                        result.mLineAscents.add(0f);
-                        result.mLineDescents.add(0f);
-                        result.mLineFlags.add(firstTabIndex < goodBreakIndex ? TAB_MASK : 0);
-                        firstTabIndex = Integer.MAX_VALUE;
-                    } else {
-                        // must split a word because there is no other option
-                        i = breakIndex; // no +1 because of i++
-                        lineNum++;
-                        maxWidth = mLineWidth.getLineWidth(lineNum);
-                        result.mLineBreakOffset.add(mPrimitives.get(breakIndex).location);
-                        result.mLineWidths.add(breakWidth);
-                        result.mLineAscents.add(0f);
-                        result.mLineDescents.add(0f);
-                        result.mLineFlags.add(firstTabIndex < breakIndex ? TAB_MASK : 0);
-                        firstTabIndex = Integer.MAX_VALUE;
-                    }
-                    printedWidth = width = 0;
-                    goodBreakFound = breakFound = false;
-                    goodBreakWidth = breakWidth = 0;
-                    continue;
-                } else {
-                    // no choice, keep going... must make progress by putting at least one
-                    // character on a line, even if part of that character is cut off --
-                    // there is no other option
-                }
-            }
-
-            // update possible break points
-            if (p.type == PrimitiveType.PENALTY &&
-                    p.penalty < PENALTY_INFINITY) {
-                // this does not handle penalties with width
-
-                // handle forced line break
-                if (p.penalty == -PENALTY_INFINITY) {
-                    lineNum++;
-                    maxWidth = mLineWidth.getLineWidth(lineNum);
-                    result.mLineBreakOffset.add(p.location);
-                    result.mLineWidths.add(printedWidth);
-                    result.mLineAscents.add(0f);
-                    result.mLineDescents.add(0f);
-                    result.mLineFlags.add(firstTabIndex < i ? TAB_MASK : 0);
-                    firstTabIndex = Integer.MAX_VALUE;
-                    printedWidth = width = 0;
-                    goodBreakFound = breakFound = false;
-                    goodBreakWidth = breakWidth = 0;
-                    continue;
-                }
-                if (i > breakIndex && (printedWidth <= maxWidth || !breakFound)) {
-                    breakFound = true;
-                    breakIndex = i;
-                    breakWidth = printedWidth;
-                }
-                if (i > goodBreakIndex && printedWidth <= maxWidth) {
-                    goodBreakFound = true;
-                    goodBreakIndex = i;
-                    goodBreakWidth = printedWidth;
-                }
-            } else if (p.type == PrimitiveType.WORD_BREAK) {
-                // only do this if necessary -- we don't want to break words
-                // when possible, but sometimes it is unavoidable
-                if (i > breakIndex && (printedWidth <= maxWidth || !breakFound)) {
-                    breakFound = true;
-                    breakIndex = i;
-                    breakWidth = printedWidth;
-                }
-            }
-        }
-
-        if (breakFound || goodBreakFound) {
-            // output last break if there are more characters to output
-            if (goodBreakFound) {
-                result.mLineBreakOffset.add(mPrimitives.get(goodBreakIndex).location);
-                result.mLineWidths.add(goodBreakWidth);
-                result.mLineAscents.add(0f);
-                result.mLineDescents.add(0f);
-                result.mLineFlags.add(firstTabIndex < goodBreakIndex ? TAB_MASK : 0);
-            } else {
-                result.mLineBreakOffset.add(mPrimitives.get(breakIndex).location);
-                result.mLineWidths.add(breakWidth);
-                result.mLineAscents.add(0f);
-                result.mLineDescents.add(0f);
-                result.mLineFlags.add(firstTabIndex < breakIndex ? TAB_MASK : 0);
-            }
-        }
-        return result;
-    }
-}
diff --git a/bridge/src/android/graphics/text/LineBreaker_Delegate.java b/bridge/src/android/graphics/text/LineBreaker_Delegate.java
deleted file mode 100644
index 92c99cc..0000000
--- a/bridge/src/android/graphics/text/LineBreaker_Delegate.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics.text;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.icu.text.BreakIterator;
-import android.text.Layout;
-import android.text.Layout.BreakStrategy;
-import android.text.Layout.HyphenationFrequency;
-import android.graphics.text.Primitive.PrimitiveType;
-
-import java.text.CharacterIterator;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.text.Segment;
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-/**
- * Delegate that provides implementation for native methods in {@link android.text.StaticLayout}
- * <p/>
- * Through the layoutlib_create tool, selected methods of StaticLayout have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- */
-public class LineBreaker_Delegate {
-
-    private static final char CHAR_SPACE     = 0x20;
-    private static final char CHAR_TAB       = 0x09;
-    private static final char CHAR_NEWLINE   = 0x0A;
-    private static final char CHAR_ZWSP      = 0x200B;  // Zero width space.
-
-    // ---- Builder delegate manager ----
-    private static final DelegateManager<Builder> sBuilderManager =
-        new DelegateManager<>(Builder.class);
-    private static long sFinalizer = -1;
-
-    // ---- Result delegate manager ----
-    private static final DelegateManager<Result> sResultManager =
-        new DelegateManager<>(Result.class);
-    private static long sResultFinalizer = -1;
-
-    @LayoutlibDelegate
-    /*package*/ static long nInit(
-            @BreakStrategy int breakStrategy,
-            @HyphenationFrequency int hyphenationFrequency,
-            boolean isJustified,
-            @Nullable int[] indents) {
-        Builder builder = new Builder();
-        builder.mBreakStrategy = breakStrategy;
-        return sBuilderManager.addNewDelegate(builder);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetReleaseFunc() {
-        synchronized (MeasuredText_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
-                        sBuilderManager::removeJavaReferenceFor);
-            }
-        }
-        return sFinalizer;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nComputeLineBreaks(
-            /* non zero */ long nativePtr,
-
-            // Inputs
-            @NonNull char[] text,
-            long measuredTextPtr,
-            int length,
-            float firstWidth,
-            int firstWidthLineCount,
-            float restWidth,
-            @Nullable float[] variableTabStops,
-            float defaultTabStop,
-            int indentsOffset) {
-        Builder builder = sBuilderManager.getDelegate(nativePtr);
-        if (builder == null) {
-            return 0;
-        }
-
-        builder.mText = text;
-        builder.mWidths = new float[length];
-        builder.mLineWidth = new LineWidth(firstWidth, firstWidthLineCount, restWidth);
-        builder.mTabStopCalculator = new TabStops(variableTabStops, defaultTabStop);
-
-        MeasuredText_Delegate.computeRuns(measuredTextPtr, builder);
-
-        // compute all possible breakpoints.
-        BreakIterator it = BreakIterator.getLineInstance();
-        it.setText((CharacterIterator) new Segment(builder.mText, 0, length));
-
-        // average word length in english is 5. So, initialize the possible breaks with a guess.
-        List<Integer> breaks = new ArrayList<Integer>((int) Math.ceil(length / 5d));
-        int loc;
-        it.first();
-        while ((loc = it.next()) != BreakIterator.DONE) {
-            breaks.add(loc);
-        }
-
-        List<Primitive> primitives =
-                computePrimitives(builder.mText, builder.mWidths, length, breaks);
-        switch (builder.mBreakStrategy) {
-            case Layout.BREAK_STRATEGY_SIMPLE:
-                builder.mLineBreaker = new GreedyLineBreaker(primitives, builder.mLineWidth,
-                        builder.mTabStopCalculator);
-                break;
-            case Layout.BREAK_STRATEGY_HIGH_QUALITY:
-                // TODO
-//                break;
-            case Layout.BREAK_STRATEGY_BALANCED:
-                builder.mLineBreaker = new OptimizingLineBreaker(primitives, builder.mLineWidth,
-                        builder.mTabStopCalculator);
-                break;
-            default:
-                assert false : "Unknown break strategy: " + builder.mBreakStrategy;
-                builder.mLineBreaker = new GreedyLineBreaker(primitives, builder.mLineWidth,
-                        builder.mTabStopCalculator);
-        }
-        Result result = new Result(builder.mLineBreaker.computeBreaks());
-        return sResultManager.addNewDelegate(result);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetLineCount(long ptr) {
-        Result result = sResultManager.getDelegate(ptr);
-        return result.mResult.mLineBreakOffset.size();
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetLineBreakOffset(long ptr, int idx) {
-        Result result = sResultManager.getDelegate(ptr);
-        return result.mResult.mLineBreakOffset.get(idx);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetLineWidth(long ptr, int idx) {
-        Result result = sResultManager.getDelegate(ptr);
-        return result.mResult.mLineWidths.get(idx);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetLineAscent(long ptr, int idx) {
-        Result result = sResultManager.getDelegate(ptr);
-        return result.mResult.mLineAscents.get(idx);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetLineDescent(long ptr, int idx) {
-        Result result = sResultManager.getDelegate(ptr);
-        return result.mResult.mLineDescents.get(idx);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetLineFlag(long ptr, int idx) {
-        Result result = sResultManager.getDelegate(ptr);
-        return result.mResult.mLineFlags.get(idx);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetReleaseResultFunc() {
-        synchronized (MeasuredText_Delegate.class) {
-            if (sResultFinalizer == -1) {
-                sResultFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
-                        sBuilderManager::removeJavaReferenceFor);
-            }
-        }
-        return sResultFinalizer;
-    }
-
-    /**
-     * Compute metadata each character - things which help in deciding if it's possible to break
-     * at a point or not.
-     */
-    @NonNull
-    private static List<Primitive> computePrimitives(@NonNull char[] text, @NonNull float[] widths,
-            int length, @NonNull List<Integer> breaks) {
-        // Initialize the list with a guess of the number of primitives:
-        // 2 Primitives per non-whitespace char and approx 5 chars per word (i.e. 83% chars)
-        List<Primitive> primitives = new ArrayList<Primitive>(((int) Math.ceil(length * 1.833)));
-        int breaksSize = breaks.size();
-        int breakIndex = 0;
-        for (int i = 0; i < length; i++) {
-            char c = text[i];
-            if (c == CHAR_SPACE || c == CHAR_ZWSP) {
-                primitives.add(PrimitiveType.GLUE.getNewPrimitive(i, widths[i]));
-            } else if (c == CHAR_TAB) {
-                primitives.add(PrimitiveType.VARIABLE.getNewPrimitive(i));
-            } else if (c != CHAR_NEWLINE) {
-                while (breakIndex < breaksSize && breaks.get(breakIndex) < i) {
-                    breakIndex++;
-                }
-                Primitive p;
-                if (widths[i] != 0) {
-                    if (breakIndex < breaksSize && breaks.get(breakIndex) == i) {
-                        p = PrimitiveType.PENALTY.getNewPrimitive(i, 0, 0);
-                    } else {
-                        p = PrimitiveType.WORD_BREAK.getNewPrimitive(i, 0);
-                    }
-                    primitives.add(p);
-                }
-
-                primitives.add(PrimitiveType.BOX.getNewPrimitive(i, widths[i]));
-            }
-        }
-        // final break at end of everything
-        primitives.add(
-                PrimitiveType.PENALTY.getNewPrimitive(length, 0, -PrimitiveType.PENALTY_INFINITY));
-        return primitives;
-    }
-
-    // TODO: Rename to LineBreakerRef and move everything other than LineBreaker to LineBreaker.
-    /**
-     * Java representation of the native Builder class.
-     */
-    public static class Builder {
-        char[] mText;
-        float[] mWidths;
-        private BaseLineBreaker mLineBreaker;
-        private int mBreakStrategy;
-        private LineWidth mLineWidth;
-        private TabStops mTabStopCalculator;
-    }
-
-    public abstract static class Run {
-        int mStart;
-        int mEnd;
-
-        Run(int start, int end) {
-            mStart = start;
-            mEnd = end;
-        }
-
-        abstract void addTo(Builder builder);
-    }
-
-    public static class Result {
-        final BaseLineBreaker.Result mResult;
-        public Result(BaseLineBreaker.Result result) {
-            mResult = result;
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/text/LineWidth.java b/bridge/src/android/graphics/text/LineWidth.java
deleted file mode 100644
index 809b967..0000000
--- a/bridge/src/android/graphics/text/LineWidth.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics.text;
-
-// Based on the native implementation of LineWidth in
-// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
-public class LineWidth {
-    private final float mFirstWidth;
-    private final int mFirstWidthLineCount;
-    private float mRestWidth;
-
-    public LineWidth(float firstWidth, int firstWidthLineCount, float restWidth) {
-        mFirstWidth = firstWidth;
-        mFirstWidthLineCount = firstWidthLineCount;
-        mRestWidth = restWidth;
-    }
-
-    public float getLineWidth(int line) {
-        return (line < mFirstWidthLineCount) ? mFirstWidth : mRestWidth;
-    }
-}
diff --git a/bridge/src/android/graphics/text/MeasuredText_Builder_Delegate.java b/bridge/src/android/graphics/text/MeasuredText_Builder_Delegate.java
deleted file mode 100644
index f9abbe1..0000000
--- a/bridge/src/android/graphics/text/MeasuredText_Builder_Delegate.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics.text;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.NonNull;
-import android.graphics.BidiRenderer;
-import android.graphics.Paint;
-import android.graphics.Paint_Delegate;
-import android.graphics.RectF;
-import android.graphics.text.LineBreaker_Delegate.Builder;
-import android.graphics.text.LineBreaker_Delegate.Run;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * Delegate that provides implementation for native methods in
- * {@link android.graphics.text.MeasuredText}
- * <p/>
- * Through the layoutlib_create tool, selected methods of StaticLayout have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- */
-public class MeasuredText_Builder_Delegate {
-    // ---- Builder delegate manager ----
-    protected static final DelegateManager<MeasuredText_Builder_Delegate>
-            sBuilderManager =
-            new DelegateManager<>(MeasuredText_Builder_Delegate.class);
-
-    protected final ArrayList<Run> mRuns = new ArrayList<>();
-
-    @LayoutlibDelegate
-    /*package*/ static long nInitBuilder() {
-        return sBuilderManager.addNewDelegate(new MeasuredText_Builder_Delegate());
-    }
-
-    /**
-     * Apply style to make native measured text.
-     *
-     * @param nativeBuilderPtr The native NativeMeasuredParagraph builder pointer.
-     * @param paintPtr The native paint pointer to be applied.
-     * @param start The start offset in the copied buffer.
-     * @param end The end offset in the copied buffer.
-     * @param isRtl True if the text is RTL.
-     */
-    @LayoutlibDelegate
-    /*package*/ static void nAddStyleRun(long nativeBuilderPtr, long paintPtr, int start,
-            int end, boolean isRtl) {
-        MeasuredText_Builder_Delegate builder = sBuilderManager.getDelegate(nativeBuilderPtr);
-        if (builder == null) {
-            return;
-        }
-        builder.mRuns.add(new StyleRun(paintPtr, start, end, isRtl));
-    }
-
-    /**
-     * Apply ReplacementRun to make native measured text.
-     *
-     * @param nativeBuilderPtr The native NativeMeasuredParagraph builder pointer.
-     * @param paintPtr The native paint pointer to be applied.
-     * @param start The start offset in the copied buffer.
-     * @param end The end offset in the copied buffer.
-     * @param width The width of the replacement.
-     */
-    @LayoutlibDelegate
-    /*package*/ static void nAddReplacementRun(long nativeBuilderPtr, long paintPtr, int start,
-            int end, float width) {
-        MeasuredText_Builder_Delegate builder = sBuilderManager.getDelegate(nativeBuilderPtr);
-        if (builder == null) {
-            return;
-        }
-        builder.mRuns.add(new ReplacementRun(start, end, width));
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nBuildMeasuredText(long nativeBuilderPtr, long hintMtPtr,
-            @NonNull char[] text, boolean computeHyphenation, boolean computeLayout) {
-        MeasuredText_Delegate delegate = new MeasuredText_Delegate();
-        delegate.mNativeBuilderPtr = nativeBuilderPtr;
-        return MeasuredText_Delegate.sManager.addNewDelegate(delegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nFreeBuilder(long nativeBuilderPtr) {
-        sBuilderManager.removeJavaReferenceFor(nativeBuilderPtr);
-    }
-
-    private static float measureText(long nativePaint, char[] text, int index, int count,
-            float[] widths, int bidiFlags) {
-        Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint);
-        RectF bounds =
-                new BidiRenderer(null, paint, text).renderText(index, index + count, bidiFlags,
-                        widths, 0, false);
-        return bounds.right - bounds.left;
-    }
-
-    private static class StyleRun extends Run {
-        private final long mNativePaint;
-        private final boolean mIsRtl;
-
-        private StyleRun(long nativePaint, int start, int end, boolean isRtl) {
-            super(start, end);
-            mNativePaint = nativePaint;
-            mIsRtl = isRtl;
-        }
-
-        @Override
-        void addTo(Builder builder) {
-            int bidiFlags = mIsRtl ? Paint.BIDI_FORCE_RTL : Paint.BIDI_FORCE_LTR;
-            measureText(mNativePaint, builder.mText, mStart, mEnd - mStart, builder.mWidths,
-                    bidiFlags);
-        }
-    }
-
-    private static class ReplacementRun extends Run {
-        private final float mWidth;
-
-        private ReplacementRun(int start, int end, float width) {
-            super(start, end);
-            mWidth = width;
-        }
-
-        @Override
-        void addTo(Builder builder) {
-            builder.mWidths[mStart] = mWidth;
-            Arrays.fill(builder.mWidths, mStart + 1, mEnd, 0.0f);
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/text/MeasuredText_Delegate.java b/bridge/src/android/graphics/text/MeasuredText_Delegate.java
deleted file mode 100644
index 02e2845..0000000
--- a/bridge/src/android/graphics/text/MeasuredText_Delegate.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics.text;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.graphics.Rect;
-import android.graphics.text.LineBreaker_Delegate.Builder;
-import android.graphics.text.LineBreaker_Delegate.Run;
-
-import libcore.util.NativeAllocationRegistry_Delegate;
-
-/**
- * Delegate that provides implementation for native methods in
- * {@link android.graphics.text.MeasuredText}
- * <p/>
- * Through the layoutlib_create tool, selected methods of StaticLayout have been replaced
- * by calls to methods of the same name in this delegate class.
- *
- */
-public class MeasuredText_Delegate {
-
-    // ---- Builder delegate manager ----
-    protected static final DelegateManager<MeasuredText_Delegate> sManager =
-            new DelegateManager<>(MeasuredText_Delegate.class);
-    private static long sFinalizer = -1;
-
-    protected long mNativeBuilderPtr;
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetWidth(long nativePtr, int start, int end) {
-        // Ignore as it is not used for the layoutlib implementation
-        return 0.0f;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nGetReleaseFunc() {
-        synchronized (MeasuredText_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(
-                        sManager::removeJavaReferenceFor);
-            }
-        }
-        return sFinalizer;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int nGetMemoryUsage(long nativePtr) {
-        // Ignore as it is not used for the layoutlib implementation
-        return 0;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nGetBounds(long nativePtr, char[] buf, int start, int end, Rect rect) {
-        // Ignore as it is not used for the layoutlib implementation
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static float nGetCharWidthAt(long nativePtr, int offset) {
-        // Ignore as it is not used for the layoutlib implementation
-        return 0.0f;
-    }
-
-    public static void computeRuns(long measuredTextPtr, Builder staticLayoutBuilder) {
-        MeasuredText_Delegate delegate = sManager.getDelegate(measuredTextPtr);
-        if (delegate == null) {
-            return;
-        }
-        MeasuredText_Builder_Delegate builder =
-                MeasuredText_Builder_Delegate.sBuilderManager.getDelegate(delegate.mNativeBuilderPtr);
-        if (builder == null) {
-            return;
-        }
-        for (Run run: builder.mRuns) {
-            run.addTo(staticLayoutBuilder);
-        }
-    }
-}
\ No newline at end of file
diff --git a/bridge/src/android/graphics/text/OptimizingLineBreaker.java b/bridge/src/android/graphics/text/OptimizingLineBreaker.java
deleted file mode 100644
index 95e0920..0000000
--- a/bridge/src/android/graphics/text/OptimizingLineBreaker.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics.text;
-
-import android.annotation.NonNull;
-import android.graphics.text.Primitive.PrimitiveType;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.ListIterator;
-
-import static android.graphics.text.Primitive.PrimitiveType.PENALTY_INFINITY;
-
-
-// Based on the native implementation of OptimizingLineBreaker in
-// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
-/**
- * A more complex version of line breaking where we try to prevent the right edge from being too
- * jagged.
- */
-public class OptimizingLineBreaker extends BaseLineBreaker {
-
-    public OptimizingLineBreaker(@NonNull List<Primitive> primitives, @NonNull LineWidth lineWidth,
-            @NonNull TabStops tabStops) {
-        super(primitives, lineWidth, tabStops);
-    }
-
-    @Override
-    public Result computeBreaks() {
-        Result result = new Result();
-        int numBreaks = mPrimitives.size();
-        assert numBreaks > 0;
-        if (numBreaks == 1) {
-            // This can be true only if it's an empty paragraph.
-            Primitive p = mPrimitives.get(0);
-            assert p.type == PrimitiveType.PENALTY;
-            result.mLineBreakOffset.add(0);
-            result.mLineWidths.add(p.width);
-            result.mLineAscents.add(0f);
-            result.mLineDescents.add(0f);
-            result.mLineFlags.add(0);
-            return result;
-        }
-        Node[] opt = new Node[numBreaks];
-        opt[0] = new Node(-1, 0, 0, 0, false);
-        opt[numBreaks - 1] = new Node(-1, 0, 0, 0, false);
-
-        ArrayList<Integer> active = new ArrayList<Integer>();
-        active.add(0);
-        int lastBreak = 0;
-        for (int i = 0; i < numBreaks; i++) {
-            Primitive p = mPrimitives.get(i);
-            if (p.type == PrimitiveType.PENALTY) {
-                boolean finalBreak = (i + 1 == numBreaks);
-                Node bestBreak = null;
-
-                for (ListIterator<Integer> it = active.listIterator(); it.hasNext();
-                        /* incrementing done in loop */) {
-                    int pos = it.next();
-                    int lines = opt[pos].mPrevCount;
-                    float maxWidth = mLineWidth.getLineWidth(lines);
-                    // we have to compute metrics every time --
-                    // we can't really pre-compute this stuff and just deal with breaks
-                    // because of the way tab characters work, this makes it computationally
-                    // harder, but this way, we can still optimize while treating tab characters
-                    // correctly
-                    LineMetrics lineMetrics = computeMetrics(pos, i);
-                    if (lineMetrics.mPrintedWidth <= maxWidth) {
-                        float demerits = computeDemerits(maxWidth, lineMetrics.mPrintedWidth,
-                                finalBreak, p.penalty) + opt[pos].mDemerits;
-                        if (bestBreak == null || demerits < bestBreak.mDemerits) {
-                            if (bestBreak == null) {
-                                bestBreak = new Node(pos, opt[pos].mPrevCount + 1, demerits,
-                                        lineMetrics.mPrintedWidth, lineMetrics.mHasTabs);
-                            } else {
-                                bestBreak.mPrev = pos;
-                                bestBreak.mPrevCount = opt[pos].mPrevCount + 1;
-                                bestBreak.mDemerits = demerits;
-                                bestBreak.mWidth = lineMetrics.mPrintedWidth;
-                                bestBreak.mHasTabs = lineMetrics.mHasTabs;
-                            }
-                        }
-                    } else {
-                        it.remove();
-                    }
-                }
-                if (p.penalty == -PENALTY_INFINITY) {
-                    active.clear();
-                }
-                if (bestBreak != null) {
-                    opt[i] = bestBreak;
-                    active.add(i);
-                    lastBreak = i;
-                }
-                if (active.isEmpty()) {
-                    // we can't give up!
-                    LineMetrics lineMetrics = new LineMetrics();
-                    int lines = opt[lastBreak].mPrevCount;
-                    float maxWidth = mLineWidth.getLineWidth(lines);
-                    int breakIndex = desperateBreak(lastBreak, numBreaks, maxWidth, lineMetrics);
-                    opt[breakIndex] = new Node(lastBreak, lines + 1, 0 /*doesn't matter*/,
-                            lineMetrics.mWidth, lineMetrics.mHasTabs);
-                    active.add(breakIndex);
-                    lastBreak = breakIndex;
-                    i = breakIndex; // incremented by i++
-                }
-            }
-        }
-
-        int idx = numBreaks - 1;
-        while (opt[idx].mPrev != -1) {
-            result.mLineBreakOffset.add(mPrimitives.get(idx).location);
-            result.mLineWidths.add(opt[idx].mWidth);
-            result.mLineAscents.add(0f);
-            result.mLineDescents.add(0f);
-            result.mLineFlags.add(opt[idx].mHasTabs ? TAB_MASK : 0);
-            idx = opt[idx].mPrev;
-        }
-
-        Collections.reverse(result.mLineBreakOffset);
-        Collections.reverse(result.mLineWidths);
-        Collections.reverse(result.mLineAscents);
-        Collections.reverse(result.mLineDescents);
-        Collections.reverse(result.mLineFlags);
-        return result;
-    }
-
-    @NonNull
-    private LineMetrics computeMetrics(int start, int end) {
-        boolean f = false;
-        float w = 0, pw = 0;
-        for (int i = start; i < end; i++) {
-            Primitive p = mPrimitives.get(i);
-            if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
-                w += p.width;
-                if (p.type == PrimitiveType.BOX) {
-                    pw = w;
-                }
-            } else if (p.type == PrimitiveType.VARIABLE) {
-                w = mTabStops.width(w);
-                f = true;
-            }
-        }
-        return new LineMetrics(w, pw, f);
-    }
-
-    private static float computeDemerits(float maxWidth, float width, boolean finalBreak,
-            float penalty) {
-        float deviation = finalBreak ? 0 : maxWidth - width;
-        return (deviation * deviation) + penalty;
-    }
-
-    /**
-     * @return the last break position or -1 if failed.
-     */
-    @SuppressWarnings("ConstantConditions")  // method too complex to be analyzed.
-    private int desperateBreak(int start, int limit, float maxWidth,
-            @NonNull LineMetrics lineMetrics) {
-        float w = 0, pw = 0;
-        boolean breakFound = false;
-        int breakIndex = 0, firstTabIndex = Integer.MAX_VALUE;
-        for (int i = start; i < limit; i++) {
-            Primitive p = mPrimitives.get(i);
-
-            if (p.type == PrimitiveType.BOX || p.type == PrimitiveType.GLUE) {
-                w += p.width;
-                if (p.type == PrimitiveType.BOX) {
-                    pw = w;
-                }
-            } else if (p.type == PrimitiveType.VARIABLE) {
-                w = mTabStops.width(w);
-                firstTabIndex = Math.min(firstTabIndex, i);
-            }
-
-            if (pw > maxWidth && breakFound) {
-                break;
-            }
-
-            // must make progress
-            if (i > start &&
-                    (p.type == PrimitiveType.PENALTY || p.type == PrimitiveType.WORD_BREAK)) {
-                breakFound = true;
-                breakIndex = i;
-            }
-        }
-
-        if (breakFound) {
-            lineMetrics.mWidth = w;
-            lineMetrics.mPrintedWidth = pw;
-            lineMetrics.mHasTabs = (start <= firstTabIndex && firstTabIndex < breakIndex);
-            return breakIndex;
-        } else {
-            return -1;
-        }
-    }
-
-    private static class LineMetrics {
-        /** Actual width of the line. */
-        float mWidth;
-        /** Width of the line minus trailing whitespace. */
-        float mPrintedWidth;
-        boolean mHasTabs;
-
-        public LineMetrics() {
-        }
-
-        public LineMetrics(float width, float printedWidth, boolean hasTabs) {
-            mWidth = width;
-            mPrintedWidth = printedWidth;
-            mHasTabs = hasTabs;
-        }
-    }
-
-    /**
-     * A struct to store the info about a break.
-     */
-    @SuppressWarnings("SpellCheckingInspection")  // For the word struct.
-    private static class Node {
-        // -1 for the first node.
-        int mPrev;
-        // number of breaks so far.
-        int mPrevCount;
-        float mDemerits;
-        float mWidth;
-        boolean mHasTabs;
-
-        public Node(int prev, int prevCount, float demerits, float width, boolean hasTabs) {
-            mPrev = prev;
-            mPrevCount = prevCount;
-            mDemerits = demerits;
-            mWidth = width;
-            mHasTabs = hasTabs;
-        }
-    }
-}
diff --git a/bridge/src/android/graphics/text/Primitive.java b/bridge/src/android/graphics/text/Primitive.java
deleted file mode 100644
index b8157ec..0000000
--- a/bridge/src/android/graphics/text/Primitive.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics.text;
-
-import android.annotation.NonNull;
-
-// Based on the native implementation of Primitive in
-// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
-public class Primitive {
-    public final @NonNull PrimitiveType type;
-    public final int location;
-    // The following fields don't make sense for all types.
-    // Box and Glue have width only.
-    // Penalty has both width and penalty.
-    // Word_break has penalty only.
-    public final float width;
-    public final float penalty;
-
-    /**
-     * Use {@code PrimitiveType#getNewPrimitive()}
-     */
-    private Primitive(@NonNull PrimitiveType type, int location, float width, float penalty) {
-        this.type = type;
-        this.location = location;
-        this.width = width;
-        this.penalty = penalty;
-    }
-
-    public static enum PrimitiveType {
-        /**
-         * Something with a constant width that is to be typeset - like a character.
-         */
-        BOX,
-        /**
-         * Blank space with fixed width.
-         */
-        GLUE,
-        /**
-         * Aesthetic cost indicating how desirable breaking at this point will be. A penalty of
-         * {@link #PENALTY_INFINITY} means a forced non-break, whereas a penalty of negative
-         * {@code #PENALTY_INFINITY} means a forced break.
-         * <p/>
-         * Currently, it only stores penalty with values 0 or -infinity.
-         */
-        PENALTY,
-        /**
-         * For tabs - variable width space.
-         */
-        VARIABLE,
-        /**
-         * Possible breakpoints within a word. Think of this as a high cost {@link #PENALTY}.
-         */
-        WORD_BREAK;
-
-        public Primitive getNewPrimitive(int location) {
-            assert this == VARIABLE;
-            return new Primitive(this, location, 0f, 0f);
-        }
-
-        public Primitive getNewPrimitive(int location, float value) {
-            assert this == BOX || this == GLUE || this == WORD_BREAK;
-            if (this == BOX || this == GLUE) {
-                return new Primitive(this, location, value, 0f);
-            } else {
-                return new Primitive(this, location, 0f, value);
-            }
-        }
-
-        public Primitive getNewPrimitive(int location, float width, float penalty) {
-            assert this == PENALTY;
-            return new Primitive(this, location, width, penalty);
-        }
-
-        // forced non-break, negative infinity is forced break.
-        public static final float PENALTY_INFINITY = 1e7f;
-    }
-}
-
diff --git a/bridge/src/android/graphics/text/TabStops.java b/bridge/src/android/graphics/text/TabStops.java
deleted file mode 100644
index 6ede24c..0000000
--- a/bridge/src/android/graphics/text/TabStops.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics.text;
-
-import android.annotation.Nullable;
-
-// Based on the native implementation of TabStops in
-// frameworks/base/core/jni/android_text_StaticLayout.cpp revision b808260
-public class TabStops {
-    @Nullable
-    private float[] mStops;
-    private final float mTabWidth;
-
-    public TabStops(@Nullable float[] stops, float defaultTabWidth) {
-        mTabWidth = defaultTabWidth;
-        mStops = stops;
-    }
-
-    public float width(float widthSoFar) {
-        if (mStops != null) {
-            for (float f : mStops) {
-                if (f > widthSoFar) {
-                    return f;
-                }
-            }
-        }
-        // find the next tabStop after widthSoFar.
-        return ((widthSoFar + mTabWidth) / mTabWidth) * mTabWidth;
-    }
-}
diff --git a/bridge/src/android/os/Handler_Delegate.java b/bridge/src/android/os/Handler_Delegate.java
index 2152c8a..b0e8598 100644
--- a/bridge/src/android/os/Handler_Delegate.java
+++ b/bridge/src/android/os/Handler_Delegate.java
@@ -16,8 +16,16 @@
 
 package android.os;
 
+import com.android.ide.common.rendering.api.ILayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.impl.RenderAction;
+import com.android.layoutlib.bridge.util.HandlerMessageQueue;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.android.tools.layoutlib.annotations.NotNull;
+import com.android.tools.layoutlib.annotations.VisibleForTesting;
 
+import java.util.WeakHashMap;
 
 /**
  * Delegate overriding selected methods of android.os.Handler
@@ -30,6 +38,9 @@
 public class Handler_Delegate {
 
     // -------- Delegate methods
+    @VisibleForTesting
+    public static final WeakHashMap<BridgeContext, HandlerMessageQueue> sRunnablesQueues =
+            new WeakHashMap<>();
 
     @LayoutlibDelegate
     /*package*/ static boolean sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
@@ -37,11 +48,58 @@
         IHandlerCallback callback = sCallbacks.get();
         if (callback != null) {
             callback.sendMessageAtTime(handler, msg, uptimeMillis);
+        } else {
+            if (msg.callback != null) {
+                HandlerMessageQueue queue = currentQueue();
+                if (queue == null) {
+                    return true;
+                }
+                queue.add(handler, uptimeMillis, msg.callback);
+            }
         }
         return true;
     }
 
+    /**
+     * Current implementation of Compose uses {@link Handler#postAtFrontOfQueue} to execute state
+     * updates. We can not intercept postAtFrontOfQueue Compose calls, however we can intecept
+     * internal Handler calls. Since postAtFrontOfQueue is just a wrapper of
+     * sendMessageAtFrontOfQueue we re-define sendMessageAtFrontOfQueue here to catch Compose calls
+     * (we are only interested in them) and execute them.
+     * TODO(b/137794558): Clean/rework this when Compose reworks Handler usage.
+     */
+    @LayoutlibDelegate
+    /*package*/ static boolean sendMessageAtFrontOfQueue(Handler handler, Message msg) {
+        // We will also catch calls from the Choreographer that have no callback.
+        if (msg.callback != null) {
+            HandlerMessageQueue queue = currentQueue();
+            if (queue == null) {
+                return true;
+            }
+            queue.add(handler, 0, msg.callback);
+        }
+
+        return true;
+    }
+
     // -------- Delegate implementation
+    /**
+     * Executed all the collected callbacks
+     *
+     * @return if there are more callbacks to execute
+     */
+    public static boolean executeCallbacks() {
+        HandlerMessageQueue queue = currentQueue();
+        if (queue == null) {
+            return false;
+        }
+        long uptimeMillis = SystemClock_Delegate.uptimeMillis();
+        Runnable r;
+        while ((r = queue.extractFirst(uptimeMillis)) != null) {
+            executeSafely(r);
+        }
+        return queue.isNotEmpty();
+    }
 
     public interface IHandlerCallback {
         void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis);
@@ -54,4 +112,30 @@
         sCallbacks.set(callback);
     }
 
+    public static void dispose(@NotNull BridgeContext context) {
+        sRunnablesQueues.remove(context);
+    }
+
+    /**
+     * The runnables we are executing are mostly library/user code and we have no guarantee that it
+     * is safe to execute them. Thus, we have to wrap each executing in try/catch block to isolate
+     * dangerous executions.
+     * @param r a runnable to be executed
+     */
+    private static void executeSafely(@NotNull Runnable r) {
+        try {
+            r.run();
+        } catch (Throwable t) {
+            Bridge.getLog().error(ILayoutLog.TAG_BROKEN, "Failed executing Handler callback", t,
+                    null, null);
+        }
+    }
+
+    private static HandlerMessageQueue currentQueue() {
+        BridgeContext context = RenderAction.getCurrentContext();
+        if (context == null) {
+            return null;
+        }
+        return sRunnablesQueues.computeIfAbsent(context, c -> new HandlerMessageQueue());
+    }
 }
diff --git a/bridge/src/android/os/SystemProperties_Delegate.java b/bridge/src/android/os/SystemProperties_Delegate.java
deleted file mode 100644
index b5c8294..0000000
--- a/bridge/src/android/os/SystemProperties_Delegate.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.os;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import java.util.Map;
-
-/**
- * Delegate implementing the native methods of android.os.SystemProperties
- *
- * Through the layoutlib_create tool, the original native methods of SystemProperties have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
- * around to map int to instance of the delegate.
- */
-public class SystemProperties_Delegate {
-
-    @LayoutlibDelegate
-    /*package*/ static String native_get(String key, String def) {
-        Map<String, String> properties = Bridge.getPlatformProperties();
-        String value = properties.get(key);
-        if (value != null) {
-            return value;
-        }
-
-        return def;
-    }
-    @LayoutlibDelegate
-    /*package*/ static int native_get_int(String key, int def) {
-        Map<String, String> properties = Bridge.getPlatformProperties();
-        String value = properties.get(key);
-        if (value != null) {
-            return Integer.decode(value);
-        }
-
-        return def;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long native_get_long(String key, long def) {
-        Map<String, String> properties = Bridge.getPlatformProperties();
-        String value = properties.get(key);
-        if (value != null) {
-            return Long.decode(value);
-        }
-
-        return def;
-    }
-
-    /**
-     * Values 'n', 'no', '0', 'false' or 'off' are considered false.
-     * Values 'y', 'yes', '1', 'true' or 'on' are considered true.
-     */
-    @LayoutlibDelegate
-    /*package*/ static boolean native_get_boolean(String key, boolean def) {
-        Map<String, String> properties = Bridge.getPlatformProperties();
-        String value = properties.get(key);
-
-        if ("n".equals(value) || "no".equals(value) || "0".equals(value) || "false".equals(value)
-                || "off".equals(value)) {
-            return false;
-        }
-        //noinspection SimplifiableIfStatement
-        if ("y".equals(value) || "yes".equals(value) || "1".equals(value) || "true".equals(value)
-                || "on".equals(value)) {
-            return true;
-        }
-
-        return def;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void native_set(String key, String def) {
-        Map<String, String> properties = Bridge.getPlatformProperties();
-        properties.put(key, def);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void native_add_change_callback() {
-        // pass.
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void native_report_sysprop_change() {
-        // pass.
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static String native_get(long handle) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Layoutlib does not support SystemProperties Handle", null, null, null);
-        return null;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static int native_get_int(long handle, int def) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Layoutlib does not support SystemProperties Handle", null, null, null);
-        return def;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long native_get_long(long handle, long def) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Layoutlib does not support SystemProperties Handle", null, null, null);
-        return def;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean native_get_boolean(long handle, boolean def) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Layoutlib does not support SystemProperties Handle", null, null, null);
-        return def;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long native_find(String name) {
-        Bridge.getLog().fidelityWarning(ILayoutLog.TAG_UNSUPPORTED,
-                "Layoutlib does not support SystemProperties Handle", null, null, null);
-        return 0;
-    }
-}
diff --git a/bridge/src/android/util/Log_Delegate.java b/bridge/src/android/util/Log_Delegate.java
deleted file mode 100644
index 7f432ab..0000000
--- a/bridge/src/android/util/Log_Delegate.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-package android.util;
-
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-class Log_Delegate {
-    // to replicate prefix visible when using 'adb logcat'
-    private static char priorityChar(int priority) {
-        switch (priority) {
-            case Log.VERBOSE:
-                return 'V';
-            case Log.DEBUG:
-                return 'D';
-            case Log.INFO:
-                return 'I';
-            case Log.WARN:
-                return 'W';
-            case Log.ERROR:
-                return 'E';
-            case Log.ASSERT:
-                return 'A';
-            default:
-                return '?';
-        }
-    }
-
-    @LayoutlibDelegate
-    static int println_native(int bufID, int priority, String tag, String msgs) {
-        String prefix = priorityChar(priority) + "/" + tag + ": ";
-        for (String msg: msgs.split("\n")) {
-            System.out.println(prefix + msg);
-        }
-        return 0;
-    }
-
-}
diff --git a/bridge/src/android/util/PathParser_Delegate.java b/bridge/src/android/util/PathParser_Delegate.java
deleted file mode 100644
index 46e94a7..0000000
--- a/bridge/src/android/util/PathParser_Delegate.java
+++ /dev/null
@@ -1,846 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-package android.util;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.NonNull;
-import android.graphics.Path_Delegate;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * Delegate that provides implementation for native methods in {@link android.util.PathParser}
- * <p/>
- * Through the layoutlib_create tool, selected methods of PathParser have been replaced by calls to
- * methods of the same name in this delegate class.
- *
- * Most of the code has been taken from the implementation in
- * {@code tools/base/sdk-common/src/main/java/com/android/ide/common/vectordrawable/PathParser.java}
- * revision be6fe89a3b686db5a75e7e692a148699973957f3
- */
-public class PathParser_Delegate {
-
-    private static final Logger LOGGER = Logger.getLogger("PathParser");
-
-    // ---- Builder delegate manager ----
-    private static final DelegateManager<PathParser_Delegate> sManager =
-            new DelegateManager<PathParser_Delegate>(PathParser_Delegate.class);
-
-    // ---- delegate data ----
-    @NonNull
-    private PathDataNode[] mPathDataNodes;
-
-    public static PathParser_Delegate getDelegate(long nativePtr) {
-        return sManager.getDelegate(nativePtr);
-    }
-
-    private PathParser_Delegate(@NonNull PathDataNode[] nodes) {
-        mPathDataNodes = nodes;
-    }
-
-    public PathDataNode[] getPathDataNodes() {
-        return mPathDataNodes;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nParseStringForPath(long pathPtr, @NonNull String pathString, int
-            stringLength) {
-        Path_Delegate path_delegate = Path_Delegate.getDelegate(pathPtr);
-        if (path_delegate == null) {
-            return;
-        }
-        assert pathString.length() == stringLength;
-        PathDataNode.nodesToPath(createNodesFromPathData(pathString), path_delegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nCreatePathFromPathData(long outPathPtr, long pathData) {
-        Path_Delegate path_delegate = Path_Delegate.getDelegate(outPathPtr);
-        PathParser_Delegate source = sManager.getDelegate(outPathPtr);
-        if (source == null || path_delegate == null) {
-            return;
-        }
-        PathDataNode.nodesToPath(source.mPathDataNodes, path_delegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreateEmptyPathData() {
-        PathParser_Delegate newDelegate = new PathParser_Delegate(new PathDataNode[0]);
-        return sManager.addNewDelegate(newDelegate);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreatePathData(long nativePtr) {
-        PathParser_Delegate source = sManager.getDelegate(nativePtr);
-        if (source == null) {
-            return 0;
-        }
-        PathParser_Delegate dest = new PathParser_Delegate(deepCopyNodes(source.mPathDataNodes));
-        return sManager.addNewDelegate(dest);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static long nCreatePathDataFromString(@NonNull String pathString,
-            int stringLength) {
-        assert pathString.length() == stringLength : "Inconsistent path string length.";
-        PathDataNode[] nodes = createNodesFromPathData(pathString);
-        PathParser_Delegate delegate = new PathParser_Delegate(nodes);
-        return sManager.addNewDelegate(delegate);
-
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nInterpolatePathData(long outDataPtr, long fromDataPtr,
-            long toDataPtr, float fraction) {
-        PathParser_Delegate out = sManager.getDelegate(outDataPtr);
-        PathParser_Delegate from = sManager.getDelegate(fromDataPtr);
-        PathParser_Delegate to = sManager.getDelegate(toDataPtr);
-        if (out == null || from == null || to == null) {
-            return false;
-        }
-        int length = from.mPathDataNodes.length;
-        if (length != to.mPathDataNodes.length) {
-            Bridge.getLog().error(ILayoutLog.TAG_BROKEN,
-                    "Cannot interpolate path data with different lengths (from " + length + " to " +
-                            to.mPathDataNodes.length + ").", null, null);
-            return false;
-        }
-        if (out.mPathDataNodes.length != length) {
-            out.mPathDataNodes = new PathDataNode[length];
-        }
-        for (int i = 0; i < length; i++) {
-            if (out.mPathDataNodes[i] == null) {
-                out.mPathDataNodes[i] = new PathDataNode(from.mPathDataNodes[i]);
-            }
-            out.mPathDataNodes[i].interpolatePathDataNode(from.mPathDataNodes[i],
-                        to.mPathDataNodes[i], fraction);
-        }
-        return true;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nFinalize(long nativePtr) {
-        sManager.removeJavaReferenceFor(nativePtr);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static boolean nCanMorph(long fromDataPtr, long toDataPtr) {
-        PathParser_Delegate fromPath = PathParser_Delegate.getDelegate(fromDataPtr);
-        PathParser_Delegate toPath = PathParser_Delegate.getDelegate(toDataPtr);
-        if (fromPath == null || toPath == null || fromPath.getPathDataNodes() == null || toPath
-                .getPathDataNodes() == null) {
-            return true;
-        }
-        return PathParser_Delegate.canMorph(fromPath.getPathDataNodes(), toPath.getPathDataNodes());
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static void nSetPathData(long outDataPtr, long fromDataPtr) {
-        PathParser_Delegate out = sManager.getDelegate(outDataPtr);
-        PathParser_Delegate from = sManager.getDelegate(fromDataPtr);
-        if (from == null || out == null) {
-            return;
-        }
-        out.mPathDataNodes = deepCopyNodes(from.mPathDataNodes);
-    }
-
-    /**
-     * @param pathData The string representing a path, the same as "d" string in svg file.
-     *
-     * @return an array of the PathDataNode.
-     */
-    @NonNull
-    public static PathDataNode[] createNodesFromPathData(@NonNull String pathData) {
-        int start = 0;
-        int end = 1;
-
-        ArrayList<PathDataNode> list = new ArrayList<PathDataNode>();
-        while (end < pathData.length()) {
-            end = nextStart(pathData, end);
-            String s = pathData.substring(start, end).trim();
-            if (s.length() > 0) {
-                float[] val = getFloats(s);
-                addNode(list, s.charAt(0), val);
-            }
-
-            start = end;
-            end++;
-        }
-        if ((end - start) == 1 && start < pathData.length()) {
-            addNode(list, pathData.charAt(start), new float[0]);
-        }
-        return list.toArray(new PathDataNode[list.size()]);
-    }
-
-    /**
-     * @param source The array of PathDataNode to be duplicated.
-     *
-     * @return a deep copy of the <code>source</code>.
-     */
-    @NonNull
-    public static PathDataNode[] deepCopyNodes(@NonNull PathDataNode[] source) {
-        PathDataNode[] copy = new PathDataNode[source.length];
-        for (int i = 0; i < source.length; i++) {
-            copy[i] = new PathDataNode(source[i]);
-        }
-        return copy;
-    }
-
-    /**
-     * @param nodesFrom The source path represented in an array of PathDataNode
-     * @param nodesTo The target path represented in an array of PathDataNode
-     * @return whether the <code>nodesFrom</code> can morph into <code>nodesTo</code>
-     */
-    public static boolean canMorph(PathDataNode[] nodesFrom, PathDataNode[] nodesTo) {
-        if (nodesFrom == null || nodesTo == null) {
-            return false;
-        }
-
-        if (nodesFrom.length != nodesTo.length) {
-            return false;
-        }
-
-        for (int i = 0; i < nodesFrom.length; i ++) {
-            if (nodesFrom[i].mType != nodesTo[i].mType
-                    || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Update the target's data to match the source.
-     * Before calling this, make sure canMorph(target, source) is true.
-     *
-     * @param target The target path represented in an array of PathDataNode
-     * @param source The source path represented in an array of PathDataNode
-     */
-    public static void updateNodes(PathDataNode[] target, PathDataNode[] source) {
-        for (int i = 0; i < source.length; i ++) {
-            target[i].mType = source[i].mType;
-            for (int j = 0; j < source[i].mParams.length; j ++) {
-                target[i].mParams[j] = source[i].mParams[j];
-            }
-        }
-    }
-
-    private static int nextStart(@NonNull String s, int end) {
-        char c;
-
-        while (end < s.length()) {
-            c = s.charAt(end);
-            // Note that 'e' or 'E' are not valid path commands, but could be
-            // used for floating point numbers' scientific notation.
-            // Therefore, when searching for next command, we should ignore 'e'
-            // and 'E'.
-            if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0))
-                    && c != 'e' && c != 'E') {
-                return end;
-            }
-            end++;
-        }
-        return end;
-    }
-
-    /**
-     * Calculate the position of the next comma or space or negative sign
-     *
-     * @param s the string to search
-     * @param start the position to start searching
-     * @param result the result of the extraction, including the position of the the starting
-     * position of next number, whether it is ending with a '-'.
-     */
-    private static void extract(@NonNull String s, int start, @NonNull ExtractFloatResult result) {
-        // Now looking for ' ', ',', '.' or '-' from the start.
-        int currentIndex = start;
-        boolean foundSeparator = false;
-        result.mEndWithNegOrDot = false;
-        boolean secondDot = false;
-        boolean isExponential = false;
-        for (; currentIndex < s.length(); currentIndex++) {
-            boolean isPrevExponential = isExponential;
-            isExponential = false;
-            char currentChar = s.charAt(currentIndex);
-            switch (currentChar) {
-                case ' ':
-                case ',':
-                case '\t':
-                case '\n':
-                    foundSeparator = true;
-                    break;
-                case '-':
-                    // The negative sign following a 'e' or 'E' is not a separator.
-                    if (currentIndex != start && !isPrevExponential) {
-                        foundSeparator = true;
-                        result.mEndWithNegOrDot = true;
-                    }
-                    break;
-                case '.':
-                    if (!secondDot) {
-                        secondDot = true;
-                    } else {
-                        // This is the second dot, and it is considered as a separator.
-                        foundSeparator = true;
-                        result.mEndWithNegOrDot = true;
-                    }
-                    break;
-                case 'e':
-                case 'E':
-                    isExponential = true;
-                    break;
-            }
-            if (foundSeparator) {
-                break;
-            }
-        }
-        // When there is nothing found, then we put the end position to the end
-        // of the string.
-        result.mEndPosition = currentIndex;
-    }
-
-    /**
-     * Parse the floats in the string. This is an optimized version of
-     * parseFloat(s.split(",|\\s"));
-     *
-     * @param s the string containing a command and list of floats
-     *
-     * @return array of floats
-     */
-    @NonNull
-    private static float[] getFloats(@NonNull String s) {
-        if (s.charAt(0) == 'z' || s.charAt(0) == 'Z') {
-            return new float[0];
-        }
-        try {
-            float[] results = new float[s.length()];
-            int count = 0;
-            int startPosition = 1;
-            int endPosition;
-
-            ExtractFloatResult result = new ExtractFloatResult();
-            int totalLength = s.length();
-
-            // The startPosition should always be the first character of the
-            // current number, and endPosition is the character after the current
-            // number.
-            while (startPosition < totalLength) {
-                extract(s, startPosition, result);
-                endPosition = result.mEndPosition;
-
-                if (startPosition < endPosition) {
-                    results[count++] = Float.parseFloat(
-                            s.substring(startPosition, endPosition));
-                }
-
-                if (result.mEndWithNegOrDot) {
-                    // Keep the '-' or '.' sign with next number.
-                    startPosition = endPosition;
-                } else {
-                    startPosition = endPosition + 1;
-                }
-            }
-            return Arrays.copyOf(results, count);
-        } catch (NumberFormatException e) {
-            assert false : "error in parsing \"" + s + "\"" + e;
-            return new float[0];
-        }
-    }
-
-
-    private static void addNode(@NonNull ArrayList<PathDataNode> list, char cmd,
-            @NonNull float[] val) {
-        list.add(new PathDataNode(cmd, val));
-    }
-
-    private static class ExtractFloatResult {
-        // We need to return the position of the next separator and whether the
-        // next float starts with a '-' or a '.'.
-        private int mEndPosition;
-        private boolean mEndWithNegOrDot;
-    }
-
-    /**
-     * Each PathDataNode represents one command in the "d" attribute of the svg file. An array of
-     * PathDataNode can represent the whole "d" attribute.
-     */
-    public static class PathDataNode {
-        private char mType;
-        @NonNull
-        private float[] mParams;
-
-        private PathDataNode(char type, @NonNull float[] params) {
-            mType = type;
-            mParams = params;
-        }
-
-        public char getType() {
-            return mType;
-        }
-
-        @NonNull
-        public float[] getParams() {
-            return mParams;
-        }
-
-        private PathDataNode(@NonNull PathDataNode n) {
-            mType = n.mType;
-            mParams = Arrays.copyOf(n.mParams, n.mParams.length);
-        }
-
-        /**
-         * Convert an array of PathDataNode to Path. Reset the passed path as needed before
-         * calling this method.
-         *
-         * @param node The source array of PathDataNode.
-         * @param path The target Path object.
-         */
-        public static void nodesToPath(@NonNull PathDataNode[] node, @NonNull Path_Delegate path) {
-            float[] current = new float[6];
-            char previousCommand = 'm';
-            //noinspection ForLoopReplaceableByForEach
-            for (int i = 0; i < node.length; i++) {
-                addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
-                previousCommand = node[i].mType;
-            }
-        }
-
-        /**
-         * The current PathDataNode will be interpolated between the <code>nodeFrom</code> and
-         * <code>nodeTo</code> according to the <code>fraction</code>.
-         *
-         * @param nodeFrom The start value as a PathDataNode.
-         * @param nodeTo The end value as a PathDataNode
-         * @param fraction The fraction to interpolate.
-         */
-        private void interpolatePathDataNode(@NonNull PathDataNode nodeFrom,
-                @NonNull PathDataNode nodeTo, float fraction) {
-            for (int i = 0; i < nodeFrom.mParams.length; i++) {
-                mParams[i] = nodeFrom.mParams[i] * (1 - fraction)
-                        + nodeTo.mParams[i] * fraction;
-            }
-        }
-
-        @SuppressWarnings("PointlessArithmeticExpression")
-        private static void addCommand(@NonNull Path_Delegate path, float[] current,
-                char previousCmd, char cmd, @NonNull float[] val) {
-
-            int incr = 2;
-            float currentX = current[0];
-            float currentY = current[1];
-            float ctrlPointX = current[2];
-            float ctrlPointY = current[3];
-            float currentSegmentStartX = current[4];
-            float currentSegmentStartY = current[5];
-            float reflectiveCtrlPointX;
-            float reflectiveCtrlPointY;
-
-            switch (cmd) {
-                case 'z':
-                case 'Z':
-                    path.close();
-                    // Path is closed here, but we need to move the pen to the
-                    // closed position. So we cache the segment's starting position,
-                    // and restore it here.
-                    currentX = currentSegmentStartX;
-                    currentY = currentSegmentStartY;
-                    ctrlPointX = currentSegmentStartX;
-                    ctrlPointY = currentSegmentStartY;
-                    path.moveTo(currentX, currentY);
-                    break;
-                case 'm':
-                case 'M':
-                case 'l':
-                case 'L':
-                case 't':
-                case 'T':
-                    incr = 2;
-                    break;
-                case 'h':
-                case 'H':
-                case 'v':
-                case 'V':
-                    incr = 1;
-                    break;
-                case 'c':
-                case 'C':
-                    incr = 6;
-                    break;
-                case 's':
-                case 'S':
-                case 'q':
-                case 'Q':
-                    incr = 4;
-                    break;
-                case 'a':
-                case 'A':
-                    incr = 7;
-                    break;
-            }
-
-            for (int k = 0; k < val.length; k += incr) {
-                switch (cmd) {
-                    case 'm': // moveto - Start a new sub-path (relative)
-                        currentX += val[k + 0];
-                        currentY += val[k + 1];
-
-                        if (k > 0) {
-                            // According to the spec, if a moveto is followed by multiple
-                            // pairs of coordinates, the subsequent pairs are treated as
-                            // implicit lineto commands.
-                            path.rLineTo(val[k + 0], val[k + 1]);
-                        } else {
-                            path.rMoveTo(val[k + 0], val[k + 1]);
-                            currentSegmentStartX = currentX;
-                            currentSegmentStartY = currentY;
-                        }
-                        break;
-                    case 'M': // moveto - Start a new sub-path
-                        currentX = val[k + 0];
-                        currentY = val[k + 1];
-
-                        if (k > 0) {
-                            // According to the spec, if a moveto is followed by multiple
-                            // pairs of coordinates, the subsequent pairs are treated as
-                            // implicit lineto commands.
-                            path.lineTo(val[k + 0], val[k + 1]);
-                        } else {
-                            path.moveTo(val[k + 0], val[k + 1]);
-                            currentSegmentStartX = currentX;
-                            currentSegmentStartY = currentY;
-                        }
-                        break;
-                    case 'l': // lineto - Draw a line from the current point (relative)
-                        path.rLineTo(val[k + 0], val[k + 1]);
-                        currentX += val[k + 0];
-                        currentY += val[k + 1];
-                        break;
-                    case 'L': // lineto - Draw a line from the current point
-                        path.lineTo(val[k + 0], val[k + 1]);
-                        currentX = val[k + 0];
-                        currentY = val[k + 1];
-                        break;
-                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
-                        path.rLineTo(val[k + 0], 0);
-                        currentX += val[k + 0];
-                        break;
-                    case 'H': // horizontal lineto - Draws a horizontal line
-                        path.lineTo(val[k + 0], currentY);
-                        currentX = val[k + 0];
-                        break;
-                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
-                        path.rLineTo(0, val[k + 0]);
-                        currentY += val[k + 0];
-                        break;
-                    case 'V': // vertical lineto - Draws a vertical line from the current point
-                        path.lineTo(currentX, val[k + 0]);
-                        currentY = val[k + 0];
-                        break;
-                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
-                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
-                                val[k + 4], val[k + 5]);
-
-                        ctrlPointX = currentX + val[k + 2];
-                        ctrlPointY = currentY + val[k + 3];
-                        currentX += val[k + 4];
-                        currentY += val[k + 5];
-
-                        break;
-                    case 'C': // curveto - Draws a cubic Bézier curve
-                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
-                                val[k + 4], val[k + 5]);
-                        currentX = val[k + 4];
-                        currentY = val[k + 5];
-                        ctrlPointX = val[k + 2];
-                        ctrlPointY = val[k + 3];
-                        break;
-                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
-                        reflectiveCtrlPointX = 0;
-                        reflectiveCtrlPointY = 0;
-                        if (previousCmd == 'c' || previousCmd == 's'
-                                || previousCmd == 'C' || previousCmd == 'S') {
-                            reflectiveCtrlPointX = currentX - ctrlPointX;
-                            reflectiveCtrlPointY = currentY - ctrlPointY;
-                        }
-                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
-                                val[k + 0], val[k + 1],
-                                val[k + 2], val[k + 3]);
-
-                        ctrlPointX = currentX + val[k + 0];
-                        ctrlPointY = currentY + val[k + 1];
-                        currentX += val[k + 2];
-                        currentY += val[k + 3];
-                        break;
-                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
-                        reflectiveCtrlPointX = currentX;
-                        reflectiveCtrlPointY = currentY;
-                        if (previousCmd == 'c' || previousCmd == 's'
-                                || previousCmd == 'C' || previousCmd == 'S') {
-                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
-                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
-                        }
-                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
-                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
-                        ctrlPointX = val[k + 0];
-                        ctrlPointY = val[k + 1];
-                        currentX = val[k + 2];
-                        currentY = val[k + 3];
-                        break;
-                    case 'q': // Draws a quadratic Bézier (relative)
-                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
-                        ctrlPointX = currentX + val[k + 0];
-                        ctrlPointY = currentY + val[k + 1];
-                        currentX += val[k + 2];
-                        currentY += val[k + 3];
-                        break;
-                    case 'Q': // Draws a quadratic Bézier
-                        path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
-                        ctrlPointX = val[k + 0];
-                        ctrlPointY = val[k + 1];
-                        currentX = val[k + 2];
-                        currentY = val[k + 3];
-                        break;
-                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
-                        reflectiveCtrlPointX = 0;
-                        reflectiveCtrlPointY = 0;
-                        if (previousCmd == 'q' || previousCmd == 't'
-                                || previousCmd == 'Q' || previousCmd == 'T') {
-                            reflectiveCtrlPointX = currentX - ctrlPointX;
-                            reflectiveCtrlPointY = currentY - ctrlPointY;
-                        }
-                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
-                                val[k + 0], val[k + 1]);
-                        ctrlPointX = currentX + reflectiveCtrlPointX;
-                        ctrlPointY = currentY + reflectiveCtrlPointY;
-                        currentX += val[k + 0];
-                        currentY += val[k + 1];
-                        break;
-                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
-                        reflectiveCtrlPointX = currentX;
-                        reflectiveCtrlPointY = currentY;
-                        if (previousCmd == 'q' || previousCmd == 't'
-                                || previousCmd == 'Q' || previousCmd == 'T') {
-                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
-                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
-                        }
-                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
-                                val[k + 0], val[k + 1]);
-                        ctrlPointX = reflectiveCtrlPointX;
-                        ctrlPointY = reflectiveCtrlPointY;
-                        currentX = val[k + 0];
-                        currentY = val[k + 1];
-                        break;
-                    case 'a': // Draws an elliptical arc
-                        // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
-                        drawArc(path,
-                                currentX,
-                                currentY,
-                                val[k + 5] + currentX,
-                                val[k + 6] + currentY,
-                                val[k + 0],
-                                val[k + 1],
-                                val[k + 2],
-                                val[k + 3] != 0,
-                                val[k + 4] != 0);
-                        currentX += val[k + 5];
-                        currentY += val[k + 6];
-                        ctrlPointX = currentX;
-                        ctrlPointY = currentY;
-                        break;
-                    case 'A': // Draws an elliptical arc
-                        drawArc(path,
-                                currentX,
-                                currentY,
-                                val[k + 5],
-                                val[k + 6],
-                                val[k + 0],
-                                val[k + 1],
-                                val[k + 2],
-                                val[k + 3] != 0,
-                                val[k + 4] != 0);
-                        currentX = val[k + 5];
-                        currentY = val[k + 6];
-                        ctrlPointX = currentX;
-                        ctrlPointY = currentY;
-                        break;
-                }
-                previousCmd = cmd;
-            }
-            current[0] = currentX;
-            current[1] = currentY;
-            current[2] = ctrlPointX;
-            current[3] = ctrlPointY;
-            current[4] = currentSegmentStartX;
-            current[5] = currentSegmentStartY;
-        }
-
-        private static void drawArc(@NonNull Path_Delegate p, float x0, float y0, float x1,
-                float y1, float a, float b, float theta, boolean isMoreThanHalf,
-                boolean isPositiveArc) {
-
-            LOGGER.log(Level.FINE, "(" + x0 + "," + y0 + ")-(" + x1 + "," + y1
-                    + ") {" + a + " " + b + "}");
-        /* Convert rotation angle from degrees to radians */
-            double thetaD = theta * Math.PI / 180.0f;
-        /* Pre-compute rotation matrix entries */
-            double cosTheta = Math.cos(thetaD);
-            double sinTheta = Math.sin(thetaD);
-        /* Transform (x0, y0) and (x1, y1) into unit space */
-        /* using (inverse) rotation, followed by (inverse) scale */
-            double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
-            double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
-            double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
-            double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
-            LOGGER.log(Level.FINE, "unit space (" + x0p + "," + y0p + ")-(" + x1p
-                    + "," + y1p + ")");
-        /* Compute differences and averages */
-            double dx = x0p - x1p;
-            double dy = y0p - y1p;
-            double xm = (x0p + x1p) / 2;
-            double ym = (y0p + y1p) / 2;
-        /* Solve for intersecting unit circles */
-            double dsq = dx * dx + dy * dy;
-            if (dsq == 0.0) {
-                LOGGER.log(Level.FINE, " Points are coincident");
-                return; /* Points are coincident */
-            }
-            double disc = 1.0 / dsq - 1.0 / 4.0;
-            if (disc < 0.0) {
-                LOGGER.log(Level.FINE, "Points are too far apart " + dsq);
-                float adjust = (float) (Math.sqrt(dsq) / 1.99999);
-                drawArc(p, x0, y0, x1, y1, a * adjust, b * adjust, theta,
-                        isMoreThanHalf, isPositiveArc);
-                return; /* Points are too far apart */
-            }
-            double s = Math.sqrt(disc);
-            double sdx = s * dx;
-            double sdy = s * dy;
-            double cx;
-            double cy;
-            if (isMoreThanHalf == isPositiveArc) {
-                cx = xm - sdy;
-                cy = ym + sdx;
-            } else {
-                cx = xm + sdy;
-                cy = ym - sdx;
-            }
-
-            double eta0 = Math.atan2((y0p - cy), (x0p - cx));
-            LOGGER.log(Level.FINE, "eta0 = Math.atan2( " + (y0p - cy) + " , "
-                    + (x0p - cx) + ") = " + Math.toDegrees(eta0));
-
-            double eta1 = Math.atan2((y1p - cy), (x1p - cx));
-            LOGGER.log(Level.FINE, "eta1 = Math.atan2( " + (y1p - cy) + " , "
-                    + (x1p - cx) + ") = " + Math.toDegrees(eta1));
-            double sweep = (eta1 - eta0);
-            if (isPositiveArc != (sweep >= 0)) {
-                if (sweep > 0) {
-                    sweep -= 2 * Math.PI;
-                } else {
-                    sweep += 2 * Math.PI;
-                }
-            }
-
-            cx *= a;
-            cy *= b;
-            double tcx = cx;
-            cx = cx * cosTheta - cy * sinTheta;
-            cy = tcx * sinTheta + cy * cosTheta;
-            LOGGER.log(
-                    Level.FINE,
-                    "cx, cy, a, b, x0, y0, thetaD, eta0, sweep = " + cx + " , "
-                            + cy + " , " + a + " , " + b + " , " + x0 + " , " + y0
-                            + " , " + Math.toDegrees(thetaD) + " , "
-                            + Math.toDegrees(eta0) + " , " + Math.toDegrees(sweep));
-
-            arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
-        }
-
-        /**
-         * Converts an arc to cubic Bezier segments and records them in p.
-         *
-         * @param p The target for the cubic Bezier segments
-         * @param cx The x coordinate center of the ellipse
-         * @param cy The y coordinate center of the ellipse
-         * @param a The radius of the ellipse in the horizontal direction
-         * @param b The radius of the ellipse in the vertical direction
-         * @param e1x E(eta1) x coordinate of the starting point of the arc
-         * @param e1y E(eta2) y coordinate of the starting point of the arc
-         * @param theta The angle that the ellipse bounding rectangle makes with the horizontal
-         * plane
-         * @param start The start angle of the arc on the ellipse
-         * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
-         */
-        private static void arcToBezier(@NonNull Path_Delegate p, double cx, double cy, double a,
-                double b, double e1x, double e1y, double theta, double start,
-                double sweep) {
-            // Taken from equations at:
-            // http://spaceroots.org/documents/ellipse/node8.html
-            // and http://www.spaceroots.org/documents/ellipse/node22.html
-            // Maximum of 45 degrees per cubic Bezier segment
-            int numSegments = (int) Math.ceil(Math.abs(sweep * 4 / Math.PI));
-
-
-            double eta1 = start;
-            double cosTheta = Math.cos(theta);
-            double sinTheta = Math.sin(theta);
-            double cosEta1 = Math.cos(eta1);
-            double sinEta1 = Math.sin(eta1);
-            double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
-            double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
-
-            double anglePerSegment = sweep / numSegments;
-            for (int i = 0; i < numSegments; i++) {
-                double eta2 = eta1 + anglePerSegment;
-                double sinEta2 = Math.sin(eta2);
-                double cosEta2 = Math.cos(eta2);
-                double e2x = cx + (a * cosTheta * cosEta2)
-                        - (b * sinTheta * sinEta2);
-                double e2y = cy + (a * sinTheta * cosEta2)
-                        + (b * cosTheta * sinEta2);
-                double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
-                double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
-                double tanDiff2 = Math.tan((eta2 - eta1) / 2);
-                double alpha = Math.sin(eta2 - eta1)
-                        * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
-                double q1x = e1x + alpha * ep1x;
-                double q1y = e1y + alpha * ep1y;
-                double q2x = e2x - alpha * ep2x;
-                double q2y = e2y - alpha * ep2y;
-
-                p.cubicTo((float) q1x,
-                        (float) q1y,
-                        (float) q2x,
-                        (float) q2y,
-                        (float) e2x,
-                        (float) e2y);
-                eta1 = eta2;
-                e1x = e2x;
-                e1y = e2y;
-                ep1x = ep2x;
-                ep1y = ep2y;
-            }
-        }
-    }
-}
diff --git a/bridge/src/android/util/imagepool/Bucket.java b/bridge/src/android/util/imagepool/Bucket.java
deleted file mode 100644
index c562243..0000000
--- a/bridge/src/android/util/imagepool/Bucket.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.util.imagepool;
-
-import com.android.tools.layoutlib.annotations.Nullable;
-import com.android.tools.layoutlib.annotations.VisibleForTesting;
-
-import android.util.imagepool.ImagePool.Image.Orientation;
-
-import java.awt.image.BufferedImage;
-import java.lang.ref.SoftReference;
-import java.util.LinkedList;
-import java.util.Queue;
-
-/**
- * Data model for image pool. Bucket contains the list of same sized buffered image in soft ref.
- */
-/* private package */ class Bucket {
-
-    @VisibleForTesting final Queue<SoftReference<BufferedImage>> mBufferedImageRef = new LinkedList<>();
-
-    public boolean isEmpty() {
-        return mBufferedImageRef.isEmpty();
-    }
-
-    @Nullable
-    public BufferedImage remove() {
-        if (mBufferedImageRef.isEmpty()) {
-            return null;
-        }
-
-        SoftReference<BufferedImage> reference = mBufferedImageRef.remove();
-        return reference == null ? null : reference.get();
-    }
-
-    public void offer(BufferedImage img) {
-        mBufferedImageRef.offer(new SoftReference<>(img));
-    }
-
-    public void clear() {
-        mBufferedImageRef.clear();
-    }
-
-    static class BucketCreationMetaData {
-        public final int mWidth;
-        public final int mHeight;
-        public final int mType;
-        public final int mNumberOfCopies;
-        public final Orientation mOrientation;
-        public final long mMaxCacheSize;
-
-        BucketCreationMetaData(int width, int height, int type, int numberOfCopies,
-                Orientation orientation, long maxCacheSize) {
-            mWidth = width;
-            mHeight = height;
-            mType = type;
-            mNumberOfCopies = numberOfCopies;
-            mOrientation = orientation;
-            mMaxCacheSize = maxCacheSize;
-        }
-    }
-}
\ No newline at end of file
diff --git a/bridge/src/android/util/imagepool/ImageImpl.java b/bridge/src/android/util/imagepool/ImageImpl.java
deleted file mode 100644
index 42a6e73..0000000
--- a/bridge/src/android/util/imagepool/ImageImpl.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.util.imagepool;
-
-import com.android.tools.layoutlib.annotations.NotNull;
-import com.android.tools.layoutlib.annotations.Nullable;
-import com.android.tools.layoutlib.annotations.VisibleForTesting;
-import java.awt.Graphics2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.ImageObserver;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * Representation of buffered image. When used with ImagePool, it provides 2 features
- * (last one not yet impl'd):
- *
- * <ul>
- *   <li>Automatic recycle of BufferedImage through use of reference counter</li>
- *   <li>Able to re-use the image for similar size of buffered image</li>
- *   <li>TODO: Able to re-use the iamge for different orientation (not yet impl'd)</li>
- * </ul>
- */
-/* private package */ class ImageImpl implements ImagePool.Image {
-
-    private final ReadWriteLock mLock = new ReentrantReadWriteLock();
-
-    private final int mWidth;
-    private final int mHeight;
-    private final Orientation mOrientation;
-
-    @VisibleForTesting final BufferedImage mImg;
-
-    ImageImpl(
-            int width,
-            int height,
-            @NotNull BufferedImage img,
-            Orientation orientation) {
-        mImg = img;
-        mWidth = width;
-        mHeight = height;
-        mOrientation = orientation;
-    }
-
-    @Override
-    public int getWidth() {
-        return mWidth;
-    }
-
-    @Override
-    public int getHeight() {
-        return mHeight;
-    }
-
-    @Override
-    public void setRGB(int x, int y, int width, int height, int[] colors, int offset, int stride) {
-        mLock.readLock().lock();
-        try {
-            // TODO: Apply orientation.
-            mImg.setRGB(x, y, width, height, colors, offset, stride);
-        } finally {
-            mLock.readLock().unlock();
-        }
-    }
-
-    @Override
-    public void drawImage(Graphics2D graphics, int x, int y, @Nullable ImageObserver o) {
-        mLock.readLock().lock();
-        try {
-            // TODO: Apply orientation.
-            graphics.drawImage(mImg, x, y, mWidth, mHeight, o);
-        } finally {
-            mLock.readLock().unlock();
-        }
-    }
-}
\ No newline at end of file
diff --git a/bridge/src/android/util/imagepool/ImagePool.java b/bridge/src/android/util/imagepool/ImagePool.java
deleted file mode 100644
index baec65d..0000000
--- a/bridge/src/android/util/imagepool/ImagePool.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.util.imagepool;
-
-import com.android.tools.layoutlib.annotations.NotNull;
-
-import java.awt.Graphics2D;
-import java.awt.Image;
-import java.awt.image.BufferedImage;
-import java.awt.image.ImageObserver;
-import java.util.function.Consumer;
-
-/**
- * Simplified version of image pool that exists in Studio.
- *
- * Lacks:
- * - PhantomReference and FinalizableReference to recognize the death of references automatically.
- *   (Meaning devs need to be more deligent in dispose.)
- * Has:
- * + Debugger that allows us to better trace where image is being leaked in stack.
- */
-public interface ImagePool {
-
-    /**
-     * Returns a new image of width w and height h.
-     */
-    @NotNull
-    Image acquire(final int w, final int h, final int type);
-
-    /**
-     * Disposes the image pool, releasing all the references to the buffered images.
-     */
-    void dispose();
-
-    /**
-     * Interface that represents a buffered image. Using this wrapper allows us ot better track
-     * memory usages around BufferedImage. When all of it's references are removed, it will
-     * automatically be pooled back into the image pool for re-use.
-     */
-    interface Image {
-
-        /**
-         * Same as {@link BufferedImage#setRGB(int, int, int, int, int[], int, int)}
-         */
-        void setRGB(int x, int y, int width, int height, int[] colors, int offset, int stride);
-
-        /**
-         * Same as {@link Graphics2D#drawImage(java.awt.Image, int, int, ImageObserver)}
-         */
-        void drawImage(Graphics2D graphics, int x, int y, ImageObserver o);
-
-        /**
-         * Image orientation. It's not used at the moment. To be used later.
-         */
-        enum Orientation {
-            NONE,
-            CW_90
-        }
-
-        int getWidth();
-        int getHeight();
-    }
-
-    /**
-     * Policy for how to set up the memory pool.
-     */
-    class ImagePoolPolicy {
-
-        public final int[] mBucketSizes;
-        public final int[] mNumberOfCopies;
-        public final long mBucketMaxCacheSize;
-
-        /**
-         * @param bucketPixelSizes - list of pixel sizes to bucket (categorize) images. The list
-         * must be sorted (low to high).
-         * @param numberOfCopies - Allows users to create multiple copies of the bucket. It is
-         * recommended to create more copies for smaller images to avoid fragmentation in memory.
-         * It must match the size of bucketPixelSizes.
-         * @param bucketMaxCacheByteSize - Maximum cache byte sizes image pool is allowed to hold onto
-         * in memory.
-         */
-        public ImagePoolPolicy(
-                int[] bucketPixelSizes, int[] numberOfCopies, long bucketMaxCacheByteSize) {
-            assert bucketPixelSizes.length == numberOfCopies.length;
-            mBucketSizes = bucketPixelSizes;
-            mNumberOfCopies = numberOfCopies;
-            mBucketMaxCacheSize = bucketMaxCacheByteSize;
-        }
-    }
-}
diff --git a/bridge/src/android/util/imagepool/ImagePoolHelper.java b/bridge/src/android/util/imagepool/ImagePoolHelper.java
deleted file mode 100644
index 292fc59..0000000
--- a/bridge/src/android/util/imagepool/ImagePoolHelper.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.util.imagepool;
-
-import com.android.tools.layoutlib.annotations.Nullable;
-
-import android.util.imagepool.Bucket.BucketCreationMetaData;
-import android.util.imagepool.ImagePool.Image.Orientation;
-import android.util.imagepool.ImagePool.ImagePoolPolicy;
-
-import java.awt.image.BufferedImage;
-import java.util.Map;
-
-/* private package */ class ImagePoolHelper {
-
-    @Nullable
-    public static BucketCreationMetaData getBucketCreationMetaData(int w, int h, int type, ImagePoolPolicy poolPolicy, ImagePoolStats stats) {
-        // Find the bucket sizes for both dimensions
-        int widthBucket = -1;
-        int heightBucket = -1;
-        int index = 0;
-
-        for (int bucketMinSize : poolPolicy.mBucketSizes) {
-            if (widthBucket == -1 && w <= bucketMinSize) {
-                widthBucket = bucketMinSize;
-
-                if (heightBucket != -1) {
-                    break;
-                }
-            }
-            if (heightBucket == -1 && h <= bucketMinSize) {
-                heightBucket = bucketMinSize;
-
-                if (widthBucket != -1) {
-                    break;
-                }
-            }
-            ++index;
-        }
-
-        stats.recordBucketRequest(w, h);
-
-        if (index >= poolPolicy.mNumberOfCopies.length) {
-            return null;
-        }
-
-        // TODO: Apply orientation
-//        if (widthBucket < heightBucket) {
-//            return new BucketCreationMetaData(heightBucket, widthBucket, type, poolPolicy.mNumberOfCopies[index],
-//                    Orientation.CW_90, poolPolicy.mBucketMaxCacheSize);
-//        }
-        return new BucketCreationMetaData(widthBucket, heightBucket, type, poolPolicy.mNumberOfCopies[index],
-                Orientation.NONE, poolPolicy.mBucketMaxCacheSize);
-    }
-
-    @Nullable
-    public static BufferedImage getBufferedImage(
-            Bucket bucket, BucketCreationMetaData metaData, ImagePoolStats stats) {
-
-        // strongref is just for gc.
-        BufferedImage strongRef = populateBucket(bucket, metaData, stats);
-
-        // pool is too small to create the requested buffer.
-        if (bucket.isEmpty()) {
-            assert strongRef == null;
-            return null;
-        }
-
-        // Go through the bucket of soft references to find the first buffer that's not null.
-        // Even if gc is triggered here, strongref should survive.
-        BufferedImage img = bucket.remove();
-        while (img == null && !bucket.isEmpty()) {
-            img = bucket.remove();
-        }
-
-        if (img == null && bucket.isEmpty()) {
-            // Whole buffer was null. Recurse.
-            return getBufferedImage(bucket, metaData, stats);
-        }
-        return img;
-    }
-
-    /**
-     * Populate the bucket in greedy manner to avoid fragmentation.
-     * Behaviour is controlled by {@link ImagePoolPolicy}.
-     * Returns one strong referenced buffer to avoid getting results gc'd. Null if pool is not large
-     * enough.
-     */
-    @Nullable
-    private static BufferedImage populateBucket(
-            Bucket bucket, BucketCreationMetaData metaData, ImagePoolStats stats) {
-        if (!bucket.isEmpty()) {
-            // If not empty no need to populate.
-            return null;
-        }
-
-        BufferedImage strongRef = null;
-        for (int i = 0; i < metaData.mNumberOfCopies; i++) {
-            if (!stats.fitsMaxCacheSize(
-                    metaData.mWidth, metaData.mHeight, metaData.mMaxCacheSize)) {
-                break;
-            }
-            strongRef =new BufferedImage(metaData.mWidth, metaData.mHeight,
-                    metaData.mType);
-            bucket.offer(strongRef);
-            stats.recordBucketCreation(metaData.mWidth, metaData.mHeight);
-        }
-        return strongRef;
-    }
-
-    private static String toKey(int w, int h, int type) {
-        return new StringBuilder()
-                .append(w)
-                .append('x')
-                .append(h)
-                .append(':')
-                .append(type)
-                .toString();
-    }
-
-    public static Bucket getBucket(Map<String, Bucket> map, BucketCreationMetaData metaData, ImagePoolPolicy mPolicy) {
-        String key = toKey(metaData.mWidth, metaData.mHeight, metaData.mType);
-        Bucket bucket = map.get(key);
-        if (bucket == null) {
-            bucket = new Bucket();
-            map.put(key, bucket);
-        }
-        return bucket;
-    }
-}
\ No newline at end of file
diff --git a/bridge/src/android/util/imagepool/ImagePoolImpl.java b/bridge/src/android/util/imagepool/ImagePoolImpl.java
deleted file mode 100644
index 3da706e..0000000
--- a/bridge/src/android/util/imagepool/ImagePoolImpl.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.util.imagepool;
-
-import com.android.tools.layoutlib.annotations.Nullable;
-import com.android.tools.layoutlib.annotations.VisibleForTesting;
-
-import android.util.imagepool.Bucket.BucketCreationMetaData;
-import android.util.imagepool.ImagePool.Image.Orientation;
-
-import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferInt;
-import java.lang.ref.Reference;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.function.Consumer;
-
-import com.google.common.base.FinalizablePhantomReference;
-import com.google.common.base.FinalizableReferenceQueue;
-
-class ImagePoolImpl implements ImagePool {
-
-    private final ReentrantReadWriteLock mReentrantLock = new ReentrantReadWriteLock();
-    private final ImagePoolPolicy mPolicy;
-    @VisibleForTesting final Map<String, Bucket> mPool = new HashMap<>();
-    @VisibleForTesting final ImagePoolStats mImagePoolStats = new ImagePoolStatsProdImpl();
-    private final FinalizableReferenceQueue mFinalizableReferenceQueue = new FinalizableReferenceQueue();
-    private final Set<Reference<?>> mReferences = new HashSet<>();
-
-    public ImagePoolImpl(ImagePoolPolicy policy) {
-        mPolicy = policy;
-        mImagePoolStats.start();
-    }
-
-    @Override
-    public Image acquire(int w, int h, int type) {
-        return acquire(w, h, type, null);
-    }
-
-    /* package private */ Image acquire(int w, int h, int type,
-            @Nullable Consumer<BufferedImage> freedCallback) {
-        mReentrantLock.writeLock().lock();
-        try {
-            BucketCreationMetaData metaData =
-                    ImagePoolHelper.getBucketCreationMetaData(w, h, type, mPolicy, mImagePoolStats);
-            if (metaData == null) {
-                return defaultImageImpl(w, h, type, freedCallback);
-            }
-
-            final Bucket existingBucket = ImagePoolHelper.getBucket(mPool, metaData, mPolicy);
-            final BufferedImage img =
-                    ImagePoolHelper.getBufferedImage(existingBucket, metaData, mImagePoolStats);
-            if (img == null) {
-                return defaultImageImpl(w, h, type, freedCallback);
-            }
-
-            // Clear the image. - is this necessary?
-            if (img.getRaster().getDataBuffer().getDataType() == java.awt.image.DataBuffer.TYPE_INT) {
-                Arrays.fill(((DataBufferInt)img.getRaster().getDataBuffer()).getData(), 0);
-            }
-
-            return prepareImage(
-                    new ImageImpl(w, h, img, metaData.mOrientation),
-                    true,
-                    img,
-                    existingBucket,
-                    freedCallback);
-        } finally {
-            mReentrantLock.writeLock().unlock();
-        }
-    }
-
-    /**
-     * Add statistics as well as dispose behaviour before returning image.
-     */
-    private Image prepareImage(
-            Image image,
-            boolean offerBackToBucket,
-            @Nullable BufferedImage img,
-            @Nullable Bucket existingBucket,
-            @Nullable Consumer<BufferedImage> freedCallback) {
-        final Integer imageHash = image.hashCode();
-        mImagePoolStats.acquiredImage(imageHash);
-        FinalizablePhantomReference<Image> reference =
-                new FinalizablePhantomReference<ImagePool.Image>(image, mFinalizableReferenceQueue) {
-                    @Override
-                    public void finalizeReferent() {
-                        // This method might be called twice if the user has manually called the free() method. The second call will have no effect.
-                        if (mReferences.remove(this)) {
-                            mImagePoolStats.disposeImage(imageHash);
-                            if (offerBackToBucket) {
-                                if (!mImagePoolStats.fitsMaxCacheSize(img.getWidth(), img.getHeight(),
-                                        mPolicy.mBucketMaxCacheSize)) {
-                                    mImagePoolStats.tooBigForCache();
-                                    // Adding this back would go over the max cache size we set for ourselves. Release it.
-                                    return;
-                                }
-
-                                // else stat does not change.
-                                existingBucket.offer(img);
-                            }
-                            if (freedCallback != null) {
-                                freedCallback.accept(img);
-                            }
-                        }
-                    }
-                };
-        mReferences.add(reference);
-        return image;
-    }
-
-    /**
-     * Default Image Impl to be used when the pool is not big enough.
-     */
-    private Image defaultImageImpl(int w, int h, int type,
-            @Nullable Consumer<BufferedImage> freedCallback) {
-        BufferedImage bufferedImage = new BufferedImage(w, h, type);
-        mImagePoolStats.tooBigForCache();
-        mImagePoolStats.recordAllocOutsidePool(w, h);
-        return prepareImage(new ImageImpl(w, h, bufferedImage, Orientation.NONE),
-                false,  null, null, freedCallback);
-    }
-
-    @Override
-    public void dispose() {
-        mReentrantLock.writeLock().lock();
-        try {
-            for (Bucket bucket : mPool.values()) {
-                bucket.clear();
-            }
-            mImagePoolStats.clear();
-        } finally {
-            mReentrantLock.writeLock().unlock();
-        }
-    }
-
-    /* package private */ void printStat() {
-        System.out.println(mImagePoolStats.getStatistic());
-    }
-}
\ No newline at end of file
diff --git a/bridge/src/android/util/imagepool/ImagePoolProvider.java b/bridge/src/android/util/imagepool/ImagePoolProvider.java
deleted file mode 100644
index dbdd849..0000000
--- a/bridge/src/android/util/imagepool/ImagePoolProvider.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.util.imagepool;
-
-import com.android.tools.layoutlib.annotations.NotNull;
-
-import android.util.imagepool.ImagePool.ImagePoolPolicy;
-
-public class ImagePoolProvider {
-
-    private static ImagePool sInstance;
-
-    @NotNull
-    public static synchronized ImagePool get() {
-        if (sInstance == null) {
-            // Idea is to create more
-            ImagePoolPolicy policy = new ImagePoolPolicy(
-                    new int[]{100, 200, 400, 600, 800, 1000, 1600, 3200},
-                    new int[]{  3,   3,   2,   2,   2,    1,    1,    1},
-                    10_000_000L); // 10 MB
-
-            sInstance = new ImagePoolImpl(policy);
-        }
-        return sInstance;
-    }
-}
\ No newline at end of file
diff --git a/bridge/src/android/util/imagepool/ImagePoolStats.java b/bridge/src/android/util/imagepool/ImagePoolStats.java
deleted file mode 100644
index 17dab14..0000000
--- a/bridge/src/android/util/imagepool/ImagePoolStats.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.util.imagepool;
-
-/**
- * Keeps track of statistics. Some are purely for debugging purposes in which case it's wrapped
- * around DEBUG check.
- */
-interface ImagePoolStats {
-
-    void recordBucketCreation(int widthBucket, int heightBucket);
-
-    boolean fitsMaxCacheSize(int width, int height, long maxCacheSize);
-
-    void clear();
-
-    void recordBucketRequest(int w, int h);
-
-    void recordAllocOutsidePool(int width, int height);
-
-    void tooBigForCache();
-
-    void acquiredImage(Integer imageHash);
-
-    void disposeImage(Integer imageHash);
-
-    void start();
-
-    String getStatistic();
-}
diff --git a/bridge/src/android/util/imagepool/ImagePoolStatsDebugImpl.java b/bridge/src/android/util/imagepool/ImagePoolStatsDebugImpl.java
deleted file mode 100644
index de0f757..0000000
--- a/bridge/src/android/util/imagepool/ImagePoolStatsDebugImpl.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.util.imagepool;
-
-import java.lang.management.GarbageCollectorMXBean;
-import java.lang.management.ManagementFactory;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.google.common.collect.HashMultiset;
-import com.google.common.collect.Multiset;
-
-/**
- * Useful impl for debugging reproable error.
- */
-public class ImagePoolStatsDebugImpl extends ImagePoolStatsProdImpl {
-
-    private static String PACKAGE_NAME = ImagePoolStats.class.getPackage().getName();
-
-    // Used for deugging purposes only.
-    private final Map<Integer, String> mCallStack = new HashMap<>();
-    private long mRequestedTotalBytes = 0;
-    private long mAllocatedOutsidePoolBytes = 0;
-
-    // Used for gc-related stats.
-    private long mPreviousGcCollection = 0;
-    private long mPreviousGcTime = 0;
-
-    /** Used for policy */
-    @Override
-    public void recordBucketCreation(int widthBucket, int heightBucket) {
-        super.recordBucketCreation(widthBucket, heightBucket);
-    }
-
-    @Override
-    public boolean fitsMaxCacheSize(int width, int height, long maxCacheSize) {
-        return super.fitsMaxCacheSize(width, height, maxCacheSize);
-    }
-
-    @Override
-    public void clear() {
-        super.clear();
-
-        mRequestedTotalBytes = 0;
-        mAllocatedOutsidePoolBytes = 0;
-        mTooBigForPoolCount = 0;
-        mCallStack.clear();
-    }
-
-    @Override
-    public void tooBigForCache() {
-        super.tooBigForCache();
-    }
-
-    /** Used for Debugging only */
-    @Override
-    public void recordBucketRequest(int w, int h) {
-        mRequestedTotalBytes += (w * h * ESTIMATED_PIXEL_BYTES);
-    }
-
-    @Override
-    public void recordAllocOutsidePool(int width, int height) {
-        mAllocatedOutsidePoolBytes += (width * height * ESTIMATED_PIXEL_BYTES);
-    }
-
-    @Override
-    public void acquiredImage(Integer imageHash) {
-        for (int i = 1; i < Thread.currentThread().getStackTrace().length; i++) {
-            StackTraceElement element = Thread.currentThread().getStackTrace()[i];
-            String str = element.toString();
-
-            if (!str.contains(PACKAGE_NAME)) {
-                mCallStack.put(imageHash, str);
-                break;
-            }
-        }
-    }
-
-    @Override
-    public void disposeImage(Integer imageHash) {
-        mCallStack.remove(imageHash);
-    }
-
-    @Override
-    public void start() {
-        long totalGarbageCollections = 0;
-        long garbageCollectionTime = 0;
-        for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
-            long count = gc.getCollectionCount();
-            if (count >= 0) {
-                totalGarbageCollections += count;
-            }
-            long time = gc.getCollectionTime();
-            if (time >= 0) {
-                garbageCollectionTime += time;
-            }
-        }
-        mPreviousGcCollection = totalGarbageCollections;
-        mPreviousGcTime = garbageCollectionTime;
-    }
-
-    private String calculateGcStatAndReturn() {
-        long totalGarbageCollections = 0;
-        long garbageCollectionTime = 0;
-        for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) {
-            long count = gc.getCollectionCount();
-            if (count > 0) {
-                totalGarbageCollections += count;
-            }
-            long time = gc.getCollectionTime();
-            if(time > 0) {
-                garbageCollectionTime += time;
-            }
-        }
-        totalGarbageCollections -= mPreviousGcCollection;
-        garbageCollectionTime -= mPreviousGcTime;
-
-        StringBuilder builder = new StringBuilder();
-        builder.append("Total Garbage Collections: ");
-        builder.append(totalGarbageCollections);
-        builder.append("\n");
-
-        builder.append("Total Garbage Collection Time (ms): ");
-        builder.append(garbageCollectionTime);
-        builder.append("\n");
-
-        return builder.toString();
-    }
-
-    @Override
-    public String getStatistic() {
-        StringBuilder builder = new StringBuilder();
-
-        builder.append(calculateGcStatAndReturn());
-        builder.append("Memory\n");
-        builder.append(" requested total         : ");
-        builder.append(mRequestedTotalBytes / 1_000_000);
-        builder.append(" MB\n");
-        builder.append(" allocated (in pool)     : ");
-        builder.append(mAllocateTotalBytes / 1_000_000);
-        builder.append(" MB\n");
-        builder.append(" allocated (out of pool) : ");
-        builder.append(mAllocatedOutsidePoolBytes / 1_000_000);
-        builder.append(" MB\n");
-
-        double percent = (1.0 - (double) mRequestedTotalBytes / (mAllocateTotalBytes +
-                mAllocatedOutsidePoolBytes));
-        if (percent < 0.0) {
-            builder.append(" saved : ");
-            builder.append(-1.0 * percent);
-            builder.append("%\n");
-        } else {
-            builder.append(" wasting : ");
-            builder.append(percent);
-            builder.append("%\n");
-        }
-
-        builder.append("Undispose images\n");
-        Multiset<String> countSet = HashMultiset.create();
-        for (String callsite : mCallStack.values()) {
-            countSet.add(callsite);
-        }
-
-        for (Multiset.Entry<String> entry : countSet.entrySet()) {
-            builder.append(" - ");
-            builder.append(entry.getElement());
-            builder.append(" - missed dispose : ");
-            builder.append(entry.getCount());
-            builder.append(" times\n");
-        }
-
-        builder.append("Number of times requested image didn't fit the pool : ");
-        builder.append(mTooBigForPoolCount);
-        builder.append("\n");
-
-        return builder.toString();
-    }
-}
diff --git a/bridge/src/android/util/imagepool/ImagePoolStatsProdImpl.java b/bridge/src/android/util/imagepool/ImagePoolStatsProdImpl.java
deleted file mode 100644
index e6c6abe..0000000
--- a/bridge/src/android/util/imagepool/ImagePoolStatsProdImpl.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.util.imagepool;
-
-import com.android.tools.layoutlib.annotations.NotNull;
-import com.android.tools.layoutlib.annotations.VisibleForTesting;
-
-class ImagePoolStatsProdImpl implements ImagePoolStats {
-
-    static int ESTIMATED_PIXEL_BYTES = 4;
-
-    // Used for determining how many buckets can be created.
-    @VisibleForTesting long mAllocateTotalBytes = 0;
-    @VisibleForTesting int mTooBigForPoolCount = 0;
-
-    /** Used for policy */
-    @Override
-    public void recordBucketCreation(int widthBucket, int heightBucket) {
-        mAllocateTotalBytes += (widthBucket * heightBucket * ESTIMATED_PIXEL_BYTES);
-    }
-
-    @Override
-    public boolean fitsMaxCacheSize(int width, int height, long maxCacheSize) {
-        long newTotal = mAllocateTotalBytes + (width * height * ESTIMATED_PIXEL_BYTES);
-        return newTotal <= maxCacheSize;
-    }
-
-    @Override
-    public void tooBigForCache() {
-        mTooBigForPoolCount++;
-    }
-
-    @Override
-    public void clear() {
-        mAllocateTotalBytes = 0;
-    }
-
-    @Override
-    public void recordBucketRequest(int w, int h) { }
-
-    @Override
-    public void recordAllocOutsidePool(int width, int height) { }
-
-    @Override
-    public void acquiredImage(@NotNull Integer imageHash) { }
-
-    @Override
-    public void disposeImage(@NotNull Integer imageHash) { }
-
-    @Override
-    public void start() { }
-
-    @Override
-    public String getStatistic() { return ""; }
-}
diff --git a/bridge/src/android/view/AttachInfo_Accessor.java b/bridge/src/android/view/AttachInfo_Accessor.java
index 60c13c0..0efafdb 100644
--- a/bridge/src/android/view/AttachInfo_Accessor.java
+++ b/bridge/src/android/view/AttachInfo_Accessor.java
@@ -20,7 +20,7 @@
 import android.os.Handler;
 import android.view.View.AttachInfo;
 
-import com.android.layoutlib.bridge.util.ReflectionUtils;
+import com.android.layoutlib.common.util.ReflectionUtils;
 
 /**
  * Class allowing access to package-protected methods/fields.
@@ -38,7 +38,9 @@
         info.mHasWindowFocus = true;
         info.mWindowVisibility = View.VISIBLE;
         info.mInTouchMode = false; // this is so that we can display selections.
-        info.mHardwareAccelerated = false;
+        info.mHardwareAccelerated = true;
+        // We do not use this one at all, it is only needed to satisfy null checks in View
+        info.mThreadedRenderer = new ThreadedRenderer(context, false, "layoutlib-renderer");
         view.dispatchAttachedToWindow(info, 0);
     }
 
@@ -46,9 +48,16 @@
         view.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
     }
 
-    public static void detachFromWindow(View view) {
+    public static void detachFromWindow(final View view) {
         if (view != null) {
+            final View.AttachInfo attachInfo = view.mAttachInfo;
             view.dispatchDetachedFromWindow();
+            if (attachInfo != null) {
+                final ThreadedRenderer threadedRenderer = attachInfo.mThreadedRenderer;
+                if(threadedRenderer != null) {
+                    threadedRenderer.destroy();
+                }
+            }
         }
     }
 
diff --git a/bridge/src/android/view/BridgeInflater.java b/bridge/src/android/view/BridgeInflater.java
index dfb46f2..53043a0 100644
--- a/bridge/src/android/view/BridgeInflater.java
+++ b/bridge/src/android/view/BridgeInflater.java
@@ -31,7 +31,7 @@
 import com.android.layoutlib.bridge.android.support.DrawerLayoutUtil;
 import com.android.layoutlib.bridge.android.support.RecyclerViewUtil;
 import com.android.layoutlib.bridge.impl.ParserFactory;
-import com.android.layoutlib.bridge.util.ReflectionUtils;
+import com.android.layoutlib.common.util.ReflectionUtils;
 import com.android.tools.layoutlib.annotations.NotNull;
 import com.android.tools.layoutlib.annotations.Nullable;
 
diff --git a/bridge/src/android/view/Choreographer_CallbackRecord_Delegate.java b/bridge/src/android/view/Choreographer_CallbackRecord_Delegate.java
new file mode 100644
index 0000000..ac5b96a
--- /dev/null
+++ b/bridge/src/android/view/Choreographer_CallbackRecord_Delegate.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.view;
+
+import com.android.layoutlib.bridge.util.CallbacksDisposer.SessionKey;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.view.Choreographer.CallbackRecord;
+
+import static com.android.layoutlib.bridge.impl.RenderAction.getCurrentContext;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link CallbackRecord}
+ *
+ * Through the layoutlib_create tool, the original methods of {@link CallbackRecord} have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ */
+public class Choreographer_CallbackRecord_Delegate {
+    @LayoutlibDelegate
+    public static void run(CallbackRecord thiz, long frameTimeNanos) {
+        SessionKey sessionKey = new SessionKey(getCurrentContext());
+        if (Choreographer_Delegate.sCallbacksDisposer.onCallbackRemoved(sessionKey, thiz.action)) {
+            // The callback is for this session and we can execute it
+            thiz.run_Original(frameTimeNanos);
+        } else {
+            // The callback is for another session, we should put it back using the minimum
+            // delay (but not now to prevent potential infinite loop).
+            Choreographer.getInstance().postCallbackDelayedInternal_Original(
+                    Choreographer.CALLBACK_ANIMATION, thiz.action, thiz.token, 1);
+        }
+    }
+}
diff --git a/bridge/src/android/view/Choreographer_Delegate.java b/bridge/src/android/view/Choreographer_Delegate.java
index 1dc7778..5381b47 100644
--- a/bridge/src/android/view/Choreographer_Delegate.java
+++ b/bridge/src/android/view/Choreographer_Delegate.java
@@ -15,13 +15,18 @@
  */
 package android.view;
 
+import com.android.ide.common.rendering.api.ILayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.util.CallbacksDisposer;
+import com.android.layoutlib.bridge.util.CallbacksDisposer.SessionKey;
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.android.tools.layoutlib.annotations.NotNull;
 
-import android.animation.AnimationHandler;
-import android.util.TimeUtils;
-import android.view.animation.AnimationUtils;
+import android.view.Choreographer.FrameCallback;
 
-import java.util.concurrent.atomic.AtomicReference;
+import static android.content.Context.LAYOUT_INFLATER_SERVICE;
+import static com.android.layoutlib.bridge.impl.RenderAction.getCurrentContext;
 
 /**
  * Delegate used to provide new implementation of a select few methods of {@link Choreographer}
@@ -31,16 +36,21 @@
  *
  */
 public class Choreographer_Delegate {
-    private static final AtomicReference<Choreographer> mInstance = new AtomicReference<Choreographer>();
-
-    @LayoutlibDelegate
-    public static Choreographer getInstance() {
-        if (mInstance.get() == null) {
-            mInstance.compareAndSet(null, Choreographer.getInstance_Original());
+    static final CallbacksDisposer sCallbacksDisposer = new CallbacksDisposer(
+        action -> {
+            if (action instanceof FrameCallback) {
+                FrameCallback callback = (FrameCallback) action;
+                Choreographer.getInstance().removeFrameCallback(callback);
+            } else if (action instanceof Runnable) {
+                Runnable runnable = (Runnable) action;
+                Choreographer.getInstance().removeCallbacksInternal_Original(
+                        Choreographer.CALLBACK_ANIMATION, runnable, null);
+            } else {
+                Bridge.getLog().error(ILayoutLog.TAG_BROKEN,
+                        "Unexpected action as " + "ANIMATION_CALLBACK", (Object) null, null);
+            }
         }
-
-        return mInstance.get();
-    }
+    );
 
     @LayoutlibDelegate
     public static float getRefreshRate() {
@@ -48,46 +58,44 @@
     }
 
     @LayoutlibDelegate
-    static void scheduleVsyncLocked(Choreographer thisChoreographer) {
-        // do nothing
-    }
-
-    public static void doFrame(long frameTimeNanos) {
-        Choreographer thisChoreographer = Choreographer.getInstance();
-
-        AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
-
-        try {
-            thisChoreographer.mLastFrameTimeNanos = frameTimeNanos - thisChoreographer.getFrameIntervalNanos();
-            thisChoreographer.mFrameInfo.markInputHandlingStart();
-            thisChoreographer.doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
-
-            thisChoreographer.mFrameInfo.markAnimationsStart();
-            thisChoreographer.doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
-
-            thisChoreographer.mFrameInfo.markPerformTraversalsStart();
-            thisChoreographer.doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
-
-            thisChoreographer.doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
-        } finally {
-            AnimationUtils.unlockAnimationClock();
+    public static void postCallbackDelayedInternal(
+            Choreographer thiz, int callbackType, Object action, Object token, long delayMillis) {
+        BridgeContext context = getCurrentContext();
+        if (context == null) {
+            return;
         }
+        if (callbackType != Choreographer.CALLBACK_ANIMATION) {
+            // Ignore non-animation callbacks
+            return;
+        }
+        if (action == null) {
+            Bridge.getLog().error(ILayoutLog.TAG_BROKEN,
+                    "Callback with null action", (Object) null, null);
+        }
+        sCallbacksDisposer.onCallbackAdded(new SessionKey(context), action);
+        thiz.postCallbackDelayedInternal_Original(callbackType, action, token, delayMillis);
     }
 
-    public static void clearFrames() {
-        Choreographer thisChoreographer = Choreographer.getInstance();
-
-        thisChoreographer.removeCallbacks(Choreographer.CALLBACK_INPUT, null, null);
-        thisChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, null, null);
-        thisChoreographer.removeCallbacks(Choreographer.CALLBACK_TRAVERSAL, null, null);
-        thisChoreographer.removeCallbacks(Choreographer.CALLBACK_COMMIT, null, null);
-
-        // Release animation handler instance since it holds references to the callbacks
-        AnimationHandler.sAnimatorHandler.set(null);
+    @LayoutlibDelegate
+    public static void removeCallbacksInternal(
+            Choreographer thiz, int callbackType, Object action, Object token) {
+        BridgeContext context = getCurrentContext();
+        if (context == null) {
+            return;
+        }
+        if (callbackType != Choreographer.CALLBACK_ANIMATION) {
+            // Ignore non-animation callbacks
+            return;
+        }
+        if (action == null) {
+            Bridge.getLog().error(ILayoutLog.TAG_BROKEN,
+                    "Callback with null action", (Object) null, null);
+        }
+        sCallbacksDisposer.onCallbackRemoved(new SessionKey(context), action);
+        thiz.removeCallbacksInternal_Original(callbackType, action, token);
     }
 
-    public static void dispose() {
-        clearFrames();
-        Choreographer.releaseInstance();
+    public static void dispose(@NotNull BridgeContext bridgeContext) {
+        sCallbacksDisposer.onDispose(new SessionKey(bridgeContext));
     }
 }
diff --git a/bridge/src/android/view/DisplayEventReceiver_VsyncEventData_Accessor.java b/bridge/src/android/view/DisplayEventReceiver_VsyncEventData_Accessor.java
new file mode 100644
index 0000000..a72ea79
--- /dev/null
+++ b/bridge/src/android/view/DisplayEventReceiver_VsyncEventData_Accessor.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.view;
+
+import com.android.tools.layoutlib.annotations.NotNull;
+
+import android.view.DisplayEventReceiver.VsyncEventData;
+
+public class DisplayEventReceiver_VsyncEventData_Accessor {
+    private static VsyncEventData sVsyncEventData;
+
+    @NotNull
+    public static VsyncEventData getVsyncEventDataInstance() {
+        if (sVsyncEventData == null) {
+            sVsyncEventData = new VsyncEventData();
+        }
+        return sVsyncEventData;
+    }
+}
diff --git a/bridge/src/android/view/RectShadowPainter.java b/bridge/src/android/view/RectShadowPainter.java
deleted file mode 100644
index 88771a7..0000000
--- a/bridge/src/android/view/RectShadowPainter.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-package android.view;
-
-import com.android.layoutlib.bridge.impl.GcSnapshot;
-import com.android.layoutlib.bridge.impl.ResourceHelper;
-
-import android.graphics.BaseCanvas_Delegate;
-import android.graphics.Canvas;
-import android.graphics.Canvas_Delegate;
-import android.graphics.Color;
-import android.graphics.LinearGradient;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.graphics.Path;
-import android.graphics.Path.FillType;
-import android.graphics.RadialGradient;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Region.Op;
-import android.graphics.Shader.TileMode;
-
-import java.awt.Rectangle;
-
-/**
- * Paints shadow for rounded rectangles. Inspiration from CardView. Couldn't use that directly,
- * since it modifies the size of the content, that we can't do.
- */
-public class RectShadowPainter {
-
-
-    private static final int START_COLOR = ResourceHelper.getColor("#37000000");
-    private static final int END_COLOR = ResourceHelper.getColor("#03000000");
-    private static final float PERPENDICULAR_ANGLE = 90f;
-
-    public static void paintShadow(Outline viewOutline, float elevation, Canvas canvas,
-            float alpha) {
-        Rect outline = new Rect();
-        if (!viewOutline.getRect(outline)) {
-            assert false : "Outline is not a rect shadow";
-            return;
-        }
-
-        // TODO replacing the algorithm here to create better shadow
-
-        float shadowSize = elevationToShadow(elevation);
-        int saved = modifyCanvas(canvas, shadowSize);
-        if (saved == -1) {
-            return;
-        }
-
-        float radius = viewOutline.getRadius();
-        if (radius <= 0) {
-            // We can not paint a shadow with radius 0
-            return;
-        }
-
-        try {
-            Paint cornerPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
-            cornerPaint.setStyle(Style.FILL);
-            Paint edgePaint = new Paint(cornerPaint);
-            edgePaint.setAntiAlias(false);
-            float outerArcRadius = radius + shadowSize;
-            int[] colors = {START_COLOR, START_COLOR, END_COLOR};
-            if (alpha != 1f) {
-                // Correct colors using the given component alpha
-                for (int i = 0; i < colors.length; i++) {
-                    colors[i] = Color.argb((int) (Color.alpha(colors[i]) * alpha), Color.red(colors[i]),
-                            Color.green(colors[i]), Color.blue(colors[i]));
-                }
-            }
-            cornerPaint.setShader(new RadialGradient(0, 0, outerArcRadius, colors,
-                    new float[]{0f, radius / outerArcRadius, 1f}, TileMode.CLAMP));
-            edgePaint.setShader(new LinearGradient(0, 0, -shadowSize, 0, colors[0], colors[2],
-                    TileMode.CLAMP));
-            Path path = new Path();
-            path.setFillType(FillType.EVEN_ODD);
-            // A rectangle bounding the complete shadow.
-            RectF shadowRect = new RectF(outline);
-            shadowRect.inset(-shadowSize, -shadowSize);
-            // A rectangle with edges corresponding to the straight edges of the outline.
-            RectF inset = new RectF(outline);
-            inset.inset(radius, radius);
-            // A rectangle used to represent the edge shadow.
-            RectF edgeShadowRect = new RectF();
-
-
-            // left and right sides.
-            edgeShadowRect.set(-shadowSize, 0f, 0f, inset.height());
-            // Left shadow
-            sideShadow(canvas, edgePaint, edgeShadowRect, outline.left, inset.top, 0);
-            // Right shadow
-            sideShadow(canvas, edgePaint, edgeShadowRect, outline.right, inset.bottom, 2);
-            // Top shadow
-            edgeShadowRect.set(-shadowSize, 0, 0, inset.width());
-            sideShadow(canvas, edgePaint, edgeShadowRect, inset.right, outline.top, 1);
-            // bottom shadow. This needs an inset so that blank doesn't appear when the content is
-            // moved up.
-            edgeShadowRect.set(-shadowSize, 0, shadowSize / 2f, inset.width());
-            edgePaint.setShader(new LinearGradient(edgeShadowRect.right, 0, edgeShadowRect.left, 0,
-                    colors, new float[]{0f, 1 / 3f, 1f}, TileMode.CLAMP));
-            sideShadow(canvas, edgePaint, edgeShadowRect, inset.left, outline.bottom, 3);
-
-            // Draw corners.
-            drawCorner(canvas, cornerPaint, path, inset.right, inset.bottom, outerArcRadius, 0);
-            drawCorner(canvas, cornerPaint, path, inset.left, inset.bottom, outerArcRadius, 1);
-            drawCorner(canvas, cornerPaint, path, inset.left, inset.top, outerArcRadius, 2);
-            drawCorner(canvas, cornerPaint, path, inset.right, inset.top, outerArcRadius, 3);
-        } finally {
-            canvas.restoreToCount(saved);
-        }
-    }
-
-    private static float elevationToShadow(float elevation) {
-        // The factor is chosen by eyeballing the shadow size on device and preview.
-        return elevation * 0.5f;
-    }
-
-    /**
-     * Translate canvas by half of shadow size up, so that it appears that light is coming
-     * slightly from above. Also, remove clipping, so that shadow is not clipped.
-     */
-    private static int modifyCanvas(Canvas canvas, float shadowSize) {
-        Rect clipBounds = canvas.getClipBounds();
-        if (clipBounds.isEmpty()) {
-            return -1;
-        }
-        int saved = canvas.save();
-        // Usually canvas has been translated to the top left corner of the view when this is
-        // called. So, setting a clip rect at 0,0 will clip the top left part of the shadow.
-        // Thus, we just expand in each direction by width and height of the canvas, while staying
-        // inside the original drawing region.
-        GcSnapshot snapshot = Canvas_Delegate.getDelegate(canvas).getSnapshot();
-        Rectangle originalClip = snapshot.getOriginalClip();
-        if (originalClip != null) {
-            canvas.clipRect(originalClip.x, originalClip.y, originalClip.x + originalClip.width,
-              originalClip.y + originalClip.height, Op.REPLACE);
-            canvas.clipRect(-canvas.getWidth(), -canvas.getHeight(), canvas.getWidth(),
-              canvas.getHeight(), Op.INTERSECT);
-        }
-        canvas.translate(0, shadowSize / 2f);
-        return saved;
-    }
-
-    private static void sideShadow(Canvas canvas, Paint edgePaint,
-            RectF edgeShadowRect, float dx, float dy, int rotations) {
-        if (isRectEmpty(edgeShadowRect)) {
-            return;
-        }
-        int saved = canvas.save();
-        canvas.translate(dx, dy);
-        canvas.rotate(rotations * PERPENDICULAR_ANGLE);
-        canvas.drawRect(edgeShadowRect, edgePaint);
-        canvas.restoreToCount(saved);
-    }
-
-    /**
-     * @param canvas Canvas to draw the rectangle on.
-     * @param paint Paint to use when drawing the corner.
-     * @param path A path to reuse. Prevents allocating memory for each path.
-     * @param x Center of circle, which this corner is a part of.
-     * @param y Center of circle, which this corner is a part of.
-     * @param radius radius of the arc
-     * @param rotations number of quarter rotations before starting to paint the arc.
-     */
-    private static void drawCorner(Canvas canvas, Paint paint, Path path, float x, float y,
-            float radius, int rotations) {
-        int saved = canvas.save();
-        canvas.translate(x, y);
-        path.reset();
-        path.arcTo(-radius, -radius, radius, radius, rotations * PERPENDICULAR_ANGLE,
-                PERPENDICULAR_ANGLE, false);
-        path.lineTo(0, 0);
-        path.close();
-        canvas.drawPath(path, paint);
-        canvas.restoreToCount(saved);
-    }
-
-    /**
-     * Differs from {@link RectF#isEmpty()} as this first converts the rect to int and then checks.
-     * <p/>
-     * This is required because {@link BaseCanvas_Delegate#native_drawRect(long, float, float,
-     * float,
-     * float, long)} casts the co-ordinates to int and we want to ensure that it doesn't end up
-     * drawing empty rectangles, which results in IllegalArgumentException.
-     */
-    private static boolean isRectEmpty(RectF rect) {
-        return (int) rect.left >= (int) rect.right || (int) rect.top >= (int) rect.bottom;
-    }
-}
diff --git a/bridge/src/android/view/ShadowPainter.java b/bridge/src/android/view/ShadowPainter.java
deleted file mode 100644
index 788c6c3..0000000
--- a/bridge/src/android/view/ShadowPainter.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.view;
-
-import android.annotation.NonNull;
-
-import java.awt.Graphics2D;
-import java.awt.Image;
-import java.awt.image.BufferedImage;
-import java.awt.image.DataBufferInt;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.imageio.ImageIO;
-
-public class ShadowPainter {
-
-    /**
-     * Adds a drop shadow to a semi-transparent image (of an arbitrary shape) and returns it as a
-     * new image. This method attempts to mimic the same visual characteristics as the rectangular
-     * shadow painting methods in this class, {@link #createRectangularDropShadow(java.awt.image.BufferedImage)}
-     * and {@link #createSmallRectangularDropShadow(java.awt.image.BufferedImage)}.
-     * <p/>
-     * If shadowSize is less or equals to 1, no shadow will be painted and the source image will be
-     * returned instead.
-     *
-     * @param source the source image
-     * @param shadowSize the size of the shadow, normally {@link #SHADOW_SIZE or {@link
-     * #SMALL_SHADOW_SIZE}}
-     * @param alpha alpha value to apply to the shadow
-     *
-     * @return an image with the shadow painted in or the source image if shadowSize <= 1
-     */
-    @NonNull
-    public static BufferedImage createDropShadow(BufferedImage source, int shadowSize, float
-            alpha) {
-        shadowSize /= 2; // make shadow size have the same meaning as in the other shadow paint methods in this class
-
-        return createDropShadow(source, shadowSize, 0.7f * alpha, 0);
-    }
-
-    /**
-     * Creates a drop shadow of a given image and returns a new image which shows the input image on
-     * top of its drop shadow.
-     * <p/>
-     * <b>NOTE: If the shape is rectangular and opaque, consider using {@link
-     * #drawRectangleShadow(Graphics2D, int, int, int, int)} instead.</b>
-     *
-     * @param source the source image to be shadowed
-     * @param shadowSize the size of the shadow in pixels
-     * @param shadowOpacity the opacity of the shadow, with 0=transparent and 1=opaque
-     * @param shadowRgb the RGB int to use for the shadow color
-     *
-     * @return a new image with the source image on top of its shadow when shadowSize > 0 or the
-     * source image otherwise
-     */
-    @SuppressWarnings({"SuspiciousNameCombination", "UnnecessaryLocalVariable"})  // Imported code
-    public static BufferedImage createDropShadow(BufferedImage source, int shadowSize,
-            float shadowOpacity, int shadowRgb) {
-        if (shadowSize <= 0) {
-            return source;
-        }
-
-        // This code is based on
-        //      http://www.jroller.com/gfx/entry/non_rectangular_shadow
-
-        BufferedImage image;
-        int width = source.getWidth();
-        int height = source.getHeight();
-        image = new BufferedImage(width + SHADOW_SIZE, height + SHADOW_SIZE,
-                BufferedImage.TYPE_INT_ARGB);
-
-        Graphics2D g2 = image.createGraphics();
-        g2.drawImage(image, shadowSize, shadowSize, null);
-
-        int dstWidth = image.getWidth();
-        int dstHeight = image.getHeight();
-
-        int left = (shadowSize - 1) >> 1;
-        int right = shadowSize - left;
-        int xStart = left;
-        int xStop = dstWidth - right;
-        int yStart = left;
-        int yStop = dstHeight - right;
-
-        shadowRgb &= 0x00FFFFFF;
-
-        int[] aHistory = new int[shadowSize];
-        int historyIdx;
-
-        int aSum;
-
-        int[] dataBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
-        int lastPixelOffset = right * dstWidth;
-        float sumDivider = shadowOpacity / shadowSize;
-
-        // horizontal pass
-        for (int y = 0, bufferOffset = 0; y < dstHeight; y++, bufferOffset = y * dstWidth) {
-            aSum = 0;
-            historyIdx = 0;
-            for (int x = 0; x < shadowSize; x++, bufferOffset++) {
-                int a = dataBuffer[bufferOffset] >>> 24;
-                aHistory[x] = a;
-                aSum += a;
-            }
-
-            bufferOffset -= right;
-
-            for (int x = xStart; x < xStop; x++, bufferOffset++) {
-                int a = (int) (aSum * sumDivider);
-                dataBuffer[bufferOffset] = a << 24 | shadowRgb;
-
-                // subtract the oldest pixel from the sum
-                aSum -= aHistory[historyIdx];
-
-                // get the latest pixel
-                a = dataBuffer[bufferOffset + right] >>> 24;
-                aHistory[historyIdx] = a;
-                aSum += a;
-
-                if (++historyIdx >= shadowSize) {
-                    historyIdx -= shadowSize;
-                }
-            }
-        }
-        // vertical pass
-        for (int x = 0, bufferOffset = 0; x < dstWidth; x++, bufferOffset = x) {
-            aSum = 0;
-            historyIdx = 0;
-            for (int y = 0; y < shadowSize; y++, bufferOffset += dstWidth) {
-                int a = dataBuffer[bufferOffset] >>> 24;
-                aHistory[y] = a;
-                aSum += a;
-            }
-
-            bufferOffset -= lastPixelOffset;
-
-            for (int y = yStart; y < yStop; y++, bufferOffset += dstWidth) {
-                int a = (int) (aSum * sumDivider);
-                dataBuffer[bufferOffset] = a << 24 | shadowRgb;
-
-                // subtract the oldest pixel from the sum
-                aSum -= aHistory[historyIdx];
-
-                // get the latest pixel
-                a = dataBuffer[bufferOffset + lastPixelOffset] >>> 24;
-                aHistory[historyIdx] = a;
-                aSum += a;
-
-                if (++historyIdx >= shadowSize) {
-                    historyIdx -= shadowSize;
-                }
-            }
-        }
-
-        g2.drawImage(source, null, 0, 0);
-        g2.dispose();
-
-        return image;
-    }
-
-    /**
-     * Draws a rectangular drop shadow (of size {@link #SHADOW_SIZE} by {@link #SHADOW_SIZE} around
-     * the given source and returns a new image with both combined
-     *
-     * @param source the source image
-     *
-     * @return the source image with a drop shadow on the bottom and right
-     */
-    @SuppressWarnings("UnusedDeclaration")
-    public static BufferedImage createRectangularDropShadow(BufferedImage source) {
-        int type = source.getType();
-        if (type == BufferedImage.TYPE_CUSTOM) {
-            type = BufferedImage.TYPE_INT_ARGB;
-        }
-
-        int width = source.getWidth();
-        int height = source.getHeight();
-        BufferedImage image;
-        image = new BufferedImage(width + SHADOW_SIZE, height + SHADOW_SIZE, type);
-        Graphics2D g = image.createGraphics();
-        g.drawImage(source, 0, 0, null);
-        drawRectangleShadow(image, 0, 0, width, height);
-        g.dispose();
-
-        return image;
-    }
-
-    /**
-     * Draws a small rectangular drop shadow (of size {@link #SMALL_SHADOW_SIZE} by {@link
-     * #SMALL_SHADOW_SIZE} around the given source and returns a new image with both combined
-     *
-     * @param source the source image
-     *
-     * @return the source image with a drop shadow on the bottom and right
-     */
-    @SuppressWarnings("UnusedDeclaration")
-    public static BufferedImage createSmallRectangularDropShadow(BufferedImage source) {
-        int type = source.getType();
-        if (type == BufferedImage.TYPE_CUSTOM) {
-            type = BufferedImage.TYPE_INT_ARGB;
-        }
-
-        int width = source.getWidth();
-        int height = source.getHeight();
-
-        BufferedImage image;
-        image = new BufferedImage(width + SMALL_SHADOW_SIZE, height + SMALL_SHADOW_SIZE, type);
-
-        Graphics2D g = image.createGraphics();
-        g.drawImage(source, 0, 0, null);
-        drawSmallRectangleShadow(image, 0, 0, width, height);
-        g.dispose();
-
-        return image;
-    }
-
-    /**
-     * Draws a drop shadow for the given rectangle into the given context. It will not draw anything
-     * if the rectangle is smaller than a minimum determined by the assets used to draw the shadow
-     * graphics. The size of the shadow is {@link #SHADOW_SIZE}.
-     *
-     * @param image the image to draw the shadow into
-     * @param x the left coordinate of the left hand side of the rectangle
-     * @param y the top coordinate of the top of the rectangle
-     * @param width the width of the rectangle
-     * @param height the height of the rectangle
-     */
-    public static void drawRectangleShadow(BufferedImage image,
-            int x, int y, int width, int height) {
-        Graphics2D gc = image.createGraphics();
-        try {
-            drawRectangleShadow(gc, x, y, width, height);
-        } finally {
-            gc.dispose();
-        }
-    }
-
-    /**
-     * Draws a small drop shadow for the given rectangle into the given context. It will not draw
-     * anything if the rectangle is smaller than a minimum determined by the assets used to draw the
-     * shadow graphics. The size of the shadow is {@link #SMALL_SHADOW_SIZE}.
-     *
-     * @param image the image to draw the shadow into
-     * @param x the left coordinate of the left hand side of the rectangle
-     * @param y the top coordinate of the top of the rectangle
-     * @param width the width of the rectangle
-     * @param height the height of the rectangle
-     */
-    public static void drawSmallRectangleShadow(BufferedImage image,
-            int x, int y, int width, int height) {
-        Graphics2D gc = image.createGraphics();
-        try {
-            drawSmallRectangleShadow(gc, x, y, width, height);
-        } finally {
-            gc.dispose();
-        }
-    }
-
-    /**
-     * The width and height of the drop shadow painted by
-     * {@link #drawRectangleShadow(Graphics2D, int, int, int, int)}
-     */
-    public static final int SHADOW_SIZE = 20; // DO NOT EDIT. This corresponds to bitmap graphics
-
-    /**
-     * The width and height of the drop shadow painted by
-     * {@link #drawSmallRectangleShadow(Graphics2D, int, int, int, int)}
-     */
-    public static final int SMALL_SHADOW_SIZE = 10; // DO NOT EDIT. Corresponds to bitmap graphics
-
-    /**
-     * Draws a drop shadow for the given rectangle into the given context. It will not draw anything
-     * if the rectangle is smaller than a minimum determined by the assets used to draw the shadow
-     * graphics.
-     *
-     * @param gc the graphics context to draw into
-     * @param x the left coordinate of the left hand side of the rectangle
-     * @param y the top coordinate of the top of the rectangle
-     * @param width the width of the rectangle
-     * @param height the height of the rectangle
-     */
-    public static void drawRectangleShadow(Graphics2D gc, int x, int y, int width, int height) {
-        assert ShadowBottomLeft != null;
-        assert ShadowBottomRight.getWidth(null) == SHADOW_SIZE;
-        assert ShadowBottomRight.getHeight(null) == SHADOW_SIZE;
-
-        int blWidth = ShadowBottomLeft.getWidth(null);
-        int trHeight = ShadowTopRight.getHeight(null);
-        if (width < blWidth) {
-            return;
-        }
-        if (height < trHeight) {
-            return;
-        }
-
-        gc.drawImage(ShadowBottomLeft, x - ShadowBottomLeft.getWidth(null), y + height, null);
-        gc.drawImage(ShadowBottomRight, x + width, y + height, null);
-        gc.drawImage(ShadowTopRight, x + width, y, null);
-        gc.drawImage(ShadowTopLeft, x - ShadowTopLeft.getWidth(null), y, null);
-        gc.drawImage(ShadowBottom,
-                x, y + height, x + width, y + height + ShadowBottom.getHeight(null),
-                0, 0, ShadowBottom.getWidth(null), ShadowBottom.getHeight(null), null);
-        gc.drawImage(ShadowRight,
-                x + width, y + ShadowTopRight.getHeight(null), x + width + ShadowRight.getWidth(null), y + height,
-                0, 0, ShadowRight.getWidth(null), ShadowRight.getHeight(null), null);
-        gc.drawImage(ShadowLeft,
-                x - ShadowLeft.getWidth(null), y + ShadowTopLeft.getHeight(null), x, y + height,
-                0, 0, ShadowLeft.getWidth(null), ShadowLeft.getHeight(null), null);
-    }
-
-    /**
-     * Draws a small drop shadow for the given rectangle into the given context. It will not draw
-     * anything if the rectangle is smaller than a minimum determined by the assets used to draw the
-     * shadow graphics.
-     * <p/>
-     *
-     * @param gc the graphics context to draw into
-     * @param x the left coordinate of the left hand side of the rectangle
-     * @param y the top coordinate of the top of the rectangle
-     * @param width the width of the rectangle
-     * @param height the height of the rectangle
-     */
-    public static void drawSmallRectangleShadow(Graphics2D gc, int x, int y, int width,
-            int height) {
-        assert Shadow2BottomLeft != null;
-        assert Shadow2TopRight != null;
-        assert Shadow2BottomRight.getWidth(null) == SMALL_SHADOW_SIZE;
-        assert Shadow2BottomRight.getHeight(null) == SMALL_SHADOW_SIZE;
-
-        int blWidth = Shadow2BottomLeft.getWidth(null);
-        int trHeight = Shadow2TopRight.getHeight(null);
-        if (width < blWidth) {
-            return;
-        }
-        if (height < trHeight) {
-            return;
-        }
-
-        gc.drawImage(Shadow2BottomLeft, x - Shadow2BottomLeft.getWidth(null), y + height, null);
-        gc.drawImage(Shadow2BottomRight, x + width, y + height, null);
-        gc.drawImage(Shadow2TopRight, x + width, y, null);
-        gc.drawImage(Shadow2TopLeft, x - Shadow2TopLeft.getWidth(null), y, null);
-        gc.drawImage(Shadow2Bottom,
-                x, y + height, x + width, y + height + Shadow2Bottom.getHeight(null),
-                0, 0, Shadow2Bottom.getWidth(null), Shadow2Bottom.getHeight(null), null);
-        gc.drawImage(Shadow2Right,
-                x + width, y + Shadow2TopRight.getHeight(null), x + width + Shadow2Right.getWidth(null), y + height,
-                0, 0, Shadow2Right.getWidth(null), Shadow2Right.getHeight(null), null);
-        gc.drawImage(Shadow2Left,
-                x - Shadow2Left.getWidth(null), y + Shadow2TopLeft.getHeight(null), x, y + height,
-                0, 0, Shadow2Left.getWidth(null), Shadow2Left.getHeight(null), null);
-    }
-
-    private static Image loadIcon(String name) {
-        InputStream inputStream = ShadowPainter.class.getResourceAsStream(name);
-        if (inputStream == null) {
-            throw new RuntimeException("Unable to load image for shadow: " + name);
-        }
-        try {
-            return ImageIO.read(inputStream);
-        } catch (IOException e) {
-            throw new RuntimeException("Unable to load image for shadow:" + name, e);
-        } finally {
-            try {
-                inputStream.close();
-            } catch (IOException e) {
-                // ignore.
-            }
-        }
-    }
-
-    // Shadow graphics. This was generated by creating a drop shadow in
-    // Gimp, using the parameters x offset=10, y offset=10, blur radius=10,
-    // (for the small drop shadows x offset=10, y offset=10, blur radius=10)
-    // color=black, and opacity=51. These values attempt to make a shadow
-    // that is legible both for dark and light themes, on top of the
-    // canvas background (rgb(150,150,150). Darker shadows would tend to
-    // blend into the foreground for a dark holo screen, and lighter shadows
-    // would be hard to spot on the canvas background. If you make adjustments,
-    // make sure to check the shadow with both dark and light themes.
-    //
-    // After making the graphics, I cut out the top right, bottom left
-    // and bottom right corners as 20x20 images, and these are reproduced by
-    // painting them in the corresponding places in the target graphics context.
-    // I then grabbed a single horizontal gradient line from the middle of the
-    // right edge,and a single vertical gradient line from the bottom. These
-    // are then painted scaled/stretched in the target to fill the gaps between
-    // the three corner images.
-    //
-    // Filenames: bl=bottom left, b=bottom, br=bottom right, r=right, tr=top right
-
-    // Normal Drop Shadow
-    private static final Image ShadowBottom = loadIcon("/icons/shadow-b.png");
-    private static final Image ShadowBottomLeft = loadIcon("/icons/shadow-bl.png");
-    private static final Image ShadowBottomRight = loadIcon("/icons/shadow-br.png");
-    private static final Image ShadowRight = loadIcon("/icons/shadow-r.png");
-    private static final Image ShadowTopRight = loadIcon("/icons/shadow-tr.png");
-    private static final Image ShadowTopLeft = loadIcon("/icons/shadow-tl.png");
-    private static final Image ShadowLeft = loadIcon("/icons/shadow-l.png");
-
-    // Small Drop Shadow
-    private static final Image Shadow2Bottom = loadIcon("/icons/shadow2-b.png");
-    private static final Image Shadow2BottomLeft = loadIcon("/icons/shadow2-bl.png");
-    private static final Image Shadow2BottomRight = loadIcon("/icons/shadow2-br.png");
-    private static final Image Shadow2Right = loadIcon("/icons/shadow2-r.png");
-    private static final Image Shadow2TopRight = loadIcon("/icons/shadow2-tr.png");
-    private static final Image Shadow2TopLeft = loadIcon("/icons/shadow2-tl.png");
-    private static final Image Shadow2Left = loadIcon("/icons/shadow2-l.png");
-}
diff --git a/bridge/src/android/view/SurfaceControl_Delegate.java b/bridge/src/android/view/SurfaceControl_Delegate.java
index 24838b2..9cb0d5d 100644
--- a/bridge/src/android/view/SurfaceControl_Delegate.java
+++ b/bridge/src/android/view/SurfaceControl_Delegate.java
@@ -26,20 +26,9 @@
     // ---- delegate manager ----
     private static final DelegateManager<SurfaceControl_Delegate> sManager =
             new DelegateManager<>(SurfaceControl_Delegate.class);
-    private static long sFinalizer = -1;
 
     @LayoutlibDelegate
     /*package*/ static long nativeCreateTransaction() {
         return sManager.addNewDelegate(new SurfaceControl_Delegate());
     }
-
-    @LayoutlibDelegate
-    /*package*/ static long nativeGetNativeTransactionFinalizer() {
-        synchronized (SurfaceControl_Delegate.class) {
-            if (sFinalizer == -1) {
-                sFinalizer = NativeAllocationRegistry_Delegate.createFinalizer(sManager::removeJavaReferenceFor);
-            }
-        }
-        return sFinalizer;
-    }
 }
diff --git a/bridge/src/android/view/TextureView_Delegate.java b/bridge/src/android/view/TextureView_Delegate.java
new file mode 100644
index 0000000..0a2abe1
--- /dev/null
+++ b/bridge/src/android/view/TextureView_Delegate.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.view;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+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/bridge/src/android/view/ViewGroup_Delegate.java b/bridge/src/android/view/ViewGroup_Delegate.java
deleted file mode 100644
index e71af61..0000000
--- a/bridge/src/android/view/ViewGroup_Delegate.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.view;
-
-import com.android.layoutlib.bridge.android.BridgeContext;
-import com.android.resources.Density;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap_Delegate;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Path_Delegate;
-import android.graphics.Rect;
-import android.view.animation.Transformation;
-import android.view.shadow.HighQualityShadowPainter;
-
-import java.awt.Graphics2D;
-import java.awt.image.BufferedImage;
-
-/**
- * Delegate used to provide new implementation of a select few methods of {@link ViewGroup}
- * <p/>
- * Through the layoutlib_create tool, the original  methods of ViewGroup have been replaced by calls
- * to methods of the same name in this delegate class.
- */
-public class ViewGroup_Delegate {
-
-    /**
-     * Overrides the original drawChild call in ViewGroup to draw the shadow.
-     */
-    @LayoutlibDelegate
-    /*package*/ static boolean drawChild(ViewGroup thisVG, Canvas canvas, View child,
-            long drawingTime) {
-        if (child.getZ() > thisVG.getZ()) {
-            // The background's bounds are set lazily. Make sure they are set correctly so that
-            // the outline obtained is correct.
-            child.setBackgroundBounds();
-            ViewOutlineProvider outlineProvider = child.getOutlineProvider();
-            if (outlineProvider != null) {
-                Outline outline = child.mAttachInfo.mTmpOutline;
-                outlineProvider.getOutline(child, outline);
-                if (outline.mPath != null || (outline.mRect != null && !outline.mRect.isEmpty())) {
-                    int restoreTo = transformCanvas(thisVG, canvas, child);
-                    drawShadow(thisVG, canvas, child, outline);
-                    canvas.restoreToCount(restoreTo);
-                }
-            }
-        }
-        return thisVG.drawChild_Original(canvas, child, drawingTime);
-    }
-
-    private static void drawShadow(ViewGroup parent, Canvas canvas, View child,
-            Outline outline) {
-        boolean highQualityShadow = false;
-        boolean enableShadow = true;
-        float elevation = getElevation(child, parent);
-        Context bridgeContext = parent.getContext();
-        if (bridgeContext instanceof BridgeContext) {
-            highQualityShadow = ((BridgeContext) bridgeContext).isHighQualityShadows();
-            enableShadow = ((BridgeContext) bridgeContext).isShadowsEnabled();
-        }
-
-        if (!enableShadow) {
-            return;
-        }
-
-        if(outline.mMode == Outline.MODE_ROUND_RECT && outline.mRect != null) {
-            if (highQualityShadow) {
-                float densityDpi = bridgeContext.getResources().getDisplayMetrics().densityDpi;
-                HighQualityShadowPainter.paintRectShadow(
-                        parent, outline, elevation, canvas, child.getAlpha(), densityDpi);
-            } else {
-                RectShadowPainter.paintShadow(outline, elevation, canvas, child.getAlpha());
-            }
-            return;
-        }
-
-        BufferedImage shadow = null;
-        if (outline.mPath != null) {
-            shadow = getPathShadow(outline, canvas, elevation, child.getAlpha());
-        }
-        if (shadow == null) {
-            return;
-        }
-        Bitmap bitmap = Bitmap_Delegate.createBitmap(shadow, false,
-                Density.getEnum(canvas.getDensity()));
-        canvas.save();
-        Rect clipBounds = canvas.getClipBounds();
-        Rect newBounds = new Rect(clipBounds);
-        newBounds.inset((int)-elevation, (int)-elevation);
-        canvas.clipRectUnion(newBounds);
-        canvas.drawBitmap(bitmap, 0, 0, null);
-        canvas.restore();
-    }
-
-    private static float getElevation(View child, ViewGroup parent) {
-        return child.getZ() - parent.getZ();
-    }
-
-    private static BufferedImage getPathShadow(Outline outline, Canvas canvas, float elevation,
-            float alpha) {
-        Rect clipBounds = canvas.getClipBounds();
-        if (clipBounds.isEmpty()) {
-          return null;
-        }
-        BufferedImage image = new BufferedImage(clipBounds.width(), clipBounds.height(),
-                BufferedImage.TYPE_INT_ARGB);
-        Graphics2D graphics = image.createGraphics();
-        graphics.draw(Path_Delegate.getDelegate(outline.mPath.mNativePath).getJavaShape());
-        graphics.dispose();
-        return ShadowPainter.createDropShadow(image, (int) elevation, alpha);
-    }
-
-    // Copied from android.view.View#draw(Canvas, ViewGroup, long) and removed code paths
-    // which were never taken. Ideally, we should hook up the shadow code in the same method so
-    // that we don't have to transform the canvas twice.
-    private static int transformCanvas(ViewGroup thisVG, Canvas canvas, View child) {
-        final int restoreTo = canvas.save();
-        final boolean childHasIdentityMatrix = child.hasIdentityMatrix();
-        int flags = thisVG.mGroupFlags;
-        Transformation transformToApply = null;
-        boolean concatMatrix = false;
-        if ((flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
-            final Transformation t = thisVG.getChildTransformation();
-            final boolean hasTransform = thisVG.getChildStaticTransformation(child, t);
-            if (hasTransform) {
-                final int transformType = t.getTransformationType();
-                transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null;
-                concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
-            }
-        }
-        concatMatrix |= childHasIdentityMatrix;
-
-        canvas.translate(child.mLeft, child.mTop);
-        float alpha = child.getAlpha() * child.getTransitionAlpha();
-
-        if (transformToApply != null || alpha < 1 || !childHasIdentityMatrix) {
-            if (transformToApply != null || !childHasIdentityMatrix) {
-
-                if (transformToApply != null) {
-                    if (concatMatrix) {
-                        canvas.concat(transformToApply.getMatrix());
-                    }
-                }
-                if (!childHasIdentityMatrix) {
-                    canvas.concat(child.getMatrix());
-                }
-
-            }
-        }
-        return restoreTo;
-    }
-}
diff --git a/bridge/src/android/view/math/Math3DHelper.java b/bridge/src/android/view/math/Math3DHelper.java
deleted file mode 100644
index 35a1ee1..0000000
--- a/bridge/src/android/view/math/Math3DHelper.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.view.math;
-
-public class Math3DHelper {
-
-    private Math3DHelper() { }
-
-    public final static int min(int x1, int x2, int x3) {
-        return (x1 > x2) ? ((x2 > x3) ? x3 : x2) : ((x1 > x3) ? x3 : x1);
-    }
-
-    public final static int max(int x1, int x2, int x3) {
-        return (x1 < x2) ? ((x2 < x3) ? x3 : x2) : ((x1 < x3) ? x3 : x1);
-    }
-
-    /**
-     * @return Rect bound of flattened (ignoring z). LTRB
-     * @param dimension - 2D or 3D
-     */
-    public static float[] flatBound(float[] poly, int dimension) {
-        int polySize = poly.length/dimension;
-        float left = poly[0];
-        float right = poly[0];
-        float top = poly[1];
-        float bottom = poly[1];
-
-        for (int i = 0; i < polySize; i++) {
-            float x = poly[i * dimension + 0];
-            float y = poly[i * dimension + 1];
-
-            if (left > x) {
-                left = x;
-            } else if (right < x) {
-                right = x;
-            }
-
-            if (top > y) {
-                top = y;
-            } else if (bottom < y) {
-                bottom = y;
-            }
-        }
-        return new float[]{left, top, right, bottom};
-    }
-
-    /**
-     * Translate the polygon to x and y
-     * @param dimension in what dimension is polygon represented (supports 2 or 3D).
-     */
-    public static void translate(float[] poly, float translateX, float translateY, int dimension) {
-        int polySize = poly.length/dimension;
-
-        for (int i = 0; i < polySize; i++) {
-            poly[i * dimension + 0] += translateX;
-            poly[i * dimension + 1] += translateY;
-        }
-    }
-
-}
-
diff --git a/bridge/src/android/view/shadow/AmbientShadowConfig.java b/bridge/src/android/view/shadow/AmbientShadowConfig.java
deleted file mode 100644
index 97efd86..0000000
--- a/bridge/src/android/view/shadow/AmbientShadowConfig.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.view.shadow;
-
-/**
- * Model for ambient shadow rendering. Assumes light sources from centroid of the object.
- */
-class AmbientShadowConfig {
-
-    private final float mEdgeScale;
-    private final float mShadowBoundRatio;
-    private final float mShadowStrength;
-
-    private final float[] mPolygon;
-    private float[] mLightSourcePosition;
-
-    private AmbientShadowConfig(Builder builder) {
-        mEdgeScale = builder.mEdgeScale;
-        mShadowBoundRatio = builder.mShadowBoundRatio;
-        mShadowStrength = builder.mShadowStrength;
-        mPolygon = builder.mPolygon;
-        mLightSourcePosition = builder.mLightSourcePosition;
-    }
-
-    /**
-     * Returns scales intensity of the edge of the shadow (opacity) [0-100]
-     */
-    public float getEdgeScale() {
-        return mEdgeScale;
-    }
-
-    /**
-     * Returns scales the area (in xy) of the shadow [0-1]
-     */
-    public float getShadowBoundRatio() {
-        return mShadowBoundRatio;
-    }
-
-    /**
-     * Returns scales the intensity of the entire shadow (opacity) [0-1]
-     */
-    public float getShadowStrength() {
-        return mShadowStrength;
-    }
-
-    /**
-     * Returns opaque polygon to cast shadow
-     */
-    public float[] getPolygon() {
-        return mPolygon;
-    }
-
-    /**
-     * Returns 2D position of the light source
-     */
-    public float[] getLightSourcePosition() {
-        return mLightSourcePosition;
-    }
-
-    public static class Builder {
-
-        private float mEdgeScale;
-        private float mShadowBoundRatio;
-        private float mShadowStrength;
-
-        private float[] mPolygon;
-        private float[] mLightSourcePosition;
-
-        public Builder setEdgeScale(float edgeScale) {
-            mEdgeScale = edgeScale;
-            return this;
-        }
-
-        public Builder setShadowBoundRatio(float shadowBoundRatio) {
-            mShadowBoundRatio = shadowBoundRatio;
-            return this;
-        }
-
-        public Builder setShadowStrength(float shadowStrength) {
-            mShadowStrength = shadowStrength;
-            return this;
-        }
-
-        public Builder setPolygon(float[] polygon) {
-            mPolygon = polygon;
-            return this;
-        }
-
-        public Builder setLightSourcePosition(float x, float y) {
-            mLightSourcePosition = new float[] { x, y };
-            return this;
-        }
-
-        public AmbientShadowConfig build() {
-            return new AmbientShadowConfig(this);
-        }
-    }
-}
diff --git a/bridge/src/android/view/shadow/AmbientShadowTriangulator.java b/bridge/src/android/view/shadow/AmbientShadowTriangulator.java
deleted file mode 100644
index d768fa3..0000000
--- a/bridge/src/android/view/shadow/AmbientShadowTriangulator.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.view.shadow;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-
-/**
- * Generates ambient shadow bitmap
- */
-class AmbientShadowTriangulator {
-
-    private final AmbientShadowConfig mShadowConfig;
-    private final AmbientShadowVertexCalculator mCalculator;
-
-    private boolean mValid;
-
-    public AmbientShadowTriangulator(AmbientShadowConfig shadowConfig) {
-        mShadowConfig = shadowConfig;
-
-        mCalculator = new AmbientShadowVertexCalculator(mShadowConfig);
-    }
-
-    /**
-     * Populate vertices and fill the triangle buffers.
-     */
-    public void triangulate() {
-        try {
-            mCalculator.generateVertex();
-            mValid = true;
-        } catch (IndexOutOfBoundsException|ArithmeticException mathError) {
-            Bridge.getLog().warning(ILayoutLog.TAG_INFO,  "Arithmetic error while drawing " +
-                            "ambient shadow",
-                    null, mathError);
-        } catch (Exception ex) {
-            Bridge.getLog().warning(ILayoutLog.TAG_INFO,  "Error while drawing shadow",
-                    null, ex);
-        }
-    }
-
-    public boolean isValid() {
-        return mValid;
-    }
-
-    public float[] getVertices() { return mCalculator.getVertex(); }
-
-    public int[] getIndices() { return mCalculator.getIndex(); }
-
-    public float[] getColors() { return mCalculator.getColor(); }
-}
diff --git a/bridge/src/android/view/shadow/AmbientShadowVertexCalculator.java b/bridge/src/android/view/shadow/AmbientShadowVertexCalculator.java
deleted file mode 100644
index 5928f35..0000000
--- a/bridge/src/android/view/shadow/AmbientShadowVertexCalculator.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.view.shadow;
-
-import android.view.math.Math3DHelper;
-
-/**
- * Generates vertices, colours, and indices required for ambient shadow. Ambient shadows are
- * assumed to be raycasted from the centroid of the polygon, and reaches upto a ratio based on
- * the polygon's z-height.
- */
-class AmbientShadowVertexCalculator {
-
-    private final float[] mVertex;
-    private final float[] mColor;
-    private final int[] mIndex;
-    private final AmbientShadowConfig mConfig;
-
-    public AmbientShadowVertexCalculator(AmbientShadowConfig config) {
-        mConfig = config;
-
-        int size = mConfig.getPolygon().length / 3;
-
-        mVertex = new float[size * 2 * 2];
-        mColor = new float[size * 2 * 4];
-        mIndex = new int[(size * 3 - 2) * 3];
-    }
-
-    /**
-     * Generates ambient shadow triangulation using configuration provided
-     */
-    public void generateVertex() {
-        float[] polygon = mConfig.getPolygon();
-        float cx = mConfig.getLightSourcePosition()[0];
-        float cy = mConfig.getLightSourcePosition()[1];
-
-        int polygonLength = polygon.length/3;
-
-        float opacity = .8f * (0.5f / (mConfig.getEdgeScale() / 10f));
-
-        int trShift = 0;
-        for (int i = 0; i < polygonLength; ++i, trShift += 6) {
-            int shift = i * 4;
-            int colorShift = i * 8;
-            int idxShift = i * 2;
-
-            float px = polygon[3 * i + 0];
-            float py = polygon[3 * i + 1];
-            mVertex[shift + 0] = px;
-            mVertex[shift + 1] = py;
-
-            // TODO: I do not really understand this but this matches the previous behavior.
-            // The weird bit is that for outlines with low elevation the ambient shadow is
-            // entirely drawn underneath the shadow caster. This is most probably incorrect
-            float h = polygon[3 * i + 2] * mConfig.getShadowBoundRatio();
-
-            mVertex[shift + 2] = cx + h * (px - cx);
-            mVertex[shift + 3] = cy + h * (py - cy);
-
-            mColor[colorShift + 3] = opacity;
-
-            mIndex[trShift + 0] = idxShift + 0;
-            mIndex[trShift + 1] = idxShift + 1;
-            mIndex[trShift + 2] = idxShift + 2;
-
-            mIndex[trShift + 3] = idxShift + 1;
-            mIndex[trShift + 4] = idxShift + 2;
-            mIndex[trShift + 5] = idxShift + 3;
-        }
-        // cycle back to the front
-        mIndex[trShift - 1] = 1;
-        mIndex[trShift - 2] = 0;
-        mIndex[trShift - 4] = 0;
-
-        // Filling the shadow right under the outline. Can we skip that?
-        for (int i = 1; i < polygonLength - 1; ++i, trShift += 3) {
-            mIndex[trShift + 0] = 0;
-            mIndex[trShift + 1] = 2 * i;
-            mIndex[trShift + 2] = 2 * (i+1);
-        }
-    }
-
-    public int[] getIndex() {
-        return mIndex;
-    }
-
-    /**
-     * @return list of vertices in 2d in format : {x1, y1, x2, y2 ...}
-     */
-    public float[] getVertex() {
-        return mVertex;
-    }
-
-    public float[] getColor() {
-        return mColor;
-    }
-}
diff --git a/bridge/src/android/view/shadow/HighQualityShadowPainter.java b/bridge/src/android/view/shadow/HighQualityShadowPainter.java
deleted file mode 100644
index 7b8873c..0000000
--- a/bridge/src/android/view/shadow/HighQualityShadowPainter.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.view.shadow;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.util.DisplayMetrics;
-import android.view.ViewGroup;
-import android.view.math.Math3DHelper;
-
-import static android.view.shadow.ShadowConstants.MIN_ALPHA;
-import static android.view.shadow.ShadowConstants.SCALE_DOWN;
-
-public class HighQualityShadowPainter {
-    private static final float sRoundedGap = (float) (1.0 - Math.sqrt(2.0) / 2.0);
-
-    private HighQualityShadowPainter() { }
-
-    /**
-     * Draws simple Rect shadow
-     */
-    public static void paintRectShadow(ViewGroup parent, Outline outline, float elevation,
-            Canvas canvas, float alpha, float densityDpi) {
-
-        if (!validate(elevation, densityDpi)) {
-            return;
-        }
-
-        int width = parent.getWidth() / SCALE_DOWN;
-        int height = parent.getHeight() / SCALE_DOWN;
-
-        Rect rectOriginal = new Rect();
-        Rect rectScaled = new Rect();
-        if (!outline.getRect(rectScaled) || alpha < MIN_ALPHA) {
-            // If alpha below MIN_ALPHA it's invisible (based on manual test). Save some perf.
-            return;
-        }
-
-        outline.getRect(rectOriginal);
-
-        rectScaled.left /= SCALE_DOWN;
-        rectScaled.right /= SCALE_DOWN;
-        rectScaled.top /= SCALE_DOWN;
-        rectScaled.bottom /= SCALE_DOWN;
-        float radius = outline.getRadius() / SCALE_DOWN;
-
-        if (radius > rectScaled.width() || radius > rectScaled.height()) {
-            // Rounded edge generation fails if radius is bigger than drawing box.
-            return;
-        }
-
-        // ensure alpha doesn't go over 1
-        alpha = (alpha > 1.0f) ? 1.0f : alpha;
-        boolean isOpaque = outline.getAlpha() * alpha == 1.0f;
-        float[] poly = getPoly(rectScaled, elevation / SCALE_DOWN, radius);
-
-        AmbientShadowConfig ambientConfig = new AmbientShadowConfig.Builder()
-                .setPolygon(poly)
-                .setLightSourcePosition(
-                        (rectScaled.left + rectScaled.right) / 2.0f,
-                        (rectScaled.top + rectScaled.bottom) / 2.0f)
-                .setEdgeScale(ShadowConstants.AMBIENT_SHADOW_EDGE_SCALE)
-                .setShadowBoundRatio(ShadowConstants.AMBIENT_SHADOW_SHADOW_BOUND)
-                .setShadowStrength(ShadowConstants.AMBIENT_SHADOW_STRENGTH * alpha)
-                .build();
-
-        AmbientShadowTriangulator ambientTriangulator = new AmbientShadowTriangulator(ambientConfig);
-        ambientTriangulator.triangulate();
-
-        SpotShadowTriangulator spotTriangulator = null;
-        float lightZHeightPx = ShadowConstants.SPOT_SHADOW_LIGHT_Z_HEIGHT_DP * (densityDpi / DisplayMetrics.DENSITY_DEFAULT);
-        if (lightZHeightPx - elevation / SCALE_DOWN >= ShadowConstants.SPOT_SHADOW_LIGHT_Z_EPSILON) {
-
-            float lightX = (rectScaled.left + rectScaled.right) / 2;
-            float lightY = rectScaled.top;
-            // Light shouldn't be bigger than the object by too much.
-            int dynamicLightRadius = Math.min(rectScaled.width(), rectScaled.height());
-
-            SpotShadowConfig spotConfig = new SpotShadowConfig.Builder()
-                    .setLightCoord(lightX, lightY, lightZHeightPx)
-                    .setLightRadius(dynamicLightRadius)
-                    .setShadowStrength(ShadowConstants.SPOT_SHADOW_STRENGTH * alpha)
-                    .setPolygon(poly, poly.length / ShadowConstants.COORDINATE_SIZE)
-                    .build();
-
-            spotTriangulator = new SpotShadowTriangulator(spotConfig);
-            spotTriangulator.triangulate();
-        }
-
-        int translateX = 0;
-        int translateY = 0;
-        int imgW = 0;
-        int imgH = 0;
-
-        if (ambientTriangulator.isValid()) {
-            float[] shadowBounds = Math3DHelper.flatBound(ambientTriangulator.getVertices(), 2);
-            // Move the shadow to the left top corner to occupy the least possible bitmap
-
-            translateX = -(int) Math.floor(shadowBounds[0]);
-            translateY = -(int) Math.floor(shadowBounds[1]);
-
-            // create bitmap of the least possible size that covers the entire shadow
-            imgW = (int) Math.ceil(shadowBounds[2] + translateX);
-            imgH = (int) Math.ceil(shadowBounds[3] + translateY);
-        }
-
-        if (spotTriangulator != null && spotTriangulator.validate()) {
-
-            // Bit of a hack to re-adjust spot shadow to fit correctly within parent canvas.
-            // Problem is that outline passed is not a final position, which throws off our
-            // whereas our shadow rendering algorithm, which requires pre-set range for
-            // optimization purposes.
-            float[] shadowBounds = Math3DHelper.flatBound(spotTriangulator.getStrips()[0], 3);
-
-            if ((shadowBounds[2] - shadowBounds[0]) > width ||
-                    (shadowBounds[3] - shadowBounds[1]) > height) {
-                // Spot shadow to be casted is larger than the parent canvas,
-                // We'll let ambient shadow do the trick and skip spot shadow here.
-                spotTriangulator = null;
-            }
-
-            translateX = Math.max(-(int) Math.floor(shadowBounds[0]), translateX);
-            translateY = Math.max(-(int) Math.floor(shadowBounds[1]), translateY);
-
-            // create bitmap of the least possible size that covers the entire shadow
-            imgW = Math.max((int) Math.ceil(shadowBounds[2] + translateX), imgW);
-            imgH = Math.max((int) Math.ceil(shadowBounds[3] + translateY), imgH);
-        }
-
-        TriangleBuffer renderer = new TriangleBuffer();
-        renderer.setSize(imgW, imgH, 0);
-
-        if (ambientTriangulator.isValid()) {
-
-            Math3DHelper.translate(ambientTriangulator.getVertices(), translateX, translateY, 2);
-            renderer.drawTriangles(ambientTriangulator.getIndices(), ambientTriangulator.getVertices(),
-                    ambientTriangulator.getColors(), ambientConfig.getShadowStrength());
-        }
-
-        if (spotTriangulator != null && spotTriangulator.validate()) {
-            float[][] strips = spotTriangulator.getStrips();
-            for (int i = 0; i < strips.length; ++i) {
-                Math3DHelper.translate(strips[i], translateX, translateY, 3);
-                renderer.drawTriangles(strips[i], ShadowConstants.SPOT_SHADOW_STRENGTH * alpha);
-            }
-        }
-
-        Bitmap img = renderer.createImage();
-
-        drawScaled(canvas, img, translateX, translateY, rectOriginal, radius, isOpaque);
-    }
-
-    /**
-     * High quality shadow does not work well with object that is too high in elevation. Check if
-     * the object elevation is reasonable and returns true if shadow will work well. False other
-     * wise.
-     */
-    private static boolean validate(float elevation, float densityDpi) {
-        float scaledElevationPx = elevation / SCALE_DOWN;
-        float scaledSpotLightHeightPx = ShadowConstants.SPOT_SHADOW_LIGHT_Z_HEIGHT_DP *
-                (densityDpi / DisplayMetrics.DENSITY_DEFAULT);
-        if (scaledElevationPx > scaledSpotLightHeightPx) {
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Draw the bitmap scaled up.
-     * @param translateX - offset in x axis by which the bitmap is shifted.
-     * @param translateY - offset in y axis by which the bitmap is shifted.
-     * @param shadowCaster - unscaled outline of shadow caster
-     * @param radius
-     */
-    private static void drawScaled(Canvas canvas, Bitmap bitmap, int translateX, int translateY,
-            Rect shadowCaster, float radius, boolean isOpaque) {
-        int unscaledTranslateX = translateX * SCALE_DOWN;
-        int unscaledTranslateY = translateY * SCALE_DOWN;
-
-        // To the canvas
-        Rect dest = new Rect(
-                -unscaledTranslateX,
-                -unscaledTranslateY,
-                (bitmap.getWidth() * SCALE_DOWN) - unscaledTranslateX,
-                (bitmap.getHeight() * SCALE_DOWN) - unscaledTranslateY);
-        Rect destSrc = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
-        // We can skip drawing the shadows behind the caster if either
-        // 1) radius is 0, the shadow caster is rectangle and we can have a perfect cut
-        // 2) shadow caster is opaque and even if remove shadow only partially it won't affect
-        // the visual quality, otherwise we will observe shadow part through the translucent caster
-        // This can be improved by:
-        // TODO: do not draw the shadow behind the caster at all during the tesselation phase
-        if (radius > 0 && !isOpaque) {
-            // Rounded edge.
-            int save = canvas.save();
-            canvas.drawBitmap(bitmap, destSrc, dest, null);
-            canvas.restoreToCount(save);
-            return;
-        }
-
-        /**
-         * ----------------------------------
-         * |                                |
-         * |              top               |
-         * |                                |
-         * ----------------------------------
-         * |      |                 |       |
-         * | left |  shadow caster  | right |
-         * |      |                 |       |
-         * ----------------------------------
-         * |                                |
-         * |            bottom              |
-         * |                                |
-         * ----------------------------------
-         *
-         * dest == top + left + shadow caster + right + bottom
-         * Visually, canvas.drawBitmap(bitmap, destSrc, dest, paint) would achieve the same result.
-         */
-        int gap = (int) Math.ceil(radius * SCALE_DOWN * sRoundedGap);
-        shadowCaster.bottom -= gap;
-        shadowCaster.top += gap;
-        shadowCaster.left += gap;
-        shadowCaster.right -= gap;
-        Rect left = new Rect(dest.left, shadowCaster.top, shadowCaster.left,
-                shadowCaster.bottom);
-        int leftScaled = left.width() / SCALE_DOWN + destSrc.left;
-
-        Rect top = new Rect(dest.left, dest.top, dest.right, shadowCaster.top);
-        int topScaled = top.height() / SCALE_DOWN + destSrc.top;
-
-        Rect right = new Rect(shadowCaster.right, shadowCaster.top, dest.right,
-                shadowCaster.bottom);
-        int rightScaled = (shadowCaster.right - dest.left) / SCALE_DOWN + destSrc.left;
-
-        Rect bottom = new Rect(dest.left, shadowCaster.bottom, dest.right, dest.bottom);
-        int bottomScaled = (shadowCaster.bottom - dest.top) / SCALE_DOWN + destSrc.top;
-
-        // calculate parts of the middle ground that can be ignored.
-        Rect leftSrc = new Rect(destSrc.left, topScaled, leftScaled, bottomScaled);
-        Rect topSrc = new Rect(destSrc.left, destSrc.top, destSrc.right, topScaled);
-        Rect rightSrc = new Rect(rightScaled, topScaled, destSrc.right, bottomScaled);
-        Rect bottomSrc = new Rect(destSrc.left, bottomScaled, destSrc.right, destSrc.bottom);
-
-        int save = canvas.save();
-        Paint paint = new Paint();
-        canvas.drawBitmap(bitmap, leftSrc, left, paint);
-        canvas.drawBitmap(bitmap, topSrc, top, paint);
-        canvas.drawBitmap(bitmap, rightSrc, right, paint);
-        canvas.drawBitmap(bitmap, bottomSrc, bottom, paint);
-        canvas.restoreToCount(save);
-    }
-
-    private static float[] getPoly(Rect rect, float elevation, float radius) {
-        if (radius <= 0) {
-            float[] poly = new float[ShadowConstants.RECT_VERTICES_SIZE * ShadowConstants.COORDINATE_SIZE];
-
-            poly[0] = poly[9] = rect.left;
-            poly[1] = poly[4] = rect.top;
-            poly[3] = poly[6] = rect.right;
-            poly[7] = poly[10] = rect.bottom;
-            poly[2] = poly[5] = poly[8] = poly[11] = elevation;
-
-            return poly;
-        }
-
-        return buildRoundedEdges(rect, elevation, radius);
-    }
-
-    private static float[] buildRoundedEdges(
-            Rect rect, float elevation, float radius) {
-
-        float[] roundedEdgeVertices = new float[(ShadowConstants.SPLICE_ROUNDED_EDGE + 1) * 4 * 3];
-        int index = 0;
-        // 1.0 LT. From theta 0 to pi/2 in K division.
-        for (int i = 0; i <= ShadowConstants.SPLICE_ROUNDED_EDGE; i++) {
-            double theta = (Math.PI / 2.0d) * ((double) i / ShadowConstants.SPLICE_ROUNDED_EDGE);
-            float x = (float) (rect.left + (radius - radius * Math.cos(theta)));
-            float y = (float) (rect.top + (radius - radius * Math.sin(theta)));
-            roundedEdgeVertices[index++] = x;
-            roundedEdgeVertices[index++] = y;
-            roundedEdgeVertices[index++] = elevation;
-        }
-
-        // 2.0 RT
-        for (int i = ShadowConstants.SPLICE_ROUNDED_EDGE; i >= 0; i--) {
-            double theta = (Math.PI / 2.0d) * ((double) i / ShadowConstants.SPLICE_ROUNDED_EDGE);
-            float x = (float) (rect.right - (radius - radius * Math.cos(theta)));
-            float y = (float) (rect.top + (radius - radius * Math.sin(theta)));
-            roundedEdgeVertices[index++] = x;
-            roundedEdgeVertices[index++] = y;
-            roundedEdgeVertices[index++] = elevation;
-        }
-
-        // 3.0 RB
-        for (int i = 0; i <= ShadowConstants.SPLICE_ROUNDED_EDGE; i++) {
-            double theta = (Math.PI / 2.0d) * ((double) i / ShadowConstants.SPLICE_ROUNDED_EDGE);
-            float x = (float) (rect.right - (radius - radius * Math.cos(theta)));
-            float y = (float) (rect.bottom - (radius - radius * Math.sin(theta)));
-            roundedEdgeVertices[index++] = x;
-            roundedEdgeVertices[index++] = y;
-            roundedEdgeVertices[index++] = elevation;
-        }
-
-        // 4.0 LB
-        for (int i = ShadowConstants.SPLICE_ROUNDED_EDGE; i >= 0; i--) {
-            double theta = (Math.PI / 2.0d) * ((double) i / ShadowConstants.SPLICE_ROUNDED_EDGE);
-            float x = (float) (rect.left + (radius - radius * Math.cos(theta)));
-            float y = (float) (rect.bottom - (radius - radius * Math.sin(theta)));
-            roundedEdgeVertices[index++] = x;
-            roundedEdgeVertices[index++] = y;
-            roundedEdgeVertices[index++] = elevation;
-        }
-
-        return roundedEdgeVertices;
-    }
-}
diff --git a/bridge/src/android/view/shadow/ShadowConstants.java b/bridge/src/android/view/shadow/ShadowConstants.java
deleted file mode 100644
index 049a549..0000000
--- a/bridge/src/android/view/shadow/ShadowConstants.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.view.shadow;
-
-/**
- * Constant values for shadow related configuration
- */
-class ShadowConstants {
-
-    /**
-     * This is used as a factor by which to scale down the shadow bitmap. If we have world
-     * Width x Height, shadow bitmap will be Width/SCALE_DOWN x Height/SCALE_DOWN and during
-     * canvas draw the shadow will be scaled up, resulting faster perf (due to smaller bitmap) but
-     * blurrier (lower quality) shadow.
-     */
-    public static final int SCALE_DOWN = 5;
-
-    public static final float MIN_ALPHA = 0.2f;
-
-    public static final int SPOT_SHADOW_LIGHT_Z_HEIGHT_DP = 50 / SCALE_DOWN;
-    public static final int SPOT_SHADOW_LIGHT_Z_EPSILON = 10 / SCALE_DOWN;
-    public static final float SPOT_SHADOW_STRENGTH = 0.3f;
-
-    public static final float AMBIENT_SHADOW_EDGE_SCALE = 60f;
-    public static final float AMBIENT_SHADOW_SHADOW_BOUND = 0.02f * SCALE_DOWN;
-    public static final float AMBIENT_SHADOW_STRENGTH = 1.0f;
-
-    public static final int COORDINATE_SIZE = 3;
-    public static final int RECT_VERTICES_SIZE = 4;
-
-    public static final int SPLICE_ROUNDED_EDGE = 5;
-}
diff --git a/bridge/src/android/view/shadow/SpotShadowConfig.java b/bridge/src/android/view/shadow/SpotShadowConfig.java
deleted file mode 100644
index 7b4fa4b..0000000
--- a/bridge/src/android/view/shadow/SpotShadowConfig.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.view.shadow;
-
-
-/**
- * Model for spot shadow rendering. Assumes single light, single object.
- */
-class SpotShadowConfig {
-
-    // No need to be final but making it immutable for now.
-    private final int mLightRadius;
-
-
-    // No need to be final but making it immutable for now.
-    private final float[] mPoly;
-    private final int mPolyLength;
-
-    private float[] mLightCoord;
-
-    private final float mShadowStrength;
-
-    private SpotShadowConfig(SpotShadowConfig.Builder builder) {
-        mLightRadius = builder.mLightRadius;
-        mPoly = builder.mPoly;
-        mPolyLength = builder.mPolyLength;
-
-        mLightCoord = new float[3];
-        mLightCoord[0] = builder.mLightX;
-        mLightCoord[1] = builder.mLightY;
-        mLightCoord[2] = builder.mLightHeight;
-        mShadowStrength = builder.mShadowStrength;
-    }
-
-    /**
-     * @return size of the light source radius (light source is always generated as a circular shape)
-     */
-    public int getLightRadius() {
-        return mLightRadius;
-    }
-
-    /**
-     * @return object that casts shadow. xyz coordinates.
-     */
-    public float[] getPoly() {
-        return mPoly;
-    }
-
-    /**
-     * @return # of vertices in the object {@link #getPoly()} that casts shadow.
-     */
-    public int getPolyLength() {
-        return mPolyLength;
-    }
-
-    /**
-     * Update the light source coord.
-     * @param x - horizontal coordinate
-     * @param y - vertical coordinate
-     */
-    public void setLightCoord(float x, float y) {
-        mLightCoord[0] = x;
-        mLightCoord[1] = y;
-    }
-
-    /**
-     * @return shadow intensity from 0 to 1
-     */
-    public float getShadowStrength() {
-        return mShadowStrength;
-    }
-
-    public float[] getLightCoord() {
-        return mLightCoord;
-    }
-
-    public static class Builder {
-
-        // No need to be final but making it immutable for now.
-        private int mLightRadius;
-
-        // No need to be final but making it immutable for now.
-        private float[] mPoly;
-        private int mPolyLength;
-
-        private float mLightX;
-        private float mLightY;
-        private float mLightHeight;
-
-        private float mShadowStrength;
-
-        /**
-         * @param shadowStrength from 0 to 1
-         */
-        public Builder setShadowStrength(float shadowStrength) {
-            this.mShadowStrength = shadowStrength;
-            return this;
-        }
-
-        public Builder setLightRadius(int mLightRadius) {
-            this.mLightRadius = mLightRadius;
-            return this;
-        }
-
-        public Builder setPolygon(float[] poly, int polyLength) {
-            this.mPoly = poly;
-            this.mPolyLength = polyLength;
-            return this;
-        }
-
-        public Builder setLightCoord(float lightX, float lightY, float lightHeight) {
-            this.mLightX = lightX;
-            this.mLightY = lightY;
-            this.mLightHeight = lightHeight;
-            return this;
-        }
-
-        public SpotShadowConfig build() {
-            return new SpotShadowConfig(this);
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/bridge/src/android/view/shadow/SpotShadowTriangulator.java b/bridge/src/android/view/shadow/SpotShadowTriangulator.java
deleted file mode 100644
index d666153..0000000
--- a/bridge/src/android/view/shadow/SpotShadowTriangulator.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.view.shadow;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-
-/**
- * Generate spot shadow bitmap.
- */
-class SpotShadowTriangulator {
-
-    private final SpotShadowConfig mShadowConfig;
-    private float[][] mStrips;
-
-    public SpotShadowTriangulator(SpotShadowConfig config) {
-        mShadowConfig = config;
-    }
-
-    /**
-     * Populate the shadow bitmap.
-     */
-    public void triangulate() {
-        try {
-            float[] lightSources =
-                    SpotShadowVertexCalculator.calculateLight(mShadowConfig.getLightRadius(),
-                            mShadowConfig.getLightCoord()[0],
-                            mShadowConfig.getLightCoord()[1], mShadowConfig.getLightCoord()[2]);
-
-
-            mStrips = new float[2][];
-            int[] sizes = SpotShadowVertexCalculator.getStripSizes(mShadowConfig.getPolyLength());
-            for (int i = 0; i < sizes.length; ++i) {
-                mStrips[i] = new float[3 * sizes[i]];
-            }
-
-            SpotShadowVertexCalculator.calculateShadow(lightSources,
-                    mShadowConfig.getPoly(),
-                    mShadowConfig.getPolyLength(),
-                    mShadowConfig.getShadowStrength(),
-                    mStrips);
-        } catch (IndexOutOfBoundsException|ArithmeticException mathError) {
-            Bridge.getLog().warning(ILayoutLog.TAG_INFO,  "Arithmetic error while drawing " +
-                            "spot shadow",
-                    null, mathError);
-        } catch (Exception ex) {
-            Bridge.getLog().warning(ILayoutLog.TAG_INFO,  "Error while drawing shadow",
-                    null, ex);
-        }
-    }
-    /**
-     * @return true if generated shadow poly is valid. False otherwise.
-     */
-    public boolean validate() {
-        return mStrips != null && mStrips[0].length >= 9;
-    }
-
-    public float[][] getStrips() {
-        return mStrips;
-    }
-}
diff --git a/bridge/src/android/view/shadow/SpotShadowVertexCalculator.java b/bridge/src/android/view/shadow/SpotShadowVertexCalculator.java
deleted file mode 100644
index fc02d18..0000000
--- a/bridge/src/android/view/shadow/SpotShadowVertexCalculator.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.view.shadow;
-
-import android.graphics.Rect;
-import android.view.math.Math3DHelper;
-
-/**
- * Generates the vertices required for spot shadow and all other shadow-related rendering.
- */
-class SpotShadowVertexCalculator {
-
-    private SpotShadowVertexCalculator() { }
-
-    /**
-     * Create evenly distributed circular light source points from x and y (on flat z plane).
-     * This is useful for ray tracing the shadow points later. Format : (x1,y1,z1,x2,y2,z2 ...)
-     *
-     * @param radius - radius of the light source
-     * @param x - center X of the light source
-     * @param y - center Y of the light source
-     * @param height - how high (z depth) the light should be
-     * @return float points (x,y,z) of light source points.
-     */
-    public static float[] calculateLight(float radius, float x, float y, float height) {
-        float[] ret = new float[4 * 3];
-        // bottom
-        ret[0] = x;
-        ret[1] = y + radius;
-        ret[2] = height;
-        // left
-        ret[3] = x - radius;
-        ret[4] = y;
-        ret[5] = height;
-        // top
-        ret[6] = x;
-        ret[7] = y - radius;
-        ret[8] = height;
-        // right
-        ret[9] = x + radius;
-        ret[10] = y;
-        ret[11] = height;
-
-        return ret;
-    }
-
-    /**
-     * @param polyLength - length of the outline polygon
-     * @return size required for shadow vertices mData array based on # of vertices in the
-     * outline polygon
-     */
-    public static int[] getStripSizes(int polyLength){
-        return new int[] { ((polyLength + 4) / 8) * 16 + 2, 4};
-    }
-
-    /**
-     * Generate shadow vertices based on params. Format : (x1,y1,z1,x2,y2,z2 ...)
-     * Precondition : Light poly must be evenly distributed on a flat surface
-     * Precondition : Poly vertices must be a convex
-     * Precondition : Light height must be higher than any poly vertices
-     *
-     * @param lightPoly - Vertices of a light source.
-     * @param poly - Vertices of opaque object casting shadow
-     * @param polyLength - Size of the vertices
-     * @param strength - Strength of the shadow overall [0-1]
-     * @param retstrips - Arrays of triplets, each triplet represents a point, thus every array to
-     * be filled in format : {x1, y1, z1, x2, y2, z2, ...},
-     * every 3 consecutive triplets constitute a triangle to fill, namely [t1, t2, t3], [t2, t3,
-     * t4], ... If at some point [t(n-1), tn, t(n+1)] is no longer a desired a triangle and
-     * there are more triangles to draw one can start a new array, hence retstrips is a 2D array.
-     */
-    public static void calculateShadow(
-            float[] lightPoly,
-            float[] poly,
-            int polyLength,
-            float strength,
-            float[][] retstrips) {
-        float[] outerStrip = retstrips[0];
-
-        // We would like to unify the cases where we have roundrects and rectangles
-        int roundedEdgeSegments = ((polyLength == 4) ? 0 : ShadowConstants.SPLICE_ROUNDED_EDGE);
-        int sideLength = (roundedEdgeSegments / 2 + 1) * 2;
-        float[] umbra = new float[4 * 2 * sideLength];
-        int idx = (roundedEdgeSegments + 1) / 2;
-        int uShift = 0;
-        // If we have even number of segments in rounded corner (0 included), the central point of
-        // rounded corner contributes to the hull twice, from 2 different light sources, thus
-        // rollBack in that case, otherwise every point contributes only once
-        int rollBack = (((polyLength % 8) == 0) ? 0 : 1);
-        // Calculate umbra - a hull of all projections
-        for (int s = 0; s < 4; ++s) { // 4 sides
-            float lx = lightPoly[s * 3 + 0];
-            float ly = lightPoly[s * 3 + 1];
-            float lz = lightPoly[s * 3 + 2];
-            for (int i = 0; i < sideLength; ++i, uShift += 2, ++idx) {
-                int shift = (idx % polyLength) * 3;
-
-                float t = lz / (lz - poly[shift + 2]);
-
-                umbra[uShift + 0] = lx - t * (lx - poly[shift + 0]);
-                umbra[uShift + 1] = ly - t * (ly - poly[shift + 1]);
-            }
-
-            idx -= rollBack;
-        }
-
-        idx = roundedEdgeSegments;
-        // An array that wil contain top, right, bottom, left coordinate of penumbra
-        float[] penumbraRect = new float[4];
-        // Calculate penumbra
-        for (int s = 0; s < 4; ++s, idx += (roundedEdgeSegments + 1)) { // 4 sides
-            int sp = (s + 2) % 4;
-
-            float lz = lightPoly[sp * 3 + 2];
-
-            int shift = (idx % polyLength) * 3;
-
-            float t = lz / (lz - poly[shift + 2]);
-
-            // We are interested in just one coordinate: x or y, depending on the light source
-            int c = (s + 1) % 2;
-            penumbraRect[s] =
-                    lightPoly[sp * 3 + c] - t * (lightPoly[sp * 3 + c] - poly[shift + c]);
-        }
-        if (penumbraRect[0] > penumbraRect[2]) {
-            float tmp = (penumbraRect[0] + penumbraRect[2]) / 2.0f;
-            penumbraRect[0] = penumbraRect[2] = tmp;
-        }
-        if (penumbraRect[3] > penumbraRect[1]) {
-            float tmp = (penumbraRect[1] + penumbraRect[3]) / 2.0f;
-            penumbraRect[1] = penumbraRect[3] = tmp;
-        }
-
-        // Now just connect umbra points (at least 8 of them) with the closest points from
-        // penumbra (only 4 of them) to form triangles to fill the entire space between umbra and
-        // penumbra
-        idx = sideLength * 4 - sideLength / 2;
-        int rsShift = 0;
-        for (int s = 0; s < 4; ++s) {
-            int xidx = (((s + 3) % 4) / 2) * 2 + 1;
-            int yidx = (s / 2) * 2;
-            float penumbraX = penumbraRect[xidx];
-            float penumbraY = penumbraRect[yidx];
-            for (int i = 0; i < sideLength; ++i, rsShift += 6, ++idx) {
-                int shift = (idx % (sideLength * 4)) * 2;
-
-                outerStrip[rsShift + 0] = umbra[shift + 0];
-                outerStrip[rsShift + 1] = umbra[shift + 1];
-                outerStrip[rsShift + 3] = penumbraX;
-                outerStrip[rsShift + 4] = penumbraY;
-                outerStrip[rsShift + 5] = strength;
-            }
-        }
-        // Connect with the beginning
-        outerStrip[rsShift + 0] = outerStrip[0];
-        outerStrip[rsShift + 1] = outerStrip[1];
-        // outerStrip[rsShift + 2] = 0;
-        outerStrip[rsShift + 3] = outerStrip[3];
-        outerStrip[rsShift + 4] = outerStrip[4];
-        outerStrip[rsShift + 5] = strength;
-
-        float[] innerStrip = retstrips[1];
-        // Covering penumbra rectangle
-        // left, top
-        innerStrip[0] = penumbraRect[3];
-        innerStrip[1] = penumbraRect[0];
-        innerStrip[2] = strength;
-        // right, top
-        innerStrip[3] = penumbraRect[1];
-        innerStrip[4] = penumbraRect[0];
-        innerStrip[5] = strength;
-        // left, bottom
-        innerStrip[6] = penumbraRect[3];
-        innerStrip[7] = penumbraRect[2];
-        innerStrip[8] = strength;
-        // right, bottom
-        innerStrip[9] = penumbraRect[1];
-        innerStrip[10] = penumbraRect[2];
-        innerStrip[11] = strength;
-    }
-}
\ No newline at end of file
diff --git a/bridge/src/android/view/shadow/TriangleBuffer.java b/bridge/src/android/view/shadow/TriangleBuffer.java
deleted file mode 100644
index 3c01171..0000000
--- a/bridge/src/android/view/shadow/TriangleBuffer.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.view.shadow;
-
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.view.math.Math3DHelper;
-
-import java.util.Arrays;
-
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-/**
- * 2D Triangle buffer element that colours using z value. (z scale set).
- */
-class TriangleBuffer {
-    int mWidth;
-    int mHeight;
-    int mImgWidth;
-    int mImgHeight;
-    int mBorder;
-    Bitmap mBitmap;
-    int mData[];
-
-    public void setSize(int width, int height, int border) {
-        if (mWidth == width && mHeight == height) {
-            return;
-        }
-        mWidth = width-2*border;
-        mHeight = height-2*border;
-        mBorder = border;
-        mImgWidth = width;
-        mImgHeight = height;
-
-        mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
-        mData = new int[width * height];
-    }
-
-    public void drawTriangles(int[] index, float[] vert, float[] color,float scale) {
-        int indexSize = index.length / 3;
-        for (int i = 0; i < indexSize; i++) {
-            int vIndex = index[i * 3 + 0];
-            float vx = vert[vIndex * 2 + 0];
-            float vy = vert[vIndex * 2 + 1];
-            float c =  scale*color[vIndex * 4 + 3];
-            float fx3 = vx, fy3 = vy, fz3 = c;
-
-            vIndex = index[i * 3 + 1];
-            vx = vert[vIndex * 2 + 0];
-            vy = vert[vIndex * 2 + 1];
-            c =  scale*color[vIndex * 4 + 3];
-            float fx2 = vx, fy2 = vy, fz2 = c;
-
-            vIndex = index[i * 3 + 2];
-            vx = vert[vIndex * 2 + 0];
-            vy = vert[vIndex * 2 + 1];
-            c =  scale*color[vIndex * 4 + 3];
-            float fx1 = vx, fy1 = vy, fz1 = c;
-
-            triangleZBuffMin(mData, mImgWidth, mImgHeight, fx1, fy1, fz1, fx2, fy2,
-                    fz2, fx3, fy3, fz3);
-        }
-    }
-
-    public void drawTriangles(float[] strip,float scale) {
-        for (int i = 0; i < strip.length-8; i+=3) {
-            float fx3 = strip[i], fy3 = strip[i+1], fz3 = scale* strip[i+2];
-            float fx2 = strip[i+3], fy2 = strip[i+4], fz2 = scale* strip[i+5];
-            float fx1 = strip[i+6], fy1 = strip[i+7], fz1 = scale* strip[i+8];
-
-            if (fx1*(fy2-fy3)+fx2*(fy3-fy1)+fx3*(fy1-fy2) ==0) {
-                continue;
-            }
-            triangleZBuffMin(mData, mImgWidth, mImgHeight, fx3, fy3, fz3, fx2, fy2,
-                    fz2, fx1, fy1, fz1);
-        }
-    }
-
-    public Bitmap createImage() {
-        mBitmap.setPixels(mData, 0, mWidth, 0, 0, mWidth, mHeight);
-        return mBitmap;
-    }
-
-    private static void triangleZBuffMin(int[] buff, int w, int h, float fx3,
-            float fy3, float fz3, float fx2, float fy2, float fz2, float fx1,
-            float fy1, float fz1) {
-        if (((fx1 - fx2) * (fy3 - fy2) - (fy1 - fy2) * (fx3 - fx2)) < 0) {
-            float tmpx = fx1;
-            float tmpy = fy1;
-            float tmpz = fz1;
-            fx1 = fx2;
-            fy1 = fy2;
-            fz1 = fz2;
-            fx2 = tmpx;
-            fy2 = tmpy;
-            fz2 = tmpz;
-        }
-        // using maxmima
-        // solve([x1*dx+y1*dy+zoff=z1,x2*dx+y2*dy+zoff=z2,x3*dx+y3*dy+zoff=z3],[dx,dy,zoff]);
-        double d = (fx1 * (fy3 - fy2) - fx2 * fy3 + fx3 * fy2 + (fx2 - fx3) * fy1);
-        if (d == 0) {
-            return;
-        }
-        float dx = (float) (-(fy1 * (fz3 - fz2) - fy2 * fz3 + fy3 * fz2 + (fy2 - fy3)
-                * fz1) / d);
-        float dy = (float) ((fx1 * (fz3 - fz2) - fx2 * fz3 + fx3 * fz2 + (fx2 - fx3)
-                * fz1) / d);
-        float zoff = (float) ((fx1 * (fy3 * fz2 - fy2 * fz3) + fy1
-                * (fx2 * fz3 - fx3 * fz2) + (fx3 * fy2 - fx2 * fy3) * fz1) / d);
-
-        // 28.4 fixed-point coordinates
-        int y1 = (int) (16.0f * fy1 + .5f);
-        int y2 = (int) (16.0f * fy2 + .5f);
-        int y3 = (int) (16.0f * fy3 + .5f);
-
-        int x1 = (int) (16.0f * fx1 + .5f);
-        int x2 = (int) (16.0f * fx2 + .5f);
-        int x3 = (int) (16.0f * fx3 + .5f);
-
-        int dx12 = x1 - x2;
-        int dx23 = x2 - x3;
-        int dx31 = x3 - x1;
-
-        int dy12 = y1 - y2;
-        int dy23 = y2 - y3;
-        int dy31 = y3 - y1;
-
-        int fdx12 = dx12 << 4;
-        int fdx23 = dx23 << 4;
-        int fdx31 = dx31 << 4;
-
-        int fdy12 = dy12 << 4;
-        int fdy23 = dy23 << 4;
-        int fdy31 = dy31 << 4;
-
-        int minx = (Math3DHelper.min(x1, x2, x3) + 0xF) >> 4;
-        int maxx = (Math3DHelper.max(x1, x2, x3) + 0xF) >> 4;
-        int miny = (Math3DHelper.min(y1, y2, y3) + 0xF) >> 4;
-        int maxy = (Math3DHelper.max(y1, y2, y3) + 0xF) >> 4;
-
-        if (miny < 0) {
-            miny = 0;
-        }
-        if (minx < 0) {
-            minx = 0;
-        }
-        if (maxx > w) {
-            maxx = w;
-        }
-        if (maxy > h) {
-            maxy = h;
-        }
-        int off = miny * w;
-
-        int c1 = dy12 * x1 - dx12 * y1;
-        int c2 = dy23 * x2 - dx23 * y2;
-        int c3 = dy31 * x3 - dx31 * y3;
-
-        if (dy12 < 0 || (dy12 == 0 && dx12 > 0)) {
-            c1++;
-        }
-        if (dy23 < 0 || (dy23 == 0 && dx23 > 0)) {
-            c2++;
-        }
-        if (dy31 < 0 || (dy31 == 0 && dx31 > 0)) {
-            c3++;
-        }
-        int cy1 = c1 + dx12 * (miny << 4) - dy12 * (minx << 4);
-        int cy2 = c2 + dx23 * (miny << 4) - dy23 * (minx << 4);
-        int cy3 = c3 + dx31 * (miny << 4) - dy31 * (minx << 4);
-
-        for (int y = miny; y < maxy; y++) {
-            int cx1 = cy1;
-            int cx2 = cy2;
-            int cx3 = cy3;
-            float p = zoff + dy * y;
-
-            int startx = start(cx1, fdy12, minx, minx, maxx);
-            startx = start(cx2, fdy23, minx, startx, maxx);
-            startx = start(cx3, fdy31, minx, startx, maxx);
-
-            cx1 -= (startx - minx) * fdy12;
-            cx2 -= (startx - minx) * fdy23;
-            cx3 -= (startx - minx) * fdy31;
-
-            int endx = end(cx1, fdy12, startx, minx, maxx);
-            endx = end(cx2, fdy23, startx, minx, endx);
-            endx = end(cx3, fdy31, startx, minx, endx);
-
-            for (int x = startx; x < endx; x++) {
-                int point = x + off;
-                float zval = p + dx * x;
-                // Simple alpha-blending
-                int prev = (buff[point] >> 24) & 0xFF;
-                int res = (int) (zval * (255 - prev )) + prev;
-                buff[point] = res << 24;
-            }
-            cy1 += fdx12;
-            cy2 += fdx23;
-            cy3 += fdx31;
-            off += w;
-        }
-    }
-
-    /**
-     * Returns the minimum value of x in the range [minx, maxx]: y0 - dy * (x - x0) > 0
-     * If no value satisfies the expression, maxx is returned
-     *
-     * @param y0 - value in x0
-     * @param dy - delta y
-     * @param x0 - some position, for which value is known (y0)
-     * @param minx - start of the range
-     * @param maxx - end of the range
-     * @return minimum x
-     */
-    private static int start(int y0, int dy, int x0, int minx, int maxx) {
-        if (y0 > 0) {
-            return minx;
-        }
-        if (dy >= 0) {
-            return maxx;
-        }
-        return max(x0 + y0 / dy + 1, minx);
-    }
-
-    /**
-     * Returns the minimum value of x in range [minx, maxx]: y0 - dy * (x - x0) <= 0
-     * If no value satisfies the expression maxx is returned
-     *
-     * @param y0 - value in x0
-     * @param dy - delta y
-     * @param x0 - some position, for which value is known (y0)
-     * @param minx - start of the range
-     * @param maxx - end of the range
-     * @return minimum x
-     */
-    private static int end(int y0, int dy, int x0, int minx, int maxx) {
-        if (y0 <= 0) {
-            return minx;
-        }
-        if (dy <= 0) {
-            return maxx;
-        }
-        return min(x0 + (y0 - 1) / dy + 1, maxx);
-    }
-
-    public void clear() {
-        Arrays.fill(mData, 0);
-    }
-}
\ No newline at end of file
diff --git a/bridge/src/com/android/internal/util/ArrayUtils_Delegate.java b/bridge/src/com/android/internal/util/ArrayUtils_Delegate.java
new file mode 100644
index 0000000..f830f0e
--- /dev/null
+++ b/bridge/src/com/android/internal/util/ArrayUtils_Delegate.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.internal.util;
+
+import java.util.Arrays;
+
+public class ArrayUtils_Delegate {
+    public static void clearCache() {
+        // Prevent cache from retaining ModuleClassLoader classes, so that when we change
+        // ModuleClassLoader (when rebuilding or using other project/module) we can free the memory.
+        Arrays.fill(ArrayUtils.sCache, null);
+    }
+}
diff --git a/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java b/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java
deleted file mode 100644
index 01fe45d..0000000
--- a/bridge/src/com/android/internal/util/VirtualRefBasePtr_Delegate.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-package com.android.internal.util;
-
-import com.android.layoutlib.bridge.impl.DelegateManager;
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.util.LongSparseLongArray;
-
-/**
- * Delegate used to provide new implementation the native methods of {@link VirtualRefBasePtr}
- *
- * Through the layoutlib_create tool, the original native  methods of VirtualRefBasePtr have been
- * replaced by calls to methods of the same name in this delegate class.
- *
- */
-@SuppressWarnings("unused")
-public class VirtualRefBasePtr_Delegate {
-    private static final DelegateManager<Object> sManager = new DelegateManager<>(Object.class);
-    private static final LongSparseLongArray sRefCount = new LongSparseLongArray();
-
-    @LayoutlibDelegate
-    /*package*/ static synchronized void nIncStrong(long ptr) {
-        long counter = sRefCount.get(ptr);
-        sRefCount.put(ptr, ++counter);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static synchronized void nDecStrong(long ptr) {
-        long counter = sRefCount.get(ptr);
-
-        if (counter > 1) {
-            sRefCount.put(ptr, --counter);
-        } else {
-            sRefCount.delete(ptr);
-            sManager.removeJavaReferenceFor(ptr);
-        }
-    }
-}
diff --git a/bridge/src/com/android/layoutlib/bridge/Bridge.java b/bridge/src/com/android/layoutlib/bridge/Bridge.java
index aa76e75..76af367 100644
--- a/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -24,28 +24,33 @@
 import com.android.ide.common.rendering.api.Result;
 import com.android.ide.common.rendering.api.Result.Status;
 import com.android.ide.common.rendering.api.SessionParams;
+import com.android.ide.common.rendering.api.XmlParserFactory;
 import com.android.layoutlib.bridge.android.RenderParamsFlags;
+import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.RenderDrawable;
 import com.android.layoutlib.bridge.impl.RenderSessionImpl;
 import com.android.layoutlib.bridge.util.DynamicIdMap;
-import com.android.ninepatch.NinePatchChunk;
+import com.android.layoutlib.common.util.ReflectionUtils;
 import com.android.resources.ResourceType;
+import com.android.tools.layoutlib.annotations.NonNull;
 import com.android.tools.layoutlib.annotations.Nullable;
 import com.android.tools.layoutlib.create.MethodAdapter;
+import com.android.tools.layoutlib.create.NativeConfig;
 import com.android.tools.layoutlib.create.OverrideMethod;
 import com.android.utils.Pair;
 
-import android.animation.PropertyValuesHolder;
-import android.animation.PropertyValuesHolder_Delegate;
+import org.kxml2.io.KXmlParser;
+import org.xmlpull.v1.XmlPullParser;
+
 import android.content.res.BridgeAssetManager;
 import android.graphics.Bitmap;
-import android.graphics.FontFamily_Delegate;
 import android.graphics.Typeface;
 import android.graphics.Typeface_Builder_Delegate;
-import android.graphics.Typeface_Delegate;
+import android.graphics.fonts.SystemFonts_Delegate;
 import android.icu.util.ULocale;
 import android.os.Looper;
 import android.os.Looper_Accessor;
+import android.os.SystemProperties;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
@@ -57,7 +62,9 @@
 import java.util.Arrays;
 import java.util.EnumMap;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.WeakHashMap;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -109,12 +116,8 @@
 
     private final static Map<Object, Map<String, SoftReference<Bitmap>>> sProjectBitmapCache =
             new WeakHashMap<>();
-    private final static Map<Object, Map<String, SoftReference<NinePatchChunk>>> sProject9PatchCache =
-            new WeakHashMap<>();
 
     private final static Map<String, SoftReference<Bitmap>> sFrameworkBitmapCache = new HashMap<>();
-    private final static Map<String, SoftReference<NinePatchChunk>> sFramework9PatchCache =
-            new HashMap<>();
 
     private static Map<String, Map<String, Integer>> sEnumValueMap;
     private static Map<String, String> sPlatformProperties;
@@ -138,6 +141,11 @@
         public void warning(String tag, String message, Object viewCookie, Object data) {
             System.out.println(message);
         }
+
+        @Override
+        public void logAndroidFramework(int priority, String tag, String message) {
+            System.out.println(message);
+        }
     };
 
     /**
@@ -145,7 +153,12 @@
      */
     private static ILayoutLog sCurrentLog = sDefaultLog;
 
-    public static boolean sIsTypefaceInitialized;
+    private static String sIcuDataPath;
+
+    private static final String[] LINUX_NATIVE_LIBRARIES = {"libandroid_runtime.so"};
+    private static final String[] MAC_NATIVE_LIBRARIES = {"libandroid_runtime.dylib"};
+    private static final String[] WINDOWS_NATIVE_LIBRARIES =
+            {"libicuuc_stubdata.dll", "libicuuc-host.dll", "libandroid_runtime.dll"};
 
     @Override
     public boolean init(Map<String,String> platformProperties,
@@ -156,8 +169,12 @@
             ILayoutLog log) {
         sPlatformProperties = platformProperties;
         sEnumValueMap = enumValueMap;
+        sIcuDataPath = icuDataPath;
+        sCurrentLog = log;
 
-        BridgeAssetManager.initSystem();
+        if (!loadNativeLibrariesIfNeeded(log, nativeLibPath)) {
+            return false;
+        }
 
         // When DEBUG_LAYOUT is set and is not 0 or false, setup a default listener
         // on static (native) methods which prints the signature on the console and
@@ -188,9 +205,46 @@
             });
         }
 
-        // load the fonts.
-        FontFamily_Delegate.setFontLocation(fontLocation.getAbsolutePath());
-        MemoryMappedFile_Delegate.setDataDir(fontLocation.getAbsoluteFile().getParentFile());
+        try {
+            BridgeAssetManager.initSystem();
+
+            // Do the static initialization of all the classes for which it was deferred.
+            // In order to initialize Typeface, we first need to specify the location of fonts
+            // and set a parser factory that will be used to parse the fonts.xml file.
+            SystemFonts_Delegate.setFontLocation(fontLocation.getAbsolutePath() + File.separator);
+            MemoryMappedFile_Delegate.setDataDir(fontLocation.getAbsoluteFile().getParentFile());
+            ParserFactory.setParserFactory(new XmlParserFactory() {
+                @Override
+                @Nullable
+                public XmlPullParser createXmlParserForPsiFile(@NonNull String fileName) {
+                    return null;
+                }
+
+                @Override
+                @Nullable
+                public XmlPullParser createXmlParserForFile(@NonNull String fileName) {
+                    return null;
+                }
+
+                @Override
+                @NonNull
+                public XmlPullParser createXmlParser() {
+                    return new KXmlParser();
+                }
+            });
+            for (String deferredClass : NativeConfig.DEFERRED_STATIC_INITIALIZER_CLASSES) {
+                ReflectionUtils.invokeStatic(deferredClass, "deferredStaticInitializer");
+            }
+            // Load system fonts now that Typeface has been initialized
+            Typeface.loadPreinstalledSystemFontMap();
+            ParserFactory.setParserFactory(null);
+        } catch (Throwable t) {
+            if (log != null) {
+                log.error(ILayoutLog.TAG_BROKEN, "Layoutlib Bridge initialization failed", t,
+                        null, null);
+            }
+            return false;
+        }
 
         // now parse com.android.internal.R (and only this one as android.R is a subset of
         // the internal version), and put the content in the maps.
@@ -253,6 +307,17 @@
     }
 
     /**
+     * Sets System properties using the Android framework code.
+     * This is accessed by the native libraries through JNI.
+     */
+    @SuppressWarnings("unused")
+    private static void setSystemProperties() {
+        for (Entry<String, String> property : sPlatformProperties.entrySet()) {
+            SystemProperties.set(property.getKey(), property.getValue());
+        }
+    }
+
+    /**
      * Tests if the field is pubic, static and one of int or int[].
      */
     private static boolean isValidRField(Field field) {
@@ -337,10 +402,9 @@
         BridgeAssetManager.clearSystem();
 
         // dispose of the default typeface.
-        if (sIsTypefaceInitialized) {
+        if (SystemFonts_Delegate.sIsTypefaceInitialized) {
             Typeface.sDynamicTypefaceCache.evictAll();
         }
-        sProject9PatchCache.clear();
         sProjectBitmapCache.clear();
 
         return true;
@@ -422,14 +486,12 @@
     public void clearResourceCaches(Object projectKey) {
         if (projectKey != null) {
             sProjectBitmapCache.remove(projectKey);
-            sProject9PatchCache.remove(projectKey);
         }
     }
 
     @Override
     public void clearAllCaches(Object projectKey) {
         clearResourceCaches(projectKey);
-        PropertyValuesHolder_Delegate.clearCaches();
     }
 
     @Override
@@ -570,13 +632,6 @@
     }
 
     /**
-     * Returns the platform build properties.
-     */
-    public static Map<String, String> getPlatformProperties() {
-        return sPlatformProperties;
-    }
-
-    /**
      * Returns the bitmap for a specific path, from a specific project cache, or from the
      * framework cache.
      * @param value the path of the bitmap
@@ -620,52 +675,66 @@
     }
 
     /**
-     * Returns the 9 patch chunk for a specific path, from a specific project cache, or from the
-     * framework cache.
-     * @param value the path of the 9 patch
-     * @param projectKey the key of the project, or null to query the framework cache.
-     * @return the cached 9 patch or null if not found.
+     * This is called by the native layoutlib loader.
      */
-    public static NinePatchChunk getCached9Patch(String value, Object projectKey) {
-        if (projectKey != null) {
-            Map<String, SoftReference<NinePatchChunk>> map = sProject9PatchCache.get(projectKey);
-
-            if (map != null) {
-                SoftReference<NinePatchChunk> ref = map.get(value);
-                if (ref != null) {
-                    return ref.get();
-                }
-            }
-        } else {
-            SoftReference<NinePatchChunk> ref = sFramework9PatchCache.get(value);
-            if (ref != null) {
-                return ref.get();
-            }
-        }
-
-        return null;
+    @SuppressWarnings("unused")
+    public static String getIcuDataPath() {
+        return sIcuDataPath;
     }
 
-    /**
-     * Sets a 9 patch chunk in a project cache or in the framework cache.
-     * @param value the path of the 9 patch
-     * @param ninePatch the 9 patch object
-     * @param projectKey the key of the project, or null to put the bitmap in the framework cache.
-     */
-    public static void setCached9Patch(String value, NinePatchChunk ninePatch, Object projectKey) {
-        if (projectKey != null) {
-            Map<String, SoftReference<NinePatchChunk>> map =
-                    sProject9PatchCache.computeIfAbsent(projectKey, k -> new HashMap<>());
+    private static boolean sJniLibLoadAttempted;
+    private static boolean sJniLibLoaded;
 
-            map.put(value, new SoftReference<>(ninePatch));
-        } else {
-            sFramework9PatchCache.put(value, new SoftReference<>(ninePatch));
+    private synchronized static boolean loadNativeLibrariesIfNeeded(ILayoutLog log,
+            String nativeLibDir) {
+        if (!sJniLibLoadAttempted) {
+            try {
+                loadNativeLibraries(nativeLibDir);
+            }
+            catch (Throwable t) {
+                log.error(ILayoutLog.TAG_BROKEN, "Native layoutlib failed to load", t, null, null);
+            }
         }
+        return sJniLibLoaded;
+    }
+
+    private synchronized static void loadNativeLibraries(String nativeLibDir) {
+        if (sJniLibLoadAttempted) {
+            // Already attempted to load, nothing to do here.
+            return;
+        }
+        try {
+            // set the system property so LayoutLibLoader.cpp can read it
+            System.setProperty("native_classes", String.join(",",
+                    NativeConfig.CLASS_NATIVES));
+            System.setProperty("icu.dir", Bridge.getIcuDataPath());
+            System.setProperty("use_bridge_for_logging", "true");
+            System.setProperty("register_properties_during_load", "true");
+            for (String library : getNativeLibraries()) {
+                String path = new File(nativeLibDir, library).getAbsolutePath();
+                System.load(path);
+            }
+        }
+        finally {
+            sJniLibLoadAttempted = true;
+        }
+        sJniLibLoaded = true;
+    }
+
+    private static String[] getNativeLibraries() {
+        String osName = System.getProperty("os.name").toLowerCase(Locale.US);
+        if (osName.startsWith("windows")) {
+            return WINDOWS_NATIVE_LIBRARIES;
+        }
+        if (osName.startsWith("mac")) {
+            return MAC_NATIVE_LIBRARIES;
+        }
+        return LINUX_NATIVE_LIBRARIES;
     }
 
     @Override
     public void clearFontCache(String path) {
-        if (sIsTypefaceInitialized) {
+        if (SystemFonts_Delegate.sIsTypefaceInitialized) {
             final String key =
                     Typeface_Builder_Delegate.createAssetUid(BridgeAssetManager.initSystem(), path,
                             0, null, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE, DEFAULT_FAMILY);
diff --git a/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index 5584708..5f035b1 100644
--- a/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -16,16 +16,23 @@
 
 package com.android.layoutlib.bridge;
 
+import com.android.ide.common.rendering.api.ILayoutLog;
+import com.android.ide.common.rendering.api.RenderParams;
 import com.android.ide.common.rendering.api.RenderSession;
 import com.android.ide.common.rendering.api.ResourceReference;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.Result;
 import com.android.ide.common.rendering.api.ViewInfo;
+import com.android.internal.util.ArrayUtils_Delegate;
 import com.android.layoutlib.bridge.impl.RenderSessionImpl;
 import com.android.tools.layoutlib.java.System_Delegate;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.Handler_Delegate;
+import android.view.Choreographer;
+import android.view.DisplayEventReceiver_VsyncEventData_Accessor;
+import android.view.MotionEvent;
 
 import java.awt.image.BufferedImage;
 import java.util.Collections;
@@ -46,6 +53,8 @@
     @NonNull
     private Result mLastResult;
 
+    private static final Runnable NOOP_RUNNABLE = () -> { };
+
     @Override
     public Result getResult() {
         return mLastResult;
@@ -136,10 +145,74 @@
     }
 
     @Override
+    public boolean executeCallbacks(long nanos) {
+        // Currently, Compose relies on Choreographer frame callback and Handler#postAtFrontOfQueue.
+        // Calls to Handler are handled by Handler_Delegate and can be executed by Handler_Delegate#
+        // executeCallbacks. Choreographer frame callback is handled by Choreographer#doFrame.
+        if (mSession == null) {
+            return false;
+        }
+        try {
+            Bridge.prepareThread();
+            mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
+            boolean hasMoreCallbacks = Handler_Delegate.executeCallbacks();
+            // Put a no-op callback to make sure Choreographer.mFrameScheduled is true and
+            // therefore frame callbacks will be executed
+            Choreographer.getInstance().postCallbackDelayedInternal(
+                    Choreographer.CALLBACK_ANIMATION, NOOP_RUNNABLE, null, 0);
+            Choreographer.getInstance().doFrame(nanos, 0,
+                    DisplayEventReceiver_VsyncEventData_Accessor.getVsyncEventDataInstance());
+            return hasMoreCallbacks;
+        } catch (Throwable t) {
+            Bridge.getLog().error(ILayoutLog.TAG_BROKEN, "Failed executing Choreographer#doFrame "
+                    , t, null, null);
+            return false;
+        } finally {
+            mSession.release();
+            Bridge.cleanupThread();
+        }
+    }
+
+    private static int toMotionEventType(TouchEventType eventType) {
+        switch (eventType) {
+            case PRESS:
+                return MotionEvent.ACTION_DOWN;
+            case RELEASE:
+                return MotionEvent.ACTION_UP;
+            case DRAG:
+                return MotionEvent.ACTION_MOVE;
+        }
+        throw new IllegalStateException("Unexpected touch event type: " + eventType);
+    }
+
+    @Override
+    public void triggerTouchEvent(TouchEventType type, int x, int y) {
+        int motionEventType = toMotionEventType(type);
+        if (mSession != null) {
+            try {
+                Bridge.prepareThread();
+                mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
+                mSession.dispatchTouchEvent(motionEventType, System_Delegate.nanoTime(), x, y);
+            } finally {
+                mSession.release();
+                Bridge.cleanupThread();
+            }
+        }
+    }
+
+    @Override
     public void dispose() {
         if (mSession != null) {
-            mSession.dispose();
+            try {
+                Bridge.prepareThread();
+                mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
+                mSession.dispose();
+            } finally {
+                mSession.release();
+                Bridge.cleanupThread();
+            }
         }
+        ArrayUtils_Delegate.clearCache();
     }
 
     /*package*/ BridgeRenderSession(@Nullable RenderSessionImpl scene, @NonNull Result lastResult) {
diff --git a/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java b/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java
index 2dfbd24..abeab83 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/AndroidLocale.java
@@ -23,7 +23,7 @@
 import java.util.Locale;
 
 /**
- * This class provides an alternate implementation for {@code java.util.Locale#adjustLanguageCode}
+ * This class provides an alternate implementation for {@code java.util.Locale#getDefault}
  * which is not available in openJDK. It also overrides the getDefault method.
  *
  * The create tool re-writes references to the above mentioned method to this one. Hence it's
@@ -32,21 +32,6 @@
 @SuppressWarnings("UnusedDeclaration")
 public class AndroidLocale {
 
-    public static String adjustLanguageCode(String languageCode) {
-        String adjusted = languageCode.toLowerCase(Locale.US);
-        // Map new language codes to the obsolete language
-        // codes so the correct resource bundles will be used.
-        if (languageCode.equals("he")) {
-            adjusted = "iw";
-        } else if (languageCode.equals("id")) {
-            adjusted = "in";
-        } else if (languageCode.equals("yi")) {
-            adjusted = "ji";
-        }
-
-        return adjusted;
-    }
-
     public static Locale getDefault() {
         BridgeContext context = RenderAction.getCurrentContext();
         if (context != null) {
diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 73a73d0..9c0ae2e 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -69,7 +69,9 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
+import android.graphics.Typeface_Delegate;
 import android.graphics.drawable.Drawable;
+import android.graphics.fonts.SystemFonts_Delegate;
 import android.hardware.display.DisplayManager;
 import android.net.ConnectivityManager;
 import android.net.Uri;
diff --git a/bridge/src/com/android/layoutlib/bridge/android/graphics/NopCanvas.java b/bridge/src/com/android/layoutlib/bridge/android/graphics/NopCanvas.java
index 131aa17..6e424fa 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/graphics/NopCanvas.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/graphics/NopCanvas.java
@@ -42,7 +42,7 @@
     public boolean isHardwareAccelerated() {
         // We return true the first time so there are no allocations for the software renderer in
         // the constructor
-        return !mIsInitialized;
+        return false;
     }
 
     @Override
@@ -304,4 +304,9 @@
     @Override
     public void drawPicture(Picture picture, Rect dst) {
     }
+
+    @Override
+    public boolean quickReject(float left, float top, float right, float bottom) {
+        return false;
+    }
 }
diff --git a/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java b/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java
index 92693c6..226be24 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java
@@ -18,14 +18,14 @@
 
 import com.android.ide.common.rendering.api.ILayoutLog;
 import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+import com.android.layoutlib.common.util.ReflectionUtils.ReflectionException;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.view.View;
 
-import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
+import static com.android.layoutlib.common.util.ReflectionUtils.getMethod;
+import static com.android.layoutlib.common.util.ReflectionUtils.invoke;
 
 /**
  * Utility class for working with the design support lib.
diff --git a/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java b/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
index 08e7419..3f99c64 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
@@ -18,7 +18,7 @@
 
 import com.android.ide.common.rendering.api.ILayoutLog;
 import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+import com.android.layoutlib.common.util.ReflectionUtils.ReflectionException;
 
 import android.annotation.Nullable;
 import android.view.View;
@@ -27,9 +27,9 @@
 import static android.view.Gravity.LEFT;
 import static android.view.Gravity.RIGHT;
 import static android.view.Gravity.START;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.getCause;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
+import static com.android.layoutlib.common.util.ReflectionUtils.getCause;
+import static com.android.layoutlib.common.util.ReflectionUtils.getMethod;
+import static com.android.layoutlib.common.util.ReflectionUtils.invoke;
 
 public class DrawerLayoutUtil {
 
diff --git a/bridge/src/com/android/layoutlib/bridge/android/support/FragmentTabHostUtil.java b/bridge/src/com/android/layoutlib/bridge/android/support/FragmentTabHostUtil.java
index a426b27..1224e57 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/support/FragmentTabHostUtil.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/support/FragmentTabHostUtil.java
@@ -18,14 +18,14 @@
 
 import com.android.ide.common.rendering.api.ILayoutLog;
 import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+import com.android.layoutlib.common.util.ReflectionUtils.ReflectionException;
 
 import android.content.Context;
 import android.widget.TabHost;
 
-import static com.android.layoutlib.bridge.util.ReflectionUtils.getCause;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
+import static com.android.layoutlib.common.util.ReflectionUtils.getCause;
+import static com.android.layoutlib.common.util.ReflectionUtils.getMethod;
+import static com.android.layoutlib.common.util.ReflectionUtils.invoke;
 
 /**
  * Utility class for working with android.support.v4.app.FragmentTabHost
diff --git a/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java b/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
index ff20fbf..1b4d2a8 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
@@ -21,17 +21,17 @@
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.RenderParamsFlags;
-import com.android.layoutlib.bridge.util.ReflectionUtils;
-import com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+import com.android.layoutlib.common.util.ReflectionUtils;
+import com.android.layoutlib.common.util.ReflectionUtils.ReflectionException;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.view.View;
 
-import static com.android.layoutlib.bridge.util.ReflectionUtils.getCause;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
+import static com.android.layoutlib.common.util.ReflectionUtils.getCause;
+import static com.android.layoutlib.common.util.ReflectionUtils.getMethod;
+import static com.android.layoutlib.common.util.ReflectionUtils.invoke;
 
 /**
  * Utility class for working with android.support.v7.widget.RecyclerView and
diff --git a/bridge/src/com/android/layoutlib/bridge/android/support/SupportPreferencesUtil.java b/bridge/src/com/android/layoutlib/bridge/android/support/SupportPreferencesUtil.java
index f195a5e..870a0f9 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/support/SupportPreferencesUtil.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/support/SupportPreferencesUtil.java
@@ -18,13 +18,11 @@
 
 import com.android.ide.common.rendering.api.LayoutlibCallback;
 import com.android.ide.common.rendering.api.RenderResources;
-import com.android.ide.common.rendering.api.ResourceNamespace;
-import com.android.ide.common.rendering.api.ResourceReference;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.StyleResourceValue;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
-import com.android.layoutlib.bridge.util.ReflectionUtils.ReflectionException;
+import com.android.layoutlib.common.util.ReflectionUtils.ReflectionException;
 import com.android.resources.ResourceType;
 import com.android.tools.layoutlib.annotations.NotNull;
 
@@ -45,10 +43,10 @@
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 
-import static com.android.layoutlib.bridge.util.ReflectionUtils.getAccessibleMethod;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.getClassInstance;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.getMethod;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.invoke;
+import static com.android.layoutlib.common.util.ReflectionUtils.getAccessibleMethod;
+import static com.android.layoutlib.common.util.ReflectionUtils.getClassInstance;
+import static com.android.layoutlib.common.util.ReflectionUtils.getMethod;
+import static com.android.layoutlib.common.util.ReflectionUtils.invoke;
 
 /**
  * Class with utility methods to instantiate Preferences provided by the support library.
diff --git a/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 0bb72ed..63efec3 100644
--- a/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -33,7 +33,8 @@
 import android.annotation.NonNull;
 import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap_Delegate;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapFactory.Options;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.TypedValue;
@@ -44,7 +45,6 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import java.io.IOException;
 import java.io.InputStream;
 
 import static android.os._Original_Build.VERSION_CODES.LOLLIPOP;
@@ -116,12 +116,10 @@
             // look for a cached bitmap
             Bitmap bitmap = Bridge.getCachedBitmap(path, Boolean.TRUE /*isFramework*/);
             if (bitmap == null) {
-                try {
-                    bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density);
-                    Bridge.setCachedBitmap(path, bitmap, Boolean.TRUE /*isFramework*/);
-                } catch (IOException e) {
-                    return imageView;
-                }
+                Options options = new Options();
+                options.inDensity = density.getDpiValue();
+                bitmap = BitmapFactory.decodeStream(stream, null, options);
+                Bridge.setCachedBitmap(path, bitmap, Boolean.TRUE /*isFramework*/);
             }
 
             if (bitmap != null) {
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
index 5991eb0..69325bd 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
@@ -16,7 +16,6 @@
 
 package com.android.layoutlib.bridge.impl;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.layoutlib.bridge.util.Debug;
 import com.android.layoutlib.bridge.util.SparseWeakArray;
 
@@ -26,12 +25,9 @@
 import java.io.PrintStream;
 import java.lang.ref.WeakReference;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.Set;
-import java.util.WeakHashMap;
 import java.util.concurrent.atomic.AtomicLong;
 
-import libcore.util.NativeAllocationRegistry_Delegate;
 
 /**
  * Manages native delegates.
@@ -86,30 +82,6 @@
      */
     private static final Set<Object> sJavaReferences = new HashSet<>();
     private static final AtomicLong sDelegateCounter = new AtomicLong(1);
-    /**
-     * Tracks "native" allocations. This means that we know of the object in the Java side and we
-     * can attach the delegate lifecycle to the lifecycle of the Java object. If the Java object
-     * is disposed, it means we can get rid of the delegate allocation.
-     * Ideally, we would use a {@link WeakHashMap} but we do not control the equals() method of the
-     * referents so we can not safely rely on them.
-     */
-    private static final LinkedList<NativeAllocationHolder> sNativeAllocations = new LinkedList<>();
-    /**
-     * Map that allows to do a quick lookup of delegates that have been marked as native
-     * allocations.
-     * This allows us to quickly check if, when a manual dispose happens, there is work we have
-     * to do.
-     */
-    @GuardedBy("sNativeAllocations")
-    private static final WeakHashMap<Object, WeakReference<NativeAllocationHolder>>
-            sNativeAllocationsReferences = new WeakHashMap<>();
-    /**
-     * Counter of the number of native allocations. We use this counter to trigger the collection
-     * of unlinked references in the sNativeAllocations list. We do not need to do this process
-     * on every allocation so only run it every 50 allocations.
-     */
-    @GuardedBy("sNativeAllocations")
-    private static long sNativeAllocationsCount = 0;
 
     private final Class<T> mClass;
 
@@ -193,80 +165,7 @@
                         " with int " + native_object);
             }
 
-            if (!sJavaReferences.remove(delegate)) {
-                // We didn't have any strong references to the delegate so it might be tracked by
-                // the native allocations tracker. If so, we want to remove that reference to
-                // make it available to collect ASAP.
-                synchronized (sNativeAllocations) {
-                    WeakReference<NativeAllocationHolder> holderRef = sNativeAllocationsReferences.get(delegate);
-                    NativeAllocationHolder holder = holderRef.get();
-                    if (holder != null) {
-                        // We only null the referred delegate. We do not spend the time in finding
-                        // the holder in the list and removing it since the "garbage collection" in
-                        // markAsNativeAllocation will do it for us.
-                        holder.mReferred = null;
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * This method marks the given native_object as a native allocation of the passed referent.
-     * This means that the lifecycle of the native_object can now be attached to the referent and
-     * if the referent is disposed, we can safely dispose the delegate.
-     * This method is called by the {@link NativeAllocationRegistry_Delegate} and allows the
-     * DelegateManager to remove the strong reference to the delegate.
-     */
-    public void markAsNativeAllocation(Object referent, long native_object) {
-        NativeAllocationHolder holder;
-        synchronized (DelegateManager.class) {
-            T delegate = getDelegate(native_object);
-            if (Debug.DEBUG) {
-                if (delegate == null) {
-                    System.err.println("Unknown " + mClass.getSimpleName() + " with int " +
-                            native_object);
-                }
-                else {
-                    System.err.println("Marking element as native " + native_object);
-                }
-            }
-
-            assert delegate != null;
-            if (sJavaReferences.remove(delegate)) {
-                // We had a strong reference, move to the native allocation tracker.
-                holder = new NativeAllocationHolder(referent, delegate);
-            }
-            else {
-                holder = null;
-            }
-        }
-
-        if (holder != null) {
-            synchronized (sNativeAllocations) {
-                sNativeAllocations.add(holder);
-                // The value references the key in this case but we use a WeakReference value.
-                sNativeAllocationsReferences.put(holder.mReferred, new WeakReference<>(holder));
-
-                if (++sNativeAllocationsCount % 50 == 0) {
-                    // Do garbage collection
-                    boolean collected = sNativeAllocations.removeIf(e -> e.mReferent.get() == null);
-                    if (Debug.DEBUG && collected) {
-                        System.err.println("Elements collected");
-                    }
-                }
-            }
-        }
-    }
-
-    private static class NativeAllocationHolder {
-        private final WeakReference<Object> mReferent;
-        // The referred object is not null so we can null them on demand
-        private Object mReferred;
-
-        private NativeAllocationHolder(Object referent, Object referred) {
-            mReferent = new WeakReference<>(referent);
-            mReferred = referred;
+            sJavaReferences.remove(delegate);
         }
     }
 }
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
deleted file mode 100644
index f3ebd40..0000000
--- a/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
+++ /dev/null
@@ -1,925 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package com.android.layoutlib.bridge.impl;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-
-import android.graphics.Bitmap_Delegate;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter_Delegate;
-import android.graphics.Paint;
-import android.graphics.Paint_Delegate;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Region;
-import android.graphics.Region_Delegate;
-import android.graphics.Shader_Delegate;
-
-import java.awt.AlphaComposite;
-import java.awt.Color;
-import java.awt.Composite;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Area;
-import java.awt.geom.NoninvertibleTransformException;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.util.ArrayList;
-
-import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
-import static java.awt.image.BufferedImage.TYPE_INT_RGB;
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
-/**
- * Class representing a graphics context snapshot, as well as a context stack as a linked list.
- * <p>
- * This is based on top of {@link Graphics2D} but can operate independently if none are available
- * yet when setting transforms and clip information.
- * <p>
- * This allows for drawing through {@link #draw(Drawable, Paint_Delegate, boolean, boolean)} and
- * {@link #draw(Drawable)}
- *
- * Handling of layers (created with {@link Canvas#saveLayer(RectF, Paint, int)}) is handled through
- * a list of Graphics2D for each layers. The class actually maintains a list of {@link Layer}
- * for each layer. Doing a save() will duplicate this list so that each graphics2D object
- * ({@link Layer#getGraphics()}) is configured only for the new snapshot.
- */
-public class GcSnapshot {
-    private static final AffineTransform IDENTITY_TRANSFORM = new AffineTransform();
-
-    private final GcSnapshot mPrevious;
-    private final int mFlags;
-
-    /** list of layers. The first item in the list is always the  */
-    private final ArrayList<Layer> mLayers = new ArrayList<Layer>();
-
-    /** temp transform in case transformation are set before a Graphics2D exists */
-    private AffineTransform mTransform = null;
-    /** temp clip in case clipping is set before a Graphics2D exists */
-    private Area mClip = null;
-
-    // local layer data
-    /** a local layer created with {@link Canvas#saveLayer(RectF, Paint, int)}.
-     * If this is null, this does not mean there's no layer, just that the snapshot is not the
-     * one that created the layer.
-     */
-    private final Layer mLocalLayer;
-    private final Paint_Delegate mLocalLayerPaint;
-    private final Rect mLayerBounds;
-
-    public interface Drawable {
-        void draw(Graphics2D graphics, Paint_Delegate paint);
-    }
-
-    /**
-     * Class containing information about a layer.
-     *
-     * This contains graphics, bitmap and layer information.
-     */
-    private static class Layer {
-        private final Graphics2D mGraphics;
-        private final Bitmap_Delegate mBitmap;
-        private final BufferedImage mImage;
-        /** the flags that were used to configure the layer. This is never changed, and passed
-         * as is when {@link #makeCopy()} is called */
-        private final int mFlags;
-        /** the original content of the layer when the next object was created. This is not
-         * passed in {@link #makeCopy()} and instead is recreated when a new layer is added
-         * (depending on its flags) */
-        private BufferedImage mOriginalCopy;
-
-        /**
-         * Creates a layer with a graphics and a bitmap. This is only used to create
-         * the base layer.
-         *
-         * @param graphics the graphics
-         * @param bitmap the bitmap
-         */
-        Layer(Graphics2D graphics, Bitmap_Delegate bitmap) {
-            mGraphics = graphics;
-            mBitmap = bitmap;
-            mImage = mBitmap.getImage();
-            mFlags = 0;
-        }
-
-        /**
-         * Creates a layer with a graphics and an image. If the image belongs to a
-         * {@link Bitmap_Delegate} (case of the base layer), then
-         * {@link Layer#Layer(Graphics2D, Bitmap_Delegate)} should be used.
-         *
-         * @param graphics the graphics the new graphics for this layer
-         * @param image the image the image from which the graphics came
-         * @param flags the flags that were used to save this layer
-         */
-        Layer(Graphics2D graphics, BufferedImage image, int flags) {
-            mGraphics = graphics;
-            mBitmap = null;
-            mImage = image;
-            mFlags = flags;
-        }
-
-        /** The Graphics2D, guaranteed to be non null */
-        Graphics2D getGraphics() {
-            return mGraphics;
-        }
-
-        /** The BufferedImage, guaranteed to be non null */
-        BufferedImage getImage() {
-            return mImage;
-        }
-
-        /** Returns the layer save flags. This is only valid for additional layers.
-         * For the base layer this will always return 0;
-         * For a given layer, all further copies of this {@link Layer} object in new snapshots
-         * will always return the same value.
-         */
-        int getFlags() {
-            return mFlags;
-        }
-
-        Layer makeCopy() {
-            if (mBitmap != null) {
-                return new Layer((Graphics2D) mGraphics.create(), mBitmap);
-            }
-
-            return new Layer((Graphics2D) mGraphics.create(), mImage, mFlags);
-        }
-
-        /** sets an optional copy of the original content to be used during restore */
-        void setOriginalCopy(BufferedImage image) {
-            mOriginalCopy = image;
-        }
-
-        BufferedImage getOriginalCopy() {
-            return mOriginalCopy;
-        }
-
-        void change() {
-            if (mBitmap != null) {
-                mBitmap.change();
-            }
-        }
-
-        /**
-         * Sets the clip for the graphics2D object associated with the layer.
-         * This should be used over the normal Graphics2D setClip method.
-         *
-         * @param clipShape the shape to use a the clip shape.
-         */
-        void setClip(Shape clipShape) {
-            // because setClip is only guaranteed to work with rectangle shape,
-            // first reset the clip to max and then intersect the current (empty)
-            // clip with the shap.
-            mGraphics.setClip(null);
-            mGraphics.clip(clipShape);
-        }
-
-        /**
-         * Clips the layer with the given shape. This performs an intersect between the current
-         * clip shape and the given shape.
-         * @param shape the new clip shape.
-         */
-        public void clip(Shape shape) {
-            mGraphics.clip(shape);
-        }
-    }
-
-    /**
-     * Creates the root snapshot associating it with a given bitmap.
-     * <p>
-     * If <var>bitmap</var> is null, then {@link GcSnapshot#setBitmap(Bitmap_Delegate)} must be
-     * called before the snapshot can be used to draw. Transform and clip operations are permitted
-     * before.
-     *
-     * @param bitmap the image to associate to the snapshot or null.
-     * @return the root snapshot
-     */
-    public static GcSnapshot createDefaultSnapshot(Bitmap_Delegate bitmap) {
-        GcSnapshot snapshot = new GcSnapshot();
-        if (bitmap != null) {
-            snapshot.setBitmap(bitmap);
-        }
-
-        return snapshot;
-    }
-
-    /**
-     * Saves the current state according to the given flags and returns the new current snapshot.
-     * <p/>
-     * This is the equivalent of {@link Canvas#save(int)}
-     *
-     * @param flags the save flags.
-     * @return the new snapshot
-     *
-     * @see Canvas#save(int)
-     */
-    public GcSnapshot save(int flags) {
-        return new GcSnapshot(this, null /*layerbounds*/, null /*paint*/, flags);
-    }
-
-    /**
-     * Saves the current state and creates a new layer, and returns the new current snapshot.
-     * <p/>
-     * This is the equivalent of {@link Canvas#saveLayer(RectF, Paint, int)}
-     *
-     * @param layerBounds the layer bounds
-     * @param paint the Paint information used to blit the layer back into the layers underneath
-     *          upon restore
-     * @param flags the save flags.
-     * @return the new snapshot
-     *
-     * @see Canvas#saveLayer(RectF, Paint, int)
-     */
-    public GcSnapshot saveLayer(RectF layerBounds, Paint_Delegate paint, int flags) {
-        return new GcSnapshot(this, layerBounds, paint, flags);
-    }
-
-    /**
-     * Creates the root snapshot.
-     */
-    private GcSnapshot() {
-        mPrevious = null;
-        mFlags = 0;
-        mLocalLayer = null;
-        mLocalLayerPaint = null;
-        mLayerBounds = null;
-    }
-
-    /**
-     * Creates a new {@link GcSnapshot} on top of another one, with a layer data to be restored
-     * into the main graphics when {@link #restore()} is called.
-     *
-     * @param previous the previous snapshot head.
-     * @param layerBounds the region of the layer. Optional, if null, this is a normal save()
-     * @param paint the Paint information used to blit the layer back into the layers underneath
-     *          upon restore
-     * @param flags the flags regarding what should be saved.
-     */
-    private GcSnapshot(GcSnapshot previous, RectF layerBounds, Paint_Delegate paint, int flags) {
-        assert previous != null;
-        mPrevious = previous;
-        mFlags = flags;
-
-        // make a copy of the current layers before adding the new one.
-        // This keeps the same BufferedImage reference but creates new Graphics2D for this
-        // snapshot.
-        // It does not copy whatever original copy the layers have, as they will be done
-        // only if the new layer doesn't clip drawing to itself.
-        for (Layer layer : mPrevious.mLayers) {
-            mLayers.add(layer.makeCopy());
-        }
-
-        if (layerBounds != null) {
-            // get the current transform
-            AffineTransform matrix = mLayers.get(0).getGraphics().getTransform();
-
-            // transform the layerBounds with the current transform and stores it into a int rect
-            RectF rect2 = new RectF();
-            mapRect(matrix, rect2, layerBounds);
-            mLayerBounds = new Rect();
-            rect2.round(mLayerBounds);
-
-            // get the base layer (always at index 0)
-            Layer baseLayer = mLayers.get(0);
-
-            // create the image for the layer
-            BufferedImage layerImage = new BufferedImage(
-                    baseLayer.getImage().getWidth(),
-                    baseLayer.getImage().getHeight(),
-                    (mFlags & Canvas.HAS_ALPHA_LAYER_SAVE_FLAG) != 0 ?
-                            TYPE_INT_ARGB :
-                                TYPE_INT_RGB);
-
-            // create a graphics for it so that drawing can be done.
-            Graphics2D layerGraphics = layerImage.createGraphics();
-
-            // because this layer inherits the current context for transform and clip,
-            // set them to one from the base layer.
-            AffineTransform currentMtx = baseLayer.getGraphics().getTransform();
-            layerGraphics.setTransform(currentMtx);
-
-            // create a new layer for this new layer and add it to the list at the end.
-            mLayers.add(mLocalLayer = new Layer(layerGraphics, layerImage, flags));
-
-            // set the clip on it.
-            Shape currentClip = baseLayer.getGraphics().getClip();
-            mLocalLayer.setClip(currentClip);
-
-            // if the drawing is not clipped to the local layer only, we save the current content
-            // of all other layers. We are only interested in the part that will actually
-            // be drawn, so we create as small bitmaps as we can.
-            // This is so that we can erase the drawing that goes in the layers below that will
-            // be coming from the layer itself.
-            if ((mFlags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0) {
-                int w = mLayerBounds.width();
-                int h = mLayerBounds.height();
-                for (int i = 0 ; i < mLayers.size() - 1 ; i++) {
-                    Layer layer = mLayers.get(i);
-                    BufferedImage image = new BufferedImage(w, h, TYPE_INT_ARGB);
-                    Graphics2D graphics = image.createGraphics();
-                    graphics.drawImage(layer.getImage(),
-                            0, 0, w, h,
-                            mLayerBounds.left, mLayerBounds.top,
-                                    mLayerBounds.right, mLayerBounds.bottom,
-                            null);
-                    graphics.dispose();
-                    layer.setOriginalCopy(image);
-                }
-            }
-        } else {
-            mLocalLayer = null;
-            mLayerBounds = null;
-        }
-
-        mLocalLayerPaint  = paint;
-    }
-
-    public void dispose() {
-        for (Layer layer : mLayers) {
-            layer.getGraphics().dispose();
-        }
-
-        if (mPrevious != null) {
-            mPrevious.dispose();
-        }
-    }
-
-    /**
-     * Restores the top {@link GcSnapshot}, and returns the next one.
-     */
-    public GcSnapshot restore() {
-        return doRestore();
-    }
-
-    /**
-     * Restores the {@link GcSnapshot} to <var>saveCount</var>.
-     * @param saveCount the saveCount or -1 to only restore 1.
-     *
-     * @return the new head of the Gc snapshot stack.
-     */
-    public GcSnapshot restoreTo(int saveCount) {
-        return doRestoreTo(size(), saveCount);
-    }
-
-    public int size() {
-        if (mPrevious != null) {
-            return mPrevious.size() + 1;
-        }
-
-        return 1;
-    }
-
-    /**
-     * Link the snapshot to a Bitmap_Delegate.
-     * <p/>
-     * This is only for the case where the snapshot was created with a null image when calling
-     * {@link #createDefaultSnapshot(Bitmap_Delegate)}, and is therefore not yet linked to
-     * a previous snapshot.
-     * <p/>
-     * If any transform or clip information was set before, they are put into the Graphics object.
-     * @param bitmap the bitmap to link to.
-     */
-    public void setBitmap(Bitmap_Delegate bitmap) {
-        // create a new Layer for the bitmap. This will be the base layer.
-        Graphics2D graphics2D = bitmap.getImage().createGraphics();
-        Layer baseLayer = new Layer(graphics2D, bitmap);
-
-        // Set the current transform and clip which can either come from mTransform/mClip if they
-        // were set when there was no bitmap/layers or from the current base layers if there is
-        // one already.
-
-        graphics2D.setTransform(getTransform());
-        // reset mTransform in case there was one.
-        mTransform = null;
-
-        baseLayer.setClip(getClip());
-        // reset mClip in case there was one.
-        mClip = null;
-
-        // replace whatever current layers we have with this.
-        mLayers.clear();
-        mLayers.add(baseLayer);
-
-    }
-
-    public void translate(float dx, float dy) {
-        if (mLayers.size() > 0) {
-            for (Layer layer : mLayers) {
-                layer.getGraphics().translate(dx, dy);
-            }
-        } else {
-            if (mTransform == null) {
-                mTransform = new AffineTransform();
-            }
-            mTransform.translate(dx, dy);
-        }
-    }
-
-    public void rotate(double radians) {
-        if (mLayers.size() > 0) {
-            for (Layer layer : mLayers) {
-                layer.getGraphics().rotate(radians);
-            }
-        } else {
-            if (mTransform == null) {
-                mTransform = new AffineTransform();
-            }
-            mTransform.rotate(radians);
-        }
-    }
-
-    public void scale(float sx, float sy) {
-        if (mLayers.size() > 0) {
-            for (Layer layer : mLayers) {
-                layer.getGraphics().scale(sx, sy);
-            }
-        } else {
-            if (mTransform == null) {
-                mTransform = new AffineTransform();
-            }
-            mTransform.scale(sx, sy);
-        }
-    }
-
-    public AffineTransform getTransform() {
-        if (mLayers.size() > 0) {
-            // all graphics2D in the list have the same transform
-            return mLayers.get(0).getGraphics().getTransform();
-        } else {
-            if (mTransform == null) {
-                mTransform = new AffineTransform();
-            }
-            return mTransform;
-        }
-    }
-
-    public void setTransform(AffineTransform transform) {
-        if (mLayers.size() > 0) {
-            for (Layer layer : mLayers) {
-                layer.getGraphics().setTransform(transform);
-            }
-        } else {
-            if (mTransform == null) {
-                mTransform = new AffineTransform();
-            }
-            mTransform.setTransform(transform);
-        }
-    }
-
-    public boolean clip(Shape shape, int regionOp) {
-        // Simple case of intersect with existing layers.
-        // Because Graphics2D#setClip works a bit peculiarly, we optimize
-        // the case of clipping by intersection, as it's supported natively.
-        if (regionOp == Region.Op.INTERSECT.nativeInt && mLayers.size() > 0) {
-            for (Layer layer : mLayers) {
-                layer.clip(shape);
-            }
-
-            Shape currentClip = getClip();
-            return currentClip != null && currentClip.getBounds().isEmpty() == false;
-        }
-
-        Area area = null;
-
-        if (regionOp == Region.Op.REPLACE.nativeInt) {
-            area = new Area(shape);
-        } else {
-            area = Region_Delegate.combineShapes(getClip(), shape, regionOp);
-        }
-
-        if (mLayers.size() > 0) {
-            if (area != null) {
-                for (Layer layer : mLayers) {
-                    layer.setClip(area);
-                }
-            }
-
-            Shape currentClip = getClip();
-            return currentClip != null && currentClip.getBounds().isEmpty() == false;
-        } else {
-            if (area != null) {
-                mClip = area;
-            } else {
-                mClip = new Area();
-            }
-
-            return mClip.getBounds().isEmpty() == false;
-        }
-    }
-
-    public boolean clipRect(float left, float top, float right, float bottom, int regionOp) {
-        return clip(new Rectangle2D.Float(left, top, right - left, bottom - top), regionOp);
-    }
-
-    /**
-     * Returns the current clip, or null if none have been setup.
-     */
-    public Shape getClip() {
-        if (mLayers.size() > 0) {
-            // they all have the same clip
-            return mLayers.get(0).getGraphics().getClip();
-        } else {
-            return mClip;
-        }
-    }
-
-    private GcSnapshot doRestoreTo(int size, int saveCount) {
-        if (size <= saveCount) {
-            return this;
-        }
-
-        // restore the current one first.
-        GcSnapshot previous = doRestore();
-
-        if (size == saveCount + 1) { // this was the only one that needed restore.
-            return previous;
-        } else {
-            return previous.doRestoreTo(size - 1, saveCount);
-        }
-    }
-
-    /**
-     * Executes the Drawable's draw method, with a null paint delegate.
-     * <p/>
-     * Note that the method can be called several times if there are more than one active layer.
-     */
-    public void draw(Drawable drawable) {
-        draw(drawable, null, false /*compositeOnly*/, false /*forceSrcMode*/);
-    }
-
-    /**
-     * Executes the Drawable's draw method.
-     * <p/>
-     * Note that the method can be called several times if there are more than one active layer.
-     * @param compositeOnly whether the paint is used for composite only. This is typically
-     *          the case for bitmaps.
-     * @param forceSrcMode if true, this overrides the composite to be SRC
-     */
-    public void draw(Drawable drawable, Paint_Delegate paint, boolean compositeOnly,
-            boolean forceSrcMode) {
-        int forceMode = forceSrcMode ? AlphaComposite.SRC : 0;
-        // the current snapshot may not have a mLocalLayer (ie it was created on save() instead
-        // of saveLayer(), but that doesn't mean there's no layer.
-        // mLayers however saves all the information we need (flags).
-        if (mLayers.size() == 1) {
-            // no layer, only base layer. easy case.
-            drawInLayer(mLayers.get(0), drawable, paint, compositeOnly, forceMode);
-        } else {
-            // draw in all the layers until the layer save flags tells us to stop (ie drawing
-            // in that layer is limited to the layer itself.
-            int flags;
-            int i = mLayers.size() - 1;
-
-            do {
-                Layer layer = mLayers.get(i);
-
-                drawInLayer(layer, drawable, paint, compositeOnly, forceMode);
-
-                // then go to previous layer, only if there are any left, and its flags
-                // doesn't restrict drawing to the layer itself.
-                i--;
-                flags = layer.getFlags();
-            } while (i >= 0 && (flags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0);
-        }
-    }
-
-    /**
-     * This function calculates a minimum (in area) integer rectangle that contains the input
-     * rectangle after applying to it the affine transform
-     *
-     * @param rect input rectangle
-     * @param transform affine transform applied to the input rectangle
-     *
-     * Returns an output rectangle
-     */
-    private static Rectangle transformRect(Rectangle rect, AffineTransform transform) {
-        double[] coords = new double[16];
-        coords[0] = rect.x;
-        coords[1] = rect.y;
-        coords[2] = rect.x + rect.width;
-        coords[3] = rect.y + rect.height;
-        coords[4] = rect.x;
-        coords[5] = rect.y + rect.height;
-        coords[6] = rect.x + rect.width;
-        coords[7] = rect.y;
-        transform.transform(coords, 0, coords, 8, 4);
-        // From 4 transformed vertices of the input rectangle we search for the minimum and maximum
-        // for both coordinates. We round the found extrema to the closest integer, smaller of equal
-        // for the minimums and larger or equal for the maximums. These values represent the border
-        // or the minimum rectangle with sides parallel to the coordinate axis that contains
-        // the transformed rectangle
-        int x = (int) Math.floor(min(min(coords[8], coords[10]), min(coords[12], coords[14])));
-        int y = (int) Math.floor(min(min(coords[9], coords[11]), min(coords[13], coords[15])));
-        int w = (int) Math.ceil(max(max(coords[8], coords[10]), max(coords[12], coords[14]))) - x;
-        int h = (int) Math.ceil(max(max(coords[9], coords[11]), max(coords[13], coords[15]))) - y;
-        return new Rectangle(x, y, w, h);
-    }
-
-    private void drawInLayer(Layer layer, Drawable drawable, Paint_Delegate paint,
-            boolean compositeOnly, int forceMode) {
-        Graphics2D originalGraphics = layer.getGraphics();
-        if (paint == null) {
-            drawOnGraphics((Graphics2D) originalGraphics.create(), drawable,
-                    null /*paint*/, layer);
-        } else {
-            ColorFilter_Delegate filter = paint.getColorFilter();
-            if (filter == null || !filter.isSupported()) {
-                // get a Graphics2D object configured with the drawing parameters.
-                Graphics2D configuredGraphics = createCustomGraphics(originalGraphics, paint,
-                        compositeOnly, forceMode);
-                drawOnGraphics(configuredGraphics, drawable, paint, layer);
-                return;
-            }
-
-            Rectangle clipBounds = originalGraphics.getClip() != null ? originalGraphics
-                    .getClipBounds() : null;
-            AffineTransform transform = originalGraphics.getTransform();
-            Rectangle imgRect;
-            if (clipBounds != null) {
-                if (clipBounds.width == 0 || clipBounds.height == 0) {
-                    // Clip is 0 so no need to paint anything.
-                    return;
-                }
-                // Calculate integer rectangle that contains clipBounds after the transform, that is
-                // the minimum image size we can use to render the drawable
-                imgRect = transformRect(clipBounds, transform);
-                transform = new AffineTransform(
-                        transform.getScaleX(),
-                        transform.getShearY(),
-                        transform.getShearX(),
-                        transform.getScaleY(),
-                        transform.getTranslateX() - imgRect.x,
-                        transform.getTranslateY() - imgRect.y);
-            } else {
-                imgRect =
-                        new Rectangle(
-                                0, 0, layer.getImage().getWidth(), layer.getImage().getHeight());
-            }
-
-            // Create a temporary image to which the color filter will be applied.
-            BufferedImage image = new BufferedImage(imgRect.width, imgRect.height, TYPE_INT_ARGB);
-            Graphics2D imageBaseGraphics = (Graphics2D) image.getGraphics();
-            // Configure the Graphics2D object with drawing parameters and shader.
-            Graphics2D imageGraphics = createCustomGraphics(
-                    imageBaseGraphics, paint, compositeOnly,
-                    AlphaComposite.SRC_OVER);
-
-            // get a Graphics2D object configured with the drawing parameters, but no shader.
-            Graphics2D configuredGraphics = createCustomGraphics(originalGraphics, paint,
-                    true /*compositeOnly*/, forceMode);
-            configuredGraphics.setTransform(IDENTITY_TRANSFORM);
-            try {
-                // The main draw operation.
-                // We translate the operation to take into account that the rendering does not
-                // know about the clipping area.
-                imageGraphics.setTransform(transform);
-                drawable.draw(imageGraphics, paint);
-
-                // Apply the color filter.
-                // Restore the original coordinates system and apply the filter only to the
-                // clipped area.
-                imageGraphics.setTransform(IDENTITY_TRANSFORM);
-                filter.applyFilter(imageGraphics, imgRect.width, imgRect.height);
-
-                // Draw the tinted image on the main layer using as start point the clipping
-                // upper left coordinates.
-                configuredGraphics.drawImage(image, imgRect.x, imgRect.y, null);
-                layer.change();
-            } finally {
-                // dispose Graphics2D objects
-                imageGraphics.dispose();
-                imageBaseGraphics.dispose();
-                configuredGraphics.dispose();
-            }
-        }
-    }
-
-    private void drawOnGraphics(Graphics2D g, Drawable drawable, Paint_Delegate paint,
-            Layer layer) {
-        try {
-            drawable.draw(g, paint);
-            layer.change();
-        } finally {
-            g.dispose();
-        }
-    }
-
-    private GcSnapshot doRestore() {
-        if (mPrevious != null) {
-            if (mLocalLayer != null) {
-                // prepare to blit the layers in which we have draw, in the layer beneath
-                // them, starting with the top one (which is the current local layer).
-                int i = mLayers.size() - 1;
-                int flags;
-                do {
-                    Layer dstLayer = mLayers.get(i - 1);
-
-                    restoreLayer(dstLayer);
-
-                    flags = dstLayer.getFlags();
-                    i--;
-                } while (i > 0 && (flags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0);
-            }
-
-            // if this snapshot does not save everything, then set the previous snapshot
-            // to this snapshot content
-
-            // didn't save the matrix? set the current matrix on the previous snapshot
-            if ((mFlags & Canvas.MATRIX_SAVE_FLAG) == 0) {
-                AffineTransform mtx = getTransform();
-                for (Layer layer : mPrevious.mLayers) {
-                    layer.getGraphics().setTransform(mtx);
-                }
-            }
-
-            // didn't save the clip? set the current clip on the previous snapshot
-            if ((mFlags & Canvas.CLIP_SAVE_FLAG) == 0) {
-                Shape clip = getClip();
-                for (Layer layer : mPrevious.mLayers) {
-                    layer.setClip(clip);
-                }
-            }
-        }
-
-        for (Layer layer : mLayers) {
-            layer.getGraphics().dispose();
-        }
-
-        return mPrevious;
-    }
-
-    private void restoreLayer(Layer dstLayer) {
-
-        Graphics2D baseGfx = dstLayer.getImage().createGraphics();
-
-        // if the layer contains an original copy this means the flags
-        // didn't restrict drawing to the local layer and we need to make sure the
-        // layer bounds in the layer beneath didn't receive any drawing.
-        // so we use the originalCopy to erase the new drawings in there.
-        BufferedImage originalCopy = dstLayer.getOriginalCopy();
-        if (originalCopy != null) {
-            Graphics2D g = (Graphics2D) baseGfx.create();
-            g.setComposite(AlphaComposite.Src);
-
-            g.drawImage(originalCopy,
-                    mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom,
-                    0, 0, mLayerBounds.width(), mLayerBounds.height(),
-                    null);
-            g.dispose();
-        }
-
-        // now draw put the content of the local layer onto the layer,
-        // using the paint information
-        Graphics2D g = createCustomGraphics(baseGfx, mLocalLayerPaint,
-                true /*alphaOnly*/, 0 /*forceMode*/);
-
-        g.drawImage(mLocalLayer.getImage(),
-                mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom,
-                mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom,
-                null);
-        g.dispose();
-
-        baseGfx.dispose();
-    }
-
-    /**
-     * Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
-     * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
-     */
-    private Graphics2D createCustomGraphics(Graphics2D original, Paint_Delegate paint,
-            boolean compositeOnly, int forceMode) {
-        // make new one graphics
-        Graphics2D g = (Graphics2D) original.create();
-
-        if (paint == null) {
-            return g;
-        }
-
-        // configure it
-
-        if (paint.isAntiAliased()) {
-            g.setRenderingHint(
-                    RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-            g.setRenderingHint(
-                    RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
-        }
-
-        // set the shader first, as it'll replace the color if it can be used it.
-        if (!compositeOnly) {
-            setShader(g, paint);
-            // set the stroke
-            g.setStroke(paint.getJavaStroke());
-        }
-        // set the composite.
-        setComposite(g, paint, compositeOnly, forceMode);
-
-        return g;
-    }
-
-    private void setShader(Graphics2D g, Paint_Delegate paint) {
-        Shader_Delegate shaderDelegate = paint.getShader();
-        if (shaderDelegate != null) {
-            if (shaderDelegate.isSupported()) {
-                java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint();
-                assert shaderPaint != null;
-                g.setPaint(shaderPaint);
-                return;
-            } else {
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_SHADER,
-                        shaderDelegate.getSupportMessage(), null, null, null);
-            }
-        }
-
-        // if no shader, use the paint color
-        g.setColor(new Color(paint.getColor(), true /*hasAlpha*/));
-    }
-
-    private void setComposite(Graphics2D g, Paint_Delegate paint, boolean usePaintAlpha,
-            int forceMode) {
-        // the alpha for the composite. Always opaque if the normal paint color is used since
-        // it contains the alpha
-        int alpha = usePaintAlpha ? paint.getAlpha() : 0xFF;
-        Shader_Delegate shader = paint.getShader();
-        if (shader != null) {
-            alpha = (int)(alpha * shader.getAlpha());
-        }
-        if (forceMode != 0) {
-            g.setComposite(AlphaComposite.getInstance(forceMode, (float) alpha / 255.f));
-            return;
-        }
-        Mode mode = PorterDuff.intToMode(paint.getPorterDuffMode());
-        Composite composite = PorterDuffUtility.getComposite(mode, alpha);
-        g.setComposite(composite);
-    }
-
-    private void mapRect(AffineTransform matrix, RectF dst, RectF src) {
-        // array with 4 corners
-        float[] corners = new float[] {
-                src.left, src.top,
-                src.right, src.top,
-                src.right, src.bottom,
-                src.left, src.bottom,
-        };
-
-        // apply the transform to them.
-        matrix.transform(corners, 0, corners, 0, 4);
-
-        // now put the result in the rect. We take the min/max of Xs and min/max of Ys
-        dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
-        dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
-
-        dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
-        dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
-    }
-
-    /**
-     * Returns the clip of the oldest snapshot of the stack, appropriately translated to be
-     * expressed in the coordinate system of the latest snapshot.
-     */
-    public Rectangle getOriginalClip() {
-        GcSnapshot originalSnapshot = this;
-        while (originalSnapshot.mPrevious != null) {
-            originalSnapshot = originalSnapshot.mPrevious;
-        }
-        if (originalSnapshot.mLayers.isEmpty()) {
-            return null;
-        }
-        Graphics2D graphics2D = originalSnapshot.mLayers.get(0).getGraphics();
-        Rectangle bounds = graphics2D.getClipBounds();
-        if (bounds == null) {
-            return null;
-        }
-        try {
-            AffineTransform originalTransform =
-                    ((Graphics2D) graphics2D.create()).getTransform().createInverse();
-            AffineTransform latestTransform = getTransform().createInverse();
-            bounds.x += latestTransform.getTranslateX() - originalTransform.getTranslateX();
-            bounds.y += latestTransform.getTranslateY() - originalTransform.getTranslateY();
-        } catch (NoninvertibleTransformException e) {
-            Bridge.getLog().warning(null, "Non invertible transformation", null, null);
-        }
-        return bounds;
-    }
-
-}
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java b/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java
deleted file mode 100644
index 7b70180..0000000
--- a/bridge/src/com/android/layoutlib/bridge/impl/PlayAnimationThread.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-package com.android.layoutlib.bridge.impl;
-
-import com.android.ide.common.rendering.api.IAnimationListener;
-import com.android.ide.common.rendering.api.Result;
-import com.android.ide.common.rendering.api.Result.Status;
-
-import android.animation.AnimationThread;
-import android.animation.Animator;
-
-public class PlayAnimationThread extends AnimationThread {
-
-    private final Animator mAnimator;
-
-    public PlayAnimationThread(Animator animator, RenderSessionImpl scene, String animName,
-            IAnimationListener listener) {
-        super(scene, animName, listener);
-        mAnimator = animator;
-    }
-
-    @Override
-    public Result preAnimation() {
-        // start the animation. This will send a message to the handler right away, so
-        // the queue is filled when this method returns.
-        mAnimator.start();
-
-        return Status.SUCCESS.createResult();
-    }
-
-    @Override
-    public void postAnimation() {
-        // nothing to be done.
-    }
-}
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java b/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java
deleted file mode 100644
index 86f80fe..0000000
--- a/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package com.android.layoutlib.bridge.impl;
-
-import com.android.ide.common.rendering.api.ILayoutLog;
-import com.android.layoutlib.bridge.Bridge;
-
-import android.graphics.BlendComposite;
-import android.graphics.BlendComposite.BlendingMode;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffColorFilter_Delegate;
-
-import java.awt.AlphaComposite;
-import java.awt.Composite;
-
-/**
- * Provides various utility methods for {@link PorterDuffColorFilter_Delegate}.
- */
-public final class PorterDuffUtility {
-
-    private static final int MODES_COUNT = Mode.values().length;
-
-    // Make the class non-instantiable.
-    private PorterDuffUtility() {
-    }
-
-    /**
-     * Convert the porterDuffMode from the framework to its corresponding enum. This defaults to
-     * {@link Mode#SRC_OVER} for invalid modes.
-     */
-    public static Mode getPorterDuffMode(int porterDuffMode) {
-        if (porterDuffMode >= 0 && porterDuffMode < MODES_COUNT) {
-            return PorterDuff.intToMode(porterDuffMode);
-        }
-        Bridge.getLog().error(ILayoutLog.TAG_BROKEN,
-                String.format("Unknown PorterDuff.Mode: %1$d", porterDuffMode), null, null);
-        assert false;
-        return Mode.SRC_OVER;
-    }
-
-    /**
-     * A utility method to get the {@link Composite} that represents the filter for the given
-     * PorterDuff mode and the alpha. Defaults to {@link Mode#SRC_OVER} for invalid modes.
-     */
-    public static Composite getComposite(Mode mode, int alpha255) {
-        float alpha1 = alpha255 != 0xFF ? alpha255 / 255.f : 1.f;
-        switch (mode) {
-            case CLEAR:
-                return AlphaComposite.getInstance(AlphaComposite.CLEAR, alpha1);
-            case SRC:
-                return AlphaComposite.getInstance(AlphaComposite.SRC, alpha1);
-            case DST:
-                return AlphaComposite.getInstance(AlphaComposite.DST, alpha1);
-            case SRC_OVER:
-                return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha1);
-            case DST_OVER:
-                return AlphaComposite.getInstance(AlphaComposite.DST_OVER, alpha1);
-            case SRC_IN:
-                return AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha1);
-            case DST_IN:
-                return AlphaComposite.getInstance(AlphaComposite.DST_IN, alpha1);
-            case SRC_OUT:
-                return AlphaComposite.getInstance(AlphaComposite.SRC_OUT, alpha1);
-            case DST_OUT:
-                return AlphaComposite.getInstance(AlphaComposite.DST_OUT, alpha1);
-            case SRC_ATOP:
-                return AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha1);
-            case DST_ATOP:
-                return AlphaComposite.getInstance(AlphaComposite.DST_ATOP, alpha1);
-            case XOR:
-                return AlphaComposite.getInstance(AlphaComposite.XOR, alpha1);
-            case DARKEN:
-                return BlendComposite.getInstance(BlendingMode.DARKEN, alpha1);
-            case LIGHTEN:
-                return BlendComposite.getInstance(BlendingMode.LIGHTEN, alpha1);
-            case MULTIPLY:
-                return BlendComposite.getInstance(BlendingMode.MULTIPLY, alpha1);
-            case SCREEN:
-                return BlendComposite.getInstance(BlendingMode.SCREEN, alpha1);
-            case ADD:
-                return BlendComposite.getInstance(BlendingMode.ADD, alpha1);
-            case OVERLAY:
-                return BlendComposite.getInstance(BlendingMode.OVERLAY, alpha1);
-            default:
-                Bridge.getLog().fidelityWarning(ILayoutLog.TAG_BROKEN,
-                        String.format("Unsupported PorterDuff Mode: %1$s", mode.name()),
-                        null, null, null /*data*/);
-
-                return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha1);
-        }
-    }
-}
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 2ab0509..7f351b6 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -31,7 +31,6 @@
 import com.android.tools.layoutlib.annotations.VisibleForTesting;
 
 import android.animation.PropertyValuesHolder_Accessor;
-import android.animation.PropertyValuesHolder_Delegate;
 import android.content.res.Configuration;
 import android.os.HandlerThread_Delegate;
 import android.util.DisplayMetrics;
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index dc05951..6a6e184 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -27,7 +27,7 @@
 
 import android.annotation.NonNull;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap_Delegate;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
@@ -153,8 +153,11 @@
         BufferedImage image = getImage(w, h);
 
         // Create an Android bitmap around the BufferedImage.
-        Bitmap bitmap = Bitmap_Delegate.createBitmap(image,
-                true /*isMutable*/, hardwareConfig.getDensity());
+        Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(),
+                Config.ARGB_8888);
+        bitmap.setPixels(image.getRGB(0, 0, image.getWidth(), image.getHeight(),
+                null, 0, image.getWidth()), 0, image.getWidth(), 0, 0, image
+                .getWidth(), image.getHeight());
 
         // Create a Canvas around the Android bitmap.
         Canvas canvas = new Canvas(bitmap);
@@ -162,6 +165,10 @@
 
         // Draw.
         content.draw(canvas);
+        int[] pixels = new int[image.getWidth() * image.getHeight()];
+        bitmap.getPixels(pixels, 0, image.getWidth(), 0, 0, image.getWidth(),
+                image.getHeight());
+        image.setRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
 
         // Detach root from window after draw.
         AttachInfo_Accessor.detachFromWindow(content);
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 93d3df8..9e93d75 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -49,20 +49,26 @@
 import com.android.tools.idea.validator.LayoutValidator;
 import com.android.tools.idea.validator.ValidatorResult;
 import com.android.tools.idea.validator.ValidatorResult.Builder;
-import com.android.tools.layoutlib.java.System_Delegate;
 import com.android.utils.Pair;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap_Delegate;
 import android.graphics.Canvas;
-import android.graphics.NinePatch_Delegate;
-import android.os.Looper;
+import android.graphics.HardwareRenderer;
+import android.graphics.LayoutlibRenderer;
+import android.graphics.PixelFormat;
+import android.graphics.RenderNode;
+import android.graphics.drawable.AnimatedVectorDrawable_VectorDrawableAnimatorUI_Delegate;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.media.ImageReader;
+import android.os.Handler_Delegate;
 import android.preference.Preference_Delegate;
 import android.view.AttachInfo_Accessor;
 import android.view.BridgeInflater;
 import android.view.Choreographer_Delegate;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
@@ -82,22 +88,24 @@
 import android.widget.TabHost.TabSpec;
 import android.widget.TabWidget;
 
-import java.awt.AlphaComposite;
-import java.awt.Color;
-import java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.nio.IntBuffer;
 import java.util.ArrayList;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
 
+import com.android.internal.R;
+import android.content.res.TypedArray;
+
 import com.google.android.apps.common.testing.accessibility.framework.uielement.AccessibilityHierarchyAndroid_ViewElementClassNamesAndroid_Delegate;
 
 import static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
 import static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
 import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
 import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
-import static com.android.layoutlib.bridge.util.ReflectionUtils.isInstanceOf;
+import static com.android.layoutlib.common.util.ReflectionUtils.isInstanceOf;
 
 /**
  * Class implementing the render session.
@@ -116,7 +124,6 @@
     private BridgeInflater mInflater;
     private ViewGroup mViewRoot;
     private FrameLayout mContentRoot;
-    private Canvas mCanvas;
     private int mMeasuredScreenWidth = -1;
     private int mMeasuredScreenHeight = -1;
     /** If >= 0, a frame will be executed */
@@ -130,6 +137,11 @@
     private List<ViewInfo> mSystemViewInfoList;
     private Layout.Builder mLayoutBuilder;
     private boolean mNewRenderSize;
+    private ImageReader mImageReader;
+    private Image mNativeImage;
+    private LayoutlibRenderer mRenderer = new LayoutlibRenderer();
+
+    private long mLastActionDownTimeNanos = -1;
     @Nullable private ValidatorResult mValidatorResult = null;
 
     private static final class PostInflateException extends Exception {
@@ -183,6 +195,11 @@
         ILayoutPullParser layoutParser = params.getLayoutDescription();
         mBlockParser = new BridgeXmlBlockParser(layoutParser, context, layoutParser.getLayoutNamespace());
 
+        Bitmap.setDefaultDensity(params.getHardwareConfig().getDensity().getDpiValue());
+
+        // Needed in order to initialize static state of ImageReader
+        ImageReader.nativeClassInit();
+
         return SUCCESS.createResult();
     }
 
@@ -191,16 +208,15 @@
      */
     private void measureLayout(@NonNull SessionParams params) {
         // only do the screen measure when needed.
-        if (mMeasuredScreenWidth != -1) {
-            return;
+        int previousWidth = mMeasuredScreenWidth;
+        int previousHeight = mMeasuredScreenHeight;
+        HardwareConfig hardwareConfig = params.getHardwareConfig();
+        if (mMeasuredScreenWidth == -1) {
+            mMeasuredScreenWidth = hardwareConfig.getScreenWidth();
+            mMeasuredScreenHeight = hardwareConfig.getScreenHeight();
         }
 
         RenderingMode renderingMode = params.getRenderingMode();
-        HardwareConfig hardwareConfig = params.getHardwareConfig();
-
-        mNewRenderSize = true;
-        mMeasuredScreenWidth = hardwareConfig.getScreenWidth();
-        mMeasuredScreenHeight = hardwareConfig.getScreenHeight();
 
         if (renderingMode != RenderingMode.NORMAL) {
             int widthMeasureSpecMode = renderingMode.getHorizAction() == SizeAction.EXPAND ?
@@ -224,55 +240,62 @@
             // and apply this to the screen size.
 
             View measuredView = mContentRoot.getChildAt(0);
+            if (measuredView == null) {
+                return;
+            }
 
+            int maxWidth = hardwareConfig.getScreenWidth();
+            int maxHeight = hardwareConfig.getScreenHeight();
             // first measure the full layout, with EXACTLY to get the size of the
             // content as it is inside the decor/dialog
             Pair<Integer, Integer> exactMeasure = measureView(
                     mViewRoot, measuredView,
-                    mMeasuredScreenWidth, MeasureSpec.EXACTLY,
-                    mMeasuredScreenHeight, MeasureSpec.EXACTLY);
+                    maxWidth, MeasureSpec.EXACTLY,
+                    maxHeight, MeasureSpec.EXACTLY);
 
             // now measure the content only using UNSPECIFIED (where applicable, based on
             // the rendering mode). This will give us the size the content needs.
             Pair<Integer, Integer> neededMeasure = measureView(
-                    mContentRoot, mContentRoot.getChildAt(0),
-                    mMeasuredScreenWidth, widthMeasureSpecMode,
-                    mMeasuredScreenHeight, heightMeasureSpecMode);
-            int neededWidth = neededMeasure.getFirst();
-            int neededHeight = neededMeasure.getSecond();
+                    mContentRoot, measuredView,
+                    maxWidth, widthMeasureSpecMode,
+                    maxHeight, heightMeasureSpecMode);
 
             // If measuredView is not null, exactMeasure nor result will be null.
-            assert (exactMeasure != null && neededMeasure != null) || measuredView == null;
+            assert (exactMeasure != null && neededMeasure != null);
 
             // now look at the difference and add what is needed.
-            if (renderingMode.getHorizAction() == SizeAction.EXPAND) {
-                int measuredWidth = exactMeasure.getFirst();
-                if (neededWidth > measuredWidth) {
-                    mMeasuredScreenWidth += neededWidth - measuredWidth;
-                }
-                if (mMeasuredScreenWidth < measuredWidth) {
-                    // If the screen width is less than the exact measured width,
-                    // expand to match.
-                    mMeasuredScreenWidth = measuredWidth;
-                }
-            } else if (renderingMode.getHorizAction() == SizeAction.SHRINK) {
-                mMeasuredScreenWidth = neededWidth;
-            }
-
-            if (renderingMode.getVertAction() == SizeAction.EXPAND) {
-                int measuredHeight = exactMeasure.getSecond();
-                if (neededHeight > measuredHeight) {
-                    mMeasuredScreenHeight += neededHeight - measuredHeight;
-                }
-                if (mMeasuredScreenHeight < measuredHeight) {
-                    // If the screen height is less than the exact measured height,
-                    // expand to match.
-                    mMeasuredScreenHeight = measuredHeight;
-                }
-            } else if (renderingMode.getVertAction() == SizeAction.SHRINK) {
-                mMeasuredScreenHeight = neededHeight;
-            }
+            mMeasuredScreenWidth = calcSize(mMeasuredScreenWidth, neededMeasure.getFirst(),
+                    exactMeasure.getFirst(), renderingMode.getHorizAction());
+            mMeasuredScreenHeight = calcSize(mMeasuredScreenHeight, neededMeasure.getSecond(),
+                    exactMeasure.getSecond(), renderingMode.getVertAction());
         }
+        mNewRenderSize =
+                mMeasuredScreenWidth != previousWidth || mMeasuredScreenHeight != previousHeight;
+    }
+
+    /**
+     * Calculate the required vertical (height) or horizontal (width) size of the canvas for the
+     * view, given current size requirements.
+     * @param currentSize current size of the canvas
+     * @param neededSize the size the content actually needs
+     * @param measuredSize the measured size of the content (restricted by the current size)
+     * @param action the {@link SizeAction} of the view
+     * @return the size the canvas should be
+     */
+    private static int calcSize(int currentSize, int neededSize, int measuredSize,
+            SizeAction action) {
+        if (action == SizeAction.EXPAND) {
+            if (neededSize > measuredSize) {
+                currentSize += neededSize - measuredSize;
+            }
+            if (currentSize < measuredSize) {
+                // If the screen size is less than the exact measured size, expand to match.
+                currentSize = measuredSize;
+            }
+        } else if (action == SizeAction.SHRINK) {
+            currentSize = neededSize;
+        }
+        return currentSize;
     }
 
     /**
@@ -346,8 +369,6 @@
                     visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(),
                     false);
 
-            Choreographer_Delegate.clearFrames();
-
             return SUCCESS.createResult();
         } catch (PostInflateException e) {
             return ERROR_INFLATION.createResult(e.getMessage(), e);
@@ -387,18 +408,19 @@
     }
 
     /**
-     * Renders the given view hierarchy to the passed canvas and returns the result of the render
-     * operation.
-     * @param canvas an optional canvas to render the views to. If null, only the measure and
-     * layout steps will be executed.
+     * Creates a display list for the root view and draws that display list with a "hardware"
+     * renderer. In layoutlib the renderer is not actually hardware (in contrast to the actual
+     * android) but pretends to be so in order to draw all the advanced android features (e.g.
+     * shadows).
      */
-    private static Result renderAndBuildResult(@NonNull ViewGroup viewRoot, @Nullable Canvas canvas) {
-        if (canvas == null) {
-            return SUCCESS.createResult();
-        }
+    private static Result renderAndBuildResult(@NonNull ViewGroup viewRoot,
+        @NonNull HardwareRenderer renderer) {
 
         AttachInfo_Accessor.dispatchOnPreDraw(viewRoot);
-        viewRoot.draw(canvas);
+
+        RenderNode node = viewRoot.updateDisplayListIfDirty();
+        renderer.setContentRoot(node);
+        renderer.createRenderRequest().syncAndDraw();
 
         return SUCCESS.createResult();
     }
@@ -469,13 +491,9 @@
             if (onlyMeasure) {
                 // delete the canvas and image to reset them on the next full rendering
                 mImage = null;
-                mCanvas = null;
+                disposeImageSurface();
                 doLayout(getContext(), mViewRoot, mMeasuredScreenWidth, mMeasuredScreenHeight);
             } else {
-                // draw the views
-                // create the BufferedImage into which the layout will be rendered.
-                boolean newImage = false;
-
                 // When disableBitmapCaching is true, we do not reuse mImage and
                 // we create a new one in every render.
                 // This is useful when mImage is just a wrapper of Graphics2D so
@@ -483,8 +501,7 @@
                 boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
                     RenderParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
 
-                if (mNewRenderSize || mCanvas == null || disableBitmapCaching) {
-                    mNewRenderSize = false;
+                if (mNewRenderSize || mImageReader == null || disableBitmapCaching) {
                     if (params.getImageFactory() != null) {
                         mImage = params.getImageFactory().getImage(
                                 mMeasuredScreenWidth,
@@ -494,72 +511,68 @@
                                 mMeasuredScreenWidth,
                                 mMeasuredScreenHeight,
                                 BufferedImage.TYPE_INT_ARGB);
-                        newImage = true;
-                    }
-
-                    if (params.isTransparentBackground()) {
-                        // since we override the content, it's the same as if it was a new image.
-                        newImage = true;
-                        Graphics2D gc = mImage.createGraphics();
-                        gc.setColor(new Color(0, true));
-                        gc.setComposite(AlphaComposite.Src);
-                        gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
-                        gc.dispose();
-                    }
-
-                    // create an Android bitmap around the BufferedImage
-                    Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
-                            true /*isMutable*/, hardwareConfig.getDensity());
-
-                    if (mCanvas == null) {
-                        // create a Canvas around the Android bitmap
-                        mCanvas = new Canvas(bitmap);
-                    } else {
-                        mCanvas.setBitmap(bitmap);
                     }
 
                     boolean enableImageResizing =
                             mImage.getWidth() != mMeasuredScreenWidth &&
-                            mImage.getHeight() != mMeasuredScreenHeight &&
-                            Boolean.TRUE.equals(params.getFlag(
-                                    RenderParamsFlags.FLAG_KEY_RESULT_IMAGE_AUTO_SCALE));
+                                    mImage.getHeight() != mMeasuredScreenHeight &&
+                                    Boolean.TRUE.equals(params.getFlag(
+                                            RenderParamsFlags.FLAG_KEY_RESULT_IMAGE_AUTO_SCALE));
 
-                    if (enableImageResizing) {
-                        float scaleX = (float)mImage.getWidth() / mMeasuredScreenWidth;
-                        float scaleY = (float)mImage.getHeight() / mMeasuredScreenHeight;
-                        mCanvas.scale(scaleX, scaleY);
+                    if (enableImageResizing || mNewRenderSize) {
+                        disposeImageSurface();
                     }
 
-                    mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
-                }
+                    if (enableImageResizing) {
+                        mRenderer.setScale(mImage.getWidth() * 1.0f / mMeasuredScreenWidth,
+                                mImage.getHeight() * 1.0f / mMeasuredScreenHeight);
+                    } else {
+                        mRenderer.setScale(1.0f, 1.0f);
+                    }
 
-                if (freshRender && !newImage) {
-                    Graphics2D gc = mImage.createGraphics();
-                    gc.setComposite(AlphaComposite.Src);
-
-                    gc.setColor(new Color(0x00000000, true));
-                    gc.fillRect(0, 0,
-                            mMeasuredScreenWidth, mMeasuredScreenHeight);
-
-                    // done
-                    gc.dispose();
+                    if (mImageReader == null) {
+                        mImageReader = ImageReader.newInstance(mImage.getWidth(), mImage.getHeight(), PixelFormat.RGBA_8888, 1);
+                        mRenderer.setSurface(mImageReader.getSurface());
+                        mNativeImage = mImageReader.acquireNextImage();
+                    }
+                    mNewRenderSize = false;
                 }
 
                 doLayout(getContext(), mViewRoot, mMeasuredScreenWidth, mMeasuredScreenHeight);
+
                 if (mElapsedFrameTimeNanos >= 0) {
-                    long initialTime = System_Delegate.nanoTime();
                     if (!mFirstFrameExecuted) {
                         // We need to run an initial draw call to initialize the animations
-                        renderAndBuildResult(mViewRoot, NOP_CANVAS);
+                        AttachInfo_Accessor.dispatchOnPreDraw(mViewRoot);
+                        mViewRoot.draw(NOP_CANVAS);
 
                         // The first frame will initialize the animations
-                        Choreographer_Delegate.doFrame(initialTime);
                         mFirstFrameExecuted = true;
                     }
                     // Second frame will move the animations
-                    Choreographer_Delegate.doFrame(initialTime + mElapsedFrameTimeNanos);
+                    AnimatedVectorDrawable_VectorDrawableAnimatorUI_Delegate.sFrameTime =
+                            mElapsedFrameTimeNanos / 1000000;
                 }
-                renderResult = renderAndBuildResult(mViewRoot, mCanvas);
+
+                final TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.Lighting, 0, 0);
+                float lightY = a.getDimension(R.styleable.Lighting_lightY, 0);
+                float lightZ = a.getDimension(R.styleable.Lighting_lightZ, 0);
+                float lightRadius = a.getDimension(R.styleable.Lighting_lightRadius, 0);
+                float ambientShadowAlpha = a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0);
+                float spotShadowAlpha = a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0);
+                a.recycle();
+
+                mRenderer.setLightSourceGeometry(mMeasuredScreenWidth / 2, lightY, lightZ, lightRadius);
+                mRenderer.setLightSourceAlpha(ambientShadowAlpha, spotShadowAlpha);
+
+                renderResult = renderAndBuildResult(mViewRoot, mRenderer);
+
+                int[] imageData = ((DataBufferInt) mImage.getRaster().getDataBuffer()).getData();
+
+                Plane[] planes = mNativeImage.getPlanes();
+                IntBuffer buff = planes[0].getBuffer().asIntBuffer();
+                int len = buff.remaining();
+                buff.get(imageData, 0, len);
             }
 
             mSystemViewInfoList =
@@ -1159,36 +1172,47 @@
         return mScene;
     }
 
+    public void dispatchTouchEvent(int motionEventType, long currentTimeNanos, float x, float y) {
+        if (mViewRoot == null) {
+            return;
+        }
+        if (motionEventType == MotionEvent.ACTION_DOWN) {
+            mLastActionDownTimeNanos = currentTimeNanos;
+        }
+        // Ignore events not started with MotionEvent.ACTION_DOWN
+        if (mLastActionDownTimeNanos == -1) {
+            return;
+        }
+
+        MotionEvent event = MotionEvent.obtain(mLastActionDownTimeNanos, currentTimeNanos,
+                motionEventType, x, y, 0);
+        mViewRoot.dispatchTouchEvent(event);
+    }
+
+    private void disposeImageSurface() {
+        if (mImageReader != null) {
+            mImageReader.close();
+            mImageReader = null;
+        }
+    }
+
     public void dispose() {
         try {
-            boolean createdLooper = false;
-            if (Looper.myLooper() == null) {
-                // Detaching the root view from the window will try to stop any running animations.
-                // The stop method checks that it can run in the looper so, if there is no current
-                // looper, we create a temporary one to complete the shutdown.
-                Bridge.prepareThread();
-                createdLooper = true;
-            }
+            mRenderer.destroy();
+            disposeImageSurface();
+            mImage = null;
+            // detachFromWindow might create Handler callbacks, thus before Handler_Delegate.dispose
             AttachInfo_Accessor.detachFromWindow(mViewRoot);
-            if (mCanvas != null) {
-                mCanvas.release();
-                mCanvas = null;
-            }
+            Handler_Delegate.dispose(getContext());
+            Choreographer_Delegate.dispose(getContext());
             if (mViewInfoList != null) {
                 mViewInfoList.clear();
             }
             if (mSystemViewInfoList != null) {
                 mSystemViewInfoList.clear();
             }
-            mImage = null;
             mViewRoot = null;
             mContentRoot = null;
-            NinePatch_Delegate.clearCache();
-
-            if (createdLooper) {
-                Choreographer_Delegate.dispose();
-                Bridge.cleanupThread();
-            }
         } catch (Throwable t) {
             getContext().error("Error while disposing a RenderSession", t);
         }
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index 0a36359..6a336ee 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -30,8 +30,8 @@
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.layoutlib.bridge.android.BridgeContext.Key;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.ninepatch.GraphicsUtilities;
 import com.android.ninepatch.NinePatch;
-import com.android.ninepatch.NinePatchChunk;
 import com.android.resources.Density;
 import com.android.resources.ResourceType;
 
@@ -48,8 +48,9 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap_Delegate;
-import android.graphics.NinePatch_Delegate;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapFactory.Options;
 import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.graphics.Typeface_Accessor;
@@ -60,10 +61,11 @@
 import android.graphics.drawable.NinePatchDrawable;
 import android.util.TypedValue;
 
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.MalformedURLException;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.regex.Matcher;
@@ -339,18 +341,7 @@
         }
 
         String lowerCaseValue = stringValue.toLowerCase();
-        if (lowerCaseValue.endsWith(NinePatch.EXTENSION_9PATCH)) {
-            try {
-                return getNinePatchDrawable(density, value.isFramework(), stringValue, context);
-            } catch (IOException e) {
-                // failed to read the file, we'll return null below.
-                Bridge.getLog().error(ILayoutLog.TAG_RESOURCES_READ,
-                        "Failed to load " + stringValue, e, null, null /*data*/);
-            }
-
-            return null;
-        } else if (lowerCaseValue.endsWith(".xml") ||
-                value.getResourceType() == ResourceType.AAPT) {
+        if (lowerCaseValue.endsWith(".xml") || value.getResourceType() == ResourceType.AAPT) {
             // create a block parser for the file
             try {
                 BridgeXmlBlockParser blockParser = getXmlBlockParser(context, value);
@@ -396,13 +387,39 @@
                         } catch (FileNotFoundException e) {
                             stream = null;
                         }
-                        bitmap =
-                                Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density);
+                        Options options = new Options();
+                        options.inDensity = density.getDpiValue();
+                        bitmap = BitmapFactory.decodeStream(stream, null, options);
+                        if (bitmap != null && bitmap.getNinePatchChunk() == null &&
+                                lowerCaseValue.endsWith(NinePatch.EXTENSION_9PATCH)) {
+                            //We are dealing with a non-compiled nine patch.
+                            stream = repository.openNonAsset(0, stringValue, ACCESS_STREAMING);
+                            NinePatch ninePatch = NinePatch.load(stream, true /*is9Patch*/, false /* convert */);
+                            BufferedImage image = ninePatch.getImage();
+
+                            // width and height of the nine patch without the special border.
+                            int width = image.getWidth();
+                            int height = image.getHeight();
+
+                            // Get pixel data from image independently of its type.
+                            int[] imageData = GraphicsUtilities.getPixels(image, 0, 0, width,
+                                    height, null);
+
+                            bitmap = Bitmap.createBitmap(imageData, width, height, Config.ARGB_8888);
+
+                            bitmap.setDensity(options.inDensity);
+                            bitmap.setNinePatchChunk(ninePatch.getChunk().getSerializedChunk());
+                        }
                         Bridge.setCachedBitmap(stringValue, bitmap,
                                 value.isFramework() ? null : context.getProjectKey());
                     }
 
-                    return new BitmapDrawable(context.getResources(), bitmap);
+                    if (bitmap != null && bitmap.getNinePatchChunk() != null) {
+                        return new NinePatchDrawable(context.getResources(), bitmap, bitmap
+                                .getNinePatchChunk(), new Rect(), lowerCaseValue);
+                    } else {
+                        return new BitmapDrawable(context.getResources(), bitmap);
+                    }
                 } catch (IOException e) {
                     // we'll return null below
                     Bridge.getLog().error(ILayoutLog.TAG_RESOURCES_READ,
@@ -451,58 +468,6 @@
         return getFont(value.getValue(), context, theme, value.isFramework());
     }
 
-    private static Drawable getNinePatchDrawable(Density density, boolean isFramework,
-            String path, BridgeContext context) throws IOException {
-        // see if we still have both the chunk and the bitmap in the caches
-        NinePatchChunk chunk = Bridge.getCached9Patch(path,
-                isFramework ? null : context.getProjectKey());
-        Bitmap bitmap = Bridge.getCachedBitmap(path,
-                isFramework ? null : context.getProjectKey());
-
-        // if either chunk or bitmap is null, then we reload the 9-patch file.
-        if (chunk == null || bitmap == null) {
-            try {
-                AssetRepository repository = getAssetRepository(context);
-                if (!repository.isFileResource(path)) {
-                    return null;
-                }
-                InputStream stream = repository.openNonAsset(0, path, ACCESS_STREAMING);
-                NinePatch ninePatch = NinePatch.load(stream, true /*is9Patch*/,
-                        false /* convert */);
-                if (ninePatch != null) {
-                    if (chunk == null) {
-                        chunk = ninePatch.getChunk();
-
-                        Bridge.setCached9Patch(path, chunk,
-                                isFramework ? null : context.getProjectKey());
-                    }
-
-                    if (bitmap == null) {
-                        bitmap = Bitmap_Delegate.createBitmap(ninePatch.getImage(),
-                                false /*isMutable*/,
-                                density);
-
-                        Bridge.setCachedBitmap(path, bitmap,
-                                isFramework ? null : context.getProjectKey());
-                    }
-                }
-            } catch (MalformedURLException e) {
-                // URL is wrong, we'll return null below
-            }
-        }
-
-        if (chunk != null && bitmap != null) {
-            int[] padding = chunk.getPadding();
-            Rect paddingRect = new Rect(padding[0], padding[1], padding[2], padding[3]);
-
-            return new NinePatchDrawable(context.getResources(), bitmap,
-                    NinePatch_Delegate.serialize(chunk),
-                    paddingRect, null);
-        }
-
-        return null;
-    }
-
     /**
      * Looks for an attribute in the current theme.
      *
diff --git a/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java b/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java
index d84b411..84ed6a0 100644
--- a/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java
+++ b/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java
@@ -31,7 +31,8 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap_Delegate;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapFactory.Options;
 import android.graphics.drawable.BitmapDrawable;
 import android.widget.ImageView;
 
@@ -81,12 +82,10 @@
             // look for a cached bitmap
             Bitmap bitmap = Bridge.getCachedBitmap(path, Boolean.TRUE /*isFramework*/);
             if (bitmap == null) {
-                try {
-                    bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density);
-                    Bridge.setCachedBitmap(path, bitmap, Boolean.TRUE /*isFramework*/);
-                } catch (IOException e) {
-                    return imageView;
-                }
+                Options options = new Options();
+                options.inDensity = density.getDpiValue();
+                bitmap = BitmapFactory.decodeStream(stream, null, options);
+                Bridge.setCachedBitmap(path, bitmap, Boolean.TRUE /*isFramework*/);
             }
 
             if (bitmap != null) {
diff --git a/bridge/src/com/android/layoutlib/bridge/util/CachedPathIteratorFactory.java b/bridge/src/com/android/layoutlib/bridge/util/CachedPathIteratorFactory.java
deleted file mode 100644
index 0a9b9ec..0000000
--- a/bridge/src/com/android/layoutlib/bridge/util/CachedPathIteratorFactory.java
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-package com.android.layoutlib.bridge.util;
-
-import android.annotation.NonNull;
-
-import java.awt.geom.CubicCurve2D;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.awt.geom.QuadCurve2D;
-import java.util.ArrayList;
-
-import com.google.android.collect.Lists;
-
-/**
- * Class that returns iterators for a given path. These iterators are lightweight and can be reused
- * multiple times to iterate over the path.
- */
-public class CachedPathIteratorFactory {
-    /*
-     * A few conventions used in the code:
-     * Coordinates or coords arrays store segment coordinates. They use the same format as
-     * PathIterator#currentSegment coordinates array.
-     * float arrays store always points where the first element is X and the second is Y.
-     */
-
-    // This governs how accurate the approximation of the Path is.
-    private static final float PRECISION = 0.002f;
-
-    private final int mWindingRule;
-    private final int[] mTypes;
-    private final float[][] mCoordinates;
-    private final float[] mSegmentsLength;
-    private final float mTotalLength;
-
-    public CachedPathIteratorFactory(@NonNull PathIterator iterator) {
-        mWindingRule = iterator.getWindingRule();
-
-        ArrayList<Integer> typesArray = Lists.newArrayList();
-        ArrayList<float[]> pointsArray = Lists.newArrayList();
-        float[] points = new float[6];
-        while (!iterator.isDone()) {
-            int type = iterator.currentSegment(points);
-            int nPoints = getNumberOfPoints(type) * 2; // 2 coordinates per point
-
-            typesArray.add(type);
-            float[] itemPoints = new float[nPoints];
-            System.arraycopy(points, 0, itemPoints, 0, nPoints);
-            pointsArray.add(itemPoints);
-            iterator.next();
-        }
-
-        mTypes = new int[typesArray.size()];
-        mCoordinates = new float[mTypes.length][];
-        for (int i = 0; i < typesArray.size(); i++) {
-            mTypes[i] = typesArray.get(i);
-            mCoordinates[i] = pointsArray.get(i);
-        }
-
-        // Do measurement
-        mSegmentsLength = new float[mTypes.length];
-
-        // Curves that we can reuse to estimate segments length
-        CubicCurve2D.Float cubicCurve = new CubicCurve2D.Float();
-        QuadCurve2D.Float quadCurve = new QuadCurve2D.Float();
-        float lastX = 0;
-        float lastY = 0;
-        float totalLength = 0;
-        for (int i = 0; i < mTypes.length; i++) {
-            switch (mTypes[i]) {
-                case PathIterator.SEG_CUBICTO:
-                    cubicCurve.setCurve(lastX, lastY,
-                            mCoordinates[i][0], mCoordinates[i][1], mCoordinates[i][2],
-                            mCoordinates[i][3], lastX = mCoordinates[i][4],
-                            lastY = mCoordinates[i][5]);
-                    mSegmentsLength[i] =
-                            getFlatPathLength(cubicCurve.getPathIterator(null, PRECISION));
-                    break;
-                case PathIterator.SEG_QUADTO:
-                    quadCurve.setCurve(lastX, lastY, mCoordinates[i][0], mCoordinates[i][1],
-                            lastX = mCoordinates[i][2], lastY = mCoordinates[i][3]);
-                    mSegmentsLength[i] =
-                            getFlatPathLength(quadCurve.getPathIterator(null, PRECISION));
-                    break;
-                case PathIterator.SEG_CLOSE:
-                    mSegmentsLength[i] = (float) Point2D.distance(lastX, lastY,
-                            lastX = mCoordinates[0][0],
-                            lastY = mCoordinates[0][1]);
-                    mCoordinates[i] = new float[2];
-                    // We convert a SEG_CLOSE segment to a SEG_LINETO so we do not have to worry
-                    // about this special case in the rest of the code.
-                    mTypes[i] = PathIterator.SEG_LINETO;
-                    mCoordinates[i][0] = mCoordinates[0][0];
-                    mCoordinates[i][1] = mCoordinates[0][1];
-                    break;
-                case PathIterator.SEG_MOVETO:
-                    mSegmentsLength[i] = 0;
-                    lastX = mCoordinates[i][0];
-                    lastY = mCoordinates[i][1];
-                    break;
-                case PathIterator.SEG_LINETO:
-                    mSegmentsLength[i] = (float) Point2D.distance(lastX, lastY, mCoordinates[i][0],
-                            mCoordinates[i][1]);
-                    lastX = mCoordinates[i][0];
-                    lastY = mCoordinates[i][1];
-                default:
-            }
-            totalLength += mSegmentsLength[i];
-        }
-
-        mTotalLength = totalLength;
-    }
-
-    private static void quadCurveSegment(float[] coords, float t0, float t1) {
-        // Calculate X and Y at 0.5 (We'll use this to reconstruct the control point later)
-        float mt = t0 + (t1 - t0) / 2;
-        float mu = 1 - mt;
-        float mx = mu * mu * coords[0] + 2 * mu * mt * coords[2] + mt * mt * coords[4];
-        float my = mu * mu * coords[1] + 2 * mu * mt * coords[3] + mt * mt * coords[5];
-
-        float u0 = 1 - t0;
-        float u1 = 1 - t1;
-
-        // coords at t0
-        coords[0] = coords[0] * u0 * u0 + coords[2] * 2 * t0 * u0 + coords[4] * t0 * t0;
-        coords[1] = coords[1] * u0 * u0 + coords[3] * 2 * t0 * u0 + coords[5] * t0 * t0;
-
-        // coords at t1
-        coords[4] = coords[0] * u1 * u1 + coords[2] * 2 * t1 * u1 + coords[4] * t1 * t1;
-        coords[5] = coords[1] * u1 * u1 + coords[3] * 2 * t1 * u1 + coords[5] * t1 * t1;
-
-        // estimated control point at t'=0.5
-        coords[2] = 2 * mx - coords[0] / 2 - coords[4] / 2;
-        coords[3] = 2 * my - coords[1] / 2 - coords[5] / 2;
-    }
-
-    private static void cubicCurveSegment(float[] coords, float t0, float t1) {
-        // http://stackoverflow.com/questions/11703283/cubic-bezier-curve-segment
-        float u0 = 1 - t0;
-        float u1 = 1 - t1;
-
-        // Calculate the points at t0 and t1 for the quadratic curves formed by (P0, P1, P2) and
-        // (P1, P2, P3)
-        float qxa = coords[0] * u0 * u0 + coords[2] * 2 * t0 * u0 + coords[4] * t0 * t0;
-        float qxb = coords[0] * u1 * u1 + coords[2] * 2 * t1 * u1 + coords[4] * t1 * t1;
-        float qxc = coords[2] * u0 * u0 + coords[4] * 2 * t0 * u0 + coords[6] * t0 * t0;
-        float qxd = coords[2] * u1 * u1 + coords[4] * 2 * t1 * u1 + coords[6] * t1 * t1;
-
-        float qya = coords[1] * u0 * u0 + coords[3] * 2 * t0 * u0 + coords[5] * t0 * t0;
-        float qyb = coords[1] * u1 * u1 + coords[3] * 2 * t1 * u1 + coords[5] * t1 * t1;
-        float qyc = coords[3] * u0 * u0 + coords[5] * 2 * t0 * u0 + coords[7] * t0 * t0;
-        float qyd = coords[3] * u1 * u1 + coords[5] * 2 * t1 * u1 + coords[7] * t1 * t1;
-
-        // Linear interpolation
-        coords[0] = qxa * u0 + qxc * t0;
-        coords[1] = qya * u0 + qyc * t0;
-
-        coords[2] = qxa * u1 + qxc * t1;
-        coords[3] = qya * u1 + qyc * t1;
-
-        coords[4] = qxb * u0 + qxd * t0;
-        coords[5] = qyb * u0 + qyd * t0;
-
-        coords[6] = qxb * u1 + qxd * t1;
-        coords[7] = qyb * u1 + qyd * t1;
-    }
-
-    /**
-     * Returns the end point of a given segment
-     *
-     * @param type the segment type
-     * @param coords the segment coordinates array
-     * @param point the return array where the point will be stored
-     */
-    private static void getShapeEndPoint(int type, @NonNull float[] coords, @NonNull float[]
-            point) {
-        // start index of the end point for the segment type
-        int pointIndex = (getNumberOfPoints(type) - 1) * 2;
-        point[0] = coords[pointIndex];
-        point[1] = coords[pointIndex + 1];
-    }
-
-    /**
-     * Returns the number of points stored in a coordinates array for the given segment type.
-     */
-    private static int getNumberOfPoints(int segmentType) {
-        switch (segmentType) {
-            case PathIterator.SEG_QUADTO:
-                return 2;
-            case PathIterator.SEG_CUBICTO:
-                return 3;
-            case PathIterator.SEG_CLOSE:
-                return 0;
-            default:
-                return 1;
-        }
-    }
-
-    /**
-     * Returns the estimated length of a flat path. If the passed path is not flat (i.e. contains a
-     * segment that is not {@link PathIterator#SEG_CLOSE}, {@link PathIterator#SEG_MOVETO} or {@link
-     * PathIterator#SEG_LINETO} this method will fail.
-     */
-    private static float getFlatPathLength(@NonNull PathIterator iterator) {
-        float segment[] = new float[6];
-        float totalLength = 0;
-        float[] previousPoint = new float[2];
-        boolean isFirstPoint = true;
-
-        while (!iterator.isDone()) {
-            int type = iterator.currentSegment(segment);
-            assert type == PathIterator.SEG_LINETO || type == PathIterator.SEG_CLOSE || type ==
-                    PathIterator.SEG_MOVETO;
-
-            // MoveTo shouldn't affect the length
-            if (!isFirstPoint && type != PathIterator.SEG_MOVETO) {
-                totalLength += Point2D.distance(previousPoint[0], previousPoint[1], segment[0],
-                        segment[1]);
-            } else {
-                isFirstPoint = false;
-            }
-            previousPoint[0] = segment[0];
-            previousPoint[1] = segment[1];
-            iterator.next();
-        }
-
-        return totalLength;
-    }
-
-    /**
-     * Returns the estimated position along a path of the given length.
-     */
-    private void getPointAtLength(int type, @NonNull float[] coords, float lastX, float
-            lastY, float t, @NonNull float[] point) {
-        if (type == PathIterator.SEG_LINETO) {
-            point[0] = lastX + (coords[0] - lastX) * t;
-            point[1] = lastY + (coords[1] - lastY) * t;
-            // Return here, since we do not need a shape to estimate
-            return;
-        }
-
-        float[] curve = new float[8];
-        int lastPointIndex = (getNumberOfPoints(type) - 1) * 2;
-
-        System.arraycopy(coords, 0, curve, 2, coords.length);
-        curve[0] = lastX;
-        curve[1] = lastY;
-        if (type == PathIterator.SEG_CUBICTO) {
-            cubicCurveSegment(curve, 0f, t);
-        } else {
-            quadCurveSegment(curve, 0f, t);
-        }
-
-        point[0] = curve[2 + lastPointIndex];
-        point[1] = curve[2 + lastPointIndex + 1];
-    }
-
-    public CachedPathIterator iterator() {
-        return new CachedPathIterator();
-    }
-
-    /**
-     * Class that allows us to iterate over a path multiple times
-     */
-    public class CachedPathIterator implements PathIterator {
-        private int mNextIndex;
-
-        /**
-         * Current segment type.
-         *
-         * @see PathIterator
-         */
-        private int mCurrentType;
-
-        /**
-         * Stores the coordinates array of the current segment. The number of points stored depends
-         * on the segment type.
-         *
-         * @see PathIterator
-         */
-        private float[] mCurrentCoords = new float[6];
-        private float mCurrentSegmentLength;
-
-        /**
-         * Current segment length offset. When asking for the length of the current segment, the
-         * length will be reduced by this amount. This is useful when we are only using portions of
-         * the segment.
-         *
-         * @see #jumpToSegment(float)
-         */
-        private float mOffsetLength;
-
-        /** Point where the current segment started */
-        private float[] mLastPoint = new float[2];
-        private boolean isIteratorDone;
-
-        private CachedPathIterator() {
-            next();
-        }
-
-        public float getCurrentSegmentLength() {
-            return mCurrentSegmentLength;
-        }
-
-        @Override
-        public int getWindingRule() {
-            return mWindingRule;
-        }
-
-        @Override
-        public boolean isDone() {
-            return isIteratorDone;
-        }
-
-        @Override
-        public void next() {
-            if (mNextIndex >= mTypes.length) {
-                isIteratorDone = true;
-                return;
-            }
-
-            if (mNextIndex >= 1) {
-                // We've already called next() once so there is a previous segment in this path.
-                // We want to get the coordinates where the path ends.
-                getShapeEndPoint(mCurrentType, mCurrentCoords, mLastPoint);
-            } else {
-                // This is the first segment, no previous point so initialize to 0, 0
-                mLastPoint[0] = mLastPoint[1] = 0f;
-            }
-            mCurrentType = mTypes[mNextIndex];
-            mCurrentSegmentLength = mSegmentsLength[mNextIndex] - mOffsetLength;
-
-            if (mOffsetLength > 0f && (mCurrentType == SEG_CUBICTO || mCurrentType == SEG_QUADTO)) {
-                // We need to skip part of the start of the current segment (because
-                // mOffsetLength > 0)
-                float[] points = new float[8];
-
-                if (mNextIndex < 1) {
-                    points[0] = points[1] = 0f;
-                } else {
-                    getShapeEndPoint(mTypes[mNextIndex - 1], mCoordinates[mNextIndex - 1], points);
-                }
-
-                System.arraycopy(mCoordinates[mNextIndex], 0, points, 2,
-                        mCoordinates[mNextIndex].length);
-                float t0 = (mSegmentsLength[mNextIndex] - mCurrentSegmentLength) /
-                        mSegmentsLength[mNextIndex];
-                if (mCurrentType == SEG_CUBICTO) {
-                    cubicCurveSegment(points, t0, 1f);
-                } else {
-                    quadCurveSegment(points, t0, 1f);
-                }
-                System.arraycopy(points, 2, mCurrentCoords, 0, mCoordinates[mNextIndex].length);
-            } else {
-                System.arraycopy(mCoordinates[mNextIndex], 0, mCurrentCoords, 0,
-                        mCoordinates[mNextIndex].length);
-            }
-
-            mOffsetLength = 0f;
-            mNextIndex++;
-        }
-
-        @Override
-        public int currentSegment(float[] coords) {
-            System.arraycopy(mCurrentCoords, 0, coords, 0, getNumberOfPoints(mCurrentType) * 2);
-            return mCurrentType;
-        }
-
-        @Override
-        public int currentSegment(double[] coords) {
-            throw new UnsupportedOperationException();
-        }
-
-        /**
-         * Returns the point where the current segment ends
-         */
-        public void getCurrentSegmentEnd(float[] point) {
-            point[0] = mLastPoint[0];
-            point[1] = mLastPoint[1];
-        }
-
-        /**
-         * Restarts the iterator and jumps all the segments of this path up to the length value.
-         */
-        public void jumpToSegment(float length) {
-            isIteratorDone = false;
-            if (length <= 0f) {
-                mNextIndex = 0;
-                return;
-            }
-
-            float accLength = 0;
-            float lastPoint[] = new float[2];
-            for (mNextIndex = 0; mNextIndex < mTypes.length; mNextIndex++) {
-                float segmentLength = mSegmentsLength[mNextIndex];
-                if (accLength + segmentLength >= length && mTypes[mNextIndex] != SEG_MOVETO) {
-                    float[] estimatedPoint = new float[2];
-                    getPointAtLength(mTypes[mNextIndex],
-                            mCoordinates[mNextIndex], lastPoint[0], lastPoint[1],
-                            (length - accLength) / segmentLength,
-                            estimatedPoint);
-
-                    // This segment makes us go further than length so we go back one step,
-                    // set a moveto and offset the length of the next segment by the length
-                    // of this segment that we've already used.
-                    mCurrentType = PathIterator.SEG_MOVETO;
-                    mCurrentCoords[0] = estimatedPoint[0];
-                    mCurrentCoords[1] = estimatedPoint[1];
-                    mCurrentSegmentLength = 0;
-
-                    // We need to offset next path length to account for the segment we've just
-                    // skipped.
-                    mOffsetLength = length - accLength;
-                    return;
-                }
-                accLength += segmentLength;
-                getShapeEndPoint(mTypes[mNextIndex], mCoordinates[mNextIndex], lastPoint);
-            }
-        }
-
-        /**
-         * Returns the current segment up to certain length. If the current segment is shorter than
-         * length, then the whole segment is returned. The segment coordinates are copied into the
-         * coords array.
-         *
-         * @return the segment type
-         */
-        public int currentSegment(@NonNull float[] coords, float length) {
-            int type = currentSegment(coords);
-            // If the length is greater than the current segment length, no need to find
-            // the cut point. Same if this is a SEG_MOVETO.
-            if (mCurrentSegmentLength <= length || type == SEG_MOVETO) {
-                return type;
-            }
-
-            float t = length / getCurrentSegmentLength();
-
-            // We find at which offset the end point is located within the coords array and set
-            // a new end point to cut the segment short
-            switch (type) {
-                case SEG_CUBICTO:
-                case SEG_QUADTO:
-                    float[] curve = new float[8];
-                    curve[0] = mLastPoint[0];
-                    curve[1] = mLastPoint[1];
-                    System.arraycopy(coords, 0, curve, 2, coords.length);
-                    if (type == SEG_CUBICTO) {
-                        cubicCurveSegment(curve, 0f, t);
-                    } else {
-                        quadCurveSegment(curve, 0f, t);
-                    }
-                    System.arraycopy(curve, 2, coords, 0, coords.length);
-                    break;
-                default:
-                    float[] point = new float[2];
-                    getPointAtLength(type, coords, mLastPoint[0], mLastPoint[1], t, point);
-                    coords[0] = point[0];
-                    coords[1] = point[1];
-            }
-
-            return type;
-        }
-
-        /**
-         * Returns the total length of the path
-         */
-        public float getTotalLength() {
-            return mTotalLength;
-        }
-    }
-}
diff --git a/bridge/src/com/android/layoutlib/bridge/util/CallbacksDisposer.java b/bridge/src/com/android/layoutlib/bridge/util/CallbacksDisposer.java
new file mode 100644
index 0000000..dab4d0d
--- /dev/null
+++ b/bridge/src/com/android/layoutlib/bridge/util/CallbacksDisposer.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.layoutlib.bridge.util;
+
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.tools.layoutlib.annotations.NotNull;
+import com.android.tools.layoutlib.annotations.VisibleForTesting;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.function.Consumer;
+
+/**
+ * Tracks Choreographer callbacks with corresponding RenderSessions (represented by BridgeContext)
+ * and calls actionDisposer against the action that can be disposed.
+ */
+public class CallbacksDisposer {
+    /**
+     * An abstraction not to keep heavy session-related object like BridgeContext.
+     */
+    public static class SessionKey {
+        private final int bridgeContextHash;
+
+        public SessionKey(@NotNull BridgeContext bc) {
+            bridgeContextHash = System.identityHashCode(bc);
+        }
+
+        @VisibleForTesting
+        public SessionKey(int bridgeContextHash) {
+            this.bridgeContextHash = bridgeContextHash;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof SessionKey)) {
+                return false;
+            }
+
+            return this.bridgeContextHash == ((SessionKey) obj).bridgeContextHash;
+        }
+
+        @Override
+        public int hashCode() {
+            return bridgeContextHash;
+        }
+    }
+
+    @NotNull private final Consumer<Object> mActionDisposer;
+    // Tracking actions that should be removed from Choreographer to prevent memory leaks. Using
+    // WeakHashMap as WeakHashSet. If a key (action) gets garbage collected we do not need to do
+    // anything since it is not referenced by the Choreographer.
+    @NotNull private final Map<SessionKey, WeakHashMap<Object, Object>> mFrameCallbacks =
+            new HashMap<>();
+
+    /**
+     * Constructs disposer
+     * @param actionDisposer a function to be called against the action that should be disposed
+     */
+    public CallbacksDisposer(@NotNull Consumer<Object> actionDisposer) {
+        mActionDisposer = actionDisposer;
+    }
+
+    /**
+     * Inform disposer that an action was added during the session
+     * @param sessionKey representing the session
+     * @param action callback that was added
+     */
+    public void onCallbackAdded(@NotNull SessionKey sessionKey, @NotNull Object action) {
+        mFrameCallbacks.computeIfAbsent(sessionKey, r -> new WeakHashMap<>()).put(action, null);
+    }
+
+    /**
+     * Inform disposer that an action was removed during the session
+     * @param sessionKey representing the session
+     * @param action callback that was removed
+     * @return true if the callback for the session was stored and removed, false otherwise
+     */
+    public boolean onCallbackRemoved(@NotNull SessionKey sessionKey, @NotNull Object action) {
+        WeakHashMap<Object, Object> sessionCallbacks = mFrameCallbacks.get(sessionKey);
+        if (sessionCallbacks == null) {
+            return false;
+        }
+        return sessionCallbacks.remove(action, null);
+    }
+
+    /**
+     * Inform the disposer that the session is being disposed
+     * @param sessionKey representing the session
+     */
+    public void onDispose(@NotNull SessionKey sessionKey) {
+        WeakHashMap<Object, Object> actionSet = mFrameCallbacks.remove(sessionKey);
+        if (actionSet != null) {
+            for (Object action : actionSet.keySet()) {
+                mActionDisposer.accept(action);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    public Set<SessionKey> getSessionsWithCallbacks() {
+        return mFrameCallbacks.keySet();
+    }
+}
diff --git a/bridge/src/com/android/layoutlib/bridge/util/HandlerMessageQueue.java b/bridge/src/com/android/layoutlib/bridge/util/HandlerMessageQueue.java
new file mode 100644
index 0000000..7fe38d6
--- /dev/null
+++ b/bridge/src/com/android/layoutlib/bridge/util/HandlerMessageQueue.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.layoutlib.bridge.util;
+
+import com.android.tools.layoutlib.annotations.NotNull;
+import com.android.tools.layoutlib.annotations.Nullable;
+import com.android.utils.Pair;
+
+import android.os.Handler;
+
+import java.util.LinkedList;
+import java.util.WeakHashMap;
+
+/**
+ * A queue that stores {@link Runnable}s associated with the corresponding {@link Handler}s.
+ * {@link Runnable}s get automatically released when the corresponding {@link Handler} gets
+ * collected by the garbage collector. All {@link Runnable}s are queued in a single virtual queue
+ * with respect to their corresponding uptime (the time when they should be executed).
+ */
+public class HandlerMessageQueue {
+    private final WeakHashMap<Handler, LinkedList<Pair<Long, Runnable>>> runnablesMap =
+            new WeakHashMap<>();
+
+    /**
+     * Adds a {@link Runnable} associated with the {@link Handler} to be executed at
+     * particular time
+     * @param h handler associated with the {@link Runnable}
+     * @param uptimeMillis time in milliseconds the {@link Runnable} to be executed
+     * @param r {@link Runnable} to be added
+     */
+    public void add(@NotNull Handler h, long uptimeMillis, @NotNull Runnable r) {
+        LinkedList<Pair<Long, Runnable>> runnables = runnablesMap.computeIfAbsent(h,
+                k -> new LinkedList<>());
+
+        int idx = 0;
+        while (idx < runnables.size()) {
+            if (runnables.get(idx).getFirst() <= uptimeMillis) {
+                idx++;
+            } else {
+                break;
+            }
+        }
+        runnables.add(idx, Pair.of(uptimeMillis, r));
+    }
+
+    private static class HandlerWrapper {
+        public Handler handler;
+    }
+
+    /**
+     * Removes from the queue and returns the {@link Runnable} with the smallest uptime if it
+     * is less than the one passed as a parameter or null if such runnable does not exist.
+     * @param uptimeMillis
+     * @return the {@link Runnable} from the queue
+     */
+    @Nullable
+    public Runnable extractFirst(long uptimeMillis) {
+        final HandlerWrapper w = new HandlerWrapper();
+        runnablesMap.forEach((h, l) -> {
+            if (!l.isEmpty()) {
+                long currentUptime = l.getFirst().getFirst();
+                if (currentUptime <= uptimeMillis) {
+                    if (w.handler == null || currentUptime <
+                            runnablesMap.get(w.handler).getFirst().getFirst()) {
+                        w.handler = h;
+                    }
+                }
+            }
+        });
+        if (w.handler != null) {
+            return runnablesMap.get(w.handler).pollFirst().getSecond();
+        }
+        return null;
+    }
+
+    /**
+     * @return true is queue has no runnables left
+     */
+    public boolean isNotEmpty() {
+        return runnablesMap.values().stream().anyMatch(l -> !l.isEmpty());
+    }
+
+    /**
+     * @return number of runnables in the queue
+     */
+    public int size() {
+        return runnablesMap.values().stream().mapToInt(LinkedList::size).sum();
+    }
+
+    /**
+     * Completely clears the entire queue
+     */
+    public void clear() {
+        runnablesMap.clear();
+    }
+}
diff --git a/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java b/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java
index 75e4a2b..a50090b 100644
--- a/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java
+++ b/bridge/src/com/android/layoutlib/bridge/util/NinePatchInputStream.java
@@ -33,13 +33,21 @@
 public class NinePatchInputStream extends InputStream {
     private final InputStream mDelegate;
     private boolean mFakeMarkSupport = true;
+    private final String mPath;
 
     public NinePatchInputStream(File file) throws FileNotFoundException {
         mDelegate = new FileInputStream(file);
+        mPath = file.getPath();
     }
 
-    public NinePatchInputStream(@NotNull InputStream stream) {
+    public NinePatchInputStream(@NotNull InputStream stream, @NotNull String path) {
         mDelegate = stream;
+        mPath = path;
+    }
+
+    @NotNull
+    public String getPath() {
+        return mPath;
     }
 
     @Override
diff --git a/bridge/src/dalvik/system/VMRuntime_Delegate.java b/bridge/src/dalvik/system/VMRuntime_Delegate.java
index 648d2be..2fe1015 100644
--- a/bridge/src/dalvik/system/VMRuntime_Delegate.java
+++ b/bridge/src/dalvik/system/VMRuntime_Delegate.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -26,59 +26,14 @@
  */
 public class VMRuntime_Delegate {
 
-    // Copied from libcore/libdvm/src/main/java/dalvik/system/VMRuntime
     @LayoutlibDelegate
     /*package*/ static Object newUnpaddedArray(VMRuntime runtime, Class<?> componentType,
             int minLength) {
-        // Dalvik has 32bit pointers, the array header is 16bytes plus 4bytes for dlmalloc,
-        // allocations are 8byte aligned so having 4bytes of array data avoids padding.
-        if (!componentType.isPrimitive()) {
-            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
-            return java.lang.reflect.Array.newInstance(componentType, size);
-        } else if (componentType == char.class) {
-            int bytes = 20 + (2 * minLength);
-            int alignedUpBytes = (bytes + 7) & -8;
-            int dataBytes = alignedUpBytes - 20;
-            int size = dataBytes / 2;
-            return new char[size];
-        } else if (componentType == int.class) {
-            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
-            return new int[size];
-        } else if (componentType == byte.class) {
-            int bytes = 20 + minLength;
-            int alignedUpBytes = (bytes + 7) & -8;
-            int dataBytes = alignedUpBytes - 20;
-            int size = dataBytes;
-            return new byte[size];
-        } else if (componentType == boolean.class) {
-            int bytes = 20 + minLength;
-            int alignedUpBytes = (bytes + 7) & -8;
-            int dataBytes = alignedUpBytes - 20;
-            int size = dataBytes;
-            return new boolean[size];
-        } else if (componentType == short.class) {
-            int bytes = 20 + (2 * minLength);
-            int alignedUpBytes = (bytes + 7) & -8;
-            int dataBytes = alignedUpBytes - 20;
-            int size = dataBytes / 2;
-            return new short[size];
-        } else if (componentType == float.class) {
-            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
-            return new float[size];
-        } else if (componentType == long.class) {
-            return new long[minLength];
-        } else if (componentType == double.class) {
-            return new double[minLength];
-        } else {
-            assert componentType == void.class;
-            throw new IllegalArgumentException("Can't allocate an array of void");
-        }
+        return VMRuntimeCommonHelper.newUnpaddedArray(runtime, componentType, minLength);
     }
 
     @LayoutlibDelegate
     /*package*/ static int getNotifyNativeInterval() {
-        // This cannot return 0, otherwise it is responsible for triggering an exception
-        // whenever trying to use a NativeAllocationRegistry with size 0
-        return 1;
+        return VMRuntimeCommonHelper.getNotifyNativeInterval();
     }
 }
diff --git a/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java b/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java
index 141c728..04fabc2 100644
--- a/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java
+++ b/bridge/src/libcore/util/NativeAllocationRegistry_Delegate.java
@@ -51,22 +51,6 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void registerNativeAllocation(long size) {
-        NativeAllocationRegistry.registerNativeAllocation_Original(size);
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static Runnable registerNativeAllocation(NativeAllocationRegistry registry,
-            Object referent,
-            long nativePtr) {
-        // Mark the object as already "natively" tracked.
-        // This allows the DelegateManager to dispose objects without waiting
-        // for an explicit call when the referent does not exist anymore.
-        sManager.markAsNativeAllocation(referent, nativePtr);
-        return registry.registerNativeAllocation_Original(referent, nativePtr);
-    }
-
-    @LayoutlibDelegate
     /*package*/ static void applyFreeFunction(long freeFunction, long nativePtr) {
         // This method MIGHT run in the context of the finalizer thread. If the delegate method
         // crashes, it could bring down the VM. That's why we catch all the exceptions and ignore
diff --git a/bridge/tests/res/com/android/layoutlib/testdata/compiled.9.png b/bridge/tests/res/com/android/layoutlib/testdata/compiled.9.png
new file mode 100644
index 0000000..a5f5f3b
--- /dev/null
+++ b/bridge/tests/res/com/android/layoutlib/testdata/compiled.9.png
Binary files differ
diff --git a/bridge/tests/res/com/android/layoutlib/testdata/non_compiled.9.png b/bridge/tests/res/com/android/layoutlib/testdata/non_compiled.9.png
new file mode 100644
index 0000000..9d52f40
--- /dev/null
+++ b/bridge/tests/res/com/android/layoutlib/testdata/non_compiled.9.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$drawable.class b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$drawable.class
index 5ac9e72..0292770 100644
--- a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$drawable.class
+++ b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$drawable.class
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$font.class b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$font.class
index 6fe46c5..5a596a2 100644
--- a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$font.class
+++ b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$font.class
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$id.class b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$id.class
index 15e3e52..aafc5b4 100644
--- a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$id.class
+++ b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$id.class
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$integer.class b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$integer.class
index 64df0c3..def2f60 100644
--- a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$integer.class
+++ b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$integer.class
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$layout.class b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$layout.class
index c0bb96d..6786cf2 100644
--- a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$layout.class
+++ b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$layout.class
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$menu.class b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$menu.class
index afeb357..252030e 100644
--- a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$menu.class
+++ b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$menu.class
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$string.class b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$string.class
index c8d5e0b..823ba90 100644
--- a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$string.class
+++ b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$string.class
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$style.class b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$style.class
index ccfecc8..4dd0af6 100644
--- a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$style.class
+++ b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/R$style.class
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/ThemableWidget.class b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/ThemableWidget.class
index 5171dad..5500abe 100644
--- a/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/ThemableWidget.class
+++ b/bridge/tests/res/testApp/MyApplication/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/android/layoutlib/test/myapplication/ThemableWidget.class
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/a11y_test1.png b/bridge/tests/res/testApp/MyApplication/golden-mac/a11y_test1.png
new file mode 100644
index 0000000..7108915
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/a11y_test1.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/activity.png b/bridge/tests/res/testApp/MyApplication/golden-mac/activity.png
new file mode 100644
index 0000000..8a0b3fd
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/activity.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon.png b/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon.png
new file mode 100644
index 0000000..efcd49e
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon_circle.png b/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon_circle.png
new file mode 100644
index 0000000..f85ef1b
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon_circle.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon_rounded_corners.png b/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon_rounded_corners.png
new file mode 100644
index 0000000..3bb7055
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon_rounded_corners.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon_squircle.png b/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon_squircle.png
new file mode 100644
index 0000000..f3b3a08
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/adaptive_icon_squircle.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/allwidgets.png b/bridge/tests/res/testApp/MyApplication/golden-mac/allwidgets.png
new file mode 100644
index 0000000..32d7f8f
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/allwidgets.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/allwidgets_tab.png b/bridge/tests/res/testApp/MyApplication/golden-mac/allwidgets_tab.png
new file mode 100644
index 0000000..fb4c791
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/allwidgets_tab.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/animated_vector.png b/bridge/tests/res/testApp/MyApplication/golden-mac/animated_vector.png
new file mode 100644
index 0000000..b4bed24
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/animated_vector.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/animated_vector_1.png b/bridge/tests/res/testApp/MyApplication/golden-mac/animated_vector_1.png
new file mode 100644
index 0000000..37863c7
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/animated_vector_1.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/array_check.png b/bridge/tests/res/testApp/MyApplication/golden-mac/array_check.png
new file mode 100644
index 0000000..db6e934
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/array_check.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/asset.png b/bridge/tests/res/testApp/MyApplication/golden-mac/asset.png
new file mode 100644
index 0000000..9e58720
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/asset.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/auto-scale-image.png b/bridge/tests/res/testApp/MyApplication/golden-mac/auto-scale-image.png
new file mode 100644
index 0000000..9e4465a
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/auto-scale-image.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/button_resize.png b/bridge/tests/res/testApp/MyApplication/golden-mac/button_resize.png
new file mode 100644
index 0000000..dc81204
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/button_resize.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/button_resize2.png b/bridge/tests/res/testApp/MyApplication/golden-mac/button_resize2.png
new file mode 100644
index 0000000..9b79576
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/button_resize2.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/canvas.png b/bridge/tests/res/testApp/MyApplication/golden-mac/canvas.png
new file mode 100644
index 0000000..0d6c011
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/canvas.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/color_interpolation.png b/bridge/tests/res/testApp/MyApplication/golden-mac/color_interpolation.png
new file mode 100644
index 0000000..c816e57
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/color_interpolation.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/context_theme_wrapper.png b/bridge/tests/res/testApp/MyApplication/golden-mac/context_theme_wrapper.png
new file mode 100644
index 0000000..63578fa
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/context_theme_wrapper.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/expand_horz_layout.png b/bridge/tests/res/testApp/MyApplication/golden-mac/expand_horz_layout.png
new file mode 100644
index 0000000..f179977
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/expand_horz_layout.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/expand_vert_layout.png b/bridge/tests/res/testApp/MyApplication/golden-mac/expand_vert_layout.png
new file mode 100644
index 0000000..269b7ac
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/expand_vert_layout.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/font_test.png b/bridge/tests/res/testApp/MyApplication/golden-mac/font_test.png
new file mode 100644
index 0000000..e036c16
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/font_test.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/four_corners.png b/bridge/tests/res/testApp/MyApplication/golden-mac/four_corners.png
new file mode 100644
index 0000000..f400c9a
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/four_corners.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/four_corners_translucent.png b/bridge/tests/res/testApp/MyApplication/golden-mac/four_corners_translucent.png
new file mode 100644
index 0000000..7b11e3d
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/four_corners_translucent.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/four_corners_translucent_land.png b/bridge/tests/res/testApp/MyApplication/golden-mac/four_corners_translucent_land.png
new file mode 100644
index 0000000..82d937f
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/four_corners_translucent_land.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/gradient_alpha_drawable.png b/bridge/tests/res/testApp/MyApplication/golden-mac/gradient_alpha_drawable.png
new file mode 100644
index 0000000..8892bcf
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/gradient_alpha_drawable.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/gradient_colors.png b/bridge/tests/res/testApp/MyApplication/golden-mac/gradient_colors.png
new file mode 100644
index 0000000..d5b7c10
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/gradient_colors.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/justified_inter_word.png b/bridge/tests/res/testApp/MyApplication/golden-mac/justified_inter_word.png
new file mode 100644
index 0000000..4807821
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/justified_inter_word.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/justified_none.png b/bridge/tests/res/testApp/MyApplication/golden-mac/justified_none.png
new file mode 100644
index 0000000..e083346
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/justified_none.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/large_shadows_test_high_quality.png b/bridge/tests/res/testApp/MyApplication/golden-mac/large_shadows_test_high_quality.png
new file mode 100644
index 0000000..a79ad55
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/large_shadows_test_high_quality.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/many_line_breaks.png b/bridge/tests/res/testApp/MyApplication/golden-mac/many_line_breaks.png
new file mode 100644
index 0000000..ea5750c
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/many_line_breaks.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/ninepatch_background.png b/bridge/tests/res/testApp/MyApplication/golden-mac/ninepatch_background.png
new file mode 100644
index 0000000..13514f4
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/ninepatch_background.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/ninepatch_drawable.png b/bridge/tests/res/testApp/MyApplication/golden-mac/ninepatch_drawable.png
new file mode 100644
index 0000000..211594d
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/ninepatch_drawable.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/normal_layout.png b/bridge/tests/res/testApp/MyApplication/golden-mac/normal_layout.png
new file mode 100644
index 0000000..f60ecb0
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/normal_layout.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/ondraw_crash.png b/bridge/tests/res/testApp/MyApplication/golden-mac/ondraw_crash.png
new file mode 100644
index 0000000..8633a25
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/ondraw_crash.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/onmeasure_crash.png b/bridge/tests/res/testApp/MyApplication/golden-mac/onmeasure_crash.png
new file mode 100644
index 0000000..5559a89
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/onmeasure_crash.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/rtl_ltr.png b/bridge/tests/res/testApp/MyApplication/golden-mac/rtl_ltr.png
new file mode 100644
index 0000000..6a451a2
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/rtl_ltr.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/scrolled.png b/bridge/tests/res/testApp/MyApplication/golden-mac/scrolled.png
new file mode 100644
index 0000000..97bf039
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/scrolled.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/shadow_scrollview_test_high_quality.png b/bridge/tests/res/testApp/MyApplication/golden-mac/shadow_scrollview_test_high_quality.png
new file mode 100644
index 0000000..b0c8611
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/shadow_scrollview_test_high_quality.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/shadow_sizes_test_high_quality.png b/bridge/tests/res/testApp/MyApplication/golden-mac/shadow_sizes_test_high_quality.png
new file mode 100644
index 0000000..e656899
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/shadow_sizes_test_high_quality.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test.png b/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test.png
new file mode 100644
index 0000000..c8dea1b
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test_high_quality.png b/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test_high_quality.png
new file mode 100644
index 0000000..c8dea1b
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test_high_quality.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test_high_quality_rounded_edge.png b/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test_high_quality_rounded_edge.png
new file mode 100644
index 0000000..c12d0c9
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test_high_quality_rounded_edge.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test_no_shadow.png b/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test_no_shadow.png
new file mode 100644
index 0000000..c8dea1b
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/shadows_test_no_shadow.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/shrunk_layout.png b/bridge/tests/res/testApp/MyApplication/golden-mac/shrunk_layout.png
new file mode 100644
index 0000000..e2eb120
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/shrunk_layout.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/simple_activity-old-theme.png b/bridge/tests/res/testApp/MyApplication/golden-mac/simple_activity-old-theme.png
new file mode 100644
index 0000000..6dca9fd
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/simple_activity-old-theme.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/simple_activity.png b/bridge/tests/res/testApp/MyApplication/golden-mac/simple_activity.png
new file mode 100644
index 0000000..3542bd5
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/simple_activity.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/simple_activity_noactionbar.png b/bridge/tests/res/testApp/MyApplication/golden-mac/simple_activity_noactionbar.png
new file mode 100644
index 0000000..9620fdb
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/simple_activity_noactionbar.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/textclock.png b/bridge/tests/res/testApp/MyApplication/golden-mac/textclock.png
new file mode 100644
index 0000000..108380c
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/textclock.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/translate_test.png b/bridge/tests/res/testApp/MyApplication/golden-mac/translate_test.png
new file mode 100644
index 0000000..032089f
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/translate_test.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/transparent_drawable.png b/bridge/tests/res/testApp/MyApplication/golden-mac/transparent_drawable.png
new file mode 100644
index 0000000..68ccf2f
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/transparent_drawable.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/typed_arrays.png b/bridge/tests/res/testApp/MyApplication/golden-mac/typed_arrays.png
new file mode 100644
index 0000000..e3f4df7
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/typed_arrays.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable.png b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable.png
new file mode 100644
index 0000000..0827ea5
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_91383.png b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_91383.png
new file mode 100644
index 0000000..1d4ac39
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_91383.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_gradient.png b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_gradient.png
new file mode 100644
index 0000000..0268d9c
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_gradient.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_radial_gradient.png b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_radial_gradient.png
new file mode 100644
index 0000000..a27a48e
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_radial_gradient.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_with_tint_in_image_view.png b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_with_tint_in_image_view.png
new file mode 100644
index 0000000..48f0f05
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_with_tint_in_image_view.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_with_tint_itself.png b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_with_tint_itself.png
new file mode 100644
index 0000000..92855d1
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/vector_drawable_with_tint_itself.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/view_boundaries.png b/bridge/tests/res/testApp/MyApplication/golden-mac/view_boundaries.png
new file mode 100644
index 0000000..69974da
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/view_boundaries.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden-mac/view_stub.png b/bridge/tests/res/testApp/MyApplication/golden-mac/view_stub.png
new file mode 100644
index 0000000..b66ff2d
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden-mac/view_stub.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/activity.png b/bridge/tests/res/testApp/MyApplication/golden/activity.png
index 2d55e8f..b7efa2a 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/activity.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/activity.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon.png b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon.png
index eccd6ea..efcd49e 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_circle.png b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_circle.png
index b98b38b..228ba4b 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_circle.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_circle.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_rounded_corners.png b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_rounded_corners.png
index 44d2161..8e3f729 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_rounded_corners.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_rounded_corners.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_squircle.png b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_squircle.png
index 3361cc9..1e6c70f 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_squircle.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/adaptive_icon_squircle.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png b/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
index 8d64d47..674c53e 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/allwidgets.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png b/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png
index 7559d54..fb4c791 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/allwidgets_tab.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png b/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png
index 072df30..6d55e74 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/animated_vector.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png b/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png
index 348a0f4..761f606 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/animated_vector_1.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/array_check.png b/bridge/tests/res/testApp/MyApplication/golden/array_check.png
index e4be842..f5289c4 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/array_check.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/array_check.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/asset.png b/bridge/tests/res/testApp/MyApplication/golden/asset.png
index 3a00361..1261bcf 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/asset.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/asset.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/auto-scale-image.png b/bridge/tests/res/testApp/MyApplication/golden/auto-scale-image.png
index f6ff623..eb11f1d 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/auto-scale-image.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/auto-scale-image.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/button_resize.png b/bridge/tests/res/testApp/MyApplication/golden/button_resize.png
new file mode 100644
index 0000000..96b8c7e
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden/button_resize.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/button_resize2.png b/bridge/tests/res/testApp/MyApplication/golden/button_resize2.png
new file mode 100644
index 0000000..dd75376
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden/button_resize2.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/canvas.png b/bridge/tests/res/testApp/MyApplication/golden/canvas.png
index a267b07..ff23e2c 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/canvas.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/canvas.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/color_interpolation.png b/bridge/tests/res/testApp/MyApplication/golden/color_interpolation.png
index 2d90bc3..09efad4 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/color_interpolation.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/color_interpolation.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/context_theme_wrapper.png b/bridge/tests/res/testApp/MyApplication/golden/context_theme_wrapper.png
index 5627108..63578fa 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/context_theme_wrapper.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/context_theme_wrapper.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png b/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
index 0ae96a5..f179977 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/expand_horz_layout.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png b/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png
index 2f0b937..269b7ac 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/expand_vert_layout.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/font_test.png b/bridge/tests/res/testApp/MyApplication/golden/font_test.png
index b3db624..3100636 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/font_test.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/font_test.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/four_corners.png b/bridge/tests/res/testApp/MyApplication/golden/four_corners.png
index e79c860..e476b68 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/four_corners.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/four_corners.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png b/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png
index 7129944..f759a63 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png b/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png
index 0e5336f..5cfd468 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/four_corners_translucent_land.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/gradient_alpha_drawable.png b/bridge/tests/res/testApp/MyApplication/golden/gradient_alpha_drawable.png
index c5e6e40..8892bcf 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/gradient_alpha_drawable.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/gradient_alpha_drawable.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/gradient_colors.png b/bridge/tests/res/testApp/MyApplication/golden/gradient_colors.png
index 137eda8..122aeae 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/gradient_colors.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/gradient_colors.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/justified_inter_word.png b/bridge/tests/res/testApp/MyApplication/golden/justified_inter_word.png
new file mode 100644
index 0000000..d3b4d72
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden/justified_inter_word.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/justified_none.png b/bridge/tests/res/testApp/MyApplication/golden/justified_none.png
new file mode 100644
index 0000000..e2d4405
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden/justified_none.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/large_shadows_test_high_quality.png b/bridge/tests/res/testApp/MyApplication/golden/large_shadows_test_high_quality.png
index 17bb713..2740391 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/large_shadows_test_high_quality.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/large_shadows_test_high_quality.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/many_line_breaks.png b/bridge/tests/res/testApp/MyApplication/golden/many_line_breaks.png
index bfe7ce0..76092db 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/many_line_breaks.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/many_line_breaks.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/ninepatch_background.png b/bridge/tests/res/testApp/MyApplication/golden/ninepatch_background.png
index b3ac436..dbf8dff 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/ninepatch_background.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/ninepatch_background.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/ninepatch_drawable.png b/bridge/tests/res/testApp/MyApplication/golden/ninepatch_drawable.png
new file mode 100644
index 0000000..211594d
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden/ninepatch_drawable.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/normal_layout.png b/bridge/tests/res/testApp/MyApplication/golden/normal_layout.png
index f1d406e..f60ecb0 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/normal_layout.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/normal_layout.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/ondraw_crash.png b/bridge/tests/res/testApp/MyApplication/golden/ondraw_crash.png
index 79aa3a8..8633a25 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/ondraw_crash.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/ondraw_crash.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/onmeasure_crash.png b/bridge/tests/res/testApp/MyApplication/golden/onmeasure_crash.png
index bac8f8e..5559a89 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/onmeasure_crash.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/onmeasure_crash.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/rtl_ltr.png b/bridge/tests/res/testApp/MyApplication/golden/rtl_ltr.png
index 1690785..47596ae 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/rtl_ltr.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/rtl_ltr.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/scrolled.png b/bridge/tests/res/testApp/MyApplication/golden/scrolled.png
index 27227ea..97bf039 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/scrolled.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/scrolled.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadow_scrollview_test_high_quality.png b/bridge/tests/res/testApp/MyApplication/golden/shadow_scrollview_test_high_quality.png
index 716cd08..c4420f5 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/shadow_scrollview_test_high_quality.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/shadow_scrollview_test_high_quality.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadow_sizes_test_high_quality.png b/bridge/tests/res/testApp/MyApplication/golden/shadow_sizes_test_high_quality.png
index a4ff637..7b466fd 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/shadow_sizes_test_high_quality.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/shadow_sizes_test_high_quality.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png b/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
index 21f5ee1..91aad9c 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality.png b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality.png
index 1e10963..91aad9c 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality_rounded_edge.png b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality_rounded_edge.png
index 25ba535..3d850c1 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality_rounded_edge.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_high_quality_rounded_edge.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_no_shadow.png b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_no_shadow.png
index 0492491..91aad9c 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/shadows_test_no_shadow.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/shadows_test_no_shadow.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/shrunk_layout.png b/bridge/tests/res/testApp/MyApplication/golden/shrunk_layout.png
index fe6fc16..e2eb120 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/shrunk_layout.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/shrunk_layout.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png b/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png
index 01adbd7..0d3bc22 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/simple_activity-old-theme.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png b/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png
index 4f62a5d..8acb7a3 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/simple_activity.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png b/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png
index aee806f..c8117d2 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/simple_activity_noactionbar.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/textclock.png b/bridge/tests/res/testApp/MyApplication/golden/textclock.png
index e33047d..7f1ccc6 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/textclock.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/textclock.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/translate_test.png b/bridge/tests/res/testApp/MyApplication/golden/translate_test.png
index c031e41..c680f21 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/translate_test.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/translate_test.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/transparent_drawable.png b/bridge/tests/res/testApp/MyApplication/golden/transparent_drawable.png
new file mode 100644
index 0000000..68ccf2f
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden/transparent_drawable.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/typed_arrays.png b/bridge/tests/res/testApp/MyApplication/golden/typed_arrays.png
index 5e13aac..b75b3a1 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/typed_arrays.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/typed_arrays.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
index 88f72c6..ecc4497 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png
index 5e27b09..2af7475 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_91383.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_gradient.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_gradient.png
index 89da005..0268d9c 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_gradient.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_gradient.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_multi_line_of_path_data.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_multi_line_of_path_data.png
deleted file mode 100644
index 6422056..0000000
--- a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_multi_line_of_path_data.png
+++ /dev/null
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_radial_gradient.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_radial_gradient.png
index a3dd935..a27a48e 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_radial_gradient.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_radial_gradient.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_in_image_view.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_in_image_view.png
index dc8bd06..1abac2d 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_in_image_view.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_in_image_view.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_itself.png b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_itself.png
index 9e13c62..1749850 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_itself.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/vector_drawable_with_tint_itself.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/view_boundaries.png b/bridge/tests/res/testApp/MyApplication/golden/view_boundaries.png
index b9a5001..08581eb 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/view_boundaries.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/view_boundaries.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/golden/view_stub.png b/bridge/tests/res/testApp/MyApplication/golden/view_stub.png
index 7e32c13..840f752 100644
--- a/bridge/tests/res/testApp/MyApplication/golden/view_stub.png
+++ b/bridge/tests/res/testApp/MyApplication/golden/view_stub.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable-nodpi/ninepatch.9.png b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable-nodpi/ninepatch.9.png
index fb3660e..c0bbc81 100644
--- a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable-nodpi/ninepatch.9.png
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable-nodpi/ninepatch.9.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable-nodpi/uncompiled_ninepatch.9.png b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable-nodpi/uncompiled_ninepatch.9.png
new file mode 100644
index 0000000..fb3660e
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable-nodpi/uncompiled_ninepatch.9.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/ninepatch_drawable.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/ninepatch_drawable.xml
new file mode 100644
index 0000000..c14388d
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/ninepatch_drawable.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2019 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.
+  -->
+
+<nine-patch
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/uncompiled_ninepatch" />
\ No newline at end of file
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/transparent_drawable.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/transparent_drawable.xml
new file mode 100644
index 0000000..e7cbc06
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/transparent_drawable.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="#55FF0000"/>
+    <size
+        android:width="48dp"
+        android:height="48dp"/>
+</shape>
\ No newline at end of file
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/fonts_test.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/fonts_test.xml
index c63b211..67869c8 100644
--- a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/fonts_test.xml
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/fonts_test.xml
@@ -23,7 +23,8 @@
         android:layout_height="wrap_content"
         android:text="MONOSPACE"
         android:textSize="50sp"
-        android:fontFamily="monospace"/>
+        android:fontFamily="monospace"
+        android:rotationX="45"/>
 
     <Space
         android:layout_width="wrap_content"
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/justified_inter_word.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/justified_inter_word.xml
new file mode 100644
index 0000000..6e9f183
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/justified_inter_word.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  android:layout_width="match_parent" android:layout_height="match_parent">
+
+  <TextView
+    android:id="@+id/justified"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:justificationMode="inter_word"
+    android:text="@string/large_text"/>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/justified_none.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/justified_none.xml
new file mode 100644
index 0000000..ffd757e
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/justified_none.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+  android:layout_width="match_parent" android:layout_height="match_parent">
+
+  <TextView
+    android:id="@+id/justified"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:justificationMode="none"
+    android:text="@string/large_text"/>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/values/strings.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/values/strings.xml
index 2b7083b..f4ff361 100644
--- a/bridge/tests/res/testApp/MyApplication/src/main/res/values/strings.xml
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/values/strings.xml
@@ -4,5 +4,94 @@
     <string name="app_name">My Application</string>
     <string name="hello_world">Hello world!</string>
     <string name="action_settings">Settings</string>
+    <string name="large_text">
+        "Material is the metaphor.\n\n"
+
+        "A material metaphor is the unifying theory of a rationalized space and a system of motion."
+        "The material is grounded in tactile reality, inspired by the study of paper and ink, yet "
+        "technologically advanced and open to imagination and magic.\n"
+        "Surfaces and edges of the material provide visual cues that are grounded in reality. The "
+        "use of familiar tactile attributes helps users quickly understand affordances. Yet the "
+        "flexibility of the material creates new affordances that supercede those in the physical "
+        "world, without breaking the rules of physics.\n"
+        "The fundamentals of light, surface, and movement are key to conveying how objects move, "
+        "interact, and exist in space and in relation to each other. Realistic lighting shows "
+        "seams, divides space, and indicates moving parts.\n\n"
+
+        "Bold, graphic, intentional.\n\n"
+
+        "The foundational elements of print based design typography, grids, space, scale, color, "
+        "and use of imagery guide visual treatments. These elements do far more than please the "
+        "eye. They create hierarchy, meaning, and focus. Deliberate color choices, edge to edge "
+        "imagery, large scale typography, and intentional white space create a bold and graphic "
+        "interface that immerse the user in the experience.\n"
+        "An emphasis on user actions makes core functionality immediately apparent and provides "
+        "waypoints for the user.\n\n"
+
+        "Motion provides meaning.\n\n"
+
+        "Motion respects and reinforces the user as the prime mover. Primary user actions are "
+        "inflection points that initiate motion, transforming the whole design.\n"
+        "All action takes place in a single environment. Objects are presented to the user without "
+        "breaking the continuity of experience even as they transform and reorganize.\n"
+        "Motion is meaningful and appropriate, serving to focus attention and maintain continuity. "
+        "Feedback is subtle yet clear. Transitions are efficient yet coherent.\n\n"
+
+        "3D world.\n\n"
+
+        "The material environment is a 3D space, which means all objects have x, y, and z "
+        "dimensions. The z-axis is perpendicularly aligned to the plane of the display, with the "
+        "positive z-axis extending towards the viewer. Every sheet of material occupies a single "
+        "position along the z-axis and has a standard 1dp thickness.\n"
+        "On the web, the z-axis is used for layering and not for perspective. The 3D world is "
+        "emulated by manipulating the y-axis.\n\n"
+
+        "Light and shadow.\n\n"
+
+        "Within the material environment, virtual lights illuminate the scene. Key lights create "
+        "directional shadows, while ambient light creates soft shadows from all angles.\n"
+        "Shadows in the material environment are cast by these two light sources. In Android "
+        "development, shadows occur when light sources are blocked by sheets of material at "
+        "various positions along the z-axis. On the web, shadows are depicted by manipulating the "
+        "y-axis only. The following example shows the card with a height of 6dp.\n\n"
+
+        "Resting elevation.\n\n"
+
+        "All material objects, regardless of size, have a resting elevation, or default elevation "
+        "that does not change. If an object changes elevation, it should return to its resting "
+        "elevation as soon as possible.\n\n"
+
+        "Component elevations.\n\n"
+
+        "The resting elevation for a component type is consistent across apps (e.g., FAB elevation "
+        "does not vary from 6dp in one app to 16dp in another app).\n"
+        "Components may have different resting elevations across platforms, depending on the depth "
+        "of the environment (e.g., TV has a greater depth than mobile or desktop).\n\n"
+
+        "Responsive elevation and dynamic elevation offsets.\n\n"
+
+        "Some component types have responsive elevation, meaning they change elevation in response "
+        "to user input (e.g., normal, focused, and pressed) or system events. These elevation "
+        "changes are consistently implemented using dynamic elevation offsets.\n"
+        "Dynamic elevation offsets are the goal elevation that a component moves towards, relative "
+        "to the component’s resting state. They ensure that elevation changes are consistent "
+        "across actions and component types. For example, all components that lift on press have "
+        "the same elevation change relative to their resting elevation.\n"
+        "Once the input event is completed or cancelled, the component will return to its resting "
+        "elevation.\n\n"
+
+        "Avoiding elevation interference.\n\n"
+
+        "Components with responsive elevations may encounter other components as they move between "
+        "their resting elevations and dynamic elevation offsets. Because material cannot pass "
+        "through other material, components avoid interfering with one another any number of ways, "
+        "whether on a per component basis or using the entire app layout.\n"
+        "On a component level, components can move or be removed before they cause interference. "
+        "For example, a floating action button (FAB) can disappear or move off screen before a "
+        "user picks up a card, or it can move if a snackbar appears.\n"
+        "On the layout level, design your app layout to minimize opportunities for interference. "
+        "For example, position the FAB to one side of stream of a cards so the FAB won’t interfere "
+        "when a user tries to pick up one of cards.\n\n"
+    </string>
 
 </resources>
diff --git a/bridge/tests/run_tests.sh b/bridge/tests/run_tests.sh
index 3c68921..694ccb3 100755
--- a/bridge/tests/run_tests.sh
+++ b/bridge/tests/run_tests.sh
@@ -12,9 +12,35 @@
 STUDIO_JDK=${SCRIPT_DIR}"/../../../../prebuilts/jdk/jdk11/linux-x86"
 MISC_COMMON=${SCRIPT_DIR}"/../../../../prebuilts/misc/common"
 OUT_INTERMEDIATES=${SCRIPT_DIR}"/../../../../out/soong/.intermediates"
+NATIVE_LIBRARIES=${SCRIPT_DIR}"/../../../../out/host/linux-x86/lib64/"
+SDK=${SCRIPT_DIR}"/../../../../out/host/linux-x86/sdk/sdk*/android-sdk*"
+FONT_DIR=${SCRIPT_DIR}"/../../../../out/host/common/obj/PACKAGING/fonts_intermediates"
+ICU_DIR=${SCRIPT_DIR}"/../../../../out/host/linux-x86/com.android.i18n/etc/icu"
+TMP_DIR=$(mktemp -d)
+PLATFORM=${TMP_DIR}/"android"
+
+# Copy resources to a temp directory
+cp -r ${SDK}/platforms/android* ${PLATFORM}
+
+# Compile 9-patch files
+mkdir ${TMP_DIR}/compiled
+mkdir ${TMP_DIR}/manifest
+echo \
+'<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.google.android.layoutlib" />' \
+> ${TMP_DIR}/manifest/AndroidManifest.xml
+find ${SDK}/platforms/android*/data/res -name "*.9.png" -print0 | xargs -0 ${SDK}/build-tools/android-*/aapt2 compile -o ${TMP_DIR}/compiled/
+find ${TMP_DIR}/compiled -name "*.flat" -print0 | xargs -0 -s 1000000 ${SDK}/build-tools/android-*/aapt2 link -o ${TMP_DIR}/compiled.apk --manifest ${TMP_DIR}/manifest/AndroidManifest.xml -R
+unzip -q ${TMP_DIR}/compiled.apk -d ${TMP_DIR}
+for f in ${TMP_DIR}/res/*; do mv "$f" "${f/-v4/}";done
+cp -RL ${TMP_DIR}/res ${PLATFORM}/data
 
 # Run layoutlib tests
 ${STUDIO_JDK}/bin/java -ea \
+    -Dnative.lib.path=${NATIVE_LIBRARIES} \
+    -Dfont.dir=${FONT_DIR} \
+    -Dicu.dir=${ICU_DIR} \
+    -Dplatform.dir=${PLATFORM} \
     -Dtest_res.dir=${SCRIPT_DIR}/res \
     -Dtest_failure.dir=${OUT_DIR}/${FAILURE_DIR} \
     -cp ${MISC_COMMON}/tools-common/tools-common-prebuilt.jar:${MISC_COMMON}/ninepatch/ninepatch-prebuilt.jar:${MISC_COMMON}/sdk-common/sdk-common.jar:${MISC_COMMON}/kxml2/kxml2-2.3.0.jar:${MISC_COMMON}/layoutlib_api/layoutlib_api-prebuilt.jar:${OUT_INTERMEDIATES}/prebuilts/tools/common/m2/trove-prebuilt/linux_glibc_common/combined/trove-prebuilt.jar:${OUT_INTERMEDIATES}/external/junit/junit/linux_glibc_common/javac/junit.jar:${OUT_INTERMEDIATES}/external/guava/guava-jre/linux_glibc_common/javac/guava-jre.jar:${OUT_INTERMEDIATES}/external/hamcrest/hamcrest-core/hamcrest/linux_glibc_common/javac/hamcrest.jar:${OUT_INTERMEDIATES}/external/mockito/mockito/linux_glibc_common/combined/mockito.jar:${OUT_INTERMEDIATES}/external/objenesis/objenesis/linux_glibc_common/javac/objenesis.jar:${OUT_INTERMEDIATES}/frameworks/layoutlib/bridge/layoutlib/linux_glibc_common/withres/layoutlib.jar:${OUT_INTERMEDIATES}/frameworks/layoutlib/temp_layoutlib/linux_glibc_common/gen/temp_layoutlib.jar:${OUT_INTERMEDIATES}/frameworks/layoutlib/bridge/tests/layoutlib-tests/linux_glibc_common/withres/layoutlib-tests.jar \
@@ -33,4 +59,8 @@
     mv ${OUT_DIR}/${FAILURE_ZIP} ${DIST_DIR}
 fi
 
+# Clean
+rm -rf ${TMP_DIR}
+rm -rf ${OUT_DIR}/${FAILURE_DIR}
+
 exit ${test_exit_code}
diff --git a/bridge/tests/run_tests_mac.sh b/bridge/tests/run_tests_mac.sh
new file mode 100755
index 0000000..4d67a61
--- /dev/null
+++ b/bridge/tests/run_tests_mac.sh
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+readonly OUT_DIR="$1"
+readonly DIST_DIR="$2"
+readonly BUILD_NUMBER="$3"
+
+readonly SCRIPT_DIR="$(dirname "$0")"
+
+readonly FAILURE_DIR=layoutlib-test-failures
+readonly FAILURE_ZIP=layoutlib-test-failures.zip
+
+STUDIO_JDK=${SCRIPT_DIR}"/../../../../prebuilts/jdk/jdk11/darwin-x86"
+MISC_COMMON=${SCRIPT_DIR}"/../../../../prebuilts/misc/common"
+OUT_INTERMEDIATES=${SCRIPT_DIR}"/../../../../out/soong/.intermediates"
+NATIVE_LIBRARIES=${SCRIPT_DIR}"/../../../../out/host/darwin-x86/lib64/"
+SDK=${SCRIPT_DIR}"/../../../../out/host/darwin-x86/sdk/sdk*/android-sdk*"
+FONT_DIR=${SCRIPT_DIR}"/../../../../out/host/common/obj/PACKAGING/fonts_intermediates"
+ICU_DIR=${SCRIPT_DIR}"/../../../../out/host/darwin-x86/com.android.i18n/etc/icu"
+TMP_DIR=$(mktemp -d -t tmp)
+PLATFORM=${TMP_DIR}/"android"
+
+# Copy resources to a temp directory
+cp -r ${SDK}/platforms/android* ${PLATFORM}
+
+# Compile 9-patch files
+mkdir ${TMP_DIR}/compiled
+mkdir ${TMP_DIR}/manifest
+echo \
+'<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.google.android.layoutlib" />' \
+> ${TMP_DIR}/manifest/AndroidManifest.xml
+for f in ${SDK}/platforms/android*/data/res/*
+do
+    find $f -name "*.9.png" -print0 | xargs -0 ${SDK}/build-tools/android-*/aapt2 compile -o ${TMP_DIR}/compiled/
+    find ${TMP_DIR}/compiled -name "*.flat" -print0 | xargs -0 ${SDK}/build-tools/android-*/aapt2 link -o ${TMP_DIR}/compiled.apk --manifest ${TMP_DIR}/manifest/AndroidManifest.xml -R
+    if [[ -f "${TMP_DIR}/compiled.apk" ]]; then
+        unzip -qo ${TMP_DIR}/compiled.apk -d ${TMP_DIR}
+        rm -r ${TMP_DIR}/compiled/*
+        rm ${TMP_DIR}/compiled.apk
+    fi
+done
+for f in ${TMP_DIR}/res/*; do mv "$f" "${f/-v4/}";done
+cp -RL ${TMP_DIR}/res ${PLATFORM}/data
+
+# Run layoutlib tests
+${STUDIO_JDK}/bin/java -ea \
+    -Dnative.lib.path=${NATIVE_LIBRARIES} \
+    -Dfont.dir=${FONT_DIR} \
+    -Dicu.dir=${ICU_DIR} \
+    -Dplatform.dir=${PLATFORM} \
+    -Dtest_res.dir=${SCRIPT_DIR}/res \
+    -Dtest_failure.dir=${OUT_DIR}/${FAILURE_DIR} \
+    -cp ${MISC_COMMON}/tools-common/tools-common-prebuilt.jar:${MISC_COMMON}/ninepatch/ninepatch-prebuilt.jar:${MISC_COMMON}/sdk-common/sdk-common.jar:${MISC_COMMON}/kxml2/kxml2-2.3.0.jar:${MISC_COMMON}/layoutlib_api/layoutlib_api-prebuilt.jar:${OUT_INTERMEDIATES}/prebuilts/tools/common/m2/trove-prebuilt/darwin_common/combined/trove-prebuilt.jar:${OUT_INTERMEDIATES}/external/junit/junit/darwin_common/javac/junit.jar:${OUT_INTERMEDIATES}/external/guava/guava-jre/darwin_common/javac/guava-jre.jar:${OUT_INTERMEDIATES}/external/hamcrest/hamcrest-core/hamcrest/darwin_common/javac/hamcrest.jar:${OUT_INTERMEDIATES}/external/mockito/mockito/darwin_common/combined/mockito.jar:${OUT_INTERMEDIATES}/external/objenesis/objenesis/darwin_common/javac/objenesis.jar:${OUT_INTERMEDIATES}/frameworks/layoutlib/bridge/layoutlib/darwin_common/withres/layoutlib.jar:${OUT_INTERMEDIATES}/frameworks/layoutlib/temp_layoutlib/darwin_common/gen/temp_layoutlib.jar:${OUT_INTERMEDIATES}/frameworks/layoutlib/bridge/tests/layoutlib-tests/darwin_common/withres/layoutlib-tests.jar \
+    org.junit.runner.JUnitCore \
+    com.android.layoutlib.bridge.intensive.Main
+
+test_exit_code=$?
+
+# Create zip of all failure screenshots
+if [[ -d "${OUT_DIR}/${FAILURE_DIR}" ]]; then
+    zip -q -j -r ${OUT_DIR}/${FAILURE_ZIP} ${OUT_DIR}/${FAILURE_DIR}
+fi
+
+# Move failure zip to dist directory if specified
+if [[ -d "${DIST_DIR}" ]] && [[ -e "${OUT_DIR}/${FAILURE_ZIP}" ]]; then
+    mv ${OUT_DIR}/${FAILURE_ZIP} ${DIST_DIR}
+fi
+
+# Clean
+rm -rf ${TMP_DIR}
+rm -rf ${OUT_DIR}/${FAILURE_DIR}
+
+exit ${test_exit_code}
diff --git a/bridge/tests/src/android/graphics/Color_DelegateTest.java b/bridge/tests/src/android/graphics/Color_DelegateTest.java
deleted file mode 100644
index 1b9c13e..0000000
--- a/bridge/tests/src/android/graphics/Color_DelegateTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.graphics;
-
-import junit.framework.TestCase;
-
-public class Color_DelegateTest extends TestCase {
-
-    public void testRGBToHSV() {
-        float[] hsv = new float[3];
-        Color_Delegate.nativeRGBToHSV(14, 203, 49, hsv);
-        assertTrue(131.1111 - hsv[0] < 0.001);
-        assertTrue(0.9310 - hsv[1] < 0.001);
-        assertTrue(0.7961 - hsv[2] < 0.001);
-    }
-
-    public void testHSVToColor() {
-        assertEquals(2077003642,
-                Color_Delegate.nativeHSVToColor(123, new float[]{15.0f, 0.4f, 0.8f}));
-        assertEquals(603979776,
-                Color_Delegate.nativeHSVToColor(36, new float[]{15.0f, 25.0f, -17.0f}));
-    }
-}
diff --git a/bridge/tests/src/android/graphics/Matrix_DelegateTest.java b/bridge/tests/src/android/graphics/Matrix_DelegateTest.java
deleted file mode 100644
index 0886132..0000000
--- a/bridge/tests/src/android/graphics/Matrix_DelegateTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2008 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.
- */
-
-package android.graphics;
-
-import java.util.Arrays;
-
-import junit.framework.TestCase;
-
-/**
- *
- */
-public class Matrix_DelegateTest extends TestCase {
-
-    public void testIdentity() {
-        Matrix m1 = new Matrix();
-
-        assertTrue(m1.isIdentity());
-
-        m1.setValues(new float[]{1, 0, 0, 0, 1, 0, 0, 0, 1});
-        assertTrue(m1.isIdentity());
-    }
-
-    public void testCopyConstructor() {
-        Matrix m1 = new Matrix();
-        Matrix m2 = new Matrix(m1);
-
-        float[] v1 = new float[9];
-        float[] v2 = new float[9];
-        m1.getValues(v1);
-        m2.getValues(v2);
-
-        for (int i = 0; i < 9; i++) {
-            assertEquals(v1[i], v2[i]);
-        }
-    }
-
-    public void testInvert() {
-        Matrix m1 = new Matrix();
-        Matrix inverse = new Matrix();
-        m1.setValues(new float[]{1, 2, 3, 4, 5, 6, 7, 8, 9});
-        assertFalse(m1.invert(inverse));
-
-        m1.setValues(new float[]{3, 5, 6, 2, 5, 7, 4, 8, 2});
-        m1.invert(inverse);
-        float[] values = new float[9];
-        inverse.getValues(values);
-
-        assertTrue(Arrays.equals(values,
-                new float[]{1.0952381f, -0.9047619f, -0.11904762f, -0.5714286f, 0.42857143f,
-                        0.21428572f, 0.0952381f, 0.0952381f, -0.11904762f}));
-    }
-}
diff --git a/bridge/tests/src/android/util/imagepool/ImagePoolHelperTest.java b/bridge/tests/src/android/util/imagepool/ImagePoolHelperTest.java
deleted file mode 100644
index 25aa466..0000000
--- a/bridge/tests/src/android/util/imagepool/ImagePoolHelperTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.util.imagepool;
-
-import org.junit.Test;
-
-import android.util.imagepool.Bucket.BucketCreationMetaData;
-import android.util.imagepool.ImagePool.Image.Orientation;
-
-import java.awt.image.BufferedImage;
-import java.lang.ref.SoftReference;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-public class ImagePoolHelperTest {
-
-    @Test
-    public void testGetBufferedImage() {
-        int width = 10;
-        int height = 10;
-        int numberOfCopiesInBucket = 10;
-        int maxCacheSize = width * height * 4 * 5; // can fit 5 width | height buffer
-        Bucket bucket = new Bucket();
-        BucketCreationMetaData metaData = new BucketCreationMetaData(
-                width, height, BufferedImage.TYPE_INT_ARGB, numberOfCopiesInBucket, Orientation
-                .NONE, maxCacheSize);
-        ImagePoolStats stats = new ImagePoolStatsProdImpl();
-
-        assertNotNull(ImagePoolHelper.getBufferedImage(bucket, metaData, stats));
-    }
-
-    @Test
-    public void testGetBufferedImageRecurse() {
-        int width = 10;
-        int height = 10;
-        int numberOfCopiesToRequestInBucket = 1;
-        int numberOfCopiesInBucket = 10;
-        int maxCacheSize = width * height * 4 * numberOfCopiesToRequestInBucket;
-
-        Bucket bucket = new Bucket();
-        for (int i = 0; i < numberOfCopiesInBucket; i++) {
-            bucket.mBufferedImageRef.add(new SoftReference<>(null));
-        }
-        BucketCreationMetaData metaData = new BucketCreationMetaData(
-                width, height, BufferedImage.TYPE_INT_ARGB, numberOfCopiesToRequestInBucket, Orientation
-                .NONE, maxCacheSize);
-        ImagePoolStats stats = new ImagePoolStatsProdImpl();
-
-        assertNotNull(ImagePoolHelper.getBufferedImage(bucket, metaData, stats));
-    }
-
-    @Test
-    public void testRecurseThenHitCacheLimit() {
-        int width = 10;
-        int height = 10;
-        int numberOfCopiesToRequestInBucket = 1;
-        int numberOfCopiesInBucket = 10;
-        int maxCacheSize = width * height * 4 * numberOfCopiesToRequestInBucket / 2;
-
-        Bucket bucket = new Bucket();
-        for (int i = 0; i < numberOfCopiesInBucket; i++) {
-            bucket.mBufferedImageRef.add(new SoftReference<>(null));
-        }
-        BucketCreationMetaData metaData = new BucketCreationMetaData(
-                width, height, BufferedImage.TYPE_INT_ARGB, numberOfCopiesToRequestInBucket, Orientation
-                .NONE, maxCacheSize);
-        ImagePoolStats stats = new ImagePoolStatsProdImpl();
-
-        assertNull(ImagePoolHelper.getBufferedImage(bucket, metaData, stats));
-    }
-
-    @Test
-    public void testBucketHasImageToReturn() {
-        int width = 10;
-        int height = 10;
-        int numberOfCopiesToRequestInBucket = 1;
-        int numberOfCopiesInBucket = 10;
-        int maxCacheSize = width * height * 4 * numberOfCopiesToRequestInBucket / 2;
-        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
-
-        Bucket bucket = new Bucket();
-        for (int i = 0; i < numberOfCopiesInBucket; i++) {
-            bucket.mBufferedImageRef.add(new SoftReference<>(null));
-        }
-        bucket.mBufferedImageRef.add(new SoftReference<>(image));
-        BucketCreationMetaData metaData = new BucketCreationMetaData(
-                width, height, BufferedImage.TYPE_INT_ARGB, numberOfCopiesToRequestInBucket, Orientation
-                .NONE, maxCacheSize);
-        ImagePoolStats stats = new ImagePoolStatsProdImpl();
-
-        assertNotNull(ImagePoolHelper.getBufferedImage(bucket, metaData, stats));
-    }
-}
\ No newline at end of file
diff --git a/bridge/tests/src/android/util/imagepool/ImagePoolImplTest.java b/bridge/tests/src/android/util/imagepool/ImagePoolImplTest.java
deleted file mode 100644
index 9761097..0000000
--- a/bridge/tests/src/android/util/imagepool/ImagePoolImplTest.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-
-package android.util.imagepool;
-
-import org.junit.Ignore;
-import org.junit.Test;
-
-import android.util.imagepool.ImagePool.Image;
-import android.util.imagepool.ImagePool.ImagePoolPolicy;
-
-import java.awt.image.BufferedImage;
-import java.lang.ref.SoftReference;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-public class ImagePoolImplTest {
-
-    private static final long TIMEOUT_SEC = 3;
-
-    @Test
-    public void testImagePoolInstance() {
-        ImagePool pool1 = ImagePoolProvider.get();
-        ImagePool pool2 = ImagePoolProvider.get();
-        assertNotNull(pool1);
-        assertNotNull(pool2);
-        assertEquals(pool1, pool2);
-    }
-
-
-    @Test
-    public void testImageDispose() throws InterruptedException {
-        int width = 700;
-        int height = 800;
-        int type = BufferedImage.TYPE_INT_ARGB;
-        CountDownLatch countDownLatch = new CountDownLatch(1);
-        ImagePoolImpl pool = getSimpleSingleBucketPool(width, height);
-        Image img1 = pool.acquire(width, height, type,
-                bufferedImage -> countDownLatch.countDown());
-        BufferedImage img = getImg(img1);
-        assertNotNull(img);
-        img1 = null;
-
-        // ensure dispose actually loses buffered image link so it can be gc'd
-        gc();
-        assertTrue(countDownLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS));
-    }
-    @Test
-    public void testImageDisposeFromFunction() throws InterruptedException {
-        int width = 700;
-        int height = 800;
-        int type = BufferedImage.TYPE_INT_ARGB;
-        CountDownLatch cd = new CountDownLatch(1);
-        ImagePoolImpl pool = getSimpleSingleBucketPool(width, height);
-
-        BufferedImage img = createImageAndReturnBufferedImage(pool, width, height, type, cd);
-        assertNotNull(img);
-
-        // ensure dispose actually loses buffered image link so it can be gc'd
-        gc();
-        assertTrue(cd.await(TIMEOUT_SEC, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void testImageDisposedAndRecycled() throws InterruptedException {
-        int width = 700;
-        int height = 800;
-        int bucketWidth = 800;
-        int bucketHeight = 800;
-        int variant = 1;
-        int type = BufferedImage.TYPE_INT_ARGB;
-        ImagePoolImpl pool = new ImagePoolImpl(new ImagePoolPolicy(
-                new int[]{bucketWidth, bucketHeight},
-                new int[]{1, 1},
-                bucketHeight * bucketWidth * 4 * 3));
-
-        // acquire first image and draw something.
-        BufferedImage bufferedImageForImg1;
-        final CountDownLatch countDownLatch1 = new CountDownLatch(1);
-        {
-            Image img1 = pool.acquire(width, height, type,
-                    bufferedImage -> countDownLatch1.countDown());
-            bufferedImageForImg1 = getImg(img1);
-            img1 = null; // this is still needed.
-        }
-        // dispose
-        gc();
-        assertTrue(countDownLatch1.await(TIMEOUT_SEC, TimeUnit.SECONDS));
-
-        // ensure dispose actually loses buffered image link so it can be gc'd
-        assertNotNull(bufferedImageForImg1);
-        assertEquals(bufferedImageForImg1.getWidth(), bucketWidth);
-        assertEquals(bufferedImageForImg1.getHeight(), bucketHeight);
-
-        // get 2nd image with the same spec
-        final CountDownLatch countDownLatch2 = new CountDownLatch(1);
-        BufferedImage bufferedImageForImg2;
-        {
-            Image img2 = pool.acquire(width - variant, height - variant, type,
-                    bufferedImage -> countDownLatch2.countDown());
-            bufferedImageForImg2 = getImg(img2);
-            assertEquals(bufferedImageForImg1, bufferedImageForImg2);
-            img2 = null;
-        }
-        // dispose
-        gc();
-        assertTrue(countDownLatch2.await(TIMEOUT_SEC, TimeUnit.SECONDS));
-
-        // ensure that we're recycling previously created buffered image.
-        assertNotNull(bufferedImageForImg1);
-        assertNotNull(bufferedImageForImg2);
-    }
-
-
-    @Test
-    public void testBufferedImageReleased() throws InterruptedException {
-        int width = 700;
-        int height = 800;
-        int bucketWidth = 800;
-        int bucketHeight = 800;
-        ImagePoolImpl pool = new ImagePoolImpl(new ImagePoolPolicy(
-                new int[]{bucketWidth, bucketHeight},
-                new int[]{1, 1},
-                bucketWidth * bucketWidth * 4 * 2));
-        CountDownLatch countDownLatch = new CountDownLatch(1);
-        Image image1 = pool.acquire(width, height, BufferedImage.TYPE_INT_ARGB,
-                bufferedImage -> countDownLatch.countDown());
-        BufferedImage internalPtr = getImg(image1);
-        // dispose
-        image1 = null;
-        gc();
-        assertTrue(countDownLatch.await(TIMEOUT_SEC, TimeUnit.SECONDS));
-
-        // Simulate BufferedBitmaps being gc'd. Bucket filled with null soft refs.
-        for (Bucket bucket : ((ImagePoolImpl) pool).mPool.values()) {
-            bucket.mBufferedImageRef.clear();
-            bucket.mBufferedImageRef.add(new SoftReference<>(null));
-            bucket.mBufferedImageRef.add(new SoftReference<>(null));
-        }
-
-        assertNotEquals(internalPtr,
-                getImg(pool.acquire(width, height, BufferedImage.TYPE_INT_ARGB)));
-    }
-
-    @Test
-    public void testPoolWidthHeightNotBigEnough() {
-        int width = 1000;
-        int height = 1000;
-        int bucketWidth = 999;
-        int bucketHeight = 800;
-        ImagePool pool = new ImagePoolImpl(
-                new ImagePoolPolicy(new int[]{bucketWidth, bucketHeight}, new int[]{1, 1},
-                        bucketWidth * bucketWidth * 4 * 2));
-        ImageImpl image = (ImageImpl) pool.acquire(width, height, BufferedImage.TYPE_INT_ARGB);
-
-        assertEquals(getTooBigForPoolCount(pool), 1);
-    }
-
-    @Test
-    public void testSizeNotBigEnough() {
-        int width = 500;
-        int height = 500;
-        int bucketWidth = 800;
-        int bucketHeight = 800;
-        ImagePoolImpl pool = new ImagePoolImpl(
-                new ImagePoolPolicy(new int[]{bucketWidth, bucketHeight}, new int[]{1, 1},
-                        bucketWidth * bucketWidth)); // cache not big enough.
-        ImageImpl image = (ImageImpl) pool.acquire(width, height, BufferedImage.TYPE_INT_ARGB);
-
-        assertEquals(getTooBigForPoolCount(pool), 1);
-        assertEquals(image.getWidth(), width);
-        assertEquals(image.getHeight(), height);
-    }
-
-    @Test
-    public void testImageMultipleCopies() throws InterruptedException {
-        int width = 700;
-        int height = 800;
-        int bucketWidth = 800;
-        int bucketHeight = 800;
-        int type = BufferedImage.TYPE_INT_ARGB;
-        ImagePoolImpl pool = new ImagePoolImpl(new ImagePoolPolicy(
-                new int[]{bucketWidth, bucketHeight},
-                new int[]{2, 2},
-                bucketHeight * bucketWidth * 4 * 4));
-
-        // create 1, and 2 different instances.
-        final CountDownLatch cd1 = new CountDownLatch(1);
-        Image img1 = pool.acquire(width, height, type, bufferedImage -> cd1.countDown());
-        BufferedImage bufferedImg1 = getImg(img1);
-
-        Image img2 = pool.acquire(width, height, type);
-        BufferedImage bufferedImg2 = getImg(img2);
-
-        assertNotEquals(bufferedImg1, bufferedImg2);
-
-        // disposing img1. Since # of copies == 2, this buffer should be recycled.
-        img1 = null;
-        gc();
-        cd1.await(TIMEOUT_SEC, TimeUnit.SECONDS);
-
-        // Ensure bufferedImg1 is recycled in newly acquired img3.
-        Image img3 = pool.acquire(width, height, type);
-        BufferedImage bufferedImage3 = getImg(img3);
-        assertNotEquals(bufferedImg2, bufferedImage3);
-        assertEquals(bufferedImg1, bufferedImage3);
-    }
-
-    @Ignore("b/132614809")
-    @Test
-    public void testPoolDispose() throws InterruptedException {
-        int width = 700;
-        int height = 800;
-        int bucketWidth = 800;
-        int bucketHeight = 800;
-        int type = BufferedImage.TYPE_INT_ARGB;
-
-        // Pool barely enough for 1 image.
-        ImagePoolImpl pool = new ImagePoolImpl(new ImagePoolPolicy(
-                new int[]{bucketWidth, bucketHeight},
-                new int[]{2, 2},
-                bucketHeight * bucketWidth * 4));
-
-        // create 1, and 2 different instances.
-        final CountDownLatch cd1 = new CountDownLatch(1);
-        Image img1 = pool.acquire(width, height, type, bufferedImage -> cd1.countDown());
-        BufferedImage bufferedImg1 = getImg(img1);
-        assertEquals(getAllocatedTotalBytes(pool), bucketWidth * bucketHeight * 4);
-        assertEquals(getTooBigForPoolCount(pool), 0);
-
-        // Release the img1.
-        img1 = null;
-        gc();
-        cd1.await(TIMEOUT_SEC, TimeUnit.SECONDS);
-
-        // Dispose pool.
-        pool.dispose();
-        assertEquals(getAllocatedTotalBytes(pool), 0);
-
-        // Request the same sized image as previous.
-        // If the pool was not disposed, this would return the image with bufferedImg1.
-        Image img2 = pool.acquire(width, height, type);
-        BufferedImage bufferedImg2 = getImg(img2);
-        assertEquals(getAllocatedTotalBytes(pool), bucketWidth * bucketHeight * 4);
-        assertEquals(getTooBigForPoolCount(pool), 0);
-
-        // Pool disposed before. No buffered image should be recycled.
-        assertNotEquals(img1, img2);
-        assertNotEquals(bufferedImg1, bufferedImg2);
-    }
-
-    private static BufferedImage createImageAndReturnBufferedImage(ImagePoolImpl pool, int width,
-            int height
-            , int type, CountDownLatch cd) {
-        Image img1 = pool.acquire(width, height, type, bufferedImage -> cd.countDown());
-        return getImg(img1);
-        // At this point img1 should have no reference, causing finalizable to trigger
-    }
-
-    private static ImagePoolImpl getSimpleSingleBucketPool(int width, int height) {
-
-        int bucketWidth = Math.max(width, height);
-        int bucketHeight = Math.max(width, height);
-        return new ImagePoolImpl(new ImagePoolPolicy(
-                new int[]{bucketWidth, bucketHeight},
-                new int[]{1, 1},
-                bucketHeight * bucketWidth * 4 * 3));
-    }
-
-    // Try to force a gc round
-    private static void gc() {
-        System.gc();
-        System.gc();
-        System.gc();
-    }
-
-    private static int getTooBigForPoolCount(ImagePool pool) {
-        return ((ImagePoolStatsProdImpl) ((ImagePoolImpl) pool).mImagePoolStats).mTooBigForPoolCount;
-    }
-
-    private static long getAllocatedTotalBytes(ImagePool pool) {
-        return ((ImagePoolStatsProdImpl) ((ImagePoolImpl) pool).mImagePoolStats).mAllocateTotalBytes;
-    }
-
-    private static BufferedImage getImg(Image image) {
-        return ((ImageImpl) image).mImg;
-    }
-}
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java b/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
index 8c69e3e..e763c8a 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
@@ -17,7 +17,8 @@
 package com.android.layoutlib.bridge;
 
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-import com.android.tools.layoutlib.create.CreateInfo;
+
+import com.android.tools.layoutlib.create.NativeConfig;
 
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -29,7 +30,7 @@
 /**
  * Tests that native delegate classes implement all the required methods.
  *
- * This looks at {@link CreateInfo#DELEGATE_CLASS_NATIVES} to get the list of classes that
+ * This looks at {@link NativeConfig#DELEGATE_CLASS_NATIVES} to get the list of classes that
  * have their native methods reimplemented through a delegate.
  *
  * Since the reimplemented methods are not native anymore, we look for the annotation
@@ -45,7 +46,7 @@
 
     public void testNativeDelegates() {
 
-        final String[] classes = CreateInfo.DELEGATE_CLASS_NATIVES;
+        final String[] classes = NativeConfig.DELEGATE_CLASS_NATIVES;
         mErrors.clear();
         for (String clazz : classes) {
             String targetClassName = clazz.replace('$', '_') + "_Delegate";
@@ -54,18 +55,18 @@
         assertTrue(getErrors(), mErrors.isEmpty());
     }
 
-    public void testMethodDelegates() {
-        final String[] methods = CreateInfo.DELEGATE_METHODS;
-        mErrors.clear();
-        for (String methodName : methods) {
-            // extract the class name
-            String className = methodName.substring(0, methodName.indexOf('#'));
-            String targetClassName = className.replace('$', '_') + "_Delegate";
-
-            loadAndCompareClasses(className, targetClassName);
-        }
-        assertTrue(getErrors(), mErrors.isEmpty());
-    }
+//    public void testMethodDelegates() {
+//        final String[] methods = CreateInfo.DELEGATE_METHODS;
+//        mErrors.clear();
+//        for (String methodName : methods) {
+//            // extract the class name
+//            String className = methodName.substring(0, methodName.indexOf('#'));
+//            String targetClassName = className.replace('$', '_') + "_Delegate";
+//
+//            loadAndCompareClasses(className, targetClassName);
+//        }
+//        assertTrue(getErrors(), mErrors.isEmpty());
+//    }
 
     private void loadAndCompareClasses(String originalClassName, String delegateClassName) {
         // load the classes
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/HighQualityShadowsRenderTests.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/HighQualityShadowsRenderTests.java
index 3582860..2763b67 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/HighQualityShadowsRenderTests.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/HighQualityShadowsRenderTests.java
@@ -44,9 +44,6 @@
                 .build();
 
         renderAndVerify(params, "shadows_test_high_quality.png");
-        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
-        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
-        sRenderMessages.removeIf(message -> message.equals("Font$Builder.nAddAxis is not supported."));
     }
 
     @Test
@@ -62,9 +59,6 @@
                 .build();
 
         renderAndVerify(params, "shadows_test_high_quality_rounded_edge.png");
-        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
-        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
-        sRenderMessages.removeIf(message -> message.equals("Font$Builder.nAddAxis is not supported."));
     }
 
     @Test
@@ -81,8 +75,6 @@
                 .build();
 
         renderAndVerify(params, "large_shadows_test_high_quality.png");
-        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
-        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
     }
 
     @Test
@@ -98,8 +90,6 @@
                 .build();
 
         renderAndVerify(params, "shadow_sizes_test_high_quality.png");
-        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
-        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
     }
 
     @Test
@@ -114,8 +104,5 @@
                 .build();
 
         renderAndVerify(params, "shadow_scrollview_test_high_quality.png");
-        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
-        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
-        sRenderMessages.removeIf(message -> message.equals("Font$Builder.nAddAxis is not supported."));
     }
 }
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index be57b88..5a5f1d1 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -31,11 +31,7 @@
 
 import android.content.res.BridgeTypedArrayTest;
 import android.content.res.Resources_DelegateTest;
-import android.graphics.Color_DelegateTest;
-import android.graphics.Matrix_DelegateTest;
 import android.util.BridgeXmlPullAttributesTest;
-import android.util.imagepool.ImagePoolHelperTest;
-import android.util.imagepool.ImagePoolImplTest;
 
 /**
  * Suite used by the layoutlib build system
@@ -44,10 +40,8 @@
 @SuiteClasses({
         RenderTests.class, LayoutParserWrapperTest.class,
         BridgeXmlBlockParserTest.class, BridgeXmlPullAttributesTest.class,
-        Matrix_DelegateTest.class, TestDelegates.class,
-        BridgeRenderSessionTest.class, ResourceHelperTest.class, BridgeContextTest.class,
-        Resources_DelegateTest.class, Color_DelegateTest.class, ImagePoolHelperTest.class,
-        ImagePoolImplTest.class, HighQualityShadowsRenderTests.class,
+        TestDelegates.class, BridgeRenderSessionTest.class, ResourceHelperTest.class,
+        BridgeContextTest.class, Resources_DelegateTest.class, HighQualityShadowsRenderTests.class,
         LayoutValidatorTests.class, AccessibilityValidatorTests.class, BridgeTypedArrayTest.class
 })
 public class Main {
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
index 67bb7af..6875555 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
@@ -27,7 +27,6 @@
 import com.android.ide.common.resources.deprecated.TestFolderWrapper;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.RenderParamsFlags;
-import com.android.layoutlib.bridge.impl.DelegateManager;
 import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
 import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
 import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
@@ -35,7 +34,6 @@
 import com.android.layoutlib.bridge.intensive.util.ModuleClassLoader;
 import com.android.layoutlib.bridge.intensive.util.SessionParamsBuilder;
 import com.android.layoutlib.bridge.intensive.util.TestAssetRepository;
-import com.android.layoutlib.bridge.intensive.util.TestUtils;
 import com.android.tools.layoutlib.java.System_Delegate;
 import com.android.utils.ILogger;
 
@@ -48,6 +46,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.Handler_Delegate;
+import android.view.Choreographer;
 
 import java.awt.image.BufferedImage;
 import java.io.File;
@@ -56,10 +56,10 @@
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Locale;
 import java.util.concurrent.TimeUnit;
 
 import com.google.android.collect.Lists;
-import com.google.common.collect.ImmutableMap;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.fail;
@@ -99,9 +99,16 @@
          */
         void beforeDisposed(RenderSession session);
     }
+
+    private static final String NATIVE_LIB_PATH_PROPERTY = "native.lib.path";
+    private static final String FONT_DIR_PROPERTY = "font.dir";
+    private static final String ICU_DIR_PROPERTY = "icu.dir";
     private static final String PLATFORM_DIR_PROPERTY = "platform.dir";
     private static final String RESOURCE_DIR_PROPERTY = "test_res.dir";
 
+    private static final String NATIVE_LIB_DIR_PATH;
+    private static final String FONT_DIR;
+    private static final String ICU_DIR;
     protected static final String PLATFORM_DIR;
     private static final String TEST_RES_DIR;
     /** Location of the app to test inside {@link #TEST_RES_DIR} */
@@ -128,6 +135,10 @@
                     PLATFORM_DIR_PROPERTY, System.getProperty(PLATFORM_DIR_PROPERTY)));
         }
 
+        NATIVE_LIB_DIR_PATH = getNativeLibDirPath();
+        FONT_DIR = getFontDir();
+        ICU_DIR = getIcuDir();
+
         TEST_RES_DIR = getTestResDir();
         if (TEST_RES_DIR == null) {
             fail(String.format("System property %1$s.dir not properly set. The value is %2$s",
@@ -147,8 +158,59 @@
         }
     };
 
+    @Rule
+    public TestWatcher sMemoryLeakChecker = new TestWatcher() {
+        @Override
+        protected void succeeded(Description description) {
+            if (!Handler_Delegate.sRunnablesQueues.isEmpty()) {
+                fail("Memory leak: leftover callbacks are detected in Handler_Delegate");
+            }
+            for (int i = Choreographer.CALLBACK_INPUT; i <= Choreographer.CALLBACK_COMMIT; ++i) {
+                if (Choreographer.getInstance().mCallbackQueues[i].mHead != null) {
+                    fail("Memory leak: leftover frame callbacks are detected in Choreographer");
+                }
+            }
+        }
+    };
+
     protected ClassLoader mDefaultClassLoader;
 
+    private static String getNativeLibDirPath() {
+        String nativeLibDirPath = System.getProperty(NATIVE_LIB_PATH_PROPERTY);
+        if (nativeLibDirPath != null) {
+            File nativeLibDir = new File(nativeLibDirPath);
+            if (nativeLibDir.isDirectory()) {
+                nativeLibDirPath = nativeLibDir.getAbsolutePath();
+            } else {
+                nativeLibDirPath = null;
+            }
+        }
+        if (nativeLibDirPath == null) {
+            nativeLibDirPath = PLATFORM_DIR + "/../../../../../lib64/";
+        }
+        return nativeLibDirPath;
+    }
+
+    private static String getFontDir() {
+        String fontDir = System.getProperty(FONT_DIR_PROPERTY);
+        if (fontDir == null) {
+            // The fonts are built into out/host/common/obj/PACKAGING/fonts_intermediates
+            // as specified in build/make/core/layoutlib_fonts.mk, and PLATFORM_DIR is
+            // out/host/[arch]/sdk/sdk*/android-sdk*/platforms/android*
+            fontDir = PLATFORM_DIR +
+                    "/../../../../../../common/obj/PACKAGING/fonts_intermediates";
+        }
+        return fontDir;
+    }
+
+    private static String getIcuDir() {
+        String icuDir = System.getProperty(ICU_DIR_PROPERTY);
+        if (icuDir == null) {
+            icuDir = PLATFORM_DIR + "/../../../../../com.android.i18n/etc/icu";
+        }
+        return icuDir;
+    }
+
     private static String getPlatformDir() {
         String platformDir = System.getProperty(PLATFORM_DIR_PROPERTY);
         if (platformDir != null && !platformDir.isEmpty() && new File(platformDir).isDirectory()) {
@@ -318,15 +380,12 @@
                 };
         sProjectResources.loadResources();
 
-        // The fonts are built into out/host/common/obj/PACKAGING/sdk-fonts_intermediates as specified in
-        // build/make/core/sdk_font.mk, and PLATFORM_DIR is out/host/[arch]/sdk/sdk*/android-sdk*/platforms/android*
-        File fontLocation = new File(PLATFORM_DIR,
-                "../../../../../../common/obj/PACKAGING/sdk-fonts_intermediates");
+        File fontLocation = new File(FONT_DIR);
         File buildProp = new File(PLATFORM_DIR, "build.prop");
         File attrs = new File(res, "values" + File.separator + "attrs.xml");
         sBridge = new Bridge();
-        sBridge.init(ConfigGenerator.loadProperties(buildProp), fontLocation, null, null,
-                ConfigGenerator.getEnumMap(attrs), getLayoutLog());
+        sBridge.init(ConfigGenerator.loadProperties(buildProp), fontLocation, NATIVE_LIB_DIR_PATH,
+                ICU_DIR, ConfigGenerator.getEnumMap(attrs), getLayoutLog());
         Bridge.getLock().lock();
         try {
             Bridge.setLog(getLayoutLog());
@@ -342,11 +401,6 @@
         sProjectResources = null;
         sLogger = null;
         sBridge = null;
-
-        TestUtils.gc();
-
-        System.out.println("Objects still linked from the DelegateManager:");
-        DelegateManager.dump(System.out);
     }
 
     @NonNull
@@ -399,7 +453,14 @@
      */
     protected static void verify(@NonNull String goldenImageName, @NonNull BufferedImage image) {
         try {
-            String goldenImagePath = APP_TEST_DIR + "/golden/" + goldenImageName;
+            boolean isMac = System.getProperty("os.name").toLowerCase(Locale.US).contains("mac");
+            String goldenImagePath = APP_TEST_DIR;
+            if (isMac) {
+                goldenImagePath += "/golden-mac/";
+            } else {
+                goldenImagePath += "/golden/";
+            }
+            goldenImagePath += goldenImageName;
             ImageUtils.requireSimilar(goldenImagePath, image);
         } catch (IOException e) {
             getLogger().error(e, e.getMessage());
@@ -430,14 +491,15 @@
     @Nullable
     protected static RenderResult renderAndVerify(SessionParams params, String goldenFileName)
             throws ClassNotFoundException {
-        return RenderTestBase.renderAndVerify(params, goldenFileName, -1);
+        return RenderTestBase.renderAndVerify(params, goldenFileName, TimeUnit.SECONDS.toNanos(2));
     }
 
     protected static ILayoutLog getLayoutLog() {
         if (sLayoutLibLog == null) {
             sLayoutLibLog = new ILayoutLog() {
                 @Override
-                public void warning(String tag, String message, Object cookie, Object data) {
+                public void warning(@Nullable String tag, @NonNull String message, @Nullable Object viewCookie,
+                        @Nullable Object data) {
                     System.out.println("Warning " + tag + ": " + message);
                     failWithMsg(message);
                 }
@@ -454,20 +516,26 @@
                 }
 
                 @Override
-                public void error(String tag, String message, Object cookie, Object data) {
+                public void error(@Nullable String tag, @NonNull String message, @Nullable Object viewCookie,
+                        @Nullable Object data) {
                     System.out.println("Error " + tag + ": " + message);
                     failWithMsg(message);
                 }
 
                 @Override
-                public void error(String tag, String message, Throwable throwable, Object cookie,
-                        Object data) {
+                public void error(@Nullable String tag, @NonNull String message, @Nullable Throwable throwable,
+                        @Nullable Object viewCookie, @Nullable Object data) {
                     System.out.println("Error " + tag + ": " + message);
                     if (throwable != null) {
                         throwable.printStackTrace();
                     }
                     failWithMsg(message);
                 }
+
+                @Override
+                public void logAndroidFramework(int priority, String tag, String message) {
+                    System.out.println("Android framework message " + tag + ": " + message);
+                }
             };
         }
         return sLayoutLibLog;
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
index 303c247..c39f9db 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
@@ -20,6 +20,7 @@
 import com.android.ide.common.rendering.api.ResourceNamespace;
 import com.android.ide.common.rendering.api.ResourceReference;
 import com.android.ide.common.rendering.api.ResourceValueImpl;
+import com.android.ide.common.rendering.api.Result;
 import com.android.ide.common.rendering.api.SessionParams;
 import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
 import com.android.ide.common.rendering.api.ViewInfo;
@@ -34,11 +35,15 @@
 import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
 import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
 import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
+import com.android.ninepatch.NinePatch;
 import com.android.resources.Density;
 import com.android.resources.Navigation;
 import com.android.resources.ResourceType;
+import com.android.tools.layoutlib.java.System_Delegate;
 
 import org.junit.After;
+import org.junit.Assert;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
@@ -51,10 +56,14 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.Resources_Delegate;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Color;
 import android.util.DisplayMetrics;
 import android.util.StateSet;
 import android.util.TypedValue;
+import android.widget.Button;
+import android.widget.LinearLayout;
 
 import java.awt.BasicStroke;
 import java.awt.Graphics2D;
@@ -62,6 +71,8 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.lang.reflect.Field;
 import java.util.concurrent.TimeUnit;
@@ -165,18 +176,11 @@
                 .build();
 
         renderAndVerify(params, "allwidgets.png");
-
-        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
-        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
     }
 
     @Test
     public void testArrayCheck() throws ClassNotFoundException, FileNotFoundException {
         renderAndVerify("array_check.xml", "array_check.png", false);
-
-        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
-        sRenderMessages.removeIf(
-                message -> message.equals("Font$Builder.nAddAxis is not supported."));
     }
 
     @Test
@@ -192,10 +196,6 @@
                 .disableShadows()
                 .build();
         renderAndVerify(params, "allwidgets_tab.png");
-
-        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
-        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
-        sRenderMessages.removeIf(message -> message.equals("Font$Builder.nAddAxis is not supported."));
     }
 
     @Test
@@ -545,9 +545,39 @@
     }
 
     /**
+     * Test a vector drawable which is transparent.
+     */
+    @Test
+    public void testTransparentDrawable() throws ClassNotFoundException {
+        // Create the layout pull parser.
+        LayoutPullParser parser = LayoutPullParser.createFromString(
+                "<ImageView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+                        "    android:layout_height=\"fill_parent\"\n" +
+                        "    android:layout_width=\"fill_parent\"\n" +
+                        "    android:src=\"@drawable/transparent_drawable\" />");
+        // Create LayoutLibCallback.
+        LayoutLibTestCallback layoutLibCallback =
+                new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+        layoutLibCallback.initResources();
+
+        SessionParams params = getSessionParamsBuilder()
+                .setParser(parser)
+                .setCallback(layoutLibCallback)
+                .setTheme("Theme.Material.Light.NoActionBar.Fullscreen", false)
+                .setRenderingMode(RenderingMode.V_SCROLL)
+                .disableDecoration()
+                .setTransparentBackground()
+                .build();
+
+        renderAndVerify(params, "transparent_drawable.png",
+                TimeUnit.SECONDS.toNanos(2));
+    }
+
+    /**
      * Test a vector drawable that uses trimStart and trimEnd. It also tests all the primitives
      * for vector drawables (lines, moves and cubic and quadratic curves).
      */
+    @Ignore("This test does not make sense in layoutlib anymore, test in Studio")
     @Test
     public void testVectorDrawableHasMultipleLineInPathData() throws ClassNotFoundException {
         // Create the layout pull parser.
@@ -764,6 +794,7 @@
         assertEquals(90, rootLayout.getChildren().get(5).getChildren().get(0).getLeft());
         assertEquals(-270, rootLayout.getChildren().get(5).getChildren().get(0).getBottom());
         assertEquals(690, rootLayout.getChildren().get(5).getChildren().get(0).getRight());
+        session.dispose();
 
         // Do a full render pass
         parser = createParserFromPath("scrolled.xml");
@@ -870,8 +901,6 @@
     public void testFonts() throws ClassNotFoundException, FileNotFoundException {
         // TODO: styles seem to be broken in TextView
         renderAndVerify("fonts_test.xml", "font_test.png", false);
-        sRenderMessages.removeIf(
-                message -> message.equals("Font$Builder.nAddAxis is not supported."));
     }
 
     @Test
@@ -1102,8 +1131,6 @@
                 .build();
 
         renderAndVerify(params, "shadows_test_no_shadow.png");
-        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
-        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
     }
 
     @Test
@@ -1121,8 +1148,6 @@
                 .build();
 
         renderAndVerify(params, "shadows_test.png");
-        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
-        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
     }
 
     @Test
@@ -1186,7 +1211,12 @@
      */
     @Test
     public void test9PatchNoDPIBackground() throws Exception {
-        String layout =
+        // Create LayoutLibCallback.
+        LayoutLibTestCallback layoutLibCallback =
+                new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+        layoutLibCallback.initResources();
+
+        String layoutCompiled =
                 "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
                         "    android:layout_width=\"match_parent\"\n" +
                         "    android:layout_height=\"match_parent\"\n" +
@@ -1203,12 +1233,7 @@
                         "        android:text=\"Button\" />\n"
                         + "</LinearLayout>";
 
-        LayoutPullParser parser = LayoutPullParser.createFromString(layout);
-        // Create LayoutLibCallback.
-        LayoutLibTestCallback layoutLibCallback =
-                new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
-        layoutLibCallback.initResources();
-
+        LayoutPullParser parser = LayoutPullParser.createFromString(layoutCompiled);
         SessionParams params = getSessionParamsBuilder()
                 .setParser(parser)
                 .setCallback(layoutLibCallback)
@@ -1217,6 +1242,33 @@
                 .build();
 
         renderAndVerify(params, "ninepatch_background.png");
+
+        String layoutNonCompiled =
+                "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+                        "    android:layout_width=\"match_parent\"\n" +
+                        "    android:layout_height=\"match_parent\"\n" +
+                        "    android:background=\"@drawable/uncompiled_ninepatch\"\n" +
+                        "    android:layout_margin=\"20dp\"\n" +
+                        "    android:orientation=\"vertical\">\n\n" +
+                        "    <Button\n" +
+                        "        android:layout_width=\"wrap_content\"\n" +
+                        "        android:layout_height=\"wrap_content\"\n" +
+                        "        android:text=\"Button\" />\n\n" +
+                        "    <Button\n" +
+                        "        android:layout_width=\"wrap_content\"\n" +
+                        "        android:layout_height=\"wrap_content\"\n" +
+                        "        android:text=\"Button\" />\n"
+                        + "</LinearLayout>";
+
+        parser = LayoutPullParser.createFromString(layoutNonCompiled);
+        params = getSessionParamsBuilder()
+                .setParser(parser)
+                .setCallback(layoutLibCallback)
+                .setTheme("Theme.Material.NoActionBar.Fullscreen", false)
+                .setRenderingMode(RenderingMode.V_SCROLL)
+                .build();
+
+        renderAndVerify(params, "ninepatch_background.png");
     }
 
     @Test
@@ -1638,6 +1690,12 @@
     }
 
     @Test
+    public void testJustified() throws ClassNotFoundException, FileNotFoundException {
+        renderAndVerify("justified_inter_word.xml", "justified_inter_word.png", false);
+        renderAndVerify("justified_none.xml", "justified_none.png", false);
+    }
+
+    @Test
     public void testManyLineBreaks() throws Exception {
         String layout =
                 "<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
@@ -1692,9 +1750,46 @@
                 .build();
 
         renderAndVerify(params, "shadow_scrollview_test_high_quality.png");
-        // We expect fidelity warnings for Path.isConvex. Fail for anything else.
-        sRenderMessages.removeIf(message -> message.equals("Path.isConvex is not supported."));
-        sRenderMessages.removeIf(message -> message.equals("Font$Builder.nAddAxis is not supported."));
+    }
+
+    @Test
+    public void testNinePatchChunk() throws IOException {
+        InputStream compiled =
+                getClass().getResourceAsStream("/com/android/layoutlib/testdata/compiled.9.png");
+        Bitmap compiledBitmap = BitmapFactory.decodeStream(compiled, null, null);
+
+        InputStream nonCompiled = getClass().getResourceAsStream(
+                "/com/android/layoutlib/testdata/non_compiled.9.png");
+        NinePatch ninePatch = NinePatch.load(nonCompiled, true, false);
+
+        Assert.assertArrayEquals(compiledBitmap.getNinePatchChunk(), ninePatch.getChunk().getSerializedChunk());
+    }
+
+    @Test
+    public void testNinePatchDrawable() throws Exception {
+        String layout =
+                "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+                        "              android:padding=\"16dp\"\n" +
+                        "              android:orientation=\"horizontal\"\n" +
+                        "              android:layout_width=\"fill_parent\"\n" +
+                        "              android:layout_height=\"fill_parent\">\n" +
+                        "    <ImageView\n" +
+                        "             android:layout_height=\"fill_parent\"\n" +
+                        "             android:layout_width=\"fill_parent\"\n" +
+                        "             android:src=\"@drawable/ninepatch_drawable\" />\n" +
+                        "</LinearLayout>\n";
+        LayoutPullParser parser = LayoutPullParser.createFromString(layout);
+        // Create LayoutLibCallback.
+        LayoutLibTestCallback layoutLibCallback =
+                new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+        layoutLibCallback.initResources();
+        SessionParams params = getSessionParamsBuilder()
+                .setParser(parser)
+                .setCallback(layoutLibCallback)
+                .disableDecoration()
+                .build();
+
+        renderAndVerify(params, "ninepatch_drawable.png");
     }
 
     @Test
@@ -1776,4 +1871,76 @@
 
         renderAndVerify(params, "textclock.png");
     }
+
+    @Test
+    public void testChangeSize() throws ClassNotFoundException {
+        final String layout =
+                "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+                        "              android:orientation=\"vertical\"\n" +
+                        "              android:layout_width=\"wrap_content\"\n" +
+                        "              android:layout_height=\"wrap_content\">\n" +
+                        "    <Button\n" +
+                        "             android:layout_height=\"50dp\"\n" +
+                        "             android:layout_width=\"100dp\"\n" +
+                        "             android:text=\"Hello\" />\n" +
+                        "</LinearLayout>\n";
+
+        // Create the layout pull parser.
+        LayoutPullParser parser = LayoutPullParser.createFromString(layout);
+        // Create LayoutLibCallback.
+        LayoutLibTestCallback layoutLibCallback = new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+        layoutLibCallback.initResources();
+
+        SessionParams params = getSessionParamsBuilder()
+                .setParser(parser)
+                .setCallback(layoutLibCallback)
+                .setRenderingMode(RenderingMode.SHRINK)
+                .disableDecoration()
+                .build();
+
+        System_Delegate.setBootTimeNanos(TimeUnit.MILLISECONDS.toNanos(871732800000L));
+        System_Delegate.setNanosTime(TimeUnit.MILLISECONDS.toNanos(871732800000L));
+        RenderSession session = sBridge.createSession(params);
+
+        try {
+            session.setElapsedFrameTimeNanos(TimeUnit.SECONDS.toNanos(2));
+
+            if (!session.getResult().isSuccess()) {
+                getLogger().error(session.getResult().getException(),
+                        session.getResult().getErrorMessage());
+            }
+            else {
+                // Render the session with a timeout of 50s.
+                Result renderResult = session.render(50000);
+                if (!renderResult.isSuccess()) {
+                    getLogger().error(session.getResult().getException(),
+                            session.getResult().getErrorMessage());
+                }
+            }
+
+            BufferedImage resultImage = session.getImage();
+
+            assertNotNull(resultImage);
+            verify("button_resize.png", resultImage);
+
+            Object viewObject = session.getRootViews().get(0)
+                    .getChildren().get(0).getViewObject();
+
+            Button btn = (Button) viewObject;
+            btn.setLayoutParams(new LinearLayout.LayoutParams(300, 300));
+
+            Result renderResult = session.render(50000);
+            if (!renderResult.isSuccess()) {
+                getLogger().error(session.getResult().getException(),
+                        session.getResult().getErrorMessage());
+            }
+
+            resultImage = session.getImage();
+
+            assertNotNull(resultImage);
+            verify("button_resize2.png", resultImage);
+        } finally {
+            session.dispose();
+        }
+    }
 }
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java
index b1801c6..a8adf95 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ImageUtils.java
@@ -18,10 +18,8 @@
 
 import android.annotation.NonNull;
 
-import java.awt.AlphaComposite;
 import java.awt.Color;
 import java.awt.Graphics;
-import java.awt.Graphics2D;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
@@ -29,7 +27,6 @@
 
 import javax.imageio.ImageIO;
 
-import static java.awt.RenderingHints.*;
 import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
 import static java.io.File.separatorChar;
 import static org.junit.Assert.assertEquals;
@@ -47,28 +44,22 @@
  */
 public class ImageUtils {
     /**
-     * Normally, this test will fail when there is a missing thumbnail. However, when
+     * Normally, this test will fail when there is a missing golden image. However, when
      * you create creating a new test, it's useful to be able to turn this off such that
-     * you can generate all the missing thumbnails in one go, rather than having to run
-     * the test repeatedly to get to each new render assertion generating its thumbnail.
+     * you can generate all the missing golden images in one go, rather than having to run
+     * the test repeatedly to get to each new render assertion generating its golden images.
      */
-    private static final boolean FAIL_ON_MISSING_THUMBNAIL = true;
-
-    private static final int THUMBNAIL_SIZE = 1000;
+    private static final boolean FAIL_ON_MISSING_GOLDEN = true;
 
     private static final double MAX_PERCENT_DIFFERENCE = 0.1;
 
     public static void requireSimilar(@NonNull String relativePath, @NonNull BufferedImage image)
             throws IOException {
-        int maxDimension = Math.max(image.getWidth(), image.getHeight());
-        double scale = THUMBNAIL_SIZE / (double)maxDimension;
-        BufferedImage thumbnail = scale(image, scale, scale);
-
         InputStream is = ImageUtils.class.getClassLoader().getResourceAsStream(relativePath);
         if (is == null) {
-            String message = "Unable to load golden thumbnail: " + relativePath + "\n";
-            message = saveImageAndAppendMessage(thumbnail, message, relativePath);
-            if (FAIL_ON_MISSING_THUMBNAIL) {
+            String message = "Unable to load golden image: " + relativePath + "\n";
+            message = saveImageAndAppendMessage(image, message, relativePath);
+            if (FAIL_ON_MISSING_GOLDEN) {
                 fail(message);
             } else {
                 System.out.println(message);
@@ -77,7 +68,7 @@
         else {
             try {
                 BufferedImage goldenImage = ImageIO.read(is);
-                assertImageSimilar(relativePath, goldenImage, thumbnail, MAX_PERCENT_DIFFERENCE);
+                assertImageSimilar(relativePath, goldenImage, image, MAX_PERCENT_DIFFERENCE);
             } finally {
                 is.close();
             }
@@ -192,114 +183,7 @@
     }
 
     /**
-     * Resize the given image
-     *
-     * @param source the image to be scaled
-     * @param xScale x scale
-     * @param yScale y scale
-     * @return the scaled image
-     */
-    @NonNull
-    public static BufferedImage scale(@NonNull BufferedImage source, double xScale, double yScale) {
-
-        int sourceWidth = source.getWidth();
-        int sourceHeight = source.getHeight();
-        int destWidth = Math.max(1, (int) (xScale * sourceWidth));
-        int destHeight = Math.max(1, (int) (yScale * sourceHeight));
-        int imageType = source.getType();
-        if (imageType == BufferedImage.TYPE_CUSTOM) {
-            imageType = BufferedImage.TYPE_INT_ARGB;
-        }
-        if (xScale > 0.5 && yScale > 0.5) {
-            BufferedImage scaled =
-                    new BufferedImage(destWidth, destHeight, imageType);
-            Graphics2D g2 = scaled.createGraphics();
-            g2.setComposite(AlphaComposite.Src);
-            g2.setColor(new Color(0, true));
-            g2.fillRect(0, 0, destWidth, destHeight);
-            if (xScale == 1 && yScale == 1) {
-                g2.drawImage(source, 0, 0, null);
-            } else {
-                setRenderingHints(g2);
-                g2.drawImage(source, 0, 0, destWidth, destHeight, 0, 0, sourceWidth, sourceHeight,
-                        null);
-            }
-            g2.dispose();
-            return scaled;
-        } else {
-            // When creating a thumbnail, using the above code doesn't work very well;
-            // you get some visible artifacts, especially for text. Instead use the
-            // technique of repeatedly scaling the image into half; this will cause
-            // proper averaging of neighboring pixels, and will typically (for the kinds
-            // of screen sizes used by this utility method in the layout editor) take
-            // about 3-4 iterations to get the result since we are logarithmically reducing
-            // the size. Besides, each successive pass in operating on much fewer pixels
-            // (a reduction of 4 in each pass).
-            //
-            // However, we may not be resizing to a size that can be reached exactly by
-            // successively diving in half. Therefore, once we're within a factor of 2 of
-            // the final size, we can do a resize to the exact target size.
-            // However, we can get even better results if we perform this final resize
-            // up front. Let's say we're going from width 1000 to a destination width of 85.
-            // The first approach would cause a resize from 1000 to 500 to 250 to 125, and
-            // then a resize from 125 to 85. That last resize can distort/blur a lot.
-            // Instead, we can start with the destination width, 85, and double it
-            // successfully until we're close to the initial size: 85, then 170,
-            // then 340, and finally 680. (The next one, 1360, is larger than 1000).
-            // So, now we *start* the thumbnail operation by resizing from width 1000 to
-            // width 680, which will preserve a lot of visual details such as text.
-            // Then we can successively resize the image in half, 680 to 340 to 170 to 85.
-            // We end up with the expected final size, but we've been doing an exact
-            // divide-in-half resizing operation at the end so there is less distortion.
-
-            int iterations = 0; // Number of halving operations to perform after the initial resize
-            int nearestWidth = destWidth; // Width closest to source width that = 2^x, x is integer
-            int nearestHeight = destHeight;
-            while (nearestWidth < sourceWidth / 2) {
-                nearestWidth *= 2;
-                nearestHeight *= 2;
-                iterations++;
-            }
-
-            BufferedImage scaled = new BufferedImage(nearestWidth, nearestHeight, imageType);
-
-            Graphics2D g2 = scaled.createGraphics();
-            setRenderingHints(g2);
-            g2.drawImage(source, 0, 0, nearestWidth, nearestHeight, 0, 0, sourceWidth, sourceHeight,
-                    null);
-            g2.dispose();
-
-            sourceWidth = nearestWidth;
-            sourceHeight = nearestHeight;
-            source = scaled;
-
-            for (int iteration = iterations - 1; iteration >= 0; iteration--) {
-                int halfWidth = sourceWidth / 2;
-                int halfHeight = sourceHeight / 2;
-                scaled = new BufferedImage(halfWidth, halfHeight, imageType);
-                g2 = scaled.createGraphics();
-                setRenderingHints(g2);
-                g2.drawImage(source, 0, 0, halfWidth, halfHeight, 0, 0, sourceWidth, sourceHeight,
-                        null);
-                g2.dispose();
-
-                sourceWidth = halfWidth;
-                sourceHeight = halfHeight;
-                source = scaled;
-                iterations--;
-            }
-            return scaled;
-        }
-    }
-
-    private static void setRenderingHints(@NonNull Graphics2D g2) {
-        g2.setRenderingHint(KEY_INTERPOLATION,VALUE_INTERPOLATION_BILINEAR);
-        g2.setRenderingHint(KEY_RENDERING, VALUE_RENDER_QUALITY);
-        g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
-    }
-
-    /**
-     * Directory where to write the thumbnails and deltas.
+     * Directory where to write the generated image and deltas.
      */
     @NonNull
     private static File getFailureDir() {
@@ -318,7 +202,7 @@
     }
 
     /**
-     * Saves the generated thumbnail image and appends the info message to an initial message
+     * Saves the generated golden image and appends the info message to an initial message
      */
     @NonNull
     private static String saveImageAndAppendMessage(@NonNull BufferedImage image,
@@ -329,7 +213,7 @@
             assertTrue(deleted);
         }
         ImageIO.write(image, "PNG", output);
-        initialMessage += "Thumbnail for current rendering stored at " + output.getPath();
+        initialMessage += "Golden image for current rendering stored at " + output.getPath();
 //        initialMessage += "\nRun the following command to accept the changes:\n";
 //        initialMessage += String.format("mv %1$s %2$s", output.getPath(),
 //                ImageUtils.class.getResource(relativePath).getPath());
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ModuleClassLoader.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ModuleClassLoader.java
index da360f3..d52fdcf 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ModuleClassLoader.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/ModuleClassLoader.java
@@ -17,6 +17,7 @@
 package com.android.layoutlib.bridge.intensive.util;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -49,7 +50,11 @@
         if (clazz == null) {
             String path = name.replace('.', '/').concat(".class");
             try {
-                byte[] b = Streams.readFully(getResourceAsStream(myModuleRoot + path));
+                InputStream classStream = getResourceAsStream(myModuleRoot + path);
+                if (classStream == null) {
+                    throw new IOException("Cannot find resource stream for class " + name);
+                }
+                byte[] b = Streams.readFully(classStream);
                 clazz = defineClass(name, b, 0, b.length);
                 mClasses.put(name, clazz);
             } catch (IOException ignore) {
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java
index 396880e..ccb76bb 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java
@@ -65,6 +65,7 @@
     private boolean highQualityShadows = true;
     private boolean enableLayoutValidator = false;
     private boolean enableLayoutValidatorImageCheck = false;
+    private boolean transparentBackground = false;
 
     @NonNull
     public SessionParamsBuilder setParser(@NonNull LayoutPullParser layoutParser) {
@@ -188,6 +189,12 @@
         this.enableLayoutValidatorImageCheck = true;
         return this;
     }
+    
+    @NonNull
+    public SessionParamsBuilder setTransparentBackground() {
+        this.transparentBackground = true;
+        return this;
+    }
 
     @NonNull
     public SessionParams build() {
@@ -227,6 +234,10 @@
             params.setForceNoDecor();
         }
 
+        if (transparentBackground) {
+            params.setTransparentBackground();
+        }
+
         return params;
     }
 }
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/util/CallbacksDisposerTest.java b/bridge/tests/src/com/android/layoutlib/bridge/util/CallbacksDisposerTest.java
new file mode 100644
index 0000000..f57812b
--- /dev/null
+++ b/bridge/tests/src/com/android/layoutlib/bridge/util/CallbacksDisposerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.layoutlib.bridge.util;
+
+import com.android.layoutlib.bridge.util.CallbacksDisposer.SessionKey;
+
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class CallbacksDisposerTest {
+    @Test
+    public void singleSession() {
+        Set<Object> callbacks = new HashSet<>();
+        CallbacksDisposer disposer = new CallbacksDisposer(callbacks::remove);
+
+        SessionKey session1 = new SessionKey(1);
+
+        Object action1 = new Object();
+        Object action2 = new Object();
+
+        callbacks.add(action2);
+
+        disposer.onCallbackAdded(session1, action1);
+        disposer.onCallbackAdded(session1, action2);
+
+        assertEquals(1, disposer.getSessionsWithCallbacks().size());
+        assertTrue(disposer.getSessionsWithCallbacks().contains(session1));
+        assertTrue(callbacks.contains(action2));
+        assertEquals(1, callbacks.size());
+
+        disposer.onCallbackRemoved(session1, action1);
+
+        assertEquals(1, disposer.getSessionsWithCallbacks().size());
+        assertTrue(disposer.getSessionsWithCallbacks().contains(session1));
+        assertTrue(callbacks.contains(action2));
+        assertEquals(1, callbacks.size());
+
+        disposer.onDispose(session1);
+
+        assertTrue(disposer.getSessionsWithCallbacks().isEmpty());
+        assertTrue(callbacks.isEmpty());
+    }
+
+    @Test
+    public void twoIndependentSessions() {
+        Set<Object> callbacks = new HashSet<>();
+        CallbacksDisposer disposer = new CallbacksDisposer(callbacks::remove);
+
+        SessionKey session1 = new SessionKey(1);
+        SessionKey session2 = new SessionKey(2);
+
+        Object action1 = new Object();
+        Object action2 = new Object();
+
+        callbacks.add(action2);
+        callbacks.add(action1);
+
+        disposer.onCallbackAdded(session1, action1);
+        disposer.onCallbackAdded(session2, action2);
+
+        assertEquals(2, disposer.getSessionsWithCallbacks().size());
+        assertTrue(disposer.getSessionsWithCallbacks().contains(session1));
+        assertTrue(disposer.getSessionsWithCallbacks().contains(session2));
+
+        disposer.onDispose(session1);
+
+        assertEquals(1, disposer.getSessionsWithCallbacks().size());
+        assertTrue(disposer.getSessionsWithCallbacks().contains(session2));
+        assertTrue(callbacks.contains(action2));
+        assertEquals(1, callbacks.size());
+
+        disposer.onDispose(session2);
+
+        assertTrue(disposer.getSessionsWithCallbacks().isEmpty());
+        assertTrue(callbacks.isEmpty());
+    }
+}
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/util/HandlerMessageQueueTest.java b/bridge/tests/src/com/android/layoutlib/bridge/util/HandlerMessageQueueTest.java
new file mode 100644
index 0000000..f7b091e
--- /dev/null
+++ b/bridge/tests/src/com/android/layoutlib/bridge/util/HandlerMessageQueueTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.layoutlib.bridge.util;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Looper_Accessor;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class HandlerMessageQueueTest {
+
+    @Before
+    public void setUp() {
+        Looper.prepareMainLooper();
+    }
+
+    @Test
+    public void testSingleHandler_SingleRunnable() {
+        HandlerMessageQueue q = new HandlerMessageQueue();
+        Handler h1 = new Handler();
+        Runnable r1 = () -> {};
+
+        assertFalse(q.isNotEmpty());
+
+        q.add(h1, 100, r1);
+
+        assertTrue(q.isNotEmpty());
+        assertNull(q.extractFirst(0));
+        assertEquals(q.extractFirst(100), r1);
+        assertFalse(q.isNotEmpty());
+        assertNull(q.extractFirst(100));
+    }
+
+    @Test
+    public void testSingleHandler_MultipleRunnables() {
+        HandlerMessageQueue q = new HandlerMessageQueue();
+        Handler h1 = new Handler();
+        Runnable r1 = () -> {};
+        Runnable r2 = () -> {};
+        Runnable r3 = () -> {};
+
+        q.add(h1, 100, r1);
+        q.add(h1, 100, r2);
+        q.add(h1, 50, r3);
+
+        assertEquals(q.extractFirst(100), r3);
+        assertEquals(q.extractFirst(100), r1);
+        assertTrue(q.isNotEmpty());
+        assertEquals(q.extractFirst(100), r2);
+        assertFalse(q.isNotEmpty());
+    }
+
+    @Test
+    public void testMultipleHandlers() {
+        HandlerMessageQueue q = new HandlerMessageQueue();
+        Handler h1 = new Handler();
+        Handler h2 = new Handler();
+        Runnable r1 = () -> {};
+        Runnable r2 = () -> {};
+        Runnable r3 = () -> {};
+
+        q.add(h1, 200, r1);
+        q.add(h2, 100, r2);
+        q.add(h1, 50, r3);
+
+        assertEquals(q.extractFirst(70), r3);
+        assertEquals(q.extractFirst(300), r2);
+        assertEquals(q.extractFirst(300), r1);
+        assertFalse(q.isNotEmpty());
+        assertNull(q.extractFirst(500));
+
+        q.add(h1, 400, r1);
+
+        assertTrue(q.isNotEmpty());
+        assertEquals(q.extractFirst(500), r1);
+        assertFalse(q.isNotEmpty());
+    }
+
+    @Test
+    public void testMultipleHandlers_Clear() {
+        HandlerMessageQueue q = new HandlerMessageQueue();
+        Handler h1 = new Handler();
+        Handler h2 = new Handler();
+        Runnable r1 = () -> {};
+        Runnable r2 = () -> {};
+        Runnable r3 = () -> {};
+
+        q.add(h1, 200, r1);
+        q.add(h2, 100, r2);
+        q.add(h1, 50, r3);
+
+        q.clear();
+
+        assertFalse(q.isNotEmpty());
+        assertNull(q.extractFirst(200));
+    }
+
+    @After
+    public void tearDown() {
+        Looper_Accessor.cleanupThread();
+    }
+}
diff --git a/bridge/tests/src/com/android/tools/idea/validator/accessibility/AccessibilityValidatorTests.java b/bridge/tests/src/com/android/tools/idea/validator/accessibility/AccessibilityValidatorTests.java
index 16ad4a2..5c5209e 100644
--- a/bridge/tests/src/com/android/tools/idea/validator/accessibility/AccessibilityValidatorTests.java
+++ b/bridge/tests/src/com/android/tools/idea/validator/accessibility/AccessibilityValidatorTests.java
@@ -42,7 +42,7 @@
 import static org.junit.Assert.assertTrue;
 
 /**
- * Sanity check for a11y checks. For now it lacks checking the following:
+ * Basic check for a11y checks. For now it lacks checking the following:
  * - ClassNameCheck
  * - ClickableSpanCheck
  * - EditableContentDescCheck
diff --git a/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java b/common/src/com/android/layoutlib/common/util/ReflectionUtils.java
similarity index 80%
rename from bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
rename to common/src/com/android/layoutlib/common/util/ReflectionUtils.java
index 00348ea..67b9dd5 100644
--- a/bridge/src/com/android/layoutlib/bridge/util/ReflectionUtils.java
+++ b/common/src/com/android/layoutlib/common/util/ReflectionUtils.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.layoutlib.bridge.util;
+package com.android.layoutlib.common.util;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
+import com.android.tools.layoutlib.annotations.NonNull;
+import com.android.tools.layoutlib.annotations.Nullable;
 
+import java.lang.reflect.Field;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -30,6 +31,16 @@
 public class ReflectionUtils {
 
     @NonNull
+    public static Method getMethod(@NonNull String className, @NonNull String name,
+            @Nullable Class<?>... params) throws ReflectionException {
+        try {
+            return getMethod(Class.forName(className), name, params);
+        } catch (ClassNotFoundException e) {
+            throw new ReflectionException(e);
+        }
+    }
+
+    @NonNull
     public static Method getMethod(@NonNull Class<?> clazz, @NonNull String name,
             @Nullable Class<?>... params) throws ReflectionException {
         try {
@@ -48,6 +59,19 @@
         return method;
     }
 
+    @NonNull
+    public static Object getFieldValue(@NonNull Class<?> clazz, Object object, @NonNull String name) throws ReflectionException {
+        try {
+            Field field = clazz.getDeclaredField(name);
+            field.setAccessible(true);
+            return field.get(object);
+        } catch (NoSuchFieldException e) {
+            throw new ReflectionException(e);
+        } catch (IllegalAccessException e) {
+            throw new ReflectionException(e);
+        }
+    }
+
     @Nullable
     public static Object invoke(@NonNull Method method, @Nullable Object object,
             @Nullable Object... args) throws ReflectionException {
@@ -60,6 +84,17 @@
         throw new ReflectionException(ex);
     }
 
+    @Nullable
+    public static Object invokeStatic(String className, String methodName, @Nullable Object... args)
+            throws ReflectionException {
+        try {
+            Method m = getMethod(Class.forName(className), methodName);
+            return invoke(m, null, args);
+        } catch (ClassNotFoundException e) {
+            throw new ReflectionException(e);
+        }
+    }
+
     /**
      * Check if the object is an instance of a class named {@code className}. This doesn't work
      * for interfaces.
diff --git a/common/src/com/android/tools/layoutlib/annotations/NonNull.java b/common/src/com/android/tools/layoutlib/annotations/NonNull.java
new file mode 100644
index 0000000..b48171b
--- /dev/null
+++ b/common/src/com/android/tools/layoutlib/annotations/NonNull.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.tools.layoutlib.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Denotes a parameter or field can not be null.
+ * <p/>
+ * When decorating a method call parameter, this denotes the parameter can
+ * not be null.
+ * <p/>
+ * When decorating a method, this denotes the method can not return null.
+ * <p/>
+ * This is a marker annotation and it has no specific attributes.
+ */
+@Retention(RetentionPolicy.SOURCE)
+public @interface NonNull {
+}
diff --git a/common/src/com/android/tools/layoutlib/create/NativeConfig.java b/common/src/com/android/tools/layoutlib/create/NativeConfig.java
new file mode 100644
index 0000000..6179049
--- /dev/null
+++ b/common/src/com/android/tools/layoutlib/create/NativeConfig.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.tools.layoutlib.create;
+
+/**
+ * Stores data needed for native JNI registration, and possibly the framework bytecode
+ * instrumentation.
+ */
+public class NativeConfig {
+
+    private NativeConfig() {}
+
+    public final static String[] DEFERRED_STATIC_INITIALIZER_CLASSES = new String [] {
+            "android.graphics.ColorSpace",
+            "android.graphics.FontFamily",
+            "android.graphics.Matrix",
+            "android.graphics.Path",
+            // Order is important! Fonts and FontFamily have to be initialized before Typeface
+            "android.graphics.fonts.Font$Builder",
+            "android.graphics.fonts.FontFamily$Builder",
+            "android.graphics.fonts.NativeFontBufferHelper",
+            "android.graphics.Typeface",
+            "android.graphics.text.PositionedGlyphs",
+            "android.graphics.text.LineBreaker",
+    };
+
+    public final static String[] DELEGATE_CLASS_NATIVES = new String[] {
+            "android.os.SystemClock",
+            "android.view.Display",
+            "libcore.icu.ICU",
+    };
+
+    /**
+     * The list of classes to register with JNI
+     */
+    public final static String[] CLASS_NATIVES = new String[] {
+            "android.animation.PropertyValuesHolder",
+            "android.content.res.StringBlock",
+            "android.content.res.XmlBlock",
+            "android.graphics.Bitmap",
+            "android.graphics.BitmapFactory",
+            "android.graphics.ByteBufferStreamAdaptor",
+            "android.graphics.Canvas",
+            "android.graphics.CanvasProperty",
+            "android.graphics.ColorFilter",
+            "android.graphics.ColorSpace",
+            "android.graphics.CreateJavaOutputStreamAdaptor",
+            "android.graphics.DrawFilter",
+            "android.graphics.FontFamily",
+            "android.graphics.Graphics",
+            "android.graphics.HardwareRenderer",
+            "android.graphics.ImageDecoder",
+            "android.graphics.Interpolator",
+            "android.graphics.MaskFilter",
+            "android.graphics.Matrix",
+            "android.graphics.NinePatch",
+            "android.graphics.Paint",
+            "android.graphics.Path",
+            "android.graphics.PathEffect",
+            "android.graphics.PathMeasure",
+            "android.graphics.Picture",
+            "android.graphics.RecordingCanvas",
+            "android.graphics.Region",
+            "android.graphics.RenderNode",
+            "android.graphics.Shader",
+            "android.graphics.Typeface",
+            "android.graphics.animation.NativeInterpolatorFactory",
+            "android.graphics.animation.RenderNodeAnimator",
+            "android.graphics.drawable.AnimatedVectorDrawable",
+            "android.graphics.drawable.VectorDrawable",
+            "android.graphics.fonts.Font",
+            "android.graphics.fonts.FontFamily",
+            "android.graphics.text.LineBreaker",
+            "android.graphics.text.MeasuredText",
+            "android.graphics.text.TextRunShaper",
+            "android.media.ImageReader",
+            "android.os.SystemProperties",
+            "android.os.Trace",
+            "android.text.AndroidCharacter",
+            "android.util.Log",
+            "android.util.PathParser",
+            "android.view.MotionEvent",
+            "android.view.Surface",
+            "com.android.internal.util.VirtualRefBasePtr",
+    };
+}
diff --git a/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index b77708b..6a555cb 100644
--- a/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -18,6 +18,7 @@
 
 import com.android.tools.layoutlib.annotations.NotNull;
 import com.android.tools.layoutlib.annotations.Nullable;
+import com.android.tools.layoutlib.create.ICreateInfo.MethodReplacer;
 
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.Attribute;
@@ -43,10 +44,8 @@
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeMap;
-import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.ForkJoinTask;
-import java.util.concurrent.Future;
 import java.util.function.Consumer;
 import java.util.regex.Pattern;
 import java.util.zip.ZipEntry;
@@ -105,27 +104,28 @@
     private final String[] mIncludeFileGlobs;
     /** Internal names of classes that contain method calls that need to be rewritten. */
     private final Set<String> mReplaceMethodCallClasses = new HashSet<>();
+    /** Internal names of method calls that need to be rewritten. */
+    private final MethodReplacer[] mMethodReplacers;
 
     /**
      * Creates a new analyzer.
-     *
      * @param log The log output.
      * @param osJarPath The input source JARs to parse.
      * @param deriveFrom Keep all classes that derive from these one (these included).
      * @param includeGlobs Glob patterns of classes to keep, e.g. "com.foo.*"
-     *        ("*" does not matches dots whilst "**" does, "." and "$" are interpreted as-is)
+*        ("*" does not matches dots whilst "**" does, "." and "$" are interpreted as-is)
      * @param includeFileGlobs Glob patterns of files which are kept as is. This is only for files
-     *        not ending in .class.
+     * @param methodReplacers names of method calls that need to be rewritten
      */
-    public AsmAnalyzer(Log log, List<String> osJarPath,
-            String[] deriveFrom, String[] includeGlobs, String[] excludedGlobs,
-            String[] includeFileGlobs) {
+    public AsmAnalyzer(Log log, List<String> osJarPath, String[] deriveFrom, String[] includeGlobs,
+            String[] excludedGlobs, String[] includeFileGlobs, MethodReplacer[] methodReplacers) {
         mLog = log;
         mOsSourceJar = osJarPath != null ? osJarPath : new ArrayList<>();
         mDeriveFrom = deriveFrom != null ? deriveFrom : new String[0];
         mIncludeGlobs = includeGlobs != null ? includeGlobs : new String[0];
         mExcludedGlobs = excludedGlobs != null ? excludedGlobs : new String[0];
         mIncludeFileGlobs = includeFileGlobs != null ? includeFileGlobs : new String[0];
+        mMethodReplacers = methodReplacers;
     }
 
     /**
@@ -773,6 +773,24 @@
                 // pass
             }
 
+            /**
+             * If a method some.package.Class.Method(args) is called from some.other.Class,
+             * @param owner some/package/Class
+             * @param name Method
+             * @param desc (args)returnType
+             * @param sourceClass some/other/Class
+             * @return if the method invocation needs to be replaced by some other class.
+             */
+            private boolean isReplacementNeeded(String owner, String name, String desc,
+                    String sourceClass) {
+                for (MethodReplacer replacer : mMethodReplacers) {
+                    if (replacer.isNeeded(owner, name, desc, sourceClass)) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+
             // instruction that invokes a method
             @Override
             public void visitMethodInsn(int opcode, String owner, String name, String desc,
@@ -785,7 +803,7 @@
 
 
                 // Check if method needs to replaced by a call to a different method.
-                if (ReplaceMethodCallsAdapter.isReplacementNeeded(owner, name, desc, mOwnerClass)) {
+                if (isReplacementNeeded(owner, name, desc, mOwnerClass)) {
                     mReplaceMethodCallClasses.add(mOwnerClass);
                 }
             }
diff --git a/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index f468288..500f207 100644
--- a/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -18,6 +18,7 @@
 
 import com.android.tools.layoutlib.annotations.NotNull;
 import com.android.tools.layoutlib.create.AsmAnalyzer.Result;
+import com.android.tools.layoutlib.create.ICreateInfo.MethodReplacer;
 
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
@@ -52,6 +53,7 @@
     private Map<String, ClassReader> mKeep;
     /** All dependencies that must be completely stubbed. */
     private Map<String, ClassReader> mDeps;
+    private Map<String, ClassWriter> mDelegates = new HashMap<>();
     /** All files that are to be copied as-is. */
     private Map<String, InputStream> mCopyFiles;
     /** All classes where certain method calls need to be rewritten. */
@@ -77,8 +79,21 @@
     private final Map<String, ICreateInfo.InjectMethodRunnable> mInjectedMethodsMap;
     /** A map { FQCN => set { field names } } which should be promoted to public visibility */
     private final Map<String, Set<String>> mPromotedFields;
+    /** A map { FQCN => set { method names } } which should be promoted to public visibility */
+    private final Map<String, Set<String>> mPromotedMethods;
     /** A list of classes to be promoted to public visibility */
     private final Set<String> mPromotedClasses;
+    /** A set of classes for which NOT to delegate any native method */
+    private final Set<String> mKeepNativeClasses;
+
+    private final Set<String> mDelegateAllNative;
+    /** A set of classes for which to rename static initializers */
+    private Set<String> mRenameStaticInitializerClasses;
+
+    /** A Set of methods that should be intercepted and replaced **/
+    private final Set<MethodReplacer> mMethodReplacers;
+    private boolean mKeepAllNativeClasses;
+
 
     /**
      * Creates a new generator that can generate the output JAR with the stubbed classes.
@@ -183,10 +198,26 @@
         mPromotedFields = new HashMap<>();
         addToMap(createInfo.getPromotedFields(), mPromotedFields);
 
+        mPromotedMethods = new HashMap<>();
+        addToMap(createInfo.getPromotedMethods(), mPromotedMethods);
+
         mInjectedMethodsMap = createInfo.getInjectedMethodsMap();
 
         mPromotedClasses =
                 Arrays.stream(createInfo.getPromotedClasses()).collect(Collectors.toSet());
+
+        mKeepAllNativeClasses = createInfo.shouldKeepAllNativeClasses();
+
+        mKeepNativeClasses =
+                Arrays.stream(createInfo.getKeepClassNatives()).collect(Collectors.toSet());
+
+        mDelegateAllNative =
+                Arrays.stream(createInfo.getDelegateClassNativesToNatives()).collect(Collectors.toSet());
+
+        mMethodReplacers = Arrays.stream(createInfo.getMethodReplacers()).collect(Collectors.toSet());
+
+        mRenameStaticInitializerClasses =
+                Arrays.stream(createInfo.getDeferredStaticInitializerClasses()).collect(Collectors.toSet());
     }
 
     /**
@@ -259,6 +290,13 @@
             all.put(name, b);
         }
 
+        for (Entry<String, ClassWriter> entry : mDelegates.entrySet()) {
+            ClassWriter value = entry.getValue();
+            value.visitEnd();
+            String name = classNameToEntryPath(entry.getKey());
+            all.put(name, value.toByteArray());
+        }
+
         for (Entry<String, InputStream> entry : mCopyFiles.entrySet()) {
             try {
                 byte[] b = inputStreamToByteArray(entry.getValue());
@@ -334,7 +372,7 @@
         ClassVisitor cv = cw;
 
         if (mReplaceMethodCallsClasses.contains(className)) {
-            cv = new ReplaceMethodCallsAdapter(cv, className);
+            cv = new ReplaceMethodCallsAdapter(mMethodReplacers, cv, className);
         }
 
         cv = new RefactorClassAdapter(cv, mRefactorClasses);
@@ -346,11 +384,21 @@
         if (mInjectedMethodsMap.keySet().contains(binaryNewName)) {
             cv = new InjectMethodsAdapter(cv, mInjectedMethodsMap.get(binaryNewName));
         }
-        cv = StubClassAdapter.builder(mLog, cv)
-                .withDeleteReturns(mDeleteReturns.get(className))
-                .withNewClassName(newName)
-                .useOnlyStubNative(stubNativesOnly)
-                .build();
+
+        if (mDelegateAllNative.contains(binaryNewName)) {
+            Set<String> delegateMethods = mDelegateMethods.remove(className);
+            if (delegateMethods != null && !delegateMethods.isEmpty()) {
+                cv = new DelegateClassAdapter(mLog, cv, className, delegateMethods);
+            }
+            cv = new DelegateToNativeAdapter(mLog, cv, className, mDelegates, delegateMethods);
+        }
+        else if (!mKeepAllNativeClasses && !mKeepNativeClasses.contains(binaryNewName)) {
+            cv = StubClassAdapter.builder(mLog, cv)
+                    .withDeleteReturns(mDeleteReturns.get(className))
+                    .withNewClassName(newName)
+                    .useOnlyStubNative(stubNativesOnly)
+                    .build();
+        }
 
         Set<String> delegateMethods = mDelegateMethods.get(className);
         if (delegateMethods != null && !delegateMethods.isEmpty()) {
@@ -367,10 +415,18 @@
         if (promoteFields != null && !promoteFields.isEmpty()) {
             cv = new PromoteFieldClassAdapter(cv, promoteFields);
         }
+        Set<String> promoteMethods = mPromotedMethods.get(className);
+        if (promoteMethods != null && !promoteMethods.isEmpty()) {
+            cv = new PromoteMethodClassAdapter(cv, promoteMethods);
+        }
         if (!mPromotedClasses.isEmpty()) {
             cv = new PromoteClassClassAdapter(cv, mPromotedClasses);
         }
 
+        if (mRenameStaticInitializerClasses.contains(binaryNewName)) {
+            cv = new DeferStaticInitializerClassAdapter(cv);
+        }
+
         // Make sure no class file has a version above 55 (corresponding to Java 11),
         // so that layoutlib can be run with JDK 11.
         cv = new ChangeFileVersionAdapter(mLog, 55, cv);
diff --git a/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 44046eb..edc4018 100644
--- a/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -18,13 +18,21 @@
 
 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 import com.android.tools.layoutlib.java.LinkedHashMap_Delegate;
+import com.android.tools.layoutlib.java.NioUtils_Delegate;
 import com.android.tools.layoutlib.java.System_Delegate;
 
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.text.DateFormat;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.zip.ZipEntry;
 
 /**
  * Describes the work to be done by {@link AsmGenerator}.
@@ -32,6 +40,11 @@
 public final class CreateInfo implements ICreateInfo {
 
     @Override
+    public MethodReplacer[] getMethodReplacers() {
+        return METHOD_REPLACERS;
+    }
+
+    @Override
     public Class<?>[] getInjectedClasses() {
         return INJECTED_CLASSES;
     }
@@ -47,6 +60,21 @@
     }
 
     @Override
+    public String[] getDelegateClassNativesToNatives() {
+        return DELEGATE_CLASS_NATIVES_TO_NATIVES;
+    }
+
+    @Override
+    public boolean shouldKeepAllNativeClasses() {
+        return false;
+    }
+
+    @Override
+    public String[] getKeepClassNatives() {
+        return KEEP_CLASS_NATIVES;
+    }
+
+    @Override
     public String[] getRenamedClasses() {
         return RENAMED_CLASSES;
     }
@@ -84,6 +112,11 @@
     }
 
     @Override
+    public String[] getPromotedMethods() {
+        return PROMOTED_METHODS;
+    }
+
+    @Override
     public String[] getPromotedClasses() {
         return PROMOTED_CLASSES;
     }
@@ -93,8 +126,28 @@
         return INJECTED_METHODS;
     }
 
+    @Override
+    public String[] getDeferredStaticInitializerClasses() {
+        return DEFERRED_STATIC_INITIALIZER_CLASSES;
+    }
+
     //-----
 
+    private static final MethodReplacer[] METHOD_REPLACERS = new MethodReplacer[] {
+        new SystemLoadLibraryReplacer(),
+        new SystemArrayCopyReplacer(),
+        new LocaleGetDefaultReplacer(),
+        new LocaleAdjustLanguageCodeReplacer(),
+        new SystemLogReplacer(),
+        new SystemNanoTimeReplacer(),
+        new SystemCurrentTimeMillisReplacer(),
+        new LinkedHashMapEldestReplacer(),
+        new ContextGetClassLoaderReplacer(),
+        new ImageReaderNativeInitReplacer(),
+        new NioUtilsFreeBufferReplacer(),
+        new ProcessInitializerInitSchedReplacer(),
+    };
+
     /**
      * The list of class from layoutlib_create to inject in layoutlib.
      */
@@ -110,6 +163,7 @@
             /* Java package classes */
             System_Delegate.class,
             LinkedHashMap_Delegate.class,
+            NioUtils_Delegate.class,
         };
 
     /**
@@ -117,6 +171,13 @@
      */
     public final static String[] DELEGATE_METHODS = new String[] {
         "android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
+        "android.content.res.AssetManager#createSystemAssetsInZygoteLocked",
+        "android.content.res.AssetManager#getAssignedPackageIdentifiers",
+        "android.content.res.AssetManager#nativeCreate",
+        "android.content.res.AssetManager#nativeCreateIdmapsForStaticOverlaysTargetingAndroid",
+        "android.content.res.AssetManager#nativeDestroy",
+        "android.content.res.AssetManager#nativeThemeCreate",
+        "android.content.res.AssetManager#nativeThemeDestroy",
         "android.content.res.Resources#getAnimation",
         "android.content.res.Resources#getAttributeSetSourceResId",
         "android.content.res.Resources#getBoolean",
@@ -147,121 +208,98 @@
         "android.content.res.Resources#getXml",
         "android.content.res.Resources#loadXmlResourceParser",
         "android.content.res.Resources#obtainAttributes",
-        "android.content.res.Resources#obtainTypedArray",
         "android.content.res.Resources#openRawResource",
         "android.content.res.Resources#openRawResourceFd",
+        "android.content.res.Resources#obtainTypedArray",
         "android.content.res.Resources$Theme#obtainStyledAttributes",
         "android.content.res.Resources$Theme#resolveAttribute",
         "android.content.res.Resources$Theme#resolveAttributes",
-        "android.content.res.AssetManager#nativeCreate",
-        "android.content.res.AssetManager#nativeDestroy",
-        "android.content.res.AssetManager#nativeThemeCreate",
-        "android.content.res.AssetManager#nativeThemeDestroy",
-        "android.content.res.AssetManager#getAssignedPackageIdentifiers",
-        "android.content.res.AssetManager#nativeCreateIdmapsForStaticOverlaysTargetingAndroid",
         "android.content.res.TypedArray#getValueAt",
         "android.content.res.TypedArray#obtain",
-        "android.graphics.BitmapFactory#finishDecode",
-        "android.graphics.BitmapFactory#setDensityFromOptions",
-        "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#useLastSeenTarget",
-        "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#onDraw",
-        "android.graphics.drawable.GradientDrawable#buildRing",
-        "android.graphics.drawable.AdaptiveIconDrawable#<init>",
-        "android.graphics.drawable.DrawableInflater#inflateFromClass",
-        "android.graphics.drawable.NinePatchDrawable#getOpacity",
-        "android.graphics.FontFamily#addFont",
-        "com.google.android.apps.common.testing.accessibility.framework.uielement" +
-                ".AccessibilityHierarchyAndroid$ViewElementClassNamesAndroid#getClassByName",
+        "android.graphics.ImageDecoder#decodeBitmapImpl",
         "android.graphics.Typeface#create",
         "android.graphics.Typeface$Builder#createAssetUid",
+        "android.graphics.drawable.AdaptiveIconDrawable#<init>",
+        "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorUI#onDraw",
+        "android.graphics.drawable.AnimatedVectorDrawable#draw",
+        "android.graphics.drawable.DrawableInflater#inflateFromClass",
+        "android.graphics.drawable.NinePatchDrawable#getOpacity",
         "android.graphics.fonts.Font$Builder#createBuffer",
         "android.graphics.fonts.SystemFonts#getSystemFontConfigInternal",
+        "android.graphics.fonts.SystemFonts#mmap",
         "android.os.Binder#getNativeBBinderHolder",
         "android.os.Binder#getNativeFinalizer",
+        "android.os.Handler#sendMessageAtFrontOfQueue",
         "android.os.Handler#sendMessageAtTime",
         "android.os.HandlerThread#run",
         "android.preference.Preference#getView",
-        "android.text.format.DateFormat#is24HourFormat",
-        "android.util.Xml#newPullParser",
-        "android.view.Choreographer#getInstance",
-        "android.view.Choreographer#getRefreshRate",
-        "android.view.Choreographer#scheduleVsyncLocked",
-        "android.view.Display#updateDisplayInfoLocked",
-        "android.view.Display#getWindowManager",
-        "android.view.HandlerActionQueue#postDelayed",
-        "android.view.LayoutInflater#initPrecompiledViews",
-        "android.view.LayoutInflater#rInflate",
-        "android.view.LayoutInflater#parseInclude",
-        "android.view.View#draw",
-        "android.view.View#dispatchDetachedFromWindow",
-        "android.view.View#layout",
-        "android.view.View#measure",
-        "android.view.View#getWindowToken",
-        "android.view.View#isInEditMode",
-        "android.view.ViewRootImpl#isInTouchMode",
-        "android.view.WindowManagerGlobal#getWindowManagerService",
-        "android.view.inputmethod.InputMethodManager#isInEditMode",
-        "android.view.MenuInflater#registerMenu",
-        "android.graphics.RenderNode#getMatrix",
-        "android.graphics.RenderNode#nCreate",
-        "android.graphics.RenderNode#nGetNativeFinalizer",
-        "android.graphics.RenderNode#nSetElevation",
-        "android.graphics.RenderNode#nGetElevation",
-        "android.graphics.RenderNode#nSetTranslationX",
-        "android.graphics.RenderNode#nGetTranslationX",
-        "android.graphics.RenderNode#nSetTranslationY",
-        "android.graphics.RenderNode#nGetTranslationY",
-        "android.graphics.RenderNode#nSetTranslationZ",
-        "android.graphics.RenderNode#nGetTranslationZ",
-        "android.graphics.RenderNode#nSetRotation",
-        "android.graphics.RenderNode#nGetRotation",
-        "android.graphics.RenderNode#nSetLeft",
-        "android.graphics.RenderNode#nSetTop",
-        "android.graphics.RenderNode#nSetRight",
-        "android.graphics.RenderNode#nSetBottom",
-        "android.graphics.RenderNode#nSetLeftTopRightBottom",
-        "android.graphics.RenderNode#nSetPivotX",
-        "android.graphics.RenderNode#nGetPivotX",
-        "android.graphics.RenderNode#nSetPivotY",
-        "android.graphics.RenderNode#nGetPivotY",
-        "android.graphics.RenderNode#nSetScaleX",
-        "android.graphics.RenderNode#nGetScaleX",
-        "android.graphics.RenderNode#nSetScaleY",
-        "android.graphics.RenderNode#nGetScaleY",
-        "android.graphics.RenderNode#nIsPivotExplicitlySet",
         "android.provider.DeviceConfig#getBoolean",
         "android.provider.DeviceConfig#getFloat",
         "android.provider.DeviceConfig#getInt",
         "android.provider.DeviceConfig#getLong",
         "android.provider.DeviceConfig#getString",
+        "android.text.format.DateFormat#is24HourFormat",
+        "android.util.Xml#newPullParser",
+        "android.view.Choreographer#getRefreshRate",
+        "android.view.Choreographer#postCallbackDelayedInternal",
+        "android.view.Choreographer#removeCallbacksInternal",
+        "android.view.Choreographer$CallbackRecord#run",
+        "android.view.Display#getWindowManager",
+        "android.view.Display#updateDisplayInfoLocked",
+        "android.view.HandlerActionQueue#postDelayed",
+        "android.view.LayoutInflater#initPrecompiledViews",
+        "android.view.LayoutInflater#parseInclude",
+        "android.view.LayoutInflater#rInflate",
+        "android.view.MenuInflater#registerMenu",
         "android.view.PointerIcon#loadResource",
         "android.view.PointerIcon#registerDisplayListener",
         "android.view.SurfaceControl#nativeCreateTransaction",
-        "android.view.SurfaceControl#nativeGetNativeTransactionFinalizer",
-        "android.view.ViewGroup#drawChild",
-        "com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
+        "android.view.TextureView#getTextureLayer",
+        "android.view.View#draw",
+        "android.view.View#dispatchDetachedFromWindow",
+        "android.view.View#getWindowToken",
+        "android.view.View#isInEditMode",
+        "android.view.View#layout",
+        "android.view.View#measure",
+        "android.view.ViewRootImpl#isInTouchMode",
+        "android.view.WindowManagerGlobal#getWindowManagerService",
+        "android.view.inputmethod.InputMethodManager#isInEditMode",
         "com.android.internal.util.XmlUtils#convertValueToInt",
+        "com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
+        "com.google.android.apps.common.testing.accessibility.framework.uielement" +
+            ".AccessibilityHierarchyAndroid$ViewElementClassNamesAndroid#getClassByName",
         "dalvik.system.VMRuntime#getNotifyNativeInterval",
         "dalvik.system.VMRuntime#newUnpaddedArray",
-        "libcore.io.MemoryMappedFile#mmapRO",
-        "libcore.io.MemoryMappedFile#close",
         "libcore.io.MemoryMappedFile#bigEndianIterator",
+        "libcore.io.MemoryMappedFile#close",
+        "libcore.io.MemoryMappedFile#mmapRO",
         "libcore.util.NativeAllocationRegistry#applyFreeFunction",
-        "libcore.util.NativeAllocationRegistry#registerNativeAllocation",
     };
 
     /**
      * The list of classes on which to delegate all native methods.
      */
-    public final static String[] DELEGATE_CLASS_NATIVES = new String[] {
+    public final static String[] DELEGATE_CLASS_NATIVES = NativeConfig.DELEGATE_CLASS_NATIVES;
+
+    public final static String[] DELEGATE_CLASS_NATIVES_TO_NATIVES = new String[] {};
+
+    /**
+     * The list of classes on which NOT to delegate any native method.
+     */
+    public final static String[] KEEP_CLASS_NATIVES = new String[] {
         "android.animation.PropertyValuesHolder",
+        "android.content.res.StringBlock",
+        "android.content.res.XmlBlock",
         "android.graphics.BaseCanvas",
+        "android.graphics.BaseRecordingCanvas",
         "android.graphics.Bitmap",
         "android.graphics.BitmapFactory",
         "android.graphics.BitmapShader",
         "android.graphics.BlendModeColorFilter",
         "android.graphics.BlurMaskFilter",
+        "android.graphics.BlurShader",
         "android.graphics.Canvas",
+        "android.graphics.CanvasProperty",
         "android.graphics.Color",
         "android.graphics.ColorFilter",
         "android.graphics.ColorMatrixColorFilter",
@@ -274,6 +312,9 @@
         "android.graphics.DrawFilter",
         "android.graphics.EmbossMaskFilter",
         "android.graphics.FontFamily",
+        "android.graphics.HardwareRenderer",
+        "android.graphics.ImageDecoder",
+        "android.graphics.Interpolator",
         "android.graphics.LightingColorFilter",
         "android.graphics.LinearGradient",
         "android.graphics.MaskFilter",
@@ -285,27 +326,44 @@
         "android.graphics.PathDashPathEffect",
         "android.graphics.PathEffect",
         "android.graphics.PathMeasure",
+        "android.graphics.Picture",
         "android.graphics.PorterDuffColorFilter",
         "android.graphics.RadialGradient",
+        "android.graphics.RecordingCanvas",
         "android.graphics.Region",
+        "android.graphics.RegionIterator",
+        "android.graphics.RenderNode",
+        "android.graphics.RuntimeShader",
         "android.graphics.Shader",
         "android.graphics.SumPathEffect",
         "android.graphics.SweepGradient",
+        "android.graphics.TableMaskFilter",
         "android.graphics.Typeface",
         "android.graphics.animation.NativeInterpolatorFactory",
+        "android.graphics.animation.RenderNodeAnimator",
         "android.graphics.drawable.AnimatedVectorDrawable",
         "android.graphics.drawable.VectorDrawable",
+        "android.graphics.fonts.Font",
         "android.graphics.fonts.Font$Builder",
         "android.graphics.fonts.FontFamily$Builder",
+        "android.graphics.fonts.FontFileUtil",
+        "android.graphics.fonts.NativeFontBufferHelper",
+        "android.graphics.fonts.SystemFonts",
+        "android.graphics.text.PositionedGlyphs",
+        "android.graphics.text.LineBreaker",
         "android.graphics.text.MeasuredText",
         "android.graphics.text.MeasuredText$Builder",
-        "android.graphics.text.LineBreaker",
-        "android.os.SystemClock",
+        "android.graphics.text.TextRunShaper",
+        "android.media.ImageReader",
+        "android.media.ImageReader$SurfaceImage",
         "android.os.SystemProperties",
+        "android.os.Trace",
+        "android.text.AndroidCharacter",
+        "android.util.Log",
         "android.util.PathParser",
-        "android.view.Display",
+        "android.view.MotionEvent",
+        "android.view.Surface",
         "com.android.internal.util.VirtualRefBasePtr",
-        "libcore.icu.ICU",
     };
 
     /**
@@ -321,7 +379,6 @@
             "android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager",
             "android.view.accessibility.AccessibilityNodeIdManager", "android.view.accessibility._Original_AccessibilityNodeIdManager",
             "android.webkit.WebView",                          "android.webkit._Original_WebView",
-            "android.graphics.ImageDecoder",                   "android.graphics._Original_ImageDecoder",
         };
 
     /**
@@ -360,19 +417,36 @@
      * needed when access from the delegate classes is needed.
      */
     private final static String[] PROMOTED_FIELDS = new String[] {
-        "android.graphics.drawable.VectorDrawable#mVectorState",
-        "android.view.Choreographer#mLastFrameTimeNanos",
-        "android.graphics.FontFamily#mBuilderPtr",
-        "android.graphics.Typeface#DEFAULT_FAMILY",
-        "android.graphics.Typeface#sDynamicTypefaceCache",
-        "android.graphics.drawable.AdaptiveIconDrawable#sMask",
-        "android.graphics.drawable.DrawableInflater#mRes",
+        "android.animation.AnimatorSet#mLastFrameTime",
         "android.animation.PropertyValuesHolder#sSetterPropertyMap",
         "android.animation.PropertyValuesHolder#sGetterPropertyMap",
         "android.animation.PropertyValuesHolder$IntPropertyValuesHolder#sJNISetterPropertyMap",
         "android.animation.PropertyValuesHolder$FloatPropertyValuesHolder#sJNISetterPropertyMap",
         "android.animation.PropertyValuesHolder$MultiFloatValuesHolder#sJNISetterPropertyMap",
         "android.animation.PropertyValuesHolder$MultiIntValuesHolder#sJNISetterPropertyMap",
+        "android.graphics.ImageDecoder$InputStreamSource#mInputStream",
+        "android.graphics.Typeface#DEFAULT_FAMILY",
+        "android.graphics.Typeface#sDynamicTypefaceCache",
+        "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorUI#mSet",
+        "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT#mPendingAnimationActions",
+        "android.graphics.drawable.AnimatedVectorDrawable#mAnimatorSet",
+        "android.graphics.drawable.AdaptiveIconDrawable#sMask",
+        "android.graphics.drawable.DrawableInflater#mRes",
+        "android.view.Choreographer#mCallbackQueues", // required for tests only
+        "android.view.Choreographer$CallbackQueue#mHead", // required for tests only
+        "com.android.internal.util.ArrayUtils#sCache",
+    };
+
+    /**
+     * List of methods for which we will update the visibility to be public.
+     */
+    private final static String[] PROMOTED_METHODS = new String[] {
+        "android.animation.AnimationHandler#doAnimationFrame",
+        "android.graphics.Bitmap#setNinePatchChunk",
+        "android.media.ImageReader#nativeClassInit",
+        "android.view.Choreographer#doFrame",
+        "android.view.Choreographer#postCallbackDelayedInternal",
+        "android.view.Choreographer#removeCallbacksInternal",
     };
 
     /**
@@ -380,6 +454,11 @@
      * if possible.
      */
     private final static String[] PROMOTED_CLASSES = new String[] {
+        "android.graphics.ImageDecoder$InputStreamSource",
+        "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorUI",
+        "android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimator",
+        "android.view.Choreographer$CallbackQueue", // required for tests only
+        "android.view.Choreographer$CallbackRecord"
     };
 
     /**
@@ -392,9 +471,247 @@
         new String[] {
             null };                         // separator, for next class/methods list.
 
+    private final static String[] DEFERRED_STATIC_INITIALIZER_CLASSES =
+            NativeConfig.DEFERRED_STATIC_INITIALIZER_CLASSES;
+
     private final static Map<String, InjectMethodRunnable> INJECTED_METHODS =
             new HashMap<String, InjectMethodRunnable>(1) {{
                 put("android.content.Context",
                         InjectMethodRunnables.CONTEXT_GET_FRAMEWORK_CLASS_LOADER);
             }};
+
+    public static class LinkedHashMapEldestReplacer implements MethodReplacer {
+
+        private final String VOID_TO_MAP_ENTRY =
+                Type.getMethodDescriptor(Type.getType(Map.Entry.class));
+        private final String LINKED_HASH_MAP = Type.getInternalName(LinkedHashMap.class);
+
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return LINKED_HASH_MAP.equals(owner) &&
+                    "eldest".equals(name) &&
+                    VOID_TO_MAP_ENTRY.equals(desc);
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.opcode = Opcodes.INVOKESTATIC;
+            mi.owner = Type.getInternalName(LinkedHashMap_Delegate.class);
+            mi.desc = Type.getMethodDescriptor(
+                    Type.getType(Map.Entry.class), Type.getType(LinkedHashMap.class));
+        }
+    }
+
+    private static class ContextGetClassLoaderReplacer implements MethodReplacer {
+        // When LayoutInflater asks for a class loader, we must return the class loader that
+        // cannot return app's custom views/classes. This is so that in case of any failure
+        // or exception when instantiating the views, the IDE can replace it with a mock view
+        // and have proper error handling. However, if a custom view asks for the class
+        // loader, we must return a class loader that can find app's custom views as well.
+        // Thus, we rewrite the call to get class loader in LayoutInflater to
+        // getFrameworkClassLoader and inject a new method in Context. This leaves the normal
+        // method: Context.getClassLoader() free to be used by the apps.
+        private final String VOID_TO_CLASS_LOADER =
+                Type.getMethodDescriptor(Type.getType(ClassLoader.class));
+
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return owner.equals("android/content/Context") &&
+                    sourceClass.equals("android/view/LayoutInflater") &&
+                    name.equals("getClassLoader") &&
+                    desc.equals(VOID_TO_CLASS_LOADER);
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.name = "getFrameworkClassLoader";
+        }
+    }
+
+    private static class SystemCurrentTimeMillisReplacer implements MethodReplacer {
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return Type.getInternalName(System.class).equals(owner) && name.equals("currentTimeMillis");
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.name = "currentTimeMillis";
+            mi.owner = Type.getInternalName(System_Delegate.class);
+        }
+    }
+
+    private static class SystemNanoTimeReplacer implements MethodReplacer {
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return Type.getInternalName(System.class).equals(owner) && name.equals("nanoTime");
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.name = "nanoTime";
+            mi.owner = Type.getInternalName(System_Delegate.class);
+        }
+    }
+
+    public static class SystemLogReplacer implements MethodReplacer {
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return Type.getInternalName(System.class).equals(owner) && name.length() == 4
+                    && name.startsWith("log");
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            assert mi.desc.equals("(Ljava/lang/String;Ljava/lang/Throwable;)V")
+                    || mi.desc.equals("(Ljava/lang/String;)V");
+            mi.name = "log";
+            mi.owner = Type.getInternalName(System_Delegate.class);
+        }
+    }
+
+    /**
+     * Platform code should not loadLibrary on its own. Layoutlib loading infrastructure takes case
+     * of loading all the necessary native libraries (having the right paths etc.)
+     */
+    public static class SystemLoadLibraryReplacer implements MethodReplacer {
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return Type.getInternalName(System.class).equals(owner) && name.equals("loadLibrary");
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.owner = Type.getInternalName(System_Delegate.class);
+        }
+    }
+
+    /**
+     * 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
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return Type.getInternalName(Locale.class).equals(owner)
+                    && "getDefault".equals(name)
+                    && desc.equals(Type.getMethodDescriptor(Type.getType(Locale.class)));
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.owner = "com/android/layoutlib/bridge/android/AndroidLocale";
+        }
+    }
+
+    public static class LocaleAdjustLanguageCodeReplacer implements MethodReplacer {
+
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return Type.getInternalName(java.util.Locale.class).equals(owner)
+                    && ("adjustLanguageCode".equals(name)
+                    && desc.equals(Type.getMethodDescriptor(Type.getType(String.class), Type.getType(String.class))));
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.owner = "com/android/tools/layoutlib/java/util/LocaleAdjustLanguageCodeReplacement";
+        }
+    }
+
+    private static class SystemArrayCopyReplacer implements MethodReplacer {
+        /**
+         * Descriptors for specialized versions {@link System#arraycopy} that are not present on the
+         * Desktop VM.
+         */
+        private static Set<String> ARRAYCOPY_DESCRIPTORS = new HashSet<>(Arrays.asList(
+                "([CI[CII)V", "([BI[BII)V", "([SI[SII)V", "([II[III)V",
+                "([JI[JII)V", "([FI[FII)V", "([DI[DII)V", "([ZI[ZII)V"));
+
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return Type.getInternalName(System.class).equals(owner) && "arraycopy".equals(name) &&
+                    ARRAYCOPY_DESCRIPTORS.contains(desc);
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.desc = "(Ljava/lang/Object;ILjava/lang/Object;II)V";
+        }
+    }
+
+    public static class DateFormatSet24HourTimePrefReplacer implements MethodReplacer {
+
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return Type.getInternalName(DateFormat.class).equals(owner) &&
+                    "set24HourTimePref".equals(name);
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.owner = "com/android/tools/layoutlib/java/text/DateFormat_Delegate";
+        }
+    }
+
+    /**
+     * Replace references to ZipEntry.getDataOffset with a delegate, since it does not exist in the JDK.
+     * @see {@link com.android.tools.layoutlib.java.util.zip.ZipEntry_Delegate#getDataOffset(ZipEntry)}
+     */
+    public static class ZipEntryGetDataOffsetReplacer implements MethodReplacer {
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return Type.getInternalName(ZipEntry.class).equals(owner)
+                    && "getDataOffset".equals(name);
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.opcode = Opcodes.INVOKESTATIC;
+            mi.owner = "com/android/tools/layoutlib/java/util/zip/ZipEntry_Delegate";
+            mi.desc = Type.getMethodDescriptor(
+                    Type.getType(long.class), Type.getType(ZipEntry.class));
+        }
+    }
+
+    public static class NioUtilsFreeBufferReplacer implements MethodReplacer {
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return "java/nio/NioUtils".equals(owner) && name.equals("freeDirectBuffer");
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.owner = Type.getInternalName(NioUtils_Delegate.class);
+        }
+    }
+
+    public static class ProcessInitializerInitSchedReplacer implements MethodReplacer {
+        @Override
+        public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+            return "android/graphics/HardwareRenderer$ProcessInitializer".equals(owner) &&
+                    name.equals("initSched");
+        }
+
+        @Override
+        public void replace(MethodInformation mi) {
+            mi.owner = "android/graphics/HardwareRenderer_ProcessInitializer_Delegate";
+            mi.opcode = Opcodes.INVOKESTATIC;
+            mi.desc = "(J)V";
+        }
+    }
 }
diff --git a/create/src/com/android/tools/layoutlib/create/DeferStaticInitializerClassAdapter.java b/create/src/com/android/tools/layoutlib/create/DeferStaticInitializerClassAdapter.java
new file mode 100644
index 0000000..b5c331d
--- /dev/null
+++ b/create/src/com/android/tools/layoutlib/create/DeferStaticInitializerClassAdapter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+package com.android.tools.layoutlib.create;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * Renames the static initializer to a public deferredStaticInitializer method.
+ */
+public class DeferStaticInitializerClassAdapter extends ClassVisitor {
+
+    public DeferStaticInitializerClassAdapter(ClassVisitor cv) {
+        super(Main.ASM_VERSION, cv);
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+            String[] exceptions) {
+       if (name.equals("<clinit>")) {
+           name = "deferredStaticInitializer";
+           access |= Modifier.PUBLIC;
+        }
+        return super.visitMethod(access, name, desc, signature, exceptions);
+    }
+
+    @Override
+    public FieldVisitor visitField(int access, String name, String desc, String signature,
+            Object value) {
+        // Java 9 does not allow static final field to be modified outside of <clinit>.
+        // So if a field is static, it has to be non-final.
+        if ((access & Opcodes.ACC_STATIC) != 0 ) {
+            access = access & ~Opcodes.ACC_FINAL;;
+        }
+        return super.visitField(access, name, desc, signature, value);
+    }
+}
diff --git a/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java b/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
index f9c7eb3..ac24170 100644
--- a/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
+++ b/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
@@ -99,11 +99,20 @@
         }
 
         if (CLASS_INIT.equals(name)) {
-            // We don't currently support generating delegates for constructors.
-            throw new UnsupportedOperationException(
-                String.format(
-                    "Delegate doesn't support overriding static constructor %1$s:%2$s(%3$s)",
-                    mClassName, name, desc));
+            access = access & ~Opcodes.ACC_PRIVATE;  // make the replacement method package protected.
+
+            // writer for moving the original code to a 'SomeClass.staticInit_Original' method
+            MethodVisitor renamedMethodWriter = super.visitMethod(access,
+                    "staticInit" + ORIGINAL_SUFFIX,
+                    desc, signature, exceptions);
+            // writer for writing the SomeClass.clinit method with a single call to
+            // SomeClass_Delegate.staticInit
+            MethodVisitor originalMethodWriter = super.visitMethod(access, name,
+                    desc, signature, exceptions);
+
+            return new StaticInitMethodAdapter(mLog, renamedMethodWriter,
+                    originalMethodWriter, mClassName);
+
         }
 
         if (isNative) {
diff --git a/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java b/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
index da8babc..6305500 100644
--- a/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
+++ b/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
@@ -89,6 +89,8 @@
     private final boolean mIsStaticInnerClass;
     /** The internal class name (e.g. <code>com/android/SomeClass$InnerClass</code>.) */
     private final String mClassName;
+    /** The corresponding delegate class name */
+    private final String mDelegateClassName;
     /** The method name. */
     private final String mMethodName;
     /** Logger object. */
@@ -111,6 +113,7 @@
      *          Must never be null.
      * @param className The internal class name of the class to visit,
      *          e.g. <code>com/android/SomeClass$InnerClass</code>.
+     * @param delegateClassName The internal class name of the delegate class
      * @param methodName The simple name of the method.
      * @param desc A method descriptor (c.f. {@link Type#getReturnType(String)} +
      *          {@link Type#getArgumentTypes(String)})
@@ -120,6 +123,7 @@
             MethodVisitor mvOriginal,
             MethodVisitor mvDelegate,
             String className,
+            String delegateClassName,
             String methodName,
             String desc,
             boolean isStatic,
@@ -129,12 +133,25 @@
         mOrgWriter = mvOriginal;
         mDelWriter = mvDelegate;
         mClassName = className;
+        mDelegateClassName = delegateClassName;
         mMethodName = methodName;
         mDesc = desc;
         mIsStatic = isStatic;
         mIsStaticInnerClass = isStaticClass;
     }
 
+    public DelegateMethodAdapter(Log log,
+            MethodVisitor mvOriginal,
+            MethodVisitor mvDelegate,
+            String className,
+            String methodName,
+            String desc,
+            boolean isStatic,
+            boolean isStaticClass) {
+        this(log, mvOriginal, mvDelegate, className, className + DELEGATE_SUFFIX, methodName,
+                desc, isStatic, isStaticClass);
+    }
+
     /**
      * Generates the new code for the method.
      * <p/>
@@ -189,7 +206,7 @@
         }
 
         ArrayList<Type> paramTypes = new ArrayList<>();
-        String delegateClassName = mClassName + DELEGATE_SUFFIX;
+        String delegateClassName = mDelegateClassName;
         boolean pushedArg0 = false;
         int maxStack = 0;
 
diff --git a/create/src/com/android/tools/layoutlib/create/DelegateToNativeAdapter.java b/create/src/com/android/tools/layoutlib/create/DelegateToNativeAdapter.java
new file mode 100644
index 0000000..d063e15
--- /dev/null
+++ b/create/src/com/android/tools/layoutlib/create/DelegateToNativeAdapter.java
@@ -0,0 +1,104 @@
+package com.android.tools.layoutlib.create;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Set;
+
+
+public class DelegateToNativeAdapter extends ClassVisitor {
+    private final Log mLog;
+    private final ClassWriter mDelegateWriter;
+    private final String mDelegateName;
+    private final String mClassName;
+    private final Set<String> mDelegateMethods;
+
+    public DelegateToNativeAdapter(Log logger, ClassVisitor cv, String className,
+            Map<String, ClassWriter> delegates, Set<String> delegateMethods) {
+        super(Main.ASM_VERSION, cv);
+        mLog = logger;
+        mDelegateWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+        mClassName = className;
+        mDelegateName = (className + "_NativeDelegate").replace('$', '_');
+        mDelegateMethods = delegateMethods;
+        delegates.put(mDelegateName, mDelegateWriter);
+    }
+
+    @Override
+    public void visit(int version, int access, String name, String signature, String superName,
+            String[] interfaces) {
+        super.visit(version, access, name, signature, superName, interfaces);
+
+        mDelegateWriter.visit(version, Opcodes.ACC_PUBLIC, mDelegateName, null, "java/lang/Object",
+                null);
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+            String[] exceptions) {
+        boolean isStaticMethod = (access & Opcodes.ACC_STATIC) != 0;
+        boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
+
+        if (isNative) {
+            mDelegateWriter.visitMethod(access, name + "_Original", desc, signature, exceptions);
+            generateDelegateMethod(name, desc, signature, exceptions);
+
+            if (mDelegateMethods == null || !mDelegateMethods.contains(name)) {
+                // Remove native flag
+                access = access & ~Opcodes.ACC_NATIVE;
+                MethodVisitor mwDelegate =
+                        super.visitMethod(access, name, desc, signature, exceptions);
+
+                DelegateMethodAdapter a =
+                        new DelegateMethodAdapter(mLog, null, mwDelegate, mClassName, mDelegateName,
+                                name, desc, isStaticMethod, false);
+
+                // A native has no code to visit, so we need to generate it directly.
+                a.generateDelegateCode();
+
+                return mwDelegate;
+            }
+        }
+        return super.visitMethod(access, name, desc, signature, exceptions);
+    }
+
+    private void generateDelegateMethod(String name, String desc, String signature,
+            String[] exceptions) {
+        MethodVisitor delegateVisitor =
+                mDelegateWriter.visitMethod(Opcodes.ACC_STATIC, name, desc,
+                        signature,
+                        exceptions);
+        AnnotationVisitor aw = delegateVisitor.visitAnnotation(
+                Type.getObjectType(Type.getInternalName(LayoutlibDelegate.class)).toString(),
+                true); // visible at runtime
+        if (aw != null) {
+            aw.visitEnd();
+        }
+        delegateVisitor.visitCode();
+        int maxStack = 0;
+        int maxLocals = 0;
+        Type[] argTypes = Type.getArgumentTypes(desc);
+        for (Type t : argTypes) {
+            int size = t.getSize();
+            delegateVisitor.visitVarInsn(t.getOpcode(Opcodes.ILOAD), maxLocals);
+            maxLocals += size;
+            maxStack += size;
+        }
+        delegateVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, mDelegateName,
+                name + "_Original", desc, false);
+
+        Type returnType = Type.getReturnType(desc);
+        delegateVisitor.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
+
+        delegateVisitor.visitMaxs(maxStack, maxLocals);
+        delegateVisitor.visitEnd();
+    }
+}
diff --git a/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
index 42d5727..83c5b24 100644
--- a/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
+++ b/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
@@ -19,13 +19,14 @@
 import org.objectweb.asm.ClassVisitor;
 
 import java.util.Map;
-import java.util.Set;
 
 /**
  * Interface describing the work to be done by {@link AsmGenerator}.
  */
 public interface ICreateInfo {
 
+    MethodReplacer[] getMethodReplacers();
+
     /**
      * Returns the list of class from layoutlib_create to inject in layoutlib.
      * The list can be empty but must not be null.
@@ -45,6 +46,27 @@
     String[] getDelegateClassNatives();
 
     /**
+     * Returns the list of classes for which to create a delegate class that delegates all native
+     * methods to corresponding native methods. This is useful for classes that call native
+     * methods during static initialization.
+     * The list can be empty but must not be null.
+     */
+    String[] getDelegateClassNativesToNatives();
+
+    /**
+     * Returns true if native methods should not be stubbed by default.
+     */
+    boolean shouldKeepAllNativeClasses();
+
+    /**
+     * Returns the list of classes for which not to delegate any native method.
+     * The list can be empty but must not be null.
+     *
+     * Only used when shouldKeepAllNativeClasses is false.
+     */
+    String[] getKeepClassNatives();
+
+    /**
      * Returns the list of classes to rename, must be an even list: the binary FQCN
      * of class to replace followed by the new FQCN.
      * The list can be empty but must not be null.
@@ -87,6 +109,13 @@
     String[] getPromotedFields();
 
     /**
+     * Returns a list of methods which should be promoted to public visibility. The array values
+     * are in the form of the binary FQCN of the class containing the method and the method name
+     * separated by a '#'.
+     */
+    String[] getPromotedMethods();
+
+    /**
      * Returns a list of classes to be promoted to public visibility.
      */
     String[] getPromotedClasses();
@@ -98,6 +127,18 @@
      */
     Map<String, InjectMethodRunnable> getInjectedMethodsMap();
 
+    String[] getDeferredStaticInitializerClasses();
+
+    interface MethodReplacer {
+        boolean isNeeded(String owner, String name, String desc, String sourceClass);
+
+        /**
+         * Updates the MethodInformation with the new values of the method attributes -
+         * opcode, owner, name and desc.
+         */
+        void replace(MethodInformation mi);
+    }
+
     abstract class InjectMethodRunnable {
         /**
          * @param cv Must be {@link ClassVisitor}. However, the param type is object so that when
@@ -107,4 +148,18 @@
          */
         public abstract void generateMethods(Object cv);
     }
+
+    class MethodInformation {
+        public int opcode;
+        public String owner;
+        public String name;
+        public String desc;
+
+        public MethodInformation(int opcode, String owner, String name, String desc) {
+            this.opcode = opcode;
+            this.owner = owner;
+            this.name = name;
+            this.desc = desc;
+        }
+    }
 }
diff --git a/create/src/com/android/tools/layoutlib/create/Main.java b/create/src/com/android/tools/layoutlib/create/Main.java
index 4acc754..e0f55ca 100644
--- a/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/create/src/com/android/tools/layoutlib/create/Main.java
@@ -16,9 +16,6 @@
 
 package com.android.tools.layoutlib.create;
 
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.Opcodes;
 
 import java.io.File;
@@ -62,6 +59,7 @@
         private boolean listAllDeps = false;
         private boolean listOnlyMissingDeps = false;
         private boolean createStubLib = false;
+        private boolean createNativeOnlyDelegates = false;
     }
 
     public static final int ASM_VERSION = Opcodes.ASM6;
@@ -76,7 +74,7 @@
         String[] osDestJar = { null };
 
         if (!processArgs(log, args, osJarPath, osDestJar)) {
-            log.error("Usage: layoutlib_create [-v] [--create-stub] output.jar input.jar ...");
+            log.error("Usage: layoutlib_create [-v] [--create-stub] [--create-native-only-delegates] output.jar input.jar ...");
             log.error("Usage: layoutlib_create [-v] [--list-deps|--missing-deps] input.jar ...");
             System.exit(1);
         }
@@ -99,7 +97,7 @@
         }
 
         try {
-            CreateInfo info = new CreateInfo();
+            ICreateInfo info = new CreateInfo();
             AsmGenerator agen = new AsmGenerator(log, info);
 
             AsmAnalyzer aa = new AsmAnalyzer(log, osJarPath,
@@ -143,7 +141,7 @@
                     new String[] {
                         "com/android/i18n/phonenumbers/data/*",
                         "android/icu/impl/data/**"
-                    });
+                    }, info.getMethodReplacers());
             agen.setAnalysisResult(aa.analyze());
 
             Map<String, byte[]> outputClasses = agen.generate();
@@ -166,6 +164,13 @@
                 log.info("Created stub JAR file %s", stubDestJarFile);
             }
 
+            if (sOptions.createNativeOnlyDelegates) {
+                File osDestJarFile = new File(osDestJar);
+                Map<String, byte[]> nativeDelegateClasses =
+                        outputClasses.entrySet().stream().filter(entry -> entry.getKey().endsWith("_NativeDelegate.class")).collect(Collectors.toMap(Entry::getKey, Entry::getValue));
+                JarUtil.createJar(new FileOutputStream(osDestJarFile), nativeDelegateClasses);
+                log.info("Created native delegate JAR file %s", osDestJarFile);
+            }
 
             // Throw an error if any class failed to get renamed by the generator
             //
@@ -234,6 +239,8 @@
                 needs_dest = false;
             } else if (s.equals("--create-stub")) {
                 sOptions.createStubLib = true;
+            } else if (s.equals("--create-native-only-delegates")) {
+                sOptions.createNativeOnlyDelegates = true;
             } else if (!s.startsWith("-")) {
                 if (needs_dest && osDestJar[0] == null) {
                     osDestJar[0] = s;
diff --git a/create/src/com/android/tools/layoutlib/create/PromoteMethodClassAdapter.java b/create/src/com/android/tools/layoutlib/create/PromoteMethodClassAdapter.java
new file mode 100644
index 0000000..45be08f
--- /dev/null
+++ b/create/src/com/android/tools/layoutlib/create/PromoteMethodClassAdapter.java
@@ -0,0 +1,32 @@
+package com.android.tools.layoutlib.create;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+import java.util.Set;
+
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+
+public class PromoteMethodClassAdapter extends ClassVisitor {
+
+    private final Set<String> mMethodNames;
+    private static final int CLEAR_PRIVATE_MASK = ~(ACC_PRIVATE | ACC_PROTECTED);
+
+    public PromoteMethodClassAdapter(ClassVisitor cv, Set<String> methodNames) {
+        super(Main.ASM_VERSION, cv);
+        mMethodNames = methodNames;
+    }
+
+    @Override
+    public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+            String[] exceptions) {
+        if (mMethodNames.contains(name)) {
+            if ((access & ACC_PUBLIC) == 0) {
+                access = (access & CLEAR_PRIVATE_MASK) | ACC_PUBLIC;
+            }
+        }
+        return super.visitMethod(access, name, desc, signature, exceptions);
+    }
+}
diff --git a/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java b/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
index 2967b05..a9bcd22 100644
--- a/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
+++ b/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java
@@ -16,21 +16,12 @@
 
 package com.android.tools.layoutlib.create;
 
-import com.android.tools.layoutlib.java.LinkedHashMap_Delegate;
-import com.android.tools.layoutlib.java.System_Delegate;
+import com.android.tools.layoutlib.create.ICreateInfo.MethodInformation;
+import com.android.tools.layoutlib.create.ICreateInfo.MethodReplacer;
 
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
 import java.util.Set;
 
 /**
@@ -39,176 +30,12 @@
  */
 public class ReplaceMethodCallsAdapter extends ClassVisitor {
 
-    /**
-     * Descriptors for specialized versions {@link System#arraycopy} that are not present on the
-     * Desktop VM.
-     */
-    private static Set<String> ARRAYCOPY_DESCRIPTORS = new HashSet<>(Arrays.asList(
-            "([CI[CII)V", "([BI[BII)V", "([SI[SII)V", "([II[III)V",
-            "([JI[JII)V", "([FI[FII)V", "([DI[DII)V", "([ZI[ZII)V"));
-
-    private static final List<MethodReplacer> METHOD_REPLACERS = new ArrayList<>(5);
-
-    private static final String ANDROID_LOCALE_CLASS =
-            "com/android/layoutlib/bridge/android/AndroidLocale";
-
-    private static final String JAVA_LOCALE_CLASS = Type.getInternalName(java.util.Locale.class);
-    private static final Type STRING = Type.getType(String.class);
-
-    private static final String JAVA_LANG_SYSTEM = Type.getInternalName(System.class);
-
-    // Static initialization block to initialize METHOD_REPLACERS.
-    static {
-        // Case 1: java.lang.System.arraycopy()
-        METHOD_REPLACERS.add(new MethodReplacer() {
-            @Override
-            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
-                return JAVA_LANG_SYSTEM.equals(owner) && "arraycopy".equals(name) &&
-                        ARRAYCOPY_DESCRIPTORS.contains(desc);
-            }
-
-            @Override
-            public void replace(MethodInformation mi) {
-                mi.desc = "(Ljava/lang/Object;ILjava/lang/Object;II)V";
-            }
-        });
-
-        // Case 2: java.util.Locale.adjustLanguageCode() or java.util.Locale.getDefault()
-        METHOD_REPLACERS.add(new MethodReplacer() {
-
-            private final String STRING_TO_STRING = Type.getMethodDescriptor(STRING, STRING);
-            private final String VOID_TO_LOCALE =
-                    Type.getMethodDescriptor(Type.getType(Locale.class));
-
-            @Override
-            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
-                return JAVA_LOCALE_CLASS.equals(owner) &&
-                        ("adjustLanguageCode".equals(name) && desc.equals(STRING_TO_STRING) ||
-                        "getDefault".equals(name) && desc.equals(VOID_TO_LOCALE));
-            }
-
-            @Override
-            public void replace(MethodInformation mi) {
-                mi.owner = ANDROID_LOCALE_CLASS;
-            }
-        });
-
-        // Case 3: java.lang.System.log?()
-        METHOD_REPLACERS.add(new MethodReplacer() {
-            @Override
-            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
-                return JAVA_LANG_SYSTEM.equals(owner) && name.length() == 4
-                        && name.startsWith("log");
-            }
-
-            @Override
-            public void replace(MethodInformation mi) {
-                assert mi.desc.equals("(Ljava/lang/String;Ljava/lang/Throwable;)V")
-                        || mi.desc.equals("(Ljava/lang/String;)V");
-                mi.name = "log";
-                mi.owner = Type.getInternalName(System_Delegate.class);
-            }
-        });
-
-        // Case 4: java.lang.System time calls
-        METHOD_REPLACERS.add(new MethodReplacer() {
-            @Override
-            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
-                return JAVA_LANG_SYSTEM.equals(owner) && name.equals("nanoTime");
-            }
-
-            @Override
-            public void replace(MethodInformation mi) {
-                mi.name = "nanoTime";
-                mi.owner = Type.getInternalName(System_Delegate.class);
-            }
-        });
-        METHOD_REPLACERS.add(new MethodReplacer() {
-            @Override
-            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
-                return JAVA_LANG_SYSTEM.equals(owner) && name.equals("currentTimeMillis");
-            }
-
-            @Override
-            public void replace(MethodInformation mi) {
-                mi.name = "currentTimeMillis";
-                mi.owner = Type.getInternalName(System_Delegate.class);
-            }
-        });
-
-        // Case 5: java.util.LinkedHashMap.eldest()
-        METHOD_REPLACERS.add(new MethodReplacer() {
-
-            private final String VOID_TO_MAP_ENTRY =
-                    Type.getMethodDescriptor(Type.getType(Map.Entry.class));
-            private final String LINKED_HASH_MAP = Type.getInternalName(LinkedHashMap.class);
-
-            @Override
-            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
-                return LINKED_HASH_MAP.equals(owner) &&
-                        "eldest".equals(name) &&
-                        VOID_TO_MAP_ENTRY.equals(desc);
-            }
-
-            @Override
-            public void replace(MethodInformation mi) {
-                mi.opcode = Opcodes.INVOKESTATIC;
-                mi.owner = Type.getInternalName(LinkedHashMap_Delegate.class);
-                mi.desc = Type.getMethodDescriptor(
-                        Type.getType(Map.Entry.class), Type.getType(LinkedHashMap.class));
-            }
-        });
-
-        // Case 6: android.content.Context.getClassLoader() in LayoutInflater
-        METHOD_REPLACERS.add(new MethodReplacer() {
-            // When LayoutInflater asks for a class loader, we must return the class loader that
-            // cannot return app's custom views/classes. This is so that in case of any failure
-            // or exception when instantiating the views, the IDE can replace it with a mock view
-            // and have proper error handling. However, if a custom view asks for the class
-            // loader, we must return a class loader that can find app's custom views as well.
-            // Thus, we rewrite the call to get class loader in LayoutInflater to
-            // getFrameworkClassLoader and inject a new method in Context. This leaves the normal
-            // method: Context.getClassLoader() free to be used by the apps.
-            private final String VOID_TO_CLASS_LOADER =
-                    Type.getMethodDescriptor(Type.getType(ClassLoader.class));
-
-            @Override
-            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
-                return owner.equals("android/content/Context") &&
-                        sourceClass.equals("android/view/LayoutInflater") &&
-                        name.equals("getClassLoader") &&
-                        desc.equals(VOID_TO_CLASS_LOADER);
-            }
-
-            @Override
-            public void replace(MethodInformation mi) {
-                mi.name = "getFrameworkClassLoader";
-            }
-        });
-    }
-
-    /**
-     * If a method some.package.Class.Method(args) is called from some.other.Class,
-     * @param owner some/package/Class
-     * @param name Method
-     * @param desc (args)returnType
-     * @param sourceClass some/other/Class
-     * @return if the method invocation needs to be replaced by some other class.
-     */
-    public static boolean isReplacementNeeded(String owner, String name, String desc,
-            String sourceClass) {
-        for (MethodReplacer replacer : METHOD_REPLACERS) {
-            if (replacer.isNeeded(owner, name, desc, sourceClass)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
+    private Set<MethodReplacer> mMethodReplacers;
     private final String mOriginalClassName;
 
-    public ReplaceMethodCallsAdapter(ClassVisitor cv, String originalClassName) {
+    public ReplaceMethodCallsAdapter(Set<MethodReplacer> methodReplacers, ClassVisitor cv, String originalClassName) {
         super(Main.ASM_VERSION, cv);
+        mMethodReplacers = methodReplacers;
         mOriginalClassName = originalClassName;
     }
 
@@ -227,7 +54,7 @@
         @Override
         public void visitMethodInsn(int opcode, String owner, String name, String desc,
                 boolean itf) {
-            for (MethodReplacer replacer : METHOD_REPLACERS) {
+            for (MethodReplacer replacer : mMethodReplacers) {
                 if (replacer.isNeeded(owner, name, desc, mOriginalClassName)) {
                     MethodInformation mi = new MethodInformation(opcode, owner, name, desc);
                     replacer.replace(mi);
@@ -242,27 +69,4 @@
         }
     }
 
-    private static class MethodInformation {
-        public int opcode;
-        public String owner;
-        public String name;
-        public String desc;
-
-        public MethodInformation(int opcode, String owner, String name, String desc) {
-            this.opcode = opcode;
-            this.owner = owner;
-            this.name = name;
-            this.desc = desc;
-        }
-    }
-
-    private interface MethodReplacer {
-        boolean isNeeded(String owner, String name, String desc, String sourceClass);
-
-        /**
-         * Updates the MethodInformation with the new values of the method attributes -
-         * opcode, owner, name and desc.
-         */
-        void replace(MethodInformation mi);
-    }
 }
diff --git a/create/src/com/android/tools/layoutlib/create/StaticInitMethodAdapter.java b/create/src/com/android/tools/layoutlib/create/StaticInitMethodAdapter.java
new file mode 100644
index 0000000..0e3ffeb
--- /dev/null
+++ b/create/src/com/android/tools/layoutlib/create/StaticInitMethodAdapter.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+package com.android.tools.layoutlib.create;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import static com.android.tools.layoutlib.create.DelegateMethodAdapter.DELEGATE_SUFFIX;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+class StaticInitMethodAdapter extends MethodVisitor {
+    /** static initializer delegate name. */
+    private static final String DELEGATE_STATIC_NAME = "staticInit";
+
+    /** The internal class name (e.g. <code>com/android/SomeClass$InnerClass</code>.) */
+    private final String mClassName;
+
+    /** Logger object. */
+    private final Log mLog;
+
+    /** The method writer to copy of the original method. */
+    private final MethodVisitor mRenamedMethodWriter;
+
+    /** The method writer to generate the original static { SomeClass_Delegate.staticInit} block */
+    private final MethodVisitor mOriginalMethodWriter;
+
+    /** Array used to capture the first line number information from the original method
+     *  and duplicate it in the delegate. */
+    private Object[] mDelegateLineNumber;
+
+    public StaticInitMethodAdapter(Log log, MethodVisitor renamedMethodWriter,
+            MethodVisitor originalMethodWriter,
+            String className) {
+        super(Main.ASM_VERSION);
+        mLog = log;
+        mRenamedMethodWriter = renamedMethodWriter;
+        mOriginalMethodWriter = originalMethodWriter;
+        mClassName = className;
+    }
+
+
+
+    /**
+     * Generate the new code for the method.
+     *
+     * This will be a call to className_Delegate#staticInit
+     */
+    private void generateDelegateCode() {
+        AnnotationVisitor aw = mOriginalMethodWriter.visitAnnotation(
+                Type.getObjectType(Type.getInternalName(LayoutlibDelegate.class)).toString(),
+                true); // visible at runtime
+        if (aw != null) {
+            aw.visitEnd();
+        }
+
+        mOriginalMethodWriter.visitCode();
+
+        if (mDelegateLineNumber != null) {
+            Object[] p = mDelegateLineNumber;
+            mOriginalMethodWriter.visitLineNumber((Integer) p[0], (Label) p[1]);
+        }
+
+        String delegateClassName = mClassName + DELEGATE_SUFFIX;
+        delegateClassName = delegateClassName.replace('$', '_');
+
+        // generate the SomeClass_Delegate.staticInit call.
+        mOriginalMethodWriter.visitMethodInsn(Opcodes.INVOKESTATIC, delegateClassName,
+                DELEGATE_STATIC_NAME,
+                Type.getMethodDescriptor(Type.VOID_TYPE),
+                false);
+        mOriginalMethodWriter.visitInsn(Type.VOID_TYPE.getOpcode(Opcodes.IRETURN));
+        mOriginalMethodWriter.visitMaxs(0, 0);
+
+        mOriginalMethodWriter.visitEnd();
+
+        mLog.debug("static initializer call for class %s delegated to %s#%s",
+                mClassName,
+                delegateClassName, DELEGATE_STATIC_NAME);
+    }
+
+    /* Pass down to visitor writer. In this implementation, either do nothing. */
+    @Override
+    public void visitCode() {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitCode();
+        }
+    }
+
+    /*
+     * visitMaxs is called just before visitEnd if there was any code to rewrite.
+     */
+    @Override
+    public void visitMaxs(int maxStack, int maxLocals) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitMaxs(maxStack, maxLocals);
+        }
+    }
+
+    /** End of visiting. Generate the delegating code. */
+    @Override
+    public void visitEnd() {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitEnd();
+        }
+        generateDelegateCode();
+    }
+
+    /* Writes all annotation from the original method. */
+    @Override
+    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+        if (mRenamedMethodWriter != null) {
+            return mRenamedMethodWriter.visitAnnotation(desc, visible);
+        } else {
+            return null;
+        }
+    }
+
+    /* Writes all annotation default values from the original method. */
+    @Override
+    public AnnotationVisitor visitAnnotationDefault() {
+        if (mRenamedMethodWriter != null) {
+            return mRenamedMethodWriter.visitAnnotationDefault();
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public AnnotationVisitor visitParameterAnnotation(int parameter, String desc,
+            boolean visible) {
+        if (mRenamedMethodWriter != null) {
+            return mRenamedMethodWriter.visitParameterAnnotation(parameter, desc, visible);
+        } else {
+            return null;
+        }
+    }
+
+    /* Writes all attributes from the original method. */
+    @Override
+    public void visitAttribute(Attribute attr) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitAttribute(attr);
+        }
+    }
+
+    /*
+     * Only writes the first line number present in the original code so that source
+     * viewers can direct to the correct method, even if the content doesn't match.
+     */
+    @Override
+    public void visitLineNumber(int line, Label start) {
+        // Capture the first line values for the new delegate method
+        if (mDelegateLineNumber == null) {
+            mDelegateLineNumber = new Object[] { line, start };
+        }
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitLineNumber(line, start);
+        }
+    }
+
+    @Override
+    public void visitInsn(int opcode) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitInsn(opcode);
+        }
+    }
+
+    @Override
+    public void visitLabel(Label label) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitLabel(label);
+        }
+    }
+
+    @Override
+    public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitTryCatchBlock(start, end, handler, type);
+        }
+    }
+
+    @Override
+    public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitMethodInsn(opcode, owner, name, desc, itf);
+        }
+    }
+
+    @Override
+    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitFieldInsn(opcode, owner, name, desc);
+        }
+    }
+
+    @Override
+    public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitFrame(type, nLocal, local, nStack, stack);
+        }
+    }
+
+    @Override
+    public void visitIincInsn(int var, int increment) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitIincInsn(var, increment);
+        }
+    }
+
+    @Override
+    public void visitIntInsn(int opcode, int operand) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitIntInsn(opcode, operand);
+        }
+    }
+
+    @Override
+    public void visitJumpInsn(int opcode, Label label) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitJumpInsn(opcode, label);
+        }
+    }
+
+    @Override
+    public void visitLdcInsn(Object cst) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitLdcInsn(cst);
+        }
+    }
+
+    @Override
+    public void visitLocalVariable(String name, String desc, String signature,
+            Label start, Label end, int index) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitLocalVariable(name, desc, signature, start, end, index);
+        }
+    }
+
+    @Override
+    public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitLookupSwitchInsn(dflt, keys, labels);
+        }
+    }
+
+    @Override
+    public void visitMultiANewArrayInsn(String desc, int dims) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitMultiANewArrayInsn(desc, dims);
+        }
+    }
+
+    @Override
+    public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitTableSwitchInsn(min, max, dflt, labels);
+        }
+    }
+
+    @Override
+    public void visitTypeInsn(int opcode, String type) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitTypeInsn(opcode, type);
+        }
+    }
+
+    @Override
+    public void visitVarInsn(int opcode, int var) {
+        if (mRenamedMethodWriter != null) {
+            mRenamedMethodWriter.visitVarInsn(opcode, var);
+        }
+    }
+}
diff --git a/create/src/com/android/tools/layoutlib/create/StubClassAdapter.java b/create/src/com/android/tools/layoutlib/create/StubClassAdapter.java
index e1d2df2..5202ce4 100644
--- a/create/src/com/android/tools/layoutlib/create/StubClassAdapter.java
+++ b/create/src/com/android/tools/layoutlib/create/StubClassAdapter.java
@@ -34,7 +34,7 @@
 /**
  * Class adapter that can stub some or all of the methods of the class.
  */
-class StubClassAdapter extends ClassVisitor {
+public class StubClassAdapter extends ClassVisitor {
     public interface MethodVisitorFactory {
         @NotNull
         MethodVisitor create(@NotNull MethodVisitor mv,
diff --git a/create/src/com/android/tools/layoutlib/java/NioUtils_Delegate.java b/create/src/com/android/tools/layoutlib/java/NioUtils_Delegate.java
new file mode 100644
index 0000000..33039b5
--- /dev/null
+++ b/create/src/com/android/tools/layoutlib/java/NioUtils_Delegate.java
@@ -0,0 +1,15 @@
+
+package com.android.tools.layoutlib.java;
+
+import java.nio.ByteBuffer;
+
+public final class NioUtils_Delegate {
+  public static void freeDirectBuffer(ByteBuffer buffer) {
+    /*
+     * NioUtils is not included in layoutlib classpath. Thus, calling NioUtils.freeDirectBuffer in
+     * {@link android.graphics.ImageReader} produces ClassNotFound exception. Moreover, it does not
+     * seem we have to do anything in here as we are only referencing the existing native buffer
+     * and do not perform any allocation on creation.
+     */
+  }
+}
\ No newline at end of file
diff --git a/create/src/com/android/tools/layoutlib/java/System_Delegate.java b/create/src/com/android/tools/layoutlib/java/System_Delegate.java
index 335f566..8260312 100644
--- a/create/src/com/android/tools/layoutlib/java/System_Delegate.java
+++ b/create/src/com/android/tools/layoutlib/java/System_Delegate.java
@@ -65,4 +65,9 @@
     public static long bootTimeMillis() {
         return TimeUnit.NANOSECONDS.toMillis(mBootNanosTime.get());
     }
+
+    // This is no-op since layoutlib infrastructure loads all the native libraries.
+    public static void loadLibrary(String libname) {
+        // ignore.
+    }
 }
diff --git a/create/tests/res/data/mock_android.jar b/create/tests/res/data/mock_android.jar
index 3fd6999..2534ece 100644
--- a/create/tests/res/data/mock_android.jar
+++ b/create/tests/res/data/mock_android.jar
Binary files differ
diff --git a/create/tests/res/mock_data/README.md b/create/tests/res/mock_data/README.md
new file mode 100644
index 0000000..6b59184
--- /dev/null
+++ b/create/tests/res/mock_data/README.md
@@ -0,0 +1,25 @@
+# Update mock_android.jar
+
+## Build mock_android.jar
+
+First, use set up instructions from layoutlib tutorial to make commands like `m` work.
+
+Then, run the following in the repository root:
+
+```
+m mock_android
+mv out/host/linux-x86/framework/mock_android.jar frameworks/layoutlib/create/tests/res/data/mock_android.jar
+```
+
+## Build problems
+
+If you see a build error like:
+
+```
+[ 29% 351/1203] including frameworks/layoutlib/out/test/create/mock_data/Android.mk ...
+FAILED:
+build/make/core/base_rules.mk:325: error: frameworks/layoutlib/out/test/create/mock_data: MODULE.linux.JAVA_LIBRARIES.mock_android already defined by frameworks/layoutlib/create/tests/res/mock_data.
+16:26:52 ckati failed with: exit status 1
+```
+
+a quick solution would be to remove `frameworks/layoutlib/out/test/create/mock_data/Android.mk`.
diff --git a/create/tests/res/mock_data/mock_android/view/LibLoader.java b/create/tests/res/mock_data/mock_android/view/LibLoader.java
new file mode 100644
index 0000000..c24a288
--- /dev/null
+++ b/create/tests/res/mock_data/mock_android/view/LibLoader.java
@@ -0,0 +1,7 @@
+package mock_android.view;
+
+class LibLoader {
+    static {
+        System.loadLibrary("dummy");
+    }
+}
\ No newline at end of file
diff --git a/create/tests/run_tests.sh b/create/tests/run_tests.sh
new file mode 100755
index 0000000..3d53838
--- /dev/null
+++ b/create/tests/run_tests.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+SCRIPT_DIR="$(dirname $0)"
+DIST_DIR="$1"
+
+STUDIO_JDK=${SCRIPT_DIR}"/../../../../prebuilts/jdk/jdk11/linux-x86"
+OUT_INTERMEDIATES=${SCRIPT_DIR}"/../../../../out/soong/.intermediates"
+
+${STUDIO_JDK}/bin/java -ea \
+    -cp ${OUT_INTERMEDIATES}/external/junit/junit/linux_glibc_common/javac/junit.jar:${OUT_INTERMEDIATES}/external/hamcrest/hamcrest-core/hamcrest/linux_glibc_common/javac/hamcrest.jar:${OUT_INTERMEDIATES}/frameworks/layoutlib/create/layoutlib_create/linux_glibc_common/combined/layoutlib_create.jar:${OUT_INTERMEDIATES}/frameworks/layoutlib/create/tests/layoutlib-create-tests/linux_glibc_common/combined/layoutlib-create-tests.jar:${SCRIPT_DIR}/res \
+    org.junit.runner.JUnitCore \
+    com.android.tools.layoutlib.create.AllTests
+
diff --git a/create/tests/src/com/android/tools/layoutlib/create/AllTests.java b/create/tests/src/com/android/tools/layoutlib/create/AllTests.java
new file mode 100644
index 0000000..cdc43e0
--- /dev/null
+++ b/create/tests/src/com/android/tools/layoutlib/create/AllTests.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.tools.layoutlib.create;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+/**
+ * Suite containing all the layoutlib-create tests
+ */
+@RunWith(Suite.class)
+@SuiteClasses({
+        AsmAnalyzerTest.class, AsmGeneratorTest.class,
+        ClassHasNativeVisitorTest.class, DelegateClassAdapterTest.class,
+        LogTest.class, PromoteClassClassAdapterTest.class, RenameClassAdapterTest.class,
+        StubClassAdapterTest.class, StubMethodAdapterTest.class,
+})
+public class AllTests {
+}
diff --git a/create/tests/src/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/create/tests/src/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
index 327bbb7..d0943d5 100644
--- a/create/tests/src/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
+++ b/create/tests/src/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
@@ -19,6 +19,7 @@
 
 import com.android.tools.layoutlib.create.AsmAnalyzer.DependencyVisitor;
 import com.android.tools.layoutlib.create.AsmAnalyzer.Result;
+import com.android.tools.layoutlib.create.ICreateInfo.MethodReplacer;
 
 import org.junit.Test;
 import org.objectweb.asm.ClassReader;
@@ -55,7 +56,8 @@
     private static AsmAnalyzer getDefaultAnalyzer() {
         MockLog log = new MockLog();
         return new AsmAnalyzer(log, MOCK_ANDROID_JAR, null ,
-                null /* includeGlobs */, DEFAULT_EXCLUDES, DEFAULT_INCLUDE_FILES);
+                null /* includeGlobs */, DEFAULT_EXCLUDES, DEFAULT_INCLUDE_FILES,
+                new MethodReplacer[] {});
     }
 
     @Test
@@ -84,6 +86,7 @@
                 "mock_android.fake2.keep.DoNotRemove",
                 "mock_android.util.EmptyArray",
                 "mock_android.util.NotNeeded",
+                "mock_android.view.LibLoader",
                 "mock_android.view.View",
                 "mock_android.view.ViewGroup",
                 "mock_android.view.ViewGroup$LayoutParams",
@@ -126,7 +129,8 @@
                     "mock_android.fake2.*", // Exclude subpackages select
                 },
                 DEFAULT_EXCLUDES,
-                DEFAULT_INCLUDE_FILES);
+                DEFAULT_INCLUDE_FILES,
+                new MethodReplacer[] {});
         Result result = analyzer.analyze();
         assertArrayEquals(new String[] {
                         "mock_android.fake.InnerTest$NotStaticInner1",
diff --git a/create/tests/src/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/create/tests/src/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 3f5e8f6..aadab22 100644
--- a/create/tests/src/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/create/tests/src/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -18,6 +18,10 @@
 package com.android.tools.layoutlib.create;
 
 
+import com.android.tools.layoutlib.create.CreateInfo.SystemLoadLibraryReplacer;
+import com.android.tools.layoutlib.create.ICreateInfo.MethodInformation;
+import com.android.tools.layoutlib.create.ICreateInfo.MethodReplacer;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -39,6 +43,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.zip.ZipEntry;
@@ -106,7 +111,8 @@
                     "**"
                 },
                 new String[]{}  /* excluded classes */,
-                new String[]{} /* include files */);
+                new String[]{}, /* include files */
+                new MethodReplacer[] {});
         agen.setAnalysisResult(aa.analyze());
         agen.generate();
 
@@ -150,7 +156,8 @@
                 new String[]{},
                 new String[] {        /* include files */
                     "mock_android/data/data*"
-                });
+                },
+                new MethodReplacer[] {} /* method replacers */);
         agen.setAnalysisResult(aa.analyze());
         Map<String, byte[]> output = agen.generate();
         RecordingClassVisitor cv = new RecordingClassVisitor();
@@ -195,7 +202,8 @@
                         "**"
                 },
                 new String[]{},
-                new String[] {});
+                new String[] {},
+                new MethodReplacer[] {});
         agen.setAnalysisResult(aa.analyze());
         Map<String, byte[]> output = agen.generate();
         RecordingClassVisitor cv = new RecordingClassVisitor();
@@ -232,7 +240,8 @@
                 ci.getExcludedClasses(),
                 new String[] {        /* include files */
                         "mock_android/data/data*"
-                });
+                },
+                new MethodReplacer[] {});
         agen.setAnalysisResult(aa.analyze());
         Map<String, byte[]> output = agen.generate();
         // Everything in .fake.** should be filtered
@@ -240,6 +249,7 @@
         assertArrayEquals(new String[] {
                 "mock_android.fake2.keep.DoNotRemove",
                 "mock_android.util.EmptyArray",
+                "mock_android.view.LibLoader",
                 "mock_android.view.View",
                 "mock_android.view.ViewGroup",
                 "mock_android.view.ViewGroup$LayoutParams",
@@ -275,7 +285,8 @@
                 ci.getExcludedClasses(),
                 new String[] {        /* include files */
                         "mock_android/data/data*"
-                });
+                },
+                new MethodReplacer[] {});
         agen.setAnalysisResult(aa.analyze());
         JarUtil.createJar(new FileOutputStream(mOsDestJar), agen.generate());
 
@@ -304,6 +315,58 @@
         assertEquals(classLoader, cl);
     }
 
+    @Test
+    public void testMethodVisitor_loadLibraryReplacer() throws IOException {
+        final List<String> isNeeded = new ArrayList<>();
+        final List<String> replaced = new ArrayList<>();
+        MethodReplacer recordingReplacer = new MethodReplacer() {
+            private final MethodReplacer loadLibraryReplacer = new SystemLoadLibraryReplacer();
+            private final List<String> isNeededList = isNeeded;
+            private final List<String> replacedList = replaced;
+
+            @Override
+            public boolean isNeeded(String owner, String name, String desc, String sourceClass) {
+                boolean res = loadLibraryReplacer.isNeeded(owner, name, desc, sourceClass);
+                if (res) {
+                    isNeededList.add(sourceClass + "->" + owner + "." + name);
+                }
+                return res;
+            }
+
+            @Override
+            public void replace(MethodInformation mi) {
+                replacedList.add(mi.owner + "." + mi.name);
+            }
+        };
+        MethodReplacer[] replacers = new MethodReplacer[] { recordingReplacer };
+
+        ICreateInfo ci = new CreateInfoAdapter() {
+            @Override
+            public MethodReplacer[] getMethodReplacers() {
+                return replacers;
+            }
+        };
+
+        AsmGenerator agen = new AsmGenerator(mLog, ci);
+        AsmAnalyzer aa = new AsmAnalyzer(mLog, mOsJarPath,
+                null,                 // derived from
+                new String[] {        // include classes
+                        "**"
+                },
+                new String[] {},
+                new String[] {},
+                replacers);
+        agen.setAnalysisResult(aa.analyze());
+
+        assertTrue(isNeeded.contains("mock_android/view/LibLoader->java/lang/System.loadLibrary"));
+        assertTrue(replaced.isEmpty());
+
+        agen.generate();
+
+        assertTrue(isNeeded.contains("mock_android/view/LibLoader->java/lang/System.loadLibrary"));
+        assertTrue(replaced.contains("java/lang/System.loadLibrary"));
+    }
+
     private static byte[] getByteArray(InputStream stream) throws IOException {
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         byte[] buffer = new byte[1024];
diff --git a/create/tests/src/com/android/tools/layoutlib/create/CreateInfoAdapter.java b/create/tests/src/com/android/tools/layoutlib/create/CreateInfoAdapter.java
index 668b578..3b1cb06 100644
--- a/create/tests/src/com/android/tools/layoutlib/create/CreateInfoAdapter.java
+++ b/create/tests/src/com/android/tools/layoutlib/create/CreateInfoAdapter.java
@@ -23,6 +23,11 @@
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 
     @Override
+    public MethodReplacer[] getMethodReplacers() {
+        return new MethodReplacer[0];
+    }
+
+    @Override
     public Class<?>[] getInjectedClasses() {
         return new Class<?>[0];
     }
@@ -38,6 +43,21 @@
     }
 
     @Override
+    public String[] getDelegateClassNativesToNatives() {
+        return EMPTY_STRING_ARRAY;
+    }
+
+    @Override
+    public boolean shouldKeepAllNativeClasses() {
+        return false;
+    }
+
+    @Override
+    public String[] getKeepClassNatives() {
+        return EMPTY_STRING_ARRAY;
+    }
+
+    @Override
     public String[] getRenamedClasses() {
         return EMPTY_STRING_ARRAY;
     }
@@ -68,6 +88,11 @@
     }
 
     @Override
+    public String[] getPromotedMethods() {
+        return EMPTY_STRING_ARRAY;
+    }
+
+    @Override
     public String[] getPromotedClasses() {
         return EMPTY_STRING_ARRAY;
     }
@@ -76,4 +101,9 @@
     public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
         return Collections.emptyMap();
     }
+
+    @Override
+    public String[] getDeferredStaticInitializerClasses() {
+        return EMPTY_STRING_ARRAY;
+    }
 }
diff --git a/create/tests/src/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java b/create/tests/src/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
index b7aa4e6..c6e4508 100644
--- a/create/tests/src/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
+++ b/create/tests/src/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -57,6 +58,13 @@
     private static final String OUTER_CLASS_NAME = OuterClass.class.getName();
     private static final String INNER_CLASS_NAME = InnerClass.class.getName();
     private static final String STATIC_INNER_CLASS_NAME = StaticInnerClass.class.getName();
+    // use a string to avoid triggering the static init
+    private static final String CLASS_WITH_STATIC_INIT_NAME =
+            "com.android.tools.layoutlib.create.dataclass.ClassWithStaticInit";
+    private static final String INNER_CLASS_WITH_STATIC_INIT_NAME =
+            "com.android.tools.layoutlib.create.dataclass.ClassWithStaticInit$InnerClass";
+    private static final String INNER_CLASS_WITH_STATIC_INIT_DELEGATE_NAME =
+            "com.android.tools.layoutlib.create.dataclass.ClassWithStaticInit_InnerClass_Delegate";
 
     @Before
     public void setUp() throws Exception {
@@ -237,6 +245,74 @@
     }
 
     @Test
+    public void testDelegateStaticInitializer() throws Throwable {
+        ClassWriter cw = new ClassWriter(0 /*flags*/);
+
+        String internalClassName = CLASS_WITH_STATIC_INIT_NAME.replace('.', '/');
+
+        HashSet<String> delegateMethods = new HashSet<>();
+        delegateMethods.add("<clinit>");
+        DelegateClassAdapter cv = new DelegateClassAdapter(
+                mLog, cw, internalClassName, delegateMethods);
+
+        ClassReader cr = new ClassReader(CLASS_WITH_STATIC_INIT_NAME);
+        cr.accept(cv, 0 /* flags */);
+
+        ClassLoader2 cl2 = null;
+        try {
+            cl2 = new ClassLoader2() {
+                @Override
+                public void testModifiedInstance() throws Exception {
+                    Class<?> clazz2 = loadClass(CLASS_WITH_STATIC_INIT_NAME);
+
+                    assertNull(clazz2.getField("sList").get(null));
+
+                    Class<?> delegateClass = loadClass(CLASS_WITH_STATIC_INIT_NAME + "_Delegate");
+                    assertNotNull( delegateClass.getField("sList").get(null));
+                }
+            };
+            cl2.add(CLASS_WITH_STATIC_INIT_NAME, cw);
+            cl2.testModifiedInstance();
+        } catch (Throwable t) {
+            throw dumpGeneratedClass(t, cl2);
+        }
+    }
+
+    @Test
+    public void testDelegateInnerClassStaticInitializer() throws Throwable {
+        ClassWriter cw = new ClassWriter(0 /*flags*/);
+
+        String internalClassName = INNER_CLASS_WITH_STATIC_INIT_NAME.replace('.', '/');
+
+        HashSet<String> delegateMethods = new HashSet<>();
+        delegateMethods.add("<clinit>");
+        DelegateClassAdapter cv = new DelegateClassAdapter(
+                mLog, cw, internalClassName, delegateMethods);
+
+        ClassReader cr = new ClassReader(INNER_CLASS_WITH_STATIC_INIT_NAME);
+        cr.accept(cv, 0 /* flags */);
+
+        ClassLoader2 cl2 = null;
+        try {
+            cl2 = new ClassLoader2() {
+                @Override
+                public void testModifiedInstance() throws Exception {
+                    Class<?> clazz2 = loadClass(INNER_CLASS_WITH_STATIC_INIT_NAME);
+
+                    assertNull(clazz2.getField("sInnerList").get(null));
+
+                    Class<?> delegateClass = loadClass(INNER_CLASS_WITH_STATIC_INIT_DELEGATE_NAME);
+                    assertNotNull( delegateClass.getField("sList").get(null));
+                }
+            };
+            cl2.add(INNER_CLASS_WITH_STATIC_INIT_NAME, cw);
+            cl2.testModifiedInstance();
+        } catch (Throwable t) {
+            throw dumpGeneratedClass(t, cl2);
+        }
+    }
+
+    @Test
     public void testDelegateNative() throws Throwable {
         ClassWriter cw = new ClassWriter(0 /*flags*/);
         String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
diff --git a/create/tests/src/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java b/create/tests/src/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java
index 928ac4d..1969b00 100644
--- a/create/tests/src/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java
+++ b/create/tests/src/com/android/tools/layoutlib/create/PromoteClassClassAdapterTest.java
@@ -162,7 +162,7 @@
         });
 
         reader.accept(adapter, 0);
-        assertTrue(log.mLog.contains("[visit] - version=52, access=[public], " +
+        assertTrue(log.mLog.contains("[visit] - version=53, access=[public], " +
                 "name=com/android/tools/layoutlib/create/PackageProtectedClass, signature=null, " +
                 "superName=java/lang/Object, interfaces=[]"));
 
diff --git a/create/tests/src/com/android/tools/layoutlib/create/dataclass/ClassWithStaticInit.java b/create/tests/src/com/android/tools/layoutlib/create/dataclass/ClassWithStaticInit.java
new file mode 100644
index 0000000..f5a78a9
--- /dev/null
+++ b/create/tests/src/com/android/tools/layoutlib/create/dataclass/ClassWithStaticInit.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+package com.android.tools.layoutlib.create.dataclass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClassWithStaticInit {
+
+    public static List<String> sList = new ArrayList<>();
+
+    public static class InnerClass {
+        public static List<String> sInnerList = new ArrayList<>();
+    }
+}
diff --git a/create/tests/src/com/android/tools/layoutlib/create/dataclass/ClassWithStaticInit_Delegate.java b/create/tests/src/com/android/tools/layoutlib/create/dataclass/ClassWithStaticInit_Delegate.java
new file mode 100644
index 0000000..3bc5491
--- /dev/null
+++ b/create/tests/src/com/android/tools/layoutlib/create/dataclass/ClassWithStaticInit_Delegate.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+package com.android.tools.layoutlib.create.dataclass;
+
+import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The delegate that receives the call to {@link ClassWithStaticInit}'s overridden methods.
+ *
+ * Used by {@link DelegateClassAdapterTest}.
+ */
+public class ClassWithStaticInit_Delegate {
+
+    public static List<String> sList = null;
+
+    public static void staticInit() {
+        sList = new ArrayList<>();
+    }
+}
diff --git a/create/tests/src/com/android/tools/layoutlib/create/dataclass/ClassWithStaticInit_InnerClass_Delegate.java b/create/tests/src/com/android/tools/layoutlib/create/dataclass/ClassWithStaticInit_InnerClass_Delegate.java
new file mode 100644
index 0000000..faa2956
--- /dev/null
+++ b/create/tests/src/com/android/tools/layoutlib/create/dataclass/ClassWithStaticInit_InnerClass_Delegate.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+package com.android.tools.layoutlib.create.dataclass;
+
+import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The delegate that receives the call to {@link ClassWithStaticInit$InnerClass}'s overridden
+ * methods.
+ *
+ * Used by {@link DelegateClassAdapterTest}.
+ */
+public class ClassWithStaticInit_InnerClass_Delegate {
+
+        public static List<String> sList = null;
+
+        public static void staticInit() {
+            sList = new ArrayList<>();
+        }
+}
diff --git a/delegates/Android.bp b/delegates/Android.bp
new file mode 100644
index 0000000..a7fad80
--- /dev/null
+++ b/delegates/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2008 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.
+//
+
+java_library_host {
+    name: "layoutlib-common-delegates",
+
+    srcs: ["src/**/*.java"],
+
+    libs: [
+        "temp_layoutlib",
+        "layoutlib-common",
+    ],
+
+}
diff --git a/delegates/README b/delegates/README
new file mode 100644
index 0000000..0ef28c6
--- /dev/null
+++ b/delegates/README
@@ -0,0 +1 @@
+The common set of delegates shared between layoutlib and simulated_device
\ No newline at end of file
diff --git a/delegates/delegates.iml b/delegates/delegates.iml
new file mode 100644
index 0000000..328c4b4
--- /dev/null
+++ b/delegates/delegates.iml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/tests/src" isTestSource="true" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="framework.jar" level="project" />
+    <orderEntry type="module" module-name="common" />
+    <orderEntry type="library" scope="TEST" name="junit" level="project" />
+    <orderEntry type="library" scope="TEST" name="truth-0.42" level="project" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/delegates/src/android/graphics/fonts/SystemFonts_Delegate.java b/delegates/src/android/graphics/fonts/SystemFonts_Delegate.java
new file mode 100644
index 0000000..92291cf
--- /dev/null
+++ b/delegates/src/android/graphics/fonts/SystemFonts_Delegate.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+package android.graphics.fonts;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.text.FontConfig;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Delegate implementing the native methods of android.graphics.fonts.SystemFonts
+ * <p>
+ * Through the layoutlib_create tool, the original native methods of SystemFonts have been
+ * replaced by calls to methods of the same name in this delegate class.
+ * <p>
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between it
+ * and the original SystemFonts class.
+ *
+ */
+public class SystemFonts_Delegate {
+
+    private static final String TAG = "SystemFonts_Delegate";
+    private static String sFontLocation;
+    public static boolean sIsTypefaceInitialized = false;
+
+    public static void setFontLocation(String fontLocation) {
+        sFontLocation = fontLocation;
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static FontConfig getSystemFontConfigInternal(
+            String fontsXml,
+            String systemFontDir,
+            String oemXml,
+            String productFontDir,
+            Map<String, File> updatableFontMap,
+            long lastModifiedDate,
+            int configVersion) {
+        sIsTypefaceInitialized = true;
+        return SystemFonts.getSystemFontConfigInternal_Original(
+            sFontLocation + "native/fonts.xml", sFontLocation, null, null, updatableFontMap,
+            lastModifiedDate, configVersion);
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static ByteBuffer mmap(@NonNull String fullPath) {
+        // Android does memory mapping for font files. But Windows keeps files open
+        // until the byte buffer from the memory mapping is garbage collected.
+        // To avoid that, on Windows, read the file into a byte buffer instead.
+        // See JDK-4715154.
+        String osName = System.getProperty("os.name").toLowerCase(Locale.US);
+        if (osName.startsWith("windows")) {
+            try (FileInputStream file = new FileInputStream(fullPath)) {
+                final FileChannel fileChannel = file.getChannel();
+                final int size = (int) fileChannel.size();
+                // Native code requires the ByteBuffer to be direct
+                // (see android/graphics/fonts/Font.cpp)
+                ByteBuffer buffer = ByteBuffer.allocateDirect(size);
+                fileChannel.read(buffer);
+                return buffer;
+            } catch (IOException e) {
+                Log.e(TAG, "Error mapping font file " + fullPath);
+                return null;
+            }
+        } else {
+            return SystemFonts.mmap_Original(fullPath);
+        }
+    }
+}
\ No newline at end of file
diff --git a/delegates/src/android/media/ImageReader_Delegate.java b/delegates/src/android/media/ImageReader_Delegate.java
new file mode 100644
index 0000000..0ff1ce7
--- /dev/null
+++ b/delegates/src/android/media/ImageReader_Delegate.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.media;
+
+public class ImageReader_Delegate {
+
+    static void nativeClassInit() {
+        // Call ImageReader.nativeClassInit(); in layoutlib implicitly before using ImageReader
+    }
+}
diff --git a/delegates/src/com/android/tools/layoutlib/java/nio/NIOAccess_Delegate.java b/delegates/src/com/android/tools/layoutlib/java/nio/NIOAccess_Delegate.java
new file mode 100644
index 0000000..c0653e6
--- /dev/null
+++ b/delegates/src/com/android/tools/layoutlib/java/nio/NIOAccess_Delegate.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package com.android.tools.layoutlib.java.nio;
+
+import java.nio.Buffer;
+
+/**
+ * A fork of libcore's java.nio.NIOAccess which does not exist in the JVM
+ *
+ * This class is used via JNI by code in frameworks/base/.
+ * @hide
+ */
+// @VisibleForTesting : was default
+public final class NIOAccess_Delegate {
+
+    /**
+     * Returns the underlying native pointer to the data of the given
+     * Buffer starting at the Buffer's current position, or 0 if the
+     * Buffer is not backed by native heap storage.
+     * @hide
+     */
+    // @VisibleForTesting : was default
+    public static long getBasePointer(Buffer b) {
+        throw new UnsupportedOperationException("implement me");
+//        long address = b.address;
+//        if (address == 0L) {
+//            return 0L;
+//        }
+//        return address + (b.position() << b._elementSizeShift);
+    }
+
+    /**
+     * Returns the underlying Java array containing the data of the
+     * given Buffer, or null if the Buffer is not backed by a Java array.
+     */
+    static Object getBaseArray(Buffer b) {
+        return b.hasArray() ? b.array() : null;
+    }
+
+    /**
+     * Returns the offset in bytes from the start of the underlying
+     * Java array object containing the data of the given Buffer to
+     * the actual start of the data. The start of the data takes into
+     * account the Buffer's current position. This method is only
+     * meaningful if getBaseArray() returns non-null.
+     */
+    static int getBaseArrayOffset(Buffer b) {
+        throw new UnsupportedOperationException("implement me");
+        //return b.hasArray() ? ((b.arrayOffset() + b.position()) << b._elementSizeShift) : 0;
+    }
+
+
+}
diff --git a/delegates/src/com/android/tools/layoutlib/java/text/DateFormat_Delegate.java b/delegates/src/com/android/tools/layoutlib/java/text/DateFormat_Delegate.java
new file mode 100644
index 0000000..cb72c2d
--- /dev/null
+++ b/delegates/src/com/android/tools/layoutlib/java/text/DateFormat_Delegate.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+package com.android.tools.layoutlib.java.text;
+
+import java.text.DateFormat;
+
+/**
+ * Provides alternate implementation to java.text.DateFormat.set24HourTimePref, which is present
+ * as a
+ * non-public method in the Android VM, but not present on the host VM. This is injected in the
+ * layoutlib using {@link ReplaceMethodCallsAdapter}.
+ */
+public class DateFormat_Delegate {
+
+    public static final void set24HourTimePref(Boolean is24Hour) {
+        // ignore
+    }
+}
diff --git a/delegates/src/com/android/tools/layoutlib/java/util/LocaleAdjustLanguageCodeReplacement.java b/delegates/src/com/android/tools/layoutlib/java/util/LocaleAdjustLanguageCodeReplacement.java
new file mode 100644
index 0000000..b335e86
--- /dev/null
+++ b/delegates/src/com/android/tools/layoutlib/java/util/LocaleAdjustLanguageCodeReplacement.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+package com.android.tools.layoutlib.java.util;
+
+import java.util.Locale;
+
+/**
+ * This class provides an alternate implementation for {@code java.util.Locale#adjustLanguageCode}
+ * which is not available in openJDK.
+ *
+ * The create tool re-writes references to the above mentioned method to this one. Hence it's
+ * imperative that this class is not deleted unless the create tool is modified.
+ */
+public class LocaleAdjustLanguageCodeReplacement {
+
+    public static String adjustLanguageCode(String languageCode) {
+        String adjusted = languageCode.toLowerCase(Locale.US);
+        // Map new language codes to the obsolete language
+        // codes so the correct resource bundles will be used.
+        if (languageCode.equals("he")) {
+            adjusted = "iw";
+        } else if (languageCode.equals("id")) {
+            adjusted = "in";
+        } else if (languageCode.equals("yi")) {
+            adjusted = "ji";
+        }
+
+        return adjusted;
+    }
+}
diff --git a/delegates/src/com/android/tools/layoutlib/java/util/zip/ZipEntry_Delegate.java b/delegates/src/com/android/tools/layoutlib/java/util/zip/ZipEntry_Delegate.java
new file mode 100644
index 0000000..4475fff
--- /dev/null
+++ b/delegates/src/com/android/tools/layoutlib/java/util/zip/ZipEntry_Delegate.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+package com.android.tools.layoutlib.java.util.zip;
+
+import java.util.zip.ZipEntry;
+
+/**
+ * Wrapper for calls to Android-added API to ZipEntry
+ */
+public class ZipEntry_Delegate extends ZipEntry {
+
+    private final long mDataOffset;
+
+    // Called from  StrictJarFile native code.
+    public ZipEntry_Delegate(String name, String comment, long crc, long compressedSize, long size,
+            int compressionMethod, int xdostime, byte[] extra, long dataOffset) {
+        super(name);
+        setComment(comment);
+        setCrc(crc);
+        setCompressedSize(compressedSize);
+        setSize(size);
+        setMethod(compressionMethod);
+        setTime(xdostime);
+        setExtra(extra);
+        mDataOffset = dataOffset;
+    }
+
+    /**
+     * Handle calls to the Android-added ZipEntry#getDataOffset.
+     *
+     * Called from StrictJarFile java code.
+     */
+    public static long getDataOffset(ZipEntry original) {
+        return ((ZipEntry_Delegate) original).mDataOffset;
+    }
+}
diff --git a/delegates/src/dalvik/system/VMRuntimeCommonHelper.java b/delegates/src/dalvik/system/VMRuntimeCommonHelper.java
new file mode 100644
index 0000000..ae63625
--- /dev/null
+++ b/delegates/src/dalvik/system/VMRuntimeCommonHelper.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package dalvik.system;
+
+/**
+ * Common VMRuntime Delegate code used by both layoutlib and simulated_device.
+ */
+class VMRuntimeCommonHelper {
+
+    // Copied from libcore/libdvm/src/main/java/dalvik/system/VMRuntime
+    /*package*/ static Object newUnpaddedArray(VMRuntime runtime, Class<?> componentType,
+            int minLength) {
+        // Dalvik has 32bit pointers, the array header is 16bytes plus 4bytes for dlmalloc,
+        // allocations are 8byte aligned so having 4bytes of array data avoids padding.
+        if (!componentType.isPrimitive()) {
+            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+            return java.lang.reflect.Array.newInstance(componentType, size);
+        } else if (componentType == char.class) {
+            int bytes = 20 + (2 * minLength);
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes / 2;
+            return new char[size];
+        } else if (componentType == int.class) {
+            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+            return new int[size];
+        } else if (componentType == byte.class) {
+            int bytes = 20 + minLength;
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes;
+            return new byte[size];
+        } else if (componentType == boolean.class) {
+            int bytes = 20 + minLength;
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes;
+            return new boolean[size];
+        } else if (componentType == short.class) {
+            int bytes = 20 + (2 * minLength);
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes / 2;
+            return new short[size];
+        } else if (componentType == float.class) {
+            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+            return new float[size];
+        } else if (componentType == long.class) {
+            return new long[minLength];
+        } else if (componentType == double.class) {
+            return new double[minLength];
+        } else {
+            assert componentType == void.class;
+            throw new IllegalArgumentException("Can't allocate an array of void");
+        }
+    }
+
+
+    /*package*/ static int getNotifyNativeInterval() {
+        // This cannot return 0, otherwise it is responsible for triggering an exception
+        // whenever trying to use a NativeAllocationRegistry with size 0
+        return 128; // see art/runtime/gc/heap.h -> kNotifyNativeInterval
+    }
+}
diff --git a/remote/common/src/com/android/layout/remote/api/RemoteLayoutLog.java b/remote/common/src/com/android/layout/remote/api/RemoteLayoutLog.java
index 335cf9d..8e09ece 100644
--- a/remote/common/src/com/android/layout/remote/api/RemoteLayoutLog.java
+++ b/remote/common/src/com/android/layout/remote/api/RemoteLayoutLog.java
@@ -73,10 +73,10 @@
     void error(String tag, String message, Throwable throwable, Object viewCookie, Serializable data)
             throws RemoteException;
 
-    /** 
-     * Logs messages coming from the Android Framework. 
+    /**
+     * Logs messages coming from the Android Framework.
      *
-     * @param priority the priority level of the message 
+     * @param priority the priority level of the message
      * @param tag a tag describing the type of the error
      * @param message the message of the error
      */