diff --git a/core/api/current.txt b/core/api/current.txt index 24b985d88e4b1..ece3f8eff33f3 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -12984,9 +12984,9 @@ package android.content.res { field @NonNull public static final android.os.Parcelable.Creator CREATOR; field public static final int DENSITY_DPI_UNDEFINED = 0; // 0x0 field public static final int FONT_WEIGHT_ADJUSTMENT_UNDEFINED = 2147483647; // 0x7fffffff - field public static final int GRAMMATICAL_GENDER_FEMININE = 3; // 0x3 - field public static final int GRAMMATICAL_GENDER_MASCULINE = 4; // 0x4 - field public static final int GRAMMATICAL_GENDER_NEUTRAL = 2; // 0x2 + field public static final int GRAMMATICAL_GENDER_FEMININE = 2; // 0x2 + field public static final int GRAMMATICAL_GENDER_MASCULINE = 3; // 0x3 + field public static final int GRAMMATICAL_GENDER_NEUTRAL = 1; // 0x1 field public static final int GRAMMATICAL_GENDER_NOT_SPECIFIED = 0; // 0x0 field public static final int HARDKEYBOARDHIDDEN_NO = 1; // 0x1 field public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0; // 0x0 diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index a9f55bc1ea4c9..adcd1861886a0 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -998,6 +998,7 @@ public static String launchModeToString(@LaunchMode int launchMode) { Configuration.NATIVE_CONFIG_DENSITY, // DENSITY Configuration.NATIVE_CONFIG_LAYOUTDIR, // LAYOUT DIRECTION Configuration.NATIVE_CONFIG_COLOR_MODE, // COLOR_MODE + Configuration.NATIVE_CONFIG_GRAMMATICAL_GENDER, }; /** @@ -1267,8 +1268,8 @@ public int getRealConfigChanged() { * {@link #CONFIG_LOCALE}, {@link #CONFIG_TOUCHSCREEN}, * {@link #CONFIG_KEYBOARD}, {@link #CONFIG_NAVIGATION}, * {@link #CONFIG_ORIENTATION}, {@link #CONFIG_SCREEN_LAYOUT}, - * {@link #CONFIG_DENSITY}, {@link #CONFIG_LAYOUT_DIRECTION} and - * {@link #CONFIG_COLOR_MODE}. + * {@link #CONFIG_DENSITY}, {@link #CONFIG_LAYOUT_DIRECTION}, + * {@link #CONFIG_COLOR_MODE}, and {link #CONFIG_GRAMMATICAL_GENDER}. * Set from the {@link android.R.attr#configChanges} attribute. */ public int configChanges; diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index c15b3e0b80c3c..048289f56a0c2 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1456,7 +1456,7 @@ private static void collectCertificates(Package pkg, File apkFile, boolean skipV private static AssetManager newConfiguredAssetManager() { AssetManager assetManager = new AssetManager(); - assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); return assetManager; } @@ -9011,7 +9011,7 @@ public AssetManager getBaseAssetManager() throws PackageParserException { } AssetManager assets = new AssetManager(); - assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); assets.setApkAssets(apkAssets, false /*invalidateCaches*/); @@ -9086,7 +9086,7 @@ private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) { final AssetManager assets = new AssetManager(); - assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); assets.setApkAssets(apkAssets, false /*invalidateCaches*/); return assets; diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index c8bbb0c1994d6..dfc7b46497701 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -1461,13 +1461,14 @@ Configuration[] getSizeConfigurations() { public void setConfiguration(int mcc, int mnc, @Nullable String locale, int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp, - int screenHeightDp, int screenLayout, int uiMode, int colorMode, int majorVersion) { + int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender, + int majorVersion) { synchronized (this) { ensureValidLocked(); nativeSetConfiguration(mObject, mcc, mnc, locale, orientation, touchscreen, density, keyboard, keyboardHidden, navigation, screenWidth, screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode, - colorMode, majorVersion); + colorMode, grammaticalGender, majorVersion); } } @@ -1557,7 +1558,7 @@ private static native void nativeSetConfiguration(long ptr, int mcc, int mnc, @Nullable String locale, int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout, - int uiMode, int colorMode, int majorVersion); + int uiMode, int colorMode, int grammaticalGender, int majorVersion); private static native @NonNull SparseArray nativeGetAssignedPackageIdentifiers( long ptr, boolean includeOverlays, boolean includeLoaders); diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 96aa6249245c3..0def59f36d80f 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -20,6 +20,7 @@ import static android.content.ConfigurationProto.DENSITY_DPI; import static android.content.ConfigurationProto.FONT_SCALE; import static android.content.ConfigurationProto.FONT_WEIGHT_ADJUSTMENT; +import static android.content.ConfigurationProto.GRAMMATICAL_GENDER; import static android.content.ConfigurationProto.HARD_KEYBOARD_HIDDEN; import static android.content.ConfigurationProto.KEYBOARD; import static android.content.ConfigurationProto.KEYBOARD_HIDDEN; @@ -167,19 +168,19 @@ public final class Configuration implements Parcelable, ComparableConstruct an invalid Configuration. This state is only suitable for constructing a @@ -1112,6 +1112,14 @@ public String toString() { } else { sb.append(" ?localeList"); } + if (mGrammaticalGender != 0) { + switch (mGrammaticalGender) { + case GRAMMATICAL_GENDER_NEUTRAL: sb.append(" neuter"); break; + case GRAMMATICAL_GENDER_FEMININE: sb.append(" feminine"); break; + case GRAMMATICAL_GENDER_MASCULINE: sb.append(" masculine"); break; + case GRAMMATICAL_GENDER_NOT_SPECIFIED: sb.append(" ?grgend"); break; + } + } int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK); switch (layoutDir) { case SCREENLAYOUT_LAYOUTDIR_UNDEFINED: sb.append(" ?layoutDir"); break; @@ -1292,6 +1300,7 @@ public void dumpDebug(ProtoOutputStream protoOutputStream, long fieldId, boolean protoOutputStream.write(ORIENTATION, orientation); protoOutputStream.write(SCREEN_WIDTH_DP, screenWidthDp); protoOutputStream.write(SCREEN_HEIGHT_DP, screenHeightDp); + protoOutputStream.write(GRAMMATICAL_GENDER, mGrammaticalGender); protoOutputStream.end(token); } @@ -1454,6 +1463,9 @@ public void readFromProto(ProtoInputStream protoInputStream, long fieldId) throw case (int) FONT_WEIGHT_ADJUSTMENT: fontWeightAdjustment = protoInputStream.readInt(FONT_WEIGHT_ADJUSTMENT); break; + case (int) GRAMMATICAL_GENDER: + mGrammaticalGender = protoInputStream.readInt(GRAMMATICAL_GENDER); + break; } } } finally { @@ -1839,6 +1851,9 @@ public void setTo(@NonNull Configuration delta, @Config int mask, if ((mask & ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT) != 0) { fontWeightAdjustment = delta.fontWeightAdjustment; } + if ((mask & ActivityInfo.CONFIG_GRAMMATICAL_GENDER) != 0) { + mGrammaticalGender = delta.mGrammaticalGender; + } } /** @@ -1975,7 +1990,7 @@ && getScreenLayoutNoDirection(screenLayout) != changed |= ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT; } - if (!publicOnly&& mGrammaticalGender != delta.mGrammaticalGender) { + if (!publicOnly && mGrammaticalGender != delta.mGrammaticalGender) { changed |= ActivityInfo.CONFIG_GRAMMATICAL_GENDER; } return changed; @@ -2172,6 +2187,8 @@ public int compareTo(Configuration that) { if (n != 0) return n; } + n = this.mGrammaticalGender - that.mGrammaticalGender; + if (n != 0) return n; n = this.touchscreen - that.touchscreen; if (n != 0) return n; n = this.keyboard - that.keyboard; @@ -2205,11 +2222,6 @@ public int compareTo(Configuration that) { n = windowConfiguration.compareTo(that.windowConfiguration); if (n != 0) return n; n = this.fontWeightAdjustment - that.fontWeightAdjustment; - if (n != 0) return n; - n = this.mGrammaticalGender - that.mGrammaticalGender; - if (n != 0) return n; - - // if (n != 0) return n; return n; } @@ -2482,6 +2494,20 @@ public static String resourceQualifierString(Configuration config, DisplayMetric } } + switch (config.mGrammaticalGender) { + case Configuration.GRAMMATICAL_GENDER_NEUTRAL: + parts.add("neuter"); + break; + case Configuration.GRAMMATICAL_GENDER_FEMININE: + parts.add("feminine"); + break; + case Configuration.GRAMMATICAL_GENDER_MASCULINE: + parts.add("masculine"); + break; + default: + break; + } + switch (config.screenLayout & Configuration.SCREENLAYOUT_LAYOUTDIR_MASK) { case Configuration.SCREENLAYOUT_LAYOUTDIR_LTR: parts.add("ldltr"); @@ -2768,6 +2794,10 @@ public static Configuration generateDelta( delta.locale = change.locale; } + if (base.mGrammaticalGender != change.mGrammaticalGender) { + delta.mGrammaticalGender = change.mGrammaticalGender; + } + if (base.touchscreen != change.touchscreen) { delta.touchscreen = change.touchscreen; } @@ -2881,6 +2911,7 @@ public static Configuration generateDelta( private static final String XML_ATTR_DENSITY = "density"; private static final String XML_ATTR_APP_BOUNDS = "app_bounds"; private static final String XML_ATTR_FONT_WEIGHT_ADJUSTMENT = "fontWeightAdjustment"; + private static final String XML_ATTR_GRAMMATICAL_GENDER = "grammaticalGender"; /** * Reads the attributes corresponding to Configuration member fields from the Xml parser. @@ -2932,6 +2963,8 @@ public static void readXmlAttrs(XmlPullParser parser, Configuration configOut) DENSITY_DPI_UNDEFINED); configOut.fontWeightAdjustment = XmlUtils.readIntAttribute(parser, XML_ATTR_FONT_WEIGHT_ADJUSTMENT, FONT_WEIGHT_ADJUSTMENT_UNDEFINED); + configOut.mGrammaticalGender = XmlUtils.readIntAttribute(parser, + XML_ATTR_GRAMMATICAL_GENDER, GRAMMATICAL_GENDER_NOT_SPECIFIED); // For persistence, we don't care about assetsSeq and WindowConfiguration, so do not read it // out. diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index c2b37694c0c34..21708864d73ff 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -466,7 +466,8 @@ public void updateConfiguration(Configuration config, DisplayMetrics metrics, mConfiguration.smallestScreenWidthDp, mConfiguration.screenWidthDp, mConfiguration.screenHeightDp, mConfiguration.screenLayout, mConfiguration.uiMode, - mConfiguration.colorMode, Build.VERSION.RESOURCES_SDK_INT); + mConfiguration.colorMode, mConfiguration.getGrammaticalGender(), + Build.VERSION.RESOURCES_SDK_INT); if (DEBUG_CONFIG) { Slog.i(TAG, "**** Updating config of " + this + ": final config is " diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index b60ec9f493c22..9e92542bf3a14 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -324,7 +324,7 @@ static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin jint screen_width, jint screen_height, jint smallest_screen_width_dp, jint screen_width_dp, jint screen_height_dp, jint screen_layout, jint ui_mode, - jint color_mode, jint major_version) { + jint color_mode, jint grammatical_gender, jint major_version) { ATRACE_NAME("AssetManager::SetConfiguration"); ResTable_config configuration; @@ -345,6 +345,7 @@ static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin configuration.screenLayout = static_cast(screen_layout); configuration.uiMode = static_cast(ui_mode); configuration.colorMode = static_cast(color_mode); + configuration.grammaticalInflection = static_cast(grammatical_gender); configuration.sdkVersion = static_cast(major_version); if (locale != nullptr) { @@ -1448,7 +1449,7 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"nativeCreate", "()J", (void*)NativeCreate}, {"nativeDestroy", "(J)V", (void*)NativeDestroy}, {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets}, - {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V", + {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIIII)V", (void*)NativeSetConfiguration}, {"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;", (void*)NativeGetAssignedPackageIdentifiers}, diff --git a/core/proto/android/content/configuration.proto b/core/proto/android/content/configuration.proto index b1ffe3881caa9..0e2234f2fdcc6 100644 --- a/core/proto/android/content/configuration.proto +++ b/core/proto/android/content/configuration.proto @@ -50,6 +50,7 @@ message ConfigurationProto { optional .android.app.WindowConfigurationProto window_configuration = 19; optional string locale_list = 20; optional uint32 font_weight_adjustment = 21; + optional uint32 grammatical_gender = 22; } /** diff --git a/libs/androidfw/ConfigDescription.cpp b/libs/androidfw/ConfigDescription.cpp index 93a7d173cb973..cf2fd6f59b87a 100644 --- a/libs/androidfw/ConfigDescription.cpp +++ b/libs/androidfw/ConfigDescription.cpp @@ -21,6 +21,7 @@ #include "androidfw/Util.h" #include +#include #include namespace android { @@ -38,11 +39,11 @@ static bool parseMcc(const char* name, ResTable_config* out) { return true; } const char* c = name; - if (tolower(*c) != 'm') return false; + if (*c != 'm') return false; c++; - if (tolower(*c) != 'c') return false; + if (*c != 'c') return false; c++; - if (tolower(*c) != 'c') return false; + if (*c != 'c') return false; c++; const char* val = c; @@ -68,11 +69,11 @@ static bool parseMnc(const char* name, ResTable_config* out) { return true; } const char* c = name; - if (tolower(*c) != 'm') return false; + if (*c != 'm') return false; c++; - if (tolower(*c) != 'n') return false; + if (*c != 'n') return false; c++; - if (tolower(*c) != 'c') return false; + if (*c != 'c') return false; c++; const char* val = c; @@ -93,6 +94,23 @@ static bool parseMnc(const char* name, ResTable_config* out) { return true; } +static bool parseGrammaticalInflection(const std::string& name, ResTable_config* out) { + using namespace std::literals; + if (name == "feminine"sv) { + if (out) out->grammaticalInflection = ResTable_config::GRAMMATICAL_GENDER_FEMININE; + return true; + } + if (name == "masculine"sv) { + if (out) out->grammaticalInflection = ResTable_config::GRAMMATICAL_GENDER_MASCULINE; + return true; + } + if (name == "neuter"sv) { + if (out) out->grammaticalInflection = ResTable_config::GRAMMATICAL_GENDER_NEUTER; + return true; + } + return false; +} + static bool parseLayoutDirection(const char* name, ResTable_config* out) { if (strcmp(name, kWildcardName) == 0) { if (out) @@ -678,6 +696,13 @@ bool ConfigDescription::Parse(StringPiece str, ConfigDescription* out) { } } + if (parseGrammaticalInflection(*part_iter, &config)) { + ++part_iter; + if (part_iter == parts_end) { + goto success; + } + } + if (parseLayoutDirection(part_iter->c_str(), &config)) { ++part_iter; if (part_iter == parts_end) { @@ -832,11 +857,13 @@ bool ConfigDescription::Parse(StringPiece str, ConfigDescription* out) { void ConfigDescription::ApplyVersionForCompatibility( ConfigDescription* config) { uint16_t min_sdk = 0; - if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE) + if (config->grammaticalInflection != 0) { + min_sdk = SDK_U; + } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE) == ResTable_config::UI_MODE_TYPE_VR_HEADSET || config->colorMode & ResTable_config::MASK_WIDE_COLOR_GAMUT || config->colorMode & ResTable_config::MASK_HDR) { - min_sdk = SDK_O; + min_sdk = SDK_O; } else if (config->screenLayout2 & ResTable_config::MASK_SCREENROUND) { min_sdk = SDK_MARSHMALLOW; } else if (config->density == ResTable_config::DENSITY_ANY) { @@ -913,6 +940,7 @@ bool ConfigDescription::HasHigherPrecedenceThan( if (country[0] || o.country[0]) return (!o.country[0]); // Script and variant require either a language or country, both of which // have higher precedence. + if (grammaticalInflection || o.grammaticalInflection) return !o.grammaticalInflection; if ((screenLayout | o.screenLayout) & MASK_LAYOUTDIR) { return !(o.screenLayout & MASK_LAYOUTDIR); } @@ -971,6 +999,7 @@ bool ConfigDescription::ConflictsWith(const ConfigDescription& o) const { // The values here can be found in ResTable_config#match. Density and range // values can't lead to conflicts, and are ignored. return !pred(mcc, o.mcc) || !pred(mnc, o.mnc) || !pred(locale, o.locale) || + !pred(grammaticalInflection, o.grammaticalInflection) || !pred(screenLayout & MASK_LAYOUTDIR, o.screenLayout & MASK_LAYOUTDIR) || !pred(screenLayout & MASK_SCREENLONG, diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 1fed2067d16e5..29d33da6b2f70 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -2105,6 +2105,9 @@ int ResTable_config::compare(const ResTable_config& o) const { return 1; } + if (grammaticalInflection != o.grammaticalInflection) { + return grammaticalInflection < o.grammaticalInflection ? -1 : 1; + } if (screenType != o.screenType) { return (screenType > o.screenType) ? 1 : -1; } @@ -2153,7 +2156,9 @@ int ResTable_config::compareLogical(const ResTable_config& o) const { if (diff > 0) { return 1; } - + if (grammaticalInflection != o.grammaticalInflection) { + return grammaticalInflection < o.grammaticalInflection ? -1 : 1; + } if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) { return (screenLayout & MASK_LAYOUTDIR) < (o.screenLayout & MASK_LAYOUTDIR) ? -1 : 1; } @@ -2223,6 +2228,7 @@ int ResTable_config::diff(const ResTable_config& o) const { 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; + if (grammaticalInflection != o.grammaticalInflection) diffs |= CONFIG_GRAMMATICAL_GENDER; const int diff = compareLocales(*this, o); if (diff) diffs |= CONFIG_LOCALE; @@ -2289,6 +2295,13 @@ bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const { } } + if (grammaticalInflection || o.grammaticalInflection) { + if (grammaticalInflection != o.grammaticalInflection) { + if (!grammaticalInflection) return false; + if (!o.grammaticalInflection) return true; + } + } + if (screenLayout || o.screenLayout) { if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0) { if (!(screenLayout & MASK_LAYOUTDIR)) return false; @@ -2555,6 +2568,13 @@ bool ResTable_config::isBetterThan(const ResTable_config& o, return true; } + if (grammaticalInflection || o.grammaticalInflection) { + if (grammaticalInflection != o.grammaticalInflection + && requested->grammaticalInflection) { + return !!grammaticalInflection; + } + } + if (screenLayout || o.screenLayout) { if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0 && (requested->screenLayout & MASK_LAYOUTDIR)) { @@ -2854,6 +2874,10 @@ bool ResTable_config::match(const ResTable_config& settings) const { } } + if (grammaticalInflection && grammaticalInflection != settings.grammaticalInflection) { + return false; + } + if (screenConfig != 0) { const int layoutDir = screenLayout&MASK_LAYOUTDIR; const int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR; @@ -3267,6 +3291,15 @@ String8 ResTable_config::toString() const { appendDirLocale(res); + if ((grammaticalInflection & GRAMMATICAL_INFLECTION_GENDER_MASK) != 0) { + if (res.size() > 0) res.append("-"); + switch (grammaticalInflection & GRAMMATICAL_INFLECTION_GENDER_MASK) { + case GRAMMATICAL_GENDER_NEUTER: res.append("neuter"); break; + case GRAMMATICAL_GENDER_FEMININE: res.append("feminine"); break; + case GRAMMATICAL_GENDER_MASCULINE: res.append("masculine"); break; + } + } + if ((screenLayout&MASK_LAYOUTDIR) != 0) { if (res.size() > 0) res.append("-"); switch (screenLayout&ResTable_config::MASK_LAYOUTDIR) { diff --git a/libs/androidfw/include/androidfw/ConfigDescription.h b/libs/androidfw/include/androidfw/ConfigDescription.h index 71087cdfb6fa2..7fbd7c08ea694 100644 --- a/libs/androidfw/include/androidfw/ConfigDescription.h +++ b/libs/androidfw/include/androidfw/ConfigDescription.h @@ -53,6 +53,12 @@ enum : ApiVersion { SDK_O = 26, SDK_O_MR1 = 27, SDK_P = 28, + SDK_Q = 29, + SDK_R = 30, + SDK_S = 31, + SDK_S_V2 = 32, + SDK_TIRAMISU = 33, + SDK_U = 34, }; /* diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 52321dad8a5ad..631bda4f886c9 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1071,15 +1071,32 @@ struct ResTable_config NAVHIDDEN_NO = ACONFIGURATION_NAVHIDDEN_NO << SHIFT_NAVHIDDEN, NAVHIDDEN_YES = ACONFIGURATION_NAVHIDDEN_YES << SHIFT_NAVHIDDEN, }; - - union { - struct { - uint8_t keyboard; - uint8_t navigation; - uint8_t inputFlags; - uint8_t inputPad0; + + enum { + GRAMMATICAL_GENDER_ANY = ACONFIGURATION_GRAMMATICAL_GENDER_ANY, + GRAMMATICAL_GENDER_NEUTER = ACONFIGURATION_GRAMMATICAL_GENDER_NEUTER, + GRAMMATICAL_GENDER_FEMININE = ACONFIGURATION_GRAMMATICAL_GENDER_FEMININE, + GRAMMATICAL_GENDER_MASCULINE = ACONFIGURATION_GRAMMATICAL_GENDER_MASCULINE, + GRAMMATICAL_INFLECTION_GENDER_MASK = 0b11, + }; + + struct { + union { + struct { + uint8_t keyboard; + uint8_t navigation; + uint8_t inputFlags; + uint8_t inputFieldPad0; + }; + struct { + uint32_t input : 24; + uint32_t inputFullPad0 : 8; + }; + struct { + uint8_t grammaticalInflectionPad0[3]; + uint8_t grammaticalInflection; + }; }; - uint32_t input; }; enum { @@ -1263,6 +1280,7 @@ struct ResTable_config CONFIG_LAYOUTDIR = ACONFIGURATION_LAYOUTDIR, CONFIG_SCREEN_ROUND = ACONFIGURATION_SCREEN_ROUND, CONFIG_COLOR_MODE = ACONFIGURATION_COLOR_MODE, + CONFIG_GRAMMATICAL_GENDER = ACONFIGURATION_GRAMMATICAL_GENDER, }; // Compare two configuration, returning CONFIG_* flags set for each value diff --git a/libs/androidfw/tests/ConfigDescription_test.cpp b/libs/androidfw/tests/ConfigDescription_test.cpp index 8fed0a4d22fc1..f5c01e5d9b684 100644 --- a/libs/androidfw/tests/ConfigDescription_test.cpp +++ b/libs/androidfw/tests/ConfigDescription_test.cpp @@ -154,4 +154,22 @@ TEST(ConfigDescriptionTest, RangeQualifiersDoNotConflict) { EXPECT_FALSE(ParseConfigOrDie("600x400").ConflictsWith(ParseConfigOrDie("300x200"))); } +TEST(ConfigDescriptionTest, TestGrammaticalGenderQualifier) { + ConfigDescription config; + EXPECT_TRUE(TestParse("feminine", &config)); + EXPECT_EQ(android::ResTable_config::GRAMMATICAL_GENDER_FEMININE, config.grammaticalInflection); + EXPECT_EQ(SDK_U, config.sdkVersion); + EXPECT_EQ(std::string("feminine-v34"), config.toString().string()); + + EXPECT_TRUE(TestParse("masculine", &config)); + EXPECT_EQ(android::ResTable_config::GRAMMATICAL_GENDER_MASCULINE, config.grammaticalInflection); + EXPECT_EQ(SDK_U, config.sdkVersion); + EXPECT_EQ(std::string("masculine-v34"), config.toString().string()); + + EXPECT_TRUE(TestParse("neuter", &config)); + EXPECT_EQ(android::ResTable_config::GRAMMATICAL_GENDER_NEUTER, config.grammaticalInflection); + EXPECT_EQ(SDK_U, config.sdkVersion); + EXPECT_EQ(std::string("neuter-v34"), config.toString().string()); +} + } // namespace android diff --git a/libs/androidfw/tests/Config_test.cpp b/libs/androidfw/tests/Config_test.cpp index 698c36f093013..5477621ce9fd1 100644 --- a/libs/androidfw/tests/Config_test.cpp +++ b/libs/androidfw/tests/Config_test.cpp @@ -205,4 +205,18 @@ TEST(ConfigTest, ScreenIsHdr) { EXPECT_EQ(defaultConfig.diff(hdrConfig), ResTable_config::CONFIG_COLOR_MODE); } +TEST(ConfigTest, GrammaticalGender) { + ResTable_config defaultConfig = {}; + ResTable_config masculine = {}; + masculine.grammaticalInflection = ResTable_config::GRAMMATICAL_GENDER_MASCULINE; + + EXPECT_EQ(defaultConfig.diff(masculine), ResTable_config::CONFIG_GRAMMATICAL_GENDER); + + ResTable_config feminine = {}; + feminine.grammaticalInflection = ResTable_config::GRAMMATICAL_GENDER_FEMININE; + + EXPECT_EQ(defaultConfig.diff(feminine), ResTable_config::CONFIG_GRAMMATICAL_GENDER); + EXPECT_EQ(masculine.diff(feminine), ResTable_config::CONFIG_GRAMMATICAL_GENDER); +} + } // namespace android. diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp index 87fe9edb49c51..b50514d27bac2 100644 --- a/native/android/configuration.cpp +++ b/native/android/configuration.cpp @@ -234,6 +234,14 @@ void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value) { | ((value<grammaticalInflection; +} + +void AConfiguration_setGrammaticalGender(AConfiguration* config, int32_t value) { + config->grammaticalInflection = value & ResTable_config::GRAMMATICAL_INFLECTION_GENDER_MASK; +} + // ---------------------------------------------------------------------- int32_t AConfiguration_diff(AConfiguration* config1, AConfiguration* config2) { diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index e89c8c9aa5839..e4b9b5dc6157d 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -42,6 +42,7 @@ LIBANDROID { AConfiguration_fromAssetManager; AConfiguration_getCountry; AConfiguration_getDensity; + AConfiguration_getGrammaticalGender; # introduced=UpsideDownCake AConfiguration_getKeyboard; AConfiguration_getKeysHidden; AConfiguration_getLanguage; @@ -66,6 +67,7 @@ LIBANDROID { AConfiguration_new; AConfiguration_setCountry; AConfiguration_setDensity; + AConfiguration_setGrammaticalGender; # introduced=UpsideDownCake AConfiguration_setKeyboard; AConfiguration_setKeysHidden; AConfiguration_setLanguage; diff --git a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java b/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java index 2bd7cf8481964..a2177e87bcdb9 100644 --- a/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java +++ b/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java @@ -82,7 +82,7 @@ public AssetManager getBaseAssetManager() throws IllegalArgumentException { } AssetManager assets = new AssetManager(); - assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); assets.setApkAssets(apkAssets, false /*invalidateCaches*/); diff --git a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java b/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java index ae42e0980fb71..1a8c199608dfb 100644 --- a/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java +++ b/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java @@ -80,7 +80,7 @@ private static ApkAssets loadApkAssets(String path, @ParseFlags int flags) private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) { final AssetManager assets = new AssetManager(); - assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); assets.setApkAssets(apkAssets, false /*invalidateCaches*/); return assets; diff --git a/tools/aapt2/Configuration.proto b/tools/aapt2/Configuration.proto index 8a4644c9a2192..48838445f8c14 100644 --- a/tools/aapt2/Configuration.proto +++ b/tools/aapt2/Configuration.proto @@ -120,6 +120,13 @@ message Configuration { NAVIGATION_WHEEL = 4; } + enum GrammaticalGender { + GRAM_GENDER_USET = 0; + GRAM_GENDER_NEUTER = 1; + GRAM_GENDER_FEMININE = 2; + GRAM_GENDER_MASCULINE = 3; + } + // // Axis/dimensions that are understood by the runtime. // @@ -198,6 +205,9 @@ message Configuration { // The minimum SDK version of the device. uint32 sdk_version = 24; + // Grammatical gender. + GrammaticalGender grammatical_gender = 26; + // // Build-time only dimensions. // diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index e39f327cee9f4..09ef9bddd3bdb 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -354,6 +354,7 @@ bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescripti out_config->screenWidth = static_cast(pb_config.screen_width()); out_config->screenHeight = static_cast(pb_config.screen_height()); out_config->sdkVersion = static_cast(pb_config.sdk_version()); + out_config->grammaticalInflection = pb_config.grammatical_gender(); return true; } diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index 0e40124aa79e0..0903205b5eb21 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -275,6 +275,10 @@ void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_ } out_pb_config->set_sdk_version(config.sdkVersion); + + // The constant values are the same across the structs. + out_pb_config->set_grammatical_gender( + static_cast(config.grammaticalInflection)); } static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item, diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp index ecfdba83a2e8a..afb83562b1290 100644 --- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp @@ -581,9 +581,13 @@ TEST(ProtoSerializeTest, SerializeDeserializeConfiguration) { ExpectConfigSerializes("v8"); + ExpectConfigSerializes("en-feminine"); + ExpectConfigSerializes("en-neuter-v34"); + ExpectConfigSerializes("feminine-v34"); + ExpectConfigSerializes( - "mcc123-mnc456-b+en+GB-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-land-car-" - "night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23"); + "mcc123-mnc456-b+en+GB-masculine-ldltr-sw300dp-w300dp-h400dp-large-long-round-widecg-highdr-" + "land-car-night-xhdpi-stylus-keysexposed-qwerty-navhidden-dpad-300x200-v23"); } TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h index f03d6fcd03f1e..098535d8526f2 100644 --- a/tools/aapt2/test/Builders.h +++ b/tools/aapt2/test/Builders.h @@ -251,7 +251,11 @@ class ConfigDescriptionBuilder { return *this; } ConfigDescriptionBuilder& setInputPad0(uint8_t inputPad0) { - config_.inputPad0 = inputPad0; + config_.inputFieldPad0 = inputPad0; + return *this; + } + ConfigDescriptionBuilder& setGrammaticalInflection(uint8_t value) { + config_.grammaticalInflection = value; return *this; } ConfigDescriptionBuilder& setScreenWidth(uint16_t screenWidth) {