Add resource support in binding expression.

Change-Id: Iccb8c3a5856c247d8245fe97a3c37cd60bb7e758
This commit is contained in:
George Mount
2015-01-21 16:24:43 -08:00
parent 3ab81f694f
commit dba4c94eda
8 changed files with 210 additions and 28 deletions

View File

@@ -143,6 +143,11 @@ public class ExpressionVisitor extends BindingExpressionBaseVisitor<Expr> {
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();

View File

@@ -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()) {

View File

@@ -142,6 +142,10 @@ public class ExprModel {
return register(new GroupExpr(grouped));
}
public Expr resourceExpr(String resourceText) {
return register(new ResourceExpr(resourceText));
}
public List<Expr> getBindingExpressions() {
return mBindingExpressions;
}

View File

@@ -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<String, String> RESOURCE_TYPE_TO_R_OBJECT =
ImmutableMap.<String, String>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<Dependency> 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;
}
}

View File

@@ -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<AdaptedMethod> 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;

View File

@@ -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")
}

View File

@@ -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

View File

@@ -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);