upload android base code part1

This commit is contained in:
August 2018-08-08 15:50:00 +08:00
parent e02f198e2d
commit 0a1de6c4b3
48159 changed files with 9071466 additions and 0 deletions

View file

@ -0,0 +1,26 @@
apply plugin: 'java'
sourceCompatibility = 1.6
version = '1.0'
dependencies {
testCompile 'junit:junit:4.12'
testCompile 'org.apache.commons:commons-lang3:3.3.2'
testCompile 'commons-io:commons-io:2.4'
testCompile 'commons-codec:commons-codec:1.10'
testCompile project(':dataBinding:compilerCommon')
testCompile project(':dataBinding:compiler')
}
afterEvaluate {
tasks['test'].systemProperties['useReleaseVersion'] = dataBindingConfig.inReleaseBuild ? 'true' : 'false'
tasks['test'].systemProperties['addRemoteRepos'] = dataBindingConfig.addRemoteRepos ? 'true' : 'false'
}
sourceSets {
test {
java {
srcDirs += "${project.rootProject.getProjectDir().getAbsolutePath()}/compiler/src/test/java/android/databinding/tool/reflection/java"
}
}
}

View file

@ -0,0 +1,287 @@
/*
* 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.databinding.compilationTest;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.rules.TestName;
import android.databinding.tool.store.Location;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
public class BaseCompilationTest {
private static final String PRINT_ENCODED_ERRORS_PROPERTY
= "android.injected.invoked.from.ide";
@Rule
public TestName name = new TestName();
static Pattern VARIABLES = Pattern.compile("!@\\{([A-Za-z0-9_-]*)}");
public static final String KEY_MANIFEST_PACKAGE = "PACKAGE";
public static final String KEY_DEPENDENCIES = "DEPENDENCIES";
public static final String KEY_SETTINGS_INCLUDES = "SETTINGS_INCLUDES";
public static final String DEFAULT_APP_PACKAGE = "com.android.databinding.compilationTest.test";
public static final String KEY_CLASS_NAME = "CLASSNAME";
public static final String KEY_CLASS_TYPE = "CLASSTYPE";
public static final String KEY_IMPORT_TYPE = "IMPORTTYPE";
public static final String KEY_INCLUDE_ID = "INCLUDEID";
public static final String KEY_VIEW_ID = "VIEWID";
protected final File testFolder = new File("./build/build-test");
protected void copyResourceTo(String name, String path) throws IOException {
copyResourceTo(name, new File(testFolder, path));
}
protected void copyResourceTo(String name, String path, Map<String, String> replacements)
throws IOException {
copyResourceTo(name, new File(testFolder, path), replacements);
}
protected void copyResourceDirectory(String name, String targetPath)
throws URISyntaxException, IOException {
URL dir = getClass().getResource(name);
assertNotNull(dir);
assertEquals("file", dir.getProtocol());
File folder = new File(dir.toURI());
assertTrue(folder.isDirectory());
File target = new File(testFolder, targetPath);
int len = folder.getAbsolutePath().length() + 1;
for (File item : FileUtils.listFiles(folder, null, true)) {
if (item.getAbsolutePath().equals(folder.getAbsolutePath())) {
continue;
}
String resourcePath = item.getAbsolutePath().substring(len);
copyResourceTo(name + "/" + resourcePath, new File(target, resourcePath));
}
}
@Before
public void clear() throws IOException {
if (testFolder.exists()) {
FileUtils.forceDelete(testFolder);
}
}
/**
* Extracts the text in the given location from the the at the given application path.
*
* @param pathInApp The path, relative to the root of the application under test
* @param location The location to extract
* @return The string that is contained in the given location
* @throws IOException If file is invalid.
*/
protected String extract(String pathInApp, Location location) throws IOException {
File file = new File(testFolder, pathInApp);
assertTrue(file.exists());
StringBuilder result = new StringBuilder();
List<String> lines = FileUtils.readLines(file);
for (int i = location.startLine; i <= location.endLine; i++) {
if (i > location.startLine) {
result.append("\n");
}
String line = lines.get(i);
int start = 0;
if (i == location.startLine) {
start = location.startOffset;
}
int end = line.length() - 1; // inclusive
if (i == location.endLine) {
end = location.endOffset;
}
result.append(line.substring(start, end + 1));
}
return result.toString();
}
protected void copyResourceTo(String name, File targetFile) throws IOException {
File directory = targetFile.getParentFile();
FileUtils.forceMkdir(directory);
InputStream contents = getClass().getResourceAsStream(name);
FileOutputStream fos = new FileOutputStream(targetFile);
IOUtils.copy(contents, fos);
IOUtils.closeQuietly(fos);
IOUtils.closeQuietly(contents);
}
protected static Map<String, String> toMap(String... keysAndValues) {
assertEquals(0, keysAndValues.length % 2);
Map<String, String> map = new HashMap<String, String>();
for (int i = 0; i < keysAndValues.length; i += 2) {
map.put(keysAndValues[i], keysAndValues[i + 1]);
}
return map;
}
protected void copyResourceTo(String name, File targetFile, Map<String, String> replacements)
throws IOException {
if (replacements.isEmpty()) {
copyResourceTo(name, targetFile);
}
InputStream inputStream = getClass().getResourceAsStream(name);
final String contents = IOUtils.toString(inputStream);
IOUtils.closeQuietly(inputStream);
StringBuilder out = new StringBuilder(contents.length());
final Matcher matcher = VARIABLES.matcher(contents);
int location = 0;
while (matcher.find()) {
int start = matcher.start();
if (start > location) {
out.append(contents, location, start);
}
final String key = matcher.group(1);
final String replacement = replacements.get(key);
if (replacement != null) {
out.append(replacement);
}
location = matcher.end();
}
if (location < contents.length()) {
out.append(contents, location, contents.length());
}
FileUtils.writeStringToFile(targetFile, out.toString());
}
protected void prepareProject() throws IOException, URISyntaxException {
prepareApp(null);
}
private Map<String, String> addDefaults(Map<String, String> map) {
if (map == null) {
map = new HashMap<String, String>();
}
if (!map.containsKey(KEY_MANIFEST_PACKAGE)) {
map.put(KEY_MANIFEST_PACKAGE, DEFAULT_APP_PACKAGE);
}
if (!map.containsKey(KEY_SETTINGS_INCLUDES)) {
map.put(KEY_SETTINGS_INCLUDES, "include ':app'");
}
return map;
}
protected void prepareApp(Map<String, String> replacements) throws IOException,
URISyntaxException {
replacements = addDefaults(replacements);
// how to get build folder, pass from gradle somehow ?
FileUtils.forceMkdir(testFolder);
copyResourceTo("/AndroidManifest.xml",
new File(testFolder, "app/src/main/AndroidManifest.xml"), replacements);
copyResourceTo("/project_build.gradle", new File(testFolder, "build.gradle"), replacements);
copyResourceTo("/app_build.gradle", new File(testFolder, "app/build.gradle"), replacements);
copyResourceTo("/settings.gradle", new File(testFolder, "settings.gradle"), replacements);
File localProperties = new File("../local.properties");
if (localProperties.exists()) {
FileUtils.copyFile(localProperties, new File(testFolder, "local.properties"));
}
FileUtils.copyFile(new File("../propLoader.gradle"),
new File(testFolder, "propLoaderClone.gradle"));
FileUtils.copyFile(new File("../gradlew"), new File(testFolder, "gradlew"));
FileUtils.copyDirectory(new File("../gradle"), new File(testFolder, "gradle"));
}
protected void prepareModule(String moduleName, String packageName,
Map<String, String> replacements) throws IOException, URISyntaxException {
replacements = addDefaults(replacements);
replacements.put(KEY_MANIFEST_PACKAGE, packageName);
File moduleFolder = new File(testFolder, moduleName);
if (moduleFolder.exists()) {
FileUtils.forceDelete(moduleFolder);
}
FileUtils.forceMkdir(moduleFolder);
copyResourceTo("/AndroidManifest.xml",
new File(moduleFolder, "src/main/AndroidManifest.xml"), replacements);
copyResourceTo("/module_build.gradle", new File(moduleFolder, "build.gradle"),
replacements);
}
protected CompilationResult runGradle(String... params)
throws IOException, InterruptedException {
setExecutable();
File pathToExecutable = new File(testFolder, "gradlew");
List<String> args = new ArrayList<String>();
args.add(pathToExecutable.getAbsolutePath());
args.add("-P" + PRINT_ENCODED_ERRORS_PROPERTY + "=true");
if ("true".equals(System.getProperties().getProperty("useReleaseVersion", "false"))) {
args.add("-PuseReleaseVersion=true");
}
if ("true".equals(System.getProperties().getProperty("addRemoteRepos", "false"))) {
args.add("-PaddRemoteRepos=true");
}
args.add("--project-cache-dir");
args.add(new File("../.caches/", name.getMethodName()).getAbsolutePath());
Collections.addAll(args, params);
ProcessBuilder builder = new ProcessBuilder(args);
builder.environment().putAll(System.getenv());
String javaHome = System.getProperty("java.home");
if (StringUtils.isNotBlank(javaHome)) {
builder.environment().put("JAVA_HOME", javaHome);
}
builder.directory(testFolder);
Process process = builder.start();
String output = collect(process.getInputStream());
String error = collect(process.getErrorStream());
int result = process.waitFor();
return new CompilationResult(result, output, error);
}
private void setExecutable() throws IOException {
File gw = new File(testFolder, "gradlew");
gw.setExecutable(true);
}
/**
* Use this instead of IO utils so that we can easily log the output when necessary
*/
private static String collect(InputStream stream) throws IOException {
StringBuilder sb = new StringBuilder();
String line;
final BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
return sb.toString();
}
}

View file

@ -0,0 +1,69 @@
/*
* 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.databinding.compilationTest;
import android.databinding.tool.processing.ScopedErrorReport;
import android.databinding.tool.processing.ScopedException;
import android.databinding.tool.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
public class CompilationResult {
public final int resultCode;
public final String output;
public final String error;
public CompilationResult(int resultCode, String output, String error) {
this.resultCode = resultCode;
this.output = output;
this.error = error;
}
public boolean resultContainsText(String text) {
return resultCode == 0 && output.indexOf(text) > 0;
}
public boolean errorContainsText(String text) {
return resultCode != 0 && error.indexOf(text) > 0;
}
public ScopedException getBindingException() {
List<ScopedException> errors = ScopedException.extractErrors(error);
if (errors.isEmpty()) {
return null;
}
assertEquals(error, 1, errors.size());
return errors.get(0);
}
public List<String> getBindingWarnings() {
List<String> warnings = new ArrayList<String>();
for (String line : error.split(StringUtils.LINE_SEPARATOR)) {
if (line.startsWith("warning:")) {
warnings.add(line.substring("warning:".length()));
}
}
return warnings;
}
public List<ScopedException> getBindingExceptions() {
return ScopedException.extractErrors(error);
}
}

View file

@ -0,0 +1,252 @@
/*
* 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.databinding.compilationTest;
import org.junit.Test;
import android.databinding.tool.processing.ErrorMessages;
import android.databinding.tool.processing.ScopedErrorReport;
import android.databinding.tool.processing.ScopedException;
import android.databinding.tool.store.Location;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class MultiLayoutVerificationTest extends BaseCompilationTest {
@Test
public void testMultipleLayoutFilesWithNameMismatch()
throws IOException, URISyntaxException, InterruptedException {
prepareProject();
copyResourceTo("/layout/layout_with_class_name.xml",
"/app/src/main/res/layout/with_class_name.xml", toMap(KEY_CLASS_NAME,
"AClassName"));
copyResourceTo("/layout/layout_with_class_name.xml",
"/app/src/main/res/layout-land/with_class_name.xml", toMap(KEY_CLASS_NAME,
"SomeOtherClassName"));
CompilationResult result = runGradle("assembleDebug");
assertNotEquals(result.output, 0, result.resultCode);
List<ScopedException> exceptions = result.getBindingExceptions();
assertEquals(result.error, 2, exceptions.size());
boolean foundNormal = false;
boolean foundLandscape = false;
for (ScopedException exception : exceptions) {
ScopedErrorReport report = exception.getScopedErrorReport();
assertNotNull(report);
File file = new File(report.getFilePath());
assertTrue(file.exists());
assertEquals(1, report.getLocations().size());
Location location = report.getLocations().get(0);
String name = file.getParentFile().getName();
if ("layout".equals(name)) {
assertEquals(new File(testFolder,
"/app/src/main/res/layout/with_class_name.xml")
.getCanonicalFile(), file.getCanonicalFile());
String extract = extract("/app/src/main/res/layout/with_class_name.xml",
location);
assertEquals(extract, "AClassName");
assertEquals(String.format(
ErrorMessages.MULTI_CONFIG_LAYOUT_CLASS_NAME_MISMATCH,
DEFAULT_APP_PACKAGE + ".databinding.AClassName",
"layout/with_class_name"), exception.getBareMessage());
foundNormal = true;
} else if ("layout-land".equals(name)) {
assertEquals(new File(testFolder,
"/app/src/main/res/layout-land/with_class_name.xml")
.getCanonicalFile(), file.getCanonicalFile());
String extract = extract("/app/src/main/res/layout-land/with_class_name.xml",
location);
assertEquals("SomeOtherClassName", extract);
assertEquals(String.format(
ErrorMessages.MULTI_CONFIG_LAYOUT_CLASS_NAME_MISMATCH,
DEFAULT_APP_PACKAGE + ".databinding.SomeOtherClassName",
"layout-land/with_class_name"), exception.getBareMessage());
foundLandscape = true;
} else {
fail("unexpected error file");
}
}
assertTrue("should find default config error\n" + result.error, foundNormal);
assertTrue("should find landscape error\n" + result.error, foundLandscape);
}
@Test
public void testMultipleLayoutFilesVariableMismatch()
throws IOException, URISyntaxException, InterruptedException {
prepareProject();
copyResourceTo("/layout/layout_with_variable_type.xml",
"/app/src/main/res/layout/layout_with_variable_type.xml", toMap(KEY_CLASS_TYPE,
"String"));
copyResourceTo("/layout/layout_with_variable_type.xml",
"/app/src/main/res/layout-land/layout_with_variable_type.xml", toMap(KEY_CLASS_TYPE,
"CharSequence"));
CompilationResult result = runGradle("assembleDebug");
assertNotEquals(result.output, 0, result.resultCode);
List<ScopedException> exceptions = result.getBindingExceptions();
assertEquals(result.error, 2, exceptions.size());
boolean foundNormal = false;
boolean foundLandscape = false;
for (ScopedException exception : exceptions) {
ScopedErrorReport report = exception.getScopedErrorReport();
assertNotNull(report);
File file = new File(report.getFilePath());
assertTrue(file.exists());
assertEquals(result.error, 1, report.getLocations().size());
Location location = report.getLocations().get(0);
// validated in switch
String name = file.getParentFile().getName();
String config = name;
String type = "???";
if ("layout".equals(name)) {
type = "String";
foundNormal = true;
} else if ("layout-land".equals(name)) {
type = "CharSequence";
foundLandscape = true;
} else {
fail("unexpected error file");
}
assertEquals(new File(testFolder,
"/app/src/main/res/" + config + "/layout_with_variable_type.xml")
.getCanonicalFile(), file.getCanonicalFile());
String extract = extract("/app/src/main/res/" + config +
"/layout_with_variable_type.xml", location);
assertEquals(extract, "<variable name=\"myVariable\" type=\"" + type + "\"/>");
assertEquals(String.format(
ErrorMessages.MULTI_CONFIG_VARIABLE_TYPE_MISMATCH,
"myVariable", type,
config + "/layout_with_variable_type"), exception.getBareMessage());
}
assertTrue(result.error, foundNormal);
assertTrue(result.error, foundLandscape);
}
@Test
public void testMultipleLayoutFilesImportMismatch()
throws IOException, URISyntaxException, InterruptedException {
prepareProject();
String typeNormal = "java.util.List";
String typeLand = "java.util.Map";
copyResourceTo("/layout/layout_with_import_type.xml",
"/app/src/main/res/layout/layout_with_import_type.xml", toMap(KEY_IMPORT_TYPE,
typeNormal));
copyResourceTo("/layout/layout_with_import_type.xml",
"/app/src/main/res/layout-land/layout_with_import_type.xml", toMap(KEY_IMPORT_TYPE,
typeLand));
CompilationResult result = runGradle("assembleDebug");
assertNotEquals(result.output, 0, result.resultCode);
List<ScopedException> exceptions = result.getBindingExceptions();
assertEquals(result.error, 2, exceptions.size());
boolean foundNormal = false;
boolean foundLandscape = false;
for (ScopedException exception : exceptions) {
ScopedErrorReport report = exception.getScopedErrorReport();
assertNotNull(report);
File file = new File(report.getFilePath());
assertTrue(file.exists());
assertEquals(result.error, 1, report.getLocations().size());
Location location = report.getLocations().get(0);
// validated in switch
String name = file.getParentFile().getName();
String config = name;
String type = "???";
if ("layout".equals(name)) {
type = typeNormal;
foundNormal = true;
} else if ("layout-land".equals(name)) {
type = typeLand;
foundLandscape = true;
} else {
fail("unexpected error file");
}
assertEquals(new File(testFolder,
"/app/src/main/res/" + config + "/layout_with_import_type.xml")
.getCanonicalFile(), file.getCanonicalFile());
String extract = extract("/app/src/main/res/" + config + "/layout_with_import_type.xml",
location);
assertEquals(extract, "<import alias=\"Blah\" type=\"" + type + "\"/>");
assertEquals(String.format(
ErrorMessages.MULTI_CONFIG_IMPORT_TYPE_MISMATCH,
"Blah", type,
config + "/layout_with_import_type"), exception.getBareMessage());
}
assertTrue(result.error, foundNormal);
assertTrue(result.error, foundLandscape);
}
@Test
public void testSameIdInIncludeAndView()
throws IOException, URISyntaxException, InterruptedException {
prepareProject();
copyResourceTo("/layout/basic_layout.xml",
"/app/src/main/res/layout/basic_layout.xml");
copyResourceTo("/layout/layout_with_include.xml",
"/app/src/main/res/layout/foo.xml", toMap(KEY_INCLUDE_ID, "sharedId"));
copyResourceTo("/layout/layout_with_view_id.xml",
"/app/src/main/res/layout-land/foo.xml", toMap(KEY_VIEW_ID, "sharedId"));
CompilationResult result = runGradle("assembleDebug");
assertNotEquals(result.output, 0, result.resultCode);
List<ScopedException> exceptions = result.getBindingExceptions();
boolean foundNormal = false;
boolean foundLandscape = false;
for (ScopedException exception : exceptions) {
ScopedErrorReport report = exception.getScopedErrorReport();
assertNotNull(report);
if (exception.getMessage().startsWith("Cannot find the setter")) {
continue;
}
File file = new File(report.getFilePath());
assertTrue(file.exists());
assertEquals(result.error, 1, report.getLocations().size());
Location location = report.getLocations().get(0);
// validated in switch
String config = file.getParentFile().getName();
if ("layout".equals(config)) {
String extract = extract("/app/src/main/res/" + config + "/foo.xml", location);
assertEquals(extract, "<include layout=\"@layout/basic_layout\" "
+ "android:id=\"@+id/sharedId\" bind:myVariable=\"@{myVariable}\"/>");
foundNormal = true;
} else if ("layout-land".equals(config)) {
String extract = extract("/app/src/main/res/" + config + "/foo.xml", location);
assertEquals(extract, "<TextView android:layout_width=\"wrap_content\" "
+ "android:layout_height=\"wrap_content\" android:id=\"@+id/sharedId\" "
+ "android:text=\"@{myVariable}\"/>");
foundLandscape = true;
} else {
fail("unexpected error file");
}
assertEquals(new File(testFolder,
"/app/src/main/res/" + config + "/foo.xml").getCanonicalFile(),
file.getCanonicalFile());
assertEquals(String.format(
ErrorMessages.MULTI_CONFIG_ID_USED_AS_IMPORT, "@+id/sharedId"),
exception.getBareMessage());
}
assertTrue(result.error, foundNormal);
assertTrue(result.error, foundLandscape);
}
}

View file

@ -0,0 +1,402 @@
/*
* 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.databinding.compilationTest;
import android.databinding.tool.CompilerChef;
import android.databinding.tool.processing.ErrorMessages;
import android.databinding.tool.processing.ScopedErrorReport;
import android.databinding.tool.processing.ScopedException;
import android.databinding.tool.reflection.InjectedClass;
import android.databinding.tool.reflection.ModelClass;
import android.databinding.tool.reflection.ModelMethod;
import android.databinding.tool.reflection.java.JavaAnalyzer;
import android.databinding.tool.store.Location;
import com.google.common.base.Joiner;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.PrefixFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
public class SimpleCompilationTest extends BaseCompilationTest {
@Test
public void listTasks() throws IOException, URISyntaxException, InterruptedException {
prepareProject();
CompilationResult result = runGradle("tasks");
assertEquals(0, result.resultCode);
assertTrue("there should not be any errors", StringUtils.isEmpty(result.error));
assertTrue("Test sanity, empty project tasks",
result.resultContainsText("All tasks runnable from root project"));
}
@Test
public void testEmptyCompilation() throws IOException, URISyntaxException, InterruptedException {
prepareProject();
CompilationResult result = runGradle("assembleDebug");
assertEquals(result.error, 0, result.resultCode);
assertTrue("there should not be any errors " + result.error,
StringUtils.isEmpty(result.error));
assertTrue("Test sanity, should compile fine",
result.resultContainsText("BUILD SUCCESSFUL"));
}
@Test
public void testMultipleConfigs() throws IOException, URISyntaxException, InterruptedException {
prepareProject();
copyResourceTo("/layout/basic_layout.xml",
"/app/src/main/res/layout/main.xml");
copyResourceTo("/layout/basic_layout.xml",
"/app/src/main/res/layout-sw100dp/main.xml");
CompilationResult result = runGradle("assembleDebug");
assertEquals(result.error, 0, result.resultCode);
File debugOut = new File(testFolder,
"app/build/intermediates/data-binding-layout-out/debug");
Collection<File> layoutFiles = FileUtils.listFiles(debugOut, new SuffixFileFilter(".xml"),
new PrefixFileFilter("layout"));
assertTrue("test sanity", layoutFiles.size() > 1);
for (File layout : layoutFiles) {
final String contents = FileUtils.readFileToString(layout);
if (layout.getParent().contains("sw100")) {
assertTrue("File has wrong tag:" + layout.getPath(),
contents.indexOf("android:tag=\"layout-sw100dp/main_0\"") > 0);
} else {
assertTrue("File has wrong tag:" + layout.getPath() + "\n" + contents,
contents.indexOf("android:tag=\"layout/main_0\"")
> 0);
}
}
}
private ScopedException singleFileErrorTest(String resource, String targetFile,
String expectedExtract, String errorMessage)
throws IOException, URISyntaxException, InterruptedException {
prepareProject();
copyResourceTo(resource, targetFile);
CompilationResult result = runGradle("assembleDebug");
assertNotEquals(0, result.resultCode);
ScopedException scopedException = result.getBindingException();
assertNotNull(result.error, scopedException);
ScopedErrorReport report = scopedException.getScopedErrorReport();
assertNotNull(report);
assertEquals(1, report.getLocations().size());
Location loc = report.getLocations().get(0);
if (expectedExtract != null) {
String extract = extract(targetFile, loc);
assertEquals(expectedExtract, extract);
}
final File errorFile = new File(report.getFilePath());
assertTrue(errorFile.exists());
assertEquals(new File(testFolder, targetFile).getCanonicalFile(),
errorFile.getCanonicalFile());
if (errorMessage != null) {
assertEquals(errorMessage, scopedException.getBareMessage());
}
return scopedException;
}
private void singleFileWarningTest(String resource, String targetFile,
String expectedMessage)
throws IOException, URISyntaxException, InterruptedException {
prepareProject();
copyResourceTo(resource, targetFile);
CompilationResult result = runGradle("assembleDebug");
assertEquals(0, result.resultCode);
final List<String> warnings = result.getBindingWarnings();
boolean found = false;
for (String warning : warnings) {
found |= warning.contains(expectedMessage);
}
assertTrue(Joiner.on("\n").join(warnings),found);
}
@Test
public void testMultipleExceptionsInDifferentFiles()
throws IOException, URISyntaxException, InterruptedException {
prepareProject();
copyResourceTo("/layout/undefined_variable_binding.xml",
"/app/src/main/res/layout/broken.xml");
copyResourceTo("/layout/invalid_setter_binding.xml",
"/app/src/main/res/layout/invalid_setter.xml");
CompilationResult result = runGradle("assembleDebug");
assertNotEquals(result.output, 0, result.resultCode);
List<ScopedException> bindingExceptions = result.getBindingExceptions();
assertEquals(result.error, 2, bindingExceptions.size());
File broken = new File(testFolder, "/app/src/main/res/layout/broken.xml");
File invalidSetter = new File(testFolder, "/app/src/main/res/layout/invalid_setter.xml");
for (ScopedException exception : bindingExceptions) {
ScopedErrorReport report = exception.getScopedErrorReport();
final File errorFile = new File(report.getFilePath());
String message = null;
String expectedErrorFile = null;
if (errorFile.getCanonicalPath().equals(broken.getCanonicalPath())) {
message = String.format(ErrorMessages.UNDEFINED_VARIABLE, "myVariable");
expectedErrorFile = "/app/src/main/res/layout/broken.xml";
} else if (errorFile.getCanonicalPath().equals(invalidSetter.getCanonicalPath())) {
message = String.format(ErrorMessages.CANNOT_FIND_SETTER_CALL, "android:textx",
String.class.getCanonicalName(), "android.widget.TextView");
expectedErrorFile = "/app/src/main/res/layout/invalid_setter.xml";
} else {
fail("unexpected exception " + exception.getBareMessage());
}
assertEquals(1, report.getLocations().size());
Location loc = report.getLocations().get(0);
String extract = extract(expectedErrorFile, loc);
assertEquals("myVariable", extract);
assertEquals(message, exception.getBareMessage());
}
}
@Test
public void testBadSyntax() throws IOException, URISyntaxException, InterruptedException {
singleFileErrorTest("/layout/layout_with_bad_syntax.xml",
"/app/src/main/res/layout/broken.xml",
"myVar.length())",
String.format(ErrorMessages.SYNTAX_ERROR,
"extraneous input ')' expecting {<EOF>, ',', '.', '::', '[', '+', '-', " +
"'*', '/', '%', '<<', '>>>', '>>', '<=', '>=', '>', '<', " +
"'instanceof', '==', '!=', '&', '^', '|', '&&', '||', '?', '??'}"));
}
@Test
public void testBrokenSyntax() throws IOException, URISyntaxException, InterruptedException {
singleFileErrorTest("/layout/layout_with_completely_broken_syntax.xml",
"/app/src/main/res/layout/broken.xml",
"new String()",
String.format(ErrorMessages.SYNTAX_ERROR,
"mismatched input 'String' expecting {<EOF>, ',', '.', '::', '[', '+', " +
"'-', '*', '/', '%', '<<', '>>>', '>>', '<=', '>=', '>', '<', " +
"'instanceof', '==', '!=', '&', '^', '|', '&&', '||', '?', '??'}"));
}
@Test
public void testUndefinedVariable() throws IOException, URISyntaxException,
InterruptedException {
ScopedException ex = singleFileErrorTest("/layout/undefined_variable_binding.xml",
"/app/src/main/res/layout/broken.xml", "myVariable",
String.format(ErrorMessages.UNDEFINED_VARIABLE, "myVariable"));
}
@Test
public void testInvalidSetterBinding() throws IOException, URISyntaxException,
InterruptedException {
prepareProject();
ScopedException ex = singleFileErrorTest("/layout/invalid_setter_binding.xml",
"/app/src/main/res/layout/invalid_setter.xml", "myVariable",
String.format(ErrorMessages.CANNOT_FIND_SETTER_CALL, "android:textx",
String.class.getCanonicalName(), "android.widget.TextView"));
}
@Test
public void testCallbackArgumentCountMismatch() throws Throwable {
singleFileErrorTest("/layout/layout_with_missing_callback_args.xml",
"/app/src/main/res/layout/broken.xml",
"(seekBar, progress) -> obj.length()",
String.format(ErrorMessages.CALLBACK_ARGUMENT_COUNT_MISMATCH,
"android.databinding.adapters.SeekBarBindingAdapter.OnProgressChanged",
"onProgressChanged", 3, 2));
}
@Test
public void testDuplicateCallbackArgument() throws Throwable {
singleFileErrorTest("/layout/layout_with_duplicate_callback_identifier.xml",
"/app/src/main/res/layout/broken.xml",
"(seekBar, progress, progress) -> obj.length()",
String.format(ErrorMessages.DUPLICATE_CALLBACK_ARGUMENT,
"progress"));
}
@Test
public void testConflictWithVariableName() throws Throwable {
singleFileWarningTest("/layout/layout_with_same_name_for_var_and_callback.xml",
"/app/src/main/res/layout/broken.xml",
String.format(ErrorMessages.CALLBACK_VARIABLE_NAME_CLASH,
"myVar", "myVar", "String"));
}
@Test
public void testRootTag() throws IOException, URISyntaxException,
InterruptedException {
prepareProject();
copyResourceTo("/layout/root_tag.xml", "/app/src/main/res/layout/root_tag.xml");
CompilationResult result = runGradle("assembleDebug");
assertNotEquals(0, result.resultCode);
assertNotNull(result.error);
final String expected = String.format(ErrorMessages.ROOT_TAG_NOT_SUPPORTED, "hello");
assertTrue(result.error.contains(expected));
}
@Test
public void testInvalidVariableType() throws IOException, URISyntaxException,
InterruptedException {
prepareProject();
ScopedException ex = singleFileErrorTest("/layout/invalid_variable_type.xml",
"/app/src/main/res/layout/invalid_variable.xml", "myVariable",
String.format(ErrorMessages.CANNOT_RESOLVE_TYPE, "myVariable"));
}
@Test
public void testSingleModule() throws IOException, URISyntaxException, InterruptedException {
prepareApp(toMap(KEY_DEPENDENCIES, "compile project(':module1')",
KEY_SETTINGS_INCLUDES, "include ':app'\ninclude ':module1'"));
prepareModule("module1", "com.example.module1", toMap());
copyResourceTo("/layout/basic_layout.xml", "/module1/src/main/res/layout/module_layout.xml");
copyResourceTo("/layout/basic_layout.xml", "/app/src/main/res/layout/app_layout.xml");
CompilationResult result = runGradle("assembleDebug");
assertEquals(result.error, 0, result.resultCode);
}
@Test
public void testModuleDependencyChange() throws IOException, URISyntaxException,
InterruptedException {
prepareApp(toMap(KEY_DEPENDENCIES, "compile project(':module1')",
KEY_SETTINGS_INCLUDES, "include ':app'\ninclude ':module1'"));
prepareModule("module1", "com.example.module1", toMap(
KEY_DEPENDENCIES, "compile 'com.android.support:appcompat-v7:23.1.1'"
));
copyResourceTo("/layout/basic_layout.xml", "/module1/src/main/res/layout/module_layout.xml");
copyResourceTo("/layout/basic_layout.xml", "/app/src/main/res/layout/app_layout.xml");
CompilationResult result = runGradle("assembleDebug");
assertEquals(result.error, 0, result.resultCode);
File moduleFolder = new File(testFolder, "module1");
copyResourceTo("/module_build.gradle", new File(moduleFolder, "build.gradle"),
toMap());
result = runGradle("assembleDebug");
assertEquals(result.error, 0, result.resultCode);
}
@Test
public void testTwoLevelDependency() throws IOException, URISyntaxException, InterruptedException {
prepareApp(toMap(KEY_DEPENDENCIES, "compile project(':module1')",
KEY_SETTINGS_INCLUDES, "include ':app'\ninclude ':module1'\n"
+ "include ':module2'"));
prepareModule("module1", "com.example.module1", toMap(KEY_DEPENDENCIES,
"compile project(':module2')"));
prepareModule("module2", "com.example.module2", toMap());
copyResourceTo("/layout/basic_layout.xml",
"/module2/src/main/res/layout/module2_layout.xml");
copyResourceTo("/layout/basic_layout.xml", "/module1/src/main/res/layout/module1_layout.xml");
copyResourceTo("/layout/basic_layout.xml", "/app/src/main/res/layout/app_layout.xml");
CompilationResult result = runGradle("assembleDebug");
assertEquals(result.error, 0, result.resultCode);
}
@Test
public void testIncludeInMerge() throws Throwable {
prepareProject();
copyResourceTo("/layout/merge_include.xml", "/app/src/main/res/layout/merge_include.xml");
CompilationResult result = runGradle("assembleDebug");
assertNotEquals(0, result.resultCode);
List<ScopedException> errors = ScopedException.extractErrors(result.error);
assertEquals(result.error, 1, errors.size());
final ScopedException ex = errors.get(0);
final ScopedErrorReport report = ex.getScopedErrorReport();
final File errorFile = new File(report.getFilePath());
assertTrue(errorFile.exists());
assertEquals(
new File(testFolder, "/app/src/main/res/layout/merge_include.xml")
.getCanonicalFile(),
errorFile.getCanonicalFile());
assertEquals("Merge shouldn't support includes as root. Error message was '" + result.error,
ErrorMessages.INCLUDE_INSIDE_MERGE, ex.getBareMessage());
}
@Test
public void testAssignTwoWayEvent() throws Throwable {
prepareProject();
copyResourceTo("/layout/layout_with_two_way_event_attribute.xml",
"/app/src/main/res/layout/layout_with_two_way_event_attribute.xml");
CompilationResult result = runGradle("assembleDebug");
assertNotEquals(0, result.resultCode);
List<ScopedException> errors = ScopedException.extractErrors(result.error);
assertEquals(result.error, 1, errors.size());
final ScopedException ex = errors.get(0);
final ScopedErrorReport report = ex.getScopedErrorReport();
final File errorFile = new File(report.getFilePath());
assertTrue(errorFile.exists());
assertEquals(new File(testFolder,
"/app/src/main/res/layout/layout_with_two_way_event_attribute.xml")
.getCanonicalFile(),
errorFile.getCanonicalFile());
assertEquals("The attribute android:textAttrChanged is a two-way binding event attribute " +
"and cannot be assigned.", ex.getBareMessage());
}
@SuppressWarnings("deprecated")
@Test
public void testDynamicUtilMembers() throws Throwable {
prepareProject();
CompilationResult result = runGradle("assembleDebug");
assertEquals(result.error, 0, result.resultCode);
assertTrue("there should not be any errors " + result.error,
StringUtils.isEmpty(result.error));
assertTrue("Test sanity, should compile fine",
result.resultContainsText("BUILD SUCCESSFUL"));
File classFile = new File(testFolder,
"app/build/intermediates/classes/debug/android/databinding/DynamicUtil.class");
assertTrue(classFile.exists());
File root = new File(testFolder, "app/build/intermediates/classes/debug/");
URL[] urls = new URL[] {root.toURL()};
JavaAnalyzer.initForTests();
JavaAnalyzer analyzer = (JavaAnalyzer) JavaAnalyzer.getInstance();
ClassLoader classLoader = new URLClassLoader(urls, analyzer.getClassLoader());
Class dynamicUtilClass = classLoader.loadClass("android.databinding.DynamicUtil");
InjectedClass injectedClass = CompilerChef.pushDynamicUtilToAnalyzer();
// test methods
for (Method method : dynamicUtilClass.getMethods()) {
// look for the method in the injected class
ArrayList<ModelClass> args = new ArrayList<ModelClass>();
for (Class<?> param : method.getParameterTypes()) {
args.add(analyzer.findClass(param));
}
ModelMethod modelMethod = injectedClass.getMethod(
method.getName(), args, Modifier.isStatic(method.getModifiers()), false);
assertNotNull("Method " + method + " not found", modelMethod);
}
}
}

View file

@ -0,0 +1,20 @@
<!--
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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="!@{PACKAGE}">
</manifest>

View file

@ -0,0 +1,35 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion dataBindingConfig.compileSdkVersion
buildToolsVersion dataBindingConfig.buildToolsVersion
dataBinding {
enabled = true
}
defaultConfig {
minSdkVersion 7
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'META-INF/services/javax.annotation.processing.Processor'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_6
targetCompatibility JavaVersion.VERSION_1_6
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "com.android.support:support-v4:+"
!@{DEPENDENCIES}
}

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVar" type="String"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@{myVar}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVariable" type="String"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="@+id/outerTextView"
android:textx="@{myVariable}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVariable" type="Stringx"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="@+id/outerTextView"
android:textx="@{myVariable}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVar" type="String"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@{myVar.length())}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data class="!@{CLASSNAME}">
<variable name="myVariable" type="String"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="@+id/outerTextView"
android:text="@{myVariable}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@{new String()}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVar" type="String"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<View android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onProgressChanged="@{(seekBar, progress, progress) -> obj.length()}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVariable" type="String"/>
<import alias="Blah" type="!@{IMPORTTYPE}"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="@+id/outerTextView"
android:text="@{myVariable}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVariable" type="String"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<include layout="@layout/basic_layout" android:id="@+id/!@{INCLUDEID}" bind:myVariable="@{myVariable}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVar" type="String"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<SeekBar android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onProgressChanged="@{(seekBar, progress) -> obj.length()}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVar" type="String"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<SeekBar android:layout_width="wrap_content" android:layout_height="wrap_content"
android:onClick="@{(myVar) -> myVar.setVisibility(1)}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
>
<data>
<variable name="myVariable" type="String"/>
<variable name="myEventListener" type="android.databinding.InverseBindingListener"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:text="@{myVariable}"
android:textAttrChanged="@{myEventListener}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVariable" type="!@{CLASSTYPE}"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="@+id/outerTextView"
android:text="@{myVariable}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVariable" type="String"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/!@{VIEWID}" android:text="@{myVariable}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVar" type="String"/>
</data>
<merge>
<include layout="@layout/basic_layout"
bind:myVar="@{myVar}"/>
</merge>
</layout>

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<variable name="myVar" type="String"/>
</data>
<LinearLayout
android:tag="hello"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@{myVar}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- undefined variable -->
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="@+id/outerTextView"
android:text="@{myVariable.stringValue}"/>
</LinearLayout>
</layout>

View file

@ -0,0 +1,51 @@
/*
* 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.
*/
apply plugin: 'com.android.library'
android {
compileSdkVersion dataBindingConfig.compileSdkVersion
buildToolsVersion dataBindingConfig.buildToolsVersion
dataBinding {
enabled = true
}
defaultConfig {
minSdkVersion 7
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'META-INF/services/javax.annotation.processing.Processor'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_6
targetCompatibility JavaVersion.VERSION_1_6
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "com.android.support:support-v4:+"
!@{DEPENDENCIES}
}

View file

@ -0,0 +1,23 @@
buildscript {
ext.dataBindingRootFolder = new File(project.projectDir, "../../..")
apply from: "${project.projectDir}/propLoaderClone.gradle"
ext.addRepos(repositories)
dependencies {
classpath "com.android.tools.build:gradle:${dataBindingConfig.androidPluginVersion}"
}
}
subprojects {
apply plugin: 'maven'
group = dataBindingConfig.group
version = dataBindingConfig.version
}
allprojects {
repositories {
jcenter()
maven {
url dataBindingConfig.mavenRepoDir
}
}
}

View file

@ -0,0 +1 @@
!@{SETTINGS_INCLUDES}