├── .gitignore ├── .gitmodules ├── .project ├── .settings └── org.eclipse.m2e.core.prefs ├── README.md ├── assets ├── android_smell.png └── android_smell.psd ├── cleanandroidcode-it ├── .classpath ├── .project ├── .settings │ ├── org.eclipse.core.resources.prefs │ ├── org.eclipse.jdt.core.prefs │ └── org.eclipse.m2e.core.prefs ├── AndroidManifest.xml ├── pom.xml ├── project.properties └── src │ └── main │ └── java │ └── info │ └── piwai │ └── cleanandroidcode │ └── HelloAndroidActivityTest.java ├── cleanandroidcode-processor ├── .classpath ├── .project ├── .settings │ ├── org.eclipse.core.resources.prefs │ ├── org.eclipse.jdt.core.prefs │ └── org.eclipse.m2e.core.prefs ├── pom.xml └── src │ └── main │ ├── java │ └── info │ │ └── piwai │ │ └── cleanandroidcode │ │ └── DaggerAAIntegrationProcessor.java │ └── resources │ └── META-INF │ └── services │ └── javax.annotation.processing.Processor ├── cleanandroidcode ├── .classpath ├── .factorypath ├── .project ├── .settings │ ├── org.eclipse.core.resources.prefs │ ├── org.eclipse.jdt.apt.core.prefs │ ├── org.eclipse.jdt.core.prefs │ └── org.eclipse.m2e.core.prefs ├── AndroidManifest.xml ├── pom.xml ├── project.properties ├── res │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ ├── layout │ │ ├── hello_activity.xml │ │ └── hello_fragment.xml │ └── values │ │ └── strings.xml └── src │ └── main │ └── java │ └── info │ └── piwai │ └── cleanandroidcode │ ├── HelloAndroidActivity.java │ ├── HelloApplication.java │ ├── HelloFragment.java │ ├── UpdateTitleEvent.java │ └── base │ ├── BaseActivity.java │ ├── BaseFragment.java │ ├── BaseModule.java │ └── GraphRetriever.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | bin 3 | gen 4 | .apt_generated 5 | .DS_Store 6 | *.idea 7 | *.iml 8 | *.ipr 9 | *.iws 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "otto"] 2 | path = otto 3 | url = git@github.com:pyricau/otto.git 4 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | cleanandroidcode-parent 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.m2e.core.maven2Builder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.m2e.core.maven2Nature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ALL YOUR LIB ARE BELONG TO US 2 | 3 | ![Code Smell](https://raw.github.com/pyricau/CleanAndroidCode/master/assets/android_smell.png) 4 | 5 | ## Introduction 6 | 7 | This project is a proof of concept to show how to integrate [Dagger](http://square.github.com/dagger/), [Otto](http://square.github.com/otto/) and [AndroidAnnotations](http://androidannotations.org). 8 | 9 | We can benefit from all those librairies to write Android apps that are both easy to maintain and lightning fast. 10 | 11 | Here is what the result looks like: 12 | 13 | ```java 14 | @EActivity(R.layout.hello_activity) 15 | public class HelloAndroidActivity extends BaseActivity { 16 | 17 | @Subscribe 18 | public void onUpdateTitle(UpdateTitleEvent event) { 19 | setTitle(event.title); 20 | } 21 | 22 | } 23 | ``` 24 | 25 | ```java 26 | @EFragment(R.layout.hello_fragment) 27 | public class HelloFragment extends BaseFragment { 28 | 29 | @Inject 30 | Bus bus; 31 | 32 | @Click 33 | void fragmentButtonClicked() { 34 | bus.post(new UpdateTitleEvent("Button clicked")); 35 | } 36 | } 37 | ``` 38 | 39 | This project contains only a few classes, go and read the source! 40 | 41 | ## Building and running 42 | 43 | ### Command line 44 | 45 | Here is how to build this project from the command line. 46 | 47 | * First, make sure you have a device plugged in so that the integration tests can run. 48 | * Then you just need to run the following commands: 49 | 50 | ```bash 51 | git clone git@github.com:pyricau/CleanAndroidCode.git 52 | cd CleanAndroidCode 53 | git submodule init 54 | git submodule update 55 | # We use a custom version of Otto, see below 56 | cd otto 57 | mvn clean install -DskipTests 58 | cd .. 59 | # Build, install on device and run the integration tests 60 | mvn clean install 61 | ``` 62 | 63 | ### Eclipse 64 | 65 | This project compiles and runs fine on Eclipse Juno. I have commited all the configuration files to make sure you do not spend time configuring it. You should be able to import everything "as maven projects". 66 | 67 | > I haven't tried with IntelliJ, but since everybody keeps telling me how good this IDE is, I assume everything will work perfectly fine :) . 68 | 69 | ## Gotchas 70 | 71 | ### Dagger & AndroidAnnotations 72 | 73 | Dagger requires the definition of entry points on an `@Module` annotation. These entry points are our activities and fragments, created by the system. 74 | 75 | When using both Dagger & AndroidAnnotations, one obvious configuration would be: 76 | 77 | ```java 78 | @Module( 79 | entryPoints = { 80 | HelloFragment_.class, 81 | HelloAndroidActivity_.class, 82 | }, 83 | complete = false 84 | ) 85 | public class EntryPointsModule { 86 | } 87 | ``` 88 | 89 | However, this cannot work directly when doing a full build. Even when you take care of the processor order so that you run AndroidAnnotations first and then Dagger, they run both in the same round, so the classes generated by AndroidAnnotations are not compiled yet when Dagger runs. The `@Module` annotation therefore references an unknown class. 90 | 91 | This can be solved by having an extra annotation processor that generates this module at compile time. The module is picked up by Dagger on a second round, where the generated classes are compiled and therefore available. 92 | 93 | This extra annotation processor is the `cleanandroidcode-processor` project. 94 | 95 | Since this processor creates one class out of several annotations, it needs a caching mechanism to handle Eclipse incremental compiler. 96 | 97 | Check out the [DaggerAAIntegrationProcessor](https://github.com/pyricau/CleanAndroidCode/blob/master/cleanandroidcode-processor/src/main/java/info/piwai/cleanandroidcode/DaggerAAIntegrationProcessor.java) to learn more about this processor. 98 | 99 | ### Otto & AndroidAnnotations 100 | 101 | Unlike its Guava sister, Otto doesn't look for `@Produce` and `@Subscribe` annotations through the class hierarchy for performance reasons. 102 | 103 | However, there is a custom version of Otto that replaces reflection with annotation processing and code generation. 104 | It is a proof of concept from [Jake Wharton](https://github.com/JakeWharton), available on [this branch](https://github.com/square/otto/tree/code-gen) on the Square Otto repo. 105 | 106 | ## Questions? 107 | 108 | Any question? Create a [new issue](https://github.com/pyricau/CleanAndroidCode/issues/new) or ask [@Piwai](http://twitter.com/piwai). 109 | -------------------------------------------------------------------------------- /assets/android_smell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/assets/android_smell.png -------------------------------------------------------------------------------- /assets/android_smell.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/assets/android_smell.psd -------------------------------------------------------------------------------- /cleanandroidcode-it/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /cleanandroidcode-it/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | cleanandroidcode-it 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | 35 | com.android.ide.eclipse.adt.AndroidNature 36 | org.eclipse.jdt.core.javanature 37 | org.eclipse.m2e.core.maven2Nature 38 | 39 | 40 | -------------------------------------------------------------------------------- /cleanandroidcode-it/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding//src/test/java=UTF-8 4 | encoding/=UTF-8 5 | -------------------------------------------------------------------------------- /cleanandroidcode-it/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 5 | org.eclipse.jdt.core.compiler.source=1.6 6 | -------------------------------------------------------------------------------- /cleanandroidcode-it/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /cleanandroidcode-it/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 14 | 15 | 16 | 17 | 20 | 21 | -------------------------------------------------------------------------------- /cleanandroidcode-it/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | info.piwai.cleanandroidcode 8 | cleanandroidcode-parent 9 | 1.0-SNAPSHOT 10 | 11 | 12 | cleanandroidcode-it 13 | apk 14 | cleanandroidcode-it - Integration tests 15 | 16 | 17 | 18 | com.google.android 19 | android 20 | 21 | 22 | com.google.android 23 | android-test 24 | 25 | 26 | info.piwai.cleanandroidcode 27 | cleanandroidcode 28 | apk 29 | 30 | 31 | info.piwai.cleanandroidcode 32 | cleanandroidcode 33 | jar 34 | 35 | 36 | 37 | 38 | 39 | com.jayway.maven.plugins.android.generation2 40 | android-maven-plugin 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /cleanandroidcode-it/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-16 15 | -------------------------------------------------------------------------------- /cleanandroidcode-it/src/main/java/info/piwai/cleanandroidcode/HelloAndroidActivityTest.java: -------------------------------------------------------------------------------- 1 | package info.piwai.cleanandroidcode; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentActivity; 5 | import android.test.ActivityInstrumentationTestCase2; 6 | import android.test.UiThreadTest; 7 | import android.view.View; 8 | 9 | public class HelloAndroidActivityTest extends ActivityInstrumentationTestCase2 { 10 | 11 | public HelloAndroidActivityTest() { 12 | super(HelloAndroidActivity_.class); 13 | } 14 | 15 | @UiThreadTest 16 | public void test_click_on_fragment_changes_title() { 17 | FragmentActivity activity = getActivity(); 18 | Fragment fragment = activity.getSupportFragmentManager().findFragmentById(R.id.hello_fragment); 19 | View fragmentButton = fragment.getView().findViewById(R.id.fragment_button); 20 | 21 | fragmentButton.performClick(); 22 | 23 | String title = activity.getTitle().toString(); 24 | 25 | assertTrue("Title should start with [Button clicked]. Title is [" + title + "]", title.startsWith("Button clicked")); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /cleanandroidcode-processor/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /cleanandroidcode-processor/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | cleanandroidcode-processor 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | -------------------------------------------------------------------------------- /cleanandroidcode-processor/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding//src/main/resources=UTF-8 4 | encoding//src/test/java=UTF-8 5 | encoding/=UTF-8 6 | -------------------------------------------------------------------------------- /cleanandroidcode-processor/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 5 | org.eclipse.jdt.core.compiler.source=1.6 6 | -------------------------------------------------------------------------------- /cleanandroidcode-processor/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /cleanandroidcode-processor/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | cleanandroidcode-parent 9 | info.piwai.cleanandroidcode 10 | 1.0-SNAPSHOT 11 | 12 | 13 | cleanandroidcode-processor 14 | CleanAndroidCode Annotation Processor 15 | 16 | 17 | 18 | 19 | maven-compiler-plugin 20 | 21 | -proc:none 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /cleanandroidcode-processor/src/main/java/info/piwai/cleanandroidcode/DaggerAAIntegrationProcessor.java: -------------------------------------------------------------------------------- 1 | package info.piwai.cleanandroidcode; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.IOException; 6 | import java.io.PrintWriter; 7 | import java.io.StringWriter; 8 | import java.util.Collections; 9 | import java.util.HashSet; 10 | import java.util.List; 11 | import java.util.Set; 12 | 13 | import javax.annotation.processing.AbstractProcessor; 14 | import javax.annotation.processing.Filer; 15 | import javax.annotation.processing.Messager; 16 | import javax.annotation.processing.ProcessingEnvironment; 17 | import javax.annotation.processing.RoundEnvironment; 18 | import javax.annotation.processing.SupportedAnnotationTypes; 19 | import javax.annotation.processing.SupportedSourceVersion; 20 | import javax.lang.model.SourceVersion; 21 | import javax.lang.model.element.AnnotationMirror; 22 | import javax.lang.model.element.Element; 23 | import javax.lang.model.element.TypeElement; 24 | import javax.lang.model.util.ElementFilter; 25 | import javax.lang.model.util.Elements; 26 | import javax.tools.Diagnostic; 27 | import javax.tools.FileObject; 28 | import javax.tools.JavaFileManager; 29 | import javax.tools.JavaFileObject; 30 | import javax.tools.StandardLocation; 31 | 32 | @SupportedSourceVersion(SourceVersion.RELEASE_6) 33 | @SupportedAnnotationTypes({ 34 | /* 35 | * Only supports @EActivity and @EFragment, since this is just a proof of 36 | * concept. This can be extended quite easily though. 37 | */ 38 | // 39 | "com.googlecode.androidannotations.annotations.EActivity", // 40 | "com.googlecode.androidannotations.annotations.EFragment", // 41 | }) 42 | public class DaggerAAIntegrationProcessor extends AbstractProcessor { 43 | 44 | private static final String CACHE_PACKAGE_NAME = ""; 45 | private static final String CACHE_FILE_NAME = "DaggerAAIntegrationCache.txt"; 46 | 47 | /** 48 | * We us this to avoid opening files twice in different rounds of the same 49 | * processing, because it otherwhise fails. We shouldn't do this, but rather 50 | * collect instructions on what we should do and output the module in the 51 | * last round. 52 | */ 53 | boolean alreadyProcessed = false; 54 | 55 | @Override 56 | public synchronized void init(ProcessingEnvironment processingEnv) { 57 | super.init(processingEnv); 58 | Messager messager = processingEnv.getMessager(); 59 | messager.printMessage(Diagnostic.Kind.NOTE, "Init of DaggerAAIntegrationProcessor"); 60 | } 61 | 62 | @Override 63 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 64 | 65 | if (!alreadyProcessed) { 66 | Set annotatedElements = getAnnotatedElements(roundEnv); 67 | 68 | generateDaggerModule(annotatedElements); 69 | 70 | cacheAnnotatedElements(annotatedElements); 71 | alreadyProcessed = true; 72 | } 73 | 74 | return false; 75 | } 76 | 77 | private Set getAnnotatedElements(RoundEnvironment roundEnv) { 78 | Set annotationTypeElements = getAnnotationTypeElements(); 79 | 80 | Set roundAnnotatedElements = getRoundAnnotatedElements(roundEnv, annotationTypeElements); 81 | 82 | Set cachedElements = loadCachedAnnotatedElement(roundAnnotatedElements); 83 | 84 | Set cachedAnnotatedElements = filterAnnotatedElements(cachedElements, annotationTypeElements); 85 | 86 | Set annotatedElements = new HashSet(); 87 | annotatedElements.addAll(roundAnnotatedElements); 88 | annotatedElements.addAll(cachedAnnotatedElements); 89 | return annotatedElements; 90 | } 91 | 92 | private Set filterAnnotatedElements(Set typeElements, Set annotationTypeElements) { 93 | Set annotatedTypeElements = new HashSet(); 94 | 95 | for (TypeElement typeElement : typeElements) { 96 | List annotationMirrors = typeElement.getAnnotationMirrors(); 97 | boolean typeElementIsAnnotated = false; 98 | for (AnnotationMirror annotationMirror : annotationMirrors) { 99 | Element annotationElement = annotationMirror.getAnnotationType().asElement(); 100 | if (annotationElement instanceof TypeElement) { 101 | TypeElement annotationTypeElement = (TypeElement) annotationElement; 102 | if (annotationTypeElements.contains(annotationTypeElement)) { 103 | typeElementIsAnnotated = true; 104 | break; 105 | } 106 | } else { 107 | reportNote(typeElement + " is annotated with an annotation element " + annotationElement + " that is not a TypeElement"); 108 | } 109 | } 110 | if (typeElementIsAnnotated) { 111 | annotatedTypeElements.add(typeElement); 112 | } else { 113 | reportNote("Cached element " + typeElement + " is not annotated any more"); 114 | } 115 | } 116 | 117 | return annotatedTypeElements; 118 | } 119 | 120 | private Set getAnnotationTypeElements() { 121 | Set annotationQualifiedNames = getSupportedAnnotationTypes(); 122 | Set annotationTypeElements = new HashSet(); 123 | Elements elementUtils = processingEnv.getElementUtils(); 124 | for (String annotationQualifiedName : annotationQualifiedNames) { 125 | TypeElement annotationTypeElement = elementUtils.getTypeElement(annotationQualifiedName); 126 | if (annotationTypeElement != null) { 127 | annotationTypeElements.add(annotationTypeElement); 128 | } else { 129 | reportError("Could not find annotation type element for " + annotationQualifiedName); 130 | } 131 | } 132 | return annotationTypeElements; 133 | } 134 | 135 | private Set getRoundAnnotatedElements(RoundEnvironment roundEnv, Set annotationTypeElements) { 136 | Set annotatedElements = new HashSet(); 137 | for (TypeElement annotationTypeElement : annotationTypeElements) { 138 | Set elementsAnnotatedWithAnnotation = roundEnv.getElementsAnnotatedWith(annotationTypeElement); 139 | Set typesAnnotatedWithAnnotation = ElementFilter.typesIn(elementsAnnotatedWithAnnotation); 140 | annotatedElements.addAll(typesAnnotatedWithAnnotation); 141 | } 142 | return annotatedElements; 143 | } 144 | 145 | /** 146 | * 147 | * @param roundAnnotatedElements 148 | * the annotated elements found in the current round will not be 149 | * loaded 150 | */ 151 | private Set loadCachedAnnotatedElement(Set roundAnnotatedElements) { 152 | JavaFileManager.Location location = StandardLocation.SOURCE_OUTPUT; 153 | Filer filer = processingEnv.getFiler(); 154 | try { 155 | FileObject resource = filer.getResource(location, CACHE_PACKAGE_NAME, CACHE_FILE_NAME); 156 | final boolean IGNORE_ENCODING_ERRORS = true; 157 | BufferedReader reader = new BufferedReader(resource.openReader(IGNORE_ENCODING_ERRORS)); 158 | Elements elementUtils = processingEnv.getElementUtils(); 159 | HashSet cachedAnnotatedTypeElements = new HashSet(); 160 | String annotatedElementQualifiedName; 161 | while ((annotatedElementQualifiedName = reader.readLine()) != null) { 162 | if (annotatedElementQualifiedName.startsWith("#")) { 163 | continue; 164 | } 165 | TypeElement annotatedTypeElement = elementUtils.getTypeElement(annotatedElementQualifiedName); 166 | if (annotatedTypeElement != null) { 167 | if (!roundAnnotatedElements.contains(annotatedTypeElement)) { 168 | cachedAnnotatedTypeElements.add(annotatedTypeElement); 169 | } 170 | } else { 171 | reportNote("Could not find cached annotated type element for " + annotatedTypeElement); 172 | } 173 | } 174 | reader.close(); 175 | return cachedAnnotatedTypeElements; 176 | } catch (Exception e) { 177 | reportNote("Could not load annotated elements cache (fine in case of full build)", e); 178 | return Collections.emptySet(); 179 | } 180 | } 181 | 182 | private void generateDaggerModule(Set annotatedElements) { 183 | reportNote("Entry points found: " + annotatedElements); 184 | Filer filer = processingEnv.getFiler(); 185 | try { 186 | String packageName = "info.piwai.cleanandroidcode"; 187 | String moduleClassName = "EntryPointsModule"; 188 | JavaFileObject sourceFile = filer.createSourceFile(packageName + "." + moduleClassName); 189 | BufferedWriter writer = new BufferedWriter(sourceFile.openWriter()); 190 | writer.write("package " + packageName + ";"); 191 | writer.newLine(); 192 | writer.write("import dagger.Module;"); 193 | writer.newLine(); 194 | writer.write("@Module("); 195 | writer.newLine(); 196 | writer.write(" entryPoints = {"); 197 | writer.newLine(); 198 | 199 | for (TypeElement typeElement : annotatedElements) { 200 | String qualifiedName = typeElement.getQualifiedName().toString(); 201 | String aaGeneratedQualifiedName = qualifiedName + "_"; 202 | writer.write(" " + aaGeneratedQualifiedName + ".class,"); 203 | writer.newLine(); 204 | } 205 | 206 | writer.write(" },"); 207 | writer.newLine(); 208 | writer.write(" complete = false"); 209 | writer.newLine(); 210 | writer.write(")"); 211 | writer.newLine(); 212 | writer.write("public final class " + moduleClassName + " {"); 213 | writer.newLine(); 214 | writer.write("}"); 215 | writer.newLine(); 216 | writer.close(); 217 | } catch (IOException e) { 218 | reportNote("Could not generate Dagger module", e); 219 | } 220 | } 221 | 222 | private void cacheAnnotatedElements(Set annotatedElements) { 223 | try { 224 | TypeElement[] annotatedElementsArray = annotatedElements.toArray(new TypeElement[0]); 225 | 226 | JavaFileManager.Location location = StandardLocation.SOURCE_OUTPUT; 227 | Filer filer = processingEnv.getFiler(); 228 | FileObject resource = filer.createResource(location, CACHE_PACKAGE_NAME, CACHE_FILE_NAME, annotatedElementsArray); 229 | 230 | BufferedWriter writer = new BufferedWriter(resource.openWriter()); 231 | writer.write("# This file has been generated, please do not edit it"); 232 | writer.newLine(); 233 | for (TypeElement element : annotatedElements) { 234 | writer.write(element.getQualifiedName().toString()); 235 | writer.newLine(); 236 | } 237 | writer.close(); 238 | } catch (IOException e) { 239 | reportNote("Could not cache annotated elements " + annotatedElements.toString() + " (fine in case of full build)", e); 240 | } 241 | } 242 | 243 | private void reportError(String message) { 244 | processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message); 245 | } 246 | 247 | private void reportNote(String message) { 248 | processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message); 249 | } 250 | 251 | private void reportNote(String message, Throwable throwable) { 252 | processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message + "\nException:\n" + stackTraceToString(throwable)); 253 | } 254 | 255 | private String stackTraceToString(Throwable throwable) { 256 | StringWriter writer = new StringWriter(); 257 | PrintWriter pw = new PrintWriter(writer); 258 | throwable.printStackTrace(pw); 259 | return writer.toString(); 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /cleanandroidcode-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor: -------------------------------------------------------------------------------- 1 | info.piwai.cleanandroidcode.DaggerAAIntegrationProcessor -------------------------------------------------------------------------------- /cleanandroidcode/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /cleanandroidcode/.factorypath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /cleanandroidcode/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | cleanandroidcode 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | 35 | com.android.ide.eclipse.adt.AndroidNature 36 | org.eclipse.jdt.core.javanature 37 | org.eclipse.m2e.core.maven2Nature 38 | 39 | 40 | -------------------------------------------------------------------------------- /cleanandroidcode/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding//src/test/java=UTF-8 4 | encoding/=UTF-8 5 | -------------------------------------------------------------------------------- /cleanandroidcode/.settings/org.eclipse.jdt.apt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.apt.aptEnabled=true 3 | org.eclipse.jdt.apt.genSrcDir=.apt_generated 4 | org.eclipse.jdt.apt.reconcileEnabled=true 5 | -------------------------------------------------------------------------------- /cleanandroidcode/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.6 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 12 | org.eclipse.jdt.core.compiler.processAnnotations=enabled 13 | org.eclipse.jdt.core.compiler.source=1.6 14 | -------------------------------------------------------------------------------- /cleanandroidcode/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /cleanandroidcode/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /cleanandroidcode/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | info.piwai.cleanandroidcode 8 | cleanandroidcode-parent 9 | 1.0-SNAPSHOT 10 | 11 | 12 | cleanandroidcode 13 | apk 14 | cleanandroidcode - Application 15 | 16 | 17 | 18 | com.google.android 19 | android 20 | 21 | 22 | com.google.android 23 | support-v4 24 | 25 | 26 | com.squareup 27 | otto 28 | 29 | 30 | com.squareup 31 | dagger 32 | 33 | 34 | com.googlecode.androidannotations 35 | androidannotations-api 36 | 37 | 39 | 40 | info.piwai.cleanandroidcode 41 | cleanandroidcode-processor 42 | 43 | 44 | com.googlecode.androidannotations 45 | androidannotations 46 | 47 | 48 | com.squareup 49 | dagger-compiler 50 | 51 | 52 | 53 | 54 | 55 | com.jayway.maven.plugins.android.generation2 56 | android-maven-plugin 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /cleanandroidcode/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-16 15 | -------------------------------------------------------------------------------- /cleanandroidcode/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/cleanandroidcode/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /cleanandroidcode/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/cleanandroidcode/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /cleanandroidcode/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/cleanandroidcode/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /cleanandroidcode/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyricau/CleanAndroidCode/ad77b0fcd1e3921f88739399f74f04a2250eb847/cleanandroidcode/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /cleanandroidcode/res/layout/hello_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /cleanandroidcode/res/layout/hello_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 |