[res] Add the grammatical gender qualifier
Bug: 237579711
Test: UTs + build + boot
Change-Id: Id0919799a8a364f109ff351974f02e4f151f23cd
diff --git a/core/api/current.txt b/core/api/current.txt
index 24b985d..ece3f8e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -12984,9 +12984,9 @@
field @NonNull public static final android.os.Parcelable.Creator<android.content.res.Configuration> 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 a9f55bc..adcd186 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -998,6 +998,7 @@
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 @@
* {@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 c15b3e0..048289f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1456,7 +1456,7 @@
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 @@
}
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 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 c8bbb0c1..dfc7b464 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -1461,13 +1461,14 @@
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 @@
@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<String> 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 96aa624..0def59f 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 @@
* Constant for grammatical gender: to indicate the terms of address the user
* preferred in an application is neuter.
*/
- public static final int GRAMMATICAL_GENDER_NEUTRAL = 2;
+ public static final int GRAMMATICAL_GENDER_NEUTRAL = 1;
/**
* Constant for grammatical gender: to indicate the terms of address the user
* preferred in an application is feminine.
*/
- public static final int GRAMMATICAL_GENDER_FEMININE = 3;
+ public static final int GRAMMATICAL_GENDER_FEMININE = 2;
/**
* Constant for grammatical gender: to indicate the terms of address the user
* preferred in an application is masculine.
*/
- public static final int GRAMMATICAL_GENDER_MASCULINE = 4;
+ public static final int GRAMMATICAL_GENDER_MASCULINE = 3;
/** Constant for {@link #colorMode}: bits that encode whether the screen is wide gamut. */
public static final int COLOR_MODE_WIDE_COLOR_GAMUT_MASK = 0x3;
@@ -529,15 +530,10 @@
if ((diff & ActivityInfo.CONFIG_FONT_WEIGHT_ADJUSTMENT) != 0) {
list.add("CONFIG_AUTO_BOLD_TEXT");
}
- StringBuilder builder = new StringBuilder("{");
- for (int i = 0, n = list.size(); i < n; i++) {
- builder.append(list.get(i));
- if (i != n - 1) {
- builder.append(", ");
- }
+ if ((diff & ActivityInfo.CONFIG_GRAMMATICAL_GENDER) != 0) {
+ list.add("CONFIG_GRAMMATICAL_GENDER");
}
- builder.append("}");
- return builder.toString();
+ return "{" + TextUtils.join(", ", list) + "}";
}
/**
@@ -970,6 +966,7 @@
NATIVE_CONFIG_SMALLEST_SCREEN_SIZE,
NATIVE_CONFIG_LAYOUTDIR,
NATIVE_CONFIG_COLOR_MODE,
+ NATIVE_CONFIG_GRAMMATICAL_GENDER,
})
@Retention(RetentionPolicy.SOURCE)
public @interface NativeConfig {}
@@ -1008,6 +1005,9 @@
public static final int NATIVE_CONFIG_LAYOUTDIR = 0x4000;
/** @hide Native-specific bit mask for COLOR_MODE config ; DO NOT USE UNLESS YOU ARE SURE.*/
public static final int NATIVE_CONFIG_COLOR_MODE = 0x10000;
+ /** @hide Native-specific bit mask for GRAMMATICAL_GENDER config; DO NOT USE UNLESS YOU
+ * ARE SURE.*/
+ public static final int NATIVE_CONFIG_GRAMMATICAL_GENDER = 0x20000;
/**
* <p>Construct an invalid Configuration. This state is only suitable for constructing a
@@ -1112,6 +1112,14 @@
} 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
+ 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 @@
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 @@
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 @@
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 c2b3769..2170886 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -466,7 +466,8 @@
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 b60ec9f..9e92542 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -324,7 +324,7 @@
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 @@
configuration.screenLayout = static_cast<uint8_t>(screen_layout);
configuration.uiMode = static_cast<uint8_t>(ui_mode);
configuration.colorMode = static_cast<uint8_t>(color_mode);
+ configuration.grammaticalInflection = static_cast<uint8_t>(grammatical_gender);
configuration.sdkVersion = static_cast<uint16_t>(major_version);
if (locale != nullptr) {
@@ -1448,7 +1449,7 @@
{"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 b1ffe38..0e2234f 100644
--- a/core/proto/android/content/configuration.proto
+++ b/core/proto/android/content/configuration.proto
@@ -50,6 +50,7 @@
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 93a7d17..cf2fd6f 100644
--- a/libs/androidfw/ConfigDescription.cpp
+++ b/libs/androidfw/ConfigDescription.cpp
@@ -21,6 +21,7 @@
#include "androidfw/Util.h"
#include <string>
+#include <string_view>
#include <vector>
namespace android {
@@ -38,11 +39,11 @@
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 @@
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 @@
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 @@
}
}
+ 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 @@
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 @@
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 @@
// 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 1fed206..29d33da 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -2105,6 +2105,9 @@
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 @@
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 @@
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 @@
}
}
+ 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 @@
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 @@
}
}
+ 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 @@
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 71087cd..7fbd7c0 100644
--- a/libs/androidfw/include/androidfw/ConfigDescription.h
+++ b/libs/androidfw/include/androidfw/ConfigDescription.h
@@ -53,6 +53,12 @@
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 52321da..631bda4 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1071,15 +1071,32 @@
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 @@
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 8fed0a4..f5c01e5 100644
--- a/libs/androidfw/tests/ConfigDescription_test.cpp
+++ b/libs/androidfw/tests/ConfigDescription_test.cpp
@@ -154,4 +154,22 @@
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 698c36f..5477621 100644
--- a/libs/androidfw/tests/Config_test.cpp
+++ b/libs/androidfw/tests/Config_test.cpp
@@ -205,4 +205,18 @@
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 87fe9ed..b50514d 100644
--- a/native/android/configuration.cpp
+++ b/native/android/configuration.cpp
@@ -234,6 +234,14 @@
| ((value<<ResTable_config::SHIFT_LAYOUTDIR)&ResTable_config::MASK_LAYOUTDIR);
}
+int32_t AConfiguration_getGrammaticalGender(AConfiguration* config) {
+ return config->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 e89c8c9..e4b9b5d 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -42,6 +42,7 @@
AConfiguration_fromAssetManager;
AConfiguration_getCountry;
AConfiguration_getDensity;
+ AConfiguration_getGrammaticalGender; # introduced=UpsideDownCake
AConfiguration_getKeyboard;
AConfiguration_getKeysHidden;
AConfiguration_getLanguage;
@@ -66,6 +67,7 @@
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 2bd7cf8..a2177e8 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 @@
}
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 ae42e09..1a8c1996 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 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 8a4644c..4883844 100644
--- a/tools/aapt2/Configuration.proto
+++ b/tools/aapt2/Configuration.proto
@@ -120,6 +120,13 @@
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 @@
// 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 e39f327..09ef9bd 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -354,6 +354,7 @@
out_config->screenWidth = static_cast<uint16_t>(pb_config.screen_width());
out_config->screenHeight = static_cast<uint16_t>(pb_config.screen_height());
out_config->sdkVersion = static_cast<uint16_t>(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 0e40124..0903205 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -275,6 +275,10 @@
}
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<pb::Configuration_GrammaticalGender>(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 ecfdba8..afb8356 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -581,9 +581,13 @@
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 f03d6fc..098535d 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -251,7 +251,11 @@
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) {