Added implementations of BindingAdapters.
Added renaming attribute-to-setter and automatic Conversions. Moved intermediate store (SetterStore) to compiler project. Moved annotations to their own project.
This commit is contained in:
@@ -36,11 +36,16 @@ sourceSets {
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(":annotations")
|
||||
compile project(":compiler")
|
||||
}
|
||||
|
||||
uploadArchives {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
repository(url: mavenLocal().url)
|
||||
pom.version = '0.1-SNAPSHOT'
|
||||
pom.version = '0.3-SNAPSHOT'
|
||||
pom.artifactId = 'annotationprocessor'
|
||||
pom.groupId='com.android.databinding'
|
||||
}
|
||||
|
||||
@@ -1,336 +0,0 @@
|
||||
/*
|
||||
* 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.annotationprocessor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
public class BindingAdapterStore {
|
||||
private static final BindingAdapterStore sStore = load();
|
||||
private final HashMap<String, HashMap<AccessorKey, BindingAdapterDescription>> mAdapters;
|
||||
|
||||
private BindingAdapterStore(Object adapters) {
|
||||
if (adapters == null) {
|
||||
mAdapters = new HashMap<>();
|
||||
} else {
|
||||
mAdapters = (HashMap<String, HashMap<AccessorKey, BindingAdapterDescription>>) adapters;
|
||||
}
|
||||
}
|
||||
|
||||
public static BindingAdapterStore get() {
|
||||
return sStore;
|
||||
}
|
||||
|
||||
private static BindingAdapterStore load() {
|
||||
Object adapters = null;
|
||||
File outputFile = getOutputFile();
|
||||
if (outputFile.exists()) {
|
||||
try {
|
||||
ObjectInputStream in = new ObjectInputStream(new FileInputStream(outputFile));
|
||||
adapters = in.readObject();
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Could not read BindingAdapter intermediate file: " +
|
||||
e.getLocalizedMessage());
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("Could not read BindingAdapter intermediate file: " +
|
||||
e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
return new BindingAdapterStore(adapters);
|
||||
}
|
||||
|
||||
public void add(String attribute, TypeMirror viewType, TypeMirror valueType,
|
||||
TypeElement bindingAdapterType, ExecutableElement bindingMethod) {
|
||||
HashMap<AccessorKey, BindingAdapterDescription> adapters = mAdapters.get(attribute);
|
||||
|
||||
if (adapters == null) {
|
||||
adapters = new HashMap<>();
|
||||
mAdapters.put(attribute, adapters);
|
||||
}
|
||||
String view = viewType.toString();
|
||||
String value = valueType.toString();
|
||||
|
||||
AccessorKey key = new AccessorKey(view, value);
|
||||
if (adapters.containsKey(key)) {
|
||||
throw new IllegalArgumentException("Already exists!");
|
||||
}
|
||||
|
||||
String type = bindingAdapterType.getQualifiedName().toString();
|
||||
String method = bindingMethod.getSimpleName().toString();
|
||||
adapters.put(key, new BindingAdapterDescription(type, method));
|
||||
}
|
||||
|
||||
public void clear(TypeElement bindingAdapter) {
|
||||
String className = bindingAdapter.getQualifiedName().toString();
|
||||
ArrayList<AccessorKey> removed = new ArrayList<>();
|
||||
for (HashMap<AccessorKey, BindingAdapterDescription> adapters : mAdapters.values()) {
|
||||
for (AccessorKey key : adapters.keySet()) {
|
||||
BindingAdapterDescription description = adapters.get(key);
|
||||
if (description.type.equals(className)) {
|
||||
removed.add(key);
|
||||
}
|
||||
}
|
||||
for (AccessorKey key : removed) {
|
||||
adapters.remove(key);
|
||||
}
|
||||
removed.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void write() throws IOException {
|
||||
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(getOutputFile()));
|
||||
out.writeObject(mAdapters);
|
||||
out.close();
|
||||
}
|
||||
|
||||
private static File getOutputFile() {
|
||||
File dir = new File(new File("build"),"intermediates");
|
||||
dir.mkdirs();
|
||||
return new File(dir, "binding_adapters.bin");
|
||||
}
|
||||
|
||||
public String getSetterCall(String attribute, Class<?> viewType, Class<?> valueType,
|
||||
String viewExpression, String valueExpression, ClassLoader classLoader) {
|
||||
HashMap<AccessorKey, BindingAdapterDescription> adapters = mAdapters.get(attribute);
|
||||
|
||||
BindingAdapterDescription adapter = null;
|
||||
System.out.println("adapters for " + attribute + " are " + adapters);
|
||||
if (adapters != null) {
|
||||
Class<?> bestViewType = null;
|
||||
Class<?> bestValueType = null;
|
||||
boolean bestTypeEquals = false;
|
||||
boolean bestTypeIsBoxed = false;
|
||||
int bestTypeImplicitConversion = Integer.MAX_VALUE;
|
||||
|
||||
for (AccessorKey key : adapters.keySet()) {
|
||||
try {
|
||||
Class<?> keyView = loadClass(key.viewType, classLoader);
|
||||
Class<?> keyValue = loadClass(key.valueType, classLoader);
|
||||
if (!keyView.isAssignableFrom(viewType)) {
|
||||
System.out.println("View type is wrong: " + keyView + " is not assignable from " + viewType);
|
||||
}
|
||||
if (keyView.isAssignableFrom(viewType)) {
|
||||
boolean isBetterView = bestViewType == null ||
|
||||
bestValueType.isAssignableFrom(keyView);
|
||||
System.out.println("View type is right: " + keyView + " is better? " + isBetterView);
|
||||
boolean isBetterValueType;
|
||||
// Right view type. Check the value
|
||||
if (!isBetterView && bestTypeEquals) {
|
||||
System.out.println("best type is already equal");
|
||||
isBetterValueType = false;
|
||||
} else if (valueType.equals(keyValue)) {
|
||||
// Exact match
|
||||
isBetterValueType = true;
|
||||
bestTypeEquals = true;
|
||||
System.out.println("new type equals");
|
||||
} else if (!isBetterView && bestTypeIsBoxed) {
|
||||
isBetterValueType = false;
|
||||
} else if (isBoxingConversion(keyValue, valueType)) {
|
||||
// Boxing/unboxing is second best
|
||||
isBetterValueType = true;
|
||||
bestTypeIsBoxed = true;
|
||||
} else if (isImplicitConversion(valueType, keyValue)) {
|
||||
// Better implicit conversion
|
||||
int conversionLevel = getConversionLevel(keyValue);
|
||||
isBetterValueType = conversionLevel < bestTypeImplicitConversion;
|
||||
if (isBetterValueType) {
|
||||
bestTypeImplicitConversion = conversionLevel;
|
||||
}
|
||||
} else if (bestTypeImplicitConversion < Integer.MAX_VALUE) {
|
||||
isBetterValueType = false;
|
||||
} else if (keyValue.isAssignableFrom(valueType)) {
|
||||
// Right type, see if it is better than the current best match.
|
||||
if (bestValueType == null) {
|
||||
isBetterValueType = true;
|
||||
} else {
|
||||
isBetterValueType = bestValueType.isAssignableFrom(keyValue);
|
||||
}
|
||||
} else {
|
||||
isBetterValueType = false;
|
||||
}
|
||||
if (isBetterValueType) {
|
||||
bestViewType = keyView;
|
||||
bestValueType = keyValue;
|
||||
adapter = adapters.get(key);
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (adapter == null) {
|
||||
int colonIndex = attribute.indexOf(':');
|
||||
String propertyName;
|
||||
if (colonIndex >= 0 && colonIndex + 1 < attribute.length()) {
|
||||
propertyName = Character.toUpperCase(attribute.charAt(colonIndex + 1)) +
|
||||
attribute.substring(colonIndex + 2);
|
||||
} else {
|
||||
propertyName = "";
|
||||
}
|
||||
return viewExpression + ".set" + propertyName + "(" + valueExpression + ")";
|
||||
} else {
|
||||
return adapter.type + "." + adapter.method + "(" + viewExpression + ", " +
|
||||
valueExpression + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isImplicitConversion(Class<?> from, Class<?> to) {
|
||||
if (from != null && to != null && from.isPrimitive() && to.isPrimitive()) {
|
||||
if (from.equals(boolean.class) || to.equals(boolean.class) ||
|
||||
to.equals(char.class)) {
|
||||
return false;
|
||||
}
|
||||
int fromConversionLevel = getConversionLevel(from);
|
||||
int toConversionLevel = getConversionLevel(to);
|
||||
return fromConversionLevel < toConversionLevel;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getConversionLevel(Class<?> primitive) {
|
||||
if (byte.class.equals(primitive)) {
|
||||
return 0;
|
||||
} else if (char.class.equals(primitive)) {
|
||||
return 1;
|
||||
} else if (short.class.equals(primitive)) {
|
||||
return 2;
|
||||
} else if (int.class.equals(primitive)) {
|
||||
return 3;
|
||||
} else if (long.class.equals(primitive)) {
|
||||
return 4;
|
||||
} else if (float.class.equals(primitive)) {
|
||||
return 5;
|
||||
} else if (double.class.equals(primitive)) {
|
||||
return 6;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isBoxingConversion(Class<?> class1, Class<?> class2) {
|
||||
if (class1.isPrimitive() != class2.isPrimitive()) {
|
||||
return (getWrappedType(class1).equals(getWrappedType(class2)));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> getWrappedType(Class<?> type) {
|
||||
if (!type.isPrimitive()) {
|
||||
return type;
|
||||
}
|
||||
if (int.class.equals(type)) {
|
||||
return Integer.class;
|
||||
} else if (long.class.equals(type)) {
|
||||
return Long.class;
|
||||
} else if (short.class.equals(type)) {
|
||||
return Short.class;
|
||||
} else if (byte.class.equals(type)) {
|
||||
return Byte.class;
|
||||
} else if (char.class.equals(type)) {
|
||||
return Character.class;
|
||||
} else if (double.class.equals(type)) {
|
||||
return Double.class;
|
||||
} else if (float.class.equals(type)) {
|
||||
return Float.class;
|
||||
} else if (boolean.class.equals(type)) {
|
||||
return Boolean.class;
|
||||
} else {
|
||||
// what type is this?
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> loadClass(String className, ClassLoader classLoader)
|
||||
throws ClassNotFoundException {
|
||||
switch (className) {
|
||||
case "long": return long.class;
|
||||
case "int": return int.class;
|
||||
case "short": return short.class;
|
||||
case "byte": return byte.class;
|
||||
case "char": return char.class;
|
||||
case "float": return float.class;
|
||||
case "double": return double.class;
|
||||
case "boolean": return boolean.class;
|
||||
default: return Class.forName(className, false, classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
private static class BindingAdapterDescription implements Serializable {
|
||||
public final String type;
|
||||
public final String method;
|
||||
|
||||
public BindingAdapterDescription(String type, String method) {
|
||||
this.type = type;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof BindingAdapterDescription) {
|
||||
BindingAdapterDescription that = (BindingAdapterDescription) obj;
|
||||
return that.type.equals(this.type) && that.method.equals(this.method);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, method);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AccessorKey implements Serializable {
|
||||
public final String viewType;
|
||||
public final String valueType;
|
||||
|
||||
public AccessorKey(String viewType, String valueType) {
|
||||
this.viewType = viewType;
|
||||
this.valueType = valueType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(viewType, valueType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof AccessorKey) {
|
||||
AccessorKey that = (AccessorKey) obj;
|
||||
return viewType.equals(that.valueType) && valueType.equals(that.valueType);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,6 @@ package com.android.databinding.annotationprocessor;
|
||||
import android.binding.Bindable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
@@ -15,7 +13,6 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
@@ -27,7 +24,9 @@ import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
@SupportedAnnotationTypes({"android.binding.Bindable"})
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_7)
|
||||
@@ -168,18 +167,28 @@ public class ProcessBindable extends AbstractProcessor {
|
||||
|
||||
private HashSet<String> readIntermediateFile() {
|
||||
HashSet<String> properties = null;
|
||||
File intermediate = getIntermediateFile();
|
||||
if (intermediate.exists()) {
|
||||
try {
|
||||
ObjectInputStream in = new ObjectInputStream(new FileInputStream(intermediate));
|
||||
ObjectInputStream in = null;
|
||||
try {
|
||||
FileObject intermediate = processingEnv.getFiler()
|
||||
.getResource(StandardLocation.CLASS_OUTPUT,
|
||||
ProcessBindable.class.getPackage().getName(), "binding_properties.bin");
|
||||
if (new File(intermediate.getName()).exists()) {
|
||||
in = new ObjectInputStream(intermediate.openInputStream());
|
||||
properties = (HashSet<String>) in.readObject();
|
||||
in.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("Could not read Binding properties intermediate file: " +
|
||||
e.getLocalizedMessage());
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("Could not read Binding properties intermediate file: " +
|
||||
e.getLocalizedMessage());
|
||||
} finally {
|
||||
try {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.err.println("Could not read Binding properties intermediate file: " +
|
||||
e.getLocalizedMessage());
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("Could not read Binding properties intermediate file: " +
|
||||
e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (properties == null) {
|
||||
@@ -190,8 +199,10 @@ public class ProcessBindable extends AbstractProcessor {
|
||||
|
||||
private void writeIntermediateFile(HashSet<String> properties) {
|
||||
try {
|
||||
File intermediate = getIntermediateFile();
|
||||
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(intermediate));
|
||||
FileObject intermediate = processingEnv.getFiler().createResource(
|
||||
StandardLocation.CLASS_OUTPUT, ProcessBindable.class.getPackage().getName(),
|
||||
"binding_properties.bin");
|
||||
ObjectOutputStream out = new ObjectOutputStream(intermediate.openOutputStream());
|
||||
out.writeObject(properties);
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
@@ -199,10 +210,4 @@ public class ProcessBindable extends AbstractProcessor {
|
||||
"Could not write to intermediate file: " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static File getIntermediateFile() {
|
||||
File dir = new File(new File("build"),"intermediates");
|
||||
dir.mkdirs();
|
||||
return new File(dir, "binding_properties.bin");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* 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.annotationprocessor;
|
||||
|
||||
import android.binding.BindingAdapter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
@SupportedAnnotationTypes({"android.binding.BindingAdapter"})
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_7)
|
||||
public class ProcessBindingAdapters extends AbstractProcessor {
|
||||
private boolean mProcessed;
|
||||
|
||||
public ProcessBindingAdapters() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if (mProcessed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
BindingAdapterStore store = BindingAdapterStore.get();
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(BindingAdapter.class)) {
|
||||
TypeElement containingClass = (TypeElement) element.getEnclosingElement();
|
||||
store.clear(containingClass);
|
||||
}
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(BindingAdapter.class)) {
|
||||
if (element.getKind() != ElementKind.METHOD ||
|
||||
!element.getModifiers().contains(Modifier.STATIC)) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"@BindingAdapter on invalid element: " + element);
|
||||
continue;
|
||||
}
|
||||
BindingAdapter bindingAdapter = element.getAnnotation(BindingAdapter.class);
|
||||
|
||||
ExecutableElement executableElement = (ExecutableElement) element;
|
||||
List<? extends VariableElement> parameters = executableElement.getParameters();
|
||||
if (parameters.size() != 2) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"@BindingAdapter does not take two parameters: " + element);
|
||||
continue;
|
||||
}
|
||||
TypeElement containingClass = (TypeElement) executableElement.getEnclosingElement();
|
||||
try {
|
||||
store.add(bindingAdapter.attribute(), parameters.get(0).asType(),
|
||||
parameters.get(1).asType(), containingClass, executableElement);
|
||||
} catch (IllegalArgumentException e) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"@BindingAdapter for duplicate View and parameter type: " + element);
|
||||
}
|
||||
}
|
||||
try {
|
||||
store.write();
|
||||
} catch (IOException e) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"Could not write BindingAdapter intermediate file: " + e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
mProcessed = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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.annotationprocessor;
|
||||
|
||||
import android.binding.BindingAdapter;
|
||||
import android.binding.BindingConversion;
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
import com.android.databinding.store.SetterStore;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import javax.tools.Diagnostic;
|
||||
|
||||
@SupportedAnnotationTypes({
|
||||
"android.binding.BindingAdapter",
|
||||
"android.binding.BindingMethods",
|
||||
"android.binding.BindingConversion"})
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_7)
|
||||
public class ProcessMethodAdapters extends AbstractProcessor {
|
||||
private boolean mProcessed;
|
||||
|
||||
public ProcessMethodAdapters() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
if (mProcessed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SetterStore store = SetterStore.get(processingEnv);
|
||||
clearIncrementalClasses(roundEnv, store);
|
||||
|
||||
addBindingAdapters(roundEnv, store);
|
||||
addRenamed(roundEnv, store);
|
||||
addConversions(roundEnv, store);
|
||||
try {
|
||||
store.write(processingEnv);
|
||||
} catch (IOException e) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"Could not write BindingAdapter intermediate file: " + e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
mProcessed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addBindingAdapters(RoundEnvironment roundEnv, SetterStore store) {
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(BindingAdapter.class)) {
|
||||
if (element.getKind() != ElementKind.METHOD ||
|
||||
!element.getModifiers().contains(Modifier.STATIC) ||
|
||||
!element.getModifiers().contains(Modifier.PUBLIC)) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"@BindingAdapter on invalid element: " + element);
|
||||
continue;
|
||||
}
|
||||
BindingAdapter bindingAdapter = element.getAnnotation(BindingAdapter.class);
|
||||
|
||||
ExecutableElement executableElement = (ExecutableElement) element;
|
||||
List<? extends VariableElement> parameters = executableElement.getParameters();
|
||||
if (parameters.size() != 2) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"@BindingAdapter does not take two parameters: " + element);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
|
||||
"------------------ @BindingAdapter for " + element);
|
||||
store.addBindingAdapter(bindingAdapter.value(), executableElement);
|
||||
} catch (IllegalArgumentException e) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"@BindingAdapter for duplicate View and parameter type: " + element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addRenamed(RoundEnvironment roundEnv, SetterStore store) {
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(BindingMethods.class)) {
|
||||
BindingMethods bindingMethods = element.getAnnotation(BindingMethods.class);
|
||||
for (BindingMethod bindingMethod : bindingMethods.value()) {
|
||||
store.addRenamedMethod(bindingMethod.attribute(),
|
||||
bindingMethod.type(), bindingMethod.method(), (TypeElement) element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addConversions(RoundEnvironment roundEnv, SetterStore store) {
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(BindingConversion.class)) {
|
||||
if (element.getKind() != ElementKind.METHOD ||
|
||||
!element.getModifiers().contains(Modifier.STATIC) ||
|
||||
!element.getModifiers().contains(Modifier.PUBLIC)) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"@BindingConversion is only allowed on public static methods: " + element);
|
||||
continue;
|
||||
}
|
||||
|
||||
ExecutableElement executableElement = (ExecutableElement) element;
|
||||
if (executableElement.getParameters().size() != 1) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"@BindingConversion method should have one parameter: " + element);
|
||||
continue;
|
||||
}
|
||||
if (executableElement.getReturnType().getKind() == TypeKind.VOID) {
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
|
||||
"@BindingConversion method must return a value: " + element);
|
||||
continue;
|
||||
}
|
||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE,
|
||||
"added conversion: " + element);
|
||||
store.addConversionMethod(executableElement);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearIncrementalClasses(RoundEnvironment roundEnv, SetterStore store) {
|
||||
HashSet<String> classes = new HashSet<>();
|
||||
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(BindingAdapter.class)) {
|
||||
TypeElement containingClass = (TypeElement) element.getEnclosingElement();
|
||||
classes.add(containingClass.getQualifiedName().toString());
|
||||
}
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(BindingMethods.class)) {
|
||||
classes.add(((TypeElement) element).getQualifiedName().toString());
|
||||
}
|
||||
for (Element element : roundEnv.getElementsAnnotatedWith(BindingConversion.class)) {
|
||||
classes.add(((TypeElement) element.getEnclosingElement()).getQualifiedName().toString());
|
||||
}
|
||||
store.clear(classes);
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,2 @@
|
||||
com.android.databinding.annotationprocessor.ProcessBindable
|
||||
com.android.databinding.annotationprocessor.ProcessBindingAdapters
|
||||
com.android.databinding.annotationprocessor.ProcessMethodAdapters
|
||||
48
tools/data-binding/annotations/build.gradle
Normal file
48
tools/data-binding/annotations/build.gradle
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir 'src/main/java'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uploadArchives {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
repository(url: mavenLocal().url)
|
||||
pom.version = '0.3-SNAPSHOT'
|
||||
pom.artifactId = 'annotations'
|
||||
pom.groupId='com.android.databinding'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,5 +20,5 @@ import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface BindingAdapter {
|
||||
String attribute();
|
||||
String value();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.binding;
|
||||
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.METHOD})
|
||||
public @interface BindingConversion {
|
||||
}
|
||||
@@ -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 android.binding;
|
||||
|
||||
/**
|
||||
* Created by mount on 1/12/15.
|
||||
*/
|
||||
public @interface BindingMethod {
|
||||
String type();
|
||||
String attribute();
|
||||
String method();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.binding;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.TYPE})
|
||||
public @interface BindingMethods {
|
||||
BindingMethod[] value();
|
||||
}
|
||||
@@ -32,10 +32,9 @@ buildscript {
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||
compile project(":annotations")
|
||||
compile project(":grammerBuilder")
|
||||
compile project(":xmlGrammer")
|
||||
compile "com.android.databinding:annotationprocessor:0.1-SNAPSHOT"
|
||||
//compile project(":annotationprocessor")
|
||||
}
|
||||
uploadArchives {
|
||||
repositories {
|
||||
|
||||
@@ -0,0 +1,750 @@
|
||||
/*
|
||||
* 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.store;
|
||||
|
||||
import com.android.databinding.util.ClassAnalyzer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import javax.annotation.processing.Filer;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.ArrayType;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.FileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
|
||||
import sun.net.www.protocol.jar.URLJarFile;
|
||||
|
||||
public class SetterStore {
|
||||
|
||||
private static SetterStore sStore;
|
||||
|
||||
private final HashMap<String, HashMap<AccessorKey, MethodDescription>> mAdapters;
|
||||
|
||||
private final HashMap<String, HashMap<String, MethodDescription>> mRenamed;
|
||||
|
||||
private final HashMap<String, HashMap<String, MethodDescription>> mConversions;
|
||||
|
||||
private ArrayList<ConversionMethod> mConversionMethods;
|
||||
|
||||
private HashMap<String, ArrayList<AdaptedMethod>> mAdaptedMethods;
|
||||
|
||||
private HashMap<String, ArrayList<RenamedMethod>> mRenamedMethods;
|
||||
|
||||
private SetterStore(HashMap<String, HashMap<AccessorKey, MethodDescription>> adapters,
|
||||
HashMap<String, HashMap<String, MethodDescription>> renamedMethods,
|
||||
HashMap<String, HashMap<String, MethodDescription>> conversionMethods) {
|
||||
if (adapters == null || renamedMethods == null || conversionMethods == null) {
|
||||
mAdapters = new HashMap<>();
|
||||
mRenamed = new HashMap<>();
|
||||
mConversions = new HashMap<>();
|
||||
} else {
|
||||
mAdapters = adapters;
|
||||
mRenamed = renamedMethods;
|
||||
mConversions = conversionMethods;
|
||||
}
|
||||
}
|
||||
|
||||
public static SetterStore get(ProcessingEnvironment processingEnvironment) {
|
||||
if (sStore == null) {
|
||||
InputStream in = null;
|
||||
try {
|
||||
Filer filer = processingEnvironment.getFiler();
|
||||
FileObject resource = filer.getResource(StandardLocation.CLASS_OUTPUT,
|
||||
SetterStore.class.getPackage().getName(), "setter_store.bin");
|
||||
if (resource != null && new File(resource.getName()).exists()) {
|
||||
in = resource.openInputStream();
|
||||
if (in != null) {
|
||||
sStore = load(in);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sStore == null) {
|
||||
HashMap<String, HashMap<AccessorKey, MethodDescription>> adapters = new HashMap<>();
|
||||
HashMap<String, HashMap<String, MethodDescription>> renamed = new HashMap<>();
|
||||
HashMap<String, HashMap<String, MethodDescription>> conversions = new HashMap<>();
|
||||
sStore = new SetterStore(adapters, renamed, conversions);
|
||||
}
|
||||
}
|
||||
return sStore;
|
||||
}
|
||||
|
||||
public static SetterStore get(ClassAnalyzer classAnalyzer) {
|
||||
if (sStore == null) {
|
||||
sStore = load(classAnalyzer);
|
||||
sStore.applyReflections(classAnalyzer);
|
||||
}
|
||||
return sStore;
|
||||
}
|
||||
|
||||
private static SetterStore load(ClassAnalyzer classAnalyzer) {
|
||||
HashMap<String, HashMap<AccessorKey, MethodDescription>> adapters = new HashMap<>();
|
||||
HashMap<String, HashMap<String, MethodDescription>> renamedMethods = new HashMap<>();
|
||||
HashMap<String, HashMap<String, MethodDescription>> conversionMethods = new HashMap<>();
|
||||
String resourceName = SetterStore.class.getPackage().getName().replace('.', '/') +
|
||||
"/setter_store.bin";
|
||||
try {
|
||||
Enumeration<URL> resources = classAnalyzer.getClassLoader().getResources(resourceName);
|
||||
while (resources.hasMoreElements()) {
|
||||
URL resource = resources.nextElement();
|
||||
merge(adapters, renamedMethods, conversionMethods, resource);
|
||||
}
|
||||
return new SetterStore(adapters, renamedMethods, conversionMethods);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Could not read SetterStore intermediate file: " +
|
||||
e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
} catch (ClassNotFoundException e) {
|
||||
System.err.println("Could not read SetterStore intermediate file: " +
|
||||
e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
return new SetterStore(adapters, renamedMethods, conversionMethods);
|
||||
}
|
||||
|
||||
private static SetterStore load(InputStream inputStream)
|
||||
throws IOException, ClassNotFoundException {
|
||||
ObjectInputStream in = new ObjectInputStream(inputStream);
|
||||
HashMap<String, HashMap<AccessorKey, MethodDescription>> adapters
|
||||
= (HashMap<String, HashMap<AccessorKey, MethodDescription>>) in.readObject();
|
||||
HashMap<String, HashMap<String, MethodDescription>> renamedMethods
|
||||
= (HashMap<String, HashMap<String, MethodDescription>>) in.readObject();
|
||||
HashMap<String, HashMap<String, MethodDescription>> conversionMethods
|
||||
= (HashMap<String, HashMap<String, MethodDescription>>) in.readObject();
|
||||
return new SetterStore(adapters, renamedMethods, conversionMethods);
|
||||
}
|
||||
|
||||
public void addRenamedMethod(String attribute, String declaringClass, String method,
|
||||
TypeElement declaredOn) {
|
||||
HashMap<String, MethodDescription> renamed = mRenamed.get(attribute);
|
||||
if (renamed == null) {
|
||||
renamed = new HashMap<>();
|
||||
mRenamed.put(attribute, renamed);
|
||||
}
|
||||
MethodDescription methodDescription =
|
||||
new MethodDescription(declaredOn.getQualifiedName().toString(), method);
|
||||
renamed.put(declaringClass, methodDescription);
|
||||
}
|
||||
|
||||
public void addBindingAdapter(String attribute, ExecutableElement bindingMethod) {
|
||||
HashMap<AccessorKey, MethodDescription> adapters = mAdapters.get(attribute);
|
||||
|
||||
if (adapters == null) {
|
||||
adapters = new HashMap<>();
|
||||
mAdapters.put(attribute, adapters);
|
||||
}
|
||||
List<? extends VariableElement> parameters = bindingMethod.getParameters();
|
||||
String view = getQualifiedName(parameters.get(0).asType());
|
||||
String value = getQualifiedName(parameters.get(1).asType());
|
||||
|
||||
AccessorKey key = new AccessorKey(view, value);
|
||||
if (adapters.containsKey(key)) {
|
||||
throw new IllegalArgumentException("Already exists!");
|
||||
}
|
||||
|
||||
adapters.put(key, new MethodDescription(bindingMethod));
|
||||
}
|
||||
|
||||
private static String getQualifiedName(TypeMirror type) {
|
||||
switch (type.getKind()) {
|
||||
case BOOLEAN:
|
||||
case BYTE:
|
||||
case SHORT:
|
||||
case INT:
|
||||
case LONG:
|
||||
case CHAR:
|
||||
case FLOAT:
|
||||
case DOUBLE:
|
||||
case VOID:
|
||||
return type.toString();
|
||||
case ARRAY:
|
||||
return "[" + getArrayType(((ArrayType) type).getComponentType());
|
||||
case DECLARED:
|
||||
return ((TypeElement) ((DeclaredType) type).asElement()).getQualifiedName()
|
||||
.toString();
|
||||
default:
|
||||
return "-- no type --";
|
||||
}
|
||||
}
|
||||
|
||||
private static String getArrayType(TypeMirror type) {
|
||||
switch (type.getKind()) {
|
||||
case BOOLEAN:
|
||||
return "Z";
|
||||
case BYTE:
|
||||
return "B";
|
||||
case SHORT:
|
||||
return "S";
|
||||
case INT:
|
||||
return "I";
|
||||
case LONG:
|
||||
return "J";
|
||||
case CHAR:
|
||||
return "C";
|
||||
case FLOAT:
|
||||
return "F";
|
||||
case DOUBLE:
|
||||
return "D";
|
||||
case ARRAY:
|
||||
return "[" + getArrayType(((ArrayType) type).getComponentType());
|
||||
case DECLARED:
|
||||
return "L" + ((TypeElement) ((DeclaredType) type).asElement()).getQualifiedName()
|
||||
.toString() + ";";
|
||||
}
|
||||
return "-- no type --";
|
||||
}
|
||||
|
||||
public void addConversionMethod(ExecutableElement conversionMethod) {
|
||||
List<? extends VariableElement> parameters = conversionMethod.getParameters();
|
||||
String fromType = getQualifiedName(parameters.get(0).asType());
|
||||
String toType = getQualifiedName(conversionMethod.getReturnType());
|
||||
MethodDescription methodDescription = new MethodDescription(conversionMethod);
|
||||
HashMap<String, MethodDescription> convertTo = mConversions.get(fromType);
|
||||
if (convertTo == null) {
|
||||
convertTo = new HashMap<>();
|
||||
mConversions.put(fromType, convertTo);
|
||||
}
|
||||
convertTo.put(toType, methodDescription);
|
||||
}
|
||||
|
||||
public void clear(Set<String> classes) {
|
||||
ArrayList<AccessorKey> removedAccessorKeys = new ArrayList<>();
|
||||
for (HashMap<AccessorKey, MethodDescription> adapters : mAdapters.values()) {
|
||||
for (AccessorKey key : adapters.keySet()) {
|
||||
MethodDescription description = adapters.get(key);
|
||||
if (classes.contains(description.type)) {
|
||||
removedAccessorKeys.add(key);
|
||||
}
|
||||
}
|
||||
for (AccessorKey key : removedAccessorKeys) {
|
||||
adapters.remove(key);
|
||||
}
|
||||
removedAccessorKeys.clear();
|
||||
}
|
||||
|
||||
ArrayList<String> removedRenamed = new ArrayList<>();
|
||||
for (HashMap<String, MethodDescription> renamed : mRenamed.values()) {
|
||||
for (String key : renamed.keySet()) {
|
||||
if (classes.contains(renamed.get(key).type)) {
|
||||
removedRenamed.add(key);
|
||||
}
|
||||
}
|
||||
for (String key : removedRenamed) {
|
||||
renamed.remove(key);
|
||||
}
|
||||
removedRenamed.clear();
|
||||
}
|
||||
|
||||
ArrayList<String> removedConversions = new ArrayList<>();
|
||||
for (HashMap<String, MethodDescription> convertTos : mConversions.values()) {
|
||||
for (String toType : convertTos.keySet()) {
|
||||
MethodDescription methodDescription = convertTos.get(toType);
|
||||
if (classes.contains(methodDescription.type)) {
|
||||
removedConversions.add(toType);
|
||||
}
|
||||
}
|
||||
for (String key : removedConversions) {
|
||||
convertTos.remove(key);
|
||||
}
|
||||
removedConversions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void write(ProcessingEnvironment processingEnvironment) throws IOException {
|
||||
Filer filer = processingEnvironment.getFiler();
|
||||
FileObject resource = filer.createResource(StandardLocation.CLASS_OUTPUT,
|
||||
SetterStore.class.getPackage().getName(), "setter_store.bin");
|
||||
processingEnvironment.getMessager().printMessage(Diagnostic.Kind.NOTE,
|
||||
"============= Writing intermediate file: " + resource.getName());
|
||||
ObjectOutputStream out = null;
|
||||
try {
|
||||
out = new ObjectOutputStream(resource.openOutputStream());
|
||||
|
||||
processingEnvironment.getMessager().printMessage(Diagnostic.Kind.NOTE,
|
||||
"============= adapters: " + mAdapters);
|
||||
out.writeObject(mAdapters);
|
||||
out.writeObject(mRenamed);
|
||||
out.writeObject(mConversions);
|
||||
} finally {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getSetterCall(String attribute, Class<?> viewType, Class<?> valueType,
|
||||
String viewExpression, String valueExpression) {
|
||||
ArrayList<AdaptedMethod> adapters = mAdaptedMethods.get(attribute);
|
||||
|
||||
AdaptedMethod adapter = null;
|
||||
String setterName = null;
|
||||
Method bestSetterMethod = getBestSetter(viewType, valueType, attribute);
|
||||
Class<?> bestViewType = null;
|
||||
Class<?> bestValueType = null;
|
||||
if (bestSetterMethod != null) {
|
||||
bestViewType = bestSetterMethod.getDeclaringClass();
|
||||
bestValueType = bestSetterMethod.getParameterTypes()[0];
|
||||
setterName = bestSetterMethod.getName();
|
||||
}
|
||||
|
||||
if (adapters != null) {
|
||||
for (AdaptedMethod adaptedMethod : adapters) {
|
||||
if (adaptedMethod.viewType.isAssignableFrom(viewType)) {
|
||||
boolean isBetterView = bestViewType == null ||
|
||||
bestValueType.isAssignableFrom(adaptedMethod.valueType);
|
||||
if (isBetterParameter(valueType, adaptedMethod.valueType, bestValueType,
|
||||
isBetterView)) {
|
||||
bestViewType = adaptedMethod.viewType;
|
||||
bestValueType = adaptedMethod.valueType;
|
||||
adapter = adaptedMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConversionMethod conversionMethod = getConversionMethod(valueType, bestValueType);
|
||||
if (conversionMethod != null) {
|
||||
valueExpression = conversionMethod.type + "." + conversionMethod.method + "(" +
|
||||
valueExpression + ")";
|
||||
}
|
||||
if (adapter == null) {
|
||||
if (setterName == null) {
|
||||
setterName = getDefaultSetter(attribute);
|
||||
}
|
||||
return viewExpression + "." + setterName + "(" + valueExpression + ")";
|
||||
} else {
|
||||
return adapter.type + "." + adapter.method + "(" + viewExpression + ", " +
|
||||
valueExpression + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private Method getBestSetter(Class<?> viewType, Class<?> argumentType, String attribute) {
|
||||
String setterName = null;
|
||||
|
||||
ArrayList<RenamedMethod> renamed = mRenamedMethods.get(attribute);
|
||||
if (renamed != null) {
|
||||
for (RenamedMethod renamedMethod : renamed) {
|
||||
if (renamedMethod.viewType.isAssignableFrom(viewType)) {
|
||||
setterName = renamedMethod.method;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (setterName == null) {
|
||||
setterName = getDefaultSetter(attribute);
|
||||
}
|
||||
Method[] methods = viewType.getMethods();
|
||||
|
||||
Class<?> bestParameterType = null;
|
||||
Method bestMethod = null;
|
||||
for (Method method : methods) {
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
if (parameterTypes.length == 1 && setterName.equals(method.getName()) &&
|
||||
void.class.equals(method.getReturnType()) &&
|
||||
!Modifier.isStatic(method.getModifiers()) &&
|
||||
Modifier.isPublic(method.getModifiers())) {
|
||||
Class<?> param = parameterTypes[0];
|
||||
if (isBetterParameter(argumentType, param, bestParameterType, true)) {
|
||||
bestParameterType = param;
|
||||
bestMethod = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestMethod;
|
||||
}
|
||||
|
||||
private static String getDefaultSetter(String attribute) {
|
||||
int colonIndex = attribute.indexOf(':');
|
||||
String propertyName;
|
||||
if (colonIndex >= 0 && colonIndex + 1 < attribute.length()) {
|
||||
propertyName = Character.toUpperCase(attribute.charAt(colonIndex + 1)) +
|
||||
attribute.substring(colonIndex + 2);
|
||||
} else {
|
||||
propertyName = "";
|
||||
}
|
||||
return "set" + propertyName;
|
||||
}
|
||||
|
||||
private boolean isBetterParameter(Class<?> argument, Class<?> parameter,
|
||||
Class<?> oldParameter, boolean isBetterViewTypeMatch) {
|
||||
// Right view type. Check the value
|
||||
if (!isBetterViewTypeMatch && oldParameter.equals(argument)) {
|
||||
return false;
|
||||
} else if (argument.equals(parameter)) {
|
||||
// Exact match
|
||||
return true;
|
||||
} else if (!isBetterViewTypeMatch && isBoxingConversion(oldParameter, argument)) {
|
||||
return false;
|
||||
} else if (isBoxingConversion(parameter, argument)) {
|
||||
// Boxing/unboxing is second best
|
||||
return true;
|
||||
} else {
|
||||
int oldConversionLevel = getConversionLevel(oldParameter);
|
||||
if (isImplicitConversion(argument, parameter)) {
|
||||
// Better implicit conversion
|
||||
int conversionLevel = getConversionLevel(parameter);
|
||||
return oldConversionLevel < 0 || conversionLevel < oldConversionLevel;
|
||||
} else if (oldConversionLevel >= 0) {
|
||||
return false;
|
||||
} else if (parameter.isAssignableFrom(argument)) {
|
||||
// Right type, see if it is better than the current best match.
|
||||
if (oldParameter == null) {
|
||||
return true;
|
||||
} else {
|
||||
return oldParameter.isAssignableFrom(parameter);
|
||||
}
|
||||
} else {
|
||||
return getConversionMethod(argument, parameter) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isImplicitConversion(Class<?> from, Class<?> to) {
|
||||
if (from != null && to != null && from.isPrimitive() && to.isPrimitive()) {
|
||||
if (from.equals(boolean.class) || to.equals(boolean.class) ||
|
||||
to.equals(char.class)) {
|
||||
return false;
|
||||
}
|
||||
int fromConversionLevel = getConversionLevel(from);
|
||||
int toConversionLevel = getConversionLevel(to);
|
||||
return fromConversionLevel < toConversionLevel;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private static boolean canUseForConversion(Class<?> from, Class<?> to) {
|
||||
return from.equals(to) || isBoxingConversion(from, to) || to.isAssignableFrom(from);
|
||||
}
|
||||
|
||||
private static int getConversionLevel(Class<?> primitive) {
|
||||
if (byte.class.equals(primitive)) {
|
||||
return 0;
|
||||
} else if (char.class.equals(primitive)) {
|
||||
return 1;
|
||||
} else if (short.class.equals(primitive)) {
|
||||
return 2;
|
||||
} else if (int.class.equals(primitive)) {
|
||||
return 3;
|
||||
} else if (long.class.equals(primitive)) {
|
||||
return 4;
|
||||
} else if (float.class.equals(primitive)) {
|
||||
return 5;
|
||||
} else if (double.class.equals(primitive)) {
|
||||
return 6;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isBoxingConversion(Class<?> class1, Class<?> class2) {
|
||||
if (class1.isPrimitive() != class2.isPrimitive()) {
|
||||
return (getWrappedType(class1).equals(getWrappedType(class2)));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> getWrappedType(Class<?> type) {
|
||||
if (!type.isPrimitive()) {
|
||||
return type;
|
||||
}
|
||||
if (int.class.equals(type)) {
|
||||
return Integer.class;
|
||||
} else if (long.class.equals(type)) {
|
||||
return Long.class;
|
||||
} else if (short.class.equals(type)) {
|
||||
return Short.class;
|
||||
} else if (byte.class.equals(type)) {
|
||||
return Byte.class;
|
||||
} else if (char.class.equals(type)) {
|
||||
return Character.class;
|
||||
} else if (double.class.equals(type)) {
|
||||
return Double.class;
|
||||
} else if (float.class.equals(type)) {
|
||||
return Float.class;
|
||||
} else if (boolean.class.equals(type)) {
|
||||
return Boolean.class;
|
||||
} else {
|
||||
// what type is this?
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
private static void merge(HashMap<String, HashMap<AccessorKey, MethodDescription>> adapters,
|
||||
HashMap<String, HashMap<String, MethodDescription>> renamed,
|
||||
HashMap<String, HashMap<String, MethodDescription>> conversions,
|
||||
URL nextUrl) throws IOException, ClassNotFoundException {
|
||||
InputStream inputStream = null;
|
||||
JarFile jarFile = null;
|
||||
try {
|
||||
System.out.println("merging " + nextUrl);
|
||||
inputStream = nextUrl.openStream();
|
||||
ObjectInputStream in = new ObjectInputStream(inputStream);
|
||||
HashMap<String, HashMap<AccessorKey, MethodDescription>> adapters2 =
|
||||
(HashMap<String, HashMap<AccessorKey, MethodDescription>>) in.readObject();
|
||||
merge(adapters, adapters2);
|
||||
HashMap<String, HashMap<String, MethodDescription>> renamed2 =
|
||||
(HashMap<String, HashMap<String, MethodDescription>>) in.readObject();
|
||||
merge(renamed, renamed2);
|
||||
HashMap<String, HashMap<String, MethodDescription>> conversions2 =
|
||||
(HashMap<String, HashMap<String, MethodDescription>>) in.readObject();
|
||||
merge(conversions, conversions2);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
if (jarFile != null) {
|
||||
jarFile.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <K, V> void merge(HashMap<K, HashMap<V, MethodDescription>> first,
|
||||
HashMap<K, HashMap<V, MethodDescription>> second) {
|
||||
for (K key : second.keySet()) {
|
||||
HashMap<V, MethodDescription> firstVals = first.get(key);
|
||||
HashMap<V, MethodDescription> secondVals = second.get(key);
|
||||
if (firstVals == null) {
|
||||
first.put(key, secondVals);
|
||||
} else {
|
||||
for (V key2 : secondVals.keySet()) {
|
||||
if (!firstVals.containsKey(key2)) {
|
||||
firstVals.put(key2, secondVals.get(key2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyReflections(ClassAnalyzer classAnalyzer) {
|
||||
if (mConversionMethods == null) {
|
||||
mConversionMethods = new ArrayList<>();
|
||||
for (String key : mConversions.keySet()) {
|
||||
Class<?> fromType = classAnalyzer.loadClass(key);
|
||||
HashMap<String, MethodDescription> conversion = mConversions.get(key);
|
||||
for (String toName : conversion.keySet()) {
|
||||
Class<?> toType = classAnalyzer.loadClass(toName);
|
||||
MethodDescription methodDescription = conversion.get(toName);
|
||||
mConversionMethods
|
||||
.add(new ConversionMethod(fromType, toType, methodDescription));
|
||||
}
|
||||
}
|
||||
|
||||
mAdaptedMethods = new HashMap<>();
|
||||
for (String attribute : mAdapters.keySet()) {
|
||||
ArrayList<AdaptedMethod> adaptedMethods = new ArrayList<>();
|
||||
mAdaptedMethods.put(attribute, adaptedMethods);
|
||||
HashMap<AccessorKey, MethodDescription> adapted = mAdapters.get(attribute);
|
||||
for (AccessorKey key : adapted.keySet()) {
|
||||
MethodDescription methodDescription = adapted.get(key);
|
||||
Class<?> viewType = classAnalyzer.loadClass(key.viewType);
|
||||
Class<?> valueType = classAnalyzer.loadClass(key.valueType);
|
||||
adaptedMethods.add(new AdaptedMethod(viewType, valueType,
|
||||
methodDescription));
|
||||
}
|
||||
}
|
||||
|
||||
mRenamedMethods = new HashMap<>();
|
||||
for (String attribute : mRenamed.keySet()) {
|
||||
ArrayList<RenamedMethod> renamedMethods = new ArrayList<>();
|
||||
mRenamedMethods.put(attribute, renamedMethods);
|
||||
HashMap<String, MethodDescription> renamed = mRenamed.get(attribute);
|
||||
for (String declaredClassName : renamed.keySet()) {
|
||||
MethodDescription methodDescription = renamed.get(declaredClassName);
|
||||
Class<?> viewType = classAnalyzer.loadClass(declaredClassName);
|
||||
renamedMethods.add(new RenamedMethod(viewType, methodDescription.method));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class MethodDescription implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
public final String type;
|
||||
|
||||
public final String method;
|
||||
|
||||
public MethodDescription(String type, String method) {
|
||||
this.type = type;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public MethodDescription(ExecutableElement method) {
|
||||
TypeElement enclosingClass = (TypeElement) method.getEnclosingElement();
|
||||
this.type = enclosingClass.getQualifiedName().toString();
|
||||
this.method = method.getSimpleName().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof MethodDescription) {
|
||||
MethodDescription that = (MethodDescription) obj;
|
||||
return that.type.equals(this.type) && that.method.equals(this.method);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type + "." + method + "()";
|
||||
}
|
||||
}
|
||||
|
||||
private static class AccessorKey implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
public final String viewType;
|
||||
|
||||
public final String valueType;
|
||||
|
||||
public AccessorKey(String viewType, String valueType) {
|
||||
this.viewType = viewType;
|
||||
this.valueType = valueType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(viewType, valueType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof AccessorKey) {
|
||||
AccessorKey that = (AccessorKey) obj;
|
||||
return viewType.equals(that.valueType) && valueType.equals(that.valueType);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AK(" + viewType + ", " + valueType + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConversionMethod {
|
||||
|
||||
public final Class<?> fromType;
|
||||
|
||||
public final Class<?> toType;
|
||||
|
||||
public final String type;
|
||||
|
||||
public final String method;
|
||||
|
||||
public ConversionMethod(Class<?> fromType, Class<?> toType, MethodDescription method) {
|
||||
this.fromType = fromType;
|
||||
this.toType = toType;
|
||||
this.type = method.type;
|
||||
this.method = method.method;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AdaptedMethod {
|
||||
|
||||
public final Class<?> viewType;
|
||||
|
||||
public final Class<?> valueType;
|
||||
|
||||
public final String type;
|
||||
|
||||
public final String method;
|
||||
|
||||
public AdaptedMethod(Class<?> viewType, Class<?> valueType, MethodDescription method) {
|
||||
this.viewType = viewType;
|
||||
this.valueType = valueType;
|
||||
this.type = method.type;
|
||||
this.method = method.method;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RenamedMethod {
|
||||
|
||||
public final Class<?> viewType;
|
||||
|
||||
public final String method;
|
||||
|
||||
public RenamedMethod(Class<?> viewType, String method) {
|
||||
this.viewType = viewType;
|
||||
this.method = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,22 +146,42 @@ class ClassAnalyzer(val classLoader : URLClassLoader) {
|
||||
}
|
||||
|
||||
fun loadClass(klassName : String) : Class<*> {
|
||||
var loaded = loadedClasses[klassName] ?: loadPrimitive(klassName)
|
||||
if (loaded == null) {
|
||||
loaded = loadRecursively(klassName)
|
||||
System.out.println("loaded ${loaded}")
|
||||
loaded!!.getInterfaces().forEach {
|
||||
System.out.println("interfaces ${it}")
|
||||
when (klassName) {
|
||||
"int" -> return javaClass<kotlin.Int>()
|
||||
"short" -> return javaClass<kotlin.Short>()
|
||||
"long" -> return javaClass<kotlin.Long>()
|
||||
"float" -> return javaClass<kotlin.Float>()
|
||||
"double" -> return javaClass<kotlin.Double>()
|
||||
"boolean" -> return javaClass<kotlin.Boolean>()
|
||||
"char" -> return javaClass<kotlin.Char>()
|
||||
else -> {
|
||||
var loaded = loadedClasses[klassName] ?: loadPrimitive(klassName)
|
||||
if (loaded == null) {
|
||||
if (klassName.startsWith("[") && klassName.contains("L")) {
|
||||
val indexOfL = klassName.indexOf('L');
|
||||
val baseClass = loadClass(klassName.substring(indexOfL + 1, klassName.length() - 1));
|
||||
val realClassName = klassName.substring(0, indexOfL + 1) +
|
||||
baseClass.getCanonicalName() + ';'
|
||||
loaded = Class.forName(realClassName, false, classLoader);
|
||||
loadedClasses.put(klassName, loaded)
|
||||
} else {
|
||||
loaded = loadRecursively(klassName)
|
||||
System.out.println("loaded ${loaded}")
|
||||
loaded!!.getInterfaces().forEach {
|
||||
System.out.println("interfaces ${it}")
|
||||
}
|
||||
loadedClasses.put(klassName, loaded)
|
||||
}
|
||||
}
|
||||
return loaded!!
|
||||
}
|
||||
loadedClasses.put(klassName, loaded)
|
||||
}
|
||||
return loaded!!
|
||||
}
|
||||
|
||||
fun loadRecursively(klassName : String) : Class<*> {
|
||||
System.out.println("trying to find class ${klassName}")
|
||||
try {
|
||||
return classLoader.loadClass(klassName)
|
||||
return Class.forName(klassName, false, classLoader)
|
||||
} catch(ex : ClassNotFoundException) {
|
||||
val lastIndexOfDot = klassName.lastIndexOf(".")
|
||||
if (lastIndexOfDot == -1) {
|
||||
|
||||
@@ -31,7 +31,7 @@ import com.android.databinding.util.getMethodOrField
|
||||
import com.android.databinding.util.Log
|
||||
import com.android.databinding.ext.joinToCamelCaseAsVar
|
||||
import com.android.databinding.util.isObservable
|
||||
import com.android.databinding.annotationprocessor.BindingAdapterStore
|
||||
import com.android.databinding.store.SetterStore
|
||||
|
||||
class Binding(val target : BindingTarget, val attr : String, val targetFieldName : String,
|
||||
val expr : Expr) {
|
||||
@@ -47,8 +47,8 @@ class Binding(val target : BindingTarget, val attr : String, val targetFieldName
|
||||
|
||||
val setter by Delegates.lazy {
|
||||
val viewType = ClassAnalyzer.instance.loadClass(target.viewClass);
|
||||
BindingAdapterStore.get().getSetterCall(attr, viewType, expr.resolvedClass,
|
||||
target.resolvedViewName, expr.toJava(), ClassAnalyzer.instance.classLoader)
|
||||
SetterStore.get(ClassAnalyzer.instance).getSetterCall(attr, viewType,
|
||||
expr.resolvedClass, target.resolvedViewName, expr.toJava())
|
||||
}
|
||||
|
||||
val isDirtyName by Delegates.lazy {"sDirtyFlag${target.resolvedUniqueName}_${targetFieldName.capitalize()}"}
|
||||
|
||||
@@ -55,6 +55,11 @@ android {
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile project(":annotations")
|
||||
provided 'com.android.support:cardview-v7:+'
|
||||
provided 'com.android.support:appcompat-v7:+'
|
||||
provided 'com.android.databinding:compiler:+'
|
||||
provided 'com.android.databinding:annotationprocessor:+'
|
||||
}
|
||||
//create jar tasks
|
||||
android.libraryVariants.all { variant ->
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.AbsListView", attribute = "android:listSelector", method = "setSelector"),
|
||||
@BindingMethod(type = "android.widget.AbsListView", attribute = "android:scrollingCache", method = "setScrollingCacheEnabled"),
|
||||
@BindingMethod(type = "android.widget.AbsListView", attribute = "android:smoothScrollbar", method = "setSmoothScrollbarEnabled"),
|
||||
})
|
||||
public class AbsListViewBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.AbsSeekBar", attribute = "android:thumbTint", method = "setThumbTintTintList"),
|
||||
|
||||
})
|
||||
public class AbsSeekBarBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingAdapter;
|
||||
import android.widget.AbsSpinner;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.SpinnerAdapter;
|
||||
|
||||
public class AbsSpinnerBindingAdapter {
|
||||
|
||||
@BindingAdapter("android:entries")
|
||||
public static void setEntries(AbsSpinner view, CharSequence[] entries) {
|
||||
if (entries != null) {
|
||||
SpinnerAdapter oldAdapter = view.getAdapter();
|
||||
boolean changed = true;
|
||||
if (oldAdapter.getCount() == entries.length) {
|
||||
changed = false;
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
if (!entries[i].toString().equals(oldAdapter.getItem(i))) {
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
ArrayAdapter<CharSequence> adapter =
|
||||
new ArrayAdapter<CharSequence>(view.getContext(),
|
||||
android.R.layout.simple_spinner_item, entries);
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
view.setAdapter(adapter);
|
||||
}
|
||||
} else {
|
||||
view.setAdapter(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.AutoCompleteTextView", attribute = "android:completionThreshold", method = "setThreshold"),
|
||||
@BindingMethod(type = "android.widget.AutoCompleteTextView", attribute = "android:popupBackground", method = "setDropDownBackgroundDrawable"),
|
||||
})
|
||||
public class AutoCompleteTextViewBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingAdapter;
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
import android.support.v7.widget.CardView;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.support.v7.widget.CardView", attribute = "cardCornerRadius", method = "setRadius"),
|
||||
@BindingMethod(type = "android.support.v7.widget.CardView", attribute = "cardMaxElevation", method = "setMaxCardElevation"),
|
||||
@BindingMethod(type = "android.support.v7.widget.CardView", attribute = "cardPreventCornerOverlap", method = "setPreventCornerOverlap"),
|
||||
@BindingMethod(type = "android.support.v7.widget.CardView", attribute = "cardUseCompatPadding", method = "setUseCompatPadding"),
|
||||
})
|
||||
public class CardViewBindingAdapter {
|
||||
|
||||
@BindingAdapter("contentPadding")
|
||||
public static void setContentPadding(CardView view, int padding) {
|
||||
int left = view.getContentPaddingLeft();
|
||||
int top = view.getContentPaddingTop();
|
||||
int right = view.getContentPaddingRight();
|
||||
int bottom = view.getContentPaddingBottom();
|
||||
view.setContentPadding(padding, padding, padding, padding);
|
||||
}
|
||||
|
||||
@BindingAdapter("contentPaddingLeft")
|
||||
public static void setContentPaddingLeft(CardView view, int left) {
|
||||
int top = view.getContentPaddingTop();
|
||||
int right = view.getContentPaddingRight();
|
||||
int bottom = view.getContentPaddingBottom();
|
||||
view.setContentPadding(left, top, right, bottom);
|
||||
}
|
||||
|
||||
@BindingAdapter("contentPaddingTop")
|
||||
public static void setContentPaddingTop(CardView view, int top) {
|
||||
int left = view.getContentPaddingLeft();
|
||||
int right = view.getContentPaddingRight();
|
||||
int bottom = view.getContentPaddingBottom();
|
||||
view.setContentPadding(left, top, right, bottom);
|
||||
}
|
||||
|
||||
@BindingAdapter("contentPaddingRight")
|
||||
public static void setContentPaddingRight(CardView view, int right) {
|
||||
int left = view.getContentPaddingLeft();
|
||||
int top = view.getContentPaddingTop();
|
||||
int bottom = view.getContentPaddingBottom();
|
||||
view.setContentPadding(left, top, right, bottom);
|
||||
}
|
||||
|
||||
@BindingAdapter("contentPaddingBottom")
|
||||
public static void setContentPaddingBottom(CardView view, int bottom) {
|
||||
int left = view.getContentPaddingLeft();
|
||||
int top = view.getContentPaddingTop();
|
||||
int right = view.getContentPaddingRight();
|
||||
view.setContentPadding(left, top, right, bottom);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.CheckedTextView", attribute = "android:checkMark", method = "setCheckMarkDrawable"),
|
||||
@BindingMethod(type = "android.widget.CheckedTextView", attribute = "android:checkMarkTint", method = "setCheckMarkTintList"),
|
||||
})
|
||||
public class CheckedTextViewBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.CompoundButton", attribute = "android:buttonTint", method = "setButtonTintList"),
|
||||
})
|
||||
public class CompoundButtonBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingConversion;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
|
||||
public class Converters {
|
||||
@BindingConversion
|
||||
public static ColorDrawable convertColorToDrawable(int color) {
|
||||
return new ColorDrawable(color);
|
||||
}
|
||||
|
||||
@BindingConversion
|
||||
public static ColorStateList convertColorToColorStateList(int color) {
|
||||
return ColorStateList.valueOf(color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.FrameLayout", attribute = "android:foregroundTint", method = "setForegroundTintList"),
|
||||
})
|
||||
public class FrameLayoutBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.ImageView", attribute = "src", method = "setImageDrawable"),
|
||||
@BindingMethod(type = "android.widget.ImageView", attribute = "tint", method = "setImageTintList"),
|
||||
@BindingMethod(type = "android.widget.ImageView", attribute = "tintMode", method = "setImageTintMode"),
|
||||
})
|
||||
public class ImageViewBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.LinearLayout", attribute = "android:divider", method = "setDividerDrawable"),
|
||||
@BindingMethod(type = "android.widget.LinearLayout", attribute = "android:measureWithLargestChild", method = "setMeasureWithLargestChildEnabled"),
|
||||
})
|
||||
public class LinearLayoutBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.ProgressBar", attribute = "android:indeterminateTint", method = "setIndeterminateTintList"),
|
||||
@BindingMethod(type = "android.widget.ProgressBar", attribute = "android:progressTint", method = "setProgressTintList"),
|
||||
@BindingMethod(type = "android.widget.ProgressBar", attribute = "android:secondaryProgressTint", method = "setSecondaryProgressTintList"),
|
||||
})
|
||||
public class ProgressBarBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.RadioGroup", attribute = "android:checkedButton", method = "check"),
|
||||
})
|
||||
public class RadioGroupBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.Spinner", attribute = "android:popupBackground", method = "setPopupBackgroundDrawable"),
|
||||
})
|
||||
public class SpinnerBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.binding.BindingAdapter;
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
import android.os.Build;
|
||||
import android.widget.Switch;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.Switch", attribute = "android:thumb", method = "setThumbDrawable"),
|
||||
@BindingMethod(type = "android.widget.Switch", attribute = "android:track", method = "setTrackDrawable"),
|
||||
})
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
public class SwitchBindingAdapter {
|
||||
|
||||
@BindingAdapter("android:switchTextAppearance")
|
||||
public static void setSwitchTextAppearance(Switch view, int value) {
|
||||
view.setSwitchTextAppearance(null, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingAdapter;
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
import android.support.v7.widget.SwitchCompat;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.support.v7.widget.SwitchCompat", attribute = "android:thumb", method = "setThumbDrawable"),
|
||||
@BindingMethod(type = "android.support.v7.widget.SwitchCompat", attribute = "android:track", method = "setTrackDrawable"),
|
||||
})
|
||||
public class SwitchCompatBindingAdapter {
|
||||
|
||||
@BindingAdapter("android:switchTextAppearance")
|
||||
public static void setSwitchTextAppearance(SwitchCompat view, int value) {
|
||||
view.setSwitchTextAppearance(null, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.TabWidget", attribute = "android:divider", method = "setDividerDrawable"),
|
||||
@BindingMethod(type = "android.widget.TabWidget", attribute = "android:tabStripEnabled", method = "setStripEnabled"),
|
||||
@BindingMethod(type = "android.widget.TabWidget", attribute = "android:tabStripLeft", method = "setLeftStripDrawable"),
|
||||
@BindingMethod(type = "android.widget.TabWidget", attribute = "android:tabStripRight", method = "setRightStripDrawable"),
|
||||
})
|
||||
public class TabWidgetBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingAdapter;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.widget.TableLayout;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TableLayoutBindingAdapter {
|
||||
|
||||
private static final int MAX_COLUMNS = 20;
|
||||
|
||||
private static Pattern sColumnPattern = Pattern.compile("\\s*,\\s*");
|
||||
|
||||
@BindingAdapter("android:collapseColumns")
|
||||
public static void setCollapseColumns(TableLayout view, CharSequence columnsStr) {
|
||||
SparseBooleanArray columns = parseColumns(columnsStr);
|
||||
for (int i = 0; i < MAX_COLUMNS; i++) {
|
||||
boolean isCollapsed = columns.get(i, false);
|
||||
if (isCollapsed != view.isColumnCollapsed(i)) {
|
||||
view.setColumnCollapsed(i, isCollapsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:shrinkColumns")
|
||||
public static void setShrinkColumns(TableLayout view, CharSequence columnsStr) {
|
||||
if (columnsStr.charAt(0) == '*') {
|
||||
view.setShrinkAllColumns(true);
|
||||
} else {
|
||||
view.setShrinkAllColumns(false);
|
||||
SparseBooleanArray columns = parseColumns(columnsStr);
|
||||
for (int i = 0; i < MAX_COLUMNS; i++) {
|
||||
boolean shrinkable = columns.get(i, false);
|
||||
if (shrinkable != view.isColumnShrinkable(i)) {
|
||||
view.setColumnShrinkable(i, shrinkable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:stretchColumns")
|
||||
public static void setStretchColumns(TableLayout view, CharSequence columnsStr) {
|
||||
if (columnsStr.charAt(0) == '*') {
|
||||
view.setStretchAllColumns(true);
|
||||
} else {
|
||||
view.setStretchAllColumns(false);
|
||||
SparseBooleanArray columns = parseColumns(columnsStr);
|
||||
for (int i = 0; i < MAX_COLUMNS; i++) {
|
||||
boolean stretchable = columns.get(i, false);
|
||||
if (stretchable != view.isColumnStretchable(i)) {
|
||||
view.setColumnStretchable(i, stretchable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SparseBooleanArray parseColumns(CharSequence sequence) {
|
||||
SparseBooleanArray columns = new SparseBooleanArray();
|
||||
String[] columnDefs = sColumnPattern.split(sequence);
|
||||
|
||||
for (String columnIdentifier : columnDefs) {
|
||||
try {
|
||||
int columnIndex = Integer.parseInt(columnIdentifier);
|
||||
// only valid, i.e. positive, columns indexes are handled
|
||||
if (columnIndex >= 0) {
|
||||
// putting true in this sparse array indicates that the
|
||||
// column index was defined in the XML file
|
||||
columns.put(columnIndex, true);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// we just ignore columns that don't exist
|
||||
}
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingAdapter;
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.text.InputFilter;
|
||||
import android.text.method.DialerKeyListener;
|
||||
import android.text.method.DigitsKeyListener;
|
||||
import android.text.method.KeyListener;
|
||||
import android.text.method.PasswordTransformationMethod;
|
||||
import android.text.method.TextKeyListener;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.TextView;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.widget.TextView", attribute = "android:autoLink", method = "setAutoLinkMask"),
|
||||
@BindingMethod(type = "android.widget.TextView", attribute = "android:drawablePadding", method = "setCompoundDrawablePadding"),
|
||||
@BindingMethod(type = "android.widget.TextView", attribute = "android:editorExtras", method = "setInputExtras"),
|
||||
@BindingMethod(type = "android.widget.TextView", attribute = "android:inputType", method = "setRawInputType"),
|
||||
@BindingMethod(type = "android.widget.TextView", attribute = "android:scrollHorizontally", method = "setHorizontallyScrolling"),
|
||||
@BindingMethod(type = "android.widget.TextView", attribute = "android:textAllCaps", method = "setAllCaps"),
|
||||
@BindingMethod(type = "android.widget.TextView", attribute = "android:textColorHighlight", method = "setHighlightColor"),
|
||||
@BindingMethod(type = "android.widget.TextView", attribute = "android:textColorHint", method = "setHintTextColor"),
|
||||
@BindingMethod(type = "android.widget.TextView", attribute = "android:textColorLink", method = "setLinkTextColor"),
|
||||
})
|
||||
public class TextViewBindingAdapter {
|
||||
|
||||
private static final String TAG = "TextViewBindingAdapters";
|
||||
|
||||
public static final int INTEGER = 0x01;
|
||||
|
||||
public static final int SIGNED = 0x03;
|
||||
|
||||
public static final int DECIMAL = 0x05;
|
||||
|
||||
@BindingAdapter("android:autoText")
|
||||
public static void setAutoText(TextView view, boolean autoText) {
|
||||
KeyListener listener = view.getKeyListener();
|
||||
|
||||
TextKeyListener.Capitalize capitalize = TextKeyListener.Capitalize.NONE;
|
||||
|
||||
if (listener instanceof AutoCapKeyListener) {
|
||||
capitalize = ((AutoCapKeyListener) listener).getCapitalize();
|
||||
}
|
||||
view.setKeyListener(new AutoCapKeyListener(capitalize, autoText));
|
||||
}
|
||||
|
||||
@BindingAdapter("android:capitalize")
|
||||
public static void setAutoText(TextView view, TextKeyListener.Capitalize capitalize) {
|
||||
KeyListener listener = view.getKeyListener();
|
||||
|
||||
boolean autoText = false;
|
||||
|
||||
if (listener instanceof AutoCapKeyListener) {
|
||||
autoText = ((AutoCapKeyListener) listener).isAutoText();
|
||||
}
|
||||
view.setKeyListener(new AutoCapKeyListener(capitalize, autoText));
|
||||
}
|
||||
|
||||
@BindingAdapter("android:bufferType")
|
||||
public static void setBufferType(TextView view, TextView.BufferType bufferType) {
|
||||
view.setText(view.getText(), bufferType);
|
||||
}
|
||||
|
||||
@BindingAdapter("android:digits")
|
||||
public static void setDigits(TextView view, CharSequence digits) {
|
||||
if (digits != null) {
|
||||
view.setKeyListener(DigitsKeyListener.getInstance(digits.toString()));
|
||||
} else if (view.getKeyListener() instanceof DigitsKeyListener) {
|
||||
view.setKeyListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:numeric")
|
||||
public static void setNumeric(TextView view, int numeric) {
|
||||
view.setKeyListener(DigitsKeyListener.getInstance((numeric & SIGNED) != 0,
|
||||
(numeric & DECIMAL) != 0));
|
||||
}
|
||||
|
||||
@BindingAdapter("android:phoneNumber")
|
||||
public static void setPhoneNumber(TextView view, boolean phoneNumber) {
|
||||
if (phoneNumber) {
|
||||
view.setKeyListener(DialerKeyListener.getInstance());
|
||||
} else if (view.getKeyListener() instanceof DialerKeyListener) {
|
||||
view.setKeyListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:drawableBottom")
|
||||
public static void setDrawableBottom(TextView view, Drawable drawable) {
|
||||
Drawable[] drawables = view.getCompoundDrawables();
|
||||
view.setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawable);
|
||||
}
|
||||
|
||||
@BindingAdapter("android:drawableLeft")
|
||||
public static void setDrawableLeft(TextView view, Drawable drawable) {
|
||||
Drawable[] drawables = view.getCompoundDrawables();
|
||||
view.setCompoundDrawables(drawable, drawables[1], drawables[2], drawables[3]);
|
||||
}
|
||||
|
||||
@BindingAdapter("android:drawableRight")
|
||||
public static void setDrawableRight(TextView view, Drawable drawable) {
|
||||
Drawable[] drawables = view.getCompoundDrawables();
|
||||
view.setCompoundDrawables(drawables[0], drawables[1], drawable, drawables[3]);
|
||||
}
|
||||
|
||||
@BindingAdapter("android:drawableTop")
|
||||
public static void setDrawableTop(TextView view, Drawable drawable) {
|
||||
Drawable[] drawables = view.getCompoundDrawables();
|
||||
view.setCompoundDrawables(drawables[0], drawable, drawables[2], drawables[3]);
|
||||
}
|
||||
|
||||
@BindingAdapter("android:drawableStart")
|
||||
public static void setDrawableStart(TextView view, Drawable drawable) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
setDrawableLeft(view, drawable);
|
||||
} else {
|
||||
Drawable[] drawables = view.getCompoundDrawablesRelative();
|
||||
view.setCompoundDrawables(drawable, drawables[1], drawables[2], drawables[3]);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:drawableEnd")
|
||||
public static void setDrawableEnd(TextView view, Drawable drawable) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
setDrawableRight(view, drawable);
|
||||
} else {
|
||||
Drawable[] drawables = view.getCompoundDrawablesRelative();
|
||||
view.setCompoundDrawables(drawables[0], drawables[1], drawable, drawables[3]);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:imeActionLabel")
|
||||
public static void setImeActionLabel(TextView view, CharSequence value) {
|
||||
view.setImeActionLabel(value, view.getImeActionId());
|
||||
}
|
||||
|
||||
@BindingAdapter("android:imeActionId")
|
||||
public static void setImeActionLabel(TextView view, int value) {
|
||||
view.setImeActionLabel(view.getImeActionLabel(), value);
|
||||
}
|
||||
|
||||
@BindingAdapter("android:inputMethod")
|
||||
public static void setInputMethod(TextView view, CharSequence inputMethod) {
|
||||
try {
|
||||
Class<?> c = Class.forName(inputMethod.toString());
|
||||
view.setKeyListener((KeyListener) c.newInstance());
|
||||
} catch (ClassNotFoundException e) {
|
||||
Log.e(TAG, "Could not create input method: " + inputMethod, e);
|
||||
} catch (InstantiationException e) {
|
||||
Log.e(TAG, "Could not create input method: " + inputMethod, e);
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(TAG, "Could not create input method: " + inputMethod, e);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:lineSpacingExtra")
|
||||
public static void setLineSpacingExtra(TextView view, float value) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setLineSpacing(value, view.getLineSpacingMultiplier());
|
||||
} else {
|
||||
view.setLineSpacing(value, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:lineSpacingMultiplier")
|
||||
public static void setLineSpacingMultiplier(TextView view, float value) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setLineSpacing(view.getLineSpacingExtra(), value);
|
||||
} else {
|
||||
view.setLineSpacing(0, value);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:maxLength")
|
||||
public static void setMaxLength(TextView view, int value) {
|
||||
InputFilter[] filters = view.getFilters();
|
||||
if (filters == null) {
|
||||
filters = new InputFilter[]{
|
||||
new InputFilter.LengthFilter(value)
|
||||
};
|
||||
} else {
|
||||
boolean foundMaxLength = false;
|
||||
for (int i = 0; i < filters.length; i++) {
|
||||
InputFilter filter = filters[i];
|
||||
if (filter instanceof InputFilter.LengthFilter) {
|
||||
foundMaxLength = true;
|
||||
boolean replace = true;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
replace = ((InputFilter.LengthFilter) filter).getMax() != value;
|
||||
}
|
||||
if (replace) {
|
||||
filters[i] = new InputFilter.LengthFilter(value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundMaxLength) {
|
||||
// can't use Arrays.copyOf -- it shows up in API 9
|
||||
InputFilter[] oldFilters = filters;
|
||||
filters = new InputFilter[oldFilters.length + 1];
|
||||
System.arraycopy(oldFilters, 0, filters, 0, oldFilters.length);
|
||||
filters[filters.length - 1] = new InputFilter.LengthFilter(value);
|
||||
}
|
||||
}
|
||||
view.setFilters(filters);
|
||||
}
|
||||
|
||||
@BindingAdapter("android:password")
|
||||
public static void setPassword(TextView view, boolean password) {
|
||||
if (password) {
|
||||
view.setTransformationMethod(PasswordTransformationMethod.getInstance());
|
||||
} else if (view.getTransformationMethod() instanceof PasswordTransformationMethod) {
|
||||
view.setTransformationMethod(null);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:shadowColor")
|
||||
public static void setShadowColor(TextView view, int color) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
float dx = view.getShadowDx();
|
||||
float dy = view.getShadowDy();
|
||||
float r = view.getShadowRadius();
|
||||
view.setShadowLayer(r, dx, dy, color);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:shadowDx")
|
||||
public static void setShadowDx(TextView view, float dx) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
int color = view.getShadowColor();
|
||||
float dy = view.getShadowDy();
|
||||
float r = view.getShadowRadius();
|
||||
view.setShadowLayer(r, dx, dy, color);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:shadowDy")
|
||||
public static void setShadowDy(TextView view, float dy) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
int color = view.getShadowColor();
|
||||
float dx = view.getShadowDx();
|
||||
float r = view.getShadowRadius();
|
||||
view.setShadowLayer(r, dx, dy, color);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:shadowRadius")
|
||||
public static void setShadowRadius(TextView view, float r) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
int color = view.getShadowColor();
|
||||
float dx = view.getShadowDx();
|
||||
float dy = view.getShadowDy();
|
||||
view.setShadowLayer(r, dx, dy, color);
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:textSize")
|
||||
public static void setTextSize(TextView view, float size) {
|
||||
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
|
||||
}
|
||||
|
||||
private static class AutoCapKeyListener extends TextKeyListener {
|
||||
|
||||
private final Capitalize mCapitalize;
|
||||
|
||||
private final boolean mAutoText;
|
||||
|
||||
public AutoCapKeyListener(Capitalize cap, boolean autoText) {
|
||||
super(cap, autoText);
|
||||
mCapitalize = cap;
|
||||
mAutoText = autoText;
|
||||
}
|
||||
|
||||
public Capitalize getCapitalize() {
|
||||
return mCapitalize;
|
||||
}
|
||||
|
||||
public boolean isAutoText() {
|
||||
return mAutoText;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingAdapter;
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:backgroundTint", method = "setBackgroundTintList"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:fadeScrollbars", method = "setScrollbarFadingEnabled"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:nextFocusForward", method = "setNextFocusForwardId"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:nextFocusLeft", method = "setNextFocusLeftId"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:nextFocusRight", method = "setNextFocusRightId"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:nextFocusUp", method = "setNextFocusUpId"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:padding", method = "setPaddingRelative"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:requiresFadingEdge", method = "setVerticalFadingEdgeEnabled"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:scrollbarDefaultDelayBeforeFade", method = "setScrollBarDefaultDelayBeforeFade"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:scrollbarFadeDuration", method = "setScrollBarFadeDuration"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:scrollbarSize", method = "setScrollBarSize"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:scrollbarStyle", method = "setScrollBarStyle"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:transformPivotX", method = "setPivotX"),
|
||||
@BindingMethod(type = "android.view.View", attribute = "android:transformPivotY", method = "setPivotY"),
|
||||
})
|
||||
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);
|
||||
}
|
||||
|
||||
@BindingAdapter("android:paddingBottom")
|
||||
public static void setPaddingBottom(View view, int padding) {
|
||||
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(),
|
||||
padding);
|
||||
}
|
||||
|
||||
@BindingAdapter("android:paddingEnd")
|
||||
public static void setPaddingEnd(View view, int padding) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(), padding,
|
||||
view.getPaddingBottom());
|
||||
} else {
|
||||
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), padding,
|
||||
view.getPaddingBottom());
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:paddingLeft")
|
||||
public static void setPaddingLeft(View view, int padding) {
|
||||
view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(),
|
||||
view.getPaddingBottom());
|
||||
}
|
||||
|
||||
@BindingAdapter("android:paddingRight")
|
||||
public static void setPaddingRight(View view, int padding) {
|
||||
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), padding,
|
||||
view.getPaddingBottom());
|
||||
}
|
||||
|
||||
@BindingAdapter("android:paddingStart")
|
||||
public static void setPaddingStart(View view, int padding) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setPaddingRelative(padding, view.getPaddingTop(), view.getPaddingEnd(),
|
||||
view.getPaddingBottom());
|
||||
} else {
|
||||
view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(),
|
||||
view.getPaddingBottom());
|
||||
}
|
||||
}
|
||||
|
||||
@BindingAdapter("android:paddingTop")
|
||||
public static void setPaddingTop(View view, int padding) {
|
||||
view.setPadding(view.getPaddingLeft(), padding, view.getPaddingRight(),
|
||||
view.getPaddingBottom());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.annotation.TargetApi;
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
import android.os.Build;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.view.ViewGroup", attribute = "android:alwaysDrawnWithCache", method = "setAlwaysDrawnWithCacheEnabled"),
|
||||
@BindingMethod(type = "android.view.ViewGroup", attribute = "android:animationCache", method = "setAnimationCacheEnabled"),
|
||||
@BindingMethod(type = "android.view.ViewGroup", attribute = "android:splitMotionEvents", method = "setMotionEventSplittingEnabled"),
|
||||
})
|
||||
public class ViewGroupBindingAdapter {
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public static void setAnimateLayoutChanges(ViewGroup view, boolean animate) {
|
||||
if (animate) {
|
||||
view.setLayoutTransition(new LayoutTransition());
|
||||
} else {
|
||||
view.setLayoutTransition(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.binding.adapters;
|
||||
|
||||
import android.binding.BindingMethod;
|
||||
import android.binding.BindingMethods;
|
||||
|
||||
@BindingMethods({
|
||||
@BindingMethod(type = "android.view.ViewStub", attribute = "android:layout", method = "setLayoutResource")
|
||||
})
|
||||
public class ViewStubBindingAdapter {
|
||||
|
||||
}
|
||||
@@ -40,9 +40,6 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
//sourceSets {
|
||||
// main.java.srcDirs += generatedSources
|
||||
//}
|
||||
}
|
||||
|
||||
android.applicationVariants.all { variant ->
|
||||
@@ -60,7 +57,9 @@ dependencies {
|
||||
compile 'com.android.support:appcompat-v7:21.+'
|
||||
compile 'com.android.databinding:library:0.3-SNAPSHOT@aar'
|
||||
compile 'com.android.support:recyclerview-v7:21.0.2'
|
||||
compile 'com.android.support:gridlayout-v7:21+'
|
||||
compile 'com.android.support:cardview-v7:21.0.2'
|
||||
provided 'com.android.databinding:annotationprocessor:0.1-SNAPSHOT'
|
||||
compile 'com.android.support:gridlayout-v7:21.+'
|
||||
compile 'com.android.support:cardview-v7:21.+'
|
||||
compile 'com.android.databinding:annotations:0.3-SNAPSHOT'
|
||||
provided 'com.android.databinding:compiler:0.3-SNAPSHOT'
|
||||
provided 'com.android.databinding:annotationprocessor:0.3-SNAPSHOT'
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.android.example.bindingdemo.vo;
|
||||
|
||||
import android.binding.BindingAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class TestBindingAdapter {
|
||||
@BindingAdapter(attribute = "android:text")
|
||||
public static void setText(TextView view, String value) {
|
||||
view.setText(value);
|
||||
}
|
||||
@BindingAdapter(attribute = "android:text")
|
||||
public static void setObjectText(Object view, String value) {
|
||||
((TextView)view).setText(String.valueOf(value));
|
||||
}
|
||||
@BindingAdapter(attribute = "android:text")
|
||||
public static void setTextObject(TextView view, Object value) {
|
||||
view.setText(String.valueOf(value));
|
||||
}
|
||||
@BindingAdapter(attribute = "android:text")
|
||||
public static void setTextFloat(TextView view, float value) {
|
||||
view.setText(String.valueOf(value));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
include ':library'
|
||||
include ':compiler'
|
||||
include ':gradlePlugin'
|
||||
include ':annotations'
|
||||
include ':grammerBuilder'
|
||||
include ':annotationprocessor'
|
||||
include 'xmlGrammer'
|
||||
include ':xmlGrammer'
|
||||
|
||||
Reference in New Issue
Block a user