From dba4c94edaf1ee2dc7ef26a236157b6cd23e8dfe Mon Sep 17 00:00:00 2001 From: George Mount Date: Wed, 21 Jan 2015 16:24:43 -0800 Subject: [PATCH] Add resource support in binding expression. Change-Id: Iccb8c3a5856c247d8245fe97a3c37cd60bb7e758 --- .../databinding/ExpressionVisitor.java | 5 + .../com/android/databinding/expr/Expr.java | 2 +- .../android/databinding/expr/ExprModel.java | 4 + .../databinding/expr/ResourceExpr.java | 189 ++++++++++++++++++ .../databinding/store/SetterStore.java | 15 -- .../databinding/writer/LayoutBinderWriter.kt | 4 + .../grammerBuilder/BindingExpression.g4 | 14 +- .../binding/adapters/ViewBindingAdapter.java | 5 - 8 files changed, 210 insertions(+), 28 deletions(-) create mode 100644 tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ResourceExpr.java diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/ExpressionVisitor.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/ExpressionVisitor.java index ce603e52e56ca..dbc6f550fd200 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/ExpressionVisitor.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/ExpressionVisitor.java @@ -143,6 +143,11 @@ public class ExpressionVisitor extends BindingExpressionBaseVisitor { return mModel.math(ctx.left.accept(this), ctx.op.getText(), ctx.right.accept(this)); } + @Override + public Expr visitResource(@NotNull BindingExpressionParser.ResourceContext ctx) { + return mModel.resourceExpr(ctx.getText()); + } + // @Override // public Expr visitIdentifier(@NotNull BindingExpressionParser.IdentifierContext ctx) { // final String identifier = ctx.Identifier().getText(); 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 88eef3931cd14..d68124bc19e5c 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 @@ -124,7 +124,7 @@ abstract public class Expr { private BitSet resolveInvalidFlags() { BitSet bitSet = new BitSet(); - if (mCanBeInvalidated) { + if (mCanBeInvalidated || getDependants().isEmpty()) { bitSet.set(getId(), true); } for (Dependency dependency : getDependencies()) { diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ExprModel.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ExprModel.java index ea7bbc7a533ef..bfe04e51c3784 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ExprModel.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ExprModel.java @@ -142,6 +142,10 @@ public class ExprModel { return register(new GroupExpr(grouped)); } + public Expr resourceExpr(String resourceText) { + return register(new ResourceExpr(resourceText)); + } + public List getBindingExpressions() { return mBindingExpressions; } diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ResourceExpr.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ResourceExpr.java new file mode 100644 index 0000000000000..80cbbf5ab9d3f --- /dev/null +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/expr/ResourceExpr.java @@ -0,0 +1,189 @@ +/* + * 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.expr; + +import com.google.common.collect.ImmutableMap; + +import com.android.databinding.ClassAnalyzer; + +import java.io.IOException; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +public class ResourceExpr extends Expr { + + private final static Map RESOURCE_TYPE_TO_R_OBJECT = + ImmutableMap.builder() + .put("colorStateList", "color ") + .put("dimenOffset", "dimen ") + .put("dimenSize", "dimen ") + .put("intArray", "array ") + .put("stateListAnimator", "animator ") + .put("stringArray", "array ") + .put("typedArray", "array") + .build(); + + private final String mPackage; + + private final String mResourceType; + + private final String mResourceId; + + public ResourceExpr(String resourceText) { + int colonIndex = resourceText.indexOf(':'); + int slashIndex = resourceText.indexOf('/'); + mResourceType = resourceText.substring(colonIndex + 1, slashIndex).trim(); + mResourceId = resourceText.substring(slashIndex + 1).trim(); + String packageName = ""; + if (colonIndex > 1) { + if ("android".equals(resourceText.substring(1, colonIndex).trim())) { + packageName = "android."; + } else { + packageName = ""; + } + } + mPackage = packageName; + } + + @Override + protected Class resolveType(ClassAnalyzer classAnalyzer) { + String type; + switch (mResourceType) { + case "anim": + type = "android.view.animation.Animation"; + break; + case "animator": + type = "android.animation.Animator"; + break; + case "bool": + return boolean.class; + case "color": + return int.class; + case "colorStateList": + type = "android.content.res.ColorStateList"; + break; + case "dimen": + return float.class; + case "dimenOffset": + return int.class; + case "dimenSize": + return int.class; + case "drawable": + type = "android.graphics.drawable.Drawable"; + break; + case "fraction": + return float.class; + case "id": + return int.class; + case "intArray": + return int[].class; + case "integer": + return int.class; + case "interpolator": + type = ""; + break; + case "layout": + return int.class; + case "plurals": + return int.class; + case "stateListAnimator": + type = "android.animation.StateListAnimator"; + break; + case "string": + return String.class; + case "stringArray": + return String[].class; + case "transition": + type = "android.transition.Transition"; + break; + case "typedArray": + type = "android.content.res.TypedArray"; + break; + default: + type = mResourceType; + break; + } + return classAnalyzer.findClass(type); + } + + @Override + protected List constructDependencies() { + return Collections.emptyList(); + } + + @Override + protected String computeUniqueKey() { + if (mPackage == null) { + return "@" + mResourceType + "/" + mResourceId; + } else { + return "@" + "android:" + mResourceType + "/" + mResourceId; + } + } + + @Override + public boolean isDynamic() { + return false; + } + + @Override + public boolean canBeInvalidated() { + return false; + } + + public String toJava() { + final String context = "mRoot.getContext()"; + final String resources = context + ".getResources()"; + final String resourceName = mPackage + "R." + getResourceObject() + "." + mResourceId; + switch (mResourceType) { + case "anim": return "android.view.animation.AnimationUtils.loadAnimation(" + context + ", " + resourceName + ")"; + case "animator": return "android.animation.AnimatorInflater.loadAnimator(" + context + ", " + resourceName + ")"; + case "bool": return resources + ".getBoolean(" + resourceName + ")"; + case "color": return resources + ".getColor(" + resourceName + ")"; + case "colorStateList": return resources + ".getColorStateList(" + resourceName + ")"; + case "dimen": return resources + ".getDimension(" + resourceName + ")"; + case "dimenOffset": return resources + ".getDimensionPixelOffset(" + resourceName + ")"; + case "dimenSize": return resources + ".getDimensionPixelSize(" + resourceName + ")"; + case "drawable": return resources + ".getDrawable(" + resourceName + ")"; + case "fraction": return resources + ".getFraction(" + resourceName + ", 1, 1)"; + case "id": return resourceName; + case "intArray": return resources + ".getIntArray(" + resourceName + ")"; + case "integer": return resources + ".getInteger(" + resourceName + ")"; + case "interpolator": return "android.view.animation.AnimationUtils.loadInterpolator(" + context + ", " + resourceName + ")"; + case "layout": return resourceName; + case "plurals": return resourceName; + case "stateListAnimator": return "android.animation.AnimatorInflater.loadStateListAnimator(" + context + ", " + resourceName + ")"; + case "string": return resources + ".getString(" + resourceName + ")"; + case "stringArray": return resources + ".getStringArray(" + resourceName + ")"; + case "transition": return "android.transition.TransitionInflater.from(" + context + ").inflateTransition(" + resourceName + ")"; + case "typedArray": return resources + ".obtainTypedArray(" + resourceName + ")"; + } + final String property = Character.toUpperCase(mResourceType.charAt(0)) + + mResourceType.substring(1); + return resources + ".get" + property + "(" + resourceName + ")"; + + } + + private String getResourceObject() { + String rFileObject = RESOURCE_TYPE_TO_R_OBJECT.get(mResourceType); + if (rFileObject == null) { + rFileObject = mResourceType; + } + return rFileObject; + } +} diff --git a/tools/data-binding/compiler/src/main/java/com/android/databinding/store/SetterStore.java b/tools/data-binding/compiler/src/main/java/com/android/databinding/store/SetterStore.java index 0cab80cde74ae..b41e7e16c0890 100644 --- a/tools/data-binding/compiler/src/main/java/com/android/databinding/store/SetterStore.java +++ b/tools/data-binding/compiler/src/main/java/com/android/databinding/store/SetterStore.java @@ -16,7 +16,6 @@ package com.android.databinding.store; import com.android.databinding.ClassAnalyzer; -import com.android.databinding.util.L; import java.io.File; import java.io.IOException; @@ -318,8 +317,6 @@ public class SetterStore { public String getSetterCall(String attribute, Class viewType, Class valueType, String viewExpression, String valueExpression) { - L.d("getting setter call for %s %s %s %s %s", attribute, viewType, valueType, - viewExpression, valueExpression); if (!attribute.startsWith("android:")) { int colon = attribute.indexOf(':'); if (colon >= 0) { @@ -327,11 +324,9 @@ public class SetterStore { } } ArrayList adapters = mAdaptedMethods.get(attribute); - L.d("returned adapter count %d", adapters == null ? -1 : adapters.size()); AdaptedMethod adapter = null; String setterName = null; Method bestSetterMethod = getBestSetter(viewType, valueType, attribute); - L.d("setter method: %s", bestSetterMethod == null ? "null" : bestSetterMethod.getName()); Class bestViewType = null; Class bestValueType = null; if (bestSetterMethod != null) { @@ -342,7 +337,6 @@ public class SetterStore { if (adapters != null) { for (AdaptedMethod adaptedMethod : adapters) { - L.d("checking adapter method %s", adaptedMethod); if (adaptedMethod.viewType.isAssignableFrom(viewType)) { boolean isBetterView = bestViewType == null || bestValueType.isAssignableFrom(adaptedMethod.valueType); @@ -351,12 +345,7 @@ public class SetterStore { bestViewType = adaptedMethod.viewType; bestValueType = adaptedMethod.valueType; adapter = adaptedMethod; - L.d("chosen %s", adaptedMethod); - } else { - L.d("not better"); } - } else { - L.d("not assignable"); } } } @@ -469,16 +458,12 @@ public class SetterStore { } private ConversionMethod getConversionMethod(Class from, Class to) { - System.out.println("Getting conversion from " + from + " to " + to); if (from != null && to != null) { for (ConversionMethod conversion : mConversionMethods) { - System.out.println("Testing " + conversion.fromType + " to " + conversion.toType); if (canUseForConversion(from, conversion.fromType) && canUseForConversion(conversion.toType, to)) { - System.out.println("Yes!"); return conversion; } - System.out.println("Nope!"); } } return null; 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 e72c2aef3f240..4dfc85fdcecd0 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 @@ -43,6 +43,7 @@ import com.android.databinding.ext.lazy import com.android.databinding.ext.br import com.android.databinding.ext.toJavaCode import com.android.databinding.ext.isObservable +import com.android.databinding.expr.ResourceExpr fun Expr.isObservable() = com.android.databinding.ClassAnalyzer.getInstance().isObservable(this.getResolvedType()) @@ -190,6 +191,9 @@ fun Expr.toCode(full : Boolean = false) : KCode { app("?", it.getIfTrue().toCode()) app(":", it.getIfFalse().toCode()) } + is ResourceExpr -> kcode("") { + app("", it.toJava()) + } else -> kcode("//NOT IMPLEMENTED YET") } diff --git a/tools/data-binding/grammerBuilder/BindingExpression.g4 b/tools/data-binding/grammerBuilder/BindingExpression.g4 index e647895a7a826..85d7631a22a25 100644 --- a/tools/data-binding/grammerBuilder/BindingExpression.g4 +++ b/tools/data-binding/grammerBuilder/BindingExpression.g4 @@ -445,25 +445,25 @@ fragment ResourceType : 'anim' | 'animator' - | 'array' - | 'attr' | 'bool' | 'color' + | 'colorStateList' | 'dimen' + | 'dimenOffset' + | 'dimenSize' | 'drawable' | 'fraction' | 'id' | 'integer' + | 'intArray' | 'interpolator' | 'layout' - | 'menu' - | 'mipmap' | 'plurals' - | 'raw' + | 'stateListAnimator' | 'string' - | 'style' + | 'stringArray' | 'transition' - | 'xml' + | 'typedArray' ; ResourceName diff --git a/tools/data-binding/library/src/main/java/android/binding/adapters/ViewBindingAdapter.java b/tools/data-binding/library/src/main/java/android/binding/adapters/ViewBindingAdapter.java index 01ec43c536ce2..7333abedc31fb 100644 --- a/tools/data-binding/library/src/main/java/android/binding/adapters/ViewBindingAdapter.java +++ b/tools/data-binding/library/src/main/java/android/binding/adapters/ViewBindingAdapter.java @@ -39,11 +39,6 @@ import android.view.View; }) public class ViewBindingAdapter { - @BindingAdapter("android:background") - public static void setBackground(View view, int color) { - view.setBackgroundColor(color); - } - @BindingAdapter("android:padding") public static void setPadding(View view, int padding) { view.setPadding(padding, padding, padding, padding);