From 6bd7cd429e6700dc470aa82796622b0e24bef3aa Mon Sep 17 00:00:00 2001 From: Yigit Boyar Date: Mon, 2 Feb 2015 16:55:54 -0800 Subject: [PATCH] Support for layout files in multiple resource folders Multiple layout files with the same name now share a common interface. They also share all variables no matter where it is defined. If a variable is NOT used in one of the layout files, its implementation does not create a field BUT STILL creates the setter (to implement the base interface). If the same view id is used for two different types of views, return type in the interface is android.view.View. If it is an include, the return value is IViewDataBinder. Change-Id: Ie3cc2bb8ec5ea48b71337e314ec588a050d714df --- tools/data-binding/TestApp/build.gradle | 5 +- .../testapp/BaseDataBinderTest.java | 27 +++++ .../testapp/BaseLandDataBinderTest.java | 25 ++++ .../testapp/LandDataBinderTest.java | 18 +++ .../testapp/ViewBindingAdapterTest.java | 15 ++- .../multiconfig/LandscapeConfigTest.java | 60 ++++++++++ .../multiconfig/PortraitConfigTest.java | 63 ++++++++++ .../TestApp/src/main/AndroidManifest.xml | 3 +- .../main/res/layout-land/multi_res_layout.xml | 41 +++++++ .../src/main/res/layout/multi_res_layout.xml | 38 ++++++ tools/data-binding/baseLibrary/build.gradle | 57 +-------- tools/data-binding/build.gradle | 1 + .../android/databinding/BindingTarget.java | 23 +++- .../com/android/databinding/DataBinder.java | 12 +- .../com/android/databinding/LayoutBinder.java | 93 +++++++++++++- .../com/android/databinding/expr/Expr.java | 9 ++ .../kotlin/com/android/databinding/main.kt | 113 +++++++++++++++--- .../android/databinding/util/ParserHelper.kt | 2 +- .../com/android/databinding/util/XmlEditor.kt | 62 +++++++--- .../databinding/writer/DataBinderWriter.kt | 21 +++- .../databinding/writer/LayoutBinderWriter.kt | 85 ++++++++----- .../gradle/wrapper/gradle-wrapper.properties | 20 +--- tools/data-binding/gradlePlugin/build.gradle | 2 +- .../com.android.databinding.properties | 0 tools/data-binding/library/build.gradle | 2 +- .../samples/BindingDemo/build.gradle | 2 +- 26 files changed, 637 insertions(+), 162 deletions(-) create mode 100644 tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/BaseLandDataBinderTest.java create mode 100644 tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/LandDataBinderTest.java create mode 100644 tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/multiconfig/LandscapeConfigTest.java create mode 100644 tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/multiconfig/PortraitConfigTest.java create mode 100644 tools/data-binding/TestApp/src/main/res/layout-land/multi_res_layout.xml create mode 100644 tools/data-binding/TestApp/src/main/res/layout/multi_res_layout.xml rename tools/data-binding/{compiler => gradlePlugin}/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties (100%) diff --git a/tools/data-binding/TestApp/build.gradle b/tools/data-binding/TestApp/build.gradle index 4e42f20918e60..c21652e5a9f42 100644 --- a/tools/data-binding/TestApp/build.gradle +++ b/tools/data-binding/TestApp/build.gradle @@ -10,15 +10,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - buildscript { repositories { jcenter() mavenLocal() } dependencies { - classpath 'com.android.tools.build:gradle:1.0.0' - classpath 'com.android.databinding:dataBinder:0.3-SNAPSHOT' + classpath "com.android.tools.build:gradle:$androidPluginVersion" + classpath "com.android.databinding:dataBinder:$version" } } apply plugin: 'com.android.application' diff --git a/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/BaseDataBinderTest.java b/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/BaseDataBinderTest.java index c64524e208f6c..94db7b2e76e05 100644 --- a/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/BaseDataBinderTest.java +++ b/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/BaseDataBinderTest.java @@ -16,6 +16,7 @@ package com.android.databinding.testapp; import com.android.databinding.library.DataBinder; import com.android.databinding.library.IViewDataBinder; +import android.content.pm.ActivityInfo; import android.os.Looper; import android.test.ActivityInstrumentationTestCase2; @@ -23,17 +24,24 @@ public class BaseDataBinderTest extends ActivityInstrumentationTestCase2 { private Class mBinderClass; private int mLayoutId; + private int mOrientation; protected T mBinder; public BaseDataBinderTest(final Class binderClass, final int layoutId) { + this(binderClass, layoutId, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + + public BaseDataBinderTest(final Class binderClass, final int layoutId, final int orientation) { super(TestActivity.class); mBinderClass = binderClass; mLayoutId = layoutId; + mOrientation = orientation; } @Override protected void setUp() throws Exception { super.setUp(); + getActivity().setRequestedOrientation(mOrientation); createBinder(); } @@ -47,6 +55,7 @@ public class BaseDataBinderTest @Override public void run() { mBinder = DataBinder.createBinder(mBinderClass, getActivity(), mLayoutId, null); + getActivity().setContentView(mBinder.getRoot()); } }); if (!isMainThread()) { @@ -54,4 +63,22 @@ public class BaseDataBinderTest } assertNotNull(mBinder); } + + protected void assertMethod(Class klass, String methodName) throws NoSuchMethodException { + assertEquals(klass, mBinder.getClass().getDeclaredMethod(methodName).getReturnType()); + } + + protected void assertField(Class klass, String fieldName) throws NoSuchFieldException { + assertEquals(klass, mBinder.getClass().getDeclaredField(fieldName).getType()); + } + + protected void assertNoField(String fieldName) { + Exception[] ex = new Exception[1]; + try { + mBinder.getClass().getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + ex[0] = e; + } + assertNotNull(ex[0]); + } } diff --git a/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/BaseLandDataBinderTest.java b/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/BaseLandDataBinderTest.java new file mode 100644 index 0000000000000..0f983ebaa8d7b --- /dev/null +++ b/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/BaseLandDataBinderTest.java @@ -0,0 +1,25 @@ +/* + * 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.testapp; + +import com.android.databinding.library.IViewDataBinder; + +import android.content.pm.ActivityInfo; + +public class BaseLandDataBinderTest extends BaseDataBinderTest { + + public BaseLandDataBinderTest(Class binderClass, int layoutId) { + super(binderClass, layoutId, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } +} diff --git a/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/LandDataBinderTest.java b/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/LandDataBinderTest.java new file mode 100644 index 0000000000000..218c799430b68 --- /dev/null +++ b/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/LandDataBinderTest.java @@ -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. + */ + +package com.android.databinding.testapp; + +public class LandDataBinderTest { + +} diff --git a/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/ViewBindingAdapterTest.java b/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/ViewBindingAdapterTest.java index 7d9b8ae9dfab1..102725b7b4487 100644 --- a/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/ViewBindingAdapterTest.java +++ b/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/ViewBindingAdapterTest.java @@ -20,6 +20,7 @@ import com.android.databinding.testapp.vo.ViewBindingObject; import android.content.res.ColorStateList; import android.os.Build; +import android.test.UiThreadTest; import android.view.View; public class ViewBindingAdapterTest extends BaseDataBinderTest { @@ -33,8 +34,18 @@ public class ViewBindingAdapterTest extends BaseDataBinderTest { + + public LandscapeConfigTest() { + super(MultiResLayoutBinder.class, R.layout.multi_res_layout); + } + + public void testSharedViewIdAndVariableInheritance() + throws InterruptedException, NoSuchMethodException, NoSuchFieldException { + assertEquals("MultiResLayoutBinderLandImpl", mBinder.getClass().getSimpleName()); + assertMethod(TextView.class, "getObjectInLandTextView"); + assertMethod(TextView.class, "getObjectInDefaultTextView"); + assertMethod(View.class, "getObjectInDefaultTextView2"); + + assertField(TextView.class, "mObjectInLandTextView"); + assertField(TextView.class, "mObjectInDefaultTextView"); + assertField(TextView.class, "mObjectInDefaultTextView2"); + + assertField(NotBindableVo.class, "mObjectInLand"); + assertField(NotBindableVo.class, "mObjectInDefault"); + + // includes + assertMethod(IViewDataBinder.class, "getIncludedLayoutConflict"); + assertMethod(BasicBindingBinder.class, "getIncludedLayoutShared"); + assertMethod(ConditionalBindingBinder.class, "getIncludedLayoutPort"); + assertMethod(ConditionalBindingBinder.class, "getIncludedLayoutLand"); + + assertField(IncludedLayoutBinder.class, "mIncludedLayoutConflict"); + assertField(BasicBindingBinder.class, "mIncludedLayoutShared"); + assertField(ConditionalBindingBinder.class, "mIncludedLayoutLand"); + + assertNoField("mIncludedLayoutPort"); + } +} diff --git a/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/multiconfig/PortraitConfigTest.java b/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/multiconfig/PortraitConfigTest.java new file mode 100644 index 0000000000000..8790f04be3746 --- /dev/null +++ b/tools/data-binding/TestApp/src/androidTest/java/com/android/databinding/testapp/multiconfig/PortraitConfigTest.java @@ -0,0 +1,63 @@ +/* + * 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.testapp.multiconfig; + +import com.android.databinding.library.IViewDataBinder; +import com.android.databinding.testapp.BaseDataBinderTest; +import com.android.databinding.testapp.R; +import com.android.databinding.testapp.generated.BasicBindingBinder; +import com.android.databinding.testapp.generated.ConditionalBindingBinder; +import com.android.databinding.testapp.generated.IncludedLayoutBinder; +import com.android.databinding.testapp.generated.MultiResLayoutBinder; +import com.android.databinding.testapp.vo.NotBindableVo; + +import android.content.pm.ActivityInfo; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; + +public class PortraitConfigTest extends BaseDataBinderTest { + public PortraitConfigTest() { + super(MultiResLayoutBinder.class, R.layout.multi_res_layout, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + + public void testSharedViewIdAndVariableInheritance() + throws InterruptedException, NoSuchMethodException, NoSuchFieldException { + assertEquals("MultiResLayoutBinderImpl", mBinder.getClass().getSimpleName()); + assertEquals("MultiResLayoutBinderImpl", mBinder.getClass().getSimpleName()); + assertMethod(TextView.class, "getObjectInLandTextView"); + assertMethod(TextView.class, "getObjectInDefaultTextView"); + assertMethod(View.class, "getObjectInDefaultTextView2"); + + assertNoField("mObjectInLandTextView"); + assertField(TextView.class, "mObjectInDefaultTextView"); + assertField(EditText.class, "mObjectInDefaultTextView2"); + + assertNoField("mObjectInLand"); + assertField(NotBindableVo.class, "mObjectInDefault"); + + + // includes + assertMethod(IViewDataBinder.class, "getIncludedLayoutConflict"); + assertMethod(BasicBindingBinder.class, "getIncludedLayoutShared"); + assertMethod(ConditionalBindingBinder.class, "getIncludedLayoutPort"); + assertMethod(ConditionalBindingBinder.class, "getIncludedLayoutLand"); + + assertField(BasicBindingBinder.class, "mIncludedLayoutConflict"); + assertField(BasicBindingBinder.class, "mIncludedLayoutShared"); + assertField(ConditionalBindingBinder.class, "mIncludedLayoutPort"); + + assertNoField("mIncludedLayoutLand"); + } +} diff --git a/tools/data-binding/TestApp/src/main/AndroidManifest.xml b/tools/data-binding/TestApp/src/main/AndroidManifest.xml index 83e112100072b..ae2581a67666e 100644 --- a/tools/data-binding/TestApp/src/main/AndroidManifest.xml +++ b/tools/data-binding/TestApp/src/main/AndroidManifest.xml @@ -18,7 +18,8 @@ android:label="@string/app_name" android:icon="@drawable/ic_launcher" > - + diff --git a/tools/data-binding/TestApp/src/main/res/layout-land/multi_res_layout.xml b/tools/data-binding/TestApp/src/main/res/layout-land/multi_res_layout.xml new file mode 100644 index 0000000000000..b70f029266eb0 --- /dev/null +++ b/tools/data-binding/TestApp/src/main/res/layout-land/multi_res_layout.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/data-binding/TestApp/src/main/res/layout/multi_res_layout.xml b/tools/data-binding/TestApp/src/main/res/layout/multi_res_layout.xml new file mode 100644 index 0000000000000..6ec7402279078 --- /dev/null +++ b/tools/data-binding/TestApp/src/main/res/layout/multi_res_layout.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/data-binding/baseLibrary/build.gradle b/tools/data-binding/baseLibrary/build.gradle index e32fabf98c609..d5ff440194ba4 100644 --- a/tools/data-binding/baseLibrary/build.gradle +++ b/tools/data-binding/baseLibrary/build.gradle @@ -1,62 +1,9 @@ -/* - * Copyright (C) 2014 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: 'java' -apply plugin: 'maven' -apply plugin: 'application' - -sourceCompatibility = 1.7 -mainClassName = "org.antlr.v4.Tool" - -buildscript { - repositories { - mavenLocal() - mavenCentral() - } -} repositories { mavenCentral() } -sourceSets { - main { - java { - srcDir 'src/main/java' - } - } - test { - java { - srcDir 'src/test/java' - } - } -} - dependencies { - compile 'com.tunnelvisionlabs:antlr4:4.4' - testCompile 'junit:junit:4.11' -} - -uploadArchives { - repositories { - mavenDeployer { - repository(url: mavenLocal().url) - pom.version = '0.3-SNAPSHOT' - pom.artifactId = 'baseLibrary' - pom.groupId='com.android.databinding' - } - } -} + testCompile group: 'junit', name: 'junit', version: '4.11' +} \ No newline at end of file diff --git a/tools/data-binding/build.gradle b/tools/data-binding/build.gradle index 717b9a6070320..d1bd9cd22f3c5 100644 --- a/tools/data-binding/build.gradle +++ b/tools/data-binding/build.gradle @@ -1,6 +1,7 @@ ext.kotlinVersion = '0.10.195' ext.releaseVersion = "0.3" ext.snapshotVersion = "0.3-SNAPSHOT" +ext.androidPluginVersion = "1.0.0" subprojects { group = 'com.android.databinding' diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/BindingTarget.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/BindingTarget.java index cd5c87afc1a10..ab0b34c29ec92 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/BindingTarget.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/BindingTarget.java @@ -25,26 +25,39 @@ import java.util.ArrayList; import java.util.List; public class BindingTarget { - Node mNode; String mId; String mViewClass; List mBindings = new ArrayList<>(); ExprModel mModel; Class mResolvedClass; String mIncludedLayout; + // if this target presents itself in multiple layout files with different view types, + // it receives an interface type and should use it in the getter instead. + String mInterfaceType; + // if this target is inherited from a common layout interface, used is false so that we don't + // create find view by id etc for it. + boolean mUsed; - public BindingTarget(Node node, String id, String viewClass) { - mNode = node; + public BindingTarget(String id, String viewClass, boolean used) { mId = id; mViewClass = viewClass; + mUsed = used; + } + + public boolean isUsed() { + return mUsed; } public void addBinding(String name, Expr expr) { mBindings.add(new Binding(this, name, expr)); } - public Node getNode() { - return mNode; + public void setInterfaceType(String interfaceType) { + mInterfaceType = interfaceType; + } + + public String getInterfaceType() { + return mInterfaceType == null ? mViewClass : mInterfaceType; } public String getId() { diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/DataBinder.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/DataBinder.java index ff379a4cba0b0..4503939ef2cba 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/DataBinder.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/DataBinder.java @@ -31,6 +31,7 @@ import org.xml.sax.SAXException; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Objects; @@ -53,7 +54,7 @@ public class DataBinder { private static final String XPATH_IMPORT_DEFINITIONS = "//import"; final String LAYOUT_PREFIX = "@layout/"; - List mLayoutBinders = new ArrayList<>(); + HashMap> mLayoutBinders = new HashMap<>(); public LayoutBinder parseXml(File xml, String pkg) throws ParserConfigurationException, IOException, SAXException, @@ -120,7 +121,7 @@ public class DataBinder { fullClassName = getFullViewClassName(nodeName); } final BindingTarget bindingTarget = layoutBinder - .createBindingTarget(parent, id.getNodeValue(), fullClassName); + .createBindingTarget(id.getNodeValue(), fullClassName, true); bindingTarget.setIncludedLayout(layoutName); int attrCount = attributes.getLength(); for (int i = 0; i < attrCount; i ++) { @@ -137,7 +138,10 @@ public class DataBinder { } if (!layoutBinder.isEmpty()) { - mLayoutBinders.add(layoutBinder); + if (!mLayoutBinders.containsKey(xml.getName())) { + mLayoutBinders.put(xml.getName(), new ArrayList()); + } + mLayoutBinders.get(xml.getName()).add(layoutBinder); } return layoutBinder; } @@ -178,7 +182,7 @@ public class DataBinder { return viewName; } - public List getLayoutBinders() { + public HashMap> getLayoutBinders() { return mLayoutBinders; } } diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/LayoutBinder.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/LayoutBinder.java index 88c9163da226a..cb2fc8d5ff4a4 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/LayoutBinder.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/LayoutBinder.java @@ -17,7 +17,11 @@ package com.android.databinding; import com.google.common.base.Preconditions; +import com.google.common.collect.Iterables; +import com.android.databinding.expr.Dependency; +import com.android.databinding.util.Log; +import com.android.databinding.util.ParserHelper; import com.android.databinding.writer.LayoutBinderWriter; import com.android.databinding.expr.Expr; import com.android.databinding.expr.ExprModel; @@ -27,8 +31,13 @@ import com.android.databinding.util.L; import org.w3c.dom.Node; +import java.io.File; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; /** * Keeps all information about the bindings per layout file @@ -45,9 +54,16 @@ public class LayoutBinder { private String mProjectPackage; private String mBaseClassName; private String mLayoutname; + private File mFile; + private int id; + private final HashMap mUserDefinedVariables = new HashMap<>(); + private final HashMap mUserDefinedImports = new HashMap<>(); private LayoutBinderWriter mWriter; + // layout has different definitions in different configurations + private boolean mHasVariations = false; + public LayoutBinder(Node root) { mRoot = root; mExprModel = new ExprModel(); @@ -55,22 +71,55 @@ public class LayoutBinder { mBindingTargets = new ArrayList<>(); } + public void resolveWhichExpressionsAreUsed() { + List used = new ArrayList<>(); + for (BindingTarget target : mBindingTargets) { + for (Binding binding : target.getBindings()) { + binding.getExpr().setIsUsed(true); + used.add(binding.getExpr()); + } + } + while (!used.isEmpty()) { + Expr e = used.remove(used.size() - 1); + for (Dependency dep : e.getDependencies()) { + if (!dep.getOther().isUsed()) { + used.add(dep.getOther()); + dep.getOther().setIsUsed(true); + } + } + } + } + public IdentifierExpr addVariable(String name, String type) { + Preconditions.checkState(!mUserDefinedVariables.containsKey(name), + "%s has already been defined as %s", name, type); final IdentifierExpr id = mExprModel.identifier(name); id.setUserDefinedType(type); id.enableDirectInvalidation(); + mUserDefinedVariables.put(name, type); return id; } public StaticIdentifierExpr addImport(String alias, String type) { + Preconditions.checkState(!mUserDefinedImports.containsKey(alias), + "%s has already been defined as %s", alias, type); final StaticIdentifierExpr id = mExprModel.staticIdentifier(alias); L.d("adding import %s as %s klass: %s", type, alias, id.getClass().getSimpleName()); id.setUserDefinedType(type); + mUserDefinedImports.put(alias, type); return id; } - public BindingTarget createBindingTarget(Node parent, String nodeValue, String viewClassName) { - final BindingTarget target = new BindingTarget(parent, nodeValue, viewClassName); + public HashMap getUserDefinedVariables() { + return mUserDefinedVariables; + } + + public HashMap getUserDefinedImports() { + return mUserDefinedImports; + } + + public BindingTarget createBindingTarget(String nodeValue, String viewClassName, boolean used) { + final BindingTarget target = new BindingTarget(nodeValue, viewClassName, used); mBindingTargets.add(target); target.setModel(mExprModel); return target; @@ -147,10 +196,48 @@ public class LayoutBinder { } public String getClassName() { - return mBaseClassName + "Impl"; + final String suffix; + if (hasVariations()) { + // append configuration specifiers. + final String parentFileName = mFile.getParentFile().getName(); + L.d("parent file for %s is %s", mFile.getName(), parentFileName); + if ("layout".equals(parentFileName)) { + suffix = ""; + } else { + suffix = ParserHelper.INSTANCE$.toClassName(parentFileName.substring("layout-".length())); + } + } else { + suffix = ""; + } + return mBaseClassName + suffix + "Impl"; + } public String getInterfaceName() { return mBaseClassName; } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public File getFile() { + return mFile; + } + + public void setFile(File file) { + mFile = file; + } + + public boolean hasVariations() { + return mHasVariations; + } + + public void setHasVariations(boolean hasVariations) { + mHasVariations = hasVariations; + } } diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/Expr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/Expr.java index c1f4244b7bab9..a773d66656efc 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/Expr.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/Expr.java @@ -87,6 +87,7 @@ abstract public class Expr { * Used by generators when this expression is resolved. */ private boolean mRead; + private boolean mIsUsed = false; Expr(Iterable children) { for (Expr expr : children) { @@ -555,6 +556,14 @@ abstract public class Expr { return false; } + public void setIsUsed(boolean isUsed) { + mIsUsed = isUsed; + } + + public boolean isUsed() { + return mIsUsed; + } + static class Node { BitSet mBitSet = new BitSet(); diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt index a4ace7d15aee9..6cc17a261ae20 100644 --- a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/main.kt @@ -52,6 +52,7 @@ import com.android.databinding.DataBinder import com.android.databinding.writer.DataBinderWriter import com.android.databinding.ClassAnalyzer import com.android.databinding.util.ParserHelper +import com.google.common.base.Preconditions public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Iterable, @@ -97,26 +98,109 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite findXmlFiles(it, xmlFiles) } } - //viewBinderRenderers.clear() + var layoutId = 0 for (xml in xmlFiles) { log("xmlFile $xml") - val layoutBinder = parseAndStripXml(xml, "$appPkg.generated") + val layoutBinder = parseAndStripXml(xml, "$appPkg.generated", layoutId.toString()) if (layoutBinder == null) { log("no bindings in $xml, skipping") continue } + layoutBinder.setId(layoutId) layoutBinder.setProjectPackage("$appPkg"); layoutBinder.setPackage("$appPkg.generated") layoutBinder.setBaseClassName("${ParserHelper.toClassName(xml.name)}Binder") layoutBinder.setLayoutname(toLayoutId(xml.name)) - + layoutBinder.setFile(xml) + layoutId ++ } + validateMultiResFiles() dbr = DataBinderWriter("com.android.databinding.library", appPkg, "GeneratedDataBinderRenderer", jDataBinder.getLayoutBinders()) } + /** + * checks which layout fields are defined in multiple places. Ensures their + * variables do not conflict + */ + public fun validateMultiResFiles() { + jDataBinder.getLayoutBinders() + .filter { it.getValue().size() > 1 } + .forEach { layout -> + // validate all ids are in correct view types + // and all variables have the same name + val variableTypes = hashMapOf() + val importTypes = hashMapOf() + + layout.getValue().forEach { + it.setHasVariations(true) + it.getUserDefinedVariables().forEach { + Preconditions.checkState(variableTypes.getOrPut(it.getKey(), {it.getValue()}).equals(it.getValue()), + "inconsistent variable types for %s for layout %s", it.getKey(), layout.key) + } + it.getUserDefinedImports().forEach { + Preconditions.checkState(importTypes.getOrPut(it.getKey(), {it.getValue()}).equals(it.getValue()), + "inconsistent import types for %s for layout %s", it.getKey(), layout.key) + } + } + // now add missing ones to each to ensure they can be referenced + Log.d { "checking for missing variables in ${layout.getKey()}" } + layout.getValue().forEach { binder -> + // TODO need to remove unused variables while generating the code. + variableTypes.filterNot { binder.getUserDefinedVariables().containsKey(it.key) } + .forEach { + binder.addVariable(it.key, it.value) + Log.d {"adding missing variable ${it.key} / ${it.value} to binder ${binder.getId()}"} + } + importTypes.filterNot { binder.getUserDefinedImports().containsKey(it.key) } + .forEach { + binder.addImport(it.key, it.value) + Log.d {"adding missing import ${it.key} / ${it.value} to binder ${binder.getId()}"} + } + } + val includeBindingIds = hashSetOf() + val viewBindingIds = hashSetOf() + val viewTypes = hashMapOf() + layout.getValue().forEach { + it.getBindingTargets().forEach { + if (it.isBinder()) { + Preconditions.checkState(!viewBindingIds.contains(it.mViewClass), + """Cannot use the same id for a View and an include tag. Error + for layout file ${layout.key}""") + includeBindingIds.add(it.mViewClass) + } else { + Preconditions.checkState(!includeBindingIds.contains(it.mViewClass), + """Cannot use the same id for a View and an include tag. Error + for layout file ${layout.key}""") + viewBindingIds.add(it.mViewClass) + } + if (it.mViewClass != viewTypes.getOrPut(it.getId(), {it.mViewClass})) { + if (it.isBinder()) { + viewTypes.put(it.getId(), "com.android.databinding.library.IViewDataBinder") + } else { + viewTypes.put(it.getId(), "android.view.View") + } + + } + } + } + layout.getValue().forEach { binder -> + viewTypes.forEach { common -> + val target = binder.getBindingTargets().firstOrNull { it.mId == common.key } + if (target == null) { + // undefined, just define + binder.createBindingTarget(common.key, common.value, false) + } else { + // set type + target.setInterfaceType(common.value) + } + } + } + } + } + public fun generatedCode() : Boolean { - return jDataBinder.getLayoutBinders().isNotEmpty() + return jDataBinder.getLayoutBinders().size() > 0 } public fun writeAttrFile() { @@ -127,7 +211,7 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite public fun writeDbrFile() : Unit = writeDbrFile(dbrOutputDir) public fun writeDbrFile(dir : File) : Unit { dir.mkdirs() - if (dbr.layoutBinders.isNotEmpty()) { + if (dbr.layoutBinders.size() > 0) { writeToFile(File(dir, "${dbr.className}.java"), dbr.write()) } } @@ -137,7 +221,7 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite public fun writeViewBinderInterfaces(dir : File) : Unit { dir.mkdirs() jDataBinder.getLayoutBinders().forEach { - writeToFile(File(dir, "${it.getInterfaceName()}.java"), it.writeViewBinderInterface()) + writeToFile(File(dir, "${it.value.first!!.getInterfaceName()}.java"), it.value.first!!.writeViewBinderInterface()) } } @@ -146,7 +230,9 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite public fun writeViewBinders(dir : File) : Unit { dir.mkdirs() jDataBinder.getLayoutBinders().forEach { - writeToFile(File(dir, "${it.getClassName()}.java"), it.writeViewBinder()) + it.getValue().forEach { + writeToFile(File(dir, "${it.getClassName()}.java"), it.writeViewBinder()) + } } } @@ -159,15 +245,15 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite private fun toLayoutId(name:String) : String = name.substring(0, name.indexOf(".")) - private fun stripBindingTags(xml : File) { - val res = XmlEditor.strip(xml) + private fun stripBindingTags(xml : File, newTag : String? = null) { + val res = XmlEditor.strip(xml, newTag) if (res != null) { Log.d{"file ${xml.getName()} has changed, overwriting ${xml.getAbsolutePath()}"} xml.writeText(res) } } - private fun stripFileAndGetOriginal(xml : File) : File? { + private fun stripFileAndGetOriginal(xml : File, binderId : String) : File? { System.out.println("parsing resourceY file ${xml.getAbsolutePath()}") val factory = DocumentBuilderFactory.newInstance() val builder = factory.newDocumentBuilder() @@ -194,14 +280,13 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite val variableNodes = getVariableNodes(doc, xPath) var changed = variableNodes.getLength() > 0 //TODO do we need to check more? if (changed) { - stripBindingTags(xml) + stripBindingTags(xml, binderId) } - return actualFile } - private fun parseAndStripXml(xml : File, pkg : String) : LayoutBinder? { - val original = stripFileAndGetOriginal(xml) + private fun parseAndStripXml(xml : File, pkg : String, binderId : String) : LayoutBinder? { + val original = stripFileAndGetOriginal(xml, binderId) return if (original == null) { null } else { diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/ParserHelper.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/ParserHelper.kt index bb15afcd8db09..e1474b47415f0 100644 --- a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/ParserHelper.kt +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/ParserHelper.kt @@ -17,7 +17,7 @@ object ParserHelper { public fun toClassName(name:String) : String { val dot = name.indexOf(".") val stripped = if (dot == -1) name else name.substring(0, name.indexOf(".")) - return stripped.split("_").map { "${it.substring(0,1).toUpperCase()}${it.substring(1)}" }.join("") + return stripped.split("[_-]").map { "${it.substring(0,1).toUpperCase()}${it.substring(1)}" }.join("") } } \ No newline at end of file diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/XmlEditor.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/XmlEditor.kt index 815108d676750..e57b661075f3e 100644 --- a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/XmlEditor.kt +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/util/XmlEditor.kt @@ -28,6 +28,7 @@ import com.android.databinding.Position import com.android.databinding.toPosition import com.android.databinding.toEndPosition import java.util.Comparator +import com.google.common.base.Preconditions /** * Ugly inefficient class to strip unwanted tags from XML. @@ -35,9 +36,14 @@ import java.util.Comparator */ object XmlEditor { val reservedElementNames = arrayListOf("variable", "import") + var rootNodeContext: XMLParser.ElementContext? = null + var rootNodeHasTag = false val visitor = object : XMLParserBaseVisitor>>() { override fun visitAttribute(ctx: XMLParser.AttributeContext): MutableList>? { - log{"attr:${ctx.attrName.getText()} ${ctx.attrValue.getText()}"} + log { "attr:${ctx.attrName.getText()} ${ctx.attrValue.getText()} . parent: ${ctx.getParent()}" } + if (ctx.getParent() == rootNodeContext && ctx.attrName.getText() == "android:tag") { + rootNodeHasTag = true + } if (ctx.attrName.getText().startsWith("bind:")) { return arrayListOf(Pair(ctx.getStart().toPosition(), ctx.getStop().toEndPosition())) @@ -50,7 +56,10 @@ object XmlEditor { } override fun visitElement(ctx: XMLParser.ElementContext): MutableList>? { - log{"elm ${ctx.elmName.getText()} || ${ctx.Name()}"} + log { "elm ${ctx.elmName.getText()} || ${ctx.Name()} paren : ${ctx.getParent()}" } + if (rootNodeContext == null) { + rootNodeContext = ctx + } if (reservedElementNames.contains(ctx.elmName?.getText()) || ctx.elmName.getText().startsWith("bind:")) { return arrayListOf(Pair(ctx.getStart().toPosition(), ctx.getStop().toEndPosition())) } @@ -60,28 +69,37 @@ object XmlEditor { override fun defaultResult(): MutableList>? = arrayListOf() override fun aggregateResult(aggregate: MutableList>?, nextResult: MutableList>?): MutableList>? = - if (aggregate == null) { - nextResult - } else if (nextResult == null) { - aggregate - } else { - aggregate.addAll(nextResult) - aggregate - } + if (aggregate == null) { + nextResult + } else if (nextResult == null) { + aggregate + } else { + aggregate.addAll(nextResult) + aggregate + } } - fun strip(f : File) : String? { + fun strip(f: File, newTag: String? = null): String? { + rootNodeContext = null //clear it + rootNodeHasTag = false val inputStream = ANTLRInputStream(FileReader(f)) val lexer = XMLLexer(inputStream) val tokenStream = CommonTokenStream(lexer) val parser = XMLParser(tokenStream) val expr = parser.document() val parsedExpr = expr.accept(visitor) - if (parsedExpr.size() == 0) { + if (parsedExpr.isEmpty()) { return null//nothing to strip } + 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()) + + log { "root node bounds: ${rootNodeBounds}" } val out = StringBuilder() val lines = f.readLines("utf-8") + lines.forEach { out.appendln(it) } // TODO we probably don't need to sort @@ -95,22 +113,30 @@ object XmlEditor { } }) var lineStarts = arrayListOf(0) - lines.withIndices().forEach { - if (it.first > 0) { - lineStarts.add(lineStarts[it.first - 1] + lines[it.first - 1].length() + 1) + lines.withIndex().forEach { + if (it.index > 0) { + lineStarts.add(lineStarts[it.index - 1] + lines[it.index - 1].length() + 1) } } - val seperator = System.lineSeparator().charAt(0) + val separator = System.lineSeparator().charAt(0) sorted.forEach { val posStart = lineStarts[it.first.line] + it.first.charIndex val posEnd = lineStarts[it.second.line] + it.second.charIndex - for( i in posStart..(posEnd - 1)) { - if (out.charAt(i) != seperator) { + for ( i in posStart..(posEnd - 1)) { + if (out.charAt(i) != separator) { out.setCharAt(i, ' ') } } } + Log.d{"new tag to set: $newTag"} + if (newTag != null) { + Preconditions.checkState(rootNodeBounds.first.line != rootNodeBounds.second.line, + """The root tag should be multi line to add the tag. ${f.getName()}""") + val line = rootNodeBounds.first.line + out.insert(lineStarts[line] + lines[line].length(), """ android:tag = "$newTag" """) + } + return out.toString() } diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/DataBinderWriter.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/DataBinderWriter.kt index 6f0b2469a1ebd..c3e0ce1353671 100644 --- a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/DataBinderWriter.kt +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/DataBinderWriter.kt @@ -15,7 +15,7 @@ package com.android.databinding.writer import com.android.databinding.LayoutBinder -class DataBinderWriter(val pkg: String, val projectPackage: String, val className: String, val layoutBinders : List ) { +class DataBinderWriter(val pkg: String, val projectPackage: String, val className: String, val layoutBinders : Map> ) { fun write() = kcode("") { tab("package $pkg;") @@ -25,8 +25,23 @@ class DataBinderWriter(val pkg: String, val projectPackage: String, val classNam tab("public com.android.databinding.library.ViewDataBinder getDataBinder(android.view.View view, int layoutId) {") { tab("switch(layoutId) {") { layoutBinders.forEach { - tab("case R.layout.${it.getLayoutname()}:") { - tab("return new ${it.getPackage()}.${it.getClassName()}(view);") + tab("case R.layout.${it.value.first!!.getLayoutname()}:") { + if (it.value.size() == 1) { + tab("return new ${it.value.first!!.getPackage()}.${it.value.first!!.getClassName()}(view);") + } else { + // we should check the tag to decide which layout we need to inflate + tab("{") { + tab("final String tag = (String)view.getTag();") + tab("if(tag == null) throw new java.lang.RuntimeException(\"view must have a tag\");") + it.value.forEach { + // TODO don't use strings. not necessary + tab("if (tag.equals(String.valueOf(${it.getId()}))) {") { + tab("return new ${it.getPackage()}.${it.getClassName()}(view);") + } tab("}") + } + }tab("}") + } + } } } diff --git a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt index 4cd0edf455058..1bf01097cc168 100644 --- a/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt +++ b/tools/data-binding/compiler/src/main/kotlin/com/android/databinding/writer/LayoutBinderWriter.kt @@ -323,34 +323,39 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { model.getExprMap().values().filterIsInstance(javaClass()).filter { it.isVariable() } } - public fun write() : String = - kcode("package ${layoutBinder.getPackage()};") { - nl("import ${layoutBinder.getProjectPackage()}.R;") - nl("import android.view.View;") - nl("public class ${className} extends com.android.databinding.library.ViewDataBinder implements ${interfaceName} {") { - tab(declareViews()) - tab(declareVariables()) - tab(declareConstructor()) - tab(declareInvalidateAll()) - tab(declareLog()) - tab(declareSetVariable()) - tab(variableSettersAndGetters()) - tab(viewGetters()) - tab(onFieldChange()) + val usedVariables by Delegates.lazy { + variables.filter {it.isUsed()} + } - tab(rebindDirty()) + public fun write() : String { + layoutBinder.resolveWhichExpressionsAreUsed() + return kcode("package ${layoutBinder.getPackage()};") { + nl("import ${layoutBinder.getProjectPackage()}.R;") + nl("import android.view.View;") + nl("public class ${className} extends com.android.databinding.library.ViewDataBinder implements ${interfaceName} {") { + tab(declareViews()) + tab(declareVariables()) + tab(declareConstructor()) + tab(declareInvalidateAll()) + tab(declareLog()) + tab(declareSetVariable()) + tab(variableSettersAndGetters()) + tab(viewGetters()) + tab(onFieldChange()) - tab(declareDirtyFlags()) - } - nl("}") - tab(flagMapping()) - tab("//end") - }.generate() + tab(rebindDirty()) + tab(declareDirtyFlags()) + } + nl("}") + tab(flagMapping()) + tab("//end") + }.generate() + } fun declareConstructor() = kcode("") { nl("public ${className}(View root) {") { tab("super(root, ${model.getObservables().size()});") - layoutBinder.getBindingTargets().forEach { + layoutBinder.getBindingTargets().filter{it.isUsed()}.forEach { if (it.isBinder()) { tab("this.${it.fieldName} = com.android.databinding.library.DataBinder.createBinder(root.findViewById(${it.androidId}), R.layout.${it.getIncludedLayout()});") } else { @@ -371,7 +376,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { for (i in (0..(mDirtyFlags.buckets.size() - 1))) { tab("${mDirtyFlags.localValue(i)} = ${fs.localValue(i)};") } - includedBinders.forEach { binder -> + includedBinders.filter{it.isUsed()}.forEach { binder -> tab("${binder.fieldName}.invalidateAll();") } } @@ -381,7 +386,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { fun declareSetVariable() = kcode("") { nl("public boolean setVariable(int variableId, Object variable) {") { tab("switch(variableId) {") { - variables.forEach { + usedVariables.forEach { tab ("case ${it.getName().br()} :") { tab("${it.setterName}((${it.getResolvedType().toJavaCode()}) variable);") tab("return true;") @@ -402,7 +407,18 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { } fun variableSettersAndGetters() = kcode("") { - variables.forEach { + variables.filterNot{it.isUsed()}.forEach { + nl("public void ${it.setterName}(${it.getResolvedType().toJavaCode()} ${it.readableUniqueName}) {") { + tab("// not used, ignore") + } + nl("}") + nl("") + nl("public ${it.getResolvedType().toJavaCode()} ${it.getterName}() {") { + tab("return ${it.getDefaultValue()};") + } + nl("}") + } + usedVariables.forEach { nl("public void ${it.setterName}(${it.getResolvedType().toJavaCode()} ${it.readableUniqueName}) {") { if (it.isObservable()) { tab("updateRegistration(${it.getId()}, ${it.readableUniqueName});"); @@ -472,7 +488,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { } fun declareViews() = kcode("// views") { - layoutBinder.getBindingTargets().forEach { + layoutBinder.getBindingTargets().filter{it.isUsed()}.forEach { nl("private ${it.getViewClass()} ${it.fieldName};") } } @@ -480,15 +496,20 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { fun viewGetters() = kcode("// view getters") { layoutBinder.getBindingTargets().forEach { nl("@Override") - nl("public ${it.getViewClass()} ${it.getterName}() {") { - tab("return ${it.fieldName};") + nl("public ${it.getInterfaceType()} ${it.getterName}() {") { + if (it.isUsed()) { + tab("return ${it.fieldName};") + } else { + tab("return null;") + } + } nl("}") } } fun declareVariables() = kcode("// variables") { - variables.forEach { + usedVariables.forEach { nl("private ${it.getResolvedType().toJavaCode()} ${it.fieldName};") } } @@ -546,7 +567,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { } while(model.markBitsRead()) // - layoutBinder.getBindingTargets() + layoutBinder.getBindingTargets().filter { it.isUsed() } .flatMap { it.getBindings() } .groupBy { it.getExpr() } .forEach { @@ -562,7 +583,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { tab("}") } // - includedBinders.forEach { binder -> + includedBinders.filter{it.isUsed()}.forEach { binder -> tab("${binder.fieldName}.rebindDirty();") } } @@ -649,7 +670,7 @@ class LayoutBinderWriter(val layoutBinder : LayoutBinder) { tab("public void ${it.setterName}(${it.getUserDefinedType()} ${it.readableUniqueName});") } layoutBinder.getBindingTargets().forEach { - tab("public ${it.getViewClass()} ${it.getterName}();") + tab("public ${it.getInterfaceType()} ${it.getterName}();") } nl("}") }.generate() diff --git a/tools/data-binding/gradle/wrapper/gradle-wrapper.properties b/tools/data-binding/gradle/wrapper/gradle-wrapper.properties index a958d904cf77a..e533849fbddd9 100644 --- a/tools/data-binding/gradle/wrapper/gradle-wrapper.properties +++ b/tools/data-binding/gradle/wrapper/gradle-wrapper.properties @@ -1,22 +1,6 @@ -# -# Copyright (C) 2014 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 +#Mon Feb 02 17:44:27 PST 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 +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2-all.zip diff --git a/tools/data-binding/gradlePlugin/build.gradle b/tools/data-binding/gradlePlugin/build.gradle index 30836ddc043d6..a5f1011a21e54 100644 --- a/tools/data-binding/gradlePlugin/build.gradle +++ b/tools/data-binding/gradlePlugin/build.gradle @@ -28,7 +28,7 @@ buildscript { } dependencies { - compile 'com.android.tools.build:gradle:0.14.2' + compile "com.android.tools.build:gradle:$androidPluginVersion" compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" compile gradleApi() compile 'commons-io:commons-io:2.4' diff --git a/tools/data-binding/compiler/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties b/tools/data-binding/gradlePlugin/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties similarity index 100% rename from tools/data-binding/compiler/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties rename to tools/data-binding/gradlePlugin/src/main/resources/META-INF/gradle-plugins/com.android.databinding.properties diff --git a/tools/data-binding/library/build.gradle b/tools/data-binding/library/build.gradle index 779cb85ea0430..e444a43d5ae2b 100644 --- a/tools/data-binding/library/build.gradle +++ b/tools/data-binding/library/build.gradle @@ -23,7 +23,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.0.0' + classpath "com.android.tools.build:gradle:$androidPluginVersion" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/tools/data-binding/samples/BindingDemo/build.gradle b/tools/data-binding/samples/BindingDemo/build.gradle index e4abd4e2cab6f..6dad139f0c9d7 100644 --- a/tools/data-binding/samples/BindingDemo/build.gradle +++ b/tools/data-binding/samples/BindingDemo/build.gradle @@ -23,7 +23,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.0.0' + classpath 'com.android.tools.build:gradle:0.14.2' classpath 'com.android.databinding:dataBinder:0.3-SNAPSHOT' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files