diff options
130 files changed, 3477 insertions, 658 deletions
diff --git a/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/BuildInfoUtil.java b/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/BuildInfoUtil.java new file mode 100644 index 00000000..bd242339 --- /dev/null +++ b/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/BuildInfoUtil.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.annotationprocessor; + +import com.google.common.base.Preconditions; + +import android.binding.BindingBuildInfo; + +import java.lang.annotation.Annotation; +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.Element; + +public class BuildInfoUtil { + private static BindingBuildInfo sCached; + public static BindingBuildInfo load(RoundEnvironment roundEnvironment) { + if (sCached == null) { + sCached = extractNotNull(roundEnvironment, BindingBuildInfo.class); + } + return sCached; + } + + private static <T extends Annotation> T extractNotNull(RoundEnvironment roundEnv, + Class<T> annotationClass) { + T result = null; + for (Element element : roundEnv.getElementsAnnotatedWith(annotationClass)) { + final T info = element.getAnnotation(annotationClass); + if (info == null) { + continue; // It gets confused between BindingAppInfo and BinderBundle + } + Preconditions.checkState(result == null, "Should have only one %s", + annotationClass.getCanonicalName()); + result = info; + } + return result; + + } +} diff --git a/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessBindable.java b/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessBindable.java index ca554db7..099a0eaa 100644 --- a/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessBindable.java +++ b/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessBindable.java @@ -1,30 +1,39 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.databinding.annotationprocessor; -import com.android.databinding.reflection.ModelAnalyzer; +import com.google.common.base.Preconditions; -import org.apache.commons.io.IOUtils; +import com.android.databinding.util.GenerationalClassUtil; +import com.android.databinding.util.L; import android.binding.Bindable; +import android.binding.BindingBuildInfo; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.io.Serializable; -import java.io.Writer; -import java.net.URL; import java.util.ArrayList; import java.util.Collections; -import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Set; -import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; @@ -34,91 +43,100 @@ import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeKind; -import javax.tools.Diagnostic; -import javax.tools.FileObject; -import javax.tools.JavaFileObject; -import javax.tools.StandardLocation; -@SupportedAnnotationTypes({"android.binding.Bindable"}) +// binding app info and library info are necessary to trigger this. @SupportedSourceVersion(SourceVersion.RELEASE_7) -public class ProcessBindable extends AbstractProcessor { - Intermediate mProperties = new IntermediateV1(); - - public ProcessBindable() { - } - - @Override - public synchronized void init(ProcessingEnvironment processingEnv) { - super.init(processingEnv); - ModelAnalyzer.setProcessingEnvironment(processingEnv); - } +public class ProcessBindable extends ProcessDataBinding.ProcessingStep { + private static final String INTERMEDIATE_FILE_EXT = "-br.bin"; + Intermediate mProperties; @Override - public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { + public boolean onHandleStep(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv, + BindingBuildInfo buildInfo) { + if (mProperties == null) { + mProperties = new IntermediateV1(buildInfo.modulePackage()); + } for (Element element : roundEnv.getElementsAnnotatedWith(Bindable.class)) { Element enclosingElement = element.getEnclosingElement(); ElementKind kind = enclosingElement.getKind(); if (kind != ElementKind.CLASS && kind != ElementKind.INTERFACE) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Bindable must be on a member field or method. The enclosing type is " + - enclosingElement.getKind(), element); - continue; + L.e("Bindable must be on a member field or method. The enclosing type is %s", + enclosingElement.getKind()); } TypeElement enclosing = (TypeElement) enclosingElement; String name = getPropertyName(element); if (name != null) { + Preconditions.checkNotNull(mProperties, "Must receive app / library info before " + + "Bindable fields."); mProperties.addProperty(enclosing.getQualifiedName().toString(), name); } } - if (roundEnv.processingOver()) { - writeIntermediateFile(mProperties); - generateBR(mProperties); + return false; + } + + @Override + public void onProcessingOver(RoundEnvironment roundEnvironment, + ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) { + if (mProperties != null) { + GenerationalClassUtil.writeIntermediateFile(processingEnvironment, + mProperties.getPackage(), + createIntermediateFileName(mProperties.getPackage()), mProperties); + generateBRClasses(!buildInfo.isLibrary(), mProperties.getPackage()); } - return true; } - private void generateBR(Intermediate intermediate) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, - "************* Generating BR file from Bindable attributes"); + private String createIntermediateFileName(String appPkg) { + return appPkg + INTERMEDIATE_FILE_EXT; + } + + private void generateBRClasses(boolean useFinalFields, String pkg) { + L.d("************* Generating BR file %s. use final: %s", pkg, useFinalFields); HashSet<String> properties = new HashSet<>(); - intermediate.captureProperties(properties); - mergeClassPathResources(properties); - try { - ArrayList<String> sortedProperties = new ArrayList<String>(); - sortedProperties.addAll(properties); - Collections.sort(sortedProperties); - - JavaFileObject fileObject = processingEnv.getFiler() - .createSourceFile("android.binding.BR"); - Writer writer = fileObject.openWriter(); - writer.write("package android.binding;\n\n" + - "public final class BR {\n" + - " public static final int _all = 0;\n" - ); - int id = 0; - for (String property : sortedProperties) { - id++; - writer.write(" public static final int " + property + " = " + id + ";\n"); - } - writer.write(" public static int getId(String key) {\n"); - writer.write(" switch(key) {\n"); - id = 0; - for (String property : sortedProperties) { - id++; - writer.write(" case \"" + property + "\": return " + id + ";\n"); + mProperties.captureProperties(properties); + List<Intermediate> previousIntermediates = loadPreviousBRFiles(); + for (Intermediate intermediate : previousIntermediates) { + intermediate.captureProperties(properties); + } + writeBRClass(useFinalFields, pkg, properties); + if (useFinalFields) { + // generate BR for all previous packages + for (Intermediate intermediate : previousIntermediates) { + writeBRClass(true, intermediate.getPackage(), + properties); } - writer.write(" }\n"); - writer.write(" return -1;\n"); - writer.write(" }"); - writer.write("}\n"); - - writer.close(); - } catch (IOException e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Could not generate BR file " + e.getLocalizedMessage()); } } + private void writeBRClass(boolean useFinalFields, String pkg, HashSet<String> properties) { + ArrayList<String> sortedProperties = new ArrayList<String>(); + sortedProperties.addAll(properties); + Collections.sort(sortedProperties); + StringBuilder out = new StringBuilder(); + String modifier = "public static " + (useFinalFields ? "final" : "") + " int "; + out.append("package " + pkg + ";\n\n" + + "public class BR {\n" + + " " + modifier + "_all = 0;\n" + ); + int id = 0; + for (String property : sortedProperties) { + id++; + out.append(" " + modifier + property + " = " + id + ";\n"); + } + out.append(" public static int getId(String key) {\n"); + out.append(" switch(key) {\n"); + id = 0; + for (String property : sortedProperties) { + id++; + out.append(" case \"" + property + "\": return " + id + ";\n"); + } + out.append(" }\n"); + out.append(" return -1;\n"); + out.append(" }"); + out.append("}\n"); + + getWriter().writeToFile(pkg + ".BR", out.toString() ); + } + private String getPropertyName(Element element) { switch (element.getKind()) { case FIELD: @@ -126,8 +144,7 @@ public class ProcessBindable extends AbstractProcessor { case METHOD: return stripPrefixFromMethod((ExecutableElement) element); default: - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "@Bindable is not allowed on " + element.getKind(), element); + L.e("@Bindable is not allowed on %s", element.getKind()); return null; } } @@ -159,8 +176,7 @@ public class ProcessBindable extends AbstractProcessor { } else if (isBooleanGetter(element)) { propertyName = name.subSequence(2, name.length()); } else { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "@Bindable associated with method must follow JavaBeans convention", element); + L.e("@Bindable associated with method must follow JavaBeans convention %s", element); return null; } char firstChar = propertyName.charAt(0); @@ -207,102 +223,32 @@ public class ProcessBindable extends AbstractProcessor { element.getReturnType().getKind() == TypeKind.BOOLEAN; } - private Intermediate readIntermediateFile() { - Intermediate properties = null; - ObjectInputStream in = null; - try { - FileObject intermediate = processingEnv.getFiler() - .getResource(StandardLocation.CLASS_OUTPUT, - ProcessBindable.class.getPackage().getName(), "binding_properties.bin"); - if (new File(intermediate.getName()).exists()) { - in = new ObjectInputStream(intermediate.openInputStream()); - properties = (Intermediate) in.readObject(); - } - } catch (IOException e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Could not read Binding properties intermediate file: " + - e.getLocalizedMessage()); - } catch (ClassNotFoundException e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Could not read Binding properties intermediate file: " + - e.getLocalizedMessage()); - } finally { - try { - if (in != null) { - in.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - if (properties == null) { - properties = new IntermediateV1(); - } - return properties; + private List<Intermediate> loadPreviousBRFiles() { + return GenerationalClassUtil + .loadObjects(getClass().getClassLoader(), + new GenerationalClassUtil.ExtensionFilter(INTERMEDIATE_FILE_EXT)); } - private void mergeClassPathResources(HashSet<String> intermediateProperties) { - try { - String resourcePath = ProcessBindable.class.getPackage().getName() - .replace('.', '/') + "/binding_properties.bin"; - Enumeration<URL> resources = getClass().getClassLoader() - .getResources(resourcePath); - while (resources.hasMoreElements()) { - URL url = resources.nextElement(); - processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, - "Merging binding adapters from " + url); - InputStream inputStream = null; - try { - inputStream = url.openStream(); - ObjectInputStream in = new ObjectInputStream(inputStream); - Intermediate properties = (Intermediate) in.readObject(); - if (properties != null) { - properties.captureProperties(intermediateProperties); - } - } catch (IOException e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Could not merge in Bindables from " + url + ": " + - e.getLocalizedMessage()); - } catch (ClassNotFoundException e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Could not read Binding properties intermediate file: " + - e.getLocalizedMessage()); - } finally { - IOUtils.closeQuietly(inputStream); - } - } - } catch (IOException e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Could not read Binding properties intermediate file: " + - e.getLocalizedMessage()); - } - } + private interface Intermediate extends Serializable { - private void writeIntermediateFile(Intermediate properties) { - try { - FileObject intermediate = processingEnv.getFiler().createResource( - StandardLocation.CLASS_OUTPUT, ProcessBindable.class.getPackage().getName(), - "binding_properties.bin"); - ObjectOutputStream out = new ObjectOutputStream(intermediate.openOutputStream()); - out.writeObject(properties); - out.close(); - } catch (IOException e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Could not write to intermediate file: " + e.getLocalizedMessage()); - } - } - - private interface Intermediate { void captureProperties(Set<String> properties); void addProperty(String className, String propertyName); + + String getPackage(); } private static class IntermediateV1 implements Serializable, Intermediate { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L; + + private String mPackage; private final HashMap<String, HashSet<String>> mProperties = new HashMap<>(); + public IntermediateV1(String aPackage) { + mPackage = aPackage; + } + @Override public void captureProperties(Set<String> properties) { for (HashSet<String> propertySet : mProperties.values()) { @@ -319,5 +265,10 @@ public class ProcessBindable extends AbstractProcessor { } properties.add(propertyName); } + + @Override + public String getPackage() { + return mPackage; + } } } diff --git a/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessDataBinding.java b/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessDataBinding.java new file mode 100644 index 00000000..dd648408 --- /dev/null +++ b/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessDataBinding.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.annotationprocessor; + +import com.android.databinding.reflection.ModelAnalyzer; +import com.android.databinding.writer.AnnotationJavaFileWriter; +import com.android.databinding.writer.JavaFileWriter; + +import android.binding.BindingBuildInfo; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; + +@SupportedAnnotationTypes({ + "android.binding.BindingAdapter", + "android.binding.Untaggable", + "android.binding.BindingMethods", + "android.binding.BindingConversion", + "android.binding.BindingBuildInfo"} +) +@SupportedSourceVersion(SourceVersion.RELEASE_7) +/** + * Parent annotation processor that dispatches sub steps to ensure execution order. + * Use initProcessingSteps to add a new step. + */ +public class ProcessDataBinding extends AbstractProcessor { + private List<ProcessingStep> mProcessingSteps; + @Override + public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { + if (mProcessingSteps == null) { + initProcessingSteps(); + } + final BindingBuildInfo buildInfo = BuildInfoUtil.load(roundEnv); + if (buildInfo == null) { + return false; + } + boolean done = true; + for (ProcessingStep step : mProcessingSteps) { + done = step.runStep(roundEnv, processingEnv, buildInfo) && done; + } + if (roundEnv.processingOver()) { + for (ProcessingStep step : mProcessingSteps) { + step.onProcessingOver(roundEnv, processingEnv, buildInfo); + } + } + return done; + } + + private void initProcessingSteps() { + mProcessingSteps = Arrays.asList( + new ProcessMethodAdapters(), + new ProcessExpressions(), + new ProcessBindable() + ); + AnnotationJavaFileWriter javaFileWriter = new AnnotationJavaFileWriter(processingEnv); + for (ProcessingStep step : mProcessingSteps) { + step.mJavaFileWriter = javaFileWriter; + } + } + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + ModelAnalyzer.setProcessingEnvironment(processingEnv); + } + + /** + * To ensure execution order and binding build information, we use processing steps. + */ + public abstract static class ProcessingStep { + private boolean mDone; + private JavaFileWriter mJavaFileWriter; + + protected JavaFileWriter getWriter() { + return mJavaFileWriter; + } + + private boolean runStep(RoundEnvironment roundEnvironment, + ProcessingEnvironment processingEnvironment, + BindingBuildInfo buildInfo) { + if (mDone) { + return true; + } + mDone = onHandleStep(roundEnvironment, processingEnvironment, buildInfo); + return mDone; + } + + /** + * Invoked in each annotation processing step. + * + * @return True if it is done and should never be invoked again. + */ + abstract public boolean onHandleStep(RoundEnvironment roundEnvironment, + ProcessingEnvironment processingEnvironment, + BindingBuildInfo buildInfo); + + /** + * Invoked when processing is done. A good place to generate the output if the + * processor requires multiple steps. + */ + abstract public void onProcessingOver(RoundEnvironment roundEnvironment, + ProcessingEnvironment processingEnvironment, + BindingBuildInfo buildInfo); + } +} diff --git a/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessExpressions.java b/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessExpressions.java index 2b047bb2..7f5ab94d 100644 --- a/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessExpressions.java +++ b/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessExpressions.java @@ -19,114 +19,171 @@ package com.android.databinding.annotationprocessor; import com.android.databinding.CompilerChef; import com.android.databinding.reflection.SdkUtil; import com.android.databinding.store.ResourceBundle; +import com.android.databinding.util.GenerationalClassUtil; import com.android.databinding.util.L; -import com.android.databinding.writer.AnnotationJavaFileWriter; -import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import android.binding.BinderBundle; -import android.binding.BindingAppInfo; +import android.binding.BindingBuildInfo; -import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FilenameFilter; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.StringWriter; -import java.util.Set; +import java.io.InputStream; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; -import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.annotation.processing.SupportedSourceVersion; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.TypeElement; -import javax.tools.Diagnostic; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; -@SupportedAnnotationTypes({"android.binding.BinderBundle", "android.binding.BindingAppInfo"}) -@SupportedSourceVersion(SourceVersion.RELEASE_7) -public class ProcessExpressions extends AbstractProcessor { +public class ProcessExpressions extends ProcessDataBinding.ProcessingStep { - public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { - ResourceBundle resourceBundle = null; - for (Element element : roundEnv.getElementsAnnotatedWith(BindingAppInfo.class)) { - final BindingAppInfo appInfo = element.getAnnotation(BindingAppInfo.class); - if (appInfo == null) { - continue; // It gets confused between BindingAppInfo and BinderBundle + private static final String LAYOUT_INFO_FILE_SUFFIX = "-layoutinfo.bin"; + + @Override + public boolean onHandleStep(RoundEnvironment roundEnvironment, + ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) { + ResourceBundle resourceBundle; + SdkUtil.initialize(buildInfo.minSdk(), new File(buildInfo.sdkRoot())); + resourceBundle = new ResourceBundle(buildInfo.modulePackage()); + List<Intermediate> intermediateList = + GenerationalClassUtil.loadObjects(getClass().getClassLoader(), + new GenerationalClassUtil.ExtensionFilter(LAYOUT_INFO_FILE_SUFFIX)); + IntermediateV1 mine = createIntermediateFromLayouts(buildInfo.layoutInfoDir()); + if (mine != null) { + mine.removeOverridden(intermediateList); + intermediateList.add(mine); + saveIntermediate(processingEnvironment, buildInfo, mine); + } + // generate them here so that bindable parser can read + try { + generateBinders(resourceBundle, buildInfo, intermediateList); + } catch (Throwable t) { + L.e(t, "cannot generate view binders"); + } + return true; + } + + private void saveIntermediate(ProcessingEnvironment processingEnvironment, + BindingBuildInfo buildInfo, IntermediateV1 intermediate) { + GenerationalClassUtil.writeIntermediateFile(processingEnvironment, + buildInfo.modulePackage(), buildInfo.modulePackage() + LAYOUT_INFO_FILE_SUFFIX, + intermediate); + } + + @Override + public void onProcessingOver(RoundEnvironment roundEnvironment, + ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) { + + } + + private void generateBinders(ResourceBundle resourceBundle, BindingBuildInfo buildInfo, + List<Intermediate> intermediates) + throws Throwable { + for (Intermediate intermediate : intermediates) { + intermediate.appendTo(resourceBundle); + } + writeResourceBundle(resourceBundle, buildInfo.isLibrary()); + } + + private IntermediateV1 createIntermediateFromLayouts(String layoutInfoFolderPath) { + final File layoutInfoFolder = new File(layoutInfoFolderPath); + if (!layoutInfoFolder.isDirectory()) { + L.d("layout info folder does not exist, skipping for %s", layoutInfoFolderPath); + return null; + } + IntermediateV1 result = new IntermediateV1(); + for (File layoutFile : layoutInfoFolder.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(".xml"); } - SdkUtil.initialize(appInfo.minSdk(), new File(appInfo.sdkRoot())); - if (element.getKind() != ElementKind.CLASS) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "BindingAppInfo associated with wrong type. Should be a class.", element); - continue; + })) { + try { + result.addEntry(layoutFile.getName(), FileUtils.readFileToString(layoutFile)); + } catch (IOException e) { + L.e(e, "cannot load layout file information. Try a clean build"); } - if (resourceBundle == null) { - resourceBundle = new ResourceBundle(appInfo.applicationPackage()); - processLayouts(resourceBundle, roundEnv); - } else { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "BindingAppInfo must be applied to only one class.", element); + } + return result; + } + + private void writeResourceBundle(ResourceBundle resourceBundle, boolean forLibraryModule) + throws JAXBException { + CompilerChef compilerChef = CompilerChef.createChef(resourceBundle, getWriter()); + if (compilerChef.hasAnythingToGenerate()) { + compilerChef.writeViewBinderInterfaces(); + if (!forLibraryModule) { + compilerChef.writeDbrFile(); + compilerChef.writeViewBinders(); } } + } - return true; + public static interface Intermediate extends Serializable { + + Intermediate upgrade(); + + public void appendTo(ResourceBundle resourceBundle) throws Throwable; } - private void processLayouts(ResourceBundle resourceBundle, RoundEnvironment roundEnv) { - Unmarshaller unmarshaller = null; - for (Element element : roundEnv.getElementsAnnotatedWith(BinderBundle.class)) { - final BinderBundle binderBundle = element.getAnnotation(BinderBundle.class); - if (binderBundle == null) { - continue; - } - if (element.getKind() != ElementKind.CLASS) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "BinderBundle associated with wrong type. Should be a class.", element); - continue; + public static class IntermediateV1 implements Intermediate { + + transient Unmarshaller mUnmarshaller; + + // name to xml content map + Map<String, String> mLayoutInfoMap = new HashMap<>(); + + @Override + public Intermediate upgrade() { + return this; + } + + @Override + public void appendTo(ResourceBundle resourceBundle) throws JAXBException { + if (mUnmarshaller == null) { + JAXBContext context = JAXBContext + .newInstance(ResourceBundle.LayoutFileBundle.class); + mUnmarshaller = context.createUnmarshaller(); } - ByteArrayInputStream in = null; - try { - if (unmarshaller == null) { - JAXBContext context = - JAXBContext.newInstance(ResourceBundle.LayoutFileBundle.class); - unmarshaller = context.createUnmarshaller(); - } - String binderBundle64 = binderBundle.value(); - byte[] buf = Base64.decodeBase64(binderBundle64); - in = new ByteArrayInputStream(buf); - Reader reader = new InputStreamReader(in); - ResourceBundle.LayoutFileBundle layoutFileBundle - = (ResourceBundle.LayoutFileBundle) - unmarshaller.unmarshal(reader); - resourceBundle - .addLayoutBundle(layoutFileBundle, layoutFileBundle.getLayoutId()); - } catch (Exception e) { - StringWriter stringWriter = new StringWriter(); - e.printStackTrace(new PrintWriter(stringWriter)); - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Could not generate Binders from binder data store: " + - stringWriter.getBuffer().toString(), element); - } finally { - if (in != null) { - IOUtils.closeQuietly(in); + for (String content : mLayoutInfoMap.values()) { + final InputStream is = IOUtils.toInputStream(content); + try { + final ResourceBundle.LayoutFileBundle bundle + = (ResourceBundle.LayoutFileBundle) mUnmarshaller.unmarshal(is); + resourceBundle.addLayoutBundle(bundle, bundle.getLayoutId()); + L.d("loaded layout info file %s", bundle); + } finally { + IOUtils.closeQuietly(is); } } + } + public void addEntry(String name, String contents) { + mLayoutInfoMap.put(name, contents); } - CompilerChef compilerChef = CompilerChef.createChef(resourceBundle, - new AnnotationJavaFileWriter(processingEnv)); - if (compilerChef.hasAnythingToGenerate()) { - compilerChef.writeDbrFile(); - compilerChef.writeViewBinderInterfaces(); - compilerChef.writeViewBinders(); + public void removeOverridden(List<Intermediate> existing) { + // this is the way we get rid of files that are copied from previous modules + // it is important to do this before saving the intermediate file + for (Intermediate old : existing) { + if (old instanceof IntermediateV1) { + IntermediateV1 other = (IntermediateV1) old; + for (String key : other.mLayoutInfoMap.keySet()) { + // TODO we should consider the original file as the key here + // but aapt probably cannot provide that information + if (mLayoutInfoMap.remove(key) != null) { + L.d("removing %s from bundle because it came from another module", key); + } + } + } + } } } } diff --git a/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessMethodAdapters.java b/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessMethodAdapters.java index 6ed56323..a13e3a2a 100644 --- a/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessMethodAdapters.java +++ b/annotationprocessor/src/main/java/com/android/databinding/annotationprocessor/ProcessMethodAdapters.java @@ -15,24 +15,25 @@ */ package com.android.databinding.annotationprocessor; +import com.google.common.base.Preconditions; + import android.binding.BindingAdapter; +import android.binding.BindingBuildInfo; import android.binding.BindingConversion; import android.binding.BindingMethod; import android.binding.BindingMethods; import android.binding.Untaggable; +import com.android.databinding.reflection.ModelAnalyzer; import com.android.databinding.store.SetterStore; +import com.android.databinding.util.L; import java.io.IOException; import java.util.HashSet; import java.util.List; -import java.util.Set; -import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.annotation.processing.SupportedSourceVersion; -import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; @@ -42,50 +43,46 @@ import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeKind; import javax.tools.Diagnostic; -@SupportedAnnotationTypes({ - "android.binding.BindingAdapter", - "android.binding.Untaggable", - "android.binding.BindingMethods", - "android.binding.BindingConversion"}) -@SupportedSourceVersion(SourceVersion.RELEASE_7) -public class ProcessMethodAdapters extends AbstractProcessor { - private boolean mProcessed; - +public class ProcessMethodAdapters extends ProcessDataBinding.ProcessingStep { public ProcessMethodAdapters() { } @Override - public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { - if (mProcessed) { - return true; - } - - SetterStore store = SetterStore.get(processingEnv); + public boolean onHandleStep(RoundEnvironment roundEnv, + ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) { + L.d("processing adapters"); + final ModelAnalyzer modelAnalyzer = ModelAnalyzer.getInstance(); + Preconditions.checkNotNull(modelAnalyzer, "Model analyzer should be" + + " initialized first"); + SetterStore store = SetterStore.get(modelAnalyzer); clearIncrementalClasses(roundEnv, store); - addBindingAdapters(roundEnv, store); - addRenamed(roundEnv, store); - addConversions(roundEnv, store); - addUntaggable(roundEnv, store); + addBindingAdapters(roundEnv, processingEnvironment, store); + addRenamed(roundEnv, processingEnvironment, store); + addConversions(roundEnv, processingEnvironment, store); + addUntaggable(roundEnv, processingEnvironment, store); try { - store.write(processingEnv); + store.write(buildInfo.modulePackage(), processingEnvironment); } catch (IOException e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Could not write BindingAdapter intermediate file: " + e.getLocalizedMessage()); - e.printStackTrace(); + L.e(e, "Could not write BindingAdapter intermediate file."); } - mProcessed = true; return true; } - private void addBindingAdapters(RoundEnvironment roundEnv, SetterStore store) { + @Override + public void onProcessingOver(RoundEnvironment roundEnvironment, + ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) { + + } + + private void addBindingAdapters(RoundEnvironment roundEnv, ProcessingEnvironment + processingEnv, SetterStore store) { for (Element element : roundEnv.getElementsAnnotatedWith(BindingAdapter.class)) { if (element.getKind() != ElementKind.METHOD || !element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "@BindingAdapter on invalid element: " + element); + L.e("@BindingAdapter on invalid element: %s", element); continue; } BindingAdapter bindingAdapter = element.getAnnotation(BindingAdapter.class); @@ -93,22 +90,20 @@ public class ProcessMethodAdapters extends AbstractProcessor { ExecutableElement executableElement = (ExecutableElement) element; List<? extends VariableElement> parameters = executableElement.getParameters(); if (parameters.size() != 2) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "@BindingAdapter does not take two parameters: " + element); + L.e("@BindingAdapter does not take two parameters: %s",element); continue; } try { - processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, - "------------------ @BindingAdapter for " + element); + L.d("------------------ @BindingAdapter for %s", element); store.addBindingAdapter(bindingAdapter.value(), executableElement); } catch (IllegalArgumentException e) { - processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, - "@BindingAdapter for duplicate View and parameter type: " + element); + L.e(e, "@BindingAdapter for duplicate View and parameter type: %s", element); } } } - private void addRenamed(RoundEnvironment roundEnv, SetterStore store) { + private void addRenamed(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv, + SetterStore store) { for (Element element : roundEnv.getElementsAnnotatedWith(BindingMethods.class)) { BindingMethods bindingMethods = element.getAnnotation(BindingMethods.class); for (BindingMethod bindingMethod : bindingMethods.value()) { @@ -118,7 +113,8 @@ public class ProcessMethodAdapters extends AbstractProcessor { } } - private void addConversions(RoundEnvironment roundEnv, SetterStore store) { + private void addConversions(RoundEnvironment roundEnv, + ProcessingEnvironment processingEnv, SetterStore store) { for (Element element : roundEnv.getElementsAnnotatedWith(BindingConversion.class)) { if (element.getKind() != ElementKind.METHOD || !element.getModifiers().contains(Modifier.STATIC) || @@ -145,7 +141,8 @@ public class ProcessMethodAdapters extends AbstractProcessor { } } - private void addUntaggable(RoundEnvironment roundEnv, SetterStore store) { + private void addUntaggable(RoundEnvironment roundEnv, + ProcessingEnvironment processingEnv, SetterStore store) { for (Element element : roundEnv.getElementsAnnotatedWith(Untaggable.class)) { Untaggable untaggable = element.getAnnotation(Untaggable.class); store.addUntaggableTypes(untaggable.value(), (TypeElement) element); diff --git a/annotationprocessor/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/annotationprocessor/src/main/resources/META-INF/services/javax.annotation.processing.Processor index 7b825401..27f59e00 100644 --- a/annotationprocessor/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ b/annotationprocessor/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -1,3 +1 @@ -com.android.databinding.annotationprocessor.ProcessBindable -com.android.databinding.annotationprocessor.ProcessMethodAdapters -com.android.databinding.annotationprocessor.ProcessExpressions +com.android.databinding.annotationprocessor.ProcessDataBinding
\ No newline at end of file diff --git a/baseLibrary/build.gradle b/baseLibrary/build.gradle index 66f61b38..ecb7205b 100644 --- a/baseLibrary/build.gradle +++ b/baseLibrary/build.gradle @@ -46,7 +46,6 @@ sourceSets { } dependencies { - compile 'com.tunnelvisionlabs:antlr4:4.4' testCompile 'junit:junit:4.11' } diff --git a/baseLibrary/src/main/java/android/binding/BindingAppInfo.java b/baseLibrary/src/main/java/android/binding/BindingBuildInfo.java index a90f3328..62b6043f 100644 --- a/baseLibrary/src/main/java/android/binding/BindingAppInfo.java +++ b/baseLibrary/src/main/java/android/binding/BindingBuildInfo.java @@ -7,12 +7,12 @@ * * 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, + * 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.binding; import java.lang.annotation.ElementType; @@ -22,9 +22,15 @@ import java.lang.annotation.Target; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) -public @interface BindingAppInfo { +public @interface BindingBuildInfo { String buildId(); - String applicationPackage(); + String modulePackage(); String sdkRoot(); int minSdk(); + + /** + * The folder that includes xml files which are exported by aapt or gradle plugin from layout files + */ + String layoutInfoDir(); + boolean isLibrary(); } diff --git a/build.gradle b/build.gradle index b86af2b1..c63b74b4 100644 --- a/build.gradle +++ b/build.gradle @@ -3,13 +3,12 @@ databindingProperties.load(new FileInputStream("${projectDir}/databinding.proper databindingProperties.mavenRepoDir = "${projectDir}/${databindingProperties.mavenRepoName}" ext.config = databindingProperties - println "local maven repo is ${ext.config.mavenRepoDir}." new File(ext.config.mavenRepoDir).mkdir() subprojects { apply plugin: 'maven' - group = 'com.android.databinding' + group = config.group version = config.snapshotVersion repositories { mavenCentral() @@ -30,14 +29,22 @@ task deleteRepo(type: Delete) { delete "${config.mavenRepoDir}" } +def buildExtensionsTask = project.tasks.create "buildExtensionsTask", Exec +buildExtensionsTask.workingDir file('extensions').getAbsolutePath() +//on linux +buildExtensionsTask.commandLine './gradlew' +buildExtensionsTask.args 'clean', 'uploadArchives', '--info', '--stacktrace' +buildExtensionsTask.dependsOn subprojects.uploadArchives + file('integration-tests').listFiles().findAll { it.isDirectory() }.each { - println("${it.getAbsolutePath()}") + println("Creating run test task for ${it.getAbsolutePath()}.") def testTask = project.tasks.create "runTestsOf${it.getName().capitalize()}", Exec - testTask.workingDir 'integration-tests/TestApp' + testTask.workingDir it.getAbsolutePath() //on linux testTask.commandLine './gradlew' - testTask.args 'clean', 'connectedCheck', '--info' + testTask.args 'clean', 'connectedCheck', '--info', '--stacktrace' testTask.dependsOn subprojects.uploadArchives + testTask.dependsOn buildExtensionsTask } task runIntegrationTests { @@ -51,11 +58,17 @@ task runAllTests { allprojects { afterEvaluate { project -> runAllTests.dependsOn project.tasks.findAll {task -> task.name.equals('test')} + runAllTests.dependsOn project.tasks.findAll {task -> task.name.equals('connectedCheck')} } } +subprojects.uploadArchives.each { it.shouldRunAfter deleteRepo } +buildExtensionsTask.shouldRunAfter deleteRepo +tasks['runTestsOfMultiModuleTestApp'].shouldRunAfter tasks['runTestsOfIndependentLibrary'] + task rebuildRepo() { dependsOn deleteRepo dependsOn subprojects.uploadArchives + dependsOn buildExtensionsTask }
\ No newline at end of file diff --git a/compiler/src/main/java/com/android/databinding/LayoutBinder.java b/compiler/src/main/java/com/android/databinding/LayoutBinder.java index a285e165..a2aa2485 100644 --- a/compiler/src/main/java/com/android/databinding/LayoutBinder.java +++ b/compiler/src/main/java/com/android/databinding/LayoutBinder.java @@ -43,6 +43,7 @@ public class LayoutBinder { private final ExpressionParser mExpressionParser; private final List<BindingTarget> mBindingTargets; private String mPackage; + private String mModulePackage; private String mProjectPackage; private String mBaseClassName; private final HashMap<String, String> mUserDefinedVariables = new HashMap<String, String>(); @@ -57,7 +58,8 @@ public class LayoutBinder { mBindingTargets = new ArrayList<BindingTarget>(); mBundle = layoutBundle; mProjectPackage = resourceBundle.getAppPackage(); - mPackage = mProjectPackage + ".generated"; + mModulePackage = layoutBundle.getModulePackage(); + mPackage = layoutBundle.getModulePackage() + ".generated"; mBaseClassName = ParserHelper.INSTANCE$.toClassName(layoutBundle.getFileName()) + "Binding"; // copy over data. for (Map.Entry<String, String> variable : mBundle.getVariables().entrySet()) { @@ -159,6 +161,10 @@ public class LayoutBinder { return mPackage; } + public String getModulePackage() { + return mModulePackage; + } + public void setPackage(String aPackage) { mPackage = aPackage; } diff --git a/compiler/src/main/java/com/android/databinding/LayoutXmlProcessor.java b/compiler/src/main/java/com/android/databinding/LayoutXmlProcessor.java index ed170bff..d0ce5068 100644 --- a/compiler/src/main/java/com/android/databinding/LayoutXmlProcessor.java +++ b/compiler/src/main/java/com/android/databinding/LayoutXmlProcessor.java @@ -20,15 +20,16 @@ import com.android.databinding.store.LayoutFileParser; import com.android.databinding.store.ResourceBundle; import com.android.databinding.writer.JavaFileWriter; -import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringEscapeUtils; import org.xml.sax.SAXException; +import android.binding.BindingBuildInfo; + import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.StringWriter; -import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -44,24 +45,51 @@ import javax.xml.xpath.XPathExpressionException; * processor to work with. */ public class LayoutXmlProcessor { - - public static final String RESOURCE_BUNDLE_PACKAGE = "com.android.databinding.layouts."; - public static final String APPLICATION_INFO_CLASS = "ApplicationBindingInfo"; + // hardcoded in baseAdapters + public static final String RESOURCE_BUNDLE_PACKAGE = "com.android.databinding.layouts"; + public static final String CLASS_NAME = "DataBindingInfo"; private final JavaFileWriter mFileWriter; private final ResourceBundle mResourceBundle; private final int mMinSdk; private boolean mProcessingComplete; private boolean mWritten; + private final boolean mIsLibrary; private final String mBuildId = UUID.randomUUID().toString(); - private final List<File> mResourceFolders; + // can be a list of xml files or folders that contain XML files + private final List<File> mResources; - public LayoutXmlProcessor(String applicationPackage, List<File> resourceFolders, - JavaFileWriter fileWriter, int minSdk) { + public LayoutXmlProcessor(String applicationPackage, List<File> resources, + JavaFileWriter fileWriter, int minSdk, boolean isLibrary) { mFileWriter = fileWriter; mResourceBundle = new ResourceBundle(applicationPackage); - mResourceFolders = resourceFolders; + mResources = resources; mMinSdk = minSdk; + mIsLibrary = isLibrary; + } + + public static List<File> getLayoutFiles(List<File> resources) { + List<File> result = new ArrayList<File>(); + for (File resource : Iterables.filter(resources, fileExists)) { + if (resource.isDirectory()) { + for (File layoutFolder : resource.listFiles(layoutFolderFilter)) { + for (File xmlFile : layoutFolder.listFiles(xmlFileFilter)) { + result.add(xmlFile); + } + + } + } else if (xmlFileFilter.accept(resource.getParentFile(), resource.getName())) { + result.add(resource); + } + } + return result; + } + + /** + * used by the studio plugin + */ + public ResourceBundle getResourceBundle() { + return mResourceBundle; } public boolean processResources() @@ -72,92 +100,101 @@ public class LayoutXmlProcessor { } LayoutFileParser layoutFileParser = new LayoutFileParser(); int layoutId = 0; - for (File resFolder : Iterables.filter(mResourceFolders, fileExists)) { - for (File layoutFolder : resFolder.listFiles(layoutFolderFilter)) { - for (File xmlFile : layoutFolder.listFiles(xmlFileFilter)) { - final ResourceBundle.LayoutFileBundle bindingLayout = layoutFileParser - .parseXml(xmlFile, mResourceBundle.getAppPackage(), layoutId); - if (bindingLayout != null && !bindingLayout.isEmpty()) { - mResourceBundle.addLayoutBundle(bindingLayout, layoutId); - layoutId++; - } - } + for (File xmlFile : getLayoutFiles(mResources)) { + final ResourceBundle.LayoutFileBundle bindingLayout = layoutFileParser + .parseXml(xmlFile, mResourceBundle.getAppPackage(), layoutId); + if (bindingLayout != null && !bindingLayout.isEmpty()) { + mResourceBundle.addLayoutBundle(bindingLayout, layoutId); + layoutId++; } } mProcessingComplete = true; return true; } - public ResourceBundle getResourceBundle() { - return mResourceBundle; - } - - public void writeIntermediateFile(File sdkDir) throws JAXBException { + public void writeIntermediateFile(File sdkDir, File xmlOutDir) throws JAXBException { if (mWritten) { return; } JAXBContext context = JAXBContext.newInstance(ResourceBundle.LayoutFileBundle.class); Marshaller marshaller = context.createMarshaller(); - writeAppInfo(marshaller, sdkDir); + writeInfoClass(marshaller, sdkDir, xmlOutDir); for (List<ResourceBundle.LayoutFileBundle> layouts : mResourceBundle.getLayoutBundles() .values()) { for (ResourceBundle.LayoutFileBundle layout : layouts) { - writeAnnotatedFile(layout, marshaller); + writeXmlFile(xmlOutDir, layout, marshaller); } } mWritten = true; } - private void writeAnnotatedFile(ResourceBundle.LayoutFileBundle layout, Marshaller marshaller) + private void writeXmlFile(File xmlOutDir, ResourceBundle.LayoutFileBundle layout, + Marshaller marshaller) throws JAXBException { + String filename = generateExportFileName(layout) + ".xml"; + String xml = toXML(layout, marshaller); + mFileWriter.writeToFile(new File(xmlOutDir, filename), xml); + } + + public String getInfoClassFullName() { + return RESOURCE_BUNDLE_PACKAGE + "." + CLASS_NAME; + } + + private String toXML(ResourceBundle.LayoutFileBundle layout, Marshaller marshaller) throws JAXBException { - StringBuilder className = new StringBuilder(layout.getFileName()); - className.append('-').append(layout.getDirectory()); - for (int i = className.length() - 1; i >= 0; i--) { - char c = className.charAt(i); + StringWriter writer = new StringWriter(); + marshaller.marshal(layout, writer); + return writer.getBuffer().toString(); + } + + /** + * Generates a string identifier that can uniquely identify the given layout bundle. + * This identifier can be used when we need to export data about this layout bundle. + */ + private String generateExportFileName(ResourceBundle.LayoutFileBundle layout) { + StringBuilder name = new StringBuilder(layout.getFileName()); + name.append('-').append(layout.getDirectory()); + for (int i = name.length() - 1; i >= 0; i--) { + char c = name.charAt(i); if (c == '-') { - className.deleteCharAt(i); - c = Character.toUpperCase(className.charAt(i)); - className.setCharAt(i, c); + name.deleteCharAt(i); + c = Character.toUpperCase(name.charAt(i)); + name.setCharAt(i, c); } } - className.setCharAt(0, Character.toUpperCase(className.charAt(0))); - StringWriter writer = new StringWriter(); - marshaller.marshal(layout, writer); - String xml = writer.getBuffer().toString(); - String classString = "import android.binding.BinderBundle;\n\n" + - "@BinderBundle(\"" + - Base64.encodeBase64String(xml.getBytes(StandardCharsets.UTF_8)) + - "\")\n" + - "public class " + className + " {}\n"; - mFileWriter.writeToFile(RESOURCE_BUNDLE_PACKAGE + className, classString); + return name.toString(); } - private void writeAppInfo(Marshaller marshaller, File sdkDir) { + private void writeInfoClass(Marshaller marshaller, File sdkDir, File xmlOutDir) { final String sdkPath = StringEscapeUtils.escapeJava(sdkDir.getAbsolutePath()); - String classString = "import android.binding.BindingAppInfo;\n\n" + - "@BindingAppInfo(buildId=\"" + mBuildId + "\", " + - "applicationPackage=\"" + mResourceBundle.getAppPackage() + "\", " + + final Class annotation = BindingBuildInfo.class; + final String layoutInfoPath = StringEscapeUtils.escapeJava(xmlOutDir.getAbsolutePath()); + String classString = "package " + RESOURCE_BUNDLE_PACKAGE + ";\n\n" + + "import " + annotation.getCanonicalName() + ";\n\n" + + "@" + annotation.getSimpleName() + "(buildId=\"" + mBuildId + "\", " + + "modulePackage=\"" + mResourceBundle.getAppPackage() + "\", " + "sdkRoot=\"" + sdkPath + "\", " + + "layoutInfoDir=\"" + layoutInfoPath + "\"," + + "isLibrary=" + mIsLibrary + "," + "minSdk=" + mMinSdk + ")\n" + - "public class " + APPLICATION_INFO_CLASS + " {}\n"; - mFileWriter.writeToFile(RESOURCE_BUNDLE_PACKAGE + APPLICATION_INFO_CLASS, classString); + "public class " + CLASS_NAME + " {}\n"; + mFileWriter.writeToFile(mResourceBundle.getAppPackage() + "." + CLASS_NAME, classString); } - private final Predicate<File> fileExists = new Predicate<File>() { + private static final Predicate<File> fileExists = new Predicate<File>() { @Override public boolean apply(File input) { return input.exists() && input.canRead(); } }; - private final FilenameFilter layoutFolderFilter = new FilenameFilter() { + private static final FilenameFilter layoutFolderFilter = new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.startsWith("layout"); } }; - private final FilenameFilter xmlFileFilter = new FilenameFilter() { + private static final FilenameFilter xmlFileFilter = new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.toLowerCase().endsWith(".xml"); diff --git a/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java b/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java index 63cbc38b..9a7ef2f4 100644 --- a/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java +++ b/compiler/src/main/java/com/android/databinding/reflection/ModelAnalyzer.java @@ -209,8 +209,6 @@ public abstract class ModelAnalyzer { public abstract ModelClass findClass(String className, Map<String, String> imports); - public abstract List<URL> getResources(String name); - public abstract ModelClass findClass(Class classType); public abstract TypeUtil createTypeUtil(); diff --git a/compiler/src/main/java/com/android/databinding/reflection/annotation/AnnotationAnalyzer.java b/compiler/src/main/java/com/android/databinding/reflection/annotation/AnnotationAnalyzer.java index ca40f2e8..92c6aa8c 100644 --- a/compiler/src/main/java/com/android/databinding/reflection/annotation/AnnotationAnalyzer.java +++ b/compiler/src/main/java/com/android/databinding/reflection/annotation/AnnotationAnalyzer.java @@ -439,21 +439,6 @@ public class AnnotationAnalyzer extends ModelAnalyzer { } @Override - public List<URL> getResources(String name) { - ArrayList<URL> urls = new ArrayList<URL>(); - try { - Enumeration<URL> resources = getClass().getClassLoader().getResources(name); - while (resources.hasMoreElements()) { - urls.add(resources.nextElement()); - } - } catch (IOException e) { - L.e(e, "IOException while getting resources:"); - } - - return urls; - } - - @Override public ModelClass findClass(Class classType) { return findClass(classType.getCanonicalName(), null); } diff --git a/compiler/src/main/java/com/android/databinding/store/LayoutFileParser.java b/compiler/src/main/java/com/android/databinding/store/LayoutFileParser.java index 752562ba..99efe6ba 100644 --- a/compiler/src/main/java/com/android/databinding/store/LayoutFileParser.java +++ b/compiler/src/main/java/com/android/databinding/store/LayoutFileParser.java @@ -67,7 +67,7 @@ public class LayoutFileParser { ResourceBundle.LayoutFileBundle bundle = new ResourceBundle.LayoutFileBundle( ParserHelper.INSTANCE$.stripExtension(xml.getName()), layoutId, - xml.getParentFile().getName()); + xml.getParentFile().getName(), pkg); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); final DocumentBuilder builder = factory.newDocumentBuilder(); diff --git a/compiler/src/main/java/com/android/databinding/store/ResourceBundle.java b/compiler/src/main/java/com/android/databinding/store/ResourceBundle.java index 767cc34e..a781417b 100644 --- a/compiler/src/main/java/com/android/databinding/store/ResourceBundle.java +++ b/compiler/src/main/java/com/android/databinding/store/ResourceBundle.java @@ -57,7 +57,15 @@ public class ResourceBundle implements Serializable { mLayoutBundles.put(bundle.mFileName, new ArrayList<LayoutFileBundle>()); } bundle.mLayoutId = layoutId; - mLayoutBundles.get(bundle.mFileName).add(bundle); + final List<LayoutFileBundle> bundles = mLayoutBundles.get(bundle.mFileName); + for (LayoutFileBundle existing : bundles) { + if (existing.equals(bundle)) { + L.d("skipping layout bundle %s because it already exists.", bundle); + return; + } + } + L.d("adding bundle %s", bundle); + bundles.add(bundle); } public HashMap<String, List<LayoutFileBundle>> getLayoutBundles() { @@ -200,6 +208,8 @@ public class ResourceBundle implements Serializable { public int mLayoutId; @XmlAttribute(name="layout", required = true) public String mFileName; + @XmlAttribute(name="modulePackage", required = true) + public String mModulePackage; private String mConfigName; @XmlAttribute(name="directory", required = true) @@ -222,10 +232,12 @@ public class ResourceBundle implements Serializable { public LayoutFileBundle() { } - public LayoutFileBundle(String fileName, int layoutId, String directory) { + public LayoutFileBundle(String fileName, int layoutId, String directory, + String modulePackage) { mFileName = fileName; mLayoutId = layoutId; mDirectory = directory; + mModulePackage = modulePackage; } public void addVariable(String name, String type) { @@ -288,6 +300,57 @@ public class ResourceBundle implements Serializable { public List<BindingTargetBundle> getBindingTargetBundles() { return mBindingTargetBundles; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + LayoutFileBundle bundle = (LayoutFileBundle) o; + + if (mConfigName != null ? !mConfigName.equals(bundle.mConfigName) + : bundle.mConfigName != null) { + return false; + } + if (mDirectory != null ? !mDirectory.equals(bundle.mDirectory) + : bundle.mDirectory != null) { + return false; + } + if (mFileName != null ? !mFileName.equals(bundle.mFileName) + : bundle.mFileName != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = mFileName != null ? mFileName.hashCode() : 0; + result = 31 * result + (mConfigName != null ? mConfigName.hashCode() : 0); + result = 31 * result + (mDirectory != null ? mDirectory.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "LayoutFileBundle{" + + "mHasVariations=" + mHasVariations + + ", mDirectory='" + mDirectory + '\'' + + ", mConfigName='" + mConfigName + '\'' + + ", mModulePackage='" + mModulePackage + '\'' + + ", mFileName='" + mFileName + '\'' + + ", mLayoutId=" + mLayoutId + + '}'; + } + + public String getModulePackage() { + return mModulePackage; + } } @XmlAccessorType(XmlAccessType.NONE) diff --git a/compiler/src/main/java/com/android/databinding/store/SetterStore.java b/compiler/src/main/java/com/android/databinding/store/SetterStore.java index fe14b7e5..a34c8c58 100644 --- a/compiler/src/main/java/com/android/databinding/store/SetterStore.java +++ b/compiler/src/main/java/com/android/databinding/store/SetterStore.java @@ -18,6 +18,7 @@ package com.android.databinding.store; import com.android.databinding.reflection.ModelAnalyzer; import com.android.databinding.reflection.ModelClass; import com.android.databinding.reflection.ModelMethod; +import com.android.databinding.util.GenerationalClassUtil; import com.android.databinding.util.L; import org.apache.commons.lang3.StringUtils; @@ -30,6 +31,7 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -50,7 +52,7 @@ import javax.tools.StandardLocation; public class SetterStore { - public static final String SETTER_STORE_FILE_NAME = "setter_store.bin"; + public static final String SETTER_STORE_FILE_EXT = "-setter_store.bin"; private static SetterStore sStore; @@ -62,70 +64,24 @@ public class SetterStore { mStore = store; } - public static SetterStore get(ProcessingEnvironment processingEnvironment) { - if (sStore == null) { - InputStream in = null; - try { - Filer filer = processingEnvironment.getFiler(); - FileObject resource = filer.getResource(StandardLocation.CLASS_OUTPUT, - SetterStore.class.getPackage().getName(), SETTER_STORE_FILE_NAME); - if (resource != null && new File(resource.getName()).exists()) { - in = resource.openInputStream(); - if (in != null) { - sStore = load(in); - } - } - } catch (IOException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - if (sStore == null) { - sStore = new SetterStore(null, new IntermediateV1()); - } - } - return sStore; - } - public static SetterStore get(ModelAnalyzer modelAnalyzer) { if (sStore == null) { - sStore = load(modelAnalyzer); + sStore = load(modelAnalyzer, SetterStore.class.getClassLoader()); } return sStore; } - private static SetterStore load(ModelAnalyzer modelAnalyzer) { + private static SetterStore load(ModelAnalyzer modelAnalyzer, ClassLoader classLoader) { IntermediateV1 store = new IntermediateV1(); - String resourceName = SetterStore.class.getPackage().getName().replace('.', '/') + - '/' + SETTER_STORE_FILE_NAME; - try { - for (URL resource : modelAnalyzer.getResources(resourceName)) { - merge(store, resource); - } - return new SetterStore(modelAnalyzer, store); - } catch (IOException e) { - L.e(e, "Could not read SetterStore intermediate file"); - } catch (ClassNotFoundException e) { - L.e(e, "Could not read SetterStore intermediate file"); + List<Intermediate> previousStores = GenerationalClassUtil + .loadObjects(classLoader, + new GenerationalClassUtil.ExtensionFilter(SETTER_STORE_FILE_EXT)); + for (Intermediate intermediate : previousStores) { + merge(store, intermediate); } return new SetterStore(modelAnalyzer, store); } - private static SetterStore load(InputStream inputStream) - throws IOException, ClassNotFoundException { - ObjectInputStream in = new ObjectInputStream(inputStream); - Intermediate intermediate = (Intermediate) in.readObject(); - return new SetterStore(null, (IntermediateV1) intermediate.upgrade()); - } - public void addRenamedMethod(String attribute, String declaringClass, String method, TypeElement declaredOn) { HashMap<String, MethodDescription> renamed = mStore.renamedMethods.get(attribute); @@ -135,10 +91,12 @@ public class SetterStore { } MethodDescription methodDescription = new MethodDescription(declaredOn.getQualifiedName().toString(), method); + L.d("STORE addmethod desc %s", methodDescription); renamed.put(declaringClass, methodDescription); } public void addBindingAdapter(String attribute, ExecutableElement bindingMethod) { + L.d("STORE addBindingAdapter %s %s", attribute, bindingMethod); HashMap<AccessorKey, MethodDescription> adapters = mStore.adapterMethods.get(attribute); if (adapters == null) { @@ -158,6 +116,7 @@ public class SetterStore { } public void addUntaggableTypes(String[] typeNames, TypeElement declaredOn) { + L.d("STORE addUntaggableTypes %s %s", Arrays.toString(typeNames), declaredOn); String declaredType = declaredOn.getQualifiedName().toString(); for (String type : typeNames) { mStore.untaggableTypes.put(type, declaredType); @@ -187,6 +146,7 @@ public class SetterStore { } public void addConversionMethod(ExecutableElement conversionMethod) { + L.d("STORE addConversionMethod %s", conversionMethod); List<? extends VariableElement> parameters = conversionMethod.getParameters(); String fromType = getQualifiedName(parameters.get(0).asType()); String toType = getQualifiedName(conversionMethod.getReturnType()); @@ -248,21 +208,10 @@ public class SetterStore { keys.clear(); } - public void write(ProcessingEnvironment processingEnvironment) throws IOException { - Filer filer = processingEnvironment.getFiler(); - FileObject resource = filer.createResource(StandardLocation.CLASS_OUTPUT, - SetterStore.class.getPackage().getName(), "setter_store.bin"); - L.d("============= Writing intermediate file: %s", resource.getName()); - ObjectOutputStream out = null; - try { - out = new ObjectOutputStream(resource.openOutputStream()); - - out.writeObject(mStore); - } finally { - if (out != null) { - out.close(); - } - } + public void write(String projectPackage, ProcessingEnvironment processingEnvironment) + throws IOException { + GenerationalClassUtil.writeIntermediateFile(processingEnvironment, + projectPackage, projectPackage + SETTER_STORE_FILE_EXT, mStore); } public SetterCall getSetterCall(String attribute, ModelClass viewType, @@ -503,27 +452,12 @@ public class SetterStore { } } - private static void merge(IntermediateV1 store, - URL nextUrl) throws IOException, ClassNotFoundException { - InputStream inputStream = null; - JarFile jarFile = null; - try { - inputStream = nextUrl.openStream(); - ObjectInputStream in = new ObjectInputStream(inputStream); - Intermediate intermediate = (Intermediate) in.readObject(); - IntermediateV1 intermediateV1 = (IntermediateV1) intermediate.upgrade(); - merge(store.adapterMethods, intermediateV1.adapterMethods); - merge(store.renamedMethods, intermediateV1.renamedMethods); - merge(store.conversionMethods, intermediateV1.conversionMethods); - store.untaggableTypes.putAll(intermediateV1.untaggableTypes); - } finally { - if (inputStream != null) { - inputStream.close(); - } - if (jarFile != null) { - jarFile.close(); - } - } + private static void merge(IntermediateV1 store, Intermediate dumpStore) { + IntermediateV1 intermediateV1 = (IntermediateV1) dumpStore.upgrade(); + merge(store.adapterMethods, intermediateV1.adapterMethods); + merge(store.renamedMethods, intermediateV1.renamedMethods); + merge(store.conversionMethods, intermediateV1.conversionMethods); + store.untaggableTypes.putAll(intermediateV1.untaggableTypes); } private static <K, V> void merge(HashMap<K, HashMap<V, MethodDescription>> first, @@ -619,7 +553,7 @@ public class SetterStore { } } - private interface Intermediate { + private interface Intermediate extends Serializable { Intermediate upgrade(); } diff --git a/compiler/src/main/java/com/android/databinding/util/GenerationalClassUtil.java b/compiler/src/main/java/com/android/databinding/util/GenerationalClassUtil.java new file mode 100644 index 00000000..c970ad53 --- /dev/null +++ b/compiler/src/main/java/com/android/databinding/util/GenerationalClassUtil.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.util; + +import com.android.databinding.util.L; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.filefilter.IOFileFilter; +import org.apache.commons.io.filefilter.TrueFileFilter; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.tools.FileObject; +import javax.tools.StandardLocation; + +/** + * A utility class that helps adding build specific objects to the jar file + * and their extraction later on. + */ +public class GenerationalClassUtil { + public static <T extends Serializable> List<T> loadObjects(ClassLoader classLoader, Filter filter) { + final List<T> result = new ArrayList<T>(); + if (!(classLoader instanceof URLClassLoader)) { + L.d("class loader is not url class loader (%s). skipping.", classLoader.getClass()); + return result; + } + final URLClassLoader urlClassLoader = (URLClassLoader) classLoader; + for (URL url : urlClassLoader.getURLs()) { + L.d("checking url %s for intermediate data", url); + try { + final File file = new File(url.toURI()); + if (!file.exists()) { + L.d("cannot load file for %s", url); + continue; + } + if (file.isDirectory()) { + // probably exported classes dir. + loadFromDirectory(filter, result, file); + } else { + // assume it is a zip file + loadFomZipFile(filter, result, file); + } + } catch (IOException e) { + L.d("cannot open zip file from %s", url); + } catch (URISyntaxException e) { + L.d("cannot open zip file from %s", url); + } + } + return result; + } + + private static <T extends Serializable> void loadFromDirectory(final Filter filter, List<T> result, + File directory) { + //noinspection unchecked + Collection<File> files = FileUtils.listFiles(directory, new IOFileFilter() { + @Override + public boolean accept(File file) { + return filter.accept(file.getName()); + } + + @Override + public boolean accept(File dir, String name) { + return filter.accept(name); + } + }, TrueFileFilter.INSTANCE); + for (File file : files) { + InputStream inputStream = null; + try { + inputStream = FileUtils.openInputStream(file); + T item = fromInputStream(result, inputStream); + L.d("loaded item %s from file", item); + if (item != null) { + result.add(item); + } + } catch (IOException e) { + L.e(e, "Could not merge in Bindables from %s", file.getAbsolutePath()); + } catch (ClassNotFoundException e) { + L.e(e, "Could not read Binding properties intermediate file. %s", file.getAbsolutePath()); + } finally { + IOUtils.closeQuietly(inputStream); + } + } + } + + private static <T extends Serializable> void loadFomZipFile(Filter filter, + List<T> result, File file) throws IOException { + ZipFile zipFile = new ZipFile(file); + Enumeration<? extends ZipEntry> entries = zipFile.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + if (!filter.accept(entry.getName())) { + continue; + } + L.d("loading data from file %s", entry.getName()); + InputStream inputStream = null; + try { + inputStream = zipFile.getInputStream(entry); + T item = fromInputStream(result, inputStream); + L.d("loaded item %s from zip file", item); + if (item != null) { + result.add(item); + } + } catch (IOException e) { + L.e(e, "Could not merge in Bindables from %s", file.getAbsolutePath()); + } catch (ClassNotFoundException e) { + L.e(e, "Could not read Binding properties intermediate file. %s", file.getAbsolutePath()); + } finally { + IOUtils.closeQuietly(inputStream); + } + } + } + + private static <T extends Serializable> T fromInputStream(List<T> result, + InputStream inputStream) throws IOException, ClassNotFoundException { + ObjectInputStream in = new ObjectInputStream(inputStream); + return (T) in.readObject(); + + } + + public static void writeIntermediateFile(ProcessingEnvironment processingEnv, + String packageName, String fileName, Serializable object) { + ObjectOutputStream oos = null; + try { + FileObject intermediate = processingEnv.getFiler().createResource( + StandardLocation.CLASS_OUTPUT, packageName, + fileName); + OutputStream ios = intermediate.openOutputStream(); + oos = new ObjectOutputStream(ios); + oos.writeObject(object); + oos.close(); + L.d("wrote intermediate bindable file %s %s", packageName, fileName); + } catch (IOException e) { + L.e(e, "Could not write to intermediate file: %s", fileName); + } finally { + IOUtils.closeQuietly(oos); + } + } + + + public static interface Filter { + public boolean accept(String entryName); + } + + public static class ExtensionFilter implements Filter { + private final String mExtension; + public ExtensionFilter(String extension) { + mExtension = extension; + } + + @Override + public boolean accept(String entryName) { + return entryName.endsWith(mExtension); + } + } +} diff --git a/compiler/src/main/java/com/android/databinding/writer/AnnotationJavaFileWriter.java b/compiler/src/main/java/com/android/databinding/writer/AnnotationJavaFileWriter.java index 67d274ed..d24ac04a 100644 --- a/compiler/src/main/java/com/android/databinding/writer/AnnotationJavaFileWriter.java +++ b/compiler/src/main/java/com/android/databinding/writer/AnnotationJavaFileWriter.java @@ -15,8 +15,14 @@ */ package com.android.databinding.writer; +import com.google.common.base.Preconditions; + +import com.android.databinding.util.L; + +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +import java.io.File; import java.io.IOException; import java.io.Writer; @@ -24,7 +30,7 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -public class AnnotationJavaFileWriter implements JavaFileWriter { +public class AnnotationJavaFileWriter extends JavaFileWriter { private final ProcessingEnvironment mProcessingEnvironment; public AnnotationJavaFileWriter(ProcessingEnvironment processingEnvironment) { @@ -35,13 +41,13 @@ public class AnnotationJavaFileWriter implements JavaFileWriter { public void writeToFile(String canonicalName, String contents) { Writer writer = null; try { + L.d("writing file %s", canonicalName); JavaFileObject javaFileObject = mProcessingEnvironment.getFiler().createSourceFile(canonicalName); writer = javaFileObject.openWriter(); writer.write(contents); } catch (IOException e) { - mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.ERROR, - "Could not write to " + canonicalName + ": " + e.getLocalizedMessage()); + L.e(e, "Could not write to %s", canonicalName); } finally { if (writer != null) { IOUtils.closeQuietly(writer); diff --git a/compiler/src/main/java/com/android/databinding/writer/JavaFileWriter.java b/compiler/src/main/java/com/android/databinding/writer/JavaFileWriter.java index f7b3c9ce..9fa93477 100644 --- a/compiler/src/main/java/com/android/databinding/writer/JavaFileWriter.java +++ b/compiler/src/main/java/com/android/databinding/writer/JavaFileWriter.java @@ -13,6 +13,23 @@ package com.android.databinding.writer; -public interface JavaFileWriter { - public void writeToFile(String canonicalName, String contents); +import com.android.databinding.util.L; + +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; + +public abstract class JavaFileWriter { + public abstract void writeToFile(String canonicalName, String contents); + public void writeToFile(File exactPath, String contents) { + File parent = exactPath.getParentFile(); + parent.mkdirs(); + try { + L.d("writing file %s", exactPath.getAbsoluteFile()); + FileUtils.writeStringToFile(exactPath, contents); + } catch (IOException e) { + L.e(e, "Could not write to %s", exactPath); + } + } } diff --git a/compiler/src/main/kotlin/com/android/databinding/ext/ext.kt b/compiler/src/main/kotlin/com/android/databinding/ext/ext.kt index b7abeb7e..11804ff9 100644 --- a/compiler/src/main/kotlin/com/android/databinding/ext/ext.kt +++ b/compiler/src/main/kotlin/com/android/databinding/ext/ext.kt @@ -77,4 +77,4 @@ public fun String.toCamelCaseAsVar() : String { } public fun String.br() : String = - "android.binding.BR.${if (this == "") "_all" else this}" + "BR.${if (this == "") "_all" else this}" diff --git a/compiler/src/main/kotlin/com/android/databinding/util/XmlEditor.kt b/compiler/src/main/kotlin/com/android/databinding/util/XmlEditor.kt index b1531fc4..ad79405f 100644 --- a/compiler/src/main/kotlin/com/android/databinding/util/XmlEditor.kt +++ b/compiler/src/main/kotlin/com/android/databinding/util/XmlEditor.kt @@ -131,7 +131,8 @@ object XmlEditor { Preconditions.checkNotNull(rootNodeContext, "Cannot find root node for ${f.getName()}") Preconditions.checkState(rootNodeHasTag == false, """You cannot set a tag in the layout root if you are using binding. Invalid file: ${f}""") - val rootNodeBounds = Pair(rootNodeContext!!.getStart().toPosition(), rootNodeContext!!.getStop().toEndPosition()) + val rootNodeBounds = Pair(rootNodeContext!!.getStart().toPosition(), + rootNodeContext!!.getStop().toEndPosition()) log { "root node bounds: ${rootNodeBounds}" } val out = StringBuilder() diff --git a/compiler/src/main/kotlin/com/android/databinding/writer/DataBinderWriter.kt b/compiler/src/main/kotlin/com/android/databinding/writer/DataBinderWriter.kt index d52a6122..7b3638e3 100644 --- a/compiler/src/main/kotlin/com/android/databinding/writer/DataBinderWriter.kt +++ b/compiler/src/main/kotlin/com/android/databinding/writer/DataBinderWriter.kt @@ -19,13 +19,13 @@ class DataBinderWriter(val pkg: String, val projectPackage: String, val classNam fun write() = kcode("") { nl("package $pkg;") - nl("import $projectPackage.R;") + nl("import $projectPackage.BR;") nl("public class $className implements com.android.databinding.library.DataBinderMapper {") { tab("@Override") tab("public com.android.databinding.library.ViewDataBinding getDataBinder(android.view.View view, int layoutId) {") { tab("switch(layoutId) {") { layoutBinders.groupBy{it.getLayoutname()}.forEach { - tab("case R.layout.${it.value.first!!.getLayoutname()}:") { + tab("case ${it.value.first!!.getModulePackage()}.R.layout.${it.value.first!!.getLayoutname()}:") { if (it.value.size() == 1) { tab("return new ${it.value.first!!.getPackage()}.${it.value.first!!.getClassName()}(view);") } else { @@ -51,7 +51,7 @@ class DataBinderWriter(val pkg: String, val projectPackage: String, val classNam tab("}") tab("public int getId(String key) {") { - tab("return android.binding.BR.getId(key);") + tab("return BR.getId(key);") } tab("}") } nl("}") diff --git a/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt b/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt index fec3b460..e82de91d 100644 --- a/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt +++ b/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt @@ -331,7 +331,8 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { public fun write() : String { layoutBinder.resolveWhichExpressionsAreUsed() return kcode("package ${layoutBinder.getPackage()};") { - nl("import ${layoutBinder.getProjectPackage()}.R;") + nl("import ${layoutBinder.getModulePackage()}.R;") + nl("import ${layoutBinder.getModulePackage()}.BR;") nl("import android.view.View;") nl("public class ${className} extends ${baseClassName} {") { tab(declareIncludeViews()) @@ -401,7 +402,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { if (originalTag != null) { tagValue = "\"${originalTag}\"" if (originalTag.startsWith("@")) { - var packageName = layoutBinder.getProjectPackage() + var packageName = layoutBinder.getModulePackage() if (originalTag.startsWith("@android:")) { packageName = "android" } @@ -749,15 +750,15 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { } nl("") tab("public static ${baseClassName} inflate(android.view.ViewGroup root) {") { - tab("return DataBindingUtil.<${baseClassName}>inflate(root.getContext(), ${layoutBinder.getProjectPackage()}.R.layout.${layoutBinder.getLayoutname()}, root, true);") + tab("return DataBindingUtil.<${baseClassName}>inflate(root.getContext(), ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, root, true);") } tab("}") tab("public static ${baseClassName} inflate(android.content.Context context) {") { - tab("return DataBindingUtil.<${baseClassName}>inflate(context, ${layoutBinder.getProjectPackage()}.R.layout.${layoutBinder.getLayoutname()}, null, false);") + tab("return DataBindingUtil.<${baseClassName}>inflate(context, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()}, null, false);") } tab("}") tab("public static ${baseClassName} bind(android.view.View view) {") { - tab("return (${baseClassName})DataBindingUtil.bindTo(view, ${layoutBinder.getProjectPackage()}.R.layout.${layoutBinder.getLayoutname()});") + tab("return (${baseClassName})DataBindingUtil.bindTo(view, ${layoutBinder.getModulePackage()}.R.layout.${layoutBinder.getLayoutname()});") } tab("}") nl("}") diff --git a/compiler/src/test/java/com/android/databinding/MockLayoutBinder.java b/compiler/src/test/java/com/android/databinding/MockLayoutBinder.java index 6ef97d23..dc57437a 100644 --- a/compiler/src/test/java/com/android/databinding/MockLayoutBinder.java +++ b/compiler/src/test/java/com/android/databinding/MockLayoutBinder.java @@ -19,6 +19,6 @@ public class MockLayoutBinder extends LayoutBinder { public MockLayoutBinder() { super(new ResourceBundle("com.test"), - new ResourceBundle.LayoutFileBundle("blah.xml", 1, ".")); + new ResourceBundle.LayoutFileBundle("blah.xml", 1, ".", "com.test.submodule")); } }
\ No newline at end of file diff --git a/compiler/src/test/java/com/android/databinding/reflection/java/JavaAnalyzer.java b/compiler/src/test/java/com/android/databinding/reflection/java/JavaAnalyzer.java index c6c7cf17..1e88f84f 100644 --- a/compiler/src/test/java/com/android/databinding/reflection/java/JavaAnalyzer.java +++ b/compiler/src/test/java/com/android/databinding/reflection/java/JavaAnalyzer.java @@ -314,23 +314,6 @@ public class JavaAnalyzer extends ModelAnalyzer { } } - @Override - public List<URL> getResources(String name) { - List<URL> urlList = new ArrayList<URL>(); - Enumeration<URL> urls = null; - try { - urls = mClassLoader.getResources(name); - if (urls != null) { - while (urls.hasMoreElements()) { - urlList.add(urls.nextElement()); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - return urlList; - } - public static void initForTests() { Map<String, String> env = System.getenv(); for (Map.Entry<String, String> entry : env.entrySet()) { diff --git a/databinding.properties b/databinding.properties index 7974fa99..d0c3576c 100644 --- a/databinding.properties +++ b/databinding.properties @@ -6,3 +6,6 @@ androidPluginVersion = 1.0.1 javaTargetCompatibility = 1.6 javaSourceCompatibility = 1.6 mavenRepoName=maven-repo +group=com.android.databinding +testGroup=com.android.databinding.test + diff --git a/extensions/baseAdapters/build.gradle b/extensions/baseAdapters/build.gradle new file mode 100644 index 00000000..74e90365 --- /dev/null +++ b/extensions/baseAdapters/build.gradle @@ -0,0 +1,96 @@ +/* + * 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: 'maven' +apply plugin: 'com.android.library' +apply plugin: 'com.android.databinding' + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.2" + + 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' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' + } +} + +dependencies { + compile "com.android.databinding:baseLibrary:${config.snapshotVersion}" + provided "com.android.databinding:annotationprocessor:${config.snapshotVersion}" + compile 'com.android.support:support-v4:+' + compile 'com.android.support:cardview-v7:+' + compile 'com.android.support:appcompat-v7:+' +} + +configurations { + jarArchives +} + + +//create jar tasks +android.libraryVariants.all { variant -> + def name = variant.buildType.name + + if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) { + return; // Skip debug builds. + } + // @Jar version is needed to run compiler tests + def task = project.tasks.create "jar${name.capitalize()}", Jar + task.dependsOn variant.javaCompile + task.from variant.javaCompile.destinationDir + def packageName = "com.android.databinding.library.baseAdapters" + def appPkgAsClass = packageName.replace('.', '/') + task.exclude("com/android/databinding/layouts/*.*") + task.exclude("$appPkgAsClass/generated/*") + task.exclude("$appPkgAsClass/BR.*") + artifacts.add('jarArchives', task); +} + +uploadArchives { +} + +uploadJarArchives { + repositories { + mavenDeployer { + repository(url: "file://${config.mavenRepoDir}") + pom.artifactId = "adapters" + pom.whenConfigured { + println("configured pom, $it") + it.dependencies.find {dep -> dep.groupId == 'com.android.support' && dep.artifactId == 'support-v4' }.optional = true + it.dependencies.find {dep -> dep.groupId == 'com.android.support' && dep.artifactId == 'cardview-v7' }.optional = true + it.dependencies.find {dep -> dep.groupId == 'com.android.support' && dep.artifactId == 'appcompat-v7' }.optional = true + } + } + } +} + +uploadArchives.dependsOn uploadJarArchives diff --git a/extensions/baseAdapters/src/main/AndroidManifest.xml b/extensions/baseAdapters/src/main/AndroidManifest.xml new file mode 100644 index 00000000..38cf7790 --- /dev/null +++ b/extensions/baseAdapters/src/main/AndroidManifest.xml @@ -0,0 +1,19 @@ +<!-- + ~ 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="com.android.databinding.library.baseAdapters"> +</manifest> diff --git a/library/src/main/java/android/binding/adapters/AbsListViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/AbsListViewBindingAdapter.java index c8b481d4..c8b481d4 100644 --- a/library/src/main/java/android/binding/adapters/AbsListViewBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/AbsListViewBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/AbsSeekBarBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/AbsSeekBarBindingAdapter.java index f02be48c..f02be48c 100644 --- a/library/src/main/java/android/binding/adapters/AbsSeekBarBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/AbsSeekBarBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/AbsSpinnerBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/AbsSpinnerBindingAdapter.java index b02ff074..b02ff074 100644 --- a/library/src/main/java/android/binding/adapters/AbsSpinnerBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/AbsSpinnerBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/AutoCompleteTextViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/AutoCompleteTextViewBindingAdapter.java index 79c06a8a..79c06a8a 100644 --- a/library/src/main/java/android/binding/adapters/AutoCompleteTextViewBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/AutoCompleteTextViewBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/CardViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/CardViewBindingAdapter.java index ba5246dd..ba5246dd 100644 --- a/library/src/main/java/android/binding/adapters/CardViewBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/CardViewBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/CheckedTextViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/CheckedTextViewBindingAdapter.java index 3b16d080..3b16d080 100644 --- a/library/src/main/java/android/binding/adapters/CheckedTextViewBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/CheckedTextViewBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/CompoundButtonBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/CompoundButtonBindingAdapter.java index 7115bc5c..7115bc5c 100644 --- a/library/src/main/java/android/binding/adapters/CompoundButtonBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/CompoundButtonBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/Converters.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/Converters.java index 5982dc12..5982dc12 100644 --- a/library/src/main/java/android/binding/adapters/Converters.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/Converters.java diff --git a/library/src/main/java/android/binding/adapters/FrameLayoutBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/FrameLayoutBindingAdapter.java index 49aa6a5b..49aa6a5b 100644 --- a/library/src/main/java/android/binding/adapters/FrameLayoutBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/FrameLayoutBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/ImageViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/ImageViewBindingAdapter.java index e2d09293..e2d09293 100644 --- a/library/src/main/java/android/binding/adapters/ImageViewBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/ImageViewBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/LinearLayoutBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/LinearLayoutBindingAdapter.java index b0a4cc43..b0a4cc43 100644 --- a/library/src/main/java/android/binding/adapters/LinearLayoutBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/LinearLayoutBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/ProgressBarBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/ProgressBarBindingAdapter.java index b0d6249e..b0d6249e 100644 --- a/library/src/main/java/android/binding/adapters/ProgressBarBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/ProgressBarBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/RadioGroupBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/RadioGroupBindingAdapter.java index 8d21b7af..8d21b7af 100644 --- a/library/src/main/java/android/binding/adapters/RadioGroupBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/RadioGroupBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/SpinnerBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/SpinnerBindingAdapter.java index 34a62c7e..34a62c7e 100644 --- a/library/src/main/java/android/binding/adapters/SpinnerBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/SpinnerBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/SwitchBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/SwitchBindingAdapter.java index 3645118a..3645118a 100644 --- a/library/src/main/java/android/binding/adapters/SwitchBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/SwitchBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/SwitchCompatBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/SwitchCompatBindingAdapter.java index 4c3c996a..4c3c996a 100644 --- a/library/src/main/java/android/binding/adapters/SwitchCompatBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/SwitchCompatBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/TabWidgetBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/TabWidgetBindingAdapter.java index 8c58e915..8c58e915 100644 --- a/library/src/main/java/android/binding/adapters/TabWidgetBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/TabWidgetBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/TableLayoutBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/TableLayoutBindingAdapter.java index 1973799e..1973799e 100644 --- a/library/src/main/java/android/binding/adapters/TableLayoutBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/TableLayoutBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/TextViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/TextViewBindingAdapter.java index 1cd5ef4f..1cd5ef4f 100644 --- a/library/src/main/java/android/binding/adapters/TextViewBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/TextViewBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/ViewBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/ViewBindingAdapter.java index 1e361cf2..1e361cf2 100644 --- a/library/src/main/java/android/binding/adapters/ViewBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/ViewBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/ViewGroupBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/ViewGroupBindingAdapter.java index 4448a30d..4448a30d 100644 --- a/library/src/main/java/android/binding/adapters/ViewGroupBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/ViewGroupBindingAdapter.java diff --git a/library/src/main/java/android/binding/adapters/ViewStubBindingAdapter.java b/extensions/baseAdapters/src/main/java/android/bindings/adapters/ViewStubBindingAdapter.java index f24ab03b..f24ab03b 100644 --- a/library/src/main/java/android/binding/adapters/ViewStubBindingAdapter.java +++ b/extensions/baseAdapters/src/main/java/android/bindings/adapters/ViewStubBindingAdapter.java diff --git a/extensions/build.gradle b/extensions/build.gradle new file mode 100644 index 00000000..cfa26978 --- /dev/null +++ b/extensions/build.gradle @@ -0,0 +1,45 @@ +/* + * 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. + */ + + +buildscript { + def Properties dataBindingProperties = new Properties() + dataBindingProperties.load(new FileInputStream("${projectDir}/../databinding.properties")) + dataBindingProperties.mavenRepoDir = "${projectDir}/../${dataBindingProperties.mavenRepoName}" + ext.config = dataBindingProperties + repositories { + jcenter() + maven { + url config.mavenRepoDir + } + } + dependencies { + classpath 'com.android.tools.build:gradle:1.1.3' + classpath "com.android.databinding:dataBinder:${config.snapshotVersion}" + } +} + +subprojects { + apply plugin: 'maven' + group = config.group + version = config.snapshotVersion + repositories { + mavenCentral() + maven { + url config.mavenRepoDir + } + } +}
\ No newline at end of file diff --git a/extensions/gradle/wrapper/gradle-wrapper.jar b/extensions/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 00000000..8c0fb64a --- /dev/null +++ b/extensions/gradle/wrapper/gradle-wrapper.jar diff --git a/extensions/gradle/wrapper/gradle-wrapper.properties b/extensions/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..e5fd8793 --- /dev/null +++ b/extensions/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Mar 12 15:27:48 PDT 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/extensions/gradlew b/extensions/gradlew new file mode 100755 index 00000000..91a7e269 --- /dev/null +++ b/extensions/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/extensions/settings.gradle b/extensions/settings.gradle new file mode 100644 index 00000000..80ebcc8c --- /dev/null +++ b/extensions/settings.gradle @@ -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. + */ + +/** + * These are projects that requires a compiled version of data binding. + */ +include ':baseAdapters' diff --git a/gradlePlugin/src/main/kotlin/DataBindingProcessLayoutsTask.kt b/gradlePlugin/src/main/kotlin/DataBindingProcessLayoutsTask.kt index 7732f96f..d89552cd 100644 --- a/gradlePlugin/src/main/kotlin/DataBindingProcessLayoutsTask.kt +++ b/gradlePlugin/src/main/kotlin/DataBindingProcessLayoutsTask.kt @@ -32,6 +32,9 @@ open class DataBindingProcessLayoutsTask : DefaultTask() { public fun doIt() { Log.d {"running process layouts task"} xmlProcessor.processResources() - xmlProcessor.writeIntermediateFile(sdkDir) + } + + public fun writeFiles(xmlOutFolder : File) { + xmlProcessor.writeIntermediateFile(sdkDir, xmlOutFolder) } }
\ No newline at end of file diff --git a/gradlePlugin/src/main/kotlin/plugin.kt b/gradlePlugin/src/main/kotlin/plugin.kt index 3741ba95..b991ed60 100644 --- a/gradlePlugin/src/main/kotlin/plugin.kt +++ b/gradlePlugin/src/main/kotlin/plugin.kt @@ -54,10 +54,22 @@ import org.apache.commons.codec.binary.Base64 import com.android.builder.model.ApiVersion import com.android.databinding.util.Log import org.gradle.api.Action +import com.android.build.gradle.BaseExtension +import com.android.build.gradle.LibraryExtension +import com.android.build.gradle.api.LibraryVariant +import com.android.build.gradle.api.ApplicationVariant +import com.android.build.gradle.api.BaseVariant +import com.android.build.gradle.internal.variant.BaseVariantData +import com.android.build.gradle.internal.variant.ApkVariantData +import com.android.build.gradle.internal.variant.LibraryVariantData +import com.android.build.gradle.internal.api.LibraryVariantImpl +import com.android.build.gradle.api.TestVariant +import com.android.build.gradle.internal.variant.TestVariantData +import com.android.build.gradle.internal.api.TestVariantImpl class DataBinderPlugin : Plugin<Project> { - inner class GradleFileWriter(var outputBase: String) : JavaFileWriter { + inner class GradleFileWriter(var outputBase: String) : JavaFileWriter() { override fun writeToFile(canonicalName: String, contents: String) { val f = File("$outputBase/${canonicalName.replaceAll("\\.", "/")}.java") log("Asked to write to ${canonicalName}. outputting to:${f.getAbsolutePath()}") @@ -66,158 +78,148 @@ class DataBinderPlugin : Plugin<Project> { } } - var xmlProcessor: LayoutXmlProcessor by Delegates.notNull() - var project: Project by Delegates.notNull() - - var generatedBinderSrc: File by Delegates.notNull() - - var generatedBinderOut: File by Delegates.notNull() - - var androidJar: File by Delegates.notNull() - - var variantData: ApplicationVariantData by Delegates.notNull() - - var codeGenTargetFolder: File by Delegates.notNull() - - var viewBinderSource: File by Delegates.notNull() - - var sdkDir: File by Delegates.notNull() - - val viewBinderSourceRoot by Delegates.lazy { - File(project.getBuildDir(), "databinder") - } - - - var fileWriter: GradleFileWriter by Delegates.notNull() - - val viewBinderCompileOutput by Delegates.lazy { File(viewBinderSourceRoot, "out") } - override fun apply(project: Project?) { if (project == null) return - val generateIntermediateFile = MethodClosure(this, "generateIntermediateFile") - val preprocessLayoutFiles = MethodClosure(this, "preprocessLayoutFiles") - this.project = project project.afterEvaluate { - // TODO read from app - val variants = arrayListOf("Debug") - xmlProcessor = createXmlProcessor(project) - log("after eval") - //processDebugResources - variants.forEach { variant -> - val processResTasks = it.getTasksByName("process${variant}Resources", true) - processResTasks.forEach { - Log.d { "${it} depends on ${it.getDependsOn()}" } - } - project.getTasks().create("processDataBinding${variant}Resources", - javaClass<DataBindingProcessLayoutsTask>(), - object : Action<DataBindingProcessLayoutsTask> { - override fun execute(task: DataBindingProcessLayoutsTask) { - task.xmlProcessor = xmlProcessor - task.sdkDir = sdkDir - processResTasks.forEach { - // until we add these as a new source folder, - // do it the old way - - // TODO uncomment this and comment below - // it.dependsOn(task) - it.doFirst(preprocessLayoutFiles) - it.doLast(generateIntermediateFile) - } - processResTasks.forEach { - it.getDependsOn().filterNot { it == task }.forEach { - Log.d { "adding dependency on ${it} for ${task}" } - task.dependsOn(it) - } - } - } - }); - } + createXmlProcessor(project) } } fun log(s: String) { - System.out.println("PLOG: $s") + System.out.println("[qwqw data binding]: $s") } - fun createXmlProcessor(p: Project): LayoutXmlProcessor { - val ss = p.getExtensions().getByName("android") as AppExtension - sdkDir = ss.getSdkDirectory() - val minSdkVersion = ss.getDefaultConfig().getMinSdkVersion() - androidJar = File(ss.getSdkDirectory().getAbsolutePath() - + "/platforms/${ss.getCompileSdkVersion()}/android.jar") - log("creating parser!") + fun createXmlProcessor(p: Project) { + val androidExt = p.getExtensions().getByName("android") + if (androidExt !is BaseExtension) { + return + } log("project build dir:${p.getBuildDir()}") + // TODO this will differ per flavor + + if (androidExt is AppExtension) { + createXmlProcessorForApp(p, androidExt) + } else if (androidExt is LibraryExtension) { + createXmlProcessorForLibrary(p, androidExt) + } else { + throw RuntimeException("cannot understand android extension. What is it? ${androidExt}") + } + } + + fun createXmlProcessorForLibrary(project : Project, lib : LibraryExtension) { + val sdkDir = lib.getSdkDirectory() + lib.getTestVariants().forEach { variant -> + log("test variant $variant. dir name ${variant.getDirName()}") + val variantData = getVariantData(variant) + attachXmlProcessor(project, variantData, sdkDir, false)//tests extend apk variant + } + lib.getLibraryVariants().forEach { variant -> + log("lib variant $variant . dir name ${variant.getDirName()}") + val variantData = getVariantData(variant) + attachXmlProcessor(project, variantData, sdkDir, true) + } + } + + fun getVariantData(appVariant : LibraryVariant) : LibraryVariantData { + val clazz = javaClass<LibraryVariantImpl>() + val field = clazz.getDeclaredField("variantData") + field.setAccessible(true) + return field.get(appVariant) as LibraryVariantData + } + + fun getVariantData(testVariant : TestVariant) : TestVariantData { + val clazz = javaClass<TestVariantImpl>() + val field = clazz.getDeclaredField("variantData") + field.setAccessible(true) + return field.get(testVariant) as TestVariantData + } + + fun getVariantData(appVariant : ApplicationVariant) : ApplicationVariantData { val clazz = javaClass<ApplicationVariantImpl>() val field = clazz.getDeclaredField("variantData") field.setAccessible(true) - var appVariant = ss.getApplicationVariants().first { it is ApplicationVariantImpl } - variantData = field.get(appVariant) as ApplicationVariantData + return field.get(appVariant) as ApplicationVariantData + } + fun createXmlProcessorForApp(project : Project, appExt: AppExtension) { + val sdkDir = appExt.getSdkDirectory() + appExt.getTestVariants().forEach { testVariant -> + val variantData = getVariantData(testVariant) + attachXmlProcessor(project, variantData, sdkDir, false) + } + appExt.getApplicationVariants().forEach { appVariant -> + val variantData = getVariantData(appVariant) + attachXmlProcessor(project, variantData, sdkDir, false) + } + } - val packageName = variantData.generateRClassTask.getPackageForR() + fun attachXmlProcessor(project : Project, variantData : BaseVariantData<*>, sdkDir : File, + isLibrary : Boolean) { + val configuration = variantData.getVariantConfiguration() + val minSdkVersion = configuration.getMinSdkVersion() + val generateRTask = variantData.generateRClassTask + val packageName = generateRTask.getPackageForR() + log("r task name $generateRTask . text symbols output dir: ${generateRTask.getTextSymbolOutputDir()}") + val fullName = configuration.getFullName() val sources = variantData.getJavaSources() sources.forEach({ - log("source: ${it}"); + if (it is FileCollection) { + it.forEach { + log("sources for ${variantData} ${it}}") + } + } else { + log("sources for ${variantData}: ${it}"); + } }) val resourceFolders = arrayListOf(variantData.mergeResourcesTask.getOutputDir()) log("MERGE RES OUTPUT ${variantData.mergeResourcesTask.getOutputDir()}") - //TODO - codeGenTargetFolder = variantData.generateRClassTask.getSourceOutputDir() - val resGenTargetFolder = variantData.generateRClassTask.getResDir() - variantData.addJavaSourceFoldersToModel(codeGenTargetFolder) - variantData.addJavaSourceFoldersToModel(viewBinderSourceRoot) - - val jCompileTask = variantData.javaCompileTask - val dexTask = variantData.dexTask - val options = jCompileTask.getOptions() - log("compile options: ${options.optionMap()}") - viewBinderSource = File(viewBinderSourceRoot.getAbsolutePath() + "/src") - viewBinderSource.mkdirs() - variantData.registerJavaGeneratingTask(project.task("dataBinderDummySourceGenTask", - MethodClosure(this, "dummySourceGenTask")), - File(viewBinderSourceRoot.getAbsolutePath() + "/src/")) - viewBinderCompileOutput.mkdirs() - log("view binder source will be ${viewBinderSource}") - log("adding out dir to input files ${viewBinderCompileOutput}") - var inputFiles = dexTask.getInputFiles() - var inputDir = dexTask.getInputDir() - log("current input files for dex are ${inputFiles} or dir ${inputDir}") - if (inputDir != null && inputFiles == null) { - inputFiles = arrayListOf(inputDir) - dexTask.setInputDir(null) - } - inputFiles.add(viewBinderCompileOutput) - dexTask.setInputFiles(inputFiles) + val codeGenTargetFolder = generateRTask.getSourceOutputDir() + // TODO unnecessary? - dexTask.doFirst(MethodClosure(this, "preDexAnalysis")) - val writerOutBase = codeGenTargetFolder.getAbsolutePath(); - fileWriter = GradleFileWriter(writerOutBase) - return LayoutXmlProcessor(packageName, resourceFolders, fileWriter, - minSdkVersion.getApiLevel()) - } - - - fun dummySourceGenTask(o: Any?) { - System.out.println("running dummySourceGenTask") - } - - fun preDexAnalysis(o: Any?) { - val jCompileTask = variantData.javaCompileTask - val dexTask = variantData.dexTask - log("dex task files: ${dexTask.getInputFiles()} ${dexTask.getInputFiles().javaClass}") - log("compile CP: ${jCompileTask.getClasspath().getAsPath()}") - val jarUrl = androidJar.toURI().toURL() - val androidClassLoader = URLClassLoader(array(jarUrl)) - val cpFiles = arrayListOf<File>() - cpFiles.addAll(dexTask.getInputFiles()) - cpFiles.addAll(jCompileTask.getClasspath().getFiles()) - } + // TODO attach to test module as well! - fun preprocessLayoutFiles(o: Any?) { - xmlProcessor.processResources() - } - - fun generateIntermediateFile(o: Any?) { - xmlProcessor.writeIntermediateFile(sdkDir) + variantData.addJavaSourceFoldersToModel(codeGenTargetFolder) + val writerOutBase = codeGenTargetFolder.getAbsolutePath(); + val fileWriter = GradleFileWriter(writerOutBase) + val xmlProcessor = LayoutXmlProcessor(packageName, resourceFolders, fileWriter, + minSdkVersion.getApiLevel(), isLibrary) + val processResTask = generateRTask + + val xmlOutDir = "${project.getBuildDir()}/layout-info/${configuration.getDirName()}"; + log("xml output for ${variantData} is ${xmlOutDir}") + val dataBindingTaskName = "dataBinding${processResTask.getName().capitalize()}" + log("created task $dataBindingTaskName") + project.getTasks().create(dataBindingTaskName, + javaClass<DataBindingProcessLayoutsTask>(), + object : Action<DataBindingProcessLayoutsTask> { + override fun execute(task: DataBindingProcessLayoutsTask) { + task.xmlProcessor = xmlProcessor + task.sdkDir = sdkDir + Log.d { "TASK adding dependency on ${task} for ${processResTask}" } + processResTask.dependsOn(task) + processResTask.getDependsOn().filterNot { it == task }.forEach { + Log.d { "adding dependency on ${it} for ${task}" } + task.dependsOn(it) + } + processResTask.doLast { + task.writeFiles(File(xmlOutDir)) + } + } + }); + + if (isLibrary) { + val packageJarTaskName = "package${fullName.capitalize()}Jar" + val packageTask = project.getTasks().findByName(packageJarTaskName) + if (packageTask !is org.gradle.api.tasks.bundling.Jar) { + throw RuntimeException("cannot find package task in $project $variantData project $packageJarTaskName") + } + val excludePattern = "com/android/databinding/layouts/*.*" + val appPkgAsClass = packageName.replace('.', '/') + packageTask.exclude(excludePattern) + packageTask.exclude("$appPkgAsClass/generated/*") + packageTask.exclude("$appPkgAsClass/BR.*") + packageTask.exclude(xmlProcessor.getInfoClassFullName().replace('.', '/') + ".class") + log("excludes ${packageTask.getExcludes()}") + } } } diff --git a/integration-tests/IndependentLibrary/app/.gitignore b/integration-tests/IndependentLibrary/app/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/integration-tests/IndependentLibrary/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/integration-tests/IndependentLibrary/app/build.gradle b/integration-tests/IndependentLibrary/app/build.gradle new file mode 100644 index 00000000..552e1a52 --- /dev/null +++ b/integration-tests/IndependentLibrary/app/build.gradle @@ -0,0 +1,60 @@ +/* + * 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: 'maven' +apply plugin: 'com.android.library' +apply plugin: 'com.android.databinding' + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.2" + + 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' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile "com.android.databinding:library:${config.snapshotVersion}" + provided "com.android.databinding:annotationprocessor:${config.snapshotVersion}" +} + +uploadArchives { + repositories { + mavenDeployer { + repository(url: "file://${config.mavenRepoDir}") + pom.artifactId = 'independent-library' + pom.version = config.snapshotVersion + pom.groupId = config.testGroup + } + } +} + +connectedCheck.dependsOn uploadArchives
\ No newline at end of file diff --git a/integration-tests/IndependentLibrary/app/proguard-rules.pro b/integration-tests/IndependentLibrary/app/proguard-rules.pro new file mode 100644 index 00000000..b7210d1d --- /dev/null +++ b/integration-tests/IndependentLibrary/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/yboyar/android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/integration-tests/IndependentLibrary/app/src/androidTest/java/com/android/databinding/test/independentlibrary/ApplicationTest.java b/integration-tests/IndependentLibrary/app/src/androidTest/java/com/android/databinding/test/independentlibrary/ApplicationTest.java new file mode 100644 index 00000000..0b267a3a --- /dev/null +++ b/integration-tests/IndependentLibrary/app/src/androidTest/java/com/android/databinding/test/independentlibrary/ApplicationTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.test.independentlibrary; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a> + */ +public class ApplicationTest extends ApplicationTestCase<Application> { + + public ApplicationTest() { + super(Application.class); + } +}
\ No newline at end of file diff --git a/integration-tests/IndependentLibrary/app/src/androidTest/java/com/android/databinding/test/independentlibrary/LibraryActivityTest.java b/integration-tests/IndependentLibrary/app/src/androidTest/java/com/android/databinding/test/independentlibrary/LibraryActivityTest.java new file mode 100644 index 00000000..939d1bae --- /dev/null +++ b/integration-tests/IndependentLibrary/app/src/androidTest/java/com/android/databinding/test/independentlibrary/LibraryActivityTest.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.test.independentlibrary; + +import android.test.ActivityInstrumentationTestCase2; +import android.view.View; +import android.widget.TextView; + +public class LibraryActivityTest extends ActivityInstrumentationTestCase2<LibraryActivity> { + public LibraryActivityTest() { + super(LibraryActivity.class); + } + + public void testTextViewContents() throws Throwable { + final LibraryActivity activity = getActivity(); + assertNotNull("test sanity", activity); + runTestOnUiThread(new Runnable() { + @Override + public void run() { + TextView textView = (TextView) activity.findViewById(R.id.fooTextView); + final String expected = LibraryActivity.FIELD_VALUE + " " + + LibraryActivity.FIELD_VALUE; + assertEquals(expected, textView.getText().toString()); + } + }); + } +} diff --git a/integration-tests/IndependentLibrary/app/src/main/AndroidManifest.xml b/integration-tests/IndependentLibrary/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..ff2388c2 --- /dev/null +++ b/integration-tests/IndependentLibrary/app/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ +<!-- + ~ 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="com.android.databinding.test.independentlibrary"> + + <application android:allowBackup="true" + android:label="@string/app_name"> + <activity android:name=".LibraryActivity"/> + </application> + +</manifest> diff --git a/integration-tests/IndependentLibrary/app/src/main/java/com/android/databinding/test/independentlibrary/LibraryActivity.java b/integration-tests/IndependentLibrary/app/src/main/java/com/android/databinding/test/independentlibrary/LibraryActivity.java new file mode 100644 index 00000000..2d2e0240 --- /dev/null +++ b/integration-tests/IndependentLibrary/app/src/main/java/com/android/databinding/test/independentlibrary/LibraryActivity.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.test.independentlibrary; + +import android.app.Activity; +import android.os.Bundle; + +import com.android.databinding.test.independentlibrary.vo.MyBindableObject; +import com.android.databinding.test.independentlibrary.generated.LibraryLayoutBinding; +public class LibraryActivity extends Activity { + public static final String FIELD_VALUE = "BAR"; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LibraryLayoutBinding binding = LibraryLayoutBinding.inflate(this); + setContentView(binding.getRoot()); + MyBindableObject object = new MyBindableObject(); + object.setField(FIELD_VALUE); + binding.setFoo(object); + binding.executePendingBindings(); + } +} diff --git a/integration-tests/IndependentLibrary/app/src/main/java/com/android/databinding/test/independentlibrary/LibraryAdapter.java b/integration-tests/IndependentLibrary/app/src/main/java/com/android/databinding/test/independentlibrary/LibraryAdapter.java new file mode 100644 index 00000000..e7a2ea65 --- /dev/null +++ b/integration-tests/IndependentLibrary/app/src/main/java/com/android/databinding/test/independentlibrary/LibraryAdapter.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.test.independentlibrary; + +import android.binding.BindingAdapter; +import android.view.View; + +public class LibraryAdapter { + @BindingAdapter("myTagAttr") + public static void set(View view, String someTag) { + view.setTag(someTag); + } +} diff --git a/integration-tests/IndependentLibrary/app/src/main/java/com/android/databinding/test/independentlibrary/vo/MyBindableObject.java b/integration-tests/IndependentLibrary/app/src/main/java/com/android/databinding/test/independentlibrary/vo/MyBindableObject.java new file mode 100644 index 00000000..c4c5cc8b --- /dev/null +++ b/integration-tests/IndependentLibrary/app/src/main/java/com/android/databinding/test/independentlibrary/vo/MyBindableObject.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.test.independentlibrary.vo; + +import com.android.databinding.library.BaseObservable; +import com.android.databinding.test.independentlibrary.BR; + +import android.binding.Bindable; + +public class MyBindableObject extends BaseObservable { + @Bindable + private String mField; + + public String getField() { + return mField; + } + + public void setField(String field) { + mField = field; + notifyPropertyChanged(BR.field); + } +} diff --git a/integration-tests/IndependentLibrary/app/src/main/res/layout/library_layout.xml b/integration-tests/IndependentLibrary/app/src/main/res/layout/library_layout.xml new file mode 100644 index 00000000..a7ba2857 --- /dev/null +++ b/integration-tests/IndependentLibrary/app/src/main/res/layout/library_layout.xml @@ -0,0 +1,25 @@ +<?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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <variable name="foo" type="com.android.databinding.test.independentlibrary.vo.MyBindableObject"/> + <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" + android:id="@+id/fooTextView" + android:text='@{foo.field + " " + foo.field}'/> +</LinearLayout>
\ No newline at end of file diff --git a/integration-tests/IndependentLibrary/app/src/main/res/values/strings.xml b/integration-tests/IndependentLibrary/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..8e6caf7b --- /dev/null +++ b/integration-tests/IndependentLibrary/app/src/main/res/values/strings.xml @@ -0,0 +1,18 @@ +<!-- + ~ 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. + --> + +<resources> + <string name="app_name">IndependentLibrary</string> +</resources> diff --git a/integration-tests/IndependentLibrary/build.gradle b/integration-tests/IndependentLibrary/build.gradle new file mode 100644 index 00000000..d74b7e69 --- /dev/null +++ b/integration-tests/IndependentLibrary/build.gradle @@ -0,0 +1,44 @@ +/* + * 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. + */ + +buildscript { + def Properties dataBindingProperties = new Properties() + dataBindingProperties.load(new FileInputStream("${projectDir}/../../databinding.properties")) + dataBindingProperties.mavenRepoDir = "${projectDir}/../../${dataBindingProperties.mavenRepoName}" + ext.config = dataBindingProperties + println "loaded config" + + repositories { + jcenter() + maven { + url config.mavenRepoDir + } + } + dependencies { + classpath 'com.android.tools.build:gradle:1.1.3' + classpath "com.android.databinding:dataBinder:${config.snapshotVersion}" + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + maven { + url config.mavenRepoDir + } + } +} diff --git a/integration-tests/IndependentLibrary/gradle.properties b/integration-tests/IndependentLibrary/gradle.properties new file mode 100644 index 00000000..efd23622 --- /dev/null +++ b/integration-tests/IndependentLibrary/gradle.properties @@ -0,0 +1,33 @@ +# +# 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. +# + +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true
\ No newline at end of file diff --git a/integration-tests/IndependentLibrary/gradle/wrapper/gradle-wrapper.jar b/integration-tests/IndependentLibrary/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 00000000..8c0fb64a --- /dev/null +++ b/integration-tests/IndependentLibrary/gradle/wrapper/gradle-wrapper.jar diff --git a/integration-tests/IndependentLibrary/gradle/wrapper/gradle-wrapper.properties b/integration-tests/IndependentLibrary/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..de86a571 --- /dev/null +++ b/integration-tests/IndependentLibrary/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,21 @@ +# +# 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. +# + +#Wed Apr 10 15:27:10 PDT 2013 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/integration-tests/IndependentLibrary/gradlew b/integration-tests/IndependentLibrary/gradlew new file mode 100755 index 00000000..91a7e269 --- /dev/null +++ b/integration-tests/IndependentLibrary/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/integration-tests/IndependentLibrary/gradlew.bat b/integration-tests/IndependentLibrary/gradlew.bat new file mode 100644 index 00000000..aec99730 --- /dev/null +++ b/integration-tests/IndependentLibrary/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/integration-tests/IndependentLibrary/settings.gradle b/integration-tests/IndependentLibrary/settings.gradle new file mode 100644 index 00000000..e2afad2a --- /dev/null +++ b/integration-tests/IndependentLibrary/settings.gradle @@ -0,0 +1,16 @@ +/* + * 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. + */ + +include ':app' diff --git a/integration-tests/MultiModuleTestApp/app/.gitignore b/integration-tests/MultiModuleTestApp/app/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/integration-tests/MultiModuleTestApp/app/build.gradle b/integration-tests/MultiModuleTestApp/app/build.gradle new file mode 100644 index 00000000..8079ff5d --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/build.gradle @@ -0,0 +1,52 @@ +/* + * 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.application' +apply plugin: 'com.android.databinding' + +android { + compileSdkVersion 21 + buildToolsVersion "22" + + defaultConfig { + applicationId "com.android.databinding.multimoduletestapp" + 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' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' + } +} + +println "combined ${config.testGroup}.independent-library:${config.snapshotVersion}" +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile project(':testlibrary') + compile "com.android.support:support-v4:+" + provided "com.android.databinding:annotationprocessor:${config.snapshotVersion}" + compile "${config.testGroup}:independent-library:${config.snapshotVersion}" +} diff --git a/integration-tests/MultiModuleTestApp/app/proguard-rules.pro b/integration-tests/MultiModuleTestApp/app/proguard-rules.pro new file mode 100644 index 00000000..b7210d1d --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/yboyar/android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/ApplicationTest.java b/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/ApplicationTest.java new file mode 100644 index 00000000..f1797487 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/ApplicationTest.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.multimoduletestapp; + +import com.android.databinding.testlibrary.ObservableInLibrary; + +import android.app.Application; +import android.binding.Observable; +import android.binding.OnPropertyChangedListener; +import android.test.ApplicationTestCase; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.HashMap; +import java.util.Map; + +/** + * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a> + */ +public class ApplicationTest extends ApplicationTestCase<Application> { + public ApplicationTest() { + super(Application.class); + } +}
\ No newline at end of file diff --git a/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/EventIdsTest.java b/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/EventIdsTest.java new file mode 100644 index 00000000..32dbffe8 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/androidTest/java/com/android/databinding/multimoduletestapp/EventIdsTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.multimoduletestapp; + +import com.android.databinding.testlibrary.ObservableInLibrary; + +import android.binding.Observable; +import android.binding.OnPropertyChangedListener; +import android.os.Debug; +import android.test.AndroidTestCase; + +import java.util.HashMap; +import java.util.Map; + +import com.android.databinding.multimoduletestapp.BR; + +public class EventIdsTest extends AndroidTestCase { + public void testLibraryObservable() { + ObservableInLibrary observableInLibrary = new ObservableInLibrary(); + EventCounter ec = new EventCounter(); + observableInLibrary.addOnPropertyChangedListener(ec); + ec.assertProperty(BR.libField1, 0); + ec.assertProperty(BR.libField2, 0); + ec.assertProperty(BR.sharedField, 0); + + observableInLibrary.setLibField1("a"); + ec.assertProperty(BR.libField1, 1); + ec.assertProperty(BR.libField2, 0); + ec.assertProperty(BR.sharedField, 0); + + observableInLibrary.setLibField2("b"); + ec.assertProperty(BR.libField1, 1); + ec.assertProperty(BR.libField2, 1); + ec.assertProperty(BR.sharedField, 0); + + observableInLibrary.setSharedField(3); + ec.assertProperty(BR.libField1, 1); + ec.assertProperty(BR.libField2, 1); + ec.assertProperty(BR.sharedField, 1); + } + + public void testAppObservable() { + ObservableInMainApp observableInMainApp = new ObservableInMainApp(); + EventCounter ec = new EventCounter(); + observableInMainApp.addOnPropertyChangedListener(ec); + ec.assertProperty(BR.appField1, 0); + ec.assertProperty(BR.appField2, 0); + ec.assertProperty(BR.sharedField, 0); + + observableInMainApp.setAppField2(3); + ec.assertProperty(BR.appField1, 0); + ec.assertProperty(BR.appField2, 1); + ec.assertProperty(BR.sharedField, 0); + + observableInMainApp.setAppField1("b"); + ec.assertProperty(BR.appField1, 1); + ec.assertProperty(BR.appField2, 1); + ec.assertProperty(BR.sharedField, 0); + + observableInMainApp.setSharedField(5); + ec.assertProperty(BR.appField1, 1); + ec.assertProperty(BR.appField2, 1); + ec.assertProperty(BR.sharedField, 1); + } + + public void testExtendingObservable() { + ObservableExtendingLib observable = new ObservableExtendingLib(); + EventCounter ec = new EventCounter(); + observable.addOnPropertyChangedListener(ec); + + ec.assertProperty(BR.childClassField, 0); + ec.assertProperty(BR.libField1, 0); + ec.assertProperty(BR.libField2, 0); + ec.assertProperty(BR.sharedField, 0); + + observable.setChildClassField("a"); + ec.assertProperty(BR.childClassField, 1); + ec.assertProperty(BR.libField1, 0); + ec.assertProperty(BR.libField2, 0); + ec.assertProperty(BR.sharedField, 0); + + observable.setLibField1("b"); + ec.assertProperty(BR.childClassField, 1); + ec.assertProperty(BR.libField1, 1); + ec.assertProperty(BR.libField2, 0); + ec.assertProperty(BR.sharedField, 0); + + observable.setLibField2("c"); + ec.assertProperty(BR.childClassField, 1); + ec.assertProperty(BR.libField1, 1); + ec.assertProperty(BR.libField2, 1); + ec.assertProperty(BR.sharedField, 0); + + observable.setSharedField(2); + ec.assertProperty(BR.childClassField, 1); + ec.assertProperty(BR.libField1, 1); + ec.assertProperty(BR.libField2, 1); + ec.assertProperty(BR.sharedField, 1); + } + + private static class EventCounter implements OnPropertyChangedListener { + Map<Integer, Integer> mCounter = new HashMap<>(); + + @Override + public void onPropertyChanged(Observable observable, int propertyId) { + mCounter.put(propertyId, get(propertyId) + 1); + } + + public int get(int propertyId) { + Integer val = mCounter.get(propertyId); + return val == null ? 0 : val; + } + + private void assertProperty(int propertyId, int value) { + assertEquals(get(propertyId), value); + } + } +} diff --git a/integration-tests/MultiModuleTestApp/app/src/main/AndroidManifest.xml b/integration-tests/MultiModuleTestApp/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..aaa07198 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.databinding.multimoduletestapp" > + + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name=".MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/integration-tests/MultiModuleTestApp/app/src/main/java/com/android/databinding/multimoduletestapp/MainActivity.java b/integration-tests/MultiModuleTestApp/app/src/main/java/com/android/databinding/multimoduletestapp/MainActivity.java new file mode 100644 index 00000000..f8a012a0 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/java/com/android/databinding/multimoduletestapp/MainActivity.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.multimoduletestapp; + +import com.android.databinding.multimoduletestapp.generated.ActivityMainBinding; +import android.app.Activity; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.ViewGroup; + +public class MainActivity extends Activity { + ActivityMainBinding mBinder; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mBinder = ActivityMainBinding.inflate(this); + setContentView(mBinder.getRoot()); + } + + public ActivityMainBinding getBinder() { + return mBinder; + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.action_settings) { + return true; + } + + return super.onOptionsItemSelected(item); + } +} diff --git a/integration-tests/MultiModuleTestApp/app/src/main/java/com/android/databinding/multimoduletestapp/ObservableExtendingLib.java b/integration-tests/MultiModuleTestApp/app/src/main/java/com/android/databinding/multimoduletestapp/ObservableExtendingLib.java new file mode 100644 index 00000000..b558790d --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/java/com/android/databinding/multimoduletestapp/ObservableExtendingLib.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.multimoduletestapp; + +import com.android.databinding.testlibrary.ObservableInLibrary; + +import android.binding.Bindable; +import com.android.databinding.multimoduletestapp.BR; + +public class ObservableExtendingLib extends ObservableInLibrary { + @Bindable + private String mChildClassField; + + public String getChildClassField() { + return mChildClassField; + } + + public void setChildClassField(String childClassField) { + mChildClassField = childClassField; + notifyPropertyChanged(BR.childClassField); + } +} diff --git a/integration-tests/MultiModuleTestApp/app/src/main/java/com/android/databinding/multimoduletestapp/ObservableInMainApp.java b/integration-tests/MultiModuleTestApp/app/src/main/java/com/android/databinding/multimoduletestapp/ObservableInMainApp.java new file mode 100644 index 00000000..c870fd44 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/java/com/android/databinding/multimoduletestapp/ObservableInMainApp.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.multimoduletestapp; + +import android.binding.Bindable; + +import com.android.databinding.library.BaseObservable; +import com.android.databinding.multimoduletestapp.BR; + +public class ObservableInMainApp extends BaseObservable { + @Bindable + private String mAppField1; + @Bindable + private int mAppField2; + @Bindable + private int mSharedField; + + public String getAppField1() { + return mAppField1; + } + + public void setAppField1(String appField1) { + mAppField1 = appField1; + notifyPropertyChanged(BR.appField1); + } + + public int getAppField2() { + return mAppField2; + } + + public void setAppField2(int appField2) { + mAppField2 = appField2; + notifyPropertyChanged(BR.appField2); + } + + public int getSharedField() { + return mSharedField; + } + + public void setSharedField(int sharedField) { + mSharedField = sharedField; + notifyPropertyChanged(BR.sharedField); + } +} diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-hdpi/ic_launcher.png b/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..96a442e5 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-mdpi/ic_launcher.png b/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..359047df --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-xhdpi/ic_launcher.png b/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..71c6d760 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-xxhdpi/ic_launcher.png b/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..4df18946 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/layout/activity_main.xml b/integration-tests/MultiModuleTestApp/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..4549e817 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,27 @@ +<!-- + ~ 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. + --> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" + android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingTop="@dimen/activity_vertical_margin" + android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> + <variable name="foo" type="String"/> + <TextView android:text='@{foo + " " + foo}' android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + +</RelativeLayout> diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/layout/activity_test_library_main.xml b/integration-tests/MultiModuleTestApp/app/src/main/res/layout/activity_test_library_main.xml new file mode 100644 index 00000000..5a340493 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/layout/activity_test_library_main.xml @@ -0,0 +1,27 @@ +<!-- + ~ 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. + --> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" + android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingTop="@dimen/activity_vertical_margin" + android:paddingBottom="@dimen/activity_vertical_margin" + > + <TextView android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + +</RelativeLayout> diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/menu/menu_main.xml b/integration-tests/MultiModuleTestApp/app/src/main/res/menu/menu_main.xml new file mode 100644 index 00000000..4674d4d1 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/menu/menu_main.xml @@ -0,0 +1,21 @@ +<!-- + ~ 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. + --> + +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity"> + <item android:id="@+id/action_settings" android:title="@string/action_settings" + android:orderInCategory="100" android:showAsAction="never" /> +</menu> diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/values-v21/styles.xml b/integration-tests/MultiModuleTestApp/app/src/main/res/values-v21/styles.xml new file mode 100644 index 00000000..9b24d4f7 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/values-v21/styles.xml @@ -0,0 +1,21 @@ +<?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. + --> + +<resources> + <style name="AppTheme" parent="android:Theme.Material.Light"> + </style> +</resources> diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/values-w820dp/dimens.xml b/integration-tests/MultiModuleTestApp/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 00000000..4719591c --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,22 @@ +<!-- + ~ 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. + --> + +<resources> + <!-- Example customization of dimensions originally defined in res/values/dimens.xml + (such as screen margins) for screens with more than 820dp of available width. This + would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> + <dimen name="activity_horizontal_margin">64dp</dimen> +</resources> diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/values/dimens.xml b/integration-tests/MultiModuleTestApp/app/src/main/res/values/dimens.xml new file mode 100644 index 00000000..c06ae3f9 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/values/dimens.xml @@ -0,0 +1,21 @@ +<!-- + ~ 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. + --> + +<resources> + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="activity_horizontal_margin">16dp</dimen> + <dimen name="activity_vertical_margin">16dp</dimen> +</resources> diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/values/strings.xml b/integration-tests/MultiModuleTestApp/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..20d68aa2 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/values/strings.xml @@ -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. + --> + +<resources> + + <string name="app_name">Multi Module Test App</string> + <string name="hello_world">Hello world!</string> + <string name="action_settings">Settings</string> + +</resources> diff --git a/integration-tests/MultiModuleTestApp/app/src/main/res/values/styles.xml b/integration-tests/MultiModuleTestApp/app/src/main/res/values/styles.xml new file mode 100644 index 00000000..7dc23c83 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/app/src/main/res/values/styles.xml @@ -0,0 +1,24 @@ +<!-- + ~ 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. + --> + +<resources> + + <!-- Base application theme. --> + <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar"> + <!-- Customize your theme here. --> + </style> + +</resources> diff --git a/integration-tests/MultiModuleTestApp/build.gradle b/integration-tests/MultiModuleTestApp/build.gradle new file mode 100644 index 00000000..b9340e59 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/build.gradle @@ -0,0 +1,44 @@ +/* + * 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. + */ +buildscript { + def Properties dataBindingProperties = new Properties() + dataBindingProperties.load(new FileInputStream("${projectDir}/../../databinding.properties")) + dataBindingProperties.mavenRepoDir = "${projectDir}/../../${dataBindingProperties.mavenRepoName}" + ext.config = dataBindingProperties + println "loaded config" + + repositories { + jcenter() + maven { + url config.mavenRepoDir + } + } + dependencies { + classpath 'com.android.tools.build:gradle:1.1.3' + classpath "com.android.databinding:dataBinder:${config.snapshotVersion}" + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + jcenter() + maven { + url config.mavenRepoDir + } + } +} diff --git a/integration-tests/MultiModuleTestApp/gradle.properties b/integration-tests/MultiModuleTestApp/gradle.properties new file mode 100644 index 00000000..5b24ba3e --- /dev/null +++ b/integration-tests/MultiModuleTestApp/gradle.properties @@ -0,0 +1,34 @@ +# +# 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. +# + +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx10248m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true
\ No newline at end of file diff --git a/integration-tests/MultiModuleTestApp/gradle/wrapper/gradle-wrapper.jar b/integration-tests/MultiModuleTestApp/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 00000000..8c0fb64a --- /dev/null +++ b/integration-tests/MultiModuleTestApp/gradle/wrapper/gradle-wrapper.jar diff --git a/integration-tests/MultiModuleTestApp/gradle/wrapper/gradle-wrapper.properties b/integration-tests/MultiModuleTestApp/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..992e276a --- /dev/null +++ b/integration-tests/MultiModuleTestApp/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,22 @@ +# +# 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. +# + +#Wed Apr 10 15:27:10 PDT 2013 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/integration-tests/MultiModuleTestApp/gradlew b/integration-tests/MultiModuleTestApp/gradlew new file mode 100755 index 00000000..91a7e269 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/integration-tests/MultiModuleTestApp/gradlew.bat b/integration-tests/MultiModuleTestApp/gradlew.bat new file mode 100644 index 00000000..aec99730 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/integration-tests/MultiModuleTestApp/settings.gradle b/integration-tests/MultiModuleTestApp/settings.gradle new file mode 100644 index 00000000..c79cb3da --- /dev/null +++ b/integration-tests/MultiModuleTestApp/settings.gradle @@ -0,0 +1,17 @@ +/* + * 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. + */ + +include ':app', ':testlibrary' diff --git a/integration-tests/MultiModuleTestApp/testlibrary/.gitignore b/integration-tests/MultiModuleTestApp/testlibrary/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/.gitignore @@ -0,0 +1 @@ +/build diff --git a/integration-tests/MultiModuleTestApp/testlibrary/build.gradle b/integration-tests/MultiModuleTestApp/testlibrary/build.gradle new file mode 100644 index 00000000..4b2c87c6 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/build.gradle @@ -0,0 +1,48 @@ +/* + * 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' +apply plugin: 'com.android.databinding' + +android { + compileSdkVersion 21 + buildToolsVersion "21.1.2" + + 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' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile "com.android.databinding:library:${config.snapshotVersion}" + provided "com.android.databinding:annotationprocessor:${config.snapshotVersion}" +} diff --git a/integration-tests/MultiModuleTestApp/testlibrary/proguard-rules.pro b/integration-tests/MultiModuleTestApp/testlibrary/proguard-rules.pro new file mode 100644 index 00000000..b7210d1d --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/yboyar/android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/androidTest/java/com/android/databinding/testlibrary/ApplicationTest.java b/integration-tests/MultiModuleTestApp/testlibrary/src/androidTest/java/com/android/databinding/testlibrary/ApplicationTest.java new file mode 100644 index 00000000..9efa645c --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/androidTest/java/com/android/databinding/testlibrary/ApplicationTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.testlibrary; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a> + */ +public class ApplicationTest extends ApplicationTestCase<Application> { + public ApplicationTest() { + super(Application.class); + } +}
\ No newline at end of file diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/AndroidManifest.xml b/integration-tests/MultiModuleTestApp/testlibrary/src/main/AndroidManifest.xml new file mode 100644 index 00000000..263d6632 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/AndroidManifest.xml @@ -0,0 +1,36 @@ +<?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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.databinding.testlibrary" > + + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" > + <activity + android:name=".TestLibraryMainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/java/com/android/databinding/testlibrary/ObservableInLibrary.java b/integration-tests/MultiModuleTestApp/testlibrary/src/main/java/com/android/databinding/testlibrary/ObservableInLibrary.java new file mode 100644 index 00000000..f5470f10 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/java/com/android/databinding/testlibrary/ObservableInLibrary.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.testlibrary; + +import android.binding.Bindable; + +import com.android.databinding.library.BaseObservable; +import com.android.databinding.testlibrary.BR; + +public class ObservableInLibrary extends BaseObservable { + + @Bindable + private String mLibField1; + + @Bindable + private String mLibField2; + + @Bindable + private int mSharedField; + + public String getLibField1() { + return mLibField1; + } + + public void setLibField1(String libField1) { + mLibField1 = libField1; + notifyPropertyChanged(BR.libField1); + } + + public String getLibField2() { + return mLibField2; + } + + public void setLibField2(String libField2) { + mLibField2 = libField2; + notifyPropertyChanged(BR.libField2); + } + + public int getSharedField() { + return mSharedField; + } + + public void setSharedField(int sharedField) { + mSharedField = sharedField; + notifyPropertyChanged(BR.sharedField); + } +} diff --git a/baseLibrary/src/main/java/android/binding/BinderBundle.java b/integration-tests/MultiModuleTestApp/testlibrary/src/main/java/com/android/databinding/testlibrary/TestLibObject.java index 1a59bd5a..330b870a 100644 --- a/baseLibrary/src/main/java/android/binding/BinderBundle.java +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/java/com/android/databinding/testlibrary/TestLibObject.java @@ -13,15 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package android.binding; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +package com.android.databinding.testlibrary; -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.SOURCE) -public @interface BinderBundle { - String value(); +import android.binding.Bindable; + +public class TestLibObject { + @Bindable + private String mField; + + public String getField() { + return mField; + } + + public void setField(String field) { + this.mField = field; + } } diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/java/com/android/databinding/testlibrary/TestLibraryMainActivity.java b/integration-tests/MultiModuleTestApp/testlibrary/src/main/java/com/android/databinding/testlibrary/TestLibraryMainActivity.java new file mode 100644 index 00000000..812b222b --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/java/com/android/databinding/testlibrary/TestLibraryMainActivity.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.databinding.testlibrary; + +import android.app.Activity; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import com.android.databinding.testlibrary.R; +import com.android.databinding.testlibrary.generated.ActivityTestLibraryMainBinding; +public class TestLibraryMainActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + ActivityTestLibraryMainBinding binder = ActivityTestLibraryMainBinding.inflate(this); + setContentView(binder.getRoot()); + + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_test_library_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.action_settings) { + return true; + } + + return super.onOptionsItemSelected(item); + } +} diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-hdpi/ic_launcher.png b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..96a442e5 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-mdpi/ic_launcher.png b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..359047df --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-xhdpi/ic_launcher.png b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..71c6d760 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-xxhdpi/ic_launcher.png b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..4df18946 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/layout/activity_test_library_main.xml b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/layout/activity_test_library_main.xml new file mode 100644 index 00000000..b731cc03 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/layout/activity_test_library_main.xml @@ -0,0 +1,29 @@ +<!-- + ~ 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. + --> + +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" + android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" + android:paddingRight="@dimen/activity_horizontal_margin" + android:paddingTop="@dimen/activity_vertical_margin" + android:paddingBottom="@dimen/activity_vertical_margin" + tools:context=".TestLibraryMainActivity"> + <variable name="obj1" type="com.android.databinding.testlibrary.TestLibObject"/> + + <TextView android:text="@{obj1.field}" android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + +</RelativeLayout> diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/menu/menu_test_library_main.xml b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/menu/menu_test_library_main.xml new file mode 100644 index 00000000..68d936d4 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/menu/menu_test_library_main.xml @@ -0,0 +1,21 @@ +<!-- + ~ 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. + --> + +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" tools:context=".TestLibraryMainActivity"> + <item android:id="@+id/action_settings" android:title="@string/action_settings" + android:orderInCategory="100" android:showAsAction="never" /> +</menu> diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/values-w820dp/dimens.xml b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 00000000..4719591c --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,22 @@ +<!-- + ~ 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. + --> + +<resources> + <!-- Example customization of dimensions originally defined in res/values/dimens.xml + (such as screen margins) for screens with more than 820dp of available width. This + would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> + <dimen name="activity_horizontal_margin">64dp</dimen> +</resources> diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/values/dimens.xml b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/values/dimens.xml new file mode 100644 index 00000000..c06ae3f9 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/values/dimens.xml @@ -0,0 +1,21 @@ +<!-- + ~ 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. + --> + +<resources> + <!-- Default screen margins, per the Android Design guidelines. --> + <dimen name="activity_horizontal_margin">16dp</dimen> + <dimen name="activity_vertical_margin">16dp</dimen> +</resources> diff --git a/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/values/strings.xml b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/values/strings.xml new file mode 100644 index 00000000..d930ddb6 --- /dev/null +++ b/integration-tests/MultiModuleTestApp/testlibrary/src/main/res/values/strings.xml @@ -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. + --> + +<resources> + + <string name="app_name">Test Library</string> + <string name="hello_world">Hello world!</string> + <string name="action_settings">Settings</string> + +</resources> diff --git a/integration-tests/TestApp/app/build.gradle b/integration-tests/TestApp/app/build.gradle index 2fe5cf44..11f17571 100644 --- a/integration-tests/TestApp/app/build.gradle +++ b/integration-tests/TestApp/app/build.gradle @@ -27,6 +27,7 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile "com.android.databinding:library:${config.snapshotVersion}" + compile "com.android.databinding:adapters:${config.snapshotVersion}" compile "com.android.support:support-v4:+" provided "com.android.databinding:annotationprocessor:${config.snapshotVersion}" } diff --git a/integration-tests/TestApp/app/src/androidTest/java/com/android/databinding/testapp/ProcessBindableTest.java b/integration-tests/TestApp/app/src/androidTest/java/com/android/databinding/testapp/ProcessBindableTest.java index a092d0de..0b579276 100644 --- a/integration-tests/TestApp/app/src/androidTest/java/com/android/databinding/testapp/ProcessBindableTest.java +++ b/integration-tests/TestApp/app/src/androidTest/java/com/android/databinding/testapp/ProcessBindableTest.java @@ -22,7 +22,7 @@ import android.util.ArrayMap; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.HashSet; - +import com.android.databinding.testapp.BR; public class ProcessBindableTest extends BaseDataBinderTest<BasicBindingBinding> { private static String[] EXPECTED_BINDING_NAMES = { "bindableField1", @@ -40,7 +40,7 @@ public class ProcessBindableTest extends BaseDataBinderTest<BasicBindingBinding> } public void testFieldsGenerated() throws IllegalAccessException { - Field[] fields = android.binding.BR.class.getFields(); + Field[] fields = BR.class.getFields(); ArrayMap<String, Integer> fieldValues = new ArrayMap<>(); int modifiers = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL; diff --git a/integration-tests/TestApp/app/src/main/java/com/android/databinding/testapp/vo/PublicFinalWithObservableTestVo.java b/integration-tests/TestApp/app/src/main/java/com/android/databinding/testapp/vo/PublicFinalWithObservableTestVo.java index dd415ded..2c9695b8 100644 --- a/integration-tests/TestApp/app/src/main/java/com/android/databinding/testapp/vo/PublicFinalWithObservableTestVo.java +++ b/integration-tests/TestApp/app/src/main/java/com/android/databinding/testapp/vo/PublicFinalWithObservableTestVo.java @@ -17,6 +17,7 @@ import com.android.databinding.library.BaseObservable; import com.android.databinding.testapp.R; import android.binding.Bindable; +import com.android.databinding.testapp.BR; public class PublicFinalWithObservableTestVo { public final int myField; @@ -36,7 +37,7 @@ public class PublicFinalWithObservableTestVo { public void setVal(int val) { this.val = val; - notifyPropertyChanged(android.binding.BR.val); + notifyPropertyChanged(BR.val); } } } diff --git a/integration-tests/TestApp/app/src/main/java/com/android/databinding/testapp/vo/TextViewBindingObject.java b/integration-tests/TestApp/app/src/main/java/com/android/databinding/testapp/vo/TextViewBindingObject.java index b98ded26..482be18d 100644 --- a/integration-tests/TestApp/app/src/main/java/com/android/databinding/testapp/vo/TextViewBindingObject.java +++ b/integration-tests/TestApp/app/src/main/java/com/android/databinding/testapp/vo/TextViewBindingObject.java @@ -25,6 +25,7 @@ import android.text.util.Linkify; import android.view.KeyEvent; import android.view.View; import android.widget.TextView; +import com.android.databinding.testapp.BR; public class TextViewBindingObject extends BindingAdapterBindingObject { @@ -236,7 +237,7 @@ public class TextViewBindingObject extends BindingAdapterBindingObject { public void setCapitalize(TextKeyListener.Capitalize capitalize) { mCapitalize = capitalize; - notifyPropertyChanged(android.binding.BR.capitalize); + notifyPropertyChanged(BR.capitalize); } public boolean isPhoneNumber() { diff --git a/integration-tests/TestApp/app/src/main/res/layout-land/multi_res_layout.xml b/integration-tests/TestApp/app/src/main/res/layout-land/multi_res_layout.xml index caf0389e..5906fd16 100644 --- a/integration-tests/TestApp/app/src/main/res/layout-land/multi_res_layout.xml +++ b/integration-tests/TestApp/app/src/main/res/layout-land/multi_res_layout.xml @@ -30,8 +30,7 @@ <include layout="@layout/included_layout" android:id="@+id/includedLayoutConflict" bind:innerObject="@{objectInLand}" - bind:innerValue="@{`modified ` + objectInLand.intValue}" - /> + bind:innerValue='@{"modified " + objectInLand.intValue}' /> <include layout="@layout/basic_binding" android:id="@+id/includedLayoutShared" bind:a="@{objectInDefault.stringValue}" /> diff --git a/library/build.gradle b/library/build.gradle index c91e1172..bb078f7a 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -59,9 +59,6 @@ dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile project(":baseLibrary") compile 'com.android.support:support-v4:+' - provided project(":annotationprocessor") - provided 'com.android.support:cardview-v7:+' - provided 'com.android.support:appcompat-v7:+' } configurations { diff --git a/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java b/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java index 6785b5fd..aa7661ac 100644 --- a/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java +++ b/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/MainActivity.java @@ -13,8 +13,6 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.binding.BR; - import com.android.databinding.library.DataBindingUtil; import com.android.databinding.library.PropertyChangeRegistry; import com.android.example.bindingdemo.generated.ListItemBinding; @@ -26,7 +24,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; - +import com.android.example.bindingdemo.BR; public class MainActivity extends ActionBarActivity implements Observable { @Bindable UserAdapter tkAdapter; @@ -78,7 +76,7 @@ public class MainActivity extends ActionBarActivity implements Observable { return; } this.selected = selected; - mListeners.notifyChange(this, android.binding.BR.selected); + mListeners.notifyChange(this, BR.selected); } @Bindable @@ -190,7 +188,7 @@ public class MainActivity extends ActionBarActivity implements Observable { } userList.add(user); notifyItemInserted(userList.size() - 1); - mListeners.notifyChange(this, android.binding.BR.itemCount); + mListeners.notifyChange(this, BR.itemCount); } public void remove(User user) { @@ -200,7 +198,7 @@ public class MainActivity extends ActionBarActivity implements Observable { } userList.remove(i); notifyItemRemoved(i); - mListeners.notifyChange(this, android.binding.BR.itemCount); + mListeners.notifyChange(this, BR.itemCount); } @Override diff --git a/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/vo/User.java b/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/vo/User.java index 929d6956..92523216 100644 --- a/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/vo/User.java +++ b/samples/BindingDemo/app/src/main/java/com/android/example/bindingdemo/vo/User.java @@ -4,6 +4,7 @@ import android.binding.Bindable; import android.graphics.Color; import com.android.databinding.library.BaseObservable; +import com.android.example.bindingdemo.BR; import java.util.Objects; @@ -33,7 +34,7 @@ public class User extends BaseObservable { return; } this.group = group; - notifyPropertyChanged(android.binding.BR.group); + notifyPropertyChanged(BR.group); } public int getGroup() { @@ -49,7 +50,7 @@ public class User extends BaseObservable { return; } this.name = name; - notifyPropertyChanged(android.binding.BR.name); + notifyPropertyChanged(BR.name); } public String getLastName() { @@ -61,7 +62,7 @@ public class User extends BaseObservable { return; } this.lastName = lastName; - notifyPropertyChanged(android.binding.BR.lastName); + notifyPropertyChanged(BR.lastName); } public int getPhotoResource() { @@ -73,7 +74,7 @@ public class User extends BaseObservable { return; } this.photoResource = photoResource; - notifyPropertyChanged(android.binding.BR.photoResource); + notifyPropertyChanged(BR.photoResource); } public int getFavoriteColor() { diff --git a/samples/BindingDemo/app/src/test/java/com/android/example/bindingdemo/vo/UnitTest.java b/samples/BindingDemo/app/src/test/java/com/android/example/bindingdemo/vo/UnitTest.java index 3bda1434..7f0ba3af 100644 --- a/samples/BindingDemo/app/src/test/java/com/android/example/bindingdemo/vo/UnitTest.java +++ b/samples/BindingDemo/app/src/test/java/com/android/example/bindingdemo/vo/UnitTest.java @@ -12,6 +12,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import com.android.example.bindingdemo.BR; public class UnitTest { private User testUser; @@ -33,7 +34,7 @@ public class UnitTest { OnPropertyChangedListener mockListener = mock(OnPropertyChangedListener.class); testUser.addOnPropertyChangedListener(mockListener); testUser.setName("Tom"); - verify(mockListener).onPropertyChanged(testUser, android.binding.BR.name); + verify(mockListener).onPropertyChanged(testUser, BR.name); verifyNoMoreInteractions(mockListener); } }
\ No newline at end of file diff --git a/settings.gradle b/settings.gradle index c7906238..21905180 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,4 @@ -include ':baseLibrary' +include ':baseLibrary', ':app' include ':library' include ':compiler' include ':gradlePlugin' |