Merge "Optimize layout rendering in layoutlib [DO NOT MERGE]" into jb-mr2-dev
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 19aa0f8..1e62dcd 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3265,8 +3265,9 @@
}
final boolean showWhenLocked = (attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0;
+ final boolean dismissKeyguard = (attrs.flags & FLAG_DISMISS_KEYGUARD) != 0;
if (appWindow) {
- if (showWhenLocked) {
+ if (showWhenLocked || (dismissKeyguard && !isKeyguardSecure())) {
mAppsToBeHidden.remove(win.getAppToken());
} else {
mAppsToBeHidden.add(win.getAppToken());
@@ -3282,8 +3283,7 @@
mHideLockScreen = true;
mForceStatusBarFromKeyguard = false;
}
- if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0
- && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
+ if (dismissKeyguard && mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mDismissKeyguard true by win " + win);
mDismissKeyguard = mWinDismissingKeyguard == win ?
DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START;
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index b27ce0e..12acb09 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -31,6 +31,11 @@
built_core_dep := $(call java-lib-deps,core)
built_core_classes := $(call java-lib-files,core)
+built_ext_dep := $(call java-lib-deps,ext)
+built_ext_classes := $(call java-lib-files,ext)
+built_ext_data := $(call intermediates-dir-for, \
+ JAVA_LIBRARIES,ext,,COMMON)/javalib.jar
+
built_layoutlib_create_jar := $(call intermediates-dir-for, \
JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
@@ -47,6 +52,7 @@
$(LOCAL_BUILT_MODULE): $(built_core_dep) \
$(built_framework_dep) \
+ $(built_ext_dep) \
$(built_layoutlib_create_jar)
$(hide) echo "host layoutlib_create: $@"
$(hide) mkdir -p $(dir $@)
@@ -55,7 +61,9 @@
$(hide) java -jar $(built_layoutlib_create_jar) \
$@ \
$(built_core_classes) \
- $(built_framework_classes)
+ $(built_framework_classes) \
+ $(built_ext_classes) \
+ $(built_ext_data)
$(hide) ls -l $(built_framework_classes)
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index be27b54..390044a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -159,7 +159,7 @@
/*package*/ static void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance,
byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) {
draw(canvas_instance,
- (int) loc.left, (int) loc.top, (int) loc.width(), (int) loc.height(),
+ (int) loc.left, (int) loc.top, (int) loc.right, (int) loc.bottom,
bitmap_instance, c, paint_instance_or_null,
destDensity, srcDensity);
}
@@ -168,7 +168,7 @@
/*package*/ static void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) {
draw(canvas_instance,
- loc.left, loc.top, loc.width(), loc.height(),
+ loc.left, loc.top, loc.right, loc.bottom,
bitmap_instance, c, paint_instance_or_null,
destDensity, srcDensity);
}
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 17b0eb6..bcd08eb4 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
@@ -290,7 +290,7 @@
TypedValue out = new TypedValue();
if (ResourceHelper.parseFloatAttribute("textSize", textSize.getValue(), out,
true /*requireUnit*/)) {
- textView.setTextSize(
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
out.getDimension(bridgeContext.getResources().getDisplayMetrics()));
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 87047b3..60f5331 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -248,11 +248,16 @@
* The counterpart is {@link #setUp()}.
*/
private void tearDown() {
- // Make sure to remove static references, otherwise we could not unload the lib
- mContext.disposeResources();
+ // The context may be null, if there was an error during init().
+ if (mContext != null) {
+ // Make sure to remove static references, otherwise we could not unload the lib
+ mContext.disposeResources();
+ }
- // quit HandlerThread created during this session.
- HandlerThread_Delegate.cleanUp(sCurrentContext);
+ if (sCurrentContext != null) {
+ // quit HandlerThread created during this session.
+ HandlerThread_Delegate.cleanUp(sCurrentContext);
+ }
// clear the stored ViewConfiguration since the map is per density and not per context.
ViewConfiguration_Accessor.clearConfigurations();
@@ -263,8 +268,11 @@
sCurrentContext = null;
Bridge.setLog(null);
- mContext.getRenderResources().setFrameworkResourceIdProvider(null);
- mContext.getRenderResources().setLogger(null);
+ if (mContext != null) {
+ mContext.getRenderResources().setFrameworkResourceIdProvider(null);
+ mContext.getRenderResources().setLogger(null);
+ }
+
}
public static BridgeContext getCurrentContext() {
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index 294d743..06ae804 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -17,6 +17,8 @@
package libcore.icu;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.ibm.icu.text.DateTimePatternGenerator;
+import com.ibm.icu.util.ULocale;
import java.util.Locale;
@@ -45,7 +47,8 @@
@LayoutlibDelegate
/*package*/ static String getBestDateTimePattern(String skeleton, String localeName) {
- return ""; // TODO: check what the right value should be.
+ return DateTimePatternGenerator.getInstance(new ULocale(localeName))
+ .getBestPattern(skeleton);
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
index 1572a40..9a31705 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java
@@ -29,6 +29,7 @@
import org.objectweb.asm.signature.SignatureVisitor;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
@@ -60,6 +61,9 @@
private final String[] mIncludeGlobs;
/** The set of classes to exclude.*/
private final Set<String> mExcludedClasses;
+ /** Glob patterns of files to keep as is. */
+ private final String[] mIncludeFileGlobs;
+ /** Copy these files into the output as is. */
/**
* Creates a new analyzer.
@@ -70,15 +74,19 @@
* @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)
+ * @param includeFileGlobs Glob patterns of files which are kept as is. This is only for files
+ * not ending in .class.
*/
public AsmAnalyzer(Log log, List<String> osJarPath, AsmGenerator gen,
- String[] deriveFrom, String[] includeGlobs, Set<String> excludeClasses) {
+ String[] deriveFrom, String[] includeGlobs, Set<String> excludeClasses,
+ String[] includeFileGlobs) {
mLog = log;
mGen = gen;
mOsSourceJar = osJarPath != null ? osJarPath : new ArrayList<String>();
mDeriveFrom = deriveFrom != null ? deriveFrom : new String[0];
mIncludeGlobs = includeGlobs != null ? includeGlobs : new String[0];
mExcludedClasses = excludeClasses;
+ mIncludeFileGlobs = includeFileGlobs != null ? includeFileGlobs : new String[0];
}
/**
@@ -86,7 +94,11 @@
* Fills the generator with classes & dependencies found.
*/
public void analyze() throws IOException, LogAbortException {
- Map<String, ClassReader> zipClasses = parseZip(mOsSourceJar);
+
+ TreeMap<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ parseZip(mOsSourceJar, zipClasses, filesFound);
mLog.info("Found %d classes in input JAR%s.", zipClasses.size(),
mOsSourceJar.size() > 1 ? "s" : "");
@@ -96,15 +108,29 @@
if (mGen != null) {
mGen.setKeep(found);
mGen.setDeps(deps);
+ mGen.setCopyFiles(filesFound);
}
}
/**
- * Parses a JAR file and returns a list of all classes founds using a map
- * class name => ASM ClassReader. Class names are in the form "android.view.View".
+ * Parses a JAR file and adds all the classes found to <code>classes</code>
+ * and all other files to <code>filesFound</code>.
+ *
+ * @param classes The map of class name => ASM ClassReader. Class names are
+ * in the form "android.view.View".
+ * @param fileFound The map of file name => InputStream. The file name is
+ * in the form "android/data/dataFile".
*/
- Map<String,ClassReader> parseZip(List<String> jarPathList) throws IOException {
- TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
+ void parseZip(List<String> jarPathList, Map<String, ClassReader> classes,
+ Map<String, InputStream> filesFound) throws IOException {
+ if (classes == null || filesFound == null) {
+ return;
+ }
+
+ Pattern[] includeFilePatterns = new Pattern[mIncludeFileGlobs.length];
+ for (int i = 0; i < mIncludeFileGlobs.length; ++i) {
+ includeFilePatterns[i] = getPatternFromGlob(mIncludeFileGlobs[i]);
+ }
for (String jarPath : jarPathList) {
ZipFile zip = new ZipFile(jarPath);
@@ -116,11 +142,17 @@
ClassReader cr = new ClassReader(zip.getInputStream(entry));
String className = classReaderToClassName(cr);
classes.put(className, cr);
+ } else {
+ for (int i = 0; i < includeFilePatterns.length; ++i) {
+ if (includeFilePatterns[i].matcher(entry.getName()).matches()) {
+ filesFound.put(entry.getName(), zip.getInputStream(entry));
+ break;
+ }
+ }
}
}
}
- return classes;
}
/**
@@ -202,7 +234,19 @@
*/
void findGlobs(String globPattern, Map<String, ClassReader> zipClasses,
Map<String, ClassReader> inOutFound) throws LogAbortException {
- // transforms the glob pattern in a regexp:
+
+ Pattern regexp = getPatternFromGlob(globPattern);
+
+ for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
+ String class_name = entry.getKey();
+ if (regexp.matcher(class_name).matches()) {
+ findClass(class_name, zipClasses, inOutFound);
+ }
+ }
+ }
+
+ Pattern getPatternFromGlob(String globPattern) {
+ // transforms the glob pattern in a regexp:
// - escape "." with "\."
// - replace "*" by "[^.]*"
// - escape "$" with "\$"
@@ -216,14 +260,7 @@
globPattern = globPattern.replaceAll("@", ".*");
globPattern += "$";
- Pattern regexp = Pattern.compile(globPattern);
-
- for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
- String class_name = entry.getKey();
- if (regexp.matcher(class_name).matches()) {
- findClass(class_name, zipClasses, inOutFound);
- }
- }
+ return Pattern.compile(globPattern);
}
/**
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 b102561..207d8ae 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
@@ -20,6 +20,7 @@
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
+import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -52,6 +53,8 @@
private Map<String, ClassReader> mKeep;
/** All dependencies that must be completely stubbed. */
private Map<String, ClassReader> mDeps;
+ /** All files that are to be copied as-is. */
+ private Map<String, InputStream> mCopyFiles;
/** Counter of number of classes renamed during transform. */
private int mRenameCount;
/** FQCN Names of the classes to rename: map old-FQCN => new-FQCN */
@@ -195,6 +198,11 @@
mDeps = deps;
}
+ /** Sets the map of files to output as-is. */
+ public void setCopyFiles(Map<String, InputStream> copyFiles) {
+ mCopyFiles = copyFiles;
+ }
+
/** Gets the map of classes to output as-is, except if they have native methods */
public Map<String, ClassReader> getKeep() {
return mKeep;
@@ -205,6 +213,11 @@
return mDeps;
}
+ /** Gets the map of files to output as-is. */
+ public Map<String, InputStream> getCopyFiles() {
+ return mCopyFiles;
+ }
+
/** Generates the final JAR */
public void generate() throws FileNotFoundException, IOException {
TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
@@ -232,6 +245,15 @@
all.put(name, b);
}
+ for (Entry<String, InputStream> entry : mCopyFiles.entrySet()) {
+ try {
+ byte[] b = inputStreamToByteArray(entry.getValue());
+ all.put(entry.getKey(), b);
+ } catch (IOException e) {
+ // Ignore.
+ }
+
+ }
mLog.info("# deps classes: %d", mDeps.size());
mLog.info("# keep classes: %d", mKeep.size());
mLog.info("# renamed : %d", mRenameCount);
@@ -381,4 +403,13 @@
return cv.hasNativeMethods();
}
+ private byte[] inputStreamToByteArray(InputStream is) throws IOException {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ byte[] data = new byte[8192]; // 8KB
+ int n;
+ while ((n = is.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, n);
+ }
+ return buffer.toByteArray();
+ }
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index ba23048..a79fba1 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -113,8 +113,12 @@
"android.pim.*", // for datepicker
"android.os.*", // for android.os.Handler
"android.database.ContentObserver", // for Digital clock
+ "com.android.i18n.phonenumbers.*", // for TextView with autolink attribute
},
- excludeClasses);
+ excludeClasses,
+ new String[] {
+ "com/android/i18n/phonenumbers/data/*",
+ });
aa.analyze();
agen.generate();
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
index 005fc9d..7ec0d38 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
@@ -29,6 +29,7 @@
import org.objectweb.asm.ClassReader;
import java.io.IOException;
+import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
@@ -55,8 +56,10 @@
Set<String> excludeClasses = new HashSet<String>(1);
excludeClasses.add("java.lang.JavaClass");
- mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */,
- null /* deriveFrom */, null /* includeGlobs */, excludeClasses);
+
+ String[] includeFiles = new String[]{"mock_android/data/data*"};
+ mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */, null /* deriveFrom */,
+ null /* includeGlobs */, excludeClasses, includeFiles);
}
@After
@@ -65,7 +68,11 @@
@Test
public void testParseZip() throws IOException {
- Map<String, ClassReader> map = mAa.parseZip(mOsJarPath);
+
+ Map<String, ClassReader> map = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ mAa.parseZip(mOsJarPath, map, filesFound);
assertArrayEquals(new String[] {
"java.lang.JavaClass",
@@ -86,11 +93,17 @@
"mock_android.widget.TableLayout$LayoutParams"
},
map.keySet().toArray());
+ assertArrayEquals(new String[] {"mock_android/data/dataFile"},
+ filesFound.keySet().toArray());
}
@Test
public void testFindClass() throws IOException, LogAbortException {
- Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+ Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ mAa.parseZip(mOsJarPath, zipClasses, filesFound);
TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
ClassReader cr = mAa.findClass("mock_android.view.ViewGroup$LayoutParams",
@@ -105,7 +118,11 @@
@Test
public void testFindGlobs() throws IOException, LogAbortException {
- Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+ Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ mAa.parseZip(mOsJarPath, zipClasses, filesFound);
TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
// this matches classes, a package match returns nothing
@@ -164,7 +181,11 @@
@Test
public void testFindClassesDerivingFrom() throws LogAbortException, IOException {
- Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+ Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ mAa.parseZip(mOsJarPath, zipClasses, filesFound);
TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>();
mAa.findClassesDerivingFrom("mock_android.view.View", zipClasses, found);
@@ -186,7 +207,11 @@
@Test
public void testDependencyVisitor() throws IOException, LogAbortException {
- Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
+
+ Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+
+ mAa.parseZip(mOsJarPath, zipClasses, filesFound);
TreeMap<String, ClassReader> keep = new TreeMap<String, ClassReader>();
TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>();
TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>();
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 8a27173..0dbc238 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
@@ -33,6 +33,7 @@
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
@@ -131,7 +132,8 @@
new String[] { // include classes
"**"
},
- new HashSet<String>(0) /* excluded classes */);
+ new HashSet<String>(0) /* excluded classes */,
+ new String[]{} /* include files */);
aa.analyze();
agen.generate();
@@ -195,10 +197,15 @@
new String[] { // include classes
"**"
},
- new HashSet<String>(1));
+ new HashSet<String>(1),
+ new String[] { /* include files */
+ "mock_android/data/data*"
+ });
aa.analyze();
agen.generate();
- Map<String, ClassReader> output = parseZip(mOsDestJar);
+ Map<String, ClassReader> output = new TreeMap<String, ClassReader>();
+ Map<String, InputStream> filesFound = new TreeMap<String, InputStream>();
+ parseZip(mOsDestJar, output, filesFound);
boolean injectedClassFound = false;
for (ClassReader cr: output.values()) {
TestClassVisitor cv = new TestClassVisitor();
@@ -206,10 +213,13 @@
injectedClassFound |= cv.mInjectedClassFound;
}
assertTrue(injectedClassFound);
+ assertArrayEquals(new String[] {"mock_android/data/dataFile"},
+ filesFound.keySet().toArray());
}
- private Map<String,ClassReader> parseZip(String jarPath) throws IOException {
- TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
+ private void parseZip(String jarPath,
+ Map<String, ClassReader> classes,
+ Map<String, InputStream> filesFound) throws IOException {
ZipFile zip = new ZipFile(jarPath);
Enumeration<? extends ZipEntry> entries = zip.entries();
@@ -220,10 +230,11 @@
ClassReader cr = new ClassReader(zip.getInputStream(entry));
String className = classReaderToClassName(cr);
classes.put(className, cr);
+ } else {
+ filesFound.put(entry.getName(), zip.getInputStream(entry));
}
}
- return classes;
}
private String classReaderToClassName(ClassReader classReader) {
diff --git a/tools/layoutlib/create/tests/data/mock_android.jar b/tools/layoutlib/create/tests/data/mock_android.jar
index 60d8efb..8dd0481 100644
--- a/tools/layoutlib/create/tests/data/mock_android.jar
+++ b/tools/layoutlib/create/tests/data/mock_android.jar
Binary files differ
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile b/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile
new file mode 100644
index 0000000..ab29fbe
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/data/anotherDataFile
@@ -0,0 +1 @@
+A simple data file that should *not* be copied to the output jar.
\ No newline at end of file
diff --git a/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile b/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile
new file mode 100644
index 0000000..9b01893
--- /dev/null
+++ b/tools/layoutlib/create/tests/mock_data/mock_android/data/dataFile
@@ -0,0 +1 @@
+A simple data file that should be copied to the output jar unchanged.
\ No newline at end of file