diff options
Diffstat (limited to 'tools')
35 files changed, 1135 insertions, 399 deletions
diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp index f447462..848d9a1 100644 --- a/tools/aapt/AaptConfig.cpp +++ b/tools/aapt/AaptConfig.cpp @@ -794,4 +794,23 @@ bool isSameExcept(const ResTable_config& a, const ResTable_config& b, int axisMa return a.diff(b) == axisMask; } +bool isDensityOnly(const ResTable_config& config) { + if (config.density == ResTable_config::DENSITY_NONE) { + return false; + } + + if (config.density == ResTable_config::DENSITY_ANY) { + if (config.sdkVersion != SDK_L) { + // Someone modified the sdkVersion from the default, this is not safe to assume. + return false; + } + } else if (config.sdkVersion != SDK_DONUT) { + return false; + } + + const uint32_t mask = ResTable_config::CONFIG_DENSITY | ResTable_config::CONFIG_VERSION; + const ConfigDescription nullConfig; + return (nullConfig.diff(config) & ~mask) == 0; +} + } // namespace AaptConfig diff --git a/tools/aapt/AaptConfig.h b/tools/aapt/AaptConfig.h index 2963539..f73a508 100644 --- a/tools/aapt/AaptConfig.h +++ b/tools/aapt/AaptConfig.h @@ -80,6 +80,12 @@ android::String8 getVersion(const android::ResTable_config& config); */ bool isSameExcept(const android::ResTable_config& a, const android::ResTable_config& b, int configMask); +/** + * Returns true if the configuration only has the density specified. In the case + * of 'anydpi', the version is ignored. + */ +bool isDensityOnly(const android::ResTable_config& config); + } // namespace AaptConfig #endif // __AAPT_CONFIG_H diff --git a/tools/aapt/AaptUtil.h b/tools/aapt/AaptUtil.h index 47a704a..89e1ee8 100644 --- a/tools/aapt/AaptUtil.h +++ b/tools/aapt/AaptUtil.h @@ -14,9 +14,11 @@ * limitations under the License. */ -#ifndef __AAPT_UTIL_H -#define __AAPT_UTIL_H +#ifndef H_AAPT_UTIL +#define H_AAPT_UTIL +#include <utils/KeyedVector.h> +#include <utils/SortedVector.h> #include <utils/String8.h> #include <utils/Vector.h> @@ -25,6 +27,38 @@ namespace AaptUtil { android::Vector<android::String8> split(const android::String8& str, const char sep); android::Vector<android::String8> splitAndLowerCase(const android::String8& str, const char sep); +template <typename KEY, typename VALUE> +void appendValue(android::KeyedVector<KEY, android::Vector<VALUE> >& keyedVector, + const KEY& key, const VALUE& value); + +template <typename KEY, typename VALUE> +void appendValue(android::KeyedVector<KEY, android::SortedVector<VALUE> >& keyedVector, + const KEY& key, const VALUE& value); + +// +// Implementations +// + +template <typename KEY, typename VALUE> +void appendValue(android::KeyedVector<KEY, android::Vector<VALUE> >& keyedVector, + const KEY& key, const VALUE& value) { + ssize_t idx = keyedVector.indexOfKey(key); + if (idx < 0) { + idx = keyedVector.add(key, android::Vector<VALUE>()); + } + keyedVector.editValueAt(idx).add(value); +} + +template <typename KEY, typename VALUE> +void appendValue(android::KeyedVector<KEY, android::SortedVector<VALUE> >& keyedVector, + const KEY& key, const VALUE& value) { + ssize_t idx = keyedVector.indexOfKey(key); + if (idx < 0) { + idx = keyedVector.add(key, android::SortedVector<VALUE>()); + } + keyedVector.editValueAt(idx).add(value); +} + } // namespace AaptUtil -#endif // __AAPT_UTIL_H +#endif // H_AAPT_UTIL diff --git a/tools/aapt/AaptXml.cpp b/tools/aapt/AaptXml.cpp index 708e405..b04a55d 100644 --- a/tools/aapt/AaptXml.cpp +++ b/tools/aapt/AaptXml.cpp @@ -41,7 +41,7 @@ static String8 getStringAttributeAtIndex(const ResXMLTree& tree, ssize_t attrInd } size_t len; - const uint16_t* str = tree.getAttributeStringValue(attrIndex, &len); + const char16_t* str = tree.getAttributeStringValue(attrIndex, &len); return str ? String8(str, len) : String8(); } @@ -103,7 +103,7 @@ String8 getResolvedAttribute(const ResTable& resTable, const ResXMLTree& tree, if (tree.getAttributeValue(idx, &value) != NO_ERROR) { if (value.dataType == Res_value::TYPE_STRING) { size_t len; - const uint16_t* str = tree.getAttributeStringValue(idx, &len); + const char16_t* str = tree.getAttributeStringValue(idx, &len); return str ? String8(str, len) : String8(); } resTable.resolveReference(&value, 0); diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk index 2cbabe1..bc9c1f7 100644 --- a/tools/aapt/Android.mk +++ b/tools/aapt/Android.mk @@ -33,20 +33,20 @@ aaptSources := \ Command.cpp \ CrunchCache.cpp \ FileFinder.cpp \ + Images.cpp \ Package.cpp \ - StringPool.cpp \ - XMLNode.cpp \ + pseudolocalize.cpp \ + qsort_r_compat.c \ + Resource.cpp \ ResourceFilter.cpp \ ResourceIdCache.cpp \ ResourceTable.cpp \ - Images.cpp \ - Resource.cpp \ - pseudolocalize.cpp \ SourcePos.cpp \ + StringPool.cpp \ WorkQueue.cpp \ + XMLNode.cpp \ ZipEntry.cpp \ - ZipFile.cpp \ - qsort_r_compat.c + ZipFile.cpp aaptTests := \ tests/AaptConfig_test.cpp \ @@ -88,16 +88,13 @@ endif include $(CLEAR_VARS) LOCAL_MODULE := libaapt - -LOCAL_SRC_FILES := $(aaptSources) -LOCAL_C_INCLUDES += $(aaptCIncludes) - -LOCAL_CFLAGS += -Wno-format-y2k -LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS -LOCAL_CFLAGS += $(aaptCFlags) +LOCAL_CFLAGS += -Wno-format-y2k -DSTATIC_ANDROIDFW_FOR_TOOLS $(aaptCFlags) +LOCAL_CPPFLAGS += $(aaptCppFlags) ifeq (darwin,$(HOST_OS)) LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS endif +LOCAL_C_INCLUDES += $(aaptCIncludes) +LOCAL_SRC_FILES := $(aaptSources) include $(BUILD_HOST_STATIC_LIBRARY) @@ -108,15 +105,11 @@ include $(BUILD_HOST_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := aapt - -LOCAL_SRC_FILES := $(aaptMain) - -LOCAL_STATIC_LIBRARIES += \ - libaapt \ - $(aaptHostStaticLibs) - -LOCAL_LDLIBS += $(aaptHostLdLibs) LOCAL_CFLAGS += $(aaptCFlags) +LOCAL_CPPFLAGS += $(aaptCppFlags) +LOCAL_LDLIBS += $(aaptHostLdLibs) +LOCAL_SRC_FILES := $(aaptMain) +LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs) include $(BUILD_HOST_EXECUTABLE) @@ -127,16 +120,12 @@ include $(BUILD_HOST_EXECUTABLE) include $(CLEAR_VARS) LOCAL_MODULE := libaapt_tests - +LOCAL_CFLAGS += $(aaptCFlags) +LOCAL_CPPFLAGS += $(aaptCppFlags) +LOCAL_LDLIBS += $(aaptHostLdLibs) LOCAL_SRC_FILES += $(aaptTests) LOCAL_C_INCLUDES += $(LOCAL_PATH) - -LOCAL_STATIC_LIBRARIES += \ - libaapt \ - $(aaptHostStaticLibs) - -LOCAL_LDLIBS += $(aaptHostLdLibs) -LOCAL_CFLAGS += $(aaptCFlags) +LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs) include $(BUILD_HOST_NATIVE_TEST) @@ -148,13 +137,12 @@ ifneq ($(SDK_ONLY),true) include $(CLEAR_VARS) LOCAL_MODULE := aapt - +LOCAL_CFLAGS += $(aaptCFlags) LOCAL_SRC_FILES := $(aaptSources) $(aaptMain) LOCAL_C_INCLUDES += \ $(aaptCIncludes) \ bionic \ external/stlport/stlport - LOCAL_SHARED_LIBRARIES := \ libandroidfw \ libutils \ @@ -162,14 +150,10 @@ LOCAL_SHARED_LIBRARIES := \ libpng \ liblog \ libz - LOCAL_STATIC_LIBRARIES := \ libstlport_static \ libexpat_static -LOCAL_CFLAGS += $(aaptCFlags) -LOCAL_CPPFLAGS += -Wno-non-virtual-dtor - include $(BUILD_EXECUTABLE) endif # Not SDK_ONLY diff --git a/tools/aapt/CacheUpdater.h b/tools/aapt/CacheUpdater.h index efb2453..fade53a 100644 --- a/tools/aapt/CacheUpdater.h +++ b/tools/aapt/CacheUpdater.h @@ -30,6 +30,8 @@ using namespace android; */ class CacheUpdater { public: + virtual ~CacheUpdater() {} + // Make sure all the directories along this path exist virtual void ensureDirectoriesExist(String8 path) = 0; @@ -107,4 +109,4 @@ private: Bundle* bundle; }; -#endif // CACHE_UPDATER_H
\ No newline at end of file +#endif // CACHE_UPDATER_H diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp index 2857b59..18b8e1e 100644 --- a/tools/aapt/Main.cpp +++ b/tools/aapt/Main.cpp @@ -11,9 +11,9 @@ #include <utils/List.h> #include <utils/Errors.h> -#include <stdlib.h> +#include <cstdlib> #include <getopt.h> -#include <assert.h> +#include <cassert> using namespace android; diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index a4c9dab..0d8db13 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -4,6 +4,7 @@ // Build resource files from raw assets. // #include "AaptAssets.h" +#include "AaptUtil.h" #include "AaptXml.h" #include "CacheUpdater.h" #include "CrunchCache.h" @@ -13,9 +14,12 @@ #include "Main.h" #include "ResourceTable.h" #include "StringPool.h" +#include "Symbol.h" #include "WorkQueue.h" #include "XMLNode.h" +#include <algorithm> + #if HAVE_PRINTF_ZD # define ZD "%zd" # define ZD_TYPE ssize_t @@ -261,7 +265,7 @@ static status_t parsePackage(Bundle* bundle, const sp<AaptAssets>& assets, ssize_t minSdkIndex = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, "minSdkVersion"); if (minSdkIndex >= 0) { - const uint16_t* minSdk16 = block.getAttributeStringValue(minSdkIndex, &len); + const char16_t* minSdk16 = block.getAttributeStringValue(minSdkIndex, &len); const char* minSdk8 = strdup(String8(minSdk16).string()); bundle->setManifestMinSdkVersion(minSdk8); } @@ -450,7 +454,7 @@ static int validateAttr(const String8& path, const ResTable& table, size_t len; ssize_t index = parser.indexOfAttribute(ns, attr); - const uint16_t* str; + const char16_t* str; Res_value value; if (index >= 0 && parser.getAttributeValue(index, &value) >= 0) { const ResStringPool* pool = &parser.getStrings(); @@ -503,7 +507,7 @@ static int validateAttr(const String8& path, const ResTable& table, } if (validChars) { for (size_t i=0; i<len; i++) { - uint16_t c = str[i]; + char16_t c = str[i]; const char* p = validChars; bool okay = false; while (*p) { @@ -1550,6 +1554,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil // Re-flatten because we may have added new resource IDs // -------------------------------------------------------------- + ResTable finalResTable; sp<AaptFile> resFile; @@ -1560,6 +1565,13 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil return err; } + KeyedVector<Symbol, Vector<SymbolDefinition> > densityVaryingResources; + if (builder->getSplits().size() > 1) { + // Only look for density varying resources if we're generating + // splits. + table.getDensityVaryingResources(densityVaryingResources); + } + Vector<sp<ApkSplit> >& splits = builder->getSplits(); const size_t numSplits = splits.size(); for (size_t i = 0; i < numSplits; i++) { @@ -1583,6 +1595,63 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil return err; } } else { + ResTable resTable; + err = resTable.add(flattenedTable->getData(), flattenedTable->getSize()); + if (err != NO_ERROR) { + fprintf(stderr, "Generated resource table for split '%s' is corrupt.\n", + split->getPrintableName().string()); + return err; + } + + bool hasError = false; + const std::set<ConfigDescription>& splitConfigs = split->getConfigs(); + for (std::set<ConfigDescription>::const_iterator iter = splitConfigs.begin(); + iter != splitConfigs.end(); + ++iter) { + const ConfigDescription& config = *iter; + if (AaptConfig::isDensityOnly(config)) { + // Each density only split must contain all + // density only resources. + Res_value val; + resTable.setParameters(&config); + const size_t densityVaryingResourceCount = densityVaryingResources.size(); + for (size_t k = 0; k < densityVaryingResourceCount; k++) { + const Symbol& symbol = densityVaryingResources.keyAt(k); + ssize_t block = resTable.getResource(symbol.id, &val, true); + if (block < 0) { + // Maybe it's in the base? + finalResTable.setParameters(&config); + block = finalResTable.getResource(symbol.id, &val, true); + } + + if (block < 0) { + hasError = true; + SourcePos().error("%s has no definition for density split '%s'", + symbol.toString().string(), config.toString().string()); + + if (bundle->getVerbose()) { + const Vector<SymbolDefinition>& defs = densityVaryingResources[k]; + const size_t defCount = std::min(size_t(5), defs.size()); + for (size_t d = 0; d < defCount; d++) { + const SymbolDefinition& def = defs[d]; + def.source.error("%s has definition for %s", + symbol.toString().string(), def.config.toString().string()); + } + + if (defCount < defs.size()) { + SourcePos().error("and %d more ...", (int) (defs.size() - defCount)); + } + } + } + } + } + } + + if (hasError) { + return UNKNOWN_ERROR; + } + + // Generate the AndroidManifest for this split. sp<AaptFile> generatedManifest = new AaptFile(String8("AndroidManifest.xml"), AaptGroupEntry(), String8()); err = generateAndroidManifestForSplit(bundle, assets, split, @@ -1710,7 +1779,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil } size_t len; ssize_t index = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE, "name"); - const uint16_t* id = block.getAttributeStringValue(index, &len); + const char16_t* id = block.getAttributeStringValue(index, &len); if (id == NULL) { fprintf(stderr, "%s:%d: missing name attribute in element <%s>.\n", manifestPath.string(), block.getLineNumber(), @@ -1753,7 +1822,7 @@ status_t buildResources(Bundle* bundle, const sp<AaptAssets>& assets, sp<ApkBuil hasErrors = true; } syms->addStringSymbol(String8(e), idStr, srcPos); - const uint16_t* cmt = block.getComment(&len); + const char16_t* cmt = block.getComment(&len); if (cmt != NULL && *cmt != 0) { //printf("Comment of %s: %s\n", String8(e).string(), // String8(cmt).string()); diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 4587a4b..beff604 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -6,6 +6,7 @@ #include "ResourceTable.h" +#include "AaptUtil.h" #include "XMLNode.h" #include "ResourceFilter.h" #include "ResourceIdCache.h" @@ -399,7 +400,7 @@ static status_t compileAttribute(const sp<AaptFile>& in, ssize_t l10nIdx = block.indexOfAttribute(NULL, "localization"); if (l10nIdx >= 0) { - const uint16_t* str = block.getAttributeStringValue(l10nIdx, &len); + const char16_t* str = block.getAttributeStringValue(l10nIdx, &len); bool error; uint32_t l10n_required = parse_flags(str, len, l10nRequiredFlags, &error); if (error) { @@ -1325,7 +1326,7 @@ status_t compileResourceFile(Bundle* bundle, size_t n = block.getAttributeCount(); for (size_t i = 0; i < n; i++) { size_t length; - const uint16_t* attr = block.getAttributeName(i, &length); + const char16_t* attr = block.getAttributeName(i, &length); if (strcmp16(attr, name16.string()) == 0) { name.setTo(block.getAttributeStringValue(i, &length)); } else if (strcmp16(attr, translatable16.string()) == 0) { @@ -1441,14 +1442,14 @@ status_t compileResourceFile(Bundle* bundle, // translatable. for (size_t i = 0; i < n; i++) { size_t length; - const uint16_t* attr = block.getAttributeName(i, &length); + const char16_t* attr = block.getAttributeName(i, &length); if (strcmp16(attr, formatted16.string()) == 0) { - const uint16_t* value = block.getAttributeStringValue(i, &length); + const char16_t* value = block.getAttributeStringValue(i, &length); if (strcmp16(value, false16.string()) == 0) { curIsFormatted = false; } } else if (strcmp16(attr, translatable16.string()) == 0) { - const uint16_t* value = block.getAttributeStringValue(i, &length); + const char16_t* value = block.getAttributeStringValue(i, &length); if (strcmp16(value, false16.string()) == 0) { isTranslatable = false; } @@ -4486,3 +4487,34 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle, return NO_ERROR; } + +void ResourceTable::getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources) { + const ConfigDescription nullConfig; + + const size_t packageCount = mOrderedPackages.size(); + for (size_t p = 0; p < packageCount; p++) { + const Vector<sp<Type> >& types = mOrderedPackages[p]->getOrderedTypes(); + const size_t typeCount = types.size(); + for (size_t t = 0; t < typeCount; t++) { + const Vector<sp<ConfigList> >& configs = types[t]->getOrderedConfigs(); + const size_t configCount = configs.size(); + for (size_t c = 0; c < configCount; c++) { + const DefaultKeyedVector<ConfigDescription, sp<Entry> >& configEntries = configs[c]->getEntries(); + const size_t configEntryCount = configEntries.size(); + for (size_t ce = 0; ce < configEntryCount; ce++) { + const ConfigDescription& config = configEntries.keyAt(ce); + if (AaptConfig::isDensityOnly(config)) { + // This configuration only varies with regards to density. + const Symbol symbol(mOrderedPackages[p]->getName(), + types[t]->getName(), + configs[c]->getName(), + getResId(mOrderedPackages[p], types[t], configs[c]->getEntryIndex())); + + const sp<Entry>& entry = configEntries.valueAt(ce); + AaptUtil::appendValue(resources, symbol, SymbolDefinition(symbol, config, entry->getPos())); + } + } + } + } + } +} diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h index eac5dd3..db392c8 100644 --- a/tools/aapt/ResourceTable.h +++ b/tools/aapt/ResourceTable.h @@ -7,15 +7,16 @@ #ifndef RESOURCE_TABLE_H #define RESOURCE_TABLE_H -#include "ConfigDescription.h" -#include "StringPool.h" -#include "SourcePos.h" -#include "ResourceFilter.h" - #include <map> #include <queue> #include <set> +#include "ConfigDescription.h" +#include "ResourceFilter.h" +#include "SourcePos.h" +#include "StringPool.h" +#include "Symbol.h" + using namespace std; class XMLNode; @@ -543,6 +544,8 @@ public: DefaultKeyedVector<String16, uint32_t> mKeyStringsMapping; }; + void getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources); + private: void writePublicDefinitions(const String16& package, FILE* fp, bool pub); sp<Package> getPackage(const String16& package); diff --git a/tools/aapt/SourcePos.cpp b/tools/aapt/SourcePos.cpp index ae25047..3864320 100644 --- a/tools/aapt/SourcePos.cpp +++ b/tools/aapt/SourcePos.cpp @@ -141,6 +141,12 @@ SourcePos::printf(const char* fmt, ...) const } bool +SourcePos::operator<(const SourcePos& rhs) const +{ + return (file < rhs.file) || (line < rhs.line); +} + +bool SourcePos::hasErrors() { return g_errors.size() > 0; diff --git a/tools/aapt/SourcePos.h b/tools/aapt/SourcePos.h index 4ce817f..13cfb9d 100644 --- a/tools/aapt/SourcePos.h +++ b/tools/aapt/SourcePos.h @@ -21,6 +21,8 @@ public: void warning(const char* fmt, ...) const; void printf(const char* fmt, ...) const; + bool operator<(const SourcePos& rhs) const; + static bool hasErrors(); static void printErrors(FILE* to); }; diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp index 06769e4..2727b3d 100644 --- a/tools/aapt/StringPool.cpp +++ b/tools/aapt/StringPool.cpp @@ -21,7 +21,8 @@ #define NOISY(x) //x -void strcpy16_htod(uint16_t* dst, const uint16_t* src) +#if __cplusplus >= 201103L +void strcpy16_htod(char16_t* dst, const char16_t* src) { while (*src) { char16_t s = htods(*src); @@ -30,6 +31,17 @@ void strcpy16_htod(uint16_t* dst, const uint16_t* src) } *dst = 0; } +#endif + +void strcpy16_htod(uint16_t* dst, const char16_t* src) +{ + while (*src) { + uint16_t s = htods(static_cast<uint16_t>(*src)); + *dst++ = s; + src++; + } + *dst = 0; +} void printStringPool(const ResStringPool* pool) { @@ -416,7 +428,7 @@ status_t StringPool::writeStringBlock(const sp<AaptFile>& pool) return NO_MEMORY; } - const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(char16_t); + const size_t charSize = mUTF8 ? sizeof(uint8_t) : sizeof(uint16_t); size_t strPos = 0; for (i=0; i<STRINGS; i++) { diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h index 1b3abfd..a9c7bec 100644 --- a/tools/aapt/StringPool.h +++ b/tools/aapt/StringPool.h @@ -26,7 +26,10 @@ using namespace android; #define PRINT_STRING_METRICS 0 -void strcpy16_htod(uint16_t* dst, const uint16_t* src); +#if __cplusplus >= 201103L +void strcpy16_htod(char16_t* dst, const char16_t* src); +#endif +void strcpy16_htod(uint16_t* dst, const char16_t* src); void printStringPool(const ResStringPool* pool); diff --git a/tools/aapt/Symbol.h b/tools/aapt/Symbol.h new file mode 100644 index 0000000..e157541 --- /dev/null +++ b/tools/aapt/Symbol.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2014 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. + */ + +#ifndef AAPT_SYMBOL_H +#define AAPT_SYMBOL_H + +#include <utils/String8.h> +#include <utils/String16.h> + +#include "ConfigDescription.h" +#include "SourcePos.h" + +/** + * A resource symbol, not attached to any configuration or context. + */ +struct Symbol { + inline Symbol(); + inline Symbol(const android::String16& p, const android::String16& t, const android::String16& n, uint32_t i); + inline android::String8 toString() const; + inline bool operator<(const Symbol& rhs) const; + + android::String16 package; + android::String16 type; + android::String16 name; + uint32_t id; + +}; + +/** + * A specific defintion of a symbol, defined with a configuration and a definition site. + */ +struct SymbolDefinition { + inline SymbolDefinition(); + inline SymbolDefinition(const Symbol& s, const ConfigDescription& c, const SourcePos& src); + inline bool operator<(const SymbolDefinition& rhs) const; + + Symbol symbol; + ConfigDescription config; + SourcePos source; +}; + +// +// Implementations +// + +Symbol::Symbol() { +} + +Symbol::Symbol(const android::String16& p, const android::String16& t, const android::String16& n, uint32_t i) + : package(p) + , type(t) + , name(n) + , id(i) { +} + +android::String8 Symbol::toString() const { + return android::String8::format("%s:%s/%s (0x%08x)", + android::String8(package).string(), + android::String8(type).string(), + android::String8(name).string(), + (int) id); +} + +bool Symbol::operator<(const Symbol& rhs) const { + return (package < rhs.package) || (type < rhs.type) || (name < rhs.name) || (id < rhs.id); +} + +SymbolDefinition::SymbolDefinition() { +} + +SymbolDefinition::SymbolDefinition(const Symbol& s, const ConfigDescription& c, const SourcePos& src) + : symbol(s) + , config(c) + , source(src) { +} + +bool SymbolDefinition::operator<(const SymbolDefinition& rhs) const { + return (symbol < rhs.symbol) || (config < rhs.config) || (source < rhs.source); +} + +#endif // AAPT_SYMBOL_H + diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp index 51a4154..899fb63 100644 --- a/tools/aapt/XMLNode.cpp +++ b/tools/aapt/XMLNode.cpp @@ -234,9 +234,9 @@ status_t parseStyledString(Bundle* bundle, const String8 element8(element16); size_t nslen; - const uint16_t* ns = inXml->getElementNamespace(&nslen); + const char16_t* ns = inXml->getElementNamespace(&nslen); if (ns == NULL) { - ns = (const uint16_t*)"\0\0"; + ns = (const char16_t*)"\0\0"; nslen = 0; } const String8 nspace(String16(ns, nslen)); @@ -291,9 +291,9 @@ moveon: } else if (code == ResXMLTree::END_TAG) { size_t nslen; - const uint16_t* ns = inXml->getElementNamespace(&nslen); + const char16_t* ns = inXml->getElementNamespace(&nslen); if (ns == NULL) { - ns = (const uint16_t*)"\0\0"; + ns = (const char16_t*)"\0\0"; nslen = 0; } const String8 nspace(String16(ns, nslen)); @@ -422,7 +422,7 @@ static String8 make_prefix(int depth) } static String8 build_namespace(const Vector<namespace_entry>& namespaces, - const uint16_t* ns) + const char16_t* ns) { String8 str; if (ns != NULL) { @@ -453,9 +453,9 @@ void printXMLBlock(ResXMLTree* block) int i; if (code == ResXMLTree::START_TAG) { size_t len; - const uint16_t* ns16 = block->getElementNamespace(&len); + const char16_t* ns16 = block->getElementNamespace(&len); String8 elemNs = build_namespace(namespaces, ns16); - const uint16_t* com16 = block->getComment(&len); + const char16_t* com16 = block->getComment(&len); if (com16) { printf("%s <!-- %s -->\n", prefix.string(), String8(com16).string()); } @@ -503,7 +503,7 @@ void printXMLBlock(ResXMLTree* block) } else if (code == ResXMLTree::START_NAMESPACE) { namespace_entry ns; size_t len; - const uint16_t* prefix16 = block->getNamespacePrefix(&len); + const char16_t* prefix16 = block->getNamespacePrefix(&len); if (prefix16) { ns.prefix = String8(prefix16); } else { @@ -518,7 +518,7 @@ void printXMLBlock(ResXMLTree* block) depth--; const namespace_entry& ns = namespaces.top(); size_t len; - const uint16_t* prefix16 = block->getNamespacePrefix(&len); + const char16_t* prefix16 = block->getNamespacePrefix(&len); String8 pr; if (prefix16) { pr = String8(prefix16); diff --git a/tools/layoutlib/bridge/src/android/view/WindowCallback.java b/tools/layoutlib/bridge/src/android/view/WindowCallback.java new file mode 100644 index 0000000..78242a8 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/view/WindowCallback.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2014 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. + */ + +package android.view; + +import android.view.ActionMode.Callback; +import android.view.WindowManager.LayoutParams; +import android.view.accessibility.AccessibilityEvent; + +/** + * An empty implementation of {@link Window.Callback} that always returns null/false. + */ +public class WindowCallback implements Window.Callback { + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + return false; + } + + @Override + public boolean dispatchKeyShortcutEvent(KeyEvent event) { + return false; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + return false; + } + + @Override + public boolean dispatchTrackballEvent(MotionEvent event) { + return false; + } + + @Override + public boolean dispatchGenericMotionEvent(MotionEvent event) { + return false; + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + return false; + } + + @Override + public View onCreatePanelView(int featureId) { + return null; + } + + @Override + public boolean onCreatePanelMenu(int featureId, Menu menu) { + return false; + } + + @Override + public boolean onPreparePanel(int featureId, View view, Menu menu) { + return false; + } + + @Override + public boolean onMenuOpened(int featureId, Menu menu) { + return false; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + return false; + } + + @Override + public void onWindowAttributesChanged(LayoutParams attrs) { + + } + + @Override + public void onContentChanged() { + + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + + } + + @Override + public void onAttachedToWindow() { + + } + + @Override + public void onDetachedFromWindow() { + + } + + @Override + public void onPanelClosed(int featureId, Menu menu) { + + } + + @Override + public boolean onSearchRequested() { + return false; + } + + @Override + public ActionMode onWindowStartingActionMode(Callback callback) { + return null; + } + + @Override + public void onActionModeStarted(ActionMode mode) { + + } + + @Override + public void onActionModeFinished(ActionMode mode) { + + } +} diff --git a/tools/layoutlib/bridge/src/android/widget/Toolbar_Accessor.java b/tools/layoutlib/bridge/src/android/widget/Toolbar_Accessor.java new file mode 100644 index 0000000..fdd1779 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/widget/Toolbar_Accessor.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2014 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. + */ + +package android.widget; + +import android.content.Context; + +/** + * To access non public members of classes in {@link Toolbar} + */ +public class Toolbar_Accessor { + public static ActionMenuPresenter getActionMenuPresenter(Toolbar toolbar) { + return toolbar.getOuterActionMenuPresenter(); + } + + public static Context getPopupContext(Toolbar toolbar) { + return toolbar.getPopupContext(); + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 825731b..ec78712 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -19,6 +19,7 @@ package com.android.layoutlib.bridge; import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN; import static com.android.ide.common.rendering.api.Result.Status.SUCCESS; +import com.android.annotations.NonNull; import com.android.ide.common.rendering.api.Capability; import com.android.ide.common.rendering.api.DrawableParams; import com.android.ide.common.rendering.api.LayoutLog; @@ -459,7 +460,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { public static void setLog(LayoutLog log) { // check only the thread currently owning the lock can do this. - if (sLock.isHeldByCurrentThread() == false) { + if (!sLock.isHeldByCurrentThread()) { throw new IllegalStateException("scene must be acquired first. see #acquire(long)"); } @@ -489,7 +490,6 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { /** * Returns the name of a framework resource whose value is an int array. - * @param array */ public static String resolveResourceId(int[] array) { sIntArrayWrapper.set(array); @@ -502,6 +502,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { * @param name the name of the resource. * @return an {@link Integer} containing the resource id, or null if no resource were found. */ + @NonNull public static Integer getResourceId(ResourceType type, String name) { Map<String, Integer> map = sRevRMap.get(type); Integer value = null; @@ -509,11 +510,8 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { value = map.get(name); } - if (value == null) { - value = sDynamicIds.getId(type, name); - } + return value == null ? sDynamicIds.getId(type, name) : value; - return value; } /** diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index d804230..3d3afa4 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -52,7 +52,6 @@ import android.content.res.BridgeTypedArray; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.Resources.Theme; -import android.content.res.TypedArray; import android.database.DatabaseErrorHandler; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; @@ -127,7 +126,6 @@ public final class BridgeContext extends Context { * @param metrics the {@link DisplayMetrics}. * @param renderResources the configured resources (both framework and projects) for this * render. - * @param projectCallback * @param config the Configuration object for this render. * @param targetSdkVersion the targetSdkVersion of the application. */ @@ -331,7 +329,7 @@ public final class BridgeContext extends Context { boolean attachToRoot, boolean skipCallbackParser) { boolean isPlatformLayout = resource.isFramework(); - if (isPlatformLayout == false && skipCallbackParser == false) { + if (!isPlatformLayout && !skipCallbackParser) { // check if the project callback can provide us with a custom parser. ILayoutPullParser parser = getParser(resource); @@ -663,7 +661,7 @@ public final class BridgeContext extends Context { } String attrName = attribute.getFirst(); - boolean frameworkAttr = attribute.getSecond().booleanValue(); + boolean frameworkAttr = attribute.getSecond(); String value = null; if (set != null) { value = set.getAttributeValue( @@ -672,7 +670,7 @@ public final class BridgeContext extends Context { // if this is an app attribute, and the first get fails, try with the // new res-auto namespace as well - if (frameworkAttr == false && value == null) { + if (!frameworkAttr && value == null) { value = set.getAttributeValue(BridgeConstants.NS_APP_RES_AUTO, attrName); } } @@ -789,13 +787,13 @@ public final class BridgeContext extends Context { List<Pair<String, Boolean>> results = new ArrayList<Pair<String, Boolean>>(attrs.length); // for each attribute, get its name so that we can search it in the style - for (int i = 0 ; i < attrs.length ; i++) { - Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attrs[i]); + for (int attr : attrs) { + Pair<ResourceType, String> resolvedResource = Bridge.resolveResourceId(attr); boolean isFramework = false; if (resolvedResource != null) { isFramework = true; } else { - resolvedResource = mProjectCallback.resolveResourceId(attrs[i]); + resolvedResource = mProjectCallback.resolveResourceId(attr); } if (resolvedResource != null) { @@ -841,7 +839,7 @@ public final class BridgeContext extends Context { if (id == null) { // generate a new id - id = Integer.valueOf(++mDynamicIdGenerator); + id = ++mDynamicIdGenerator; // and add it to the maps. mDynamicIdToStyleMap.put(id, resValue); @@ -860,19 +858,24 @@ public final class BridgeContext extends Context { } public int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) { - Integer value = Bridge.getResourceId(resType, resName); - if (value != null) { - return value.intValue(); + if (getRenderResources().getFrameworkResource(resType, resName) != null) { + // Bridge.getResourceId creates a new resource id if an existing one isn't found. So, + // we check for the existence of the resource before calling it. + return Bridge.getResourceId(resType, resName); } return defValue; } public int getProjectResourceValue(ResourceType resType, String resName, int defValue) { - if (mProjectCallback != null) { - Integer value = mProjectCallback.getResourceId(resType, resName); - if (value != null) { - return value.intValue(); + // getResourceId creates a new resource id if an existing resource id isn't found. So, we + // check for the existence of the resource before calling it. + if (getRenderResources().getProjectResource(resType, resName) != null) { + if (mProjectCallback != null) { + Integer value = mProjectCallback.getResourceId(resType, resName); + if (value != null) { + return value; + } } } @@ -1455,9 +1458,6 @@ public final class BridgeContext extends Context { return null; } - /** - * @hide - */ @Override public int getUserId() { return 0; // not used diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java index 22265a3..05a6fd6 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java @@ -145,4 +145,9 @@ public class BridgePowerManager implements IPowerManager { public void wakeUp(long time) throws RemoteException { // pass for now. } + + @Override + public void boostScreenBrightness(long time) throws RemoteException { + // pass for now. + } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java index d95c815..57fd68e 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ActionBarLayout.java @@ -18,36 +18,24 @@ package com.android.layoutlib.bridge.bars; import com.android.annotations.NonNull; import com.android.annotations.Nullable; -import com.android.ide.common.rendering.api.ActionBarCallback; -import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle; -import com.android.ide.common.rendering.api.RenderResources; import com.android.ide.common.rendering.api.ResourceValue; import com.android.ide.common.rendering.api.SessionParams; import com.android.internal.R; -import com.android.internal.app.WindowDecorActionBar; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuItemImpl; -import com.android.internal.widget.ActionBarAccessor; -import com.android.internal.widget.ActionBarContainer; -import com.android.internal.widget.ActionBarView; import com.android.layoutlib.bridge.android.BridgeContext; import com.android.layoutlib.bridge.impl.ResourceHelper; -import com.android.resources.ResourceType; -import android.app.ActionBar; -import android.app.ActionBar.Tab; -import android.app.ActionBar.TabListener; -import android.app.FragmentTransaction; import android.content.Context; import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; import android.util.DisplayMetrics; import android.util.TypedValue; -import android.view.Gravity; import android.view.LayoutInflater; -import android.view.MenuInflater; import android.view.View; +import android.view.View.MeasureSpec; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.widget.ActionMenuPresenter; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.ListAdapter; @@ -56,172 +44,72 @@ import android.widget.RelativeLayout; import java.util.ArrayList; -/** - * A layout representing the action bar. - */ -public class ActionBarLayout extends LinearLayout { +public class ActionBarLayout { + + private static final String LAYOUT_ATTR_NAME = "windowActionBarFullscreenDecorLayout"; + + // The Action Bar + @NonNull private CustomActionBarWrapper mActionBar; // Store another reference to the context so that we don't have to cast it repeatedly. @NonNull private final BridgeContext mBridgeContext; - @NonNull private final Context mThemedContext; - - @NonNull private final ActionBar mActionBar; - - // Data for Action Bar. - @Nullable private final String mIcon; - @Nullable private final String mTitle; - @Nullable private final String mSubTitle; - private final boolean mSplit; - private final boolean mShowHomeAsUp; - private final int mNavMode; - - // Helper fields. - @NonNull private final MenuBuilder mMenuBuilder; - private final int mPopupMaxWidth; - @NonNull private final RenderResources res; - @Nullable private final ActionBarView mActionBarView; - @Nullable private FrameLayout mContentRoot; - @NonNull private final ActionBarCallback mCallback; + + @NonNull private FrameLayout mContentRoot; // A fake parent for measuring views. @Nullable private ViewGroup mMeasureParent; - public ActionBarLayout(@NonNull BridgeContext context, @NonNull SessionParams params) { - - super(context); - setOrientation(LinearLayout.HORIZONTAL); - setGravity(Gravity.CENTER_VERTICAL); - - // Inflate action bar layout. - LayoutInflater.from(context).inflate(R.layout.screen_action_bar, this, - true /*attachToRoot*/); - mActionBar = new WindowDecorActionBar(this); - - // Set contexts. - mBridgeContext = context; - mThemedContext = mActionBar.getThemedContext(); - - // Set data for action bar. - mCallback = params.getProjectCallback().getActionBarCallback(); - mIcon = params.getAppIcon(); - mTitle = params.getAppLabel(); - // Split Action Bar when the screen size is narrow and the application requests split action - // bar when narrow. - mSplit = context.getResources().getBoolean(R.bool.split_action_bar_is_narrow) && - mCallback.getSplitActionBarWhenNarrow(); - mNavMode = mCallback.getNavigationMode(); - // TODO: Support Navigation Drawer Indicator. - mShowHomeAsUp = mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP; - mSubTitle = mCallback.getSubTitle(); - - - // Set helper fields. - mMenuBuilder = new MenuBuilder(mThemedContext); - res = mBridgeContext.getRenderResources(); - mPopupMaxWidth = Math.max(mBridgeContext.getMetrics().widthPixels / 2, - mThemedContext.getResources().getDimensionPixelSize( - R.dimen.config_prefDialogWidth)); - mActionBarView = (ActionBarView) findViewById(R.id.action_bar); - mContentRoot = (FrameLayout) findViewById(android.R.id.content); - - setupActionBar(); - } - /** - * Sets up the action bar by filling the appropriate data. + * Inflate the action bar and attach it to {@code parentView} */ - private void setupActionBar() { - // Add title and sub title. - ResourceValue titleValue = res.findResValue(mTitle, false /*isFramework*/); - if (titleValue != null && titleValue.getValue() != null) { - mActionBar.setTitle(titleValue.getValue()); - } else { - mActionBar.setTitle(mTitle); - } - if (mSubTitle != null) { - mActionBar.setSubtitle(mSubTitle); - } + public ActionBarLayout(@NonNull BridgeContext context, @NonNull SessionParams params, + @NonNull ViewGroup parentView) { - // Add show home as up icon. - if (mShowHomeAsUp) { - mActionBar.setDisplayOptions(0xFF, ActionBar.DISPLAY_HOME_AS_UP); - } + mBridgeContext = context; - // Set the navigation mode. - mActionBar.setNavigationMode(mNavMode); - if (mNavMode == ActionBar.NAVIGATION_MODE_TABS) { - setupTabs(3); + ResourceValue layoutName = context.getRenderResources() + .findItemInTheme(LAYOUT_ATTR_NAME, true); + if (layoutName != null) { + // We may need to resolve the reference obtained. + layoutName = context.getRenderResources().findResValue(layoutName.getValue(), + layoutName.isFramework()); } - - if (mActionBarView != null) { - // If the action bar style doesn't specify an icon, set the icon obtained from the session - // params. - if (!mActionBarView.hasIcon() && mIcon != null) { - Drawable iconDrawable = getDrawable(mIcon, false /*isFramework*/); - if (iconDrawable != null) { - mActionBar.setIcon(iconDrawable); - } + int layoutId = 0; + String error = null; + if (layoutName == null) { + error = "Unable to find action bar layout (" + LAYOUT_ATTR_NAME + + ") in the current theme."; + } else { + layoutId = context.getFrameworkResourceValue(layoutName.getResourceType(), + layoutName.getName(), 0); + if (layoutId == 0) { + error = String.format("Unable to resolve attribute \"%s\" of type \"%s\"", + layoutName.getName(), layoutName.getResourceType()); } - - // Set action bar to be split, if needed. - ActionBarContainer splitView = (ActionBarContainer) findViewById(R.id.split_action_bar); - mActionBarView.setSplitView(splitView); - mActionBarView.setSplitToolbar(mSplit); - - inflateMenus(); } - } - - /** - * Gets the menus to add to the action bar from the callback, resolves them, inflates them and - * adds them to the action bar. - */ - private void inflateMenus() { - if (mActionBarView == null) { - return; - } - final MenuInflater inflater = new MenuInflater(mThemedContext); - for (String name : mCallback.getMenuIdNames()) { - if (mBridgeContext.getRenderResources().getProjectResource(ResourceType.MENU, name) - != null) { - int id = mBridgeContext.getProjectResourceValue(ResourceType.MENU, name, -1); - if (id > -1) { - inflater.inflate(id, mMenuBuilder); - } - } + if (layoutId == 0) { + throw new RuntimeException(error); } - mActionBarView.setMenu(mMenuBuilder, null /*callback*/); - } + // Inflate action bar layout. + View decorContent = LayoutInflater.from(context).inflate(layoutId, parentView, true); - // TODO: Use an adapter, like List View to set up tabs. - private void setupTabs(int num) { - for (int i = 1; i <= num; i++) { - Tab tab = mActionBar.newTab().setText("Tab" + i).setTabListener(new TabListener() { - @Override - public void onTabUnselected(Tab t, FragmentTransaction ft) { - // pass - } - @Override - public void onTabSelected(Tab t, FragmentTransaction ft) { - // pass - } - @Override - public void onTabReselected(Tab t, FragmentTransaction ft) { - // pass - } - }); - mActionBar.addTab(tab); - } - } + mActionBar = CustomActionBarWrapper.getActionBarWrapper(context, params, decorContent); - @Nullable - private Drawable getDrawable(@NonNull String name, boolean isFramework) { - ResourceValue value = res.findResValue(name, isFramework); - value = res.resolveResValue(value); - if (value != null) { - return ResourceHelper.getDrawable(value, mBridgeContext); + FrameLayout contentRoot = (FrameLayout) parentView.findViewById(android.R.id.content); + + // If something went wrong and we were not able to initialize the content root, + // just add a frame layout inside this and return. + if (contentRoot == null) { + contentRoot = new FrameLayout(context); + contentRoot.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, + LayoutParams.MATCH_PARENT)); + parentView.addView(contentRoot); + mContentRoot = contentRoot; + } else { + mContentRoot = contentRoot; + mActionBar.setupActionBar(); + mActionBar.inflateMenus(); } - return null; } /** @@ -229,7 +117,7 @@ public class ActionBarLayout extends LinearLayout { * the content frame which shall serve as the new content root. */ public void createMenuPopup() { - assert mContentRoot != null && findViewById(android.R.id.content) == mContentRoot + assert mContentRoot.getId() == android.R.id.content : "Action Bar Menus have already been created."; if (!isOverflowPopupNeeded()) { @@ -237,7 +125,7 @@ public class ActionBarLayout extends LinearLayout { } // Create a layout to hold the menus and the user's content. - RelativeLayout layout = new RelativeLayout(mThemedContext); + RelativeLayout layout = new RelativeLayout(mActionBar.getPopupContext()); layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); mContentRoot.addView(layout); @@ -259,13 +147,14 @@ public class ActionBarLayout extends LinearLayout { @NonNull private View createMenuView() { DisplayMetrics metrics = mBridgeContext.getMetrics(); - OverflowMenuAdapter adapter = new OverflowMenuAdapter(mMenuBuilder, mThemedContext); + MenuBuilder menu = mActionBar.getMenuBuilder(); + OverflowMenuAdapter adapter = new OverflowMenuAdapter(menu, mActionBar.getPopupContext()); - LinearLayout layout = new LinearLayout(mThemedContext); + LinearLayout layout = new LinearLayout(mActionBar.getPopupContext()); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( measureContentWidth(adapter), LayoutParams.WRAP_CONTENT); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_END); - if (mSplit) { + if (mActionBar.isSplit()) { layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); // TODO: Find correct value instead of hardcoded 10dp. layoutParams.bottomMargin = getPixelValue("-10dp", metrics); @@ -273,7 +162,7 @@ public class ActionBarLayout extends LinearLayout { layoutParams.topMargin = getPixelValue("-10dp", metrics); } layout.setLayoutParams(layoutParams); - final TypedArray a = mThemedContext.obtainStyledAttributes(null, + final TypedArray a = mActionBar.getPopupContext().obtainStyledAttributes(null, R.styleable.PopupWindow, R.attr.popupMenuStyle, 0); layout.setBackground(a.getDrawable(R.styleable.PopupWindow_popupBackground)); layout.setDividerDrawable(a.getDrawable(R.attr.actionBarDivider)); @@ -282,20 +171,25 @@ public class ActionBarLayout extends LinearLayout { layout.setDividerPadding(getPixelValue("12dp", metrics)); layout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); - ListView listView = new ListView(mThemedContext, null, R.attr.dropDownListViewStyle); + ListView listView = new ListView(mActionBar.getPopupContext(), null, + R.attr.dropDownListViewStyle); listView.setAdapter(adapter); layout.addView(listView); return layout; } private boolean isOverflowPopupNeeded() { - boolean needed = mCallback.isOverflowPopupNeeded(); + boolean needed = mActionBar.isOverflowPopupNeeded(); if (!needed) { return false; } // Copied from android.widget.ActionMenuPresenter.updateMenuView() - ArrayList<MenuItemImpl> menus = mMenuBuilder.getNonActionItems(); - if (ActionBarAccessor.getActionMenuPresenter(mActionBarView).isOverflowReserved() && + ArrayList<MenuItemImpl> menus = mActionBar.getMenuBuilder().getNonActionItems(); + ActionMenuPresenter presenter = mActionBar.getActionMenuPresenter(); + if (presenter == null) { + throw new RuntimeException("Failed to create a Presenter for Action Bar Menus."); + } + if (presenter.isOverflowReserved() && menus != null) { final int count = menus.size(); if (count == 1) { @@ -307,7 +201,7 @@ public class ActionBarLayout extends LinearLayout { return needed; } - @Nullable + @NonNull public FrameLayout getContentRoot() { return mContentRoot; } @@ -319,6 +213,7 @@ public class ActionBarLayout extends LinearLayout { View itemView = null; int itemType = 0; + Context context = mActionBar.getPopupContext(); final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); final int count = adapter.getCount(); @@ -330,15 +225,17 @@ public class ActionBarLayout extends LinearLayout { } if (mMeasureParent == null) { - mMeasureParent = new FrameLayout(mThemedContext); + mMeasureParent = new FrameLayout(context); } itemView = adapter.getView(i, itemView, mMeasureParent); itemView.measure(widthMeasureSpec, heightMeasureSpec); final int itemWidth = itemView.getMeasuredWidth(); - if (itemWidth >= mPopupMaxWidth) { - return mPopupMaxWidth; + int popupMaxWidth = Math.max(mBridgeContext.getMetrics().widthPixels / 2, + context.getResources().getDimensionPixelSize(R.dimen.config_prefDialogWidth)); + if (itemWidth >= popupMaxWidth) { + return popupMaxWidth; } else if (itemWidth > maxWidth) { maxWidth = itemWidth; } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java new file mode 100644 index 0000000..70b9cc3 --- /dev/null +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomActionBarWrapper.java @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2014 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. + */ + +package com.android.layoutlib.bridge.bars; + +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; +import com.android.ide.common.rendering.api.ActionBarCallback; +import com.android.ide.common.rendering.api.ActionBarCallback.HomeButtonStyle; +import com.android.ide.common.rendering.api.RenderResources; +import com.android.ide.common.rendering.api.ResourceValue; +import com.android.ide.common.rendering.api.SessionParams; +import com.android.internal.R; +import com.android.internal.app.ToolbarActionBar; +import com.android.internal.app.WindowDecorActionBar; +import com.android.internal.view.menu.MenuBuilder; +import com.android.internal.widget.ActionBarAccessor; +import com.android.internal.widget.ActionBarView; +import com.android.internal.widget.DecorToolbar; +import com.android.layoutlib.bridge.android.BridgeContext; +import com.android.layoutlib.bridge.impl.ResourceHelper; + +import android.app.ActionBar; +import android.app.ActionBar.Tab; +import android.app.ActionBar.TabListener; +import android.app.FragmentTransaction; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowCallback; +import android.widget.ActionMenuPresenter; +import android.widget.Toolbar; +import android.widget.Toolbar_Accessor; + +import static com.android.SdkConstants.ANDROID_NS_NAME_PREFIX; +import static com.android.resources.ResourceType.MENU; + +/** + * A common API to access {@link ToolbarActionBar} and {@link WindowDecorActionBar}. + */ +public abstract class CustomActionBarWrapper { + + @NonNull protected ActionBar mActionBar; + @NonNull protected SessionParams mParams; + @NonNull protected ActionBarCallback mCallback; + @NonNull protected BridgeContext mContext; + + /** + * Returns a wrapper around different implementations of the Action Bar to provide a common API. + * + * @param decorContent the top level view returned by inflating + * ?attr/windowActionBarFullscreenDecorLayout + */ + @NonNull + public static CustomActionBarWrapper getActionBarWrapper(@NonNull BridgeContext context, + @NonNull SessionParams params, @NonNull View decorContent) { + View view = decorContent.findViewById(R.id.action_bar); + if (view instanceof Toolbar) { + return new ToolbarWrapper(context, params, ((Toolbar) view) + ); + } else if (view instanceof ActionBarView) { + return new WindowActionBarWrapper(context, params, decorContent, ((ActionBarView) view) + ); + } else { + throw new IllegalStateException("Can't make an action bar out of " + + view.getClass().getSimpleName()); + } + } + + CustomActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params, + @NonNull ActionBar actionBar) { + mActionBar = actionBar; + mParams = params; + mCallback = params.getProjectCallback().getActionBarCallback(); + mContext = context; + } + + protected void setupActionBar() { + // Do the things that are common to all implementations. + RenderResources res = mContext.getRenderResources(); + + String title = mParams.getAppLabel(); + ResourceValue titleValue = res.findResValue(title, false); + if (titleValue != null && titleValue.getValue() != null) { + mActionBar.setTitle(titleValue.getValue()); + } else { + mActionBar.setTitle(title); + } + + String subTitle = mCallback.getSubTitle(); + if (subTitle != null) { + mActionBar.setSubtitle(subTitle); + } + + // Add show home as up icon. + if (mCallback.getHomeButtonStyle() == HomeButtonStyle.SHOW_HOME_AS_UP) { + mActionBar.setDisplayOptions(0xFF, ActionBar.DISPLAY_HOME_AS_UP); + } + } + + protected boolean isSplit() { + return getDecorToolbar().isSplit(); + } + + protected boolean isOverflowPopupNeeded() { + return mCallback.isOverflowPopupNeeded(); + } + + /** + * Gets the menus to add to the action bar from the callback, resolves them, inflates them and + * adds them to the action bar. + */ + protected void inflateMenus() { + MenuInflater inflater = new MenuInflater(getActionMenuContext()); + MenuBuilder menuBuilder = getMenuBuilder(); + for (String name : mCallback.getMenuIdNames()) { + int id; + if (name.startsWith(ANDROID_NS_NAME_PREFIX)) { + // Framework menu. + name = name.substring(ANDROID_NS_NAME_PREFIX.length()); + id = mContext.getFrameworkResourceValue(MENU, name, -1); + } else { + // Project menu. + id = mContext.getProjectResourceValue(MENU, name, -1); + } + if (id > -1) { + inflater.inflate(id, menuBuilder); + } + } + } + + /** + * The context used for the ActionBar and the menus in the ActionBarView. + */ + @NonNull + protected Context getActionMenuContext() { + return mActionBar.getThemedContext(); + } + + /** + * The context used to inflate the popup menu. + */ + @NonNull + abstract Context getPopupContext(); + + /** + * The Menu in which to inflate the user's menus. + */ + @NonNull + abstract MenuBuilder getMenuBuilder(); + + @Nullable + abstract ActionMenuPresenter getActionMenuPresenter(); + + /** + * Framework's wrapper over two ActionBar implementations. + */ + @NonNull + abstract DecorToolbar getDecorToolbar(); + + // ---- The implementations ---- + + /** + * Material theme uses {@link Toolbar} as the action bar. This wrapper provides access to + * Toolbar using a common API. + */ + private static class ToolbarWrapper extends CustomActionBarWrapper { + + @NonNull + private final Toolbar mToolbar; // This is the view. + + ToolbarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params, + @NonNull Toolbar toolbar) { + super(context, params, new ToolbarActionBar(toolbar, "", new WindowCallback()) + ); + mToolbar = toolbar; + } + + @Override + protected void inflateMenus() { + super.inflateMenus(); + // Inflating the menus doesn't initialize the ActionMenuPresenter. Setting a fake menu + // and then setting it back does the trick. + MenuBuilder menu = getMenuBuilder(); + DecorToolbar decorToolbar = getDecorToolbar(); + decorToolbar.setMenu(new MenuBuilder(getActionMenuContext()), null); + decorToolbar.setMenu(menu, null); + } + + @NonNull + @Override + Context getPopupContext() { + return Toolbar_Accessor.getPopupContext(mToolbar); + } + + @NonNull + @Override + MenuBuilder getMenuBuilder() { + return (MenuBuilder) mToolbar.getMenu(); + } + + @Nullable + @Override + ActionMenuPresenter getActionMenuPresenter() { + return Toolbar_Accessor.getActionMenuPresenter(mToolbar); + } + + @NonNull + @Override + DecorToolbar getDecorToolbar() { + return mToolbar.getWrapper(); + } + } + + /** + * Holo theme uses {@link WindowDecorActionBar} as the action bar. This wrapper provides + * access to it using a common API. + */ + private static class WindowActionBarWrapper extends CustomActionBarWrapper{ + + @NonNull + private final WindowDecorActionBar mActionBar; + private final ActionBarView mActionBarView; + private MenuBuilder mMenuBuilder; + + public WindowActionBarWrapper(@NonNull BridgeContext context, @NonNull SessionParams params, + @NonNull View decorContentRoot, @NonNull ActionBarView actionBarView) { + super(context, params, new WindowDecorActionBar(decorContentRoot) + ); + mActionBarView = actionBarView; + mActionBar = ((WindowDecorActionBar) super.mActionBar); + } + + @Override + protected void setupActionBar() { + super.setupActionBar(); + + // Set the navigation mode. + int navMode = mCallback.getNavigationMode(); + mActionBar.setNavigationMode(navMode); + //noinspection deprecation + if (navMode == ActionBar.NAVIGATION_MODE_TABS) { + setupTabs(3); + } + + String icon = mParams.getAppIcon(); + // If the action bar style doesn't specify an icon, set the icon obtained from the + // session params. + if (!mActionBar.hasIcon() && icon != null) { + Drawable iconDrawable = getDrawable(icon, false); + if (iconDrawable != null) { + mActionBar.setIcon(iconDrawable); + } + } + + // Set action bar to be split, if needed. + ViewGroup splitView = (ViewGroup) mActionBarView.findViewById(R.id.split_action_bar); + if (splitView != null) { + mActionBarView.setSplitView(splitView); + Resources res = mContext.getResources(); + boolean split = res.getBoolean(R.bool.split_action_bar_is_narrow) + && mCallback.getSplitActionBarWhenNarrow(); + mActionBarView.setSplitToolbar(split); + } + } + + @Override + protected void inflateMenus() { + super.inflateMenus(); + // The super implementation doesn't set the menu on the view. Set it here. + mActionBarView.setMenu(getMenuBuilder(), null); + } + + @NonNull + @Override + Context getPopupContext() { + return getActionMenuContext(); + } + + @NonNull + @Override + MenuBuilder getMenuBuilder() { + if (mMenuBuilder == null) { + mMenuBuilder = new MenuBuilder(getActionMenuContext()); + } + return mMenuBuilder; + } + + @Nullable + @Override + ActionMenuPresenter getActionMenuPresenter() { + return ActionBarAccessor.getActionMenuPresenter(mActionBarView); + } + + @NonNull + @Override + ActionBarView getDecorToolbar() { + return mActionBarView; + } + + // TODO: Use an adapter, like List View to set up tabs. + @SuppressWarnings("deprecation") // For Tab + private void setupTabs(int num) { + for (int i = 1; i <= num; i++) { + Tab tab = mActionBar.newTab().setText("Tab" + i).setTabListener(new TabListener() { + @Override + public void onTabUnselected(Tab t, FragmentTransaction ft) { + // pass + } + @Override + public void onTabSelected(Tab t, FragmentTransaction ft) { + // pass + } + @Override + public void onTabReselected(Tab t, FragmentTransaction ft) { + // pass + } + }); + mActionBar.addTab(tab); + } + } + + @Nullable + private Drawable getDrawable(@NonNull String name, boolean isFramework) { + RenderResources res = mContext.getRenderResources(); + ResourceValue value = res.findResValue(name, isFramework); + value = res.resolveResValue(value); + if (value != null) { + return ResourceHelper.getDrawable(value, mContext); + } + return null; + } + + } +} diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index b8dce70..a2eed9a 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -353,8 +353,7 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { // if the theme says no title/action bar, then the size will be 0 if (mActionBarSize > 0) { - ActionBarLayout actionBar = createActionBar(context, params); - backgroundLayout.addView(actionBar); + ActionBarLayout actionBar = createActionBar(context, params, backgroundLayout); actionBar.createMenuPopup(); mContentRoot = actionBar.getContentRoot(); } else if (mTitleBarSize > 0) { @@ -1624,11 +1623,9 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { /** * Creates the action bar. Also queries the project callback for missing information. */ - private ActionBarLayout createActionBar(BridgeContext context, SessionParams params) { - ActionBarLayout actionBar = new ActionBarLayout(context, params); - actionBar.setLayoutParams(new LinearLayout.LayoutParams( - LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - return actionBar; + private ActionBarLayout createActionBar(BridgeContext context, SessionParams params, + ViewGroup parentView) { + return new ActionBarLayout(context, params, parentView); } public BufferedImage getImage() { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java index a1fae95..979aa33 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/DynamicIdMap.java @@ -16,6 +16,7 @@ package com.android.layoutlib.bridge.util; +import com.android.annotations.NonNull; import com.android.resources.ResourceType; import com.android.util.Pair; @@ -48,6 +49,7 @@ public class DynamicIdMap { * @param name the name of the resource * @return an integer. */ + @NonNull public Integer getId(ResourceType type, String name) { return getId(Pair.of(type, name)); } @@ -59,10 +61,11 @@ public class DynamicIdMap { * @param resource the type/name of the resource * @return an integer. */ + @NonNull public Integer getId(Pair<ResourceType, String> resource) { Integer value = mDynamicIds.get(resource); if (value == null) { - value = Integer.valueOf(++mDynamicSeed); + value = ++mDynamicSeed; mDynamicIds.put(resource, value); mRevDynamicIds.put(value, resource); } diff --git a/tools/split-select/Abi.cpp b/tools/split-select/Abi.cpp index 20654b6..180dd8f 100644 --- a/tools/split-select/Abi.cpp +++ b/tools/split-select/Abi.cpp @@ -16,42 +16,58 @@ #include "Abi.h" +using namespace android; + namespace split { namespace abi { -static const std::vector<Variant> sNoneVariants = {}; -static const std::vector<Variant> sArmVariants = - {Variant::armeabi, Variant::armeabi_v7a, Variant::arm64_v8a}; -static const std::vector<Variant> sIntelVariants = {Variant::x86, Variant::x86_64}; -static const std::vector<Variant> sMipsVariants = {Variant::mips, Variant::mips64}; +static Vector<Variant> buildVariants(Variant v1, Variant v2) { + Vector<Variant> v; + v.add(v1); + v.add(v2); + return v; +} + +static Vector<Variant> buildVariants(Variant v1, Variant v2, Variant v3) { + Vector<Variant> v; + v.add(v1); + v.add(v2); + v.add(v3); + return v; +} + +static const Vector<Variant> sNoneVariants; +static const Vector<Variant> sArmVariants = buildVariants(Variant_armeabi, Variant_armeabi_v7a, Variant_arm64_v8a); +static const Vector<Variant> sIntelVariants = buildVariants(Variant_x86, Variant_x86_64); +static const Vector<Variant> sMipsVariants = buildVariants(Variant_mips, Variant_mips64); Family getFamily(Variant variant) { switch (variant) { - case Variant::none: - return Family::none; - case Variant::armeabi: - case Variant::armeabi_v7a: - case Variant::arm64_v8a: - return Family::arm; - case Variant::x86: - case Variant::x86_64: - return Family::intel; - case Variant::mips: - case Variant::mips64: - return Family::mips; + case Variant_none: + return Family_none; + case Variant_armeabi: + case Variant_armeabi_v7a: + case Variant_arm64_v8a: + return Family_arm; + case Variant_x86: + case Variant_x86_64: + return Family_intel; + case Variant_mips: + case Variant_mips64: + return Family_mips; } - return Family::none; + return Family_none; } -const std::vector<Variant>& getVariants(Family family) { +const Vector<Variant>& getVariants(Family family) { switch (family) { - case Family::none: + case Family_none: return sNoneVariants; - case Family::arm: + case Family_arm: return sArmVariants; - case Family::intel: + case Family_intel: return sIntelVariants; - case Family::mips: + case Family_mips: return sMipsVariants; } return sNoneVariants; @@ -59,21 +75,21 @@ const std::vector<Variant>& getVariants(Family family) { const char* toString(Variant variant) { switch (variant) { - case Variant::none: + case Variant_none: return ""; - case Variant::armeabi: + case Variant_armeabi: return "armeabi"; - case Variant::armeabi_v7a: + case Variant_armeabi_v7a: return "armeabi-v7a"; - case Variant::arm64_v8a: + case Variant_arm64_v8a: return "arm64-v8a"; - case Variant::x86: + case Variant_x86: return "x86"; - case Variant::x86_64: + case Variant_x86_64: return "x86_64"; - case Variant::mips: + case Variant_mips: return "mips"; - case Variant::mips64: + case Variant_mips64: return "mips64"; } return ""; diff --git a/tools/split-select/Abi.h b/tools/split-select/Abi.h index 3e00eba..85b4d62 100644 --- a/tools/split-select/Abi.h +++ b/tools/split-select/Abi.h @@ -17,31 +17,31 @@ #ifndef H_ANDROID_SPLIT_ABI #define H_ANDROID_SPLIT_ABI -#include <vector> +#include <utils/Vector.h> namespace split { namespace abi { -enum class Variant { - none = 0, - armeabi, - armeabi_v7a, - arm64_v8a, - x86, - x86_64, - mips, - mips64, +enum Variant { + Variant_none = 0, + Variant_armeabi, + Variant_armeabi_v7a, + Variant_arm64_v8a, + Variant_x86, + Variant_x86_64, + Variant_mips, + Variant_mips64, }; -enum class Family { - none, - arm, - intel, - mips, +enum Family { + Family_none, + Family_arm, + Family_intel, + Family_mips, }; Family getFamily(Variant variant); -const std::vector<Variant>& getVariants(Family family); +const android::Vector<Variant>& getVariants(Family family); const char* toString(Variant variant); } // namespace abi diff --git a/tools/split-select/Android.mk b/tools/split-select/Android.mk index d0b7287..dc48ea8 100644 --- a/tools/split-select/Android.mk +++ b/tools/split-select/Android.mk @@ -17,10 +17,6 @@ # This tool is prebuilt if we're doing an app-only build. ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),) -# TODO(adamlesinski): Enable OS X builds when I figure out how -# to build with clang and libc++ -ifneq ($(HOST_OS),darwin) - # ========================================================== # Setup some common variables for the different build # targets here. @@ -55,7 +51,7 @@ hostStaticLibs := \ libexpat \ libziparchive-host -cFlags := -std=c++11 -Wall -Werror +cFlags := -Wall -Werror ifeq ($(HOST_OS),linux) hostLdLibs += -lrt -ldl -lpthread @@ -115,5 +111,4 @@ LOCAL_CFLAGS += $(cFlags) include $(BUILD_HOST_EXECUTABLE) -endif # Not OS X endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK diff --git a/tools/split-select/Grouper.cpp b/tools/split-select/Grouper.cpp index 15edf89..22685cd 100644 --- a/tools/split-select/Grouper.cpp +++ b/tools/split-select/Grouper.cpp @@ -16,25 +16,17 @@ #include "Grouper.h" +#include "aapt/AaptUtil.h" #include "SplitDescription.h" #include <utils/KeyedVector.h> #include <utils/Vector.h> using namespace android; +using AaptUtil::appendValue; namespace split { -template <typename Key, typename Value> -static void addToVector(KeyedVector<Key, SortedVector<Value> >& group, - const Key& key, const Value& value) { - ssize_t idx = group.indexOfKey(key); - if (idx < 0) { - idx = group.add(key, SortedVector<Value>()); - } - group.editValueAt(idx).add(value); -} - Vector<SortedVector<SplitDescription> > groupByMutualExclusivity(const Vector<SplitDescription>& splits) { Vector<SortedVector<SplitDescription> > groups; @@ -43,20 +35,22 @@ groupByMutualExclusivity(const Vector<SplitDescription>& splits) { KeyedVector<SplitDescription, SortedVector<SplitDescription> > densityGroups; KeyedVector<SplitDescription, SortedVector<SplitDescription> > abiGroups; KeyedVector<SplitDescription, SortedVector<SplitDescription> > localeGroups; - for (const SplitDescription& split : splits) { + const size_t splitCount = splits.size(); + for (size_t i = 0; i < splitCount; i++) { + const SplitDescription& split = splits[i]; if (split.config.density != 0) { SplitDescription key(split); key.config.density = 0; key.config.sdkVersion = 0; // Ignore density so we can support anydpi. - addToVector(densityGroups, key, split); - } else if (split.abi != abi::Variant::none) { + appendValue(densityGroups, key, split); + } else if (split.abi != abi::Variant_none) { SplitDescription key(split); - key.abi = abi::Variant::none; - addToVector(abiGroups, key, split); + key.abi = abi::Variant_none; + appendValue(abiGroups, key, split); } else if (split.config.locale != 0) { SplitDescription key(split); key.config.clearLocale(); - addToVector(localeGroups, key, split); + appendValue(localeGroups, key, split); } else { groups.add(); groups.editTop().add(split); diff --git a/tools/split-select/Grouper_test.cpp b/tools/split-select/Grouper_test.cpp index 4d146cd..a5f9c5a 100644 --- a/tools/split-select/Grouper_test.cpp +++ b/tools/split-select/Grouper_test.cpp @@ -19,7 +19,6 @@ #include "SplitDescription.h" #include <gtest/gtest.h> -#include <initializer_list> #include <utils/String8.h> #include <utils/Vector.h> @@ -55,7 +54,11 @@ protected: } void addSplit(Vector<SplitDescription>& splits, const char* str); - void expectHasGroupWithSplits(std::initializer_list<const char*> l); + void expectHasGroupWithSplits(const char* a); + void expectHasGroupWithSplits(const char* a, const char* b); + void expectHasGroupWithSplits(const char* a, const char* b, const char* c); + void expectHasGroupWithSplits(const char* a, const char* b, const char* c, const char* d); + void expectHasGroupWithSplits(const Vector<const char*>& expectedStrs); Vector<SortedVector<SplitDescription> > mGroups; }; @@ -65,39 +68,70 @@ TEST_F(GrouperTest, shouldHaveCorrectNumberOfGroups) { } TEST_F(GrouperTest, shouldGroupDensities) { - expectHasGroupWithSplits({"en-rUS-sw300dp-hdpi", "en-rUS-sw300dp-xhdpi"}); - expectHasGroupWithSplits({"en-rUS-sw600dp-hdpi", "en-rUS-sw600dp-xhdpi"}); - expectHasGroupWithSplits({"fr-rFR-sw600dp-hdpi", "fr-rFR-sw600dp-xhdpi"}); - expectHasGroupWithSplits({"hdpi", "xhdpi", "xxhdpi", "anydpi"}); + expectHasGroupWithSplits("en-rUS-sw300dp-hdpi", "en-rUS-sw300dp-xhdpi"); + expectHasGroupWithSplits("en-rUS-sw600dp-hdpi", "en-rUS-sw600dp-xhdpi"); + expectHasGroupWithSplits("fr-rFR-sw600dp-hdpi", "fr-rFR-sw600dp-xhdpi"); + expectHasGroupWithSplits("hdpi", "xhdpi", "xxhdpi", "anydpi"); } TEST_F(GrouperTest, shouldGroupAbi) { - expectHasGroupWithSplits({":armeabi", ":x86"}); + expectHasGroupWithSplits(":armeabi", ":x86"); } TEST_F(GrouperTest, shouldGroupLocale) { - expectHasGroupWithSplits({"pl-rPL", "de-rDE"}); + expectHasGroupWithSplits("pl-rPL", "de-rDE"); } TEST_F(GrouperTest, shouldGroupEachSplitIntoItsOwnGroup) { - expectHasGroupWithSplits({"large"}); - expectHasGroupWithSplits({"xlarge"}); - expectHasGroupWithSplits({"v7"}); - expectHasGroupWithSplits({"v8"}); - expectHasGroupWithSplits({"sw600dp"}); - expectHasGroupWithSplits({"sw300dp"}); + expectHasGroupWithSplits("large"); + expectHasGroupWithSplits("xlarge"); + expectHasGroupWithSplits("v7"); + expectHasGroupWithSplits("v8"); + expectHasGroupWithSplits("sw600dp"); + expectHasGroupWithSplits("sw300dp"); } // // Helper methods // -void GrouperTest::expectHasGroupWithSplits(std::initializer_list<const char*> l) { +void GrouperTest::expectHasGroupWithSplits(const char* a) { + Vector<const char*> expected; + expected.add(a); + expectHasGroupWithSplits(expected); +} + +void GrouperTest::expectHasGroupWithSplits(const char* a, const char* b) { + Vector<const char*> expected; + expected.add(a); + expected.add(b); + expectHasGroupWithSplits(expected); +} + +void GrouperTest::expectHasGroupWithSplits(const char* a, const char* b, const char* c) { + Vector<const char*> expected; + expected.add(a); + expected.add(b); + expected.add(c); + expectHasGroupWithSplits(expected); +} + +void GrouperTest::expectHasGroupWithSplits(const char* a, const char* b, const char* c, const char* d) { + Vector<const char*> expected; + expected.add(a); + expected.add(b); + expected.add(c); + expected.add(d); + expectHasGroupWithSplits(expected); +} + +void GrouperTest::expectHasGroupWithSplits(const Vector<const char*>& expectedStrs) { Vector<SplitDescription> splits; - for (const char* str : l) { + const size_t expectedStrCount = expectedStrs.size(); + for (size_t i = 0; i < expectedStrCount; i++) { splits.add(); - if (!SplitDescription::parse(String8(str), &splits.editTop())) { - ADD_FAILURE() << "Failed to parse SplitDescription " << str; + if (!SplitDescription::parse(String8(expectedStrs[i]), &splits.editTop())) { + ADD_FAILURE() << "Failed to parse SplitDescription " << expectedStrs[i]; return; } } diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp index d6251c3..434494e 100644 --- a/tools/split-select/Main.cpp +++ b/tools/split-select/Main.cpp @@ -63,7 +63,7 @@ static void help() { class SplitSelector { public: - SplitSelector() = default; + SplitSelector(); SplitSelector(const Vector<SplitDescription>& splits); Vector<SplitDescription> getBestSplits(const SplitDescription& target) const; @@ -75,6 +75,9 @@ private: Vector<SortedVector<SplitDescription> > mGroups; }; +SplitSelector::SplitSelector() { +} + SplitSelector::SplitSelector(const Vector<SplitDescription>& splits) : mGroups(groupByMutualExclusivity(splits)) { } diff --git a/tools/split-select/RuleGenerator.cpp b/tools/split-select/RuleGenerator.cpp index 669ae78..b8f3bcb 100644 --- a/tools/split-select/RuleGenerator.cpp +++ b/tools/split-select/RuleGenerator.cpp @@ -65,12 +65,12 @@ sp<Rule> RuleGenerator::generateDensity(const Vector<int>& allDensities, size_t sp<Rule> RuleGenerator::generateAbi(const Vector<abi::Variant>& splitAbis, size_t index) { const abi::Variant thisAbi = splitAbis[index]; - const std::vector<abi::Variant>& familyVariants = abi::getVariants(abi::getFamily(thisAbi)); + const Vector<abi::Variant>& familyVariants = abi::getVariants(abi::getFamily(thisAbi)); - std::vector<abi::Variant>::const_iterator start = + Vector<abi::Variant>::const_iterator start = std::find(familyVariants.begin(), familyVariants.end(), thisAbi); - std::vector<abi::Variant>::const_iterator end = familyVariants.end(); + Vector<abi::Variant>::const_iterator end = familyVariants.end(); if (index + 1 < splitAbis.size()) { end = std::find(start, familyVariants.end(), splitAbis[index + 1]); } @@ -127,7 +127,7 @@ sp<Rule> RuleGenerator::generate(const SortedVector<SplitDescription>& group, si rootRule->subrules.add(generateDensity(allDensities, densityIndex)); } - if (group[index].abi != abi::Variant::none) { + if (group[index].abi != abi::Variant_none) { size_t abiIndex = 0; Vector<abi::Variant> allVariants; allVariants.add(group[index].abi); diff --git a/tools/split-select/RuleGenerator_test.cpp b/tools/split-select/RuleGenerator_test.cpp index 60baabe..ee387be 100644 --- a/tools/split-select/RuleGenerator_test.cpp +++ b/tools/split-select/RuleGenerator_test.cpp @@ -25,19 +25,19 @@ using namespace android; namespace split { static void expectDensityRule(const Vector<int>& densities, int density, int greaterThan, int lessThan); -static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, - std::initializer_list<const char*> matches); +static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, const char* a); +static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, const char* a, const char* b); TEST(RuleGeneratorTest, testAbiRules) { Vector<abi::Variant> abis; - abis.add(abi::Variant::armeabi); - abis.add(abi::Variant::armeabi_v7a); - abis.add(abi::Variant::x86); + abis.add(abi::Variant_armeabi); + abis.add(abi::Variant_armeabi_v7a); + abis.add(abi::Variant_x86); std::sort(abis.begin(), abis.end()); - expectAbiRule(abis, abi::Variant::armeabi, {"armeabi"}); - expectAbiRule(abis, abi::Variant::armeabi_v7a, {"armeabi-v7a", "arm64-v8a"}); - expectAbiRule(abis, abi::Variant::x86, {"x86", "x86_64"}); + expectAbiRule(abis, abi::Variant_armeabi, "armeabi"); + expectAbiRule(abis, abi::Variant_armeabi_v7a, "armeabi-v7a", "arm64-v8a"); + expectAbiRule(abis, abi::Variant_x86, "x86", "x86_64"); } TEST(RuleGeneratorTest, testDensityRules) { @@ -126,8 +126,7 @@ static void expectDensityRule(const Vector<int>& densities, int density, int gre } } -static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, - std::initializer_list<const char*> matches) { +static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, const Vector<const char*>& matches) { const abi::Variant* iter = std::find(abis.begin(), abis.end(), variant); if (abis.end() == iter) { ADD_FAILURE() << abi::toString(variant) << " was not in the abi list."; @@ -143,7 +142,9 @@ static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant EXPECT_EQ(matches.size(), rule->stringArgs.size()) << " for " << abi::toString(variant) << " rule"; - for (const char* match : matches) { + const size_t matchCount = matches.size(); + for (size_t i = 0; i < matchCount; i++) { + const char* match = matches[i]; if (rule->stringArgs.end() == std::find(rule->stringArgs.begin(), rule->stringArgs.end(), String8(match))) { ADD_FAILURE() << "Rule for abi " << abi::toString(variant) @@ -152,4 +153,17 @@ static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant } } +static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, const char* a) { + Vector<const char*> matches; + matches.add(a); + expectAbiRule(abis, variant, matches); +} + +static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, const char* a, const char* b) { + Vector<const char*> matches; + matches.add(a); + matches.add(b); + expectAbiRule(abis, variant, matches); +} + } // namespace split diff --git a/tools/split-select/SplitDescription.cpp b/tools/split-select/SplitDescription.cpp index 8037ef0..99bc23d 100644 --- a/tools/split-select/SplitDescription.cpp +++ b/tools/split-select/SplitDescription.cpp @@ -27,7 +27,7 @@ using namespace android; namespace split { SplitDescription::SplitDescription() -: abi(abi::Variant::none) { +: abi(abi::Variant_none) { } int SplitDescription::compare(const SplitDescription& rhs) const { @@ -38,11 +38,11 @@ int SplitDescription::compare(const SplitDescription& rhs) const { } bool SplitDescription::isBetterThan(const SplitDescription& o, const SplitDescription& target) const { - if (abi != abi::Variant::none || o.abi != abi::Variant::none) { + if (abi != abi::Variant_none || o.abi != abi::Variant_none) { abi::Family family = abi::getFamily(abi); abi::Family oFamily = abi::getFamily(o.abi); if (family != oFamily) { - return family != abi::Family::none; + return family != abi::Family_none; } if (int(target.abi) - int(abi) < int(target.abi) - int(o.abi)) { @@ -53,7 +53,7 @@ bool SplitDescription::isBetterThan(const SplitDescription& o, const SplitDescri } bool SplitDescription::match(const SplitDescription& o) const { - if (abi != abi::Variant::none) { + if (abi != abi::Variant_none) { abi::Family family = abi::getFamily(abi); abi::Family oFamily = abi::getFamily(o.abi); if (family != oFamily) { @@ -69,7 +69,7 @@ bool SplitDescription::match(const SplitDescription& o) const { String8 SplitDescription::toString() const { String8 extension; - if (abi != abi::Variant::none) { + if (abi != abi::Variant_none) { if (extension.isEmpty()) { extension.append(":"); } else { @@ -85,40 +85,40 @@ String8 SplitDescription::toString() const { ssize_t parseAbi(const Vector<String8>& parts, const ssize_t index, SplitDescription* outSplit) { const ssize_t N = parts.size(); - abi::Variant abi = abi::Variant::none; + abi::Variant abi = abi::Variant_none; ssize_t endIndex = index; if (parts[endIndex] == "arm64") { endIndex++; if (endIndex < N) { if (parts[endIndex] == "v8a") { endIndex++; - abi = abi::Variant::arm64_v8a; + abi = abi::Variant_arm64_v8a; } } } else if (parts[endIndex] == "armeabi") { endIndex++; - abi = abi::Variant::armeabi; + abi = abi::Variant_armeabi; if (endIndex < N) { if (parts[endIndex] == "v7a") { endIndex++; - abi = abi::Variant::armeabi_v7a; + abi = abi::Variant_armeabi_v7a; } } } else if (parts[endIndex] == "x86") { endIndex++; - abi = abi::Variant::x86; + abi = abi::Variant_x86; } else if (parts[endIndex] == "x86_64") { endIndex++; - abi = abi::Variant::x86_64; + abi = abi::Variant_x86_64; } else if (parts[endIndex] == "mips") { endIndex++; - abi = abi::Variant::mips; + abi = abi::Variant_mips; } else if (parts[endIndex] == "mips64") { endIndex++; - abi = abi::Variant::mips64; + abi = abi::Variant_mips64; } - if (abi == abi::Variant::none && endIndex != index) { + if (abi == abi::Variant_none && endIndex != index) { return -1; } diff --git a/tools/split-select/SplitDescription.h b/tools/split-select/SplitDescription.h index 5fcafc8..b13c9ee 100644 --- a/tools/split-select/SplitDescription.h +++ b/tools/split-select/SplitDescription.h @@ -27,7 +27,6 @@ namespace split { struct SplitDescription { SplitDescription(); - SplitDescription(const SplitDescription&) = default; ConfigDescription config; abi::Variant abi; |
