summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/jni/android_util_AssetManager.cpp11
-rw-r--r--include/androidfw/ResourceTypes.h19
-rw-r--r--libs/androidfw/ResourceTypes.cpp43
-rw-r--r--libs/androidfw/tests/Config_test.cpp78
-rw-r--r--native/android/configuration.cpp9
-rw-r--r--tools/aapt/AaptConfig.cpp31
-rw-r--r--tools/aapt/AaptConfig.h1
-rw-r--r--tools/aapt/SdkConstants.h1
-rw-r--r--tools/aapt/tests/AaptConfig_test.cpp16
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(&notRoundConfig, 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());
+}