From a17feafba6799019912495f58d8eb52958c5819b Mon Sep 17 00:00:00 2001 From: Damien Date: Sun, 5 May 2013 22:45:50 +0200 Subject: [PATCH] Add an annotation to load default value for preferences from Android's resources --- .../sharedpreferences/DefaultRes.java | 36 +++++++++++ .../AndroidAnnotationProcessor.java | 2 +- .../helper/IdAnnotationHelper.java | 6 +- .../processing/SharedPrefProcessor.java | 56 +++++++++++++++--- .../functional-test-1-5/res/values/values.xml | 10 ++++ .../test15/prefs/SomePrefs.java | 14 ++++- .../test15/prefs/SomeResPrefs.java | 59 +++++++++++++++++++ 7 files changed, 173 insertions(+), 10 deletions(-) create mode 100644 AndroidAnnotations/androidannotations-api/src/main/java/org/androidannotations/annotations/sharedpreferences/DefaultRes.java create mode 100644 AndroidAnnotations/functional-test-1-5/res/values/values.xml create mode 100644 AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/prefs/SomeResPrefs.java diff --git a/AndroidAnnotations/androidannotations-api/src/main/java/org/androidannotations/annotations/sharedpreferences/DefaultRes.java b/AndroidAnnotations/androidannotations-api/src/main/java/org/androidannotations/annotations/sharedpreferences/DefaultRes.java new file mode 100644 index 0000000000..fc01673616 --- /dev/null +++ b/AndroidAnnotations/androidannotations-api/src/main/java/org/androidannotations/annotations/sharedpreferences/DefaultRes.java @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2010-2013 eBusiness Information, Excilys Group + * + * 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 org.androidannotations.annotations.sharedpreferences; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.androidannotations.annotations.ResId; + +/** + * Default value for a preference field + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.METHOD) +public @interface DefaultRes { + + int value() default ResId.DEFAULT_VALUE; + + String resName() default ""; + +} diff --git a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/AndroidAnnotationProcessor.java b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/AndroidAnnotationProcessor.java index f7fe918f3a..dfea823728 100644 --- a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/AndroidAnnotationProcessor.java +++ b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/AndroidAnnotationProcessor.java @@ -483,7 +483,7 @@ private ModelProcessor buildModelProcessor(IRClass rClass, AndroidSystemServices modelProcessor.register(new EViewGroupProcessor(processingEnv, rClass)); modelProcessor.register(new EViewProcessor()); modelProcessor.register(new EBeanProcessor()); - modelProcessor.register(new SharedPrefProcessor()); + modelProcessor.register(new SharedPrefProcessor(processingEnv, rClass)); modelProcessor.register(new PrefProcessor(validatedModel)); modelProcessor.register(new RoboGuiceProcessor()); modelProcessor.register(new ViewByIdProcessor(processingEnv, rClass)); diff --git a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/IdAnnotationHelper.java b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/IdAnnotationHelper.java index 95516ca108..af34c1606b 100644 --- a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/IdAnnotationHelper.java +++ b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/IdAnnotationHelper.java @@ -55,7 +55,11 @@ public List extractAnnotationFieldRefs(EBeanHolder holder, Element el } public JFieldRef extractOneAnnotationFieldRef(EBeanHolder holder, Element element, Res res, boolean useElementName) { - List jFieldRefs = extractAnnotationFieldRefs(holder, element, res, useElementName); + return extractOneAnnotationFieldRef(holder, element, getTarget(), res, useElementName); + } + + public JFieldRef extractOneAnnotationFieldRef(EBeanHolder holder, Element element, String annotationName, Res res, boolean useElementName) { + List jFieldRefs = extractAnnotationFieldRefs(holder, element, annotationName, rClass.get(res), useElementName); if (jFieldRefs.size() == 1) { return jFieldRefs.get(0); diff --git a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/SharedPrefProcessor.java b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/SharedPrefProcessor.java index 07b3bf9dd7..9ab16d3d37 100644 --- a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/SharedPrefProcessor.java +++ b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/SharedPrefProcessor.java @@ -19,12 +19,14 @@ import static com.sun.codemodel.JExpr.lit; import static com.sun.codemodel.JMod.PRIVATE; import static com.sun.codemodel.JMod.STATIC; +import static org.androidannotations.helper.CanonicalNameConstants.CONTEXT; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; @@ -34,6 +36,7 @@ import org.androidannotations.annotations.sharedpreferences.DefaultFloat; import org.androidannotations.annotations.sharedpreferences.DefaultInt; import org.androidannotations.annotations.sharedpreferences.DefaultLong; +import org.androidannotations.annotations.sharedpreferences.DefaultRes; import org.androidannotations.annotations.sharedpreferences.DefaultString; import org.androidannotations.annotations.sharedpreferences.SharedPref; import org.androidannotations.annotations.sharedpreferences.SharedPref.Scope; @@ -53,7 +56,10 @@ import org.androidannotations.api.sharedpreferences.StringPrefEditorField; import org.androidannotations.api.sharedpreferences.StringPrefField; import org.androidannotations.helper.CanonicalNameConstants; +import org.androidannotations.helper.IdAnnotationHelper; import org.androidannotations.helper.ModelConstants; +import org.androidannotations.rclass.IRClass; +import org.androidannotations.rclass.IRClass.Res; import com.sun.codemodel.ClassType; import com.sun.codemodel.JBlock; @@ -62,6 +68,8 @@ import com.sun.codemodel.JDefinedClass; import com.sun.codemodel.JExpr; import com.sun.codemodel.JExpression; +import com.sun.codemodel.JFieldRef; +import com.sun.codemodel.JFieldVar; import com.sun.codemodel.JMethod; import com.sun.codemodel.JMod; import com.sun.codemodel.JVar; @@ -89,6 +97,12 @@ public EditorFieldHolder(Class fieldClass, String fieldMethodName) { } }; + private final IdAnnotationHelper annotationHelper; + + public SharedPrefProcessor(ProcessingEnvironment processingEnv, IRClass rClass) { + annotationHelper = new IdAnnotationHelper(processingEnv, getTarget(), rClass); + } + @Override public String getTarget() { return SharedPref.class.getName(); @@ -96,7 +110,6 @@ public String getTarget() { @Override public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHolder) throws Exception { - generateApiClass(element, eBeansHolder); TypeElement typeElement = (TypeElement) element; @@ -105,7 +118,7 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo String helperQualifiedName = interfaceQualifiedName + ModelConstants.GENERATION_SUFFIX; JDefinedClass helperClass = codeModel._class(JMod.PUBLIC | JMod.FINAL, helperQualifiedName, ClassType.CLASS); - eBeansHolder.create(typeElement, SharedPref.class, helperClass); + EBeanHolder eBeanHolder = eBeansHolder.create(typeElement, SharedPref.class, helperClass); helperClass._extends(SharedPreferencesHelper.class); @@ -145,10 +158,9 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo Scope scope = sharedPrefAnnotation.value(); int mode = sharedPrefAnnotation.mode(); JMethod constructor = helperClass.constructor(JMod.PUBLIC); + JVar contextParam = constructor.param(contextClass, "context"); switch (scope) { case ACTIVITY_DEFAULT: { - - JVar contextParam = constructor.param(contextClass, "context"); JMethod getLocalClassName = getLocalClassName(eBeansHolder, helperClass, codeModel); constructor.body().invoke("super") // .arg(contextParam.invoke("getSharedPreferences") // @@ -157,7 +169,6 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo break; } case ACTIVITY: { - JVar contextParam = constructor.param(contextClass, "context"); JMethod getLocalClassName = getLocalClassName(eBeansHolder, helperClass, codeModel); constructor.body().invoke("super") // .arg(contextParam.invoke("getSharedPreferences") // @@ -167,7 +178,6 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo break; } case UNIQUE: { - JVar contextParam = constructor.param(contextClass, "context"); constructor.body() // .invoke("super") // .arg(contextParam.invoke("getSharedPreferences") // @@ -177,7 +187,6 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo } case APPLICATION_DEFAULT: { JClass preferenceManagerClass = eBeansHolder.refClass("android.preference.PreferenceManager"); - JVar contextParam = constructor.param(contextClass, "context"); constructor.body() // .invoke("super") // .arg(preferenceManagerClass.staticInvoke("getDefaultSharedPreferences") // @@ -186,6 +195,10 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo } } + // Context field + JFieldVar contextField = helperClass.field(JMod.PRIVATE, eBeansHolder.refClass(CONTEXT), "context"); + constructor.body().assign(JExpr._this().ref(contextField), contextParam); + // Helper edit method JMethod editMethod = helperClass.method(JMod.PUBLIC, editorClass, "edit"); editMethod.body()._return(JExpr._new(editorClass).arg(JExpr.invoke("getSharedPreferences"))); @@ -199,6 +212,8 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo DefaultBoolean defaultAnnotation = method.getAnnotation(DefaultBoolean.class); if (defaultAnnotation != null) { defaultValue = JExpr.lit(defaultAnnotation.value()); + } else if (method.getAnnotation(DefaultRes.class) != null) { + defaultValue = extractResValue(eBeanHolder, method, contextField, Res.BOOL); } else { defaultValue = JExpr.lit(false); } @@ -208,6 +223,8 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo DefaultFloat defaultAnnotation = method.getAnnotation(DefaultFloat.class); if (defaultAnnotation != null) { defaultValue = JExpr.lit(defaultAnnotation.value()); + } else if (method.getAnnotation(DefaultRes.class) != null) { + defaultValue = extractResValue(eBeanHolder, method, contextField, Res.INTEGER); } else { defaultValue = JExpr.lit(0f); } @@ -217,6 +234,8 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo DefaultInt defaultAnnotation = method.getAnnotation(DefaultInt.class); if (defaultAnnotation != null) { defaultValue = JExpr.lit(defaultAnnotation.value()); + } else if (method.getAnnotation(DefaultRes.class) != null) { + defaultValue = extractResValue(eBeanHolder, method, contextField, Res.INTEGER); } else { defaultValue = JExpr.lit(0); } @@ -226,6 +245,8 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo DefaultLong defaultAnnotation = method.getAnnotation(DefaultLong.class); if (defaultAnnotation != null) { defaultValue = JExpr.lit(defaultAnnotation.value()); + } else if (method.getAnnotation(DefaultRes.class) != null) { + defaultValue = extractResValue(eBeanHolder, method, contextField, Res.INTEGER); } else { defaultValue = JExpr.lit(0l); } @@ -235,13 +256,34 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo DefaultString defaultAnnotation = method.getAnnotation(DefaultString.class); if (defaultAnnotation != null) { defaultValue = JExpr.lit(defaultAnnotation.value()); + } else if (method.getAnnotation(DefaultRes.class) != null) { + defaultValue = extractResValue(eBeanHolder, method, contextField, Res.STRING); } else { defaultValue = JExpr.lit(""); } addFieldHelperMethod(helperClass, fieldName, defaultValue, StringPrefField.class, "stringField"); } } + } + private JExpression extractResValue(EBeanHolder eBeanHolder, Element method, JFieldVar contextField, Res res) { + JFieldRef idRef = annotationHelper.extractOneAnnotationFieldRef(eBeanHolder, method, DefaultRes.class.getCanonicalName(), res, true); + + String resourceGetMethodName = null; + switch (res) { + case BOOL: + resourceGetMethodName = "getBoolean"; + break; + case INTEGER: + resourceGetMethodName = "getInteger"; + break; + case STRING: + resourceGetMethodName = "getString"; + break; + default: + break; + } + return contextField.invoke("getResources").invoke(resourceGetMethodName).arg(idRef); } private void addFieldHelperMethod(JDefinedClass helperClass, String fieldName, JExpression defaultValue, Class prefFieldHelperClass, String fieldHelperMethodName) { diff --git a/AndroidAnnotations/functional-test-1-5/res/values/values.xml b/AndroidAnnotations/functional-test-1-5/res/values/values.xml new file mode 100644 index 0000000000..9878d22a60 --- /dev/null +++ b/AndroidAnnotations/functional-test-1-5/res/values/values.xml @@ -0,0 +1,10 @@ + + + + true + default pref + 42 + 4200 + 42 + + \ No newline at end of file diff --git a/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/prefs/SomePrefs.java b/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/prefs/SomePrefs.java index 9318edd56e..3e17a8a582 100644 --- a/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/prefs/SomePrefs.java +++ b/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/prefs/SomePrefs.java @@ -15,7 +15,10 @@ */ package org.androidannotations.test15.prefs; +import org.androidannotations.annotations.sharedpreferences.DefaultBoolean; +import org.androidannotations.annotations.sharedpreferences.DefaultFloat; import org.androidannotations.annotations.sharedpreferences.DefaultInt; +import org.androidannotations.annotations.sharedpreferences.DefaultLong; import org.androidannotations.annotations.sharedpreferences.DefaultString; import org.androidannotations.annotations.sharedpreferences.SharedPref; import org.androidannotations.annotations.sharedpreferences.SharedPref.Scope; @@ -25,9 +28,18 @@ public interface SomePrefs { @DefaultString("John") String name(); - + @DefaultInt(42) int age(); + + @DefaultLong(400000L) + long ageLong(); + + @DefaultFloat(42f) + float ageFloat(); + + @DefaultBoolean(true) + boolean isAwesome(); long lastUpdated(); diff --git a/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/prefs/SomeResPrefs.java b/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/prefs/SomeResPrefs.java new file mode 100644 index 0000000000..33182b2fc1 --- /dev/null +++ b/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/prefs/SomeResPrefs.java @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2010-2013 eBusiness Information, Excilys Group + * + * 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 org.androidannotations.test15.prefs; + +import org.androidannotations.annotations.sharedpreferences.DefaultRes; +import org.androidannotations.annotations.sharedpreferences.SharedPref; +import org.androidannotations.annotations.sharedpreferences.SharedPref.Scope; +import org.androidannotations.test15.R; + +@SharedPref(Scope.UNIQUE) +public interface SomeResPrefs { + + @DefaultRes + String prefDefaultString(); + + @DefaultRes(R.string.prefDefaultString) + String nameResId(); + + @DefaultRes(resName = "prefDefaultString") + String nameResName(); + + @DefaultRes + int prefDefaultInt(); + + @DefaultRes(R.integer.prefDefaultInt) + int ageResId(); + + @DefaultRes + long prefDefaultLong(); + + @DefaultRes(R.integer.prefDefaultLong) + long ageLongResId(); + + @DefaultRes + float prefDefaultFloat(); + + @DefaultRes(R.integer.prefDefaultFloat) + float ageFloatResId(); + + @DefaultRes + boolean prefsDefaultBool(); + + @DefaultRes(R.bool.prefsDefaultBool) + boolean isAwesomeResId(); + +}