Merge "aconfig: add single-exported-file parameter" into main
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index 8588a72..6bd9416 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -33,6 +33,7 @@
     pub allow_instrumentation: bool,
     pub package_fingerprint: u64,
     pub new_exported: bool,
+    pub single_exported_file: bool,
     pub check_api_level: bool,
 }
 
@@ -71,8 +72,15 @@
         is_platform_container,
         package_fingerprint: format!("0x{:X}L", config.package_fingerprint),
         new_exported: config.new_exported,
+        single_exported_file: config.single_exported_file,
     };
     let mut template = TinyTemplate::new();
+    if library_exported && config.single_exported_file {
+        template.add_template(
+            "ExportedFlags.java",
+            include_str!("../../templates/ExportedFlags.java.template"),
+        )?;
+    }
     template.add_template("Flags.java", include_str!("../../templates/Flags.java.template"))?;
     add_feature_flags_impl_template(&context, &mut template)?;
     template.add_template(
@@ -89,18 +97,25 @@
     )?;
 
     let path: PathBuf = package.split('.').collect();
-    [
+    let mut files = vec![
         "Flags.java",
         "FeatureFlags.java",
         "FeatureFlagsImpl.java",
         "CustomFeatureFlags.java",
         "FakeFeatureFlagsImpl.java",
-    ]
-    .iter()
-    .map(|file| {
-        Ok(OutputFile { contents: template.render(file, &context)?.into(), path: path.join(file) })
-    })
-    .collect::<Result<Vec<OutputFile>>>()
+    ];
+    if library_exported && config.single_exported_file {
+        files.push("ExportedFlags.java");
+    }
+    files
+        .iter()
+        .map(|file| {
+            Ok(OutputFile {
+                contents: template.render(file, &context)?.into(),
+                path: path.join(file),
+            })
+        })
+        .collect::<Result<Vec<OutputFile>>>()
 }
 
 fn gen_flags_by_namespace(flags: &[FlagElement]) -> Vec<NamespaceFlags> {
@@ -138,6 +153,7 @@
     pub is_platform_container: bool,
     pub package_fingerprint: String,
     pub new_exported: bool,
+    pub single_exported_file: bool,
 }
 
 #[derive(Serialize, Debug)]
@@ -259,7 +275,7 @@
         (true, false, _) => {
             template.add_template(
                 "FeatureFlagsImpl.java",
-                include_str!("../../templates/FeatureFlagsImpl.java.template"),
+                include_str!("../../templates/FeatureFlagsImpl.deviceConfig.java.template"),
             )?;
         }
 
@@ -275,7 +291,7 @@
         (false, _, false) => {
             template.add_template(
                 "FeatureFlagsImpl.java",
-                include_str!("../../templates/FeatureFlagsImpl.java.template"),
+                include_str!("../../templates/FeatureFlagsImpl.deviceConfig.java.template"),
             )?;
         }
     };
@@ -592,6 +608,7 @@
             allow_instrumentation: true,
             package_fingerprint: 5801144784618221668,
             new_exported: false,
+            single_exported_file: false,
             check_api_level: false,
         };
         let generated_files = generate_java_code(
@@ -752,6 +769,7 @@
             allow_instrumentation: true,
             package_fingerprint: 5801144784618221668,
             new_exported: false,
+            single_exported_file: false,
             check_api_level: false,
         };
         let generated_files = generate_java_code(
@@ -956,6 +974,7 @@
             allow_instrumentation: true,
             package_fingerprint: 5801144784618221668,
             new_exported: true,
+            single_exported_file: false,
             check_api_level: false,
         };
         let generated_files = generate_java_code(
@@ -1022,7 +1041,7 @@
                 } catch (LinkageError e) {
                     // for mainline module running on older devices.
                     // This should be replaces to version check, after the version bump.
-                    Log.e(TAG, e.toString());
+                    Log.w(TAG, e.toString());
                 }
                 isCached = true;
             }
@@ -1150,6 +1169,7 @@
             allow_instrumentation: true,
             package_fingerprint: 5801144784618221668,
             new_exported: false,
+            single_exported_file: false,
             check_api_level: false,
         };
         let generated_files = generate_java_code(
@@ -1277,6 +1297,7 @@
             allow_instrumentation: true,
             package_fingerprint: 5801144784618221668,
             new_exported: false,
+            single_exported_file: false,
             check_api_level: false,
         };
         let generated_files = generate_java_code(
diff --git a/tools/aconfig/aconfig/src/commands.rs b/tools/aconfig/aconfig/src/commands.rs
index ab726aa..ea63c7a 100644
--- a/tools/aconfig/aconfig/src/commands.rs
+++ b/tools/aconfig/aconfig/src/commands.rs
@@ -219,6 +219,7 @@
     codegen_mode: CodegenMode,
     allow_instrumentation: bool,
     new_exported: bool,
+    single_exported_file: bool,
     check_api_level: bool,
 ) -> Result<Vec<OutputFile>> {
     let parsed_flags = input.try_parse_flags()?;
@@ -237,6 +238,7 @@
         allow_instrumentation,
         package_fingerprint,
         new_exported,
+        single_exported_file,
         check_api_level,
     };
     generate_java_code(&package, modified_parsed_flags.into_iter(), config)
diff --git a/tools/aconfig/aconfig/src/main.rs b/tools/aconfig/aconfig/src/main.rs
index ef3b7ab..16b8272 100644
--- a/tools/aconfig/aconfig/src/main.rs
+++ b/tools/aconfig/aconfig/src/main.rs
@@ -158,11 +158,19 @@
                         .default_value("production"),
                 )
                 .arg(
+                    Arg::new("single-exported-file")
+                        .long("single-exported-file")
+                        .value_parser(clap::value_parser!(bool))
+                        .default_value("false"),
+                )
+                // TODO: b/395899938 - clean up flags for switching to new storage
+                .arg(
                     Arg::new("allow-instrumentation")
                         .long("allow-instrumentation")
                         .value_parser(clap::value_parser!(bool))
                         .default_value("false"),
                 )
+                // TODO: b/395899938 - clean up flags for switching to new storage
                 .arg(
                     Arg::new("new-exported")
                         .long("new-exported")
@@ -373,12 +381,15 @@
             let allow_instrumentation =
                 get_required_arg::<bool>(sub_matches, "allow-instrumentation")?;
             let new_exported = get_required_arg::<bool>(sub_matches, "new-exported")?;
+            let single_exported_file =
+                get_required_arg::<bool>(sub_matches, "single-exported-file")?;
             let check_api_level = get_required_arg::<bool>(sub_matches, "check-api-level")?;
             let generated_files = commands::create_java_lib(
                 cache,
                 *mode,
                 *allow_instrumentation,
                 *new_exported,
+                *single_exported_file,
                 *check_api_level,
             )
             .context("failed to create java lib")?;
diff --git a/tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template b/tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template
index b82b9cb..ef18367 100644
--- a/tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template
+++ b/tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template
@@ -11,7 +11,13 @@
 import java.util.function.BiPredicate;
 import java.util.function.Predicate;
 
+{{ -if single_exported_file }}
+{{ -if library_exported }}
+@Deprecated {#- PREFER ExportedFlags #}
+{{ -endif }}
+{{ -else }}
 /** @hide */
+{{ -endif }}
 public class CustomFeatureFlags implements FeatureFlags \{
 
     private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
diff --git a/tools/aconfig/aconfig/templates/ExportedFlags.java.template b/tools/aconfig/aconfig/templates/ExportedFlags.java.template
new file mode 100644
index 0000000..4e36942
--- /dev/null
+++ b/tools/aconfig/aconfig/templates/ExportedFlags.java.template
@@ -0,0 +1,49 @@
+package {package_name}; {#- CODEGEN FOR EXPORTED MODE FOR NEW STORAGE SINGLE EXPORTED FILE#}
+
+import android.os.Build;
+import android.os.flagging.AconfigPackage;
+import android.util.Log;
+public final class ExportedFlags \{
+{{ -for item in flag_elements}}
+    public static final String FLAG_{item.flag_name_constant_suffix} = "{item.device_config_flag}";
+{{- endfor }}
+    private static final String TAG = "ExportedFlags";
+    private static volatile boolean isCached = false;
+{{ for flag in flag_elements }}
+    private static boolean {flag.method_name} = false;
+{{ -endfor }} {#- end flag_elements #}
+    private ExportedFlags() \{}
+
+    private void init() \{
+        try \{
+            AconfigPackage reader = AconfigPackage.load("{package_name}");
+            {{ -for namespace_with_flags in namespace_flags }}
+            {{ -for flag in namespace_with_flags.flags }}
+            {{ -if flag.finalized_sdk_present }}
+            {flag.method_name} = Build.VERSION.SDK_INT >= {flag.finalized_sdk_value} ? true : reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value});
+            {{ - else }} {#- else finalized_sdk_present #}
+            {flag.method_name} = reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value});
+            {{ -endif}}  {#- end finalized_sdk_present#}
+            {{ -endfor }} {#- end namespace_with_flags.flags #}
+            {{ -endfor }} {#- end namespace_flags #}
+        } catch (Exception e) \{
+            // pass
+            Log.e(TAG, e.toString());
+        } catch (LinkageError e) \{
+            // for mainline module running on older devices.
+            // This should be replaces to version check, after the version bump.
+            Log.w(TAG, e.toString());
+        }
+        isCached = true;
+    }
+
+{{ -for flag in flag_elements }}
+    public static boolean {flag.method_name}() \{
+        if (!featureFlags.isCached) \{
+            featureFlags.init();
+        }
+        return featureFlags.{flag.method_name};
+    }
+{{ -endfor }}
+    private static ExportedFlags featureFlags = new ExportedFlags();
+}
diff --git a/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template
index 290d2c4..ed277ae 100644
--- a/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template
@@ -4,7 +4,13 @@
 import java.util.Map;
 import java.util.function.Predicate;
 
+{{ -if single_exported_file }}
+{{ -if library_exported }}
+@Deprecated {#- PREFER ExportedFlags #}
+{{ -endif }}
+{{ -else }}
 /** @hide */
+{{ -endif }}
 public class FakeFeatureFlagsImpl extends CustomFeatureFlags \{
     private final Map<String, Boolean> mFlagMap = new HashMap<>();
     private final FeatureFlags mDefaults;
diff --git a/tools/aconfig/aconfig/templates/FeatureFlags.java.template b/tools/aconfig/aconfig/templates/FeatureFlags.java.template
index d2799b2..c8b9b7f 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlags.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlags.java.template
@@ -3,7 +3,16 @@
 // TODO(b/303773055): Remove the annotation after access issue is resolved.
 import android.compat.annotation.UnsupportedAppUsage;
 {{ -endif }}
+{{ -if single_exported_file }}
+{{ -if library_exported }}
+/**
+ * @deprecated Use \{@link ExportedFlags} instead.
+ */
+@Deprecated {#- PREFER ExportedFlags #}
+{{ -endif }}
+{{ -else }}
 /** @hide */
+{{ -endif }}
 public interface FeatureFlags \{
 {{ for item in flag_elements }}
 {{ -if not item.is_read_write }}
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.deviceConfig.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.deviceConfig.java.template
new file mode 100644
index 0000000..44d5cc0
--- /dev/null
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.deviceConfig.java.template
@@ -0,0 +1,68 @@
+package {package_name};
+{{ if not library_exported- }}
+// TODO(b/303773055): Remove the annotation after access issue is resolved.
+import android.compat.annotation.UnsupportedAppUsage;
+{{ -endif }} {#- end of not library_exported#}
+{{ -if runtime_lookup_required }}
+import android.os.Binder;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+{{ -endif }}  {#- end of runtime_lookup_required#}
+/** @hide */
+public final class FeatureFlagsImpl implements FeatureFlags \{
+{{ -if runtime_lookup_required }}
+{{ -for namespace_with_flags in namespace_flags }}
+    private static volatile boolean {namespace_with_flags.namespace}_is_cached = false;
+{{ -endfor- }}
+{{ for flag in flag_elements }}
+{{- if flag.is_read_write }}
+    private static boolean {flag.method_name} = {flag.default_value};
+{{ -endif }} {#- end of is_read_write#}
+{{ -endfor }}
+{{ for namespace_with_flags in namespace_flags }}
+    private void load_overrides_{namespace_with_flags.namespace}() \{
+        final long ident = Binder.clearCallingIdentity();
+        try \{
+            Properties properties = DeviceConfig.getProperties("{namespace_with_flags.namespace}");
+{{ -for flag in namespace_with_flags.flags }}
+{{ -if flag.is_read_write }}
+            {flag.method_name} =
+                properties.getBoolean(Flags.FLAG_{flag.flag_name_constant_suffix}, {flag.default_value});
+{{ -endif }} {#- end of is_read_write#}
+{{ -endfor }}
+        } catch (NullPointerException e) \{
+            throw new RuntimeException(
+                "Cannot read value from namespace {namespace_with_flags.namespace} "
+                + "from DeviceConfig. It could be that the code using flag "
+                + "executed before SettingsProvider initialization. Please use "
+                + "fixed read-only flag by adding is_fixed_read_only: true in "
+                + "flag declaration.",
+                e
+            );
+        } catch (SecurityException e) \{
+            // for isolated process case, skip loading flag value from the storage, use the default
+        } finally \{
+            Binder.restoreCallingIdentity(ident);
+        }
+        {namespace_with_flags.namespace}_is_cached = true;
+}
+{{ endfor- }}
+{{ -endif }}{#- end of runtime_lookup_required #}
+{{ -for flag in flag_elements }}
+    @Override
+{{ -if not library_exported }}
+    @com.android.aconfig.annotations.AconfigFlagAccessor
+    @UnsupportedAppUsage
+{{ -endif }}{#- end of not library_exported #}
+    public boolean {flag.method_name}() \{
+{{ -if flag.is_read_write }}
+        if (!{flag.device_config_namespace}_is_cached) \{
+            load_overrides_{flag.device_config_namespace}();
+        }
+        return {flag.method_name};
+{{ -else }} {#- else is_read_write #}
+        return {flag.default_value};
+{{ -endif }}{#- end of is_read_write #}
+    }
+{{ endfor }}
+}
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.exported.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.exported.java.template
index 8b60824..b843ec2 100644
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.exported.java.template
+++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.exported.java.template
@@ -3,7 +3,16 @@
 import android.os.Build;
 import android.os.flagging.AconfigPackage;
 import android.util.Log;
+{{ -if single_exported_file }}
+{{ -if library_exported }}
+/**
+ * @deprecated Use \{@link ExportedFlags} instead.
+ */
+@Deprecated {#- PREFER ExportedFlags #}
+{{ -endif }}
+{{ -else }}
 /** @hide */
+{{ -endif }}
 public final class FeatureFlagsImpl implements FeatureFlags \{
     private static final String TAG = "FeatureFlagsImplExport";
     private static volatile boolean isCached = false;
@@ -28,7 +37,7 @@
         } catch (LinkageError e) \{
             // for mainline module running on older devices.
             // This should be replaces to version check, after the version bump.
-            Log.e(TAG, e.toString());
+            Log.w(TAG, e.toString());
         }
         isCached = true;
     }
diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
deleted file mode 100644
index ea2a2ee..0000000
--- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template
+++ /dev/null
@@ -1,248 +0,0 @@
-package {package_name};
-{{ -if not is_test_mode }}
-{{ -if allow_instrumentation }}
-{{ if not library_exported- }}{#- only new storage for prod mode #}
-// TODO(b/303773055): Remove the annotation after access issue is resolved.
-import android.compat.annotation.UnsupportedAppUsage;
-{{ -if runtime_lookup_required }}
-import android.os.Build;
-{{ if is_platform_container }}
-import android.os.flagging.PlatformAconfigPackageInternal;
-{{ -else }} {#- else is_platform_container #}
-import android.os.flagging.AconfigPackageInternal;
-{{ -endif }} {#- end of is_platform_container#}
-import android.util.Log;
-{{ -endif }} {#- end of runtime_lookup_required#}
-/** @hide */
-public final class FeatureFlagsImpl implements FeatureFlags \{
-{{ -if runtime_lookup_required }}
-    private static final String TAG = "FeatureFlagsImpl";
-    private static volatile boolean isCached = false;
-{{ for flag in flag_elements }}
-{{ -if flag.is_read_write }}
-    private static boolean {flag.method_name} = {flag.default_value};
-{{ -endif }} {#- end of is_read_write#}
-{{ -endfor }}
-
-    private void init() \{
-        try \{
-{{ if is_platform_container }}
-            PlatformAconfigPackageInternal reader = PlatformAconfigPackageInternal.load("{package_name}", {package_fingerprint});
-{{ -else }} {#- else is_platform_container #}
-            AconfigPackageInternal reader = AconfigPackageInternal.load("{package_name}", {package_fingerprint});
-{{ -endif }} {#- end of is_platform_container#}
-        {{ -for namespace_with_flags in namespace_flags }}
-        {{ -for flag in namespace_with_flags.flags }}
-        {{ -if flag.is_read_write }}
-            {flag.method_name} = reader.getBooleanFlagValue({flag.flag_offset});
-        {{ -endif }} {#- is_read_write#}
-        {{ -endfor }}
-        {{ -endfor }}
-        } catch (Exception e) \{
-            Log.e(TAG, e.toString());
-        } catch (LinkageError e) \{
-            // for mainline module running on older devices.
-            // This should be replaces to version check, after the version bump.
-            Log.e(TAG, e.toString());
-        }
-        isCached = true;
-    }
-{{ -endif }}{#- end of runtime_lookup_required #}
-{{ -for flag in flag_elements }}
-    @Override
-    @com.android.aconfig.annotations.AconfigFlagAccessor
-    @UnsupportedAppUsage
-    public boolean {flag.method_name}() \{
-{{ -if flag.is_read_write }}
-        if (!isCached) \{
-            init();
-        }
-        return {flag.method_name};
-{{ -else }}{#- else is_read_write #}
-        return {flag.default_value};
-{{ -endif }}  {#- end of is_read_write#}
-    }
-{{ endfor }}
-}
-{{ -else- }}{#- device config for exproted mode #}
-{{ -if new_exported }}
-import android.os.Build;
-import android.os.flagging.AconfigPackage;
-import android.util.Log;
-/** @hide */
-public final class FeatureFlagsImpl implements FeatureFlags \{
-    private static final String TAG = "FeatureFlagsImplExport";
-    private static volatile boolean isCached = false;
-{{ for flag in flag_elements }}
-    private static boolean {flag.method_name} = false;
-{{ -endfor }}
-    private void init() \{
-        try \{
-            AconfigPackage reader = AconfigPackage.load("{package_name}");
-            {{ -for namespace_with_flags in namespace_flags }}
-            {{ -for flag in namespace_with_flags.flags }}
-            {{ -if flag.finalized_sdk_present }}
-            {flag.method_name} = Build.VERSION.SDK_INT >= {flag.finalized_sdk_value} ? true : reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value});
-            {{ - else }} {#- else finalized_sdk_present #}
-            {flag.method_name} = reader.getBooleanFlagValue("{flag.flag_name}", {flag.default_value});
-            {{ -endif}}  {#- end of finalized_sdk_present#}
-            {{ -endfor }}
-            {{ -endfor }}
-        } catch (Exception e) \{
-            // pass
-            Log.e(TAG, e.toString());
-        } catch (LinkageError e) \{
-            // for mainline module running on older devices.
-            // This should be replaces to version check, after the version bump.
-            Log.e(TAG, e.toString());
-        }
-        isCached = true;
-    }
-{{ -for flag in flag_elements }}
-    @Override
-    public boolean {flag.method_name}() \{
-        if (!isCached) \{
-            init();
-        }
-        return {flag.method_name};
-    }
-{{ endfor }}
-}
-{{ else }}
-import android.os.Binder;
-import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.Properties;
-/** @hide */
-public final class FeatureFlagsImpl implements FeatureFlags \{
-{{ -for namespace_with_flags in namespace_flags }}
-    private static volatile boolean {namespace_with_flags.namespace}_is_cached = false;
-{{ -endfor- }}
-{{ for flag in flag_elements }}
-{{ -if flag.is_read_write }}
-    private static boolean {flag.method_name} = {flag.default_value};
-{{ -endif }}  {#- end of is_read_write#}
-{{ -endfor }}
-{{ for namespace_with_flags in namespace_flags }}
-    private void load_overrides_{namespace_with_flags.namespace}() \{
-        final long ident = Binder.clearCallingIdentity();
-        try \{
-            Properties properties = DeviceConfig.getProperties("{namespace_with_flags.namespace}");
-{{ -for flag in namespace_with_flags.flags }}
-{{ -if flag.is_read_write }}
-            {flag.method_name} =
-                properties.getBoolean(Flags.FLAG_{flag.flag_name_constant_suffix}, {flag.default_value});
-{{ -endif }}  {#- end of is_read_write#}
-{{ -endfor }}
-        } catch (NullPointerException e) \{
-            throw new RuntimeException(
-                "Cannot read value from namespace {namespace_with_flags.namespace} "
-                + "from DeviceConfig. It could be that the code using flag "
-                + "executed before SettingsProvider initialization. Please use "
-                + "fixed read-only flag by adding is_fixed_read_only: true in "
-                + "flag declaration.",
-                e
-            );
-        } catch (SecurityException e) \{
-            // for isolated process case, skip loading flag value from the storage, use the default
-        } finally \{
-            Binder.restoreCallingIdentity(ident);
-        }
-        {namespace_with_flags.namespace}_is_cached = true;
-    }
-{{ endfor- }}
-{{ -for flag in flag_elements }}
-    @Override
-    public boolean {flag.method_name}() \{
-        if (!{flag.device_config_namespace}_is_cached) \{
-            load_overrides_{flag.device_config_namespace}();
-        }
-        return {flag.method_name};
-    }
-{{ endfor }}
-}
-{{ -endif- }} {#- end new_exported mode #}
-{{ -endif- }} {#- end exported mode #}
-{{ else }} {#- else for allow_instrumentation is not enabled #}
-{{ if not library_exported- }}
-// TODO(b/303773055): Remove the annotation after access issue is resolved.
-import android.compat.annotation.UnsupportedAppUsage;
-{{ -endif }} {#- end of not library_exported#}
-
-{{ -if runtime_lookup_required }}
-import android.os.Binder;
-import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.Properties;
-{{ -endif }}  {#- end of runtime_lookup_required#}
-/** @hide */
-public final class FeatureFlagsImpl implements FeatureFlags \{
-{{ -if runtime_lookup_required }}
-{{ -for namespace_with_flags in namespace_flags }}
-    private static volatile boolean {namespace_with_flags.namespace}_is_cached = false;
-{{ -endfor- }}
-
-{{ for flag in flag_elements }}
-{{- if flag.is_read_write }}
-    private static boolean {flag.method_name} = {flag.default_value};
-{{ -endif }} {#- end of is_read_write#}
-{{ -endfor }}
-{{ for namespace_with_flags in namespace_flags }}
-    private void load_overrides_{namespace_with_flags.namespace}() \{
-        final long ident = Binder.clearCallingIdentity();
-        try \{
-            Properties properties = DeviceConfig.getProperties("{namespace_with_flags.namespace}");
-{{ -for flag in namespace_with_flags.flags }}
-{{ -if flag.is_read_write }}
-            {flag.method_name} =
-                properties.getBoolean(Flags.FLAG_{flag.flag_name_constant_suffix}, {flag.default_value});
-{{ -endif }} {#- end of is_read_write#}
-{{ -endfor }}
-        } catch (NullPointerException e) \{
-            throw new RuntimeException(
-                "Cannot read value from namespace {namespace_with_flags.namespace} "
-                + "from DeviceConfig. It could be that the code using flag "
-                + "executed before SettingsProvider initialization. Please use "
-                + "fixed read-only flag by adding is_fixed_read_only: true in "
-                + "flag declaration.",
-                e
-            );
-        } finally \{
-            Binder.restoreCallingIdentity(ident);
-        }
-        {namespace_with_flags.namespace}_is_cached = true;
-}
-{{ endfor- }}
-{{ -endif }}{#- end of runtime_lookup_required #}
-{{ -for flag in flag_elements }}
-    @Override
-{{ -if not library_exported }}
-    @com.android.aconfig.annotations.AconfigFlagAccessor
-    @UnsupportedAppUsage
-{{ -endif }}{#- end of not library_exported #}
-    public boolean {flag.method_name}() \{
-{{ -if flag.is_read_write }}
-        if (!{flag.device_config_namespace}_is_cached) \{
-            load_overrides_{flag.device_config_namespace}();
-        }
-        return {flag.method_name};
-{{ -else }} {#- else is_read_write #}
-        return {flag.default_value};
-{{ -endif }}{#- end of is_read_write #}
-    }
-{{ endfor }}
-}
-{{ endif}} {#- endif for allow_instrumentation #}
-{{ else }} {#- Generate only stub if in test mode #}
-/** @hide */
-public final class FeatureFlagsImpl implements FeatureFlags \{
-{{ for flag in flag_elements }}
-    @Override
-{{ -if not library_exported }}
-    @com.android.aconfig.annotations.AconfigFlagAccessor
-{{ -endif }}
-    public boolean {flag.method_name}() \{
-        throw new UnsupportedOperationException(
-            "Method is not implemented.");
-    }
-{{ endfor- }}
-}
-{{ endif }}
diff --git a/tools/aconfig/aconfig/templates/Flags.java.template b/tools/aconfig/aconfig/templates/Flags.java.template
index e2f70b9..8a92d33 100644
--- a/tools/aconfig/aconfig/templates/Flags.java.template
+++ b/tools/aconfig/aconfig/templates/Flags.java.template
@@ -3,7 +3,16 @@
 // TODO(b/303773055): Remove the annotation after access issue is resolved.
 import android.compat.annotation.UnsupportedAppUsage;
 {{ -endif }}
+{{ -if single_exported_file }}
+{{ -if library_exported }}
+/**
+ * @deprecated Use \{@link ExportedFlags} instead.
+ */
+@Deprecated {#- PREFER ExportedFlags #}
+{{ -endif }}
+{{ -else }}
 /** @hide */
+{{ -endif }}
 public final class Flags \{
 {{ -for item in flag_elements}}
     /** @hide */