Merge "Generate CustomFeatureFlags" into main

This commit is contained in:
Jeff DeCew
2024-04-26 18:39:43 +00:00
committed by Gerrit Code Review
3 changed files with 288 additions and 183 deletions

View File

@@ -63,19 +63,26 @@ where
"FeatureFlags.java", "FeatureFlags.java",
include_str!("../../templates/FeatureFlags.java.template"), include_str!("../../templates/FeatureFlags.java.template"),
)?; )?;
template.add_template(
"CustomFeatureFlags.java",
include_str!("../../templates/CustomFeatureFlags.java.template"),
)?;
template.add_template( template.add_template(
"FakeFeatureFlagsImpl.java", "FakeFeatureFlagsImpl.java",
include_str!("../../templates/FakeFeatureFlagsImpl.java.template"), include_str!("../../templates/FakeFeatureFlagsImpl.java.template"),
)?; )?;
let path: PathBuf = package.split('.').collect(); let path: PathBuf = package.split('.').collect();
["Flags.java", "FeatureFlags.java", "FeatureFlagsImpl.java", "FakeFeatureFlagsImpl.java"] [
"Flags.java",
"FeatureFlags.java",
"FeatureFlagsImpl.java",
"CustomFeatureFlags.java",
"FakeFeatureFlagsImpl.java",
]
.iter() .iter()
.map(|file| { .map(|file| {
Ok(OutputFile { Ok(OutputFile { contents: template.render(file, &context)?.into(), path: path.join(file) })
contents: template.render(file, &context)?.into(),
path: path.join(file),
})
}) })
.collect::<Result<Vec<OutputFile>>>() .collect::<Result<Vec<OutputFile>>>()
} }
@@ -292,76 +299,82 @@ mod tests {
} }
"#; "#;
const EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT: &str = r#" const EXPECTED_CUSTOMFEATUREFLAGS_CONTENT: &str = r#"
package com.android.aconfig.test; package com.android.aconfig.test;
// TODO(b/303773055): Remove the annotation after access issue is resolved. // TODO(b/303773055): Remove the annotation after access issue is resolved.
import android.compat.annotation.UnsupportedAppUsage; import android.compat.annotation.UnsupportedAppUsage;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
/** @hide */ /** @hide */
public class FakeFeatureFlagsImpl implements FeatureFlags { public class CustomFeatureFlags implements FeatureFlags {
public FakeFeatureFlagsImpl() {
resetAll(); private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
mGetValueImpl = getValueImpl;
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disabledRo() { public boolean disabledRo() {
return getValue(Flags.FLAG_DISABLED_RO); return getValue(Flags.FLAG_DISABLED_RO,
FeatureFlags::disabledRo);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disabledRw() { public boolean disabledRw() {
return getValue(Flags.FLAG_DISABLED_RW); return getValue(Flags.FLAG_DISABLED_RW,
FeatureFlags::disabledRw);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disabledRwExported() { public boolean disabledRwExported() {
return getValue(Flags.FLAG_DISABLED_RW_EXPORTED); return getValue(Flags.FLAG_DISABLED_RW_EXPORTED,
FeatureFlags::disabledRwExported);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disabledRwInOtherNamespace() { public boolean disabledRwInOtherNamespace() {
return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE); return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
FeatureFlags::disabledRwInOtherNamespace);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean enabledFixedRo() { public boolean enabledFixedRo() {
return getValue(Flags.FLAG_ENABLED_FIXED_RO); return getValue(Flags.FLAG_ENABLED_FIXED_RO,
FeatureFlags::enabledFixedRo);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean enabledFixedRoExported() { public boolean enabledFixedRoExported() {
return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED); return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
FeatureFlags::enabledFixedRoExported);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean enabledRo() { public boolean enabledRo() {
return getValue(Flags.FLAG_ENABLED_RO); return getValue(Flags.FLAG_ENABLED_RO,
FeatureFlags::enabledRo);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean enabledRoExported() { public boolean enabledRoExported() {
return getValue(Flags.FLAG_ENABLED_RO_EXPORTED); return getValue(Flags.FLAG_ENABLED_RO_EXPORTED,
FeatureFlags::enabledRoExported);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean enabledRw() { public boolean enabledRw() {
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);
}
} }
public boolean isFlagReadOnlyOptimized(String flagName) { public boolean isFlagReadOnlyOptimized(String flagName) {
if (mReadOnlyFlagsSet.contains(flagName) && if (mReadOnlyFlagsSet.contains(flagName) &&
isOptimizationEnabled()) { isOptimizationEnabled()) {
@@ -369,30 +382,30 @@ mod tests {
} }
return false; return false;
} }
@com.android.aconfig.annotations.AssumeTrueForR8 @com.android.aconfig.annotations.AssumeTrueForR8
private boolean isOptimizationEnabled() { private boolean isOptimizationEnabled() {
return false; return false;
} }
private boolean getValue(String flagName) {
Boolean value = this.mFlagMap.get(flagName); protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
if (value == null) { return mGetValueImpl.test(flagName, getter);
throw new IllegalArgumentException(flagName + " is not set");
} }
return value;
} public List<String> getFlagNames() {
private Map<String, Boolean> mFlagMap = new HashMap<>( return Arrays.asList(
Map.ofEntries( Flags.FLAG_DISABLED_RO,
Map.entry(Flags.FLAG_DISABLED_RO, false), Flags.FLAG_DISABLED_RW,
Map.entry(Flags.FLAG_DISABLED_RW, false), Flags.FLAG_DISABLED_RW_EXPORTED,
Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false), Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false), Flags.FLAG_ENABLED_FIXED_RO,
Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false), Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
Map.entry(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, false), Flags.FLAG_ENABLED_RO,
Map.entry(Flags.FLAG_ENABLED_RO, false), Flags.FLAG_ENABLED_RO_EXPORTED,
Map.entry(Flags.FLAG_ENABLED_RO_EXPORTED, false), Flags.FLAG_ENABLED_RW
Map.entry(Flags.FLAG_ENABLED_RW, false)
)
); );
}
private Set<String> mReadOnlyFlagsSet = new HashSet<>( private Set<String> mReadOnlyFlagsSet = new HashSet<>(
Arrays.asList( Arrays.asList(
Flags.FLAG_DISABLED_RO, 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] #[test]
fn test_generate_java_code_production() { fn test_generate_java_code_production() {
let parsed_flags = crate::test::parse_test_flags(); let parsed_flags = crate::test::parse_test_flags();
@@ -548,6 +604,10 @@ mod tests {
("com/android/aconfig/test/Flags.java", expect_flags_content.as_str()), ("com/android/aconfig/test/Flags.java", expect_flags_content.as_str()),
("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_content), ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_content),
("com/android/aconfig/test/FeatureFlags.java", EXPECTED_FEATUREFLAGS_COMMON_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", "com/android/aconfig/test/FakeFeatureFlagsImpl.java",
EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT, 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; package com.android.aconfig.test;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
/** @hide */ /** @hide */
public class FakeFeatureFlagsImpl implements FeatureFlags { public class CustomFeatureFlags implements FeatureFlags {
public FakeFeatureFlagsImpl() {
resetAll(); private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
mGetValueImpl = getValueImpl;
} }
@Override @Override
public boolean disabledRwExported() { public boolean disabledRwExported() {
return getValue(Flags.FLAG_DISABLED_RW_EXPORTED); return getValue(Flags.FLAG_DISABLED_RW_EXPORTED,
FeatureFlags::disabledRwExported);
} }
@Override @Override
public boolean enabledFixedRoExported() { public boolean enabledFixedRoExported() {
return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED); return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
FeatureFlags::enabledFixedRoExported);
} }
@Override @Override
public boolean enabledRoExported() { public boolean enabledRoExported() {
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)) { protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
throw new IllegalArgumentException("no such flag " + flagName); return mGetValueImpl.test(flagName, getter);
} }
this.mFlagMap.put(flagName, value);
} public List<String> getFlagNames() {
public void resetAll() { return Arrays.asList(
for (Map.Entry entry : mFlagMap.entrySet()) { Flags.FLAG_DISABLED_RW_EXPORTED,
entry.setValue(null); 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)
)
); );
}
private Set<String> mReadOnlyFlagsSet = new HashSet<>( private Set<String> mReadOnlyFlagsSet = new HashSet<>(
Arrays.asList( Arrays.asList(
"" ""
@@ -732,9 +790,13 @@ mod tests {
("com/android/aconfig/test/Flags.java", expect_flags_content), ("com/android/aconfig/test/Flags.java", expect_flags_content),
("com/android/aconfig/test/FeatureFlags.java", expect_feature_flags_content), ("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/FeatureFlagsImpl.java", expect_feature_flags_impl_content),
(
"com/android/aconfig/test/CustomFeatureFlags.java",
expect_custom_feature_flags_content,
),
( (
"com/android/aconfig/test/FakeFeatureFlagsImpl.java", "com/android/aconfig/test/FakeFeatureFlagsImpl.java",
expect_fake_feature_flags_impl_content, EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT,
), ),
]); ]);
@@ -853,6 +915,10 @@ mod tests {
("com/android/aconfig/test/Flags.java", expect_flags_content.as_str()), ("com/android/aconfig/test/Flags.java", expect_flags_content.as_str()),
("com/android/aconfig/test/FeatureFlags.java", EXPECTED_FEATUREFLAGS_COMMON_CONTENT), ("com/android/aconfig/test/FeatureFlags.java", EXPECTED_FEATUREFLAGS_COMMON_CONTENT),
("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_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", "com/android/aconfig/test/FakeFeatureFlagsImpl.java",
EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT, EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT,
@@ -1020,61 +1086,64 @@ mod tests {
private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl(); private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl();
}"#; }"#;
let expect_fakefeatureflags_content = r#" let expect_customfeatureflags_content = r#"
package com.android.aconfig.test; package com.android.aconfig.test;
// TODO(b/303773055): Remove the annotation after access issue is resolved. // TODO(b/303773055): Remove the annotation after access issue is resolved.
import android.compat.annotation.UnsupportedAppUsage; import android.compat.annotation.UnsupportedAppUsage;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
/** @hide */ /** @hide */
public class FakeFeatureFlagsImpl implements FeatureFlags { public class CustomFeatureFlags implements FeatureFlags {
public FakeFeatureFlagsImpl() {
resetAll(); private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl;
public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) {
mGetValueImpl = getValueImpl;
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disabledRo() { public boolean disabledRo() {
return getValue(Flags.FLAG_DISABLED_RO); return getValue(Flags.FLAG_DISABLED_RO,
FeatureFlags::disabledRo);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disabledRw() { public boolean disabledRw() {
return getValue(Flags.FLAG_DISABLED_RW); return getValue(Flags.FLAG_DISABLED_RW,
FeatureFlags::disabledRw);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean disabledRwInOtherNamespace() { public boolean disabledRwInOtherNamespace() {
return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE); return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
FeatureFlags::disabledRwInOtherNamespace);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean enabledFixedRo() { public boolean enabledFixedRo() {
return getValue(Flags.FLAG_ENABLED_FIXED_RO); return getValue(Flags.FLAG_ENABLED_FIXED_RO,
FeatureFlags::enabledFixedRo);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean enabledRo() { public boolean enabledRo() {
return getValue(Flags.FLAG_ENABLED_RO); return getValue(Flags.FLAG_ENABLED_RO,
FeatureFlags::enabledRo);
} }
@Override @Override
@UnsupportedAppUsage @UnsupportedAppUsage
public boolean enabledRw() { public boolean enabledRw() {
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);
}
} }
public boolean isFlagReadOnlyOptimized(String flagName) { public boolean isFlagReadOnlyOptimized(String flagName) {
if (mReadOnlyFlagsSet.contains(flagName) && if (mReadOnlyFlagsSet.contains(flagName) &&
isOptimizationEnabled()) { isOptimizationEnabled()) {
@@ -1082,27 +1151,27 @@ mod tests {
} }
return false; return false;
} }
@com.android.aconfig.annotations.AssumeTrueForR8 @com.android.aconfig.annotations.AssumeTrueForR8
private boolean isOptimizationEnabled() { private boolean isOptimizationEnabled() {
return false; return false;
} }
private boolean getValue(String flagName) {
Boolean value = this.mFlagMap.get(flagName); protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) {
if (value == null) { return mGetValueImpl.test(flagName, getter);
throw new IllegalArgumentException(flagName + " is not set");
} }
return value;
} public List<String> getFlagNames() {
private Map<String, Boolean> mFlagMap = new HashMap<>( return Arrays.asList(
Map.ofEntries( Flags.FLAG_DISABLED_RO,
Map.entry(Flags.FLAG_DISABLED_RO, false), Flags.FLAG_DISABLED_RW,
Map.entry(Flags.FLAG_DISABLED_RW, false), Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE,
Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false), Flags.FLAG_ENABLED_FIXED_RO,
Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false), Flags.FLAG_ENABLED_RO,
Map.entry(Flags.FLAG_ENABLED_RO, false), Flags.FLAG_ENABLED_RW
Map.entry(Flags.FLAG_ENABLED_RW, false)
)
); );
}
private Set<String> mReadOnlyFlagsSet = new HashSet<>( private Set<String> mReadOnlyFlagsSet = new HashSet<>(
Arrays.asList( Arrays.asList(
Flags.FLAG_DISABLED_RO, Flags.FLAG_DISABLED_RO,
@@ -1116,11 +1185,16 @@ mod tests {
); );
} }
"#; "#;
let mut file_set = HashMap::from([ let mut file_set = HashMap::from([
("com/android/aconfig/test/Flags.java", expect_flags_content), ("com/android/aconfig/test/Flags.java", expect_flags_content),
("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_content), ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_content),
("com/android/aconfig/test/FeatureFlags.java", expect_featureflags_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 { for file in generated_files {

View File

@@ -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 #}
)
);
}

View File

@@ -1,27 +1,30 @@
package {package_name}; 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.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.function.Predicate;
/** @hide */ /** @hide */
public class FakeFeatureFlagsImpl implements FeatureFlags \{ public class FakeFeatureFlagsImpl extends CustomFeatureFlags \{
private Map<String, Boolean> mFlagMap = new HashMap<>();
public FakeFeatureFlagsImpl() \{ 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 @Override
{{ if not library_exported }} @UnsupportedAppUsage{{ -endif }} protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) \{
public boolean {item.method_name}() \{ Boolean value = this.mFlagMap.get(flagName);
return getValue(Flags.FLAG_{item.flag_name_constant_suffix}); if (value == null) \{
throw new IllegalArgumentException(flagName + " is not set");
} }
{{ endfor}} return value;
}
public void setFlag(String flagName, boolean value) \{ public void setFlag(String flagName, boolean value) \{
if (!this.mFlagMap.containsKey(flagName)) \{ if (!this.mFlagMap.containsKey(flagName)) \{
throw new IllegalArgumentException("no such flag " + flagName); throw new IllegalArgumentException("no such flag " + flagName);
@@ -34,46 +37,4 @@ public class FakeFeatureFlagsImpl implements FeatureFlags \{
entry.setValue(null); 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 #}
)
);
} }