aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java10
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java66
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/BUILD1
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java3
-rw-r--r--third_party/BUILD1
-rw-r--r--third_party/java/android_databinding/BUILD32
6 files changed, 109 insertions, 4 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java
index 14f43f9b25..7983256ec6 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessingAction.java
@@ -117,6 +117,13 @@ public class AndroidResourceProcessingAction {
help = "Path to where the symbolsTxt should be written.")
public Path symbolsTxtOut;
+ @Option(name = "dataBindingInfoOut",
+ defaultValue = "null",
+ converter = PathConverter.class,
+ category = "output",
+ help = "Path to where data binding's layout info output should be written.")
+ public Path dataBindingInfoOut;
+
@Option(name = "packagePath",
defaultValue = "null",
converter = PathConverter.class,
@@ -306,7 +313,8 @@ public class AndroidResourceProcessingAction {
options.mainDexProguardOutput,
options.resourcesOutput != null
? processedData.getResourceDir().resolve("values").resolve("public.xml")
- : null);
+ : null,
+ options.dataBindingInfoOut);
logger.fine(String.format("aapt finished at %sms", timer.elapsed(TimeUnit.MILLISECONDS)));
if (options.srcJarOutput != null) {
diff --git a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java
index 53a7057fc6..d5194a098d 100644
--- a/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java
+++ b/src/tools/android/java/com/google/devtools/build/android/AndroidResourceProcessor.java
@@ -15,7 +15,10 @@ package com.google.devtools.build.android;
import static java.nio.charset.StandardCharsets.UTF_8;
+import android.databinding.AndroidDataBinding;
+import android.databinding.cli.ProcessXmlOptions;
import com.android.annotations.Nullable;
+import com.android.builder.core.DefaultManifestParser;
import com.android.builder.core.VariantConfiguration;
import com.android.builder.dependency.SymbolFileProvider;
import com.android.builder.internal.SymbolLoader;
@@ -414,10 +417,13 @@ public class AndroidResourceProcessor {
Path packageOut,
Path proguardOut,
Path mainDexProguardOut,
- Path publicResourcesOut)
+ Path publicResourcesOut,
+ Path dataBindingInfoOut)
throws IOException, InterruptedException, LoggedErrorException, UnrecognizedSplitsException {
Path androidManifest = primaryData.getManifest();
- final Path resourceDir = primaryData.getResourceDir();
+ final Path resourceDir = processDataBindings(primaryData.getResourceDir(), dataBindingInfoOut,
+ variantType, customPackageForR, androidManifest);
+
final Path assetsDir = primaryData.getAssetDir();
if (publicResourcesOut != null) {
prepareOutputPath(publicResourcesOut.getParent());
@@ -542,6 +548,62 @@ public class AndroidResourceProcessor {
return outputWithSourceContext;
}
+ /**
+ * If resources exist and a data binding layout info file is requested: processes data binding
+ * declarations over those resources, populates the output file, and creates a new resources
+ * directory with data binding expressions stripped out (so aapt, which doesn't understand
+ * data binding, can properly read them).
+ *
+ * <p>Returns the resources directory that aapt should read.
+ */
+ private Path processDataBindings(Path resourceDir, Path dataBindingInfoOut,
+ VariantConfiguration.Type variantType, String packagePath, Path androidManifest)
+ throws IOException {
+
+ if (dataBindingInfoOut == null) {
+ return resourceDir;
+ } else if (!Files.isDirectory(resourceDir)) {
+ // No resources: no data binding needed. Create a dummy file to satisfy declared outputs.
+ Files.createFile(dataBindingInfoOut);
+ return resourceDir;
+ }
+
+ // Strip the file name (the data binding library automatically adds it back in).
+ // ** The data binding library assumes this file is called "layout-info.zip". **
+ dataBindingInfoOut = dataBindingInfoOut.getParent();
+ if (Files.notExists(dataBindingInfoOut)) {
+ Files.createDirectory(dataBindingInfoOut);
+ }
+
+ Path processedResourceDir = resourceDir.resolveSibling("res_without_databindings");
+ if (Files.notExists(processedResourceDir)) {
+ Files.createDirectory(processedResourceDir);
+ }
+
+ ProcessXmlOptions options = new ProcessXmlOptions();
+ options.setAppId(packagePath);
+ options.setLibrary(variantType == VariantConfiguration.Type.LIBRARY);
+ options.setResInput(resourceDir.toFile());
+ options.setResOutput(processedResourceDir.toFile());
+ options.setLayoutInfoOutput(dataBindingInfoOut.toFile());
+ options.setZipLayoutInfo(true); // Aggregate data-bound .xml files into a single .zip.
+
+ Object minSdk = new DefaultManifestParser().getMinSdkVersion(androidManifest.toFile());
+ if (minSdk instanceof Integer) {
+ options.setMinSdk(((Integer) minSdk).intValue());
+ } else {
+ // TODO(bazel-team): Enforce the minimum SDK check.
+ options.setMinSdk(15);
+ }
+
+ try {
+ AndroidDataBinding.doRun(options);
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ return processedResourceDir;
+ }
+
/** Task to parse java package from AndroidManifest.xml */
private static final class PackageParsingTask implements Callable<String> {
diff --git a/src/tools/android/java/com/google/devtools/build/android/BUILD b/src/tools/android/java/com/google/devtools/build/android/BUILD
index aac3a058fa..f4b5689623 100644
--- a/src/tools/android/java/com/google/devtools/build/android/BUILD
+++ b/src/tools/android/java/com/google/devtools/build/android/BUILD
@@ -80,6 +80,7 @@ java_library(
"//third_party:asm",
"//third_party:guava",
"//third_party:jsr305",
+ "//third_party/java/android_databinding:exec",
"//third_party/protobuf",
],
)
diff --git a/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java b/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java
index ea5f1225ff..4d0498533f 100644
--- a/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java
+++ b/src/tools/android/java/com/google/devtools/build/android/ResourceShrinkerAction.java
@@ -234,7 +234,8 @@ public class ResourceShrinkerAction {
options.shrunkApk,
null /* proguardOutput */,
null /* mainDexProguardOutput */,
- null /* publicResourcesOut */);
+ null /* publicResourcesOut */,
+ null /* dataBindingInfoOut */);
if (options.shrunkResources != null) {
resourceProcessor.createResourcesZip(shrunkResources, resourceFiles.resolve("assets"),
options.shrunkResources);
diff --git a/third_party/BUILD b/third_party/BUILD
index 1de5fbdc12..ec897a375d 100644
--- a/third_party/BUILD
+++ b/third_party/BUILD
@@ -8,6 +8,7 @@ filegroup(
"//third_party/ijar:srcs",
"//third_party/iossim:srcs",
"//third_party/grpc:srcs",
+ "//third_party/java/android_databinding:srcs",
"//third_party/java/apkbuilder:srcs",
"//third_party/java/buck-ios-support:srcs",
"//third_party/java/dd_plist:srcs",
diff --git a/third_party/java/android_databinding/BUILD b/third_party/java/android_databinding/BUILD
new file mode 100644
index 0000000000..9d66f2123d
--- /dev/null
+++ b/third_party/java/android_databinding/BUILD
@@ -0,0 +1,32 @@
+# Copyright 2016 The Bazel Authors. All rights reserved.
+#
+# 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.
+
+licenses(["notice"]) # Apache License 2.0
+
+exports_files(["LICENSE"])
+
+package(
+ default_visibility = ["//visibility:public"],
+)
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+)
+
+# Executable for the databinding resource compiler.
+java_import(
+ name = "exec",
+ jars = ["exec.jar"],
+)