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
This commit is contained in:
@@ -532,6 +532,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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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]);
|
||||
103
libs/androidfw/tests/Config_test.cpp
Normal file
103
libs/androidfw/tests/Config_test.cpp
Normal file
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -24,6 +24,7 @@ enum {
|
||||
SDK_HONEYCOMB_MR2 = 13,
|
||||
SDK_ICE_CREAM_SANDWICH = 14,
|
||||
SDK_ICE_CREAM_SANDWICH_MR1 = 15,
|
||||
SDK_L = 21,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user