Loading core/jni/android_util_AssetManager.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading include/androidfw/ResourceTypes.h +19 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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 Loading libs/androidfw/ResourceTypes.cpp +43 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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) { Loading Loading @@ -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) { Loading libs/androidfw/tests/Config_test.cpp +78 −0 Original line number Diff line number Diff line Loading @@ -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. native/android/configuration.cpp +9 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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); Loading Loading
core/jni/android_util_AssetManager.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading
include/androidfw/ResourceTypes.h +19 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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 Loading
libs/androidfw/ResourceTypes.cpp +43 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); } Loading Loading @@ -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) { Loading Loading @@ -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) { Loading
libs/androidfw/tests/Config_test.cpp +78 −0 Original line number Diff line number Diff line Loading @@ -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.
native/android/configuration.cpp +9 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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); Loading