Bug 1045053 - Part 1: set intl.accept_languages from Android OS/app locale. r=bnicholson

This commit is contained in:
Richard Newman 2014-10-01 18:09:42 -07:00
Родитель 226fc0d222
Коммит 1018f86fc9
3 изменённых файлов: 146 добавлений и 11 удалений

Просмотреть файл

@ -248,6 +248,37 @@ public class BrowserLocaleManager implements LocaleManager {
return changed;
}
/**
* Gecko needs to know the OS locale to compute a useful Accept-Language
* header. If it changed since last time, send a message to Gecko and
* persist the new value. If unchanged, returns immediately.
*
* @param prefs the SharedPreferences instance to use. Cannot be null.
* @param osLocale the new locale instance. Safe if null.
*/
public static void storeAndNotifyOSLocale(final SharedPreferences prefs,
final Locale osLocale) {
if (osLocale == null) {
return;
}
final String lastOSLocale = prefs.getString("osLocale", null);
final String osLocaleString = osLocale.toString();
if (osLocaleString.equals(lastOSLocale)) {
return;
}
// Store the Java-native form.
prefs.edit().putString("osLocale", osLocaleString).apply();
// The value we send to Gecko should be a language tag, not
// a Java locale string.
final String osLanguageTag = BrowserLocaleManager.getLanguageTag(osLocale);
final GeckoEvent localeOSEvent = GeckoEvent.createBroadcastEvent("Locale:OS", osLanguageTag);
GeckoAppShell.sendEventToGecko(localeOSEvent);
}
@Override
public String getAndApplyPersistedLocale(Context context) {
initialize(context);

Просмотреть файл

@ -9,7 +9,6 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
@ -45,7 +44,6 @@ import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.preferences.ClearOnShutdownPref;
import org.mozilla.gecko.preferences.GeckoPreferences;
import org.mozilla.gecko.prompts.PromptService;
import org.mozilla.gecko.SmsManager;
import org.mozilla.gecko.updater.UpdateService;
import org.mozilla.gecko.updater.UpdateServiceHelper;
import org.mozilla.gecko.util.ActivityResultHandler;
@ -1207,6 +1205,9 @@ public abstract class GeckoApp
// the UI.
// This is using a sledgehammer to crack a nut, but it'll do for
// now.
// Our OS locale pref will be detected as invalid after the
// restart, and will be propagated to Gecko accordingly, so there's
// no need to touch that here.
if (BrowserLocaleManager.getInstance().systemLocaleDidChange()) {
Log.i(LOGTAG, "System locale changed. Restarting.");
doRestart();
@ -1317,29 +1318,36 @@ public abstract class GeckoApp
final String profilePath = getProfile().getDir().getAbsolutePath();
final EventDispatcher dispatcher = EventDispatcher.getInstance();
// Both of these are Java-format locale strings: "en_US", not "en-US".
final String osLocale = Locale.getDefault().toString();
String appLocale = localeManager.getAndApplyPersistedLocale(GeckoApp.this);
Log.d(LOGTAG, "OS locale is " + osLocale + ", app locale is " + appLocale);
// This is the locale prior to fixing it up.
final Locale osLocale = Locale.getDefault();
if (appLocale == null) {
appLocale = osLocale;
// Both of these are Java-format locale strings: "en_US", not "en-US".
final String osLocaleString = osLocale.toString();
String appLocaleString = localeManager.getAndApplyPersistedLocale(GeckoApp.this);
Log.d(LOGTAG, "OS locale is " + osLocaleString + ", app locale is " + appLocaleString);
if (appLocaleString == null) {
appLocaleString = osLocaleString;
}
mHealthRecorder = GeckoApp.this.createHealthRecorder(GeckoApp.this,
profilePath,
dispatcher,
osLocale,
appLocale,
osLocaleString,
appLocaleString,
previousSession);
final String uiLocale = appLocale;
final String uiLocale = appLocaleString;
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
GeckoApp.this.onLocaleReady(uiLocale);
}
});
// We use per-profile prefs here, because we're tracking against
// a Gecko pref. The same applies to the locale switcher!
BrowserLocaleManager.storeAndNotifyOSLocale(GeckoSharedPrefs.forProfile(GeckoApp.this), osLocale);
}
});

Просмотреть файл

@ -342,6 +342,7 @@ var BrowserApp = {
Services.androidBridge.browserApp = this;
Services.obs.addObserver(this, "Locale:OS", false);
Services.obs.addObserver(this, "Locale:Changed", false);
Services.obs.addObserver(this, "Tab:Load", false);
Services.obs.addObserver(this, "Tab:Selected", false);
@ -1771,6 +1772,34 @@ var BrowserApp = {
WebappManager.autoUninstall(JSON.parse(aData));
break;
case "Locale:OS":
// We know the system locale. We use this for generating Accept-Language headers.
console.log("Locale:OS: " + aData);
let currentOSLocale;
try {
currentOSLocale = Services.prefs.getCharPref("intl.locale.os");
} catch (e) {
}
if (currentOSLocale == aData) {
break;
}
console.log("New OS locale.");
// Ensure that this choice is immediately persisted, because
// Gecko won't be told again if it forgets.
Services.prefs.setCharPref("intl.locale.os", aData);
Services.prefs.savePrefFile(null);
let appLocale;
try {
appLocale = Services.prefs.getCharPref("general.useragent.locale");
} catch (e) {
}
this.computeAcceptLanguages(aData, appLocale);
break;
case "Locale:Changed":
if (aData) {
// The value provided to Locale:Changed should be a BCP47 language tag
@ -1792,6 +1821,16 @@ var BrowserApp = {
// Blow away the string cache so that future lookups get the
// correct locale.
Services.strings.flushBundles();
// Make sure we use the right Accept-Language header.
let osLocale;
try {
// This should never not be set at this point, but better safe than sorry.
osLocale = Services.prefs.getCharPref("intl.locale.os");
} catch (e) {
}
this.computeAcceptLanguages(osLocale, aData);
break;
default:
@ -1801,6 +1840,63 @@ var BrowserApp = {
}
},
/**
* Set intl.accept_languages accordingly.
*
* After Bug 881510 this will also accept a real Accept-Language choice as
* input; all Accept-Language logic lives here.
*
* osLocale should never be null, but this method is safe regardless.
* appLocale may explicitly be null.
*/
computeAcceptLanguages(osLocale, appLocale) {
let defaultBranch = Services.prefs.getDefaultBranch(null);
let defaultAccept = defaultBranch.getComplexValue("intl.accept_languages", Ci.nsIPrefLocalizedString).data;
console.log("Default intl.accept_languages = " + defaultAccept);
// A guard for potential breakage. Bug 438031.
// This should not be necessary, because we're reading from the default branch,
// but better safe than sorry.
if (defaultAccept && defaultAccept.startsWith("chrome://")) {
defaultAccept = null;
} else {
// Ensure lowercase everywhere so we can compare.
defaultAccept = defaultAccept.toLowerCase();
}
if (appLocale) {
appLocale = appLocale.toLowerCase();
}
if (osLocale) {
osLocale = osLocale.toLowerCase();
}
// Eliminate values if they're present in the default.
let chosen;
if (defaultAccept) {
// intl.accept_languages is a comma-separated list, with no q-value params. Those
// are added when the header is generated.
chosen = defaultAccept.split(",")
.map(String.trim)
.filter((x) => (x != appLocale && x != osLocale));
} else {
chosen = [];
}
if (osLocale) {
chosen.unshift(osLocale);
}
if (appLocale && appLocale != osLocale) {
chosen.unshift(appLocale);
}
let result = chosen.join(",");
console.log("Setting intl.accept_languages to " + result);
Services.prefs.setCharPref("intl.accept_languages", result);
},
get defaultBrowserWidth() {
delete this.defaultBrowserWidth;
let width = Services.prefs.getIntPref("browser.viewport.desktopWidth");