Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4de4596a authored by Roozbeh Pournader's avatar Roozbeh Pournader
Browse files

Fix locale matching algorithm for resources

We get ResTables two different ways: one is from AAPT, another from
settings-based requests from the Java side. In the settings-based
requests, localeScript will be autocomputed, but for AAPT-filled
tables (especially if they come from older versions of AAPT), we need
to compute the script.

Previously, locales that came from packages were incorrectly assumed
to have "undeterminable" scripts, rather than "undetermined" scripts.
This led to us mistakenly falling back to the old logic of requiring
the locales' countries to match, rather than just looking at computed
scripts.

Bug: 27157452

Change-Id: Id7e346d3ecfb17273ffb63de5bcb4849a6eafbbd
parent 7f036f8b
Loading
Loading
Loading
Loading
+23 −6
Original line number Diff line number Diff line
@@ -2236,7 +2236,7 @@ bool ResTable_config::isLocaleBetterThan(const ResTable_config& o,
    // See if any of the regions is better than the other
    const int region_comparison = localeDataCompareRegions(
            country, o.country,
            language, localeScript, requested->country);
            language, requested->localeScript, requested->country);
    if (region_comparison != 0) {
        return (region_comparison > 0);
    }
@@ -2526,17 +2526,34 @@ bool ResTable_config::match(const ResTable_config& settings) const {

        // For backward compatibility and supporting private-use locales, we
        // fall back to old behavior if we couldn't determine the script for
        // either of the desired locale or the provided locale.
        if (localeScript[0] == '\0' || localeScript[1] == '\0') {
        // either of the desired locale or the provided locale. But if we could determine
        // the scripts, they should be the same for the locales to match.
        bool countriesMustMatch = false;
        char computed_script[4];
        const char* script;
        if (settings.localeScript[0] == '\0') { // could not determine the request's script
            countriesMustMatch = true;
        } else {
            if (localeScript[0] == '\0') { // script was not provided, so we try to compute it
                localeDataComputeScript(computed_script, language, country);
                if (computed_script[0] == '\0') { // we could not compute the script
                    countriesMustMatch = true;
                } else {
                    script = computed_script;
                }
            } else { // script was provided, so just use it
                script = localeScript;
            }
        }

        if (countriesMustMatch) {
            if (country[0] != '\0'
                && (country[0] != settings.country[0]
                    || country[1] != settings.country[1])) {
                return false;
            }
        } else {
            // But if we could determine the scripts, they should be the same
            // for the locales to match.
            if (memcmp(localeScript, settings.localeScript, sizeof(localeScript)) != 0) {
            if (memcmp(script, settings.localeScript, sizeof(settings.localeScript)) != 0) {
                return false;
            }
        }
+13 −0
Original line number Diff line number Diff line
@@ -371,6 +371,19 @@ TEST(ConfigLocaleTest, match) {
    EXPECT_TRUE(supported.match(requested));
}

TEST(ConfigLocaleTest, match_emptyScript) {
    ResTable_config supported, requested;

    fillIn("fr", "FR", NULL, NULL, &supported);
    fillIn("fr", "CA", NULL, NULL, &requested);

    // emulate packages built with older AAPT
    memset(supported.localeScript, '\0', 4);
    supported.localeScriptWasProvided = false;

    EXPECT_TRUE(supported.match(requested));
}

TEST(ConfigLocaleTest, isLocaleBetterThan_basics) {
    ResTable_config config1, config2, request;