Merge "Rename android.os.Build so it can be dynamically generated"
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index df3ce19..04fdae9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -106,7 +106,7 @@
 import java.util.List;
 import java.util.Map;
 
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+import static android.os._Original_Build.VERSION_CODES.JELLY_BEAN_MR1;
 import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE;
 
 /**
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
index 5386b17..7f8d992 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
@@ -16,13 +16,13 @@
 
 package com.android.layoutlib.bridge.bars;
 
-import android.os.Build.VERSION_CODES;
+import android.os._Original_Build.VERSION_CODES;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import static android.os.Build.VERSION_CODES.*;
+import static android.os._Original_Build.VERSION_CODES.*;
 
 /**
  * Various helper methods to simulate older versions of platform.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index a6e5fb8..8bb2c59 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -49,7 +49,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-import static android.os.Build.VERSION_CODES.LOLLIPOP;
+import static android.os._Original_Build.VERSION_CODES.LOLLIPOP;
 
 /**
  * Base "bar" class for the window decor around the the edited layout.
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index bed5806a..d59b419 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -37,6 +37,7 @@
 import java.util.jar.JarEntry;
 import java.util.jar.JarOutputStream;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * Class that generates a new JAR from a list of classes, some of which are to be kept as-is
@@ -127,7 +128,10 @@
         // Create the map of classes to rename.
         mRenameClasses = new HashMap<>();
         mClassesNotRenamed = new HashSet<>();
-        String[] renameClasses = createInfo.getRenamedClasses();
+        String[] renameClasses = Stream.concat(
+                Arrays.stream(createInfo.getRenamedClasses()),
+                Arrays.stream(createInfo.getRefactoredClasses()))
+                .toArray(String[]::new);
         int n = renameClasses.length;
         for (int i = 0; i < n; i += 2) {
             assert i + 1 < n;
@@ -140,7 +144,10 @@
 
         // Create a map of classes to be refactored.
         mRefactorClasses = new HashMap<>();
-        String[] refactorClasses = createInfo.getJavaPkgClasses();
+        String[] refactorClasses = Stream.concat(
+                Arrays.stream(createInfo.getJavaPkgClasses()),
+                Arrays.stream(createInfo.getRefactoredClasses()))
+                .toArray(String[]::new);
         n = refactorClasses.length;
         for (int i = 0; i < n; i += 2) {
             assert i + 1 < n;
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index a8582c6..b0aa3c2 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -36,66 +36,42 @@
  */
 public final class CreateInfo implements ICreateInfo {
 
-    /**
-     * Returns the list of class from layoutlib_create to inject in layoutlib.
-     * The list can be empty but must not be null.
-     */
     @Override
     public Class<?>[] getInjectedClasses() {
         return INJECTED_CLASSES;
     }
 
-    /**
-     * Returns the list of methods to rewrite as delegates.
-     * The list can be empty but must not be null.
-     */
     @Override
     public String[] getDelegateMethods() {
         return DELEGATE_METHODS;
     }
 
-    /**
-     * Returns the list of classes on which to delegate all native methods.
-     * The list can be empty but must not be null.
-     */
     @Override
     public String[] getDelegateClassNatives() {
         return DELEGATE_CLASS_NATIVES;
     }
 
-    /**
-     * 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.
-     */
     @Override
     public String[] getRenamedClasses() {
         return RENAMED_CLASSES;
     }
 
-    /**
-     * Returns the list of classes for which the methods returning them should be deleted.
-     * The array contains a list of null terminated section starting with the name of the class
-     * to rename in which the methods are deleted, followed by a list of return types identifying
-     * the methods to delete.
-     * The list can be empty but must not be null.
-     */
     @Override
     public String[] getDeleteReturns() {
         return DELETE_RETURNS;
     }
 
-    /**
-     * Returns the list of classes to refactor, must be an even list: the binary FQCN of class to
-     * replace followed by the new FQCN. All references to the old class should be updated to the
-     * new class. The list can be empty but must not be null.
-     */
     @Override
     public String[] getJavaPkgClasses() {
       return JAVA_PKG_CLASSES;
     }
 
     @Override
+    public String[] getRefactoredClasses() {
+        return REFACTOR_CLASSES;
+    }
+
+    @Override
     public Set<String> getExcludedClasses() {
         String[] refactoredClasses = getJavaPkgClasses();
         int count = refactoredClasses.length / 2 + EXCLUDED_CLASSES.length;
@@ -333,10 +309,22 @@
             "java.text.SimpleDateFormat",                      "android.icu.text.SimpleDateFormat",
         };
 
+    /**
+     * List of classes to refactor. This is similar to combining {@link #getRenamedClasses()} and
+     * {@link #getJavaPkgClasses()}.
+     * Classes included here will be renamed and then all their references in any other classes
+     * will be also modified.
+     * FQCN of class to refactor followed by its new FQCN.
+     */
+    private final static String[] REFACTOR_CLASSES =
+            new String[] {
+                    "android.os.Build",                                "android.os._Original_Build",
+            };
+
     private final static String[] EXCLUDED_CLASSES =
         new String[] {
             "android.preference.PreferenceActivity",
-            "org.kxml2.io.KXmlParser"
+            "org.kxml2.io.KXmlParser",
         };
 
     /**
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
index 48abde4..eca1c07 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
@@ -52,6 +52,15 @@
     String[] getRenamedClasses();
 
     /**
+     * List of classes to refactor. This is similar to combining {@link #getRenamedClasses()} and
+     * {@link #getJavaPkgClasses()}.
+     * Classes included here will be renamed and then all their references in any other classes
+     * will be also modified.
+     * FQCN of class to refactor followed by its new FQCN.
+     */
+    String[] getRefactoredClasses();
+
+    /**
      * Returns the list of classes for which the methods returning them should be deleted.
      * The array contains a list of null terminated section starting with the name of the class
      * to rename in which the methods are deleted, followed by a list of return types identifying
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 4d5d5d2..e718fb9 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -35,6 +35,7 @@
 import java.lang.reflect.Method;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
@@ -54,8 +55,6 @@
  * Unit tests for some methods of {@link AsmGenerator}.
  */
 public class AsmGeneratorTest {
-
-    private static final String[] EMPTY_STRING_ARRAY = new String[0];
     private MockLog mLog;
     private ArrayList<String> mOsJarPath;
     private String mOsDestJar;
@@ -81,6 +80,7 @@
     @After
     public void tearDown() throws Exception {
         if (mTempFile != null) {
+            //noinspection ResultOfMethodCallIgnored
             mTempFile.delete();
             mTempFile = null;
         }
@@ -89,23 +89,7 @@
     @Test
     public void testClassRenaming() throws IOException, LogAbortException {
 
-        ICreateInfo ci = new ICreateInfo() {
-            @Override
-            public Class<?>[] getInjectedClasses() {
-                // classes to inject in the final JAR
-                return new Class<?>[0];
-            }
-
-            @Override
-            public String[] getDelegateMethods() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getDelegateClassNatives() {
-                return EMPTY_STRING_ARRAY;
-            }
-
+        ICreateInfo ci = new CreateInfoAdapter() {
             @Override
             public String[] getRenamedClasses() {
                 // classes to rename (so that we can replace them)
@@ -114,37 +98,6 @@
                         "not.an.actual.ClassName", "anoter.fake.NewClassName",
                 };
             }
-
-            @Override
-            public String[] getJavaPkgClasses() {
-              return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public Set<String> getExcludedClasses() {
-                return null;
-            }
-
-            @Override
-            public String[] getDeleteReturns() {
-                 // methods deleted from their return type.
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getPromotedFields() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getPromotedClasses() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
-                return Collections.emptyMap();
-            }
         };
 
         AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -154,7 +107,7 @@
                 new String[] {        // include classes
                     "**"
                 },
-                Collections.<String>emptySet() /* excluded classes */,
+                Collections.emptySet() /* excluded classes */,
                 new String[]{} /* include files */);
         aa.analyze();
         agen.generate();
@@ -165,8 +118,8 @@
     }
 
     @Test
-    public void testClassRefactoring() throws IOException, LogAbortException {
-        ICreateInfo ci = new ICreateInfo() {
+    public void testJavaClassRefactoring() throws IOException, LogAbortException {
+        ICreateInfo ci = new CreateInfoAdapter() {
             @Override
             public Class<?>[] getInjectedClasses() {
                 // classes to inject in the final JAR
@@ -176,22 +129,6 @@
             }
 
             @Override
-            public String[] getDelegateMethods() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getDelegateClassNatives() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getRenamedClasses() {
-                // classes to rename (so that we can replace them)
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
             public String[] getJavaPkgClasses() {
              // classes to refactor (so that we can replace them)
                 return new String[] {
@@ -203,27 +140,6 @@
             public Set<String> getExcludedClasses() {
                 return Collections.singleton("java.lang.JavaClass");
             }
-
-            @Override
-            public String[] getDeleteReturns() {
-                 // methods deleted from their return type.
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getPromotedFields() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getPromotedClasses() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
-                return Collections.emptyMap();
-            }
         };
 
         AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -233,7 +149,7 @@
                 new String[] {        // include classes
                     "**"
                 },
-                Collections.<String>emptySet(),
+                Collections.emptySet(),
                 new String[] {        /* include files */
                     "mock_android/data/data*"
                 });
@@ -242,47 +158,64 @@
         Map<String, ClassReader> output = new TreeMap<>();
         Map<String, InputStream> filesFound = new TreeMap<>();
         parseZip(mOsDestJar, output, filesFound);
-        boolean injectedClassFound = false;
+        RecordingClassVisitor cv = new RecordingClassVisitor();
         for (ClassReader cr: output.values()) {
-            TestClassVisitor cv = new TestClassVisitor();
             cr.accept(cv, 0);
-            injectedClassFound |= cv.mInjectedClassFound;
         }
-        assertTrue(injectedClassFound);
+        assertTrue(cv.mVisitedClasses.contains(
+                "com/android/tools/layoutlib/create/dataclass/JavaClass"));
+        assertFalse(cv.mVisitedClasses.contains(
+                JAVA_CLASS_NAME));
         assertArrayEquals(new String[] {"mock_android/data/dataFile"},
                 filesFound.keySet().toArray());
     }
 
     @Test
-    public void testClassExclusion() throws IOException, LogAbortException {
-        ICreateInfo ci = new ICreateInfo() {
+    public void testClassRefactoring() throws IOException, LogAbortException {
+        ICreateInfo ci = new CreateInfoAdapter() {
             @Override
             public Class<?>[] getInjectedClasses() {
-                return new Class<?>[0];
+                // classes to inject in the final JAR
+                return new Class<?>[] {
+                        com.android.tools.layoutlib.create.dataclass.JavaClass.class
+                };
             }
 
             @Override
-            public String[] getDelegateMethods() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getDelegateClassNatives() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getRenamedClasses() {
-                // classes to rename (so that we can replace them)
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getJavaPkgClasses() {
+            public String[] getRefactoredClasses() {
                 // classes to refactor (so that we can replace them)
-                return EMPTY_STRING_ARRAY;
+                return new String[] {
+                        "mock_android.view.View", "mock_android.view._Original_View",
+                };
             }
+        };
 
+        AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
+
+        AsmAnalyzer aa = new AsmAnalyzer(mLog, mOsJarPath, agen,
+                null,                 // derived from
+                new String[] {        // include classes
+                        "**"
+                },
+                Collections.emptySet(),
+                new String[] {});
+        aa.analyze();
+        agen.generate();
+        Map<String, ClassReader> output = new TreeMap<>();
+        parseZip(mOsDestJar, output, new TreeMap<>());
+        RecordingClassVisitor cv = new RecordingClassVisitor();
+        for (ClassReader cr: output.values()) {
+            cr.accept(cv, 0);
+        }
+        assertTrue(cv.mVisitedClasses.contains(
+                "mock_android/view/_Original_View"));
+        assertFalse(cv.mVisitedClasses.contains(
+                "mock_android/view/View"));
+    }
+
+    @Test
+    public void testClassExclusion() throws IOException, LogAbortException {
+        ICreateInfo ci = new CreateInfoAdapter() {
             @Override
             public Set<String> getExcludedClasses() {
                 Set<String> set = new HashSet<>(2);
@@ -290,27 +223,6 @@
                 set.add("java.lang.JavaClass");
                 return set;
             }
-
-            @Override
-            public String[] getDeleteReturns() {
-                // methods deleted from their return type.
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getPromotedFields() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getPromotedClasses() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
-                return Collections.emptyMap();
-            }
         };
 
         AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -340,55 +252,7 @@
     public void testMethodInjection() throws IOException, LogAbortException,
             ClassNotFoundException, IllegalAccessException, InstantiationException,
             NoSuchMethodException, InvocationTargetException {
-        ICreateInfo ci = new ICreateInfo() {
-            @Override
-            public Class<?>[] getInjectedClasses() {
-                return new Class<?>[0];
-            }
-
-            @Override
-            public String[] getDelegateMethods() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getDelegateClassNatives() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getRenamedClasses() {
-                // classes to rename (so that we can replace them)
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getJavaPkgClasses() {
-                // classes to refactor (so that we can replace them)
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public Set<String> getExcludedClasses() {
-                return Collections.emptySet();
-            }
-
-            @Override
-            public String[] getDeleteReturns() {
-                // methods deleted from their return type.
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getPromotedFields() {
-                return EMPTY_STRING_ARRAY;
-            }
-
-            @Override
-            public String[] getPromotedClasses() {
-                return EMPTY_STRING_ARRAY;
-            }
-
+        ICreateInfo ci = new CreateInfoAdapter() {
             @Override
             public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
                 return Collections.singletonMap("mock_android.util.EmptyArray",
@@ -474,97 +338,94 @@
         }
     }
 
-    private class TestClassVisitor extends ClassVisitor {
+    /**
+     * {@link ClassVisitor} that records every class that sees.
+     */
+    private static class RecordingClassVisitor extends ClassVisitor {
+        private Set<String> mVisitedClasses = new HashSet<>();
 
-        boolean mInjectedClassFound = false;
-
-        TestClassVisitor() {
+        private RecordingClassVisitor() {
             super(Main.ASM_VERSION);
         }
 
-        @Override
-        public void visit(int version, int access, String name, String signature,
-                String superName, String[] interfaces) {
-            assertTrue(!getBase(name).equals(JAVA_CLASS_NAME));
-            if (name.equals("com/android/tools/layoutlib/create/dataclass/JavaClass")) {
-                mInjectedClassFound = true;
+        private void addClass(String className) {
+            if (className == null) {
+                return;
             }
-            super.visit(version, access, name, signature, superName, interfaces);
+
+            int pos = className.indexOf('$');
+            if (pos > 0) {
+                // For inner classes, add also the base class
+                mVisitedClasses.add(className.substring(0, pos));
+            }
+            mVisitedClasses.add(className);
         }
 
         @Override
-        public FieldVisitor visitField(int access, String name, String desc,
-                String signature, Object value) {
-            assertTrue(testType(Type.getType(desc)));
+        public void visit(int version, int access, String name, String signature, String superName,
+                String[] interfaces) {
+            addClass(superName);
+            Arrays.stream(interfaces).forEach(this::addClass);
+        }
+
+        private void processType(Type type) {
+            switch (type.getSort()) {
+                case Type.OBJECT:
+                    addClass(type.getInternalName());
+                    break;
+                case Type.ARRAY:
+                    addClass(type.getElementType().getInternalName());
+                    break;
+                case Type.METHOD:
+                    processType(type.getReturnType());
+                    Arrays.stream(type.getArgumentTypes()).forEach(this::processType);
+                    break;
+            }
+        }
+
+        @Override
+        public FieldVisitor visitField(int access, String name, String desc, String signature,
+                Object value) {
+            processType(Type.getType(desc));
             return super.visitField(access, name, desc, signature, value);
         }
 
-        @SuppressWarnings("hiding")
         @Override
-        public MethodVisitor visitMethod(int access, String name, String desc,
-                String signature, String[] exceptions) {
+        public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+                String[] exceptions) {
             MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
             return new MethodVisitor(Main.ASM_VERSION, mv) {
 
                 @Override
-                public void visitFieldInsn(int opcode, String owner, String name,
-                        String desc) {
-                    assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME));
-                    assertTrue(testType(Type.getType(desc)));
+                public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+                    addClass(owner);
+                    processType(Type.getType(desc));
                     super.visitFieldInsn(opcode, owner, name, desc);
                 }
 
                 @Override
                 public void visitLdcInsn(Object cst) {
                     if (cst instanceof Type) {
-                        assertTrue(testType((Type)cst));
+                        processType((Type) cst);
                     }
                     super.visitLdcInsn(cst);
                 }
 
                 @Override
                 public void visitTypeInsn(int opcode, String type) {
-                    assertTrue(!getBase(type).equals(JAVA_CLASS_NAME));
+                    addClass(type);
                     super.visitTypeInsn(opcode, type);
                 }
 
                 @Override
-                public void visitMethodInsn(int opcode, String owner, String name,
-                        String desc, boolean itf) {
-                    assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME));
-                    assertTrue(testType(Type.getType(desc)));
+                public void visitMethodInsn(int opcode, String owner, String name, String desc,
+                        boolean itf) {
+                    addClass(owner);
+                    processType(Type.getType(desc));
                     super.visitMethodInsn(opcode, owner, name, desc, itf);
                 }
 
             };
         }
-
-        private boolean testType(Type type) {
-            int sort = type.getSort();
-            if (sort == Type.OBJECT) {
-                assertTrue(!getBase(type.getInternalName()).equals(JAVA_CLASS_NAME));
-            } else if (sort == Type.ARRAY) {
-                assertTrue(!getBase(type.getElementType().getInternalName())
-                        .equals(JAVA_CLASS_NAME));
-            } else if (sort == Type.METHOD) {
-                boolean r = true;
-                for (Type t : type.getArgumentTypes()) {
-                    r &= testType(t);
-                }
-                return r & testType(type.getReturnType());
-            }
-            return true;
-        }
-
-        private String getBase(String className) {
-            if (className == null) {
-                return null;
-            }
-            int pos = className.indexOf('$');
-            if (pos > 0) {
-                return className.substring(0, pos);
-            }
-            return className;
-        }
     }
 }
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java
new file mode 100644
index 0000000..ad7cb9a
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java
@@ -0,0 +1,80 @@
+/*
+ * 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.create;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+class CreateInfoAdapter implements ICreateInfo {
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    @Override
+    public Class<?>[] getInjectedClasses() {
+        return new Class<?>[0];
+    }
+
+    @Override
+    public String[] getDelegateMethods() {
+        return EMPTY_STRING_ARRAY;
+    }
+
+    @Override
+    public String[] getDelegateClassNatives() {
+        return EMPTY_STRING_ARRAY;
+    }
+
+    @Override
+    public String[] getRenamedClasses() {
+        return EMPTY_STRING_ARRAY;
+    }
+
+    @Override
+    public String[] getRefactoredClasses() {
+        return EMPTY_STRING_ARRAY;
+    }
+
+    @Override
+    public String[] getDeleteReturns() {
+        return EMPTY_STRING_ARRAY;
+    }
+
+    @Override
+    public String[] getJavaPkgClasses() {
+        return EMPTY_STRING_ARRAY;
+    }
+
+    @Override
+    public Set<String> getExcludedClasses() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public String[] getPromotedFields() {
+        return EMPTY_STRING_ARRAY;
+    }
+
+    @Override
+    public String[] getPromotedClasses() {
+        return EMPTY_STRING_ARRAY;
+    }
+
+    @Override
+    public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
+        return Collections.emptyMap();
+    }
+}