diff options
| -rw-r--r-- | libs/androidfw/ResourceTypes.cpp | 7 | ||||
| -rw-r--r-- | tools/aapt2/ConfigDescription.cpp | 4 | ||||
| -rw-r--r-- | tools/aapt2/ConfigDescription.h | 90 | ||||
| -rw-r--r-- | tools/aapt2/cmd/Link.cpp | 86 | ||||
| -rw-r--r-- | tools/aapt2/integration-tests/AppOne/res/drawable/adaptive-icon.xml | 20 | ||||
| -rw-r--r-- | tools/aapt2/link/AutoVersioner.cpp | 33 | ||||
| -rw-r--r-- | tools/aapt2/link/AutoVersioner_test.cpp | 2 | ||||
| -rw-r--r-- | tools/aapt2/link/Linkers.h | 15 | ||||
| -rw-r--r-- | tools/aapt2/readme.md | 1 | ||||
| -rw-r--r-- | tools/aapt2/util/TypeTraits.h | 1 | ||||
| -rw-r--r-- | tools/aapt2/util/Util.h | 5 | ||||
| -rw-r--r-- | tools/aapt2/xml/XmlUtil.cpp | 60 | ||||
| -rw-r--r-- | tools/aapt2/xml/XmlUtil.h | 28 | 
13 files changed, 233 insertions, 119 deletions
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 0782269d7de1..99ccc98a1b31 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -1901,8 +1901,6 @@ int ResTable_config::compare(const ResTable_config& o) const {      if (diff != 0) return diff;      diff = (int32_t)(screenSize - o.screenSize);      if (diff != 0) return diff; -    diff = (int32_t)(version - o.version); -    if (diff != 0) return diff;      diff = (int32_t)(screenLayout - o.screenLayout);      if (diff != 0) return diff;      diff = (int32_t)(screenLayout2 - o.screenLayout2); @@ -1914,6 +1912,11 @@ int ResTable_config::compare(const ResTable_config& o) const {      diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);      if (diff != 0) return diff;      diff = (int32_t)(screenSizeDp - o.screenSizeDp); +    if (diff != 0) return diff; + +    // Version MUST be last to ensure that a sorted list of configurations will always have the +    // versions beside each other. +    diff = (int32_t)(version - o.version);      return (int)diff;  } diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp index 7ff0c7227c9c..f16d806fe5c7 100644 --- a/tools/aapt2/ConfigDescription.cpp +++ b/tools/aapt2/ConfigDescription.cpp @@ -987,4 +987,8 @@ bool ConfigDescription::IsCompatibleWith(const ConfigDescription& o) const {    return !ConflictsWith(o) && !Dominates(o) && !o.Dominates(*this);  } +::std::ostream& operator<<(::std::ostream& out, const ConfigDescription& o) { +  return out << o.toString().string(); +} +  }  // namespace aapt diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h index 65c96175091c..8c519a1a913c 100644 --- a/tools/aapt2/ConfigDescription.h +++ b/tools/aapt2/ConfigDescription.h @@ -24,30 +24,22 @@  namespace aapt { -/* - * Subclass of ResTable_config that adds convenient - * initialization and comparison methods. - */ +// Subclass of ResTable_config that adds convenient +// initialization and comparison methods.  struct ConfigDescription : public android::ResTable_config { -  /** -   * Returns an immutable default config. -   */ +  // Returns an immutable default config.    static const ConfigDescription& DefaultConfig(); -  /* -   * Parse a string of the form 'fr-sw600dp-land' and fill in the -   * given ResTable_config with resulting configuration parameters. -   * -   * The resulting configuration has the appropriate sdkVersion defined -   * for backwards compatibility. -   */ +  // Parse a string of the form 'fr-sw600dp-land' and fill in the +  // given ResTable_config with resulting configuration parameters. +  // +  // The resulting configuration has the appropriate sdkVersion defined +  // for backwards compatibility.    static bool Parse(const android::StringPiece& str, ConfigDescription* out = nullptr); -  /** -   * If the configuration uses an axis that was added after -   * the original Android release, make sure the SDK version -   * is set accordingly. -   */ +  // If the configuration uses an axis that was added after +  // the original Android release, make sure the SDK version +  // is set accordingly.    static void ApplyVersionForCompatibility(ConfigDescription* config);    ConfigDescription(); @@ -61,38 +53,30 @@ struct ConfigDescription : public android::ResTable_config {    ConfigDescription CopyWithoutSdkVersion() const; -  /** -   * A configuration X dominates another configuration Y, if X has at least the -   * precedence of Y and X is strictly more general than Y: for any type defined -   * by X, the same type is defined by Y with a value equal to or, in the case -   * of ranges, more specific than that of X. -   * -   * For example, the configuration 'en-w800dp' dominates 'en-rGB-w1024dp'. It -   * does not dominate 'fr', 'en-w720dp', or 'mcc001-en-w800dp'. -   */ +  // A configuration X dominates another configuration Y, if X has at least the +  // precedence of Y and X is strictly more general than Y: for any type defined +  // by X, the same type is defined by Y with a value equal to or, in the case +  // of ranges, more specific than that of X. +  // +  // For example, the configuration 'en-w800dp' dominates 'en-rGB-w1024dp'. It +  // does not dominate 'fr', 'en-w720dp', or 'mcc001-en-w800dp'.    bool Dominates(const ConfigDescription& o) const; -  /** -   * Returns true if this configuration defines a more important configuration -   * parameter than o. For example, "en" has higher precedence than "v23", -   * whereas "en" has the same precedence as "en-v23". -   */ +  // Returns true if this configuration defines a more important configuration +  // parameter than o. For example, "en" has higher precedence than "v23", +  // whereas "en" has the same precedence as "en-v23".    bool HasHigherPrecedenceThan(const ConfigDescription& o) const; -  /** -   * A configuration conflicts with another configuration if both -   * configurations define an incompatible configuration parameter. An -   * incompatible configuration parameter is a non-range, non-density parameter -   * that is defined in both configurations as a different, non-default value. -   */ +  // A configuration conflicts with another configuration if both +  // configurations define an incompatible configuration parameter. An +  // incompatible configuration parameter is a non-range, non-density parameter +  // that is defined in both configurations as a different, non-default value.    bool ConflictsWith(const ConfigDescription& o) const; -  /** -   * A configuration is compatible with another configuration if both -   * configurations can match a common concrete device configuration and are -   * unrelated by domination. For example, land-v11 conflicts with port-v21 -   * but is compatible with v21 (both land-v11 and v21 would match en-land-v23). -   */ +  // A configuration is compatible with another configuration if both +  // configurations can match a common concrete device configuration and are +  // unrelated by domination. For example, land-v11 conflicts with port-v21 +  // but is compatible with v21 (both land-v11 and v21 would match en-land-v23).    bool IsCompatibleWith(const ConfigDescription& o) const;    bool MatchWithDensity(const ConfigDescription& o) const; @@ -105,6 +89,8 @@ struct ConfigDescription : public android::ResTable_config {    bool operator>(const ConfigDescription& o) const;  }; +::std::ostream& operator<<(::std::ostream& out, const ConfigDescription& o); +  inline ConfigDescription::ConfigDescription() {    memset(this, 0, sizeof(*this));    size = sizeof(android::ResTable_config); @@ -123,15 +109,13 @@ inline ConfigDescription::ConfigDescription(ConfigDescription&& o) {    *this = o;  } -inline ConfigDescription& ConfigDescription::operator=( -    const android::ResTable_config& o) { +inline ConfigDescription& ConfigDescription::operator=(const android::ResTable_config& o) {    *static_cast<android::ResTable_config*>(this) = o;    size = sizeof(android::ResTable_config);    return *this;  } -inline ConfigDescription& ConfigDescription::operator=( -    const ConfigDescription& o) { +inline ConfigDescription& ConfigDescription::operator=(const ConfigDescription& o) {    *static_cast<android::ResTable_config*>(this) = o;    return *this;  } @@ -141,8 +125,7 @@ inline ConfigDescription& ConfigDescription::operator=(ConfigDescription&& o) {    return *this;  } -inline bool ConfigDescription::MatchWithDensity( -    const ConfigDescription& o) const { +inline bool ConfigDescription::MatchWithDensity(const ConfigDescription& o) const {    return match(o) && (density == 0 || density == o.density);  } @@ -170,11 +153,6 @@ inline bool ConfigDescription::operator>(const ConfigDescription& o) const {    return compare(o) > 0;  } -inline ::std::ostream& operator<<(::std::ostream& out, -                                  const ConfigDescription& o) { -  return out << o.toString().string(); -} -  }  // namespace aapt  #endif  // AAPT_CONFIG_DESCRIPTION_H diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp index e6bf3a6f9f56..353d734b69c6 100644 --- a/tools/aapt2/cmd/Link.cpp +++ b/tools/aapt2/cmd/Link.cpp @@ -60,6 +60,7 @@  #include "unflatten/BinaryResourceParser.h"  #include "util/Files.h"  #include "xml/XmlDom.h" +#include "xml/XmlUtil.h"  using android::StringPiece;  using android::base::StringPrintf; @@ -342,16 +343,18 @@ class ResourceFileFlattener {      ConfigDescription config;      // The entry this file came from. -    ResourceEntry* entry; +    ResourceEntry* entry = nullptr;      // The file to copy as-is. -    io::IFile* file_to_copy; +    io::IFile* file_to_copy = nullptr;      // The XML to process and flatten.      std::unique_ptr<xml::XmlResource> xml_to_flatten;      // The destination to write this file to.      std::string dst_path; + +    bool skip_versioning = false;    };    uint32_t GetCompressionFlags(const StringPiece& str); @@ -431,19 +434,6 @@ uint32_t ResourceFileFlattener::GetCompressionFlags(const StringPiece& str) {    return ArchiveEntry::kCompress;  } -static bool IsTransitionElement(const std::string& name) { -  return name == "fade" || name == "changeBounds" || name == "slide" || name == "explode" || -         name == "changeImageTransform" || name == "changeTransform" || -         name == "changeClipBounds" || name == "autoTransition" || name == "recolor" || -         name == "changeScroll" || name == "transitionSet" || name == "transition" || -         name == "transitionManager"; -} - -static bool IsVectorElement(const std::string& name) { -  return name == "vector" || name == "animated-vector" || name == "pathInterpolator" || -         name == "objectAnimator"; -} -  template <typename T>  std::vector<T> make_singleton_vec(T&& val) {    std::vector<T> vec; @@ -476,21 +466,10 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer      }    } -  if (options_.no_auto_version) { +  if (options_.no_auto_version || file_op->skip_versioning) {      return make_singleton_vec(std::move(file_op->xml_to_flatten));    } -  if (options_.no_version_vectors || options_.no_version_transitions) { -    // Skip this if it is a vector or animated-vector. -    xml::Element* el = xml::FindRootElement(doc); -    if (el && el->namespace_uri.empty()) { -      if ((options_.no_version_vectors && IsVectorElement(el->name)) || -          (options_.no_version_transitions && IsTransitionElement(el->name))) { -        return make_singleton_vec(std::move(file_op->xml_to_flatten)); -      } -    } -  } -    const ConfigDescription& config = file_op->config;    ResourceEntry* entry = file_op->entry; @@ -504,15 +483,26 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv    bool error = false;    std::map<std::pair<ConfigDescription, StringPiece>, FileOperation> config_sorted_files; +  int tag_version_options = 0; +  if (options_.no_version_vectors) { +    tag_version_options |= xml::kNoVersionVector; +  } + +  if (options_.no_version_transitions) { +    tag_version_options |= xml::kNoVersionTransition; +  } +    for (auto& pkg : table->packages) {      for (auto& type : pkg->types) {        // Sort by config and name, so that we get better locality in the zip file.        config_sorted_files.clear(); -      std::queue<FileOperation> file_operations;        // Populate the queue with all files in the ResourceTable.        for (auto& entry : type->entries) { -        for (auto& config_value : entry->values) { +        const auto values_end = entry->values.end(); +        for (auto values_iter = entry->values.begin(); values_iter != values_end; ++values_iter) { +          ResourceConfigValue* config_value = values_iter->get(); +            // WARNING! Do not insert or remove any resources while executing in this scope. It will            // corrupt the iteration order. @@ -554,6 +544,44 @@ bool ResourceFileFlattener::Flatten(ResourceTable* table, IArchiveWriter* archiv              file_op.xml_to_flatten->file.config = config_value->config;              file_op.xml_to_flatten->file.source = file_ref->GetSource();              file_op.xml_to_flatten->file.name = ResourceName(pkg->name, type->type, entry->name); + +            // Check if this file needs to be versioned based on tag rules. +            xml::Element* root_el = xml::FindRootElement(file_op.xml_to_flatten.get()); +            if (root_el == nullptr) { +              context_->GetDiagnostics()->Error(DiagMessage(file->GetSource()) +                                                << "failed to find the root XML element"); +              return false; +            } + +            if (root_el->namespace_uri.empty()) { +              if (Maybe<xml::TagApiVersionResult> result = +                      xml::GetXmlTagApiVersion(root_el->name, tag_version_options)) { +                file_op.skip_versioning = result.value().skip_version; +                if (result.value().api_version && config_value->config.sdkVersion == 0u) { +                  const ApiVersion min_tag_version = result.value().api_version.value(); +                  // Only version it if it doesn't specify its own version and the version is +                  // greater than the minSdk. +                  const util::Range<ApiVersion> valid_range{ +                      context_->GetMinSdkVersion() + 1, +                      FindNextApiVersionForConfigInSortedVector(values_iter, values_end)}; +                  if (valid_range.Contains(min_tag_version)) { +                    // Update the configurations. The iteration order will not be affected +                    // since sdkVersions in ConfigDescriptions are the last property compared +                    // in the sort function. +                    if (context_->IsVerbose()) { +                      context_->GetDiagnostics()->Note(DiagMessage(config_value->value->GetSource()) +                                                       << "auto-versioning XML resource to API " +                                                       << min_tag_version); +                    } +                    const_cast<ConfigDescription&>(config_value->config).sdkVersion = +                        static_cast<uint16_t>(min_tag_version); +                    file_op.config.sdkVersion = static_cast<uint16_t>(min_tag_version); +                    file_op.xml_to_flatten->file.config.sdkVersion = +                        static_cast<uint16_t>(min_tag_version); +                  } +                } +              } +            }            }            // NOTE(adamlesinski): Explicitly construct a StringPiece here, or diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/adaptive-icon.xml b/tools/aapt2/integration-tests/AppOne/res/drawable/adaptive-icon.xml new file mode 100644 index 000000000000..e3cda7e1e979 --- /dev/null +++ b/tools/aapt2/integration-tests/AppOne/res/drawable/adaptive-icon.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2017 The Android Open Source Project + +     Licensed under the Apache License, Version 2.0 (the "License"); +     you may not use this file except in compliance with the License. +     You may obtain a copy of the License at + +          http://www.apache.org/licenses/LICENSE-2.0 + +     Unless required by applicable law or agreed to in writing, software +     distributed under the License is distributed on an "AS IS" BASIS, +     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +     See the License for the specific language governing permissions and +     limitations under the License. +--> + +<adaptive-icon xmlns:android="http://schema.android.com/apk/res/android"> +    <background android:drawable="@android:color/white" /> +    <foreground android:drawable="@drawable/image" /> +</adaptive-icon> diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp index f80c6e9b34d3..4ac70d91bcc9 100644 --- a/tools/aapt2/link/AutoVersioner.cpp +++ b/tools/aapt2/link/AutoVersioner.cpp @@ -34,6 +34,19 @@ bool ShouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDes    return sdk_version_to_generate < FindNextApiVersionForConfig(entry, config);  } +ApiVersion FindNextApiVersionForConfigInSortedVector( +    std::vector<std::unique_ptr<ResourceConfigValue>>::const_iterator start, +    std::vector<std::unique_ptr<ResourceConfigValue>>::const_iterator end) { +  const ConfigDescription start_config = (*start)->config.CopyWithoutSdkVersion(); +  ++start; +  if (start != end) { +    if ((*start)->config.CopyWithoutSdkVersion() == start_config) { +      return static_cast<ApiVersion>((*start)->config.sdkVersion); +    } +  } +  return std::numeric_limits<ApiVersion>::max(); +} +  ApiVersion FindNextApiVersionForConfig(const ResourceEntry* entry,                                         const ConfigDescription& config) {    const auto end_iter = entry->values.end(); @@ -46,25 +59,7 @@ ApiVersion FindNextApiVersionForConfig(const ResourceEntry* entry,    // The source config came from this list, so it should be here.    CHECK(iter != entry->values.end()); -  ++iter; - -  // The next configuration either only varies in sdkVersion, or it is completely different -  // and therefore incompatible. If it is incompatible, we must generate the versioned resource. - -  // NOTE: The ordering of configurations takes sdkVersion as higher precedence than other -  // qualifiers, so we need to iterate through the entire list to be sure there -  // are no higher sdk level versions of this resource. -  ConfigDescription temp_config(config); -  for (; iter != end_iter; ++iter) { -    temp_config.sdkVersion = (*iter)->config.sdkVersion; -    if (temp_config == (*iter)->config) { -      // The two configs are the same, return the sdkVersion. -      return (*iter)->config.sdkVersion; -    } -  } - -  // Didn't find another config with a different sdk version, so return the highest possible value. -  return std::numeric_limits<ApiVersion>::max(); +  return FindNextApiVersionForConfigInSortedVector(iter, end_iter);  }  bool AutoVersioner::Consume(IAaptContext* context, ResourceTable* table) { diff --git a/tools/aapt2/link/AutoVersioner_test.cpp b/tools/aapt2/link/AutoVersioner_test.cpp index 49639f8ad549..88a831b9e801 100644 --- a/tools/aapt2/link/AutoVersioner_test.cpp +++ b/tools/aapt2/link/AutoVersioner_test.cpp @@ -42,8 +42,8 @@ TEST(AutoVersionerTest, GenerateVersionedResourceWhenHigherVersionExists) {    ResourceEntry entry("foo");    entry.values.push_back(util::make_unique<ResourceConfigValue>(ConfigDescription::DefaultConfig(), "")); -  entry.values.push_back(util::make_unique<ResourceConfigValue>(sw600dp_v13_config, ""));    entry.values.push_back(util::make_unique<ResourceConfigValue>(v21_config, "")); +  entry.values.push_back(util::make_unique<ResourceConfigValue>(sw600dp_v13_config, ""));    EXPECT_TRUE(ShouldGenerateVersionedResource(&entry, ConfigDescription::DefaultConfig(), 17));    EXPECT_FALSE(ShouldGenerateVersionedResource(&entry, ConfigDescription::DefaultConfig(), 22)); diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h index 5527f9092c87..493b6b1181b9 100644 --- a/tools/aapt2/link/Linkers.h +++ b/tools/aapt2/link/Linkers.h @@ -23,6 +23,7 @@  #include "android-base/macros.h"  #include "Resource.h" +#include "ResourceTable.h"  #include "SdkConstants.h"  #include "process/IResourceTableConsumer.h"  #include "xml/XmlDom.h" @@ -41,17 +42,19 @@ struct CallSite {    ResourceNameRef resource;  }; -/** - * Determines whether a versioned resource should be created. If a versioned - * resource already exists, it takes precedence. - */ +// Determines whether a versioned resource should be created. If a versioned resource already +// exists, it takes precedence.  bool ShouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDescription& config,                                       const ApiVersion sdk_version_to_generate); -// Finds the next largest ApiVersion of the config which is identical to the given config except -// for sdkVersion. +// Finds the next largest ApiVersion of `config` for values defined for `entry`.  ApiVersion FindNextApiVersionForConfig(const ResourceEntry* entry, const ConfigDescription& config); +// Finds the next largest ApiVersion of the config pointed to by the iterator `start`. +ApiVersion FindNextApiVersionForConfigInSortedVector( +    std::vector<std::unique_ptr<ResourceConfigValue>>::const_iterator start, +    std::vector<std::unique_ptr<ResourceConfigValue>>::const_iterator end); +  class AutoVersioner : public IResourceTableConsumer {   public:    AutoVersioner() = default; diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md index ebcd4698d8d5..8c476fac3b89 100644 --- a/tools/aapt2/readme.md +++ b/tools/aapt2/readme.md @@ -9,6 +9,7 @@    (bug 62839863)  - Fixed issue where Java classes referenced from fragments and menus were not added to    the set of Proguard keep rules. (bug 62216174) +- Automatically version XML `<adaptive-icon>` resources to v26. (bug 62316340)  ## Version 2.17  ### `aapt2 ...` diff --git a/tools/aapt2/util/TypeTraits.h b/tools/aapt2/util/TypeTraits.h index b6539edce6d9..6fcb4bdb4145 100644 --- a/tools/aapt2/util/TypeTraits.h +++ b/tools/aapt2/util/TypeTraits.h @@ -38,6 +38,7 @@ namespace aapt {  DEFINE_HAS_BINARY_OP_TRAIT(has_eq_op, ==);  DEFINE_HAS_BINARY_OP_TRAIT(has_lt_op, <); +DEFINE_HAS_BINARY_OP_TRAIT(has_lte_op, <=);  /**   * Type trait that checks if two types can be equated (==) and compared (<). diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h index 386f74b0301a..8bca9dd739bf 100644 --- a/tools/aapt2/util/Util.h +++ b/tools/aapt2/util/Util.h @@ -48,6 +48,11 @@ template <typename T>  struct Range {    T start;    T end; + +  typename std::enable_if<has_lte_op<const T, const T>::value, bool>::type Contains( +      const T& t) const { +    return start <= t && t < end; +  }  };  std::vector<std::string> Split(const android::StringPiece& str, char sep); diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp index fb8cee8b5634..fa1b0f049678 100644 --- a/tools/aapt2/xml/XmlUtil.cpp +++ b/tools/aapt2/xml/XmlUtil.cpp @@ -80,5 +80,65 @@ void TransformReferenceFromNamespace(IPackageDeclStack* decl_stack,    }  } +namespace { + +struct TagCompat { +  ApiVersion api_version; + +  enum class XmlType { +    kVector, +    kTransition, +    kAdaptiveIcon, +  }; + +  XmlType type; +}; + +std::unordered_map<StringPiece, TagCompat> sTagVersions = { +    {"fade", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"changeBounds", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"slide", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"explode", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"changeImageTransform", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"changeTransform", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"changeClipBounds", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"autoTransition", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"recolor", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"changeScroll", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"transitionSet", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"transition", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, +    {"transitionManager", {SDK_LOLLIPOP, TagCompat::XmlType::kTransition}}, + +    {"vector", {SDK_LOLLIPOP, TagCompat::XmlType::kVector}}, +    {"animated-vector", {SDK_LOLLIPOP, TagCompat::XmlType::kVector}}, +    {"pathInterpolator", {SDK_LOLLIPOP, TagCompat::XmlType::kVector}}, +    {"objectAnimator", {SDK_LOLLIPOP, TagCompat::XmlType::kVector}}, + +    {"adaptive-icon", {SDK_O, TagCompat::XmlType::kAdaptiveIcon}}, +}; + +}  // namespace + +Maybe<TagApiVersionResult> GetXmlTagApiVersion(const StringPiece& tag_name, int options) { +  auto iter = sTagVersions.find(tag_name); +  if (iter == sTagVersions.end()) { +    return {}; +  } + +  const TagCompat& tag_compat = iter->second; +  if (options & kNoVersionVector) { +    if (tag_compat.type == TagCompat::XmlType::kVector) { +      return TagApiVersionResult{{}, true /*skip_version*/}; +    } +  } + +  if (options & kNoVersionTransition) { +    if (tag_compat.type == TagCompat::XmlType::kTransition) { +      return TagApiVersionResult{{}, true /*skip_version*/}; +    } +  } +  return TagApiVersionResult{tag_compat.api_version, false /*skip_version*/}; +} +  }  // namespace xml  }  // namespace aapt diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h index 1650ac2124ac..552f42adc464 100644 --- a/tools/aapt2/xml/XmlUtil.h +++ b/tools/aapt2/xml/XmlUtil.h @@ -20,18 +20,16 @@  #include <string>  #include "ResourceValues.h" +#include "SdkConstants.h"  #include "util/Maybe.h"  namespace aapt {  namespace xml {  constexpr const char* kSchemaAuto = "http://schemas.android.com/apk/res-auto"; -constexpr const char* kSchemaPublicPrefix = -    "http://schemas.android.com/apk/res/"; -constexpr const char* kSchemaPrivatePrefix = -    "http://schemas.android.com/apk/prv/res/"; -constexpr const char* kSchemaAndroid = -    "http://schemas.android.com/apk/res/android"; +constexpr const char* kSchemaPublicPrefix = "http://schemas.android.com/apk/res/"; +constexpr const char* kSchemaPrivatePrefix = "http://schemas.android.com/apk/prv/res/"; +constexpr const char* kSchemaAndroid = "http://schemas.android.com/apk/res/android";  constexpr const char* kSchemaTools = "http://schemas.android.com/tools";  constexpr const char* kSchemaAapt = "http://schemas.android.com/aapt"; @@ -102,6 +100,24 @@ struct IPackageDeclStack {  void TransformReferenceFromNamespace(IPackageDeclStack* decl_stack,                                       const android::StringPiece& local_package, Reference* in_ref); +struct TagApiVersionResult { +  // If set, the API version to apply. +  Maybe<ApiVersion> api_version; + +  // Whether to skip any auto-versioning. +  bool skip_version; +}; + +enum TagVersionOptions : int { +  // Skip versioning XML resources that deal with vector drawables. +  kNoVersionVector, + +  // Skip versioning XML resources that deal with transitions. +  kNoVersionTransition, +}; + +Maybe<TagApiVersionResult> GetXmlTagApiVersion(const android::StringPiece& tag_name, int options); +  }  // namespace xml  }  // namespace aapt  |