diff options
-rw-r--r-- | core/jni/android_util_AssetManager.cpp | 11 | ||||
-rw-r--r-- | include/androidfw/ResourceTypes.h | 19 | ||||
-rw-r--r-- | libs/androidfw/ResourceTypes.cpp | 43 | ||||
-rw-r--r-- | libs/androidfw/tests/Config_test.cpp | 78 | ||||
-rw-r--r-- | native/android/configuration.cpp | 9 | ||||
-rw-r--r-- | tools/aapt/AaptConfig.cpp | 31 | ||||
-rw-r--r-- | tools/aapt/AaptConfig.h | 1 | ||||
-rw-r--r-- | tools/aapt/SdkConstants.h | 1 | ||||
-rw-r--r-- | tools/aapt/tests/AaptConfig_test.cpp | 16 |
9 files changed, 208 insertions, 1 deletions
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 74a9e4e..dca04f5 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -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); diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h index b15caeb..5130e6c 100644 --- a/include/androidfw/ResourceTypes.h +++ b/include/androidfw/ResourceTypes.h @@ -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 diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 2ae7b08..a95db9f 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -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) { diff --git a/libs/androidfw/tests/Config_test.cpp b/libs/androidfw/tests/Config_test.cpp index ef30df4..738947a 100644 --- a/libs/androidfw/tests/Config_test.cpp +++ b/libs/androidfw/tests/Config_test.cpp @@ -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. diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp index 74cf80e..77237ae 100644 --- a/native/android/configuration.cpp +++ b/native/android/configuration.cpp @@ -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); diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp index ede9e99..b12867a 100644 --- a/tools/aapt/AaptConfig.cpp +++ b/tools/aapt/AaptConfig.cpp @@ -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; } diff --git a/tools/aapt/AaptConfig.h b/tools/aapt/AaptConfig.h index f73a508..04c763f 100644 --- a/tools/aapt/AaptConfig.h +++ b/tools/aapt/AaptConfig.h @@ -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); diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h index 4e0fe10..16e622a 100644 --- a/tools/aapt/SdkConstants.h +++ b/tools/aapt/SdkConstants.h @@ -38,6 +38,7 @@ enum { SDK_KITKAT_WATCH = 20, SDK_LOLLIPOP = 21, SDK_LOLLIPOP_MR1 = 22, + SDK_MNC = 23, }; #endif // H_AAPT_SDK_CONSTANTS diff --git a/tools/aapt/tests/AaptConfig_test.cpp b/tools/aapt/tests/AaptConfig_test.cpp index 7618974..8bb38ba 100644 --- a/tools/aapt/tests/AaptConfig_test.cpp +++ b/tools/aapt/tests/AaptConfig_test.cpp @@ -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()); +} |