Flip the runtime flag default and remove the compiler option for the Fragment.getContext() fix since the compiler option has to be set on every target that compiles a Hilt fragment which can be difficult to set in practice.

PiperOrigin-RevId: 404578308
diff --git a/java/dagger/hilt/android/flags/FragmentGetContextFix.java b/java/dagger/hilt/android/flags/FragmentGetContextFix.java
index d85d39b..b867ec8 100644
--- a/java/dagger/hilt/android/flags/FragmentGetContextFix.java
+++ b/java/dagger/hilt/android/flags/FragmentGetContextFix.java
@@ -36,11 +36,15 @@
  * regular, non-Hilt fragment and can help catch issues where a removed or leaked fragment is
  * incorrectly used.
  *
+ * <p>This flag is paired with the compiler option flag
+ * dagger.hilt.android.useFragmentGetContextFix. When that flag is false, this runtime flag has no
+ * effect on behavior (e.g. the compiler flag being off takes precedence). When the compiler flag is
+ * on, then the runtime flag may be used to disable the behavior at runtime.
+ *
  * <p>In order to set the flag, bind a boolean value qualified with
  * {@link DisableFragmentGetContextFix} into a set in the {@code SingletonComponent}. A set is used
  * instead of an optional binding to avoid a dependency on Guava. Only one value may be bound into
- * the set within a given app. If this is not set, the default is to not use the fix. Example for
- * binding the value:
+ * the set within a given app. Example for binding the value:
  *
  * <pre><code>
  * {@literal @}Module
@@ -72,7 +76,7 @@
         "Cannot bind the flag @DisableFragmentGetContextFix more than once.");
 
     if (flagSet.isEmpty()) {
-      return true;
+      return false;
     } else {
       return flagSet.iterator().next();
     }
diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
index e7a7026..bbadb83 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/FragmentGenerator.java
@@ -16,6 +16,8 @@
 
 package dagger.hilt.android.processor.internal.androidentrypoint;
 
+import static dagger.hilt.processor.internal.HiltCompilerOptions.useFragmentGetContextFix;
+
 import com.squareup.javapoet.AnnotationSpec;
 import com.squareup.javapoet.ClassName;
 import com.squareup.javapoet.FieldSpec;
@@ -76,8 +78,11 @@
             .addMethod(onAttachActivityMethod())
             .addMethod(initializeComponentContextMethod())
             .addMethod(getContextMethod())
-            .addMethod(inflatorMethod())
-            .addField(DISABLE_GET_CONTEXT_FIX_FIELD);
+            .addMethod(inflatorMethod());
+
+    if (useFragmentGetContextFix(env)) {
+      builder.addField(DISABLE_GET_CONTEXT_FIX_FIELD);
+    }
 
     Generators.addGeneratedBaseClassJavadoc(builder, AndroidClassNames.ANDROID_ENTRY_POINT);
     Processors.addGeneratedAnnotation(builder, env, getClass());
@@ -179,25 +184,11 @@
             "$N = $T.createContextWrapper(super.getContext(), this)",
             COMPONENT_CONTEXT_FIELD,
             metadata.componentManager());
-    if (metadata.allowsOptionalInjection()) {
-      // When optionally injected, since the runtime flag is only available in Hilt, we need to
-      // check that the parent uses Hilt first.
-      builder.beginControlFlow("if (optionalInjectParentUsesHilt(optionalInjectGetParent()))");
-    }
 
-    builder
-        .addStatement("$N = $T.isFragmentGetContextFixDisabled(super.getContext())",
-            DISABLE_GET_CONTEXT_FIX_FIELD,
-            AndroidClassNames.FRAGMENT_GET_CONTEXT_FIX);
-
-    if (metadata.allowsOptionalInjection()) {
-      // If not attached to a Hilt parent, just disable the fix for now since this is the current
-      // default. There's not a good way to flip this at runtime without Hilt, so after we flip
-      // the default we may just have to flip this and hope that the Hilt usage is already enough
-      // coverage as this should be a fairly rare case.
-      builder.nextControlFlow("else")
-          .addStatement("$N = true", DISABLE_GET_CONTEXT_FIX_FIELD)
-          .endControlFlow();
+    if (useFragmentGetContextFix(env)) {
+      builder.addStatement("$N = $T.isFragmentGetContextFixDisabled(super.getContext())",
+          DISABLE_GET_CONTEXT_FIX_FIELD,
+          AndroidClassNames.FRAGMENT_GET_CONTEXT_FIX);
     }
 
     return builder
@@ -214,15 +205,26 @@
   //   return componentContext;
   // }
   private MethodSpec getContextMethod() {
-    return MethodSpec.methodBuilder("getContext")
+    MethodSpec.Builder builder = MethodSpec.methodBuilder("getContext")
         .returns(AndroidClassNames.CONTEXT)
         .addAnnotation(Override.class)
-        .addModifiers(Modifier.PUBLIC)
-        // Note that disableGetContext can only be true if componentContext is set, so if it is
-        // true we don't need to check whether componentContext is set or not.
-        .beginControlFlow(
-            "if (super.getContext() == null && !$N)",
-            DISABLE_GET_CONTEXT_FIX_FIELD)
+        .addModifiers(Modifier.PUBLIC);
+
+    if (useFragmentGetContextFix(env)) {
+      builder
+          // Note that disableGetContext can only be true if componentContext is set, so if it is
+          // true we don't need to check whether componentContext is set or not.
+          .beginControlFlow(
+              "if (super.getContext() == null && !$N)",
+              DISABLE_GET_CONTEXT_FIX_FIELD);
+    } else {
+      builder
+          .beginControlFlow(
+              "if (super.getContext() == null && $N == null)",
+              COMPONENT_CONTEXT_FIELD);
+    }
+
+    return builder
         .addStatement("return null")
         .endControlFlow()
         .addStatement("initializeComponentContext()")
diff --git a/java/dagger/hilt/processor/internal/BaseProcessor.java b/java/dagger/hilt/processor/internal/BaseProcessor.java
index a921075..f864420 100644
--- a/java/dagger/hilt/processor/internal/BaseProcessor.java
+++ b/java/dagger/hilt/processor/internal/BaseProcessor.java
@@ -159,7 +159,6 @@
     this.elements = processingEnv.getElementUtils();
     this.types = processingEnv.getTypeUtils();
     this.errorHandler = new ProcessorErrorHandler(processingEnvironment);
-    HiltCompilerOptions.checkWrongAndDeprecatedOptions(processingEnvironment);
   }
 
   @Override
diff --git a/java/dagger/hilt/processor/internal/HiltCompilerOptions.java b/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
index b06faed..f92ae86 100644
--- a/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
+++ b/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
@@ -23,7 +23,6 @@
 import java.util.stream.Collectors;
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.TypeElement;
-import javax.tools.Diagnostic.Kind;
 
 /** Hilt annotation processor options. */
 // TODO(danysantiago): Consider consolidating with Dagger compiler options logic.
@@ -86,6 +85,16 @@
     return BooleanOption.USE_AGGREGATING_ROOT_PROCESSOR.get(env);
   }
 
+  /**
+   * Returns {@code true} if fragment code should use the fixed getContext() behavior where it
+   * correctly returns null after a fragment is removed. This fixed behavior matches the behavior
+   * of a regular fragment and can help catch issues where a removed or leaked fragment is
+   * incorrectly used.
+   */
+  public static boolean useFragmentGetContextFix(ProcessingEnvironment env) {
+    return BooleanOption.USE_FRAGMENT_GET_CONTEXT_FIX.get(env);
+  }
+
   /** Processor options which can have true or false values. */
   private enum BooleanOption {
     /** Do not use! This is for internal use only. */
@@ -100,7 +109,9 @@
     DISABLE_MODULES_HAVE_INSTALL_IN_CHECK("disableModulesHaveInstallInCheck", false),
 
     SHARE_TEST_COMPONENTS(
-        "shareTestComponents", true);
+        "shareTestComponents", true),
+
+    USE_FRAGMENT_GET_CONTEXT_FIX("android.useFragmentGetContextFix", false);
 
     private final String name;
     private final boolean defaultValue;
@@ -138,32 +149,6 @@
     }
   }
 
-  private static final ImmutableSet<String> DEPRECATED_OPTIONS = ImmutableSet.of(
-      "dagger.hilt.android.useFragmentGetContextFix");
-
-  public static void checkWrongAndDeprecatedOptions(ProcessingEnvironment env) {
-    Set<String> knownOptions = getProcessorOptions();
-    for (String option : env.getOptions().keySet()) {
-      if (knownOptions.contains(option)) {
-        continue;
-      }
-
-      if (DEPRECATED_OPTIONS.contains(option)) {
-        env.getMessager().printMessage(
-            Kind.ERROR,
-            "The compiler option " + option + " is deprecated and no longer does anything. "
-            + "Please do not set this option.");
-        continue;
-      }
-
-      if (option.startsWith("dagger.hilt.")) {
-        env.getMessager().printMessage(
-            Kind.ERROR,
-            "The compiler option " + option + " is not a recognized Hilt option. Is there a typo?");
-      }
-    }
-  }
-
   public static Set<String> getProcessorOptions() {
     return Arrays.stream(BooleanOption.values())
         .map(BooleanOption::getQualifiedName)
diff --git a/javatests/dagger/hilt/android/BUILD b/javatests/dagger/hilt/android/BUILD
index 3954aec..f59b8b0 100644
--- a/javatests/dagger/hilt/android/BUILD
+++ b/javatests/dagger/hilt/android/BUILD
@@ -189,6 +189,9 @@
     name = "FragmentContextOnAttachTest",
     size = "small",
     srcs = ["FragmentContextOnAttachTest.java"],
+    javacopts = [
+        "-Adagger.hilt.android.useFragmentGetContextFix=true",
+    ],
     manifest_values = {
         "minSdkVersion": "14",
     },