From d4f72ee5eb85befc19ab173cbeeb5d82f9e2399f Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Fri, 26 Jul 2013 11:33:41 +0200 Subject: [PATCH 1/2] Fix IntentBuilder startForResult In a fragment, startActivityForResult must be called on the Fragment and not on getActivity(), or the fragment's onActivityResult will never be hit. Now IntentBuilder may have up to 3 constructors, depending on the classpath content. According to the constructor chosen, startActivityForResult will be called on Activity, android.app.Fragment or android.support.v4.app.Fragment. From the AA user perspective, this fix is quite transparent, he just have to call MyActivity_.intent(this), whatever he's in a Fragment or an Activity, it will work. --- .../helper/APTCodeModelHelper.java | 73 ++++++++++++++++++- .../efragment/StartActivityFragment.java | 12 +++ .../StartActivityFragmentSupport.java | 12 +++ 3 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/efragment/StartActivityFragment.java create mode 100644 AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/efragment/StartActivityFragmentSupport.java diff --git a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/APTCodeModelHelper.java b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/APTCodeModelHelper.java index e4ae3aa779..bda60ddc8e 100644 --- a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/APTCodeModelHelper.java +++ b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/APTCodeModelHelper.java @@ -324,6 +324,8 @@ public void addServiceIntentBuilder(JCodeModel codeModel, EBeanHolder holder) th private void addIntentBuilder(JCodeModel codeModel, EBeanHolder holder, boolean isActivity) throws JClassAlreadyExistsException { JClass contextClass = holder.classes().CONTEXT; JClass intentClass = holder.classes().INTENT; + JClass fragmentClass = holder.classes().FRAGMENT; + JClass fragmentSupportClass = holder.classes().SUPPORT_V4_FRAGMENT; { holder.intentBuilderClass = holder.generatedClass._class(PUBLIC | STATIC, "IntentBuilder_"); @@ -339,6 +341,29 @@ private void addIntentBuilder(JCodeModel codeModel, EBeanHolder holder, boolean constructorBody.assign(contextField, constructorContextParam); constructorBody.assign(holder.intentField, _new(intentClass).arg(constructorContextParam).arg(holder.generatedClass.dotclass())); } + // Additional constructor for fragments (issue #541) + boolean fragmentInClasspath = true; + try { + Class.forName(fragmentClass.fullName(), false, getClass().getClassLoader()); + } catch (ClassNotFoundException e) { + fragmentInClasspath = false; + + } + boolean fragmentSupportInClasspath = true; + try { + Class.forName(fragmentSupportClass.fullName(), false, getClass().getClassLoader()); + } catch (ClassNotFoundException e) { + fragmentSupportInClasspath = false; + + } + JFieldVar fragmentField = null; + if (fragmentInClasspath) { + fragmentField = addIntentBuilderFragmentConstructor(holder, holder.classes().FRAGMENT, "fragment_", contextField); + } + JFieldVar fragmentSupportField = null; + if (fragmentSupportInClasspath) { + fragmentSupportField = addIntentBuilderFragmentConstructor(holder, holder.classes().SUPPORT_V4_FRAGMENT, "fragmentSupport_", contextField); + } { // get() @@ -366,7 +391,27 @@ private void addIntentBuilder(JCodeModel codeModel, EBeanHolder holder, boolean JBlock body = method.body(); JClass activityClass = holder.classes().ACTIVITY; - JConditional condition = body._if(contextField._instanceof(activityClass)); + + JConditional condition = null; + if (fragmentSupportField != null) { + condition = body._if(fragmentSupportField.ne(JExpr._null())); + condition._then() // + .invoke(fragmentSupportField, "startActivityForResult").arg(holder.intentField).arg(requestCode); + } + if (fragmentField != null) { + if (condition == null) { + condition = body._if(fragmentField.ne(JExpr._null())); + } else { + condition = condition._elseif(fragmentField.ne(JExpr._null())); + } + condition._then() // + .invoke(fragmentField, "startActivityForResult").arg(holder.intentField).arg(requestCode); + } + if (condition == null) { + condition = body._if(contextField._instanceof(activityClass)); + } else { + condition = condition._elseif(contextField._instanceof(activityClass)); + } condition._then() // .invoke(JExpr.cast(activityClass, contextField), "startActivityForResult").arg(holder.intentField).arg(requestCode); condition._else() // @@ -382,11 +427,35 @@ private void addIntentBuilder(JCodeModel codeModel, EBeanHolder holder, boolean } { - // intent() + // intent() with activity param JMethod method = holder.generatedClass.method(STATIC | PUBLIC, holder.intentBuilderClass, "intent"); JVar contextParam = method.param(contextClass, "context"); method.body()._return(_new(holder.intentBuilderClass).arg(contextParam)); } + if (fragmentInClasspath) { + // intent() with android.app.Fragment param + JMethod method = holder.generatedClass.method(STATIC | PUBLIC, holder.intentBuilderClass, "intent"); + JVar fragmentParam = method.param(fragmentClass, "fragment"); + method.body()._return(_new(holder.intentBuilderClass).arg(fragmentParam)); + } + if (fragmentSupportInClasspath) { + // intent() with android.support.v4.app.Fragment param + JMethod method = holder.generatedClass.method(STATIC | PUBLIC, holder.intentBuilderClass, "intent"); + JVar fragmentParam = method.param(fragmentSupportClass, "fragment"); + method.body()._return(_new(holder.intentBuilderClass).arg(fragmentParam)); + } } } + + private JFieldVar addIntentBuilderFragmentConstructor(EBeanHolder holder, JClass fragmentClass, String fieldName, JFieldVar contextField) { + + JFieldVar fragmentField = holder.intentBuilderClass.field(PRIVATE, fragmentClass, fieldName); + JMethod constructor = holder.intentBuilderClass.constructor(JMod.PUBLIC); + JVar constructorFragmentParam = constructor.param(fragmentClass, "fragment"); + JBlock constructorBody = constructor.body(); + constructorBody.assign(fragmentField, constructorFragmentParam); + constructorBody.assign(contextField, constructorFragmentParam.invoke("getActivity")); + constructorBody.assign(holder.intentField, _new(holder.classes().INTENT).arg(contextField).arg(holder.generatedClass.dotclass())); + return fragmentField; + } } diff --git a/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/efragment/StartActivityFragment.java b/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/efragment/StartActivityFragment.java new file mode 100644 index 0000000000..6095d6de83 --- /dev/null +++ b/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/efragment/StartActivityFragment.java @@ -0,0 +1,12 @@ +package org.androidannotations.test15.efragment; + +import android.app.Fragment; +import org.androidannotations.annotations.EFragment; +import org.androidannotations.test15.ExtraInjectedActivity_; + +@EFragment +public class StartActivityFragment extends Fragment { + void startActivity() { + ExtraInjectedActivity_.intent(this).start(); + } +} diff --git a/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/efragment/StartActivityFragmentSupport.java b/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/efragment/StartActivityFragmentSupport.java new file mode 100644 index 0000000000..494758e022 --- /dev/null +++ b/AndroidAnnotations/functional-test-1-5/src/main/java/org/androidannotations/test15/efragment/StartActivityFragmentSupport.java @@ -0,0 +1,12 @@ +package org.androidannotations.test15.efragment; + +import android.support.v4.app.Fragment; +import org.androidannotations.annotations.EFragment; +import org.androidannotations.test15.ExtraInjectedActivity_; + +@EFragment +public class StartActivityFragmentSupport extends Fragment { + void startActivity() { + ExtraInjectedActivity_.intent(this).start(); + } +} From 1239f624969cf725c2315fafd3e5bec8ca286ba7 Mon Sep 17 00:00:00 2001 From: Thomas Bruyelle Date: Tue, 3 Sep 2013 10:47:25 +0200 Subject: [PATCH 2/2] Use new method to check class in classpath --- .../AndroidAnnotationProcessor.java | 2 +- .../helper/APTCodeModelHelper.java | 31 +++++++------------ .../processing/EActivityProcessor.java | 2 +- .../processing/EServiceProcessor.java | 9 ++++-- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/AndroidAnnotationProcessor.java b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/AndroidAnnotationProcessor.java index 0dbd8534df..f5ca43c013 100644 --- a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/AndroidAnnotationProcessor.java +++ b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/AndroidAnnotationProcessor.java @@ -487,7 +487,7 @@ private ModelProcessor buildModelProcessor(IRClass rClass, AndroidSystemServices ModelProcessor modelProcessor = new ModelProcessor(); modelProcessor.register(new EApplicationProcessor()); modelProcessor.register(new EActivityProcessor(processingEnv, rClass)); - modelProcessor.register(new EServiceProcessor()); + modelProcessor.register(new EServiceProcessor(processingEnv)); modelProcessor.register(new EReceiverProcessor()); modelProcessor.register(new EProviderProcessor()); modelProcessor.register(new EFragmentProcessor(processingEnv, rClass)); diff --git a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/APTCodeModelHelper.java b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/APTCodeModelHelper.java index bda60ddc8e..659fe3d1b3 100644 --- a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/APTCodeModelHelper.java +++ b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/helper/APTCodeModelHelper.java @@ -35,6 +35,7 @@ import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.WildcardType; +import javax.lang.model.util.Elements; import org.androidannotations.processing.EBeanHolder; import org.androidannotations.processing.EBeansHolder.Classes; @@ -313,15 +314,15 @@ public JVar findParameterByName(JMethod method, String name) { return null; } - public void addActivityIntentBuilder(JCodeModel codeModel, EBeanHolder holder) throws Exception { - addIntentBuilder(codeModel, holder, true); + public void addActivityIntentBuilder(JCodeModel codeModel, EBeanHolder holder, AnnotationHelper annotationHelper) throws Exception { + addIntentBuilder(codeModel, holder, annotationHelper, true); } - public void addServiceIntentBuilder(JCodeModel codeModel, EBeanHolder holder) throws Exception { - addIntentBuilder(codeModel, holder, false); + public void addServiceIntentBuilder(JCodeModel codeModel, EBeanHolder holder, AnnotationHelper annotationHelper) throws Exception { + addIntentBuilder(codeModel, holder, annotationHelper, false); } - private void addIntentBuilder(JCodeModel codeModel, EBeanHolder holder, boolean isActivity) throws JClassAlreadyExistsException { + private void addIntentBuilder(JCodeModel codeModel, EBeanHolder holder, AnnotationHelper annotationHelper, boolean isActivity) throws JClassAlreadyExistsException { JClass contextClass = holder.classes().CONTEXT; JClass intentClass = holder.classes().INTENT; JClass fragmentClass = holder.classes().FRAGMENT; @@ -342,27 +343,17 @@ private void addIntentBuilder(JCodeModel codeModel, EBeanHolder holder, boolean constructorBody.assign(holder.intentField, _new(intentClass).arg(constructorContextParam).arg(holder.generatedClass.dotclass())); } // Additional constructor for fragments (issue #541) - boolean fragmentInClasspath = true; - try { - Class.forName(fragmentClass.fullName(), false, getClass().getClassLoader()); - } catch (ClassNotFoundException e) { - fragmentInClasspath = false; + Elements elementUtils = annotationHelper.getElementUtils(); + boolean fragmentInClasspath = elementUtils.getTypeElement(CanonicalNameConstants.FRAGMENT) != null; + boolean fragmentSupportInClasspath = elementUtils.getTypeElement(CanonicalNameConstants.SUPPORT_V4_FRAGMENT) != null; - } - boolean fragmentSupportInClasspath = true; - try { - Class.forName(fragmentSupportClass.fullName(), false, getClass().getClassLoader()); - } catch (ClassNotFoundException e) { - fragmentSupportInClasspath = false; - - } JFieldVar fragmentField = null; if (fragmentInClasspath) { - fragmentField = addIntentBuilderFragmentConstructor(holder, holder.classes().FRAGMENT, "fragment_", contextField); + fragmentField = addIntentBuilderFragmentConstructor(holder, fragmentClass, "fragment_", contextField); } JFieldVar fragmentSupportField = null; if (fragmentSupportInClasspath) { - fragmentSupportField = addIntentBuilderFragmentConstructor(holder, holder.classes().SUPPORT_V4_FRAGMENT, "fragmentSupport_", contextField); + fragmentSupportField = addIntentBuilderFragmentConstructor(holder, fragmentSupportClass, "fragmentSupport_", contextField); } { diff --git a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/EActivityProcessor.java b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/EActivityProcessor.java index 9c8ecb720f..5bc76c956b 100644 --- a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/EActivityProcessor.java +++ b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/EActivityProcessor.java @@ -201,7 +201,7 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo } - aptCodeModelHelper.addActivityIntentBuilder(codeModel, holder); + aptCodeModelHelper.addActivityIntentBuilder(codeModel, holder, annotationHelper); } diff --git a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/EServiceProcessor.java b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/EServiceProcessor.java index 8b33bf5e09..00c5aa53a4 100644 --- a/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/EServiceProcessor.java +++ b/AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/EServiceProcessor.java @@ -20,11 +20,13 @@ import static com.sun.codemodel.JMod.PRIVATE; import static com.sun.codemodel.JMod.PUBLIC; +import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import org.androidannotations.annotations.EService; import org.androidannotations.helper.APTCodeModelHelper; +import org.androidannotations.helper.AnnotationHelper; import org.androidannotations.helper.ModelConstants; import com.sun.codemodel.ClassType; @@ -39,8 +41,11 @@ public class EServiceProcessor implements GeneratingElementProcessor { private final APTCodeModelHelper aptCodeModelHelper; - public EServiceProcessor() { + private final AnnotationHelper annotationHelper; + + public EServiceProcessor(ProcessingEnvironment processingEnv) { aptCodeModelHelper = new APTCodeModelHelper(); + annotationHelper = new AnnotationHelper(processingEnv); } @Override @@ -88,7 +93,7 @@ public void process(Element element, JCodeModel codeModel, EBeansHolder eBeansHo holder.initActivityRef = null; } - aptCodeModelHelper.addServiceIntentBuilder(codeModel, holder); + aptCodeModelHelper.addServiceIntentBuilder(codeModel, holder, annotationHelper); }