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

Commit 988be5d9 authored by Jeremy Meyer's avatar Jeremy Meyer
Browse files

Add support for flag in resource directory names

This only applies it to the xml files with the top level element of
resources. Other file support will be in a later CL.

Test: Automated
Bug: 329436914
Flag: EXEMPT Aconfig not supported on host tools
Change-Id: I5e1e341e9de61073d05d9098b1b8b836025910b3
parent 3d8d4a18
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -103,6 +103,26 @@ public class ResourceFlaggingTest {
        assertThat(mResources.getIntArray(R.array.intarr1)).isEqualTo(new int[]{1, 2, 3});
    }

    @Test
    public void testDirectoryEnabledFlag() {
        assertThat(mResources.getBoolean(R.bool.bool8)).isTrue();
    }

    @Test
    public void testDirectoryDisabledFlag() {
        assertThat(mResources.getBoolean(R.bool.bool7)).isTrue();
    }

    @Test
    public void testDirectoryNegatedEnabledFlag() {
        assertThat(mResources.getBoolean(R.bool.bool9)).isTrue();
    }

    @Test
    public void testDirectoryNegatedDisabledFlag() {
        assertThat(mResources.getBoolean(R.bool.bool10)).isTrue();
    }

    @Test
    public void testLayoutWithDisabledElements() {
        LinearLayout ll = (LinearLayout) getLayoutInflater().inflate(R.layout.layout1, null);
+21 −11
Original line number Diff line number Diff line
@@ -546,8 +546,14 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
      {"symbol", std::mem_fn(&ResourceParser::ParseSymbol)},
  });

  std::string resource_type = parser->element_name();
  out_resource->flag = GetFlag(parser);
  std::string_view resource_type = parser->element_name();
  if (auto flag = GetFlag(parser)) {
    if (options_.flag) {
      diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
                   << "Resource flag are not allowed both in the path and in the file");
      return false;
    }
    out_resource->flag = std::move(flag);
    std::string error;
    auto flag_status = GetFlagStatus(out_resource->flag, options_.feature_flag_values, &error);
    if (flag_status) {
@@ -556,6 +562,10 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,
      diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number())) << error);
      return false;
    }
  } else if (options_.flag) {
    out_resource->flag = options_.flag;
    out_resource->flag_status = options_.flag_status;
  }

  // The value format accepted for this resource.
  uint32_t resource_format = 0u;
@@ -571,7 +581,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,

    // Items have their type encoded in the type attribute.
    if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
      resource_type = std::string(maybe_type.value());
      resource_type = maybe_type.value();
    } else {
      diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
                   << "<item> must have a 'type' attribute");
@@ -594,7 +604,7 @@ bool ResourceParser::ParseResource(xml::XmlPullParser* parser,

    // Bags have their type encoded in the type attribute.
    if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
      resource_type = std::string(maybe_type.value());
      resource_type = maybe_type.value();
    } else {
      diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
                   << "<bag> must have a 'type' attribute");
+5 −0
Original line number Diff line number Diff line
@@ -57,6 +57,11 @@ struct ResourceParserOptions {
  std::optional<Visibility::Level> visibility;

  FeatureFlagValues feature_flag_values;

  // The flag that should be applied to all resources parsed
  std::optional<FeatureFlagAttribute> flag;

  FlagStatus flag_status = FlagStatus::NoFlag;
};

struct FlattenedXmlSubTree {
+42 −1
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ struct ResourcePathData {
  std::string resource_dir;
  std::string name;
  std::string extension;
  std::string flag_name;

  // Original config str. We keep this because when we parse the config, we may add on
  // version qualifiers. We want to preserve the original input so the output is easily
@@ -81,6 +82,22 @@ static std::optional<ResourcePathData> ExtractResourcePathData(const std::string
                                                               std::string* out_error,
                                                               const CompileOptions& options) {
  std::vector<std::string> parts = util::Split(path, dir_sep);

  std::string flag_name;
  // Check for a flag
  for (auto iter = parts.begin(); iter != parts.end();) {
    if (iter->starts_with("flag(") && iter->ends_with(")")) {
      if (!flag_name.empty()) {
        if (out_error) *out_error = "resource path cannot contain more than one flag directory";
        return {};
      }
      flag_name = iter->substr(5, iter->size() - 6);
      iter = parts.erase(iter);
    } else {
      ++iter;
    }
  }

  if (parts.size() < 2) {
    if (out_error) *out_error = "bad resource path";
    return {};
@@ -131,6 +148,7 @@ static std::optional<ResourcePathData> ExtractResourcePathData(const std::string
                          std::string(dir_str),
                          std::string(name),
                          std::string(extension),
                          std::move(flag_name),
                          std::string(config_str),
                          config};
}
@@ -142,6 +160,9 @@ static std::string BuildIntermediateContainerFilename(const ResourcePathData& da
    name << "-" << data.config_str;
  }
  name << "_" << data.name;
  if (!data.flag_name.empty()) {
    name << ".(" << data.flag_name << ")";
  }
  if (!data.extension.empty()) {
    name << "." << data.extension;
  }
@@ -163,7 +184,6 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
                                       << "failed to open file: " << fin->GetError());
      return false;
    }

    // Parse the values file from XML.
    xml::XmlPullParser xml_parser(fin.get());

@@ -177,6 +197,27 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options,
    // we try to parse the <public>, <public-group>, <java-symbol> or <symbol> tags.
    parser_options.visibility = options.visibility;

    if (!path_data.flag_name.empty()) {
      FeatureFlagAttribute flag;
      const auto& name = path_data.flag_name;
      if (name.starts_with('!')) {
        flag.negated = true;
        flag.name = name.substr(1);
      } else {
        flag.name = name;
      }
      parser_options.flag = flag;

      std::string error;
      auto flag_status = GetFlagStatus(flag, options.feature_flag_values, &error);
      if (flag_status) {
        parser_options.flag_status = std::move(flag_status.value());
      } else {
        context->GetDiagnostics()->Error(android::DiagMessage(path_data.source) << error);
        return false;
      }
    }

    ResourceParser res_parser(context->GetDiagnostics(), &table, path_data.source, path_data.config,
        parser_options);
    if (!res_parser.Parse(&xml_parser)) {
+8 −0
Original line number Diff line number Diff line
@@ -31,9 +31,17 @@ genrule {
        "res/values/ints.xml",
        "res/values/strings.xml",
        "res/layout/layout1.xml",
        "res/flag(test.package.falseFlag)/values/bools.xml",
        "res/values/flag(test.package.trueFlag)/bools.xml",
        "res/values/flag(!test.package.trueFlag)/bools.xml",
        "res/values/flag(!test.package.falseFlag)/bools.xml",
    ],
    out: [
        "values_bools.arsc.flat",
        "values_bools.(test.package.falseFlag).arsc.flat",
        "values_bools.(test.package.trueFlag).arsc.flat",
        "values_bools.(!test.package.falseFlag).arsc.flat",
        "values_bools.(!test.package.trueFlag).arsc.flat",
        "values_bools2.arsc.flat",
        "values_ints.arsc.flat",
        "values_strings.arsc.flat",
Loading