Add application generation for root component generator.

Test: check code of generated application.
PiperOrigin-RevId: 195121315
Change-Id: I213770a2bb5dca7e565ee1006d7044c2e7acc6d9
diff --git a/Android.mk b/Android.mk
index b71f702..377ad7c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -433,6 +433,7 @@
 
 LOCAL_SRC_FILES := \
 	$(call all-java-files-under, $(BASE_DIR)/dialer/rootcomponentgenerator) \
+	      $(BASE_DIR)/dialer/inject/GenerateDaggerApp.java \
         $(BASE_DIR)/dialer/inject/DialerRootComponent.java \
         $(BASE_DIR)/dialer/inject/DialerVariant.java \
         $(BASE_DIR)/dialer/inject/HasRootComponent.java \
diff --git a/java/com/android/dialer/inject/GenerateDaggerApp.java b/java/com/android/dialer/inject/GenerateDaggerApp.java
new file mode 100644
index 0000000..042561d
--- /dev/null
+++ b/java/com/android/dialer/inject/GenerateDaggerApp.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.dialer.inject;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/** Annotates an inner class where an application with dagger instance is needed. */
+@Target({ElementType.TYPE})
+public @interface GenerateDaggerApp {
+  /** Name of the application to be generated. */
+  String name();
+
+  /** Dialer variant of the application to be generated. */
+  DialerVariant variant();
+}
diff --git a/java/com/android/dialer/inject/RootComponentGeneratorMetadata.java b/java/com/android/dialer/inject/RootComponentGeneratorMetadata.java
index 51d134a..924b41e 100644
--- a/java/com/android/dialer/inject/RootComponentGeneratorMetadata.java
+++ b/java/com/android/dialer/inject/RootComponentGeneratorMetadata.java
@@ -20,8 +20,8 @@
 import java.lang.annotation.Target;
 
 /**
- * Only used by rootcomponent generator to store metadata for locating annotated
- * (@DialerComponent, @InstallIn) class.
+ * Only used by rootcomponent generator to store metadata for locating annotated class with {@link
+ * IncludeInDialerRoot}, {@link InstallIn}.
  */
 @Target(ElementType.TYPE)
 public @interface RootComponentGeneratorMetadata {
diff --git a/java/com/android/dialer/rootcomponentgenerator/DaggerApplicationGeneratingStep.java b/java/com/android/dialer/rootcomponentgenerator/DaggerApplicationGeneratingStep.java
new file mode 100644
index 0000000..7a23486
--- /dev/null
+++ b/java/com/android/dialer/rootcomponentgenerator/DaggerApplicationGeneratingStep.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 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.dialer.rootcomponentgenerator;
+
+import com.android.dialer.inject.DialerRootComponent;
+import com.android.dialer.inject.DialerVariant;
+import com.android.dialer.inject.GenerateDaggerApp;
+import com.android.dialer.inject.HasRootComponent;
+import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.auto.common.MoreElements;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+
+/**
+ * Generates an application class with dagger component instance for a type annotated with {@link
+ * GenerateDaggerApp}.
+ *
+ * <p>Generated code example:
+ *
+ * <p><code>
+ *  @DialerRootComponent(variant = DialerVariant.DIALER_TEST)
+ * class GeneratedApplication extends Application implements HasRootComponent {
+ *  private volatile Object rootComponent;
+ *
+ *  @Override
+ *  @NonNull
+ *  public final Object component() {
+ *   Object result = rootComponent;
+ *     if (result == null) {
+ *       synchronized (this) {
+ *         result = rootComponent;
+ *         if (result == null) {
+ *           rootComponent =
+ *              result = DaggerDialerTest.builder().contextModule(new ContextModule(this)).build();
+ *         }
+ *       }
+ *     }
+ *   return result;
+ *  }
+ * }
+ * </code>
+ */
+public class DaggerApplicationGeneratingStep implements ProcessingStep {
+
+  private static final ClassName ANDROID_APPLICATION_CLASS_NAME =
+      ClassName.get("android.app", "Application");
+
+  private final ProcessingEnvironment processingEnv;
+
+  public DaggerApplicationGeneratingStep(ProcessingEnvironment processingEnv) {
+    this.processingEnv = processingEnv;
+  }
+
+  @Override
+  public Set<? extends Class<? extends Annotation>> annotations() {
+    return ImmutableSet.of(GenerateDaggerApp.class);
+  }
+
+  @Override
+  public Set<? extends Element> process(
+      SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+    for (Element element : elementsByAnnotation.get(GenerateDaggerApp.class)) {
+      GenerateDaggerApp generateDaggerApp = element.getAnnotation(GenerateDaggerApp.class);
+      RootComponentUtils.writeJavaFile(
+          processingEnv,
+          ClassName.get(MoreElements.asType(element)).packageName(),
+          generateDaggerApplication(generateDaggerApp.name(), generateDaggerApp.variant()));
+    }
+
+    return Collections.emptySet();
+  }
+
+  private TypeSpec generateDaggerApplication(String name, DialerVariant variant) {
+    return TypeSpec.classBuilder(name)
+        .addAnnotation(
+            AnnotationSpec.builder(DialerRootComponent.class)
+                .addMember("variant", "$T.$L", DialerVariant.class, variant.name())
+                .build())
+        .superclass(ANDROID_APPLICATION_CLASS_NAME)
+        .addSuperinterface(HasRootComponent.class)
+        .addField(
+            FieldSpec.builder(TypeName.OBJECT, "rootComponent", Modifier.PRIVATE, Modifier.VOLATILE)
+                .build())
+        .addMethod(generateComponentMethod(variant))
+        .build();
+  }
+
+  private MethodSpec generateComponentMethod(DialerVariant dialerVariant) {
+    return MethodSpec.overriding(getComponentMethodFromHasRootComponent())
+        .addModifiers(Modifier.FINAL)
+        .addAnnotation(ClassName.get("android.support.annotation", "NonNull"))
+        .addStatement("$T result = rootComponent", TypeName.OBJECT)
+        .beginControlFlow("if (result == null)")
+        .beginControlFlow("synchronized (this)")
+        .addStatement("result = rootComponent")
+        .beginControlFlow("if (result == null)")
+        .addStatement(
+            "rootComponent = result = Dagger$L.builder().contextModule(new $T(this)).build()",
+            dialerVariant,
+            ClassName.get("com.android.dialer.inject", "ContextModule"))
+        .endControlFlow()
+        .endControlFlow()
+        .endControlFlow()
+        .addStatement("return result")
+        .build();
+  }
+
+  private ExecutableElement getComponentMethodFromHasRootComponent() {
+    TypeElement hasRootComponentInterafce =
+        processingEnv.getElementUtils().getTypeElement(HasRootComponent.class.getTypeName());
+    for (Element element : hasRootComponentInterafce.getEnclosedElements()) {
+      if (element.getSimpleName().contentEquals("component")) {
+        return MoreElements.asExecutable(element);
+      }
+    }
+    throw new RuntimeException("No component method inside HasRootComponent!");
+  }
+}
diff --git a/java/com/android/dialer/rootcomponentgenerator/RootComponentGeneratingStep.java b/java/com/android/dialer/rootcomponentgenerator/RootComponentGeneratingStep.java
index 4c4e6ee..cb31208 100644
--- a/java/com/android/dialer/rootcomponentgenerator/RootComponentGeneratingStep.java
+++ b/java/com/android/dialer/rootcomponentgenerator/RootComponentGeneratingStep.java
@@ -72,8 +72,7 @@
       // defer root components to the next round in case where the current build target contains
       // elements annotated with @InstallIn. Annotation processor cannot detect metadata files
       // generated in the same round and the metadata is accessible in the next round.
-      if (elementsByAnnotation.containsKey(InstallIn.class)
-          || elementsByAnnotation.containsKey(IncludeInDialerRoot.class)) {
+      if (shouldDeferRootComponent(elementsByAnnotation)) {
         return elementsByAnnotation.get(DialerRootComponent.class);
       } else {
         generateRootComponent(MoreElements.asType(element));
@@ -82,6 +81,12 @@
     return Collections.emptySet();
   }
 
+  private boolean shouldDeferRootComponent(
+      SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+    return elementsByAnnotation.containsKey(InstallIn.class)
+        || elementsByAnnotation.containsKey(IncludeInDialerRoot.class);
+  }
+
   /**
    * Generates a root component.
    *
diff --git a/java/com/android/dialer/rootcomponentgenerator/RootComponentProcessor.java b/java/com/android/dialer/rootcomponentgenerator/RootComponentProcessor.java
index 76df5e3..be043eb 100644
--- a/java/com/android/dialer/rootcomponentgenerator/RootComponentProcessor.java
+++ b/java/com/android/dialer/rootcomponentgenerator/RootComponentProcessor.java
@@ -30,6 +30,7 @@
   protected Iterable<? extends ProcessingStep> initSteps() {
     return ImmutableList.of(
         new MetadataGeneratingStep(processingEnv),
+        new DaggerApplicationGeneratingStep(processingEnv),
         new RootComponentGeneratingStep(processingEnv));
   }