Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cfd7b0df authored by Jeff DeCew's avatar Jeff DeCew Committed by Gerrit Code Review
Browse files

Merge "Generate CustomFeatureFlags" into main

parents 5e6df98f c3bc24f3
Loading
Loading
Loading
Loading
+202 −128
Original line number Diff line number Diff line
@@ -63,19 +63,26 @@ where
        "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"]
    [
        "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),
            })
        Ok(OutputFile { contents: template.render(file, &context)?.into(), path: path.join(file) })
    })
    .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;

    // 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();
@@ -548,6 +604,10 @@ mod tests {
            ("com/android/aconfig/test/Flags.java", expect_flags_content.as_str()),
            ("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);
            }
            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 getValue(Flags.FLAG_ENABLED_RO_EXPORTED,
                    FeatureFlags::enabledRoExported);
            }
                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_RW_EXPORTED, false),
                    Map.entry(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, false),
                    Map.entry(Flags.FLAG_ENABLED_RO_EXPORTED, false)
                )

            public List<String> getFlagNames() {
                return Arrays.asList(
                    Flags.FLAG_DISABLED_RW_EXPORTED,
                    Flags.FLAG_ENABLED_FIXED_RO_EXPORTED,
                    Flags.FLAG_ENABLED_RO_EXPORTED
                );
            }

            private Set<String> mReadOnlyFlagsSet = new HashSet<>(
                Arrays.asList(
                    ""
@@ -732,9 +790,13 @@ mod tests {
            ("com/android/aconfig/test/Flags.java", expect_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/CustomFeatureFlags.java",
                expect_custom_feature_flags_content,
            ),
            (
                "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/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;

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

            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 {
+70 −0
Original line number Diff line number Diff line
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 #}
        )
    );
}
+17 −56
Original line number Diff line number Diff line
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");
        }
{{ endfor}}
        return value;
    }

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