Skip to content

Commit

Permalink
add all classes
Browse files Browse the repository at this point in the history
  • Loading branch information
pavel163 committed Dec 2, 2016
1 parent ff94648 commit 2291bc3
Show file tree
Hide file tree
Showing 15 changed files with 474 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.ebr163.android.attributesdispatcher;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.EditText;

import com.ebr163.attributesdispatcher.Attribute;
import com.ebr163.attributesdispatcher.CustomView;
import com.ebr163.attributesdispatcher.attr.ColorAttr;
import com.ebr163.attributesdispatcher.attr.StringAttr;

/**
* Created by mac1 on 24.11.16.
*/

@CustomView
public class MyCustomView extends EditText {

@ColorAttr("custom_color")
protected int color;
@StringAttr("custom_text")
protected String text;

public MyCustomView(Context context) {
super(context);
}

public MyCustomView(Context context, AttributeSet attrs) {
super(context, attrs);
MyCustomViewAttribute.init(this, attrs);
}

public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
MyCustomViewAttribute.init(this, attrs);
}

@Attribute
protected void setCustomAttr(@ColorAttr("custom_color") int color) {
this.setTextColor(color);
}
}
28 changes: 18 additions & 10 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.ebr163.android.attributesdispatcher.MainActivity">
android:paddingTop="@dimen/activity_vertical_margin">

<com.ebr163.android.attributesdispatcher.MyCustomView
android:id="@+id/custom_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:custom_text="Text1"
app:custom_color="@android:color/holo_blue_light" />

<TextView
android:layout_width="wrap_content"
<com.ebr163.android.attributesdispatcher.MyCustomView
android:id="@+id/custom_view1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!" />
</RelativeLayout>
app:custom_text="Text2"
app:custom_color="@android:color/holo_red_dark" />
</LinearLayout>
7 changes: 7 additions & 0 deletions app/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyCustomView">
<attr name="custom_text" format="string" />
<attr name="custom_color" format="color" />
</declare-styleable>
</resources>
Original file line number Diff line number Diff line change
@@ -1,14 +1,220 @@
package com.ebr163.attributesdispatcher.internal;

import com.ebr163.attributesdispatcher.Attribute;
import com.ebr163.attributesdispatcher.CustomView;
import com.ebr163.attributesdispatcher.attr.BooleanAttr;
import com.ebr163.attributesdispatcher.attr.ColorAttr;
import com.ebr163.attributesdispatcher.attr.DimenAttr;
import com.ebr163.attributesdispatcher.attr.FloatAttr;
import com.ebr163.attributesdispatcher.attr.IntAttr;
import com.ebr163.attributesdispatcher.attr.ReferenceAttr;
import com.ebr163.attributesdispatcher.attr.StringAttr;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
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.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;

@SupportedAnnotationTypes("com.ebr163.attributesdispatcher.CustomView")
public class AttributesProcessor extends AbstractProcessor {
private static final String METHOD_PREFIX = "Generation";

private ClassName AttributeSet = ClassName.get("android.util", "AttributeSet");
private ClassName TypedArray = ClassName.get("android.content.res", "TypedArray");
private ClassName Build = ClassName.get("android.os", "Build");

@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}

@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> set = new HashSet<>();
set.add(CustomView.class.getCanonicalName());
return Collections.unmodifiableSet(set);
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
return false;
for (Element element : roundEnv.getElementsAnnotatedWith(CustomView.class)) {
JavaFile javaFile = createJavaFile(new CustomViewElement((TypeElement) element));
try {
javaFile.writeTo(processingEnv.getFiler());
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}

private JavaFile createJavaFile(CustomViewElement customViewElement) {
return JavaFile.builder(customViewElement.packageName, createTypeSpec(customViewElement))
.addFileComment("This file was generated by AttrGenerator. Do not modify!")
.build();
}

private TypeSpec createTypeSpec(CustomViewElement customViewElement) {
TypeSpec.Builder builder = TypeSpec.classBuilder(customViewElement.generatedClassName)
.addModifiers(Modifier.FINAL)
.addMethod(createConstructor())
.addMethods(createAttrMethods(customViewElement))
.addMethod(createInitMethod(customViewElement));
return builder.build();


}

private MethodSpec createConstructor() {
return MethodSpec.constructorBuilder()
.addModifiers(Modifier.PRIVATE)
.build();
}

private MethodSpec createInitMethod(CustomViewElement customViewElement) {
MethodSpec.Builder builder = MethodSpec.methodBuilder("init")
.addTypeVariables(customViewElement.typeVariables)
.addModifiers(Modifier.STATIC)
.returns(TypeName.VOID)
.addParameter(customViewElement.typeName, "target")
.addParameter(ParameterSpec.builder(AttributeSet, "attributeSet").build());

addAttrGenBodyInit(builder, customViewElement);
return builder.build();
}

private List<MethodSpec> createAttrMethods(CustomViewElement customViewElement) {
List<MethodSpec> methods = new ArrayList<>();
for (ExecutableElement method : customViewElement.attrElements) {
methods.add(createAttrGenMethod(customViewElement, method));
}

return methods;
}

private void addAttrGenBodyInit(MethodSpec.Builder builder, CustomViewElement customViewElement) {
builder.addStatement("$T typedArray = $N.getContext().getTheme().obtainStyledAttributes(\n" +
" $N,\n" +
" R.styleable.$L,\n" +
" 0, 0)", TypedArray, "target", "attributeSet", customViewElement.inputClassName);

addInitTargetField(builder, customViewElement);

for (ExecutableElement method : customViewElement.attrElements) {
builder.addStatement(method.getSimpleName().toString() + METHOD_PREFIX + "($N, $N)", "target", "typedArray");
}
builder.addStatement("$N.recycle()", "typedArray");
}

private void addInitTargetField(MethodSpec.Builder builder, CustomViewElement customViewElement) {
for (Element field : customViewElement.booleanElements) {
String value = field.getAnnotation(BooleanAttr.class).value();
builder.addStatement("$N." + field.getSimpleName().toString() + " = $N.getBoolean(R.styleable.$L_$L, false)", "target", "typedArray", customViewElement.inputClassName, value);
}

for (Element field : customViewElement.colorElements) {
String value = field.getAnnotation(ColorAttr.class).value();
builder.addStatement("$N." + field.getSimpleName().toString() + " = $N.getColor(R.styleable.$L_$L, 0)", "target", "typedArray", customViewElement.inputClassName, value);
}

for (Element field : customViewElement.dimenElements) {
String value = field.getAnnotation(DimenAttr.class).value();
builder.addStatement("$N." + field.getSimpleName().toString() + " = $N.getDimension(R.styleable.$L_$L, 0f)", "target", "typedArray", customViewElement.inputClassName, value);
}

for (Element field : customViewElement.floatElements) {
String value = field.getAnnotation(FloatAttr.class).value();
builder.addStatement("$N." + field.getSimpleName().toString() + " = $N.getFloat(R.styleable.$L_$L, 0f)", "target", "typedArray", customViewElement.inputClassName, value);
}

for (Element field : customViewElement.integerElements) {
String value = field.getAnnotation(IntAttr.class).value();
builder.addStatement("$N." + field.getSimpleName().toString() + " = $N.getInt(R.styleable.$L_$L, 0)", "target", "typedArray", customViewElement.inputClassName, value);
}

for (Element field : customViewElement.referenceElements) {
String value = field.getAnnotation(ReferenceAttr.class).value();
builder.addStatement("$N." + field.getSimpleName().toString() + " = $N.getResourceId(R.styleable.$L_$L, -1)", "target", "typedArray", customViewElement.inputClassName, value);
}

for (Element field : customViewElement.stringElements) {
String value = field.getAnnotation(StringAttr.class).value();
builder.addStatement("$N." + field.getSimpleName().toString() + " = $N.getString(R.styleable.$L_$L)", "target", "typedArray", customViewElement.inputClassName, value);
}
}

private MethodSpec createAttrGenMethod(CustomViewElement customViewElement, ExecutableElement method) {
MethodSpec.Builder builder = MethodSpec.methodBuilder(method.getSimpleName().toString() + METHOD_PREFIX)
.addTypeVariables(customViewElement.typeVariables)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
.returns(TypeName.VOID)
.addParameter(customViewElement.typeName, "target")
.addParameter(ParameterSpec.builder(TypedArray, "typedArray").build());

addAttrGenBody(builder, method, customViewElement);
return builder.build();
}

private void addAttrGenBody(MethodSpec.Builder builder, ExecutableElement method, CustomViewElement customViewElement) {
int maxSdkVersion = method.getAnnotation(Attribute.class).maxSdkVersion();
builder.beginControlFlow("if ($T.VERSION.SDK_INT < $L)", Build, maxSdkVersion);
builder.addStatement("return");
builder.endControlFlow();

String params = "";
for (int i = 0; i < method.getParameters().size(); i++) {
TypeName type = TypeName.get(method.getParameters().get(i).asType());
String name = method.getParameters().get(i).getSimpleName().toString();

Element parameter = method.getParameters().get(i);
DeclaredType annotation = parameter.getAnnotationMirrors().get(0).getAnnotationType();

if (annotation.toString().equals(IntAttr.class.getCanonicalName())) {
String key = parameter.getAnnotation(IntAttr.class).value();
builder.addStatement("$T $N = $N.getInt(R.styleable.$L_$L, 0)", type, name, "typedArray", customViewElement.inputClassName, key);
} else if (annotation.toString().equals(BooleanAttr.class.getCanonicalName())) {
String key = parameter.getAnnotation(BooleanAttr.class).value();
builder.addStatement("$T $N = $N.getBoolean(R.styleable.$L_$L, false)", type, name, "typedArray", customViewElement.inputClassName, key);
} else if (annotation.toString().equals(ColorAttr.class.getCanonicalName())) {
String key = parameter.getAnnotation(ColorAttr.class).value();
builder.addStatement("$T $N = $N.getColor(R.styleable.$L_$L, 0)", type, name, "typedArray", customViewElement.inputClassName, key);
} else if (annotation.toString().equals(DimenAttr.class.getCanonicalName())) {
String key = parameter.getAnnotation(DimenAttr.class).value();
builder.addStatement("$T $N = $N.getDimension(R.styleable.$L_$L, 0f)", type, name, "typedArray", customViewElement.inputClassName, key);
} else if (annotation.toString().equals(FloatAttr.class.getCanonicalName())) {
String key = parameter.getAnnotation(FloatAttr.class).value();
builder.addStatement("$T $N = $N.getFloat(R.styleable.$L_$L, 0f)", type, name, "typedArray", customViewElement.inputClassName, key);
} else if (annotation.toString().equals(StringAttr.class.getCanonicalName())) {
String key = parameter.getAnnotation(StringAttr.class).value();
builder.addStatement("$T $N = $N.getString(R.styleable.$L_$L)", type, name, "typedArray", customViewElement.inputClassName, key);
} else if (annotation.toString().equals(ReferenceAttr.class.getCanonicalName())) {
String key = parameter.getAnnotation(ReferenceAttr.class).value();
builder.addStatement("$T $N = $N.getResourceId(R.styleable.$L_$L, -1)", type, name, "typedArray", customViewElement.inputClassName, key);
}
if (i == 0) {
params += name;
} else {
params += ", " + name;
}
}
builder.addStatement("$N." + method.getSimpleName().toString() + "($L)", "target", params);
}
}
Loading

0 comments on commit 2291bc3

Please sign in to comment.