blob: df36cf63e787cad1bcab4c1ef655b2f299cc1743 [file] [log] [blame]
/*
* 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.expr;
import android.databinding.tool.BindingTarget;
import android.databinding.tool.reflection.ModelAnalyzer;
import android.databinding.tool.reflection.ModelClass;
import android.databinding.tool.writer.KCode;
import android.databinding.tool.writer.LayoutBinderWriterKt;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ResourceExpr extends Expr {
private final static Map<String, String> RESOURCE_TYPE_TO_R_OBJECT;
static {
RESOURCE_TYPE_TO_R_OBJECT = new HashMap<String, String>();
RESOURCE_TYPE_TO_R_OBJECT.put("colorStateList", "color ");
RESOURCE_TYPE_TO_R_OBJECT.put("dimenOffset", "dimen ");
RESOURCE_TYPE_TO_R_OBJECT.put("dimenSize", "dimen ");
RESOURCE_TYPE_TO_R_OBJECT.put("intArray", "array ");
RESOURCE_TYPE_TO_R_OBJECT.put("stateListAnimator", "animator ");
RESOURCE_TYPE_TO_R_OBJECT.put("stringArray", "array ");
RESOURCE_TYPE_TO_R_OBJECT.put("typedArray", "array");
}
// lazily initialized
private Map<String, ModelClass> mResourceToTypeMapping;
protected final String mPackage;
protected final String mResourceType;
protected final String mResourceId;
protected final BindingTarget mTarget;
public ResourceExpr(BindingTarget target, String packageName, String resourceType,
String resourceName, List<Expr> args) {
super(args);
mTarget = target;
if ("android".equals(packageName)) {
mPackage = "android.";
} else {
mPackage = "";
}
mResourceType = resourceType;
mResourceId = resourceName;
}
private Map<String, ModelClass> getResourceToTypeMapping(ModelAnalyzer modelAnalyzer) {
if (mResourceToTypeMapping == null) {
final Map<String, String> imports = getModel().getImports();
mResourceToTypeMapping = new HashMap<String, ModelClass>();
mResourceToTypeMapping.put("anim", modelAnalyzer.findClass("android.view.animation.Animation",
imports));
mResourceToTypeMapping.put("animator", modelAnalyzer.findClass("android.animation.Animator",
imports));
mResourceToTypeMapping.put("colorStateList",
modelAnalyzer.findClass("android.content.res.ColorStateList",
imports));
mResourceToTypeMapping.put("drawable", modelAnalyzer.findClass("android.graphics.drawable.Drawable",
imports));
mResourceToTypeMapping.put("stateListAnimator",
modelAnalyzer.findClass("android.animation.StateListAnimator",
imports));
mResourceToTypeMapping.put("transition", modelAnalyzer.findClass("android.transition.Transition",
imports));
mResourceToTypeMapping.put("typedArray", modelAnalyzer.findClass("android.content.res.TypedArray",
imports));
mResourceToTypeMapping.put("interpolator",
modelAnalyzer.findClass("android.view.animation.Interpolator", imports));
mResourceToTypeMapping.put("bool", modelAnalyzer.findClass(boolean.class));
mResourceToTypeMapping.put("color", modelAnalyzer.findClass(int.class));
mResourceToTypeMapping.put("dimenOffset", modelAnalyzer.findClass(int.class));
mResourceToTypeMapping.put("dimenSize", modelAnalyzer.findClass(int.class));
mResourceToTypeMapping.put("id", modelAnalyzer.findClass(int.class));
mResourceToTypeMapping.put("integer", modelAnalyzer.findClass(int.class));
mResourceToTypeMapping.put("layout", modelAnalyzer.findClass(int.class));
mResourceToTypeMapping.put("dimen", modelAnalyzer.findClass(float.class));
mResourceToTypeMapping.put("fraction", modelAnalyzer.findClass(float.class));
mResourceToTypeMapping.put("intArray", modelAnalyzer.findClass(int[].class));
mResourceToTypeMapping.put("string", modelAnalyzer.findClass(String.class));
mResourceToTypeMapping.put("stringArray", modelAnalyzer.findClass(String[].class));
}
return mResourceToTypeMapping;
}
@Override
protected ModelClass resolveType(ModelAnalyzer modelAnalyzer) {
final Map<String, ModelClass> mapping = getResourceToTypeMapping(
modelAnalyzer);
final ModelClass modelClass = mapping.get(mResourceType);
if (modelClass != null) {
return modelClass;
}
if ("plurals".equals(mResourceType)) {
if (getChildren().isEmpty()) {
return modelAnalyzer.findClass(int.class);
} else {
return modelAnalyzer.findClass(String.class);
}
}
return modelAnalyzer.findClass(mResourceType, getModel().getImports());
}
@Override
protected List<Dependency> constructDependencies() {
return constructDynamicChildrenDependencies();
}
@Override
protected String computeUniqueKey() {
String base = toString();
String view = "";
if (requiresView()) {
view = LayoutBinderWriterKt.getFieldName(mTarget);
}
return join(base, view, computeChildrenKey());
}
@Override
protected KCode generateCode() {
return new KCode(toJava());
}
@Override
public Expr cloneToModel(ExprModel model) {
String pkg = mPackage.isEmpty() ? "" : "android";
return model.resourceExpr(mTarget, pkg, mResourceType, mResourceId,
cloneToModel(model, getChildren()));
}
public String getResourceId() {
return mPackage + "R." + getResourceObject() + "." + mResourceId;
}
@Override
public String getInvertibleError() {
return "Resources may not be the target of a two-way binding expression: " +
computeUniqueKey();
}
private boolean requiresView() {
return !mTarget.isBinder() && !("anim".equals(mResourceType) ||
"animator".equals(mResourceType) ||
"id".equals(mResourceType) ||
"interpolator".equals(mResourceType) ||
"layout".equals(mResourceType) ||
"stateListAnimator".equals(mResourceType) ||
"transition".equals(mResourceType));
}
public String toJava() {
final String context = "getRoot().getContext()";
final String viewName = requiresView() ? LayoutBinderWriterKt.getFieldName(mTarget) :
"getRoot()";
final String resources = viewName + ".getResources()";
final String resourceName = mPackage + "R." + getResourceObject() + "." + mResourceId;
if ("anim".equals(mResourceType)) return "android.view.animation.AnimationUtils.loadAnimation(" + context + ", " + resourceName + ")";
if ("animator".equals(mResourceType)) return "android.animation.AnimatorInflater.loadAnimator(" + context + ", " + resourceName + ")";
if ("bool".equals(mResourceType)) return resources + ".getBoolean(" + resourceName + ")";
if ("color".equals(mResourceType)) return "android.databinding.DynamicUtil.getColorFromResource(" + viewName + ", " + resourceName + ")";
if ("colorStateList".equals(mResourceType)) return "android.databinding.DynamicUtil.getColorStateListFromResource(" + viewName + ", " + resourceName + ")";
if ("dimen".equals(mResourceType)) return resources + ".getDimension(" + resourceName + ")";
if ("dimenOffset".equals(mResourceType)) return resources + ".getDimensionPixelOffset(" + resourceName + ")";
if ("dimenSize".equals(mResourceType)) return resources + ".getDimensionPixelSize(" + resourceName + ")";
if ("drawable".equals(mResourceType)) return "android.databinding.DynamicUtil.getDrawableFromResource(" + viewName + ", " + resourceName + ")";
if ("fraction".equals(mResourceType)) {
String base = getChildCode(0, "1");
String pbase = getChildCode(1, "1");
return resources + ".getFraction(" + resourceName + ", " + base + ", " + pbase +
")";
}
if ("id".equals(mResourceType)) return resourceName;
if ("intArray".equals(mResourceType)) return resources + ".getIntArray(" + resourceName + ")";
if ("integer".equals(mResourceType)) return resources + ".getInteger(" + resourceName + ")";
if ("interpolator".equals(mResourceType)) return "android.view.animation.AnimationUtils.loadInterpolator(" + context + ", " + resourceName + ")";
if ("layout".equals(mResourceType)) return resourceName;
if ("plurals".equals(mResourceType)) {
if (getChildren().isEmpty()) {
return resourceName;
} else {
return makeParameterCall(resources, resourceName, "getQuantityString");
}
}
if ("stateListAnimator".equals(mResourceType)) return "android.animation.AnimatorInflater.loadStateListAnimator(" + context + ", " + resourceName + ")";
if ("string".equals(mResourceType)) return makeParameterCall(resources, resourceName, "getString");
if ("stringArray".equals(mResourceType)) return resources + ".getStringArray(" + resourceName + ")";
if ("transition".equals(mResourceType)) return "android.transition.TransitionInflater.from(" + context + ").inflateTransition(" + resourceName + ")";
if ("typedArray".equals(mResourceType)) return resources + ".obtainTypedArray(" + resourceName + ")";
final String property = Character.toUpperCase(mResourceType.charAt(0)) +
mResourceType.substring(1);
return resources + ".get" + property + "(" + resourceName + ")";
}
private String getChildCode(int childIndex, String defaultValue) {
if (getChildren().size() <= childIndex) {
return defaultValue;
} else {
return getChildren().get(childIndex).toCode().generate();
}
}
private String makeParameterCall(String resources, String resourceName, String methodCall) {
StringBuilder sb = new StringBuilder(resources);
sb.append('.').append(methodCall).append("(").append(resourceName);
for (Expr expr : getChildren()) {
sb.append(", ").append(expr.toCode().generate());
}
sb.append(")");
return sb.toString();
}
private String getResourceObject() {
String rFileObject = RESOURCE_TYPE_TO_R_OBJECT.get(mResourceType);
if (rFileObject == null) {
rFileObject = mResourceType;
}
return rFileObject;
}
@Override
public String toString() {
if (mPackage == null) {
return "@" + mResourceType + "/" + mResourceId;
} else {
return "@" + "android:" + mResourceType + "/" + mResourceId;
}
}
}