summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java34
-rw-r--r--compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java46
-rw-r--r--compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java20
-rw-r--r--compiler/src/main/java/android/databinding/tool/CompilerChef.java5
-rw-r--r--compiler/src/main/java/android/databinding/tool/LayoutBinder.java1
-rw-r--r--compiler/src/main/kotlin/android/databinding/tool/writer/BRWriter.kt35
-rw-r--r--compiler/src/main/kotlin/android/databinding/tool/writer/DataBinderWriter.kt47
-rw-r--r--compilerCommon/src/main/java/android/databinding/tool/util/Preconditions.java6
-rw-r--r--integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/DataBindingMapperTest.java30
-rw-r--r--library/src/main/java/android/databinding/DataBinderMapper.java3
-rw-r--r--library/src/main/java/android/databinding/DataBindingUtil.java11
11 files changed, 184 insertions, 54 deletions
diff --git a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java
index 44cdb4f1..3066bbdc 100644
--- a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java
+++ b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessBindable.java
@@ -22,10 +22,10 @@ import android.databinding.tool.CompilerChef.BindableHolder;
import android.databinding.tool.util.GenerationalClassUtil;
import android.databinding.tool.util.L;
import android.databinding.tool.util.Preconditions;
+import android.databinding.tool.writer.BRWriter;
+import android.databinding.tool.writer.JavaFileWriter;
import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -117,34 +117,18 @@ public class ProcessBindable extends ProcessDataBinding.ProcessingStep implement
for (Intermediate intermediate : previousIntermediates) {
intermediate.captureProperties(properties);
}
- writeBRClass(useFinalFields, pkg, properties);
+ final JavaFileWriter writer = getWriter();
+ BRWriter brWriter = new BRWriter(properties, useFinalFields);
+ writer.writeToFile(pkg + ".BR", brWriter.write(pkg));
+ //writeBRClass(useFinalFields, pkg, properties);
if (useFinalFields) {
// generate BR for all previous packages
for (Intermediate intermediate : previousIntermediates) {
- writeBRClass(true, intermediate.getPackage(),
- properties);
+ writer.writeToFile(intermediate.getPackage() + ".BR",
+ brWriter.write(intermediate.getPackage()));
}
}
- }
-
- 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("}\n");
-
- getWriter().writeToFile(pkg + ".BR", out.toString() );
+ mCallback.onBrWriterReady(brWriter);
}
private String getPropertyName(Element element) {
diff --git a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java
index 944cc20a..bf88435c 100644
--- a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java
+++ b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessDataBinding.java
@@ -16,9 +16,14 @@
package android.databinding.annotationprocessor;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+
import android.databinding.BindingBuildInfo;
+import android.databinding.tool.CompilerChef;
import android.databinding.tool.reflection.ModelAnalyzer;
+import android.databinding.tool.util.Preconditions;
import android.databinding.tool.writer.AnnotationJavaFileWriter;
+import android.databinding.tool.writer.BRWriter;
import android.databinding.tool.writer.JavaFileWriter;
import java.util.Arrays;
@@ -69,15 +74,46 @@ public class ProcessDataBinding extends AbstractProcessor {
}
private void initProcessingSteps() {
- ProcessBindable processBindable = new ProcessBindable();
+ final ProcessBindable processBindable = new ProcessBindable();
mProcessingSteps = Arrays.asList(
new ProcessMethodAdapters(),
- new ProcessExpressions(processBindable),
+ new ProcessExpressions(),
processBindable
);
+ Callback dataBinderWriterCallback = new Callback() {
+ CompilerChef mChef;
+ BRWriter mBRWriter;
+ boolean mLibraryProject;
+ int mMinSdk;
+
+ @Override
+ public void onChefReady(CompilerChef chef, boolean libraryProject, int minSdk) {
+ Preconditions.checkNull(mChef, "Cannot set compiler chef twice");
+ chef.addBRVariables(processBindable);
+ mChef = chef;
+ mLibraryProject = libraryProject;
+ mMinSdk = minSdk;
+ considerWritingMapper();
+ }
+
+ private void considerWritingMapper() {
+ if (mLibraryProject || mChef == null || mBRWriter == null) {
+ return;
+ }
+ mChef.writeDataBinderMapper(mMinSdk, mBRWriter);
+ }
+
+ @Override
+ public void onBrWriterReady(BRWriter brWriter) {
+ Preconditions.checkNull(mBRWriter, "Cannot set br writer twice");
+ mBRWriter = brWriter;
+ considerWritingMapper();
+ }
+ };
AnnotationJavaFileWriter javaFileWriter = new AnnotationJavaFileWriter(processingEnv);
for (ProcessingStep step : mProcessingSteps) {
step.mJavaFileWriter = javaFileWriter;
+ step.mCallback = dataBinderWriterCallback;
}
}
@@ -93,6 +129,7 @@ public class ProcessDataBinding extends AbstractProcessor {
public abstract static class ProcessingStep {
private boolean mDone;
private JavaFileWriter mJavaFileWriter;
+ protected Callback mCallback;
protected JavaFileWriter getWriter() {
return mJavaFileWriter;
@@ -125,4 +162,9 @@ public class ProcessDataBinding extends AbstractProcessor {
ProcessingEnvironment processingEnvironment,
BindingBuildInfo buildInfo);
}
+
+ interface Callback {
+ void onChefReady(CompilerChef chef, boolean libraryProject, int minSdk);
+ void onBrWriterReady(BRWriter brWriter);
+ }
}
diff --git a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java
index a1866348..f948831a 100644
--- a/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java
+++ b/compiler/src/main/java/android/databinding/annotationprocessor/ProcessExpressions.java
@@ -26,6 +26,7 @@ import android.databinding.tool.reflection.SdkUtil;
import android.databinding.tool.store.ResourceBundle;
import android.databinding.tool.util.GenerationalClassUtil;
import android.databinding.tool.util.L;
+import android.databinding.tool.writer.BRWriter;
import java.io.File;
import java.io.FilenameFilter;
@@ -47,13 +48,9 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep {
private static final String LAYOUT_INFO_FILE_SUFFIX = "-layoutinfo.bin";
- private final ProcessBindable mProcessBindable;
-
- public ProcessExpressions(ProcessBindable processBindable) {
- mProcessBindable = processBindable;
+ public ProcessExpressions() {
}
-
@Override
public boolean onHandleStep(RoundEnvironment roundEnvironment,
ProcessingEnvironment processingEnvironment, BindingBuildInfo buildInfo) {
@@ -123,11 +120,10 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep {
}
private void writeResourceBundle(ResourceBundle resourceBundle, boolean forLibraryModule,
- int minSdk, String exportClassNamesTo)
+ final int minSdk, String exportClassNamesTo)
throws JAXBException {
- CompilerChef compilerChef = CompilerChef.createChef(resourceBundle, getWriter());
+ final CompilerChef compilerChef = CompilerChef.createChef(resourceBundle, getWriter());
if (compilerChef.hasAnythingToGenerate()) {
- compilerChef.addBRVariables(mProcessBindable);
compilerChef.writeViewBinderInterfaces(forLibraryModule);
if (!forLibraryModule) {
compilerChef.writeViewBinders(minSdk);
@@ -139,17 +135,15 @@ public class ProcessExpressions extends ProcessDataBinding.ProcessingStep {
if (forLibraryModule) {
Set<String> classNames = compilerChef.getWrittenClassNames();
String out = StringUtils.join(classNames, System.getProperty("line.separator"));
-
L.d("Writing list of classes to %s . \nList:%s", exportClassNamesTo, out);
try {
- FileUtils.write(new File(exportClassNamesTo),
- out);
+ //noinspection ConstantConditions
+ FileUtils.write(new File(exportClassNamesTo), out);
} catch (IOException e) {
L.e(e, "Cannot create list of written classes");
}
- } else {
- compilerChef.writeDbrFile(minSdk);
}
+ mCallback.onChefReady(compilerChef, forLibraryModule, minSdk);
}
public static interface Intermediate extends Serializable {
diff --git a/compiler/src/main/java/android/databinding/tool/CompilerChef.java b/compiler/src/main/java/android/databinding/tool/CompilerChef.java
index cb307e56..10cc3d43 100644
--- a/compiler/src/main/java/android/databinding/tool/CompilerChef.java
+++ b/compiler/src/main/java/android/databinding/tool/CompilerChef.java
@@ -15,6 +15,7 @@ package android.databinding.tool;
import android.databinding.tool.store.ResourceBundle;
import android.databinding.tool.util.L;
+import android.databinding.tool.writer.BRWriter;
import android.databinding.tool.writer.DataBinderWriter;
import android.databinding.tool.writer.JavaFileWriter;
@@ -59,12 +60,12 @@ public class CompilerChef {
return mResourceBundle != null && mResourceBundle.getLayoutBundles().size() > 0;
}
- public void writeDbrFile(int minSdk) {
+ public void writeDataBinderMapper(int minSdk, BRWriter brWriter) {
ensureDataBinder();
final String pkg = "android.databinding";
DataBinderWriter dbr = new DataBinderWriter(pkg, mResourceBundle.getAppPackage(),
"DataBinderMapper", mDataBinder.getLayoutBinders(), minSdk);
- mFileWriter.writeToFile(pkg + "." + dbr.getClassName(), dbr.write());
+ mFileWriter.writeToFile(pkg + "." + dbr.getClassName(), dbr.write(brWriter));
}
/**
diff --git a/compiler/src/main/java/android/databinding/tool/LayoutBinder.java b/compiler/src/main/java/android/databinding/tool/LayoutBinder.java
index 79d6bfc4..c9efe8f4 100644
--- a/compiler/src/main/java/android/databinding/tool/LayoutBinder.java
+++ b/compiler/src/main/java/android/databinding/tool/LayoutBinder.java
@@ -269,7 +269,6 @@ public class LayoutBinder implements ResolveListenersCallback {
return mWriter.writeBaseClass(forLibrary);
}
-
public String writeViewBinder(int minSdk) {
mExprModel.seal(this);
ensureWriter();
diff --git a/compiler/src/main/kotlin/android/databinding/tool/writer/BRWriter.kt b/compiler/src/main/kotlin/android/databinding/tool/writer/BRWriter.kt
new file mode 100644
index 00000000..9e41c2d6
--- /dev/null
+++ b/compiler/src/main/kotlin/android/databinding/tool/writer/BRWriter.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.tool.writer
+
+import kotlin.properties.Delegates
+
+class BRWriter(properties: Set<String>, val useFinal : Boolean) {
+ val indexedProps = properties.sort().withIndex()
+ public fun write(pkg : String): String = "package $pkg;${System.lineSeparator()}$klass"
+ val klass: String by Delegates.lazy {
+ kcode("") {
+ val prefix = if (useFinal) "final " else "";
+ nl("public class BR {") {
+ tab("public static ${prefix}int _all = 0;")
+ indexedProps.forEach {
+ tab ("public static ${prefix}int ${it.value} = ${it.index + 1};")
+ }
+ } nl ("}")
+ }.generate()
+ }
+} \ No newline at end of file
diff --git a/compiler/src/main/kotlin/android/databinding/tool/writer/DataBinderWriter.kt b/compiler/src/main/kotlin/android/databinding/tool/writer/DataBinderWriter.kt
index 34475ba8..29863395 100644
--- a/compiler/src/main/kotlin/android/databinding/tool/writer/DataBinderWriter.kt
+++ b/compiler/src/main/kotlin/android/databinding/tool/writer/DataBinderWriter.kt
@@ -17,19 +17,13 @@ import android.databinding.tool.LayoutBinder
class DataBinderWriter(val pkg: String, val projectPackage: String, val className: String,
val layoutBinders : List<LayoutBinder>, val minSdk : kotlin.Int) {
- fun write() = kcode("") {
+ fun write(brWriter : BRWriter) = kcode("") {
nl("package $pkg;")
nl("import $projectPackage.BR;")
nl("class $className {") {
tab("final static int TARGET_MIN_SDK = ${minSdk};")
nl("")
- tab("private final java.util.HashMap<String, Integer> mLayoutIds;")
- nl("")
tab("public $className() {") {
- tab("mLayoutIds = new java.util.HashMap<String, Integer>();")
- layoutBinders.forEach {
- tab("mLayoutIds.put(\"${it.getTag()}_0\", ${it.getModulePackage()}.R.layout.${it.getLayoutname()});")
- }
}
tab("}")
nl("")
@@ -97,14 +91,45 @@ class DataBinderWriter(val pkg: String, val projectPackage: String, val classNam
tab("}")
tab("int getLayoutId(String tag) {") {
- tab("Integer id = mLayoutIds.get(tag);")
- tab("if (id == null) {") {
- tab("return 0;")
+ tab("if (tag == null) {") {
+ tab("return 0;");
+ }
+ tab("}")
+ // String.hashCode is well defined in the API so we can rely on it being the same on the device and the host machine
+ tab("final int code = tag.hashCode();");
+ tab("switch(code) {") {
+ layoutBinders.groupBy {"${it.getTag()}_0".hashCode()}.forEach {
+ tab("case ${it.key}:") {
+ it.value.forEach {
+ tab("if(tag.equals(\"${it.getTag()}_0\"))") {
+ tab("return ${it.getModulePackage()}.R.layout.${it.getLayoutname()};")
+ }
+ }
+ tab("break;")
+ }
+
+ }
}
tab("}")
- tab("return id;")
+ tab("return 0;")
}
tab("}")
+
+ tab("String convertBrIdToString(int id) {") {
+ tab("if (id < 0 || id >= InnerBrLookup.sKeys.length) {") {
+ tab("return null;")
+ } tab("}")
+ tab("return InnerBrLookup.sKeys[id];")
+ } tab("}")
+
+ tab("private static class InnerBrLookup {") {
+ tab("static String[] sKeys = new String[]{") {
+ tab("\"_all\"")
+ brWriter.indexedProps.forEach {
+ tab(",\"${it.value}\"")
+ }
+ }.app("};")
+ } tab("}")
}
nl("}")
}.generate()
diff --git a/compilerCommon/src/main/java/android/databinding/tool/util/Preconditions.java b/compilerCommon/src/main/java/android/databinding/tool/util/Preconditions.java
index f1a790cd..8041cd40 100644
--- a/compilerCommon/src/main/java/android/databinding/tool/util/Preconditions.java
+++ b/compilerCommon/src/main/java/android/databinding/tool/util/Preconditions.java
@@ -31,4 +31,10 @@ public class Preconditions {
L.e(error, args);
}
}
+
+ public static void checkNull(Object value, String error, Object... args) {
+ if (value != null) {
+ L.e(error, args);
+ }
+ }
}
diff --git a/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/DataBindingMapperTest.java b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/DataBindingMapperTest.java
new file mode 100644
index 00000000..62904b49
--- /dev/null
+++ b/integration-tests/TestApp/app/src/androidTestApi7/java/android/databinding/testapp/DataBindingMapperTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.databinding.testapp;
+
+import android.databinding.DataBindingUtil;
+import android.test.AndroidTestCase;
+import android.databinding.testapp.BR;
+
+import java.lang.reflect.Field;
+
+
+public class DataBindingMapperTest extends AndroidTestCase {
+ public void testBrIds() throws IllegalAccessException {
+ for (Field field : BR.class.getDeclaredFields()) {
+ assertEquals(field.getName(),
+ DataBindingUtil.convertBrIdToString((int) field.get(BR.class)));
+ }
+ }
+}
diff --git a/library/src/main/java/android/databinding/DataBinderMapper.java b/library/src/main/java/android/databinding/DataBinderMapper.java
index be10d971..f20c480e 100644
--- a/library/src/main/java/android/databinding/DataBinderMapper.java
+++ b/library/src/main/java/android/databinding/DataBinderMapper.java
@@ -31,5 +31,8 @@ class DataBinderMapper {
return null;
}
public int getLayoutId(String tag) { return 0; }
+ public String convertBrIdToString(int id) {
+ return null;
+ }
public static int TARGET_MIN_SDK = 0;
}
diff --git a/library/src/main/java/android/databinding/DataBindingUtil.java b/library/src/main/java/android/databinding/DataBindingUtil.java
index 85530c71..2208ab4d 100644
--- a/library/src/main/java/android/databinding/DataBindingUtil.java
+++ b/library/src/main/java/android/databinding/DataBindingUtil.java
@@ -186,4 +186,15 @@ public class DataBindingUtil {
activity.setContentView(binding.getRoot(), binding.getRoot().getLayoutParams());
return binding;
}
+
+ /**
+ * Converts the given BR id to its string representation which might be useful for logging
+ * purposes.
+ *
+ * @param id The integer id, which should be a field from BR class.
+ * @return The name if the BR id or null if id is out of bounds.
+ */
+ public static String convertBrIdToString(int id) {
+ return sMapper.convertBrIdToString(id);
+ }
}