summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Adam Lesinski <adamlesinski@google.com> 2014-08-22 19:10:56 -0700
committer Adam Lesinski <adamlesinski@google.com> 2014-08-25 17:47:30 -0700
commit31245b4f06003f1c8cd44c31b387c96ab4e282f9 (patch)
treeec59d73e6b6e563876ed8c4e5de331b4df17549e
parent5b8e5a7d4c930b42e1a3c2b3e67144b89d37efa2 (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.java19
-rw-r--r--include/androidfw/ResourceTypes.h1
-rw-r--r--libs/androidfw/ResourceTypes.cpp37
-rw-r--r--libs/androidfw/tests/Android.mk3
-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.cpp103
-rw-r--r--libs/androidfw/tests/TestHelpers.h13
-rw-r--r--tools/aapt/AaptConfig.cpp7
-rw-r--r--tools/aapt/Bundle.h1
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,
};
/*