Add -round and -notround qualifier to android runtime/aapt
The round qualifier denotes a device with a screen shape that is round. The qualifier shows up after the 'long/notlong' qualifier and before the orientation 'port/land/square' qualifiers. Change-Id: I3044258b2703a9165694b79725bade770fa6cea1
This commit is contained in:
@@ -615,6 +615,10 @@ static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject c
|
||||
|
||||
const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
|
||||
|
||||
// Constants duplicated from Java class android.content.res.Configuration.
|
||||
static const jint kScreenLayoutRoundMask = 0x300;
|
||||
static const jint kScreenLayoutRoundShift = 8;
|
||||
|
||||
config.mcc = (uint16_t)mcc;
|
||||
config.mnc = (uint16_t)mnc;
|
||||
config.orientation = (uint8_t)orientation;
|
||||
@@ -632,6 +636,13 @@ static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject c
|
||||
config.uiMode = (uint8_t)uiMode;
|
||||
config.sdkVersion = (uint16_t)sdkVersion;
|
||||
config.minorVersion = 0;
|
||||
|
||||
// In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
|
||||
// in C++. We must extract the round qualifier out of the Java screenLayout and put it
|
||||
// into screenLayout2.
|
||||
config.screenLayout2 =
|
||||
(uint8_t)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
|
||||
|
||||
am->setConfiguration(config, locale8);
|
||||
|
||||
if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
|
||||
|
||||
@@ -1132,6 +1132,24 @@ struct ResTable_config
|
||||
// chars. Interpreted in conjunction with the locale field.
|
||||
char localeVariant[8];
|
||||
|
||||
enum {
|
||||
// screenLayout2 bits for round/notround.
|
||||
MASK_SCREENROUND = 0x03,
|
||||
SCREENROUND_ANY = ACONFIGURATION_SCREENROUND_ANY,
|
||||
SCREENROUND_NO = ACONFIGURATION_SCREENROUND_NO,
|
||||
SCREENROUND_YES = ACONFIGURATION_SCREENROUND_YES,
|
||||
};
|
||||
|
||||
// An extension of screenConfig.
|
||||
union {
|
||||
struct {
|
||||
uint8_t screenLayout2; // Contains round/notround qualifier.
|
||||
uint8_t screenConfigPad1; // Reserved padding.
|
||||
uint16_t screenConfigPad2; // Reserved padding.
|
||||
};
|
||||
uint32_t screenConfig2;
|
||||
};
|
||||
|
||||
void copyFromDeviceNoSwap(const ResTable_config& o);
|
||||
|
||||
void copyFromDtoH(const ResTable_config& o);
|
||||
@@ -1160,6 +1178,7 @@ struct ResTable_config
|
||||
CONFIG_SCREEN_LAYOUT = ACONFIGURATION_SCREEN_LAYOUT,
|
||||
CONFIG_UI_MODE = ACONFIGURATION_UI_MODE,
|
||||
CONFIG_LAYOUTDIR = ACONFIGURATION_LAYOUTDIR,
|
||||
CONFIG_SCREEN_ROUND = ACONFIGURATION_SCREEN_ROUND,
|
||||
};
|
||||
|
||||
// Compare two configuration, returning CONFIG_* flags set for each value
|
||||
|
||||
@@ -1894,6 +1894,8 @@ int ResTable_config::compare(const ResTable_config& o) const {
|
||||
if (diff != 0) return diff;
|
||||
diff = (int32_t)(screenLayout - o.screenLayout);
|
||||
if (diff != 0) return diff;
|
||||
diff = (int32_t)(screenLayout2 - o.screenLayout2);
|
||||
if (diff != 0) return diff;
|
||||
diff = (int32_t)(uiMode - o.uiMode);
|
||||
if (diff != 0) return diff;
|
||||
diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
|
||||
@@ -1951,6 +1953,9 @@ int ResTable_config::compareLogical(const ResTable_config& o) const {
|
||||
if (screenLayout != o.screenLayout) {
|
||||
return screenLayout < o.screenLayout ? -1 : 1;
|
||||
}
|
||||
if (screenLayout2 != o.screenLayout2) {
|
||||
return screenLayout2 < o.screenLayout2 ? -1 : 1;
|
||||
}
|
||||
if (uiMode != o.uiMode) {
|
||||
return uiMode < o.uiMode ? -1 : 1;
|
||||
}
|
||||
@@ -1975,6 +1980,7 @@ int ResTable_config::diff(const ResTable_config& o) const {
|
||||
if (version != o.version) diffs |= CONFIG_VERSION;
|
||||
if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) diffs |= CONFIG_LAYOUTDIR;
|
||||
if ((screenLayout & ~MASK_LAYOUTDIR) != (o.screenLayout & ~MASK_LAYOUTDIR)) diffs |= CONFIG_SCREEN_LAYOUT;
|
||||
if ((screenLayout2 & MASK_SCREENROUND) != (o.screenLayout2 & MASK_SCREENROUND)) diffs |= CONFIG_SCREEN_ROUND;
|
||||
if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
|
||||
if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
|
||||
if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
|
||||
@@ -2080,6 +2086,13 @@ bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
|
||||
}
|
||||
}
|
||||
|
||||
if (screenLayout2 || o.screenLayout2) {
|
||||
if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0) {
|
||||
if (!(screenLayout2 & MASK_SCREENROUND)) return false;
|
||||
if (!(o.screenLayout2 & MASK_SCREENROUND)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (orientation != o.orientation) {
|
||||
if (!orientation) return false;
|
||||
if (!o.orientation) return true;
|
||||
@@ -2267,6 +2280,13 @@ bool ResTable_config::isBetterThan(const ResTable_config& o,
|
||||
}
|
||||
}
|
||||
|
||||
if (screenLayout2 || o.screenLayout2) {
|
||||
if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0 &&
|
||||
(requested->screenLayout2 & MASK_SCREENROUND)) {
|
||||
return screenLayout2 & MASK_SCREENROUND;
|
||||
}
|
||||
}
|
||||
|
||||
if ((orientation != o.orientation) && requested->orientation) {
|
||||
return (orientation);
|
||||
}
|
||||
@@ -2480,6 +2500,15 @@ bool ResTable_config::match(const ResTable_config& settings) const {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (screenConfig2 != 0) {
|
||||
const int screenRound = screenLayout2 & MASK_SCREENROUND;
|
||||
const int setScreenRound = settings.screenLayout2 & MASK_SCREENROUND;
|
||||
if (screenRound != 0 && screenRound != setScreenRound) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (screenSizeDp != 0) {
|
||||
if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
|
||||
if (kDebugTableSuperNoisy) {
|
||||
@@ -2770,6 +2799,20 @@ String8 ResTable_config::toString() const {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((screenLayout2&MASK_SCREENROUND) != 0) {
|
||||
if (res.size() > 0) res.append("-");
|
||||
switch (screenLayout2&MASK_SCREENROUND) {
|
||||
case SCREENROUND_NO:
|
||||
res.append("notround");
|
||||
break;
|
||||
case SCREENROUND_YES:
|
||||
res.append("round");
|
||||
break;
|
||||
default:
|
||||
res.appendFormat("screenRound=%d", dtohs(screenLayout2&MASK_SCREENROUND));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (orientation != ORIENTATION_ANY) {
|
||||
if (res.size() > 0) res.append("-");
|
||||
switch (orientation) {
|
||||
|
||||
@@ -100,4 +100,82 @@ TEST(ConfigTest, shouldSelectBestDensityWhenNoneSpecified) {
|
||||
ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
|
||||
}
|
||||
|
||||
TEST(ConfigTest, shouldMatchRoundQualifier) {
|
||||
ResTable_config deviceConfig;
|
||||
memset(&deviceConfig, 0, sizeof(deviceConfig));
|
||||
|
||||
ResTable_config roundConfig;
|
||||
memset(&roundConfig, 0, sizeof(roundConfig));
|
||||
roundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
|
||||
|
||||
EXPECT_FALSE(roundConfig.match(deviceConfig));
|
||||
|
||||
deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
|
||||
|
||||
EXPECT_TRUE(roundConfig.match(deviceConfig));
|
||||
|
||||
deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_NO;
|
||||
|
||||
EXPECT_FALSE(roundConfig.match(deviceConfig));
|
||||
|
||||
ResTable_config notRoundConfig;
|
||||
memset(¬RoundConfig, 0, sizeof(notRoundConfig));
|
||||
notRoundConfig.screenLayout2 = ResTable_config::SCREENROUND_NO;
|
||||
|
||||
EXPECT_TRUE(notRoundConfig.match(deviceConfig));
|
||||
}
|
||||
|
||||
TEST(ConfigTest, RoundQualifierShouldHaveStableSortOrder) {
|
||||
ResTable_config defaultConfig;
|
||||
memset(&defaultConfig, 0, sizeof(defaultConfig));
|
||||
|
||||
ResTable_config longConfig = defaultConfig;
|
||||
longConfig.screenLayout = ResTable_config::SCREENLONG_YES;
|
||||
|
||||
ResTable_config longRoundConfig = longConfig;
|
||||
longRoundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
|
||||
|
||||
ResTable_config longRoundPortConfig = longConfig;
|
||||
longRoundPortConfig.orientation = ResTable_config::ORIENTATION_PORT;
|
||||
|
||||
EXPECT_TRUE(longConfig.compare(longRoundConfig) < 0);
|
||||
EXPECT_TRUE(longConfig.compareLogical(longRoundConfig) < 0);
|
||||
EXPECT_TRUE(longRoundConfig.compare(longConfig) > 0);
|
||||
EXPECT_TRUE(longRoundConfig.compareLogical(longConfig) > 0);
|
||||
|
||||
EXPECT_TRUE(longRoundConfig.compare(longRoundPortConfig) < 0);
|
||||
EXPECT_TRUE(longRoundConfig.compareLogical(longRoundPortConfig) < 0);
|
||||
EXPECT_TRUE(longRoundPortConfig.compare(longRoundConfig) > 0);
|
||||
EXPECT_TRUE(longRoundPortConfig.compareLogical(longRoundConfig) > 0);
|
||||
}
|
||||
|
||||
TEST(ConfigTest, ScreenShapeHasCorrectDiff) {
|
||||
ResTable_config defaultConfig;
|
||||
memset(&defaultConfig, 0, sizeof(defaultConfig));
|
||||
|
||||
ResTable_config roundConfig = defaultConfig;
|
||||
roundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
|
||||
|
||||
EXPECT_EQ(defaultConfig.diff(roundConfig), ResTable_config::CONFIG_SCREEN_ROUND);
|
||||
}
|
||||
|
||||
TEST(ConfigTest, RoundIsMoreSpecific) {
|
||||
ResTable_config deviceConfig;
|
||||
memset(&deviceConfig, 0, sizeof(deviceConfig));
|
||||
deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
|
||||
deviceConfig.screenLayout = ResTable_config::SCREENLONG_YES;
|
||||
|
||||
ResTable_config targetConfigA;
|
||||
memset(&targetConfigA, 0, sizeof(targetConfigA));
|
||||
|
||||
ResTable_config targetConfigB = targetConfigA;
|
||||
targetConfigB.screenLayout = ResTable_config::SCREENLONG_YES;
|
||||
|
||||
ResTable_config targetConfigC = targetConfigB;
|
||||
targetConfigC.screenLayout2 = ResTable_config::SCREENROUND_YES;
|
||||
|
||||
EXPECT_TRUE(targetConfigB.isBetterThan(targetConfigA, &deviceConfig));
|
||||
EXPECT_TRUE(targetConfigC.isBetterThan(targetConfigB, &deviceConfig));
|
||||
}
|
||||
|
||||
} // namespace android.
|
||||
|
||||
@@ -101,6 +101,10 @@ int32_t AConfiguration_getScreenLong(AConfiguration* config) {
|
||||
>> ResTable_config::SHIFT_SCREENLONG;
|
||||
}
|
||||
|
||||
int32_t AConfiguration_getScreenRound(AConfiguration* config) {
|
||||
return (config->screenLayout2&ResTable_config::MASK_SCREENROUND);
|
||||
}
|
||||
|
||||
int32_t AConfiguration_getUiModeType(AConfiguration* config) {
|
||||
return config->uiMode&ResTable_config::MASK_UI_MODE_TYPE;
|
||||
}
|
||||
@@ -192,6 +196,11 @@ void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong) {
|
||||
| ((screenLong<<ResTable_config::SHIFT_SCREENLONG)&ResTable_config::MASK_SCREENLONG);
|
||||
}
|
||||
|
||||
void AConfiguration_setScreenRound(AConfiguration* config, int32_t screenRound) {
|
||||
config->screenLayout2 = (config->screenLayout2&~ResTable_config::MASK_SCREENROUND)
|
||||
| (screenRound&ResTable_config::MASK_SCREENROUND);
|
||||
}
|
||||
|
||||
void AConfiguration_setUiModeType(AConfiguration* config, int32_t uiModeType) {
|
||||
config->uiMode = (config->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
|
||||
| (uiModeType&ResTable_config::MASK_UI_MODE_TYPE);
|
||||
|
||||
@@ -123,6 +123,14 @@ bool parse(const String8& str, ConfigDescription* out) {
|
||||
part = parts[index].string();
|
||||
}
|
||||
|
||||
if (parseScreenRound(part, &config)) {
|
||||
index++;
|
||||
if (index == N) {
|
||||
goto success;
|
||||
}
|
||||
part = parts[index].string();
|
||||
}
|
||||
|
||||
if (parseOrientation(part, &config)) {
|
||||
index++;
|
||||
if (index == N) {
|
||||
@@ -241,7 +249,9 @@ void applyVersionForCompatibility(ConfigDescription* config) {
|
||||
}
|
||||
|
||||
uint16_t minSdk = 0;
|
||||
if (config->density == ResTable_config::DENSITY_ANY) {
|
||||
if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) {
|
||||
minSdk = SDK_MNC;
|
||||
} else if (config->density == ResTable_config::DENSITY_ANY) {
|
||||
minSdk = SDK_LOLLIPOP;
|
||||
} else if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
|
||||
|| config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
|
||||
@@ -395,7 +405,26 @@ bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
|
||||
| ResTable_config::SCREENLONG_NO;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parseScreenRound(const char* name, ResTable_config* out) {
|
||||
if (strcmp(name, kWildcardName) == 0) {
|
||||
if (out) out->screenLayout2 =
|
||||
(out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
|
||||
| ResTable_config::SCREENROUND_ANY;
|
||||
return true;
|
||||
} else if (strcmp(name, "round") == 0) {
|
||||
if (out) out->screenLayout2 =
|
||||
(out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
|
||||
| ResTable_config::SCREENROUND_YES;
|
||||
return true;
|
||||
} else if (strcmp(name, "notround") == 0) {
|
||||
if (out) out->screenLayout2 =
|
||||
(out->screenLayout2&~ResTable_config::MASK_SCREENROUND)
|
||||
| ResTable_config::SCREENROUND_NO;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ bool parseScreenWidthDp(const char* str, android::ResTable_config* out = NULL);
|
||||
bool parseScreenHeightDp(const char* str, android::ResTable_config* out = NULL);
|
||||
bool parseScreenLayoutSize(const char* str, android::ResTable_config* out = NULL);
|
||||
bool parseScreenLayoutLong(const char* str, android::ResTable_config* out = NULL);
|
||||
bool parseScreenRound(const char* name, android::ResTable_config* out = NULL);
|
||||
bool parseOrientation(const char* str, android::ResTable_config* out = NULL);
|
||||
bool parseUiModeType(const char* str, android::ResTable_config* out = NULL);
|
||||
bool parseUiModeNight(const char* str, android::ResTable_config* out = NULL);
|
||||
|
||||
@@ -38,6 +38,7 @@ enum {
|
||||
SDK_KITKAT_WATCH = 20,
|
||||
SDK_LOLLIPOP = 21,
|
||||
SDK_LOLLIPOP_MR1 = 22,
|
||||
SDK_MNC = 23,
|
||||
};
|
||||
|
||||
#endif // H_AAPT_SDK_CONSTANTS
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "AaptConfig.h"
|
||||
#include "ConfigDescription.h"
|
||||
#include "SdkConstants.h"
|
||||
#include "TestHelper.h"
|
||||
|
||||
using android::String8;
|
||||
@@ -82,3 +83,18 @@ TEST(AaptConfigTest, TestParsingOfCarAttribute) {
|
||||
EXPECT_TRUE(TestParse("car", &config));
|
||||
EXPECT_EQ(android::ResTable_config::UI_MODE_TYPE_CAR, config.uiMode);
|
||||
}
|
||||
|
||||
TEST(AaptConfigTest, TestParsingRoundQualifier) {
|
||||
ConfigDescription config;
|
||||
EXPECT_TRUE(TestParse("round", &config));
|
||||
EXPECT_EQ(android::ResTable_config::SCREENROUND_YES,
|
||||
config.screenLayout2 & android::ResTable_config::MASK_SCREENROUND);
|
||||
EXPECT_EQ(SDK_MNC, config.sdkVersion);
|
||||
EXPECT_EQ(String8("round-v23"), config.toString());
|
||||
|
||||
EXPECT_TRUE(TestParse("notround", &config));
|
||||
EXPECT_EQ(android::ResTable_config::SCREENROUND_NO,
|
||||
config.screenLayout2 & android::ResTable_config::MASK_SCREENROUND);
|
||||
EXPECT_EQ(SDK_MNC, config.sdkVersion);
|
||||
EXPECT_EQ(String8("notround-v23"), config.toString());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user