diff options
| author | 2014-08-22 19:10:56 -0700 | |
|---|---|---|
| committer | 2014-08-25 17:47:30 -0700 | |
| commit | 31245b4f06003f1c8cd44c31b387c96ab4e282f9 (patch) | |
| tree | ec59d73e6b6e563876ed8c4e5de331b4df17549e | |
| parent | 5b8e5a7d4c930b42e1a3c2b3e67144b89d37efa2 (diff) | |
Introduce anydpi density resource qualifier
This is meant to be used with scaleable vector
drawables, and are chosen as the best match unless
there is a configuration that matches the density
requested exactly.
Bug:17007265
Change-Id: Ic3288d0236fe0bff20bb1599aba2582c25b0db32
| -rw-r--r-- | core/java/android/content/res/Configuration.java | 19 | ||||
| -rw-r--r-- | include/androidfw/ResourceTypes.h | 1 | ||||
| -rw-r--r-- | libs/androidfw/ResourceTypes.cpp | 37 | ||||
| -rw-r--r-- | libs/androidfw/tests/Android.mk | 3 | ||||
| -rw-r--r-- | libs/androidfw/tests/ConfigLocale_test.cpp (renamed from libs/androidfw/tests/ResourceTypes_test.cpp) | 18 | ||||
| -rw-r--r-- | libs/androidfw/tests/Config_test.cpp | 103 | ||||
| -rw-r--r-- | libs/androidfw/tests/TestHelpers.h | 13 | ||||
| -rw-r--r-- | tools/aapt/AaptConfig.cpp | 7 | ||||
| -rw-r--r-- | tools/aapt/Bundle.h | 1 |
9 files changed, 182 insertions, 20 deletions
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index d19418b37940..e63fd0703339 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -533,6 +533,18 @@ public final class Configuration implements Parcelable, Comparable<Configuration public static final int DENSITY_DPI_UNDEFINED = 0; /** + * Value for {@link #densityDpi} for resources that scale to any density (vector drawables). + * {@hide} + */ + public static final int DENSITY_DPI_ANY = 0xfffe; + + /** + * Value for {@link #densityDpi} for resources that are not meant to be scaled. + * {@hide} + */ + public static final int DENSITY_DPI_NONE = 0xffff; + + /** * The target screen density being rendered to, * corresponding to * <a href="{@docRoot}guide/topics/resources/providing-resources.html#DensityQualifier">density</a> @@ -1453,7 +1465,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration } switch (config.densityDpi) { - case 0: + case DENSITY_DPI_UNDEFINED: break; case 120: parts.add("ldpi"); @@ -1476,6 +1488,11 @@ public final class Configuration implements Parcelable, Comparable<Configuration case 640: parts.add("xxxhdpi"); break; + case DENSITY_DPI_ANY: + parts.add("anydpi"); + break; + case DENSITY_DPI_NONE: + parts.add("nodpi"); default: parts.add(config.densityDpi + "dpi"); break; diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h index 1af497cfb2e4..11568d280c24 100644 --- a/include/androidfw/ResourceTypes.h +++ b/include/androidfw/ResourceTypes.h @@ -954,6 +954,7 @@ struct ResTable_config DENSITY_XHIGH = ACONFIGURATION_DENSITY_XHIGH, DENSITY_XXHIGH = ACONFIGURATION_DENSITY_XXHIGH, DENSITY_XXXHIGH = ACONFIGURATION_DENSITY_XXXHIGH, + DENSITY_ANY = ACONFIGURATION_DENSITY_ANY, DENSITY_NONE = ACONFIGURATION_DENSITY_NONE }; diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 239d682d1c8c..3f014ef5de1e 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -2206,13 +2206,30 @@ bool ResTable_config::isBetterThan(const ResTable_config& o, if (screenType || o.screenType) { if (density != o.density) { - // density is tough. Any density is potentially useful + // Use the system default density (DENSITY_MEDIUM, 160dpi) if none specified. + const int thisDensity = density ? density : int(ResTable_config::DENSITY_MEDIUM); + const int otherDensity = o.density ? o.density : int(ResTable_config::DENSITY_MEDIUM); + + // We always prefer DENSITY_ANY over scaling a density bucket. + if (thisDensity == ResTable_config::DENSITY_ANY) { + return true; + } else if (otherDensity == ResTable_config::DENSITY_ANY) { + return false; + } + + int requestedDensity = requested->density; + if (requested->density == 0 || + requested->density == ResTable_config::DENSITY_ANY) { + requestedDensity = ResTable_config::DENSITY_MEDIUM; + } + + // DENSITY_ANY is now dealt with. We should look to + // pick a density bucket and potentially scale it. + // Any density is potentially useful // because the system will scale it. Scaling down // is generally better than scaling up. - // Default density counts as 160dpi (the system default) - // TODO - remove 160 constants - int h = (density?density:160); - int l = (o.density?o.density:160); + int h = thisDensity; + int l = otherDensity; bool bImBigger = true; if (l > h) { int t = h; @@ -2221,17 +2238,16 @@ bool ResTable_config::isBetterThan(const ResTable_config& o, bImBigger = false; } - int reqValue = (requested->density?requested->density:160); - if (reqValue >= h) { + if (requestedDensity >= h) { // requested value higher than both l and h, give h return bImBigger; } - if (l >= reqValue) { + if (l >= requestedDensity) { // requested value lower than both l and h, give l return !bImBigger; } // saying that scaling down is 2x better than up - if (((2 * l) - reqValue) * h > reqValue * reqValue) { + if (((2 * l) - requestedDensity) * h > requestedDensity * requestedDensity) { return !bImBigger; } else { return bImBigger; @@ -2702,6 +2718,9 @@ String8 ResTable_config::toString() const { case ResTable_config::DENSITY_NONE: res.append("nodpi"); break; + case ResTable_config::DENSITY_ANY: + res.append("anydpi"); + break; default: res.appendFormat("%ddpi", dtohs(density)); break; diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk index 4ff6eecf1685..a10c38761fbd 100644 --- a/libs/androidfw/tests/Android.mk +++ b/libs/androidfw/tests/Android.mk @@ -21,8 +21,9 @@ LOCAL_PATH:= $(call my-dir) testFiles := \ ByteBucketArray_test.cpp \ + Config_test.cpp \ + ConfigLocale_test.cpp \ Idmap_test.cpp \ - ResourceTypes_test.cpp \ ResTable_test.cpp \ Split_test.cpp \ TypeWrappers_test.cpp \ diff --git a/libs/androidfw/tests/ResourceTypes_test.cpp b/libs/androidfw/tests/ConfigLocale_test.cpp index f00a2d9ea6e3..49995942a562 100644 --- a/libs/androidfw/tests/ResourceTypes_test.cpp +++ b/libs/androidfw/tests/ConfigLocale_test.cpp @@ -21,7 +21,7 @@ #include <gtest/gtest.h> namespace android { -TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterLanguage) { +TEST(ConfigLocaleTest, packAndUnpack2LetterLanguage) { ResTable_config config; config.packLanguage("en"); @@ -44,7 +44,7 @@ TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterLanguage) { EXPECT_EQ(0, out[3]); } -TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterRegion) { +TEST(ConfigLocaleTest, packAndUnpack2LetterRegion) { ResTable_config config; config.packRegion("US"); @@ -59,7 +59,7 @@ TEST(ResourceTypesTest, ResourceConfig_packAndUnpack2LetterRegion) { EXPECT_EQ(0, out[3]); } -TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterLanguage) { +TEST(ConfigLocaleTest, packAndUnpack3LetterLanguage) { ResTable_config config; config.packLanguage("eng"); @@ -75,7 +75,7 @@ TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterLanguage) { EXPECT_EQ(0, out[3]); } -TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterLanguageAtOffset16) { +TEST(ConfigLocaleTest, packAndUnpack3LetterLanguageAtOffset16) { ResTable_config config; config.packLanguage("tgp"); @@ -88,8 +88,8 @@ TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterLanguageAtOffset16) { // which is equivalent to: // 1 [0] [1] [2] // 1-01111-00110-10011 - EXPECT_EQ(0xbc, config.language[0]); - EXPECT_EQ(0xd3, config.language[1]); + EXPECT_EQ(char(0xbc), config.language[0]); + EXPECT_EQ(char(0xd3), config.language[1]); char out[4] = { 1, 1, 1, 1}; config.unpackLanguage(out); @@ -99,7 +99,7 @@ TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterLanguageAtOffset16) { EXPECT_EQ(0, out[3]); } -TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterRegion) { +TEST(ConfigLocaleTest, packAndUnpack3LetterRegion) { ResTable_config config; config.packRegion("419"); @@ -131,7 +131,7 @@ TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterRegion) { } } -TEST(ResourceTypesTest, IsMoreSpecificThan) { +TEST(ConfigLocaleTest, IsMoreSpecificThan) { ResTable_config l; ResTable_config r; @@ -170,7 +170,7 @@ TEST(ResourceTypesTest, IsMoreSpecificThan) { EXPECT_TRUE(r.isMoreSpecificThan(l)); } -TEST(ResourceTypesTest, setLocale) { +TEST(ConfigLocaleTest, setLocale) { ResTable_config test; test.setBcp47Locale("en-US"); EXPECT_EQ('e', test.language[0]); diff --git a/libs/androidfw/tests/Config_test.cpp b/libs/androidfw/tests/Config_test.cpp new file mode 100644 index 000000000000..ef30df46d36c --- /dev/null +++ b/libs/androidfw/tests/Config_test.cpp @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#include <androidfw/ResourceTypes.h> +#include <utils/Log.h> +#include <utils/String8.h> +#include <utils/Vector.h> + +#include "TestHelpers.h" +#include <gtest/gtest.h> + +namespace android { + +static ResTable_config selectBest(const ResTable_config& target, + const Vector<ResTable_config>& configs) { + ResTable_config bestConfig; + memset(&bestConfig, 0, sizeof(bestConfig)); + const size_t configCount = configs.size(); + for (size_t i = 0; i < configCount; i++) { + const ResTable_config& thisConfig = configs[i]; + if (!thisConfig.match(target)) { + continue; + } + + if (thisConfig.isBetterThan(bestConfig, &target)) { + bestConfig = thisConfig; + } + } + return bestConfig; +} + +static ResTable_config buildDensityConfig(int density) { + ResTable_config config; + memset(&config, 0, sizeof(config)); + config.density = uint16_t(density); + config.sdkVersion = 4; + return config; +} + +TEST(ConfigTest, shouldSelectBestDensity) { + ResTable_config deviceConfig; + memset(&deviceConfig, 0, sizeof(deviceConfig)); + deviceConfig.density = ResTable_config::DENSITY_XHIGH; + deviceConfig.sdkVersion = 21; + + Vector<ResTable_config> configs; + + ResTable_config expectedBest = buildDensityConfig(ResTable_config::DENSITY_HIGH); + configs.add(expectedBest); + ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); + + expectedBest = buildDensityConfig(ResTable_config::DENSITY_XXHIGH); + configs.add(expectedBest); + ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); + + expectedBest = buildDensityConfig(int(ResTable_config::DENSITY_XXHIGH) - 20); + configs.add(expectedBest); + ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); + + configs.add(buildDensityConfig(int(ResTable_config::DENSITY_HIGH) + 20)); + ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); + + expectedBest = buildDensityConfig(ResTable_config::DENSITY_XHIGH); + configs.add(expectedBest); + ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); + + expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY); + expectedBest.sdkVersion = 21; + configs.add(expectedBest); + ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); +} + +TEST(ConfigTest, shouldSelectBestDensityWhenNoneSpecified) { + ResTable_config deviceConfig; + memset(&deviceConfig, 0, sizeof(deviceConfig)); + deviceConfig.sdkVersion = 21; + + Vector<ResTable_config> configs; + configs.add(buildDensityConfig(ResTable_config::DENSITY_HIGH)); + + ResTable_config expectedBest = buildDensityConfig(ResTable_config::DENSITY_MEDIUM); + configs.add(expectedBest); + ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); + + expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY); + configs.add(expectedBest); + ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs)); +} + +} // namespace android. diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h index 75a233acad26..fe2e5ce29eff 100644 --- a/libs/androidfw/tests/TestHelpers.h +++ b/libs/androidfw/tests/TestHelpers.h @@ -3,6 +3,7 @@ #include <ostream> +#include <androidfw/ResourceTypes.h> #include <utils/String8.h> #include <utils/String16.h> @@ -14,4 +15,16 @@ static inline ::std::ostream& operator<<(::std::ostream& out, const android::Str return out << android::String8(str).string(); } +namespace android { + +static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) { + return memcmp(&a, &b, sizeof(a)) == 0; +} + +static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) { + return out << c.toString().string(); +} + +} // namespace android + #endif // __TEST_HELPERS_H diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp index 69a9c7feca99..32a0cd3d4872 100644 --- a/tools/aapt/AaptConfig.cpp +++ b/tools/aapt/AaptConfig.cpp @@ -255,6 +255,8 @@ void applyVersionForCompatibility(ConfigDescription* config) { != ResTable_config::SCREENLONG_ANY || config->density != ResTable_config::DENSITY_DEFAULT) { minSdk = SDK_DONUT; + } else if ((config->density == ResTable_config::DENSITY_ANY)) { + minSdk = SDK_L; } if (minSdk > config->sdkVersion) { @@ -477,6 +479,11 @@ bool parseDensity(const char* name, ResTable_config* out) { return true; } + if (strcmp(name, "anydpi") == 0) { + if (out) out->density = ResTable_config::DENSITY_ANY; + return true; + } + if (strcmp(name, "nodpi") == 0) { if (out) out->density = ResTable_config::DENSITY_NONE; return true; diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index 1439f14b7fb6..af494618d6ce 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -24,6 +24,7 @@ enum { SDK_HONEYCOMB_MR2 = 13, SDK_ICE_CREAM_SANDWICH = 14, SDK_ICE_CREAM_SANDWICH_MR1 = 15, + SDK_L = 21, }; /* |