aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff DeCew <jeffdq@google.com>2024-04-24 14:43:27 +0000
committerJeff DeCew <jeffdq@google.com>2024-04-24 14:43:27 +0000
commitc3bc24f33b09ea8a841663570949efb4738ac000 (patch)
treed27ead9d27b7a5eea66f704b5357f58113cdc35f
parente0c74fbdd640865c58ff378ac4c41235e9199248 (diff)
downloadbuild-c3bc24f33b09ea8a841663570949efb4738ac000.tar.gz
Generate CustomFeatureFlags
* Creates a new general-purpose CustomFeatureFlags class * Simplifies FakeFeatureFlagsImpl to be based on that * This allows teams to fake FeatureFlags without having to make changes per flag. * This allows SetFlagsRule to inject an instance of FeatureFlags that would detect if a flag has been read. Bug: 336768870 Flag: none Test: presubmit Change-Id: Id3c2530d484fa5584c46d11381fcfc0ab294f33f NOTE FOR REVIEWERS - original patch and result patch are not identical. PLEASE REVIEW CAREFULLY. Diffs between the patches: "CustomFeatureFlags.java", > + include_str!("../../templates/CustomFeatureFlags.java.template"), > + )?; > + template.add_template( > - ["Flags.java", "FeatureFlags.java", "FeatureFlagsImpl.java", "FakeFeatureFlagsImpl.java"] > - .iter() > - .map(|file| { > - Ok(OutputFile { > - contents: template.render(file, &context)?.into(), > - path: path.join(file), > - }) > - }) > - .collect::<Result<Vec<OutputFile>>>() > + [ > + "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>>>() > - const EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT: &str = r#" > + const EXPECTED_CUSTOMFEATUREFLAGS_CONTENT: &str = r#" > + > - import java.util.HashMap; > - import java.util.Map; > + import java.util.List; > + import java.util.function.BiPredicate; > + import java.util.function.Predicate; > + > - public class FakeFeatureFlagsImpl implements FeatureFlags { > - public FakeFeatureFlagsImpl() { > - resetAll(); > + public class CustomFeatureFlags implements FeatureFlags { > + > + private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl; > + > + public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) { > + mGetValueImpl = getValueImpl; > + > - return getValue(Flags.FLAG_DISABLED_RO); > + return getValue(Flags.FLAG_DISABLED_RO, > + FeatureFlags::disabledRo); > - return getValue(Flags.FLAG_DISABLED_RW); > + return getValue(Flags.FLAG_DISABLED_RW, > + FeatureFlags::disabledRw); > - return getValue(Flags.FLAG_DISABLED_RW_EXPORTED); > + return getValue(Flags.FLAG_DISABLED_RW_EXPORTED, > + FeatureFlags::disabledRwExported); > - return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE); > + return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, > + FeatureFlags::disabledRwInOtherNamespace); > - return getValue(Flags.FLAG_ENABLED_FIXED_RO); > + return getValue(Flags.FLAG_ENABLED_FIXED_RO, > + FeatureFlags::enabledFixedRo); > - return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED); > + return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, > + FeatureFlags::enabledFixedRoExported); > - return getValue(Flags.FLAG_ENABLED_RO); > + return getValue(Flags.FLAG_ENABLED_RO, > + FeatureFlags::enabledRo); > - return getValue(Flags.FLAG_ENABLED_RO_EXPORTED); > + return getValue(Flags.FLAG_ENABLED_RO_EXPORTED, > + FeatureFlags::enabledRoExported); > - return getValue(Flags.FLAG_ENABLED_RW); > + return getValue(Flags.FLAG_ENABLED_RW, > + FeatureFlags::enabledRw); > - public void setFlag(String flagName, boolean value) { > - if (!this.mFlagMap.containsKey(flagName)) { > - throw new IllegalArgumentException("no such flag " + flagName); > - } > - this.mFlagMap.put(flagName, value); > - } > - public void resetAll() { > - for (Map.Entry entry : mFlagMap.entrySet()) { > - entry.setValue(null); > - } > - } > + > + > - private boolean getValue(String flagName) { > - Boolean value = this.mFlagMap.get(flagName); > - if (value == null) { > - throw new IllegalArgumentException(flagName + " is not set"); > - } > - return value; > + > + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) { > + return mGetValueImpl.test(flagName, getter); > - private Map<String, Boolean> mFlagMap = new HashMap<>( > - Map.ofEntries( > - Map.entry(Flags.FLAG_DISABLED_RO, false), > - Map.entry(Flags.FLAG_DISABLED_RW, false), > - Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false), > - Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false), > - Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false), > - Map.entry(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, false), > - Map.entry(Flags.FLAG_ENABLED_RO, false), > - Map.entry(Flags.FLAG_ENABLED_RO_EXPORTED, false), > - Map.entry(Flags.FLAG_ENABLED_RW, false) > - ) > - ); > + > + public List<String> getFlagNames() { > + return Arrays.asList( > + Flags.FLAG_DISABLED_RO, > + Flags.FLAG_DISABLED_RW, > + Flags.FLAG_DISABLED_RW_EXPORTED, > + Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, > + Flags.FLAG_ENABLED_FIXED_RO, > + Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, > + Flags.FLAG_ENABLED_RO, > + Flags.FLAG_ENABLED_RO_EXPORTED, > + Flags.FLAG_ENABLED_RW > + ); > + } > + > + const EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT: &str = r#" > + package com.android.aconfig.test; > + > + import java.util.HashMap; > + import java.util.Map; > + import java.util.function.Predicate; > + > + /** @hide */ > + public class FakeFeatureFlagsImpl extends CustomFeatureFlags { > + private Map<String, Boolean> mFlagMap = new HashMap<>(); > + > + public FakeFeatureFlagsImpl() { > + super(null); > + // Initialize the map with null values > + for (String flagName : getFlagNames()) { > + mFlagMap.put(flagName, null); > + } > + } > + > + @Override > + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) { > + Boolean value = this.mFlagMap.get(flagName); > + if (value == null) { > + throw new IllegalArgumentException(flagName + " is not set"); > + } > + return value; > + } > + > + public void setFlag(String flagName, boolean value) { > + if (!this.mFlagMap.containsKey(flagName)) { > + throw new IllegalArgumentException("no such flag " + flagName); > + } > + this.mFlagMap.put(flagName, value); > + } > + > + public void resetAll() { > + for (Map.Entry entry : mFlagMap.entrySet()) { > + entry.setValue(null); > + } > + } > + } > + "#; > + > + "com/android/aconfig/test/CustomFeatureFlags.java", > + EXPECTED_CUSTOMFEATUREFLAGS_CONTENT, > + ), > + ( > - let expect_fake_feature_flags_impl_content = r#" > + let expect_custom_feature_flags_content = r#" > + > - import java.util.HashMap; > - import java.util.Map; > + import java.util.List; > + import java.util.function.BiPredicate; > + import java.util.function.Predicate; > + > - public class FakeFeatureFlagsImpl implements FeatureFlags { > - public FakeFeatureFlagsImpl() { > - resetAll(); > + public class CustomFeatureFlags implements FeatureFlags { > + > + private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl; > + > + public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) { > + mGetValueImpl = getValueImpl; > + > - return getValue(Flags.FLAG_DISABLED_RW_EXPORTED); > + return getValue(Flags.FLAG_DISABLED_RW_EXPORTED, > + FeatureFlags::disabledRwExported); > - return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED); > + return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, > + FeatureFlags::enabledFixedRoExported); > - return getValue(Flags.FLAG_ENABLED_RO_EXPORTED); > + return getValue(Flags.FLAG_ENABLED_RO_EXPORTED, > + FeatureFlags::enabledRoExported); > - public void setFlag(String flagName, boolean value) { > - if (!this.mFlagMap.containsKey(flagName)) { > - throw new IllegalArgumentException("no such flag " + flagName); > - } > - this.mFlagMap.put(flagName, value); > + > + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) { > + return mGetValueImpl.test(flagName, getter); > - public void resetAll() { > - for (Map.Entry entry : mFlagMap.entrySet()) { > - entry.setValue(null); > - } > + > + public List<String> getFlagNames() { > + return Arrays.asList( > + Flags.FLAG_DISABLED_RW_EXPORTED, > + Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, > + Flags.FLAG_ENABLED_RO_EXPORTED > + ); > - private boolean getValue(String flagName) { > - Boolean value = this.mFlagMap.get(flagName); > - if (value == null) { > - throw new IllegalArgumentException(flagName + " is not set"); > - } > - return value; > - } > - private Map<String, Boolean> mFlagMap = new HashMap<>( > - Map.ofEntries( > - Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false), > - Map.entry(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, false), > - Map.entry(Flags.FLAG_ENABLED_RO_EXPORTED, false) > - ) > - ); > + > + "com/android/aconfig/test/CustomFeatureFlags.java", > + expect_custom_feature_flags_content, > + ), > + ( > - expect_fake_feature_flags_impl_content, > + EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT, > + "com/android/aconfig/test/CustomFeatureFlags.java", > + EXPECTED_CUSTOMFEATUREFLAGS_CONTENT, > + ), > + ( > - let expect_fakefeatureflags_content = r#" > + let expect_customfeatureflags_content = r#" > + > - import java.util.HashMap; > - import java.util.Map; > + import java.util.List; > + import java.util.function.BiPredicate; > + import java.util.function.Predicate; > + > - public class FakeFeatureFlagsImpl implements FeatureFlags { > - public FakeFeatureFlagsImpl() { > - resetAll(); > + public class CustomFeatureFlags implements FeatureFlags { > + > + private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl; > + > + public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) { > + mGetValueImpl = getValueImpl; > + > - return getValue(Flags.FLAG_DISABLED_RO); > + return getValue(Flags.FLAG_DISABLED_RO, > + FeatureFlags::disabledRo); > - return getValue(Flags.FLAG_DISABLED_RW); > + return getValue(Flags.FLAG_DISABLED_RW, > + FeatureFlags::disabledRw); > - return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE); > + return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, > + FeatureFlags::disabledRwInOtherNamespace); > - return getValue(Flags.FLAG_ENABLED_FIXED_RO); > + return getValue(Flags.FLAG_ENABLED_FIXED_RO, > + FeatureFlags::enabledFixedRo); > - return getValue(Flags.FLAG_ENABLED_RO); > + return getValue(Flags.FLAG_ENABLED_RO, > + FeatureFlags::enabledRo); > - return getValue(Flags.FLAG_ENABLED_RW); > + return getValue(Flags.FLAG_ENABLED_RW, > + FeatureFlags::enabledRw); > - public void setFlag(String flagName, boolean value) { > - if (!this.mFlagMap.containsKey(flagName)) { > - throw new IllegalArgumentException("no such flag " + flagName); > - } > - this.mFlagMap.put(flagName, value); > - } > - public void resetAll() { > - for (Map.Entry entry : mFlagMap.entrySet()) { > - entry.setValue(null); > - } > - } > + > + > - private boolean getValue(String flagName) { > - Boolean value = this.mFlagMap.get(flagName); > - if (value == null) { > - throw new IllegalArgumentException(flagName + " is not set"); > - } > - return value; > + > + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) { > + return mGetValueImpl.test(flagName, getter); > - private Map<String, Boolean> mFlagMap = new HashMap<>( > - Map.ofEntries( > - Map.entry(Flags.FLAG_DISABLED_RO, false), > - Map.entry(Flags.FLAG_DISABLED_RW, false), > - Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false), > - Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false), > - Map.entry(Flags.FLAG_ENABLED_RO, false), > - Map.entry(Flags.FLAG_ENABLED_RW, false) > - ) > - ); > + > + public List<String> getFlagNames() { > + return Arrays.asList( > + Flags.FLAG_DISABLED_RO, > + Flags.FLAG_DISABLED_RW, > + Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, > + Flags.FLAG_ENABLED_FIXED_RO, > + Flags.FLAG_ENABLED_RO, > + Flags.FLAG_ENABLED_RW > + ); > + } > + > + > - ("com/android/aconfig/test/FakeFeatureFlagsImpl.java", expect_fakefeatureflags_content), > + ("com/android/aconfig/test/CustomFeatureFlags.java", expect_customfeatureflags_content), > + ( > + "com/android/aconfig/test/FakeFeatureFlagsImpl.java", > + EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT, > + ), > --- /dev/null > +++ tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template > +package {package_name}; > + > +{{ if not library_exported- }} > +// TODO(b/303773055): Remove the annotation after access issue is resolved. > +import android.compat.annotation.UnsupportedAppUsage; > +{{ -endif }} > +import java.util.Arrays; > +import java.util.HashSet; > +import java.util.List; > +import java.util.Set; > +import java.util.function.BiPredicate; > +import java.util.function.Predicate; > + > +/** @hide */ > +public class CustomFeatureFlags implements FeatureFlags \{ > + > + private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl; > + > + public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) \{ > + mGetValueImpl = getValueImpl; > + } > + > +{{ -for item in flag_elements}} > + @Override > +{{ if not library_exported }} @UnsupportedAppUsage{{ -endif }} > + public boolean {item.method_name}() \{ > + return getValue(Flags.FLAG_{item.flag_name_constant_suffix}, > + FeatureFlags::{item.method_name}); > + } > +{{ endfor }} > + > +{{ -if not library_exported }} > + public boolean isFlagReadOnlyOptimized(String flagName) \{ > + if (mReadOnlyFlagsSet.contains(flagName) && > + isOptimizationEnabled()) \{ > + return true; > + } > + return false; > + } > + > + @com.android.aconfig.annotations.AssumeTrueForR8 > + private boolean isOptimizationEnabled() \{ > + return false; > + } > +{{ -endif }} > + > + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) \{ > + return mGetValueImpl.test(flagName, getter); > + } > + > + public List<String> getFlagNames() \{ > + return Arrays.asList( > + {{ -for item in flag_elements }} > + Flags.FLAG_{item.flag_name_constant_suffix} > + {{ -if not @last }},{{ endif }} > + {{ -endfor }} > + ); > + } > + > + private Set<String> mReadOnlyFlagsSet = new HashSet<>( > + Arrays.asList( > + {{ -for item in flag_elements }} > + {{ -if not item.is_read_write }} > + Flags.FLAG_{item.flag_name_constant_suffix}, > + {{ -endif }} > + {{ -endfor }} > + ""{# The empty string here is to resolve the ending comma #} > + ) > + ); > +} > --- tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template > +++ tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template > -{{ if not library_exported- }} > -// TODO(b/303773055): Remove the annotation after access issue is resolved. > -import android.compat.annotation.UnsupportedAppUsage; > -{{ -endif }} > -import java.util.Arrays; > + > -import java.util.HashSet; > -import java.util.Set; > +import java.util.function.Predicate; > -public class FakeFeatureFlagsImpl implements FeatureFlags \{ > +public class FakeFeatureFlagsImpl extends CustomFeatureFlags \{ > + private Map<String, Boolean> mFlagMap = new HashMap<>(); > + > - resetAll(); > + super(null); > + // Initialize the map with null values > + for (String flagName : getFlagNames()) \{ > + mFlagMap.put(flagName, null); > + } > -{{ for item in flag_elements}} > -{{ if not library_exported }} @UnsupportedAppUsage{{ -endif }} > - public boolean {item.method_name}() \{ > - return getValue(Flags.FLAG_{item.flag_name_constant_suffix}); > + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) \{ > + Boolean value = this.mFlagMap.get(flagName); > + if (value == null) \{ > + throw new IllegalArgumentException(flagName + " is not set"); > + } > + return value; > -{{ endfor}} > + > -{{ if not library_exported }} > - public boolean isFlagReadOnlyOptimized(String flagName) \{ > - if (mReadOnlyFlagsSet.contains(flagName) && > - isOptimizationEnabled()) \{ > - return true; > - } > - return false; > - } > - > - @com.android.aconfig.annotations.AssumeTrueForR8 > - private boolean isOptimizationEnabled() \{ > - return false; > - } > -{{ -endif }} > - private boolean getValue(String flagName) \{ > - Boolean value = this.mFlagMap.get(flagName); > - if (value == null) \{ > - throw new IllegalArgumentException(flagName + " is not set"); > - } > - return value; > - } > - > - > - private Map<String, Boolean> mFlagMap = new HashMap<>( > - Map.ofEntries( > - {{ -for item in flag_elements }} > - Map.entry(Flags.FLAG_{item.flag_name_constant_suffix}, false) > - {{ -if not @last }},{{ endif }} > - {{ -endfor }} > - ) > - ); > - > - private Set<String> mReadOnlyFlagsSet = new HashSet<>( > - Arrays.asList( > - {{ -for item in flag_elements }} > - {{ -if not item.is_read_write }} > - Flags.FLAG_{item.flag_name_constant_suffix}, > - {{ -endif }} > - {{ -endfor }} > - ""{# The empty string here is to resolve the ending comma #} > - ) > - ); Original patch: diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs old mode 100644 new mode 100644 --- a/tools/aconfig/aconfig/src/codegen/java.rs +++ b/tools/aconfig/aconfig/src/codegen/java.rs @@ -63,21 +63,28 @@ "FeatureFlags.java", include_str!("../../templates/FeatureFlags.java.template"), )?; + template.add_template( + "CustomFeatureFlags.java", + include_str!("../../templates/CustomFeatureFlags.java.template"), + )?; template.add_template( "FakeFeatureFlagsImpl.java", include_str!("../../templates/FakeFeatureFlagsImpl.java.template"), )?; let path: PathBuf = package.split('.').collect(); - ["Flags.java", "FeatureFlags.java", "FeatureFlagsImpl.java", "FakeFeatureFlagsImpl.java"] - .iter() - .map(|file| { - Ok(OutputFile { - contents: template.render(file, &context)?.into(), - path: path.join(file), - }) - }) - .co [[[Original patch trimmed due to size. Decoded string size: 26318. Decoded string SHA1: 7db34b7baf0a0bbaa1cff48b6ccab9c65408e743.]]] Result patch: diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs index 18a4be5..9abc892 100644 --- a/tools/aconfig/aconfig/src/codegen/java.rs +++ b/tools/aconfig/aconfig/src/codegen/java.rs @@ -64,20 +64,27 @@ include_str!("../../templates/FeatureFlags.java.template"), )?; template.add_template( + "CustomFeatureFlags.java", + include_str!("../../templates/CustomFeatureFlags.java.template"), + )?; + template.add_template( "FakeFeatureFlagsImpl.java", include_str!("../../templates/FakeFeatureFlagsImpl.java.template"), )?; let path: PathBuf = package.split('.').collect(); - ["Flags.java", "FeatureFlags.java", "FeatureFlagsImpl.java", "FakeFeatureFlagsImpl.java"] - .iter() - .map(|file| { - Ok(OutputFile { - contents: template.render(file, &context)?.into(), - path: path.join(file), - }) - }) - .collect::<Result<Vec<OutputFile>>> [[[Result patch trimmed due to size. Decoded string size: 26308. Decoded string SHA1: bb07ee948a630a6bc4cfbbf2a8df178f3e6d3103.]]] Change-Id: I94184633303b9d76f7943451fb3b2c93d071ec1c
-rw-r--r--tools/aconfig/aconfig/src/codegen/java.rs330
-rw-r--r--tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template70
-rw-r--r--tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template73
3 files changed, 289 insertions, 184 deletions
diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs
index 18a4be5094..9abc892908 100644
--- a/tools/aconfig/aconfig/src/codegen/java.rs
+++ b/tools/aconfig/aconfig/src/codegen/java.rs
@@ -64,20 +64,27 @@ where
include_str!("../../templates/FeatureFlags.java.template"),
)?;
template.add_template(
+ "CustomFeatureFlags.java",
+ include_str!("../../templates/CustomFeatureFlags.java.template"),
+ )?;
+ template.add_template(
"FakeFeatureFlagsImpl.java",
include_str!("../../templates/FakeFeatureFlagsImpl.java.template"),
)?;
let path: PathBuf = package.split('.').collect();
- ["Flags.java", "FeatureFlags.java", "FeatureFlagsImpl.java", "FakeFeatureFlagsImpl.java"]
- .iter()
- .map(|file| {
- Ok(OutputFile {
- contents: template.render(file, &context)?.into(),
- path: path.join(file),
- })
- })
- .collect::<Result<Vec<OutputFile>>>()
+ [
+ "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>>>()
}
fn gen_flags_by_namespace(flags: &[FlagElement]) -> Vec<NamespaceFlags> {
@@ -292,76 +299,82 @@ mod tests {
}
"#;
- const EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT: &str = r#"
+ const EXPECTED_CUSTOMFEATUREFLAGS_CONTENT: &str = r#"
package com.android.aconfig.test;
+
// TODO(b/303773055): Remove the annotation after access issue is resolved.
import android.compat.annotation.UnsupportedAppUsage;
import java.util.Arrays;
- import java.util.HashMap;
import java.util.HashSet;
- import java.util.Map;
+ import java.util.List;
import java.util.Set;
+ import java.util.function.BiPredicate;
+ import java.util.function.Predicate;
+
/** @hide */
- public class FakeFeatureFlagsImpl implements FeatureFlags {
- public FakeFeatureFlagsImpl() {
- resetAll();
+ public class CustomFeatureFlags implements FeatureFlags {
+
+ private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
+
+ public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
+ mGetValueImpl = getValueImpl;
}
+
@Override
@UnsupportedAppUsage
public boolean disabledRo() {
- return getValue(Flags.FLAG_DISABLED_RO);
+ return getValue(Flags.FLAG_DISABLED_RO,
+ FeatureFlags::disabledRo);
}
@Override
@UnsupportedAppUsage
public boolean disabledRw() {
- return getValue(Flags.FLAG_DISABLED_RW);
+ return getValue(Flags.FLAG_DISABLED_RW,
+ FeatureFlags::disabledRw);
}
@Override
@UnsupportedAppUsage
public boolean disabledRwExported() {
- return getValue(Flags.FLAG_DISABLED_RW_EXPORTED);
+ return getValue(Flags.FLAG_DISABLED_RW_EXPORTED,
+ FeatureFlags::disabledRwExported);
}
@Override
@UnsupportedAppUsage
public boolean disabledRwInOtherNamespace() {
- return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE);
+ return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
+ FeatureFlags::disabledRwInOtherNamespace);
}
@Override
@UnsupportedAppUsage
public boolean enabledFixedRo() {
- return getValue(Flags.FLAG_ENABLED_FIXED_RO);
+ return getValue(Flags.FLAG_ENABLED_FIXED_RO,
+ FeatureFlags::enabledFixedRo);
}
@Override
@UnsupportedAppUsage
public boolean enabledFixedRoExported() {
- return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED);
+ return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
+ FeatureFlags::enabledFixedRoExported);
}
@Override
@UnsupportedAppUsage
public boolean enabledRo() {
- return getValue(Flags.FLAG_ENABLED_RO);
+ return getValue(Flags.FLAG_ENABLED_RO,
+ FeatureFlags::enabledRo);
}
@Override
@UnsupportedAppUsage
public boolean enabledRoExported() {
- return getValue(Flags.FLAG_ENABLED_RO_EXPORTED);
+ return getValue(Flags.FLAG_ENABLED_RO_EXPORTED,
+ FeatureFlags::enabledRoExported);
}
@Override
@UnsupportedAppUsage
public boolean enabledRw() {
- return getValue(Flags.FLAG_ENABLED_RW);
- }
- public void setFlag(String flagName, boolean value) {
- if (!this.mFlagMap.containsKey(flagName)) {
- throw new IllegalArgumentException("no such flag " + flagName);
- }
- this.mFlagMap.put(flagName, value);
- }
- public void resetAll() {
- for (Map.Entry entry : mFlagMap.entrySet()) {
- entry.setValue(null);
- }
+ return getValue(Flags.FLAG_ENABLED_RW,
+ FeatureFlags::enabledRw);
}
+
public boolean isFlagReadOnlyOptimized(String flagName) {
if (mReadOnlyFlagsSet.contains(flagName) &&
isOptimizationEnabled()) {
@@ -369,30 +382,30 @@ mod tests {
}
return false;
}
+
@com.android.aconfig.annotations.AssumeTrueForR8
private boolean isOptimizationEnabled() {
return false;
}
- private boolean getValue(String flagName) {
- Boolean value = this.mFlagMap.get(flagName);
- if (value == null) {
- throw new IllegalArgumentException(flagName + " is not set");
- }
- return value;
+
+ protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
+ return mGetValueImpl.test(flagName, getter);
}
- private Map<String, Boolean> mFlagMap = new HashMap<>(
- Map.ofEntries(
- Map.entry(Flags.FLAG_DISABLED_RO, false),
- Map.entry(Flags.FLAG_DISABLED_RW, false),
- Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false),
- Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false),
- Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false),
- Map.entry(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, false),
- Map.entry(Flags.FLAG_ENABLED_RO, false),
- Map.entry(Flags.FLAG_ENABLED_RO_EXPORTED, false),
- Map.entry(Flags.FLAG_ENABLED_RW, false)
- )
- );
+
+ public List<String> getFlagNames() {
+ return Arrays.asList(
+ Flags.FLAG_DISABLED_RO,
+ Flags.FLAG_DISABLED_RW,
+ Flags.FLAG_DISABLED_RW_EXPORTED,
+ Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
+ Flags.FLAG_ENABLED_FIXED_RO,
+ Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
+ Flags.FLAG_ENABLED_RO,
+ Flags.FLAG_ENABLED_RO_EXPORTED,
+ Flags.FLAG_ENABLED_RW
+ );
+ }
+
private Set<String> mReadOnlyFlagsSet = new HashSet<>(
Arrays.asList(
Flags.FLAG_DISABLED_RO,
@@ -406,6 +419,49 @@ mod tests {
}
"#;
+ const EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT: &str = r#"
+ package com.android.aconfig.test;
+
+ import java.util.HashMap;
+ import java.util.Map;
+ import java.util.function.Predicate;
+
+ /** @hide */
+ public class FakeFeatureFlagsImpl extends CustomFeatureFlags {
+ private Map<String, Boolean> mFlagMap = new HashMap<>();
+
+ public FakeFeatureFlagsImpl() {
+ super(null);
+ // Initialize the map with null values
+ for (String flagName : getFlagNames()) {
+ mFlagMap.put(flagName, null);
+ }
+ }
+
+ @Override
+ protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
+ Boolean value = this.mFlagMap.get(flagName);
+ if (value == null) {
+ throw new IllegalArgumentException(flagName + " is not set");
+ }
+ return value;
+ }
+
+ public void setFlag(String flagName, boolean value) {
+ if (!this.mFlagMap.containsKey(flagName)) {
+ throw new IllegalArgumentException("no such flag " + flagName);
+ }
+ this.mFlagMap.put(flagName, value);
+ }
+
+ public void resetAll() {
+ for (Map.Entry entry : mFlagMap.entrySet()) {
+ entry.setValue(null);
+ }
+ }
+ }
+ "#;
+
#[test]
fn test_generate_java_code_production() {
let parsed_flags = crate::test::parse_test_flags();
@@ -549,6 +605,10 @@ mod tests {
("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_content),
("com/android/aconfig/test/FeatureFlags.java", EXPECTED_FEATUREFLAGS_COMMON_CONTENT),
(
+ "com/android/aconfig/test/CustomFeatureFlags.java",
+ EXPECTED_CUSTOMFEATUREFLAGS_CONTENT,
+ ),
+ (
"com/android/aconfig/test/FakeFeatureFlagsImpl.java",
EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT,
),
@@ -671,55 +731,53 @@ mod tests {
}
}"#;
- let expect_fake_feature_flags_impl_content = r#"
+ let expect_custom_feature_flags_content = r#"
package com.android.aconfig.test;
+
import java.util.Arrays;
- import java.util.HashMap;
import java.util.HashSet;
- import java.util.Map;
+ import java.util.List;
import java.util.Set;
+ import java.util.function.BiPredicate;
+ import java.util.function.Predicate;
+
/** @hide */
- public class FakeFeatureFlagsImpl implements FeatureFlags {
- public FakeFeatureFlagsImpl() {
- resetAll();
+ public class CustomFeatureFlags implements FeatureFlags {
+
+ private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
+
+ public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
+ mGetValueImpl = getValueImpl;
}
+
@Override
public boolean disabledRwExported() {
- return getValue(Flags.FLAG_DISABLED_RW_EXPORTED);
+ return getValue(Flags.FLAG_DISABLED_RW_EXPORTED,
+ FeatureFlags::disabledRwExported);
}
@Override
public boolean enabledFixedRoExported() {
- return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED);
+ return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
+ FeatureFlags::enabledFixedRoExported);
}
@Override
public boolean enabledRoExported() {
- return getValue(Flags.FLAG_ENABLED_RO_EXPORTED);
- }
- public void setFlag(String flagName, boolean value) {
- if (!this.mFlagMap.containsKey(flagName)) {
- throw new IllegalArgumentException("no such flag " + flagName);
- }
- this.mFlagMap.put(flagName, value);
+ return getValue(Flags.FLAG_ENABLED_RO_EXPORTED,
+ FeatureFlags::enabledRoExported);
}
- public void resetAll() {
- for (Map.Entry entry : mFlagMap.entrySet()) {
- entry.setValue(null);
- }
+
+ protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
+ return mGetValueImpl.test(flagName, getter);
}
- private boolean getValue(String flagName) {
- Boolean value = this.mFlagMap.get(flagName);
- if (value == null) {
- throw new IllegalArgumentException(flagName + " is not set");
- }
- return value;
+
+ public List<String> getFlagNames() {
+ return Arrays.asList(
+ Flags.FLAG_DISABLED_RW_EXPORTED,
+ Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
+ Flags.FLAG_ENABLED_RO_EXPORTED
+ );
}
- private Map<String, Boolean> mFlagMap = new HashMap<>(
- Map.ofEntries(
- Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false),
- Map.entry(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, false),
- Map.entry(Flags.FLAG_ENABLED_RO_EXPORTED, false)
- )
- );
+
private Set<String> mReadOnlyFlagsSet = new HashSet<>(
Arrays.asList(
""
@@ -733,8 +791,12 @@ mod tests {
("com/android/aconfig/test/FeatureFlags.java", expect_feature_flags_content),
("com/android/aconfig/test/FeatureFlagsImpl.java", expect_feature_flags_impl_content),
(
+ "com/android/aconfig/test/CustomFeatureFlags.java",
+ expect_custom_feature_flags_content,
+ ),
+ (
"com/android/aconfig/test/FakeFeatureFlagsImpl.java",
- expect_fake_feature_flags_impl_content,
+ EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT,
),
]);
@@ -854,6 +916,10 @@ mod tests {
("com/android/aconfig/test/FeatureFlags.java", EXPECTED_FEATUREFLAGS_COMMON_CONTENT),
("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_content),
(
+ "com/android/aconfig/test/CustomFeatureFlags.java",
+ EXPECTED_CUSTOMFEATUREFLAGS_CONTENT,
+ ),
+ (
"com/android/aconfig/test/FakeFeatureFlagsImpl.java",
EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT,
),
@@ -1020,61 +1086,64 @@ mod tests {
private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
}"#;
- let expect_fakefeatureflags_content = r#"
+ let expect_customfeatureflags_content = r#"
package com.android.aconfig.test;
+
// TODO(b/303773055): Remove the annotation after access issue is resolved.
import android.compat.annotation.UnsupportedAppUsage;
import java.util.Arrays;
- import java.util.HashMap;
import java.util.HashSet;
- import java.util.Map;
+ import java.util.List;
import java.util.Set;
+ import java.util.function.BiPredicate;
+ import java.util.function.Predicate;
+
/** @hide */
- public class FakeFeatureFlagsImpl implements FeatureFlags {
- public FakeFeatureFlagsImpl() {
- resetAll();
+ public class CustomFeatureFlags implements FeatureFlags {
+
+ private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
+
+ public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
+ mGetValueImpl = getValueImpl;
}
+
@Override
@UnsupportedAppUsage
public boolean disabledRo() {
- return getValue(Flags.FLAG_DISABLED_RO);
+ return getValue(Flags.FLAG_DISABLED_RO,
+ FeatureFlags::disabledRo);
}
@Override
@UnsupportedAppUsage
public boolean disabledRw() {
- return getValue(Flags.FLAG_DISABLED_RW);
+ return getValue(Flags.FLAG_DISABLED_RW,
+ FeatureFlags::disabledRw);
}
@Override
@UnsupportedAppUsage
public boolean disabledRwInOtherNamespace() {
- return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE);
+ return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
+ FeatureFlags::disabledRwInOtherNamespace);
}
@Override
@UnsupportedAppUsage
public boolean enabledFixedRo() {
- return getValue(Flags.FLAG_ENABLED_FIXED_RO);
+ return getValue(Flags.FLAG_ENABLED_FIXED_RO,
+ FeatureFlags::enabledFixedRo);
}
@Override
@UnsupportedAppUsage
public boolean enabledRo() {
- return getValue(Flags.FLAG_ENABLED_RO);
+ return getValue(Flags.FLAG_ENABLED_RO,
+ FeatureFlags::enabledRo);
}
@Override
@UnsupportedAppUsage
public boolean enabledRw() {
- return getValue(Flags.FLAG_ENABLED_RW);
- }
- public void setFlag(String flagName, boolean value) {
- if (!this.mFlagMap.containsKey(flagName)) {
- throw new IllegalArgumentException("no such flag " + flagName);
- }
- this.mFlagMap.put(flagName, value);
- }
- public void resetAll() {
- for (Map.Entry entry : mFlagMap.entrySet()) {
- entry.setValue(null);
- }
+ return getValue(Flags.FLAG_ENABLED_RW,
+ FeatureFlags::enabledRw);
}
+
public boolean isFlagReadOnlyOptimized(String flagName) {
if (mReadOnlyFlagsSet.contains(flagName) &&
isOptimizationEnabled()) {
@@ -1082,27 +1151,27 @@ mod tests {
}
return false;
}
+
@com.android.aconfig.annotations.AssumeTrueForR8
private boolean isOptimizationEnabled() {
return false;
}
- private boolean getValue(String flagName) {
- Boolean value = this.mFlagMap.get(flagName);
- if (value == null) {
- throw new IllegalArgumentException(flagName + " is not set");
- }
- return value;
- }
- private Map<String, Boolean> mFlagMap = new HashMap<>(
- Map.ofEntries(
- Map.entry(Flags.FLAG_DISABLED_RO, false),
- Map.entry(Flags.FLAG_DISABLED_RW, false),
- Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false),
- Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false),
- Map.entry(Flags.FLAG_ENABLED_RO, false),
- Map.entry(Flags.FLAG_ENABLED_RW, false)
- )
- );
+
+ protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
+ return mGetValueImpl.test(flagName, getter);
+ }
+
+ public List<String> getFlagNames() {
+ return Arrays.asList(
+ Flags.FLAG_DISABLED_RO,
+ Flags.FLAG_DISABLED_RW,
+ Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
+ Flags.FLAG_ENABLED_FIXED_RO,
+ Flags.FLAG_ENABLED_RO,
+ Flags.FLAG_ENABLED_RW
+ );
+ }
+
private Set<String> mReadOnlyFlagsSet = new HashSet<>(
Arrays.asList(
Flags.FLAG_DISABLED_RO,
@@ -1116,11 +1185,16 @@ mod tests {
);
}
"#;
+
let mut file_set = HashMap::from([
("com/android/aconfig/test/Flags.java", expect_flags_content),
("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_content),
("com/android/aconfig/test/FeatureFlags.java", expect_featureflags_content),
- ("com/android/aconfig/test/FakeFeatureFlagsImpl.java", expect_fakefeatureflags_content),
+ ("com/android/aconfig/test/CustomFeatureFlags.java", expect_customfeatureflags_content),
+ (
+ "com/android/aconfig/test/FakeFeatureFlagsImpl.java",
+ EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT,
+ ),
]);
for file in generated_files {
diff --git a/tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template b/tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template
new file mode 100644
index 0000000000..b82b9cb827
--- /dev/null
+++ b/tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template
@@ -0,0 +1,70 @@
+package {package_name};
+
+{{ if not library_exported- }}
+// TODO(b/303773055): Remove the annotation after access issue is resolved.
+import android.compat.annotation.UnsupportedAppUsage;
+{{ -endif }}
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.BiPredicate;
+import java.util.function.Predicate;
+
+/** @hide */
+public class CustomFeatureFlags implements FeatureFlags \{
+
+ private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
+
+ public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) \{
+ mGetValueImpl = getValueImpl;
+ }
+
+{{ -for item in flag_elements}}
+ @Override
+{{ if not library_exported }} @UnsupportedAppUsage{{ -endif }}
+ public boolean {item.method_name}() \{
+ return getValue(Flags.FLAG_{item.flag_name_constant_suffix},
+ FeatureFlags::{item.method_name});
+ }
+{{ endfor }}
+
+{{ -if not library_exported }}
+ public boolean isFlagReadOnlyOptimized(String flagName) \{
+ if (mReadOnlyFlagsSet.contains(flagName) &&
+ isOptimizationEnabled()) \{
+ return true;
+ }
+ return false;
+ }
+
+ @com.android.aconfig.annotations.AssumeTrueForR8
+ private boolean isOptimizationEnabled() \{
+ return false;
+ }
+{{ -endif }}
+
+ protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) \{
+ return mGetValueImpl.test(flagName, getter);
+ }
+
+ public List<String> getFlagNames() \{
+ return Arrays.asList(
+ {{ -for item in flag_elements }}
+ Flags.FLAG_{item.flag_name_constant_suffix}
+ {{ -if not @last }},{{ endif }}
+ {{ -endfor }}
+ );
+ }
+
+ private Set<String> mReadOnlyFlagsSet = new HashSet<>(
+ Arrays.asList(
+ {{ -for item in flag_elements }}
+ {{ -if not item.is_read_write }}
+ Flags.FLAG_{item.flag_name_constant_suffix},
+ {{ -endif }}
+ {{ -endfor }}
+ ""{# The empty string here is to resolve the ending comma #}
+ )
+ );
+}
diff --git a/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template
index 177e711e77..c20d3c5061 100644
--- a/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template
+++ b/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template
@@ -1,27 +1,30 @@
package {package_name};
-{{ if not library_exported- }}
-// TODO(b/303773055): Remove the annotation after access issue is resolved.
-import android.compat.annotation.UnsupportedAppUsage;
-{{ -endif }}
-import java.util.Arrays;
+
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
+import java.util.function.Predicate;
/** @hide */
-public class FakeFeatureFlagsImpl implements FeatureFlags \{
+public class FakeFeatureFlagsImpl extends CustomFeatureFlags \{
+ private Map<String, Boolean> mFlagMap = new HashMap<>();
+
public FakeFeatureFlagsImpl() \{
- resetAll();
+ super(null);
+ // Initialize the map with null values
+ for (String flagName : getFlagNames()) \{
+ mFlagMap.put(flagName, null);
+ }
}
-{{ for item in flag_elements}}
@Override
-{{ if not library_exported }} @UnsupportedAppUsage{{ -endif }}
- public boolean {item.method_name}() \{
- return getValue(Flags.FLAG_{item.flag_name_constant_suffix});
+ protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) \{
+ Boolean value = this.mFlagMap.get(flagName);
+ if (value == null) \{
+ throw new IllegalArgumentException(flagName + " is not set");
+ }
+ return value;
}
-{{ endfor}}
+
public void setFlag(String flagName, boolean value) \{
if (!this.mFlagMap.containsKey(flagName)) \{
throw new IllegalArgumentException("no such flag " + flagName);
@@ -34,46 +37,4 @@ public class FakeFeatureFlagsImpl implements FeatureFlags \{
entry.setValue(null);
}
}
-{{ if not library_exported }}
- public boolean isFlagReadOnlyOptimized(String flagName) \{
- if (mReadOnlyFlagsSet.contains(flagName) &&
- isOptimizationEnabled()) \{
- return true;
- }
- return false;
- }
-
- @com.android.aconfig.annotations.AssumeTrueForR8
- private boolean isOptimizationEnabled() \{
- return false;
- }
-{{ -endif }}
- private boolean getValue(String flagName) \{
- Boolean value = this.mFlagMap.get(flagName);
- if (value == null) \{
- throw new IllegalArgumentException(flagName + " is not set");
- }
- return value;
- }
-
-
- private Map<String, Boolean> mFlagMap = new HashMap<>(
- Map.ofEntries(
- {{ -for item in flag_elements }}
- Map.entry(Flags.FLAG_{item.flag_name_constant_suffix}, false)
- {{ -if not @last }},{{ endif }}
- {{ -endfor }}
- )
- );
-
- private Set<String> mReadOnlyFlagsSet = new HashSet<>(
- Arrays.asList(
- {{ -for item in flag_elements }}
- {{ -if not item.is_read_write }}
- Flags.FLAG_{item.flag_name_constant_suffix},
- {{ -endif }}
- {{ -endfor }}
- ""{# The empty string here is to resolve the ending comma #}
- )
- );
}