Bug 1437942 - Bundle all search engines with Firefox.
MozReview-Commit-ID: 2fS6erC93o9
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -62,16 +62,17 @@
</content>
<implementation implements="nsIObserver">
<constructor><![CDATA[
if (this.parentNode.parentNode.localName == "toolbarpaletteitem")
return;
Services.obs.addObserver(this, "browser-search-engine-modified");
+ Services.obs.addObserver(this, "browser-search-service");
this._initialized = true;
(window.delayedStartupPromise || Promise.resolve()).then(() => {
window.requestIdleCallback(() => {
Services.search.init(aStatus => {
// Bail out if the binding's been destroyed
if (!this._initialized)
@@ -109,16 +110,17 @@
]]></destructor>
<method name="destroy">
<body><![CDATA[
if (this._initialized) {
this._initialized = false;
Services.obs.removeObserver(this, "browser-search-engine-modified");
+ Services.obs.removeObserver(this, "browser-search-service");
}
// Make sure to break the cycle from _textbox to us. Otherwise we leak
// the world. But make sure it's actually pointing to us.
// Also make sure the textbox has ever been constructed, otherwise the
// _textbox getter will cause the textbox constructor to run, add an
// observer, and leak the world too.
if (this._textboxInitialized && this._textbox.mController.input == this)
@@ -178,17 +180,18 @@
]]></body>
</method>
<method name="observe">
<parameter name="aEngine"/>
<parameter name="aTopic"/>
<parameter name="aVerb"/>
<body><![CDATA[
- if (aTopic == "browser-search-engine-modified") {
+ if (aTopic == "browser-search-engine-modified" ||
+ (aTopic == "browser-search-service" && aVerb == "init-complete")) {
// Make sure the engine list is refetched next time it's needed
this._engines = null;
// Update the popup header and update the display after any modification.
this._textbox.popup.updateHeader();
this.updateDisplay();
}
]]></body>
@@ -1301,16 +1304,17 @@
menu.addEventListener("popuphidden", aEvent => {
this._ignoreMouseEvents = false;
aEvent.stopPropagation();
});
// Add weak referenced observers to invalidate our cached list of engines.
Services.prefs.addObserver("browser.search.hiddenOneOffs", this, true);
Services.obs.addObserver(this, "browser-search-engine-modified", true);
+ Services.obs.addObserver(this, "browser-search-service", true);
// Rebuild the buttons when the theme changes. See bug 1357800 for
// details. Summary: On Linux, switching between themes can cause a row
// of buttons to disappear.
Services.obs.addObserver(this, "lightweight-theme-changed", true);
]]></constructor>
<!-- This handles events outside the one-off buttons, like on the popup
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -56,19 +56,17 @@ libs:: searchplugins
# Required for l10n.mk - defines a list of app sub dirs that should
# be included in langpack xpis.
DIST_SUBDIRS = $(DIST_SUBDIR)
include $(topsrcdir)/config/rules.mk
include $(topsrcdir)/toolkit/locales/l10n.mk
-$(list-json): $(call mkdir_deps,$(SEARCHPLUGINS_PATH)) $(if $(IS_LANGUAGE_REPACK),FORCE)
- $(call py_action,generate_searchjson,$(srcdir)/search/list.json $(AB_CD) $(list-json))
-searchplugins:: $(list-json)
+searchplugins:: $(srcdir)/search/list.json
DEFINES += -DBOOKMARKS_INCLUDE_DIR=$(dir $(call MERGE_FILE,profile/bookmarks.inc))
libs-%: AB_CD=$*
libs-%:
$(if $(filter en-US,$(AB_CD)),, @$(MAKE) merge-$*)
$(NSINSTALL) -D $(DIST)/install
@$(MAKE) -C ../../toolkit/locales libs-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)'
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -55,23 +55,18 @@
locale/browser/feeds/subscribe.dtd (%chrome/browser/feeds/subscribe.dtd)
locale/browser/feeds/subscribe.properties (%chrome/browser/feeds/subscribe.properties)
locale/browser/migration/migration.dtd (%chrome/browser/migration/migration.dtd)
locale/browser/migration/migration.properties (%chrome/browser/migration/migration.properties)
locale/browser/preferences/preferences.properties (%chrome/browser/preferences/preferences.properties)
locale/browser/preferences/security.dtd (%chrome/browser/preferences/security.dtd)
locale/browser/syncBrand.dtd (%chrome/browser/syncBrand.dtd)
locale/browser/syncSetup.properties (%chrome/browser/syncSetup.properties)
-#if BUILD_FASTER
locale/browser/searchplugins/ (searchplugins/*.xml)
locale/browser/searchplugins/list.json (search/list.json)
-#else
- locale/browser/searchplugins/ (.deps/generated_@AB_CD@/*.xml)
- locale/browser/searchplugins/list.json (.deps/generated_@AB_CD@/list.json)
-#endif
locale/browser/searchplugins/images/amazon.ico (searchplugins/images/amazon.ico)
locale/browser/searchplugins/images/ebay.ico (searchplugins/images/ebay.ico)
locale/browser/searchplugins/images/wikipedia.ico (searchplugins/images/wikipedia.ico)
locale/browser/searchplugins/images/yandex-en.ico (searchplugins/images/yandex-en.ico)
locale/browser/searchplugins/images/yandex-ru.ico (searchplugins/images/yandex-ru.ico)
% locale browser-region @AB_CD@ %locale/browser-region/
locale/browser-region/region.properties (%chrome/browser-region/region.properties)
# the following files are browser-specific overrides
--- a/browser/modules/ContentSearch.jsm
+++ b/browser/modules/ContentSearch.jsm
@@ -102,16 +102,17 @@ var ContentSearch = {
_destroyedPromise: null,
// The current controller and browser in _onMessageGetSuggestions. Allows
// fetch cancellation from _cancelSuggestions.
_currentSuggestion: null,
init() {
Services.obs.addObserver(this, "browser-search-engine-modified");
+ Services.obs.addObserver(this, "browser-search-service");
Services.obs.addObserver(this, "shutdown-leaks-before-check");
Services.prefs.addObserver("browser.search.hiddenOneOffs", this);
this._stringBundle = Services.strings.createBundle("chrome://global/locale/autocomplete.properties");
},
get searchSuggestionUIStrings() {
if (this._searchSuggestionUIStrings) {
return this._searchSuggestionUIStrings;
@@ -128,16 +129,17 @@ var ContentSearch = {
},
destroy() {
if (this._destroyedPromise) {
return this._destroyedPromise;
}
Services.obs.removeObserver(this, "browser-search-engine-modified");
+ Services.obs.removeObserver(this, "browser-search-service");
Services.obs.removeObserver(this, "shutdown-leaks-before-check");
this._eventQueue.length = 0;
this._destroyedPromise = Promise.resolve(this._currentEventPromise);
return this._destroyedPromise;
},
/**
@@ -187,16 +189,25 @@ var ContentSearch = {
case "nsPref:changed":
case "browser-search-engine-modified":
this._eventQueue.push({
type: "Observe",
data,
});
this._processEventQueue();
break;
+ case "browser-search-service":
+ if (data == "init-complete") {
+ this._eventQueue.push({
+ type: "Observe",
+ data,
+ });
+ this._processEventQueue();
+ }
+ break;
case "shutdown-leaks-before-check":
subj.wrappedJSObject.client.addBlocker(
"ContentSearch: Wait until the service is destroyed", () => this.destroy());
break;
}
},
removeFormHistoryEntry(msg, entry) {
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -51,16 +51,17 @@ const NS_APP_USER_PROFILE_50_DIR = "Prof
// We load plugins from APP_SEARCH_PREFIX, where a list.txt
// file needs to exist to list available engines.
const APP_SEARCH_PREFIX = "resource://search-plugins/";
// See documentation in nsIBrowserSearchService.idl.
const SEARCH_ENGINE_TOPIC = "browser-search-engine-modified";
const REQ_LOCALES_CHANGED_TOPIC = "intl:requested-locales-changed";
+const TOPIC_LOCALES_CHANGE = "intl:app-locales-changed";
const QUIT_APPLICATION_TOPIC = "quit-application";
const SEARCH_ENGINE_REMOVED = "engine-removed";
const SEARCH_ENGINE_ADDED = "engine-added";
const SEARCH_ENGINE_CHANGED = "engine-changed";
const SEARCH_ENGINE_LOADED = "engine-loaded";
const SEARCH_ENGINE_CURRENT = "engine-current";
const SEARCH_ENGINE_DEFAULT = "engine-default";
@@ -2998,19 +2999,19 @@ SearchService.prototype = {
await ensureKnownCountryCode(this);
// Due to the HTTP requests done by ensureKnownCountryCode, it's possible that
// at this point a synchronous init has been forced by other code.
if (!gInitialized)
await this._asyncLoadEngines(cache);
// Typically we'll re-init as a result of a pref observer,
// so signal to 'callers' that we're done.
+ gInitialized = true;
Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "init-complete");
this._recordEngineTelemetry();
- gInitialized = true;
} catch (err) {
LOG("Reinit failed: " + err);
Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "reinit-failed");
} finally {
Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "reinit-complete");
}
})();
},
@@ -3411,24 +3412,35 @@ SearchService.prototype = {
this._parseListTxt(list, uris);
} else {
this._parseListJSON(list, uris);
}
return uris;
},
_parseListJSON: function SRCH_SVC_parseListJSON(list, uris) {
- let searchSettings;
+ let json;
try {
- searchSettings = JSON.parse(list);
+ json = JSON.parse(list);
} catch (e) {
LOG("failing to parse list.json: " + e);
return;
}
+ let searchSettings;
+ let locale = Services.locale.getAppLocaleAsBCP47();
+ if ("locales" in json &&
+ locale in json.locales) {
+ searchSettings = json.locales[locale];
+ } else {
+ // json.default should always be there.
+ // Should we assert?
+ searchSettings = json;
+ }
+
// Check if we have a useable country specific list of visible default engines.
// This will only be set if we got the list from the Mozilla search server;
// it will not be set for distributions.
let engineNames;
let visibleDefaultEngines = this.getVerifiedGlobalAttr("visibleDefaultEngines");
if (visibleDefaultEngines) {
let jarNames = new Set();
for (let region in searchSettings) {
@@ -3470,48 +3482,62 @@ SearchService.prototype = {
"visibleDefaultEngines" in searchSettings[searchRegion]) {
engineNames = searchSettings[searchRegion].visibleDefaultEngines;
} else {
engineNames = searchSettings.default.visibleDefaultEngines;
}
}
// Remove any engine names that are supposed to be ignored.
- // This pref is only allows in a partner distribution.
+ // This pref is only allowed in a partner distribution.
let branch = Services.prefs.getDefaultBranch(BROWSER_SEARCH_PREF);
if (isPartnerBuild() &&
branch.getPrefType("ignoredJAREngines") == branch.PREF_STRING) {
let ignoredJAREngines = branch.getCharPref("ignoredJAREngines")
.split(",");
let filteredEngineNames = engineNames.filter(e => !ignoredJAREngines.includes(e));
// Don't allow all engines to be hidden
if (filteredEngineNames.length > 0) {
engineNames = filteredEngineNames;
}
}
+ if ("regionOverrides" in json &&
+ searchRegion in json.regionOverrides) {
+ for (let engine in json.regionOverrides[searchRegion]) {
+ let index = engineNames.indexOf(engine);
+ if (index > -1) {
+ engineNames[index] = json.regionOverrides[searchRegion][engine];
+ }
+ }
+ }
+
for (let name of engineNames) {
uris.push(APP_SEARCH_PREFIX + name + ".xml");
}
// Store this so that it can be used while writing the cache file.
this._visibleDefaultEngines = engineNames;
if (searchRegion && searchRegion in searchSettings &&
"searchDefault" in searchSettings[searchRegion]) {
this._searchDefault = searchSettings[searchRegion].searchDefault;
- } else {
+ } else if ("searchDefault" in searchSettings.default) {
this._searchDefault = searchSettings.default.searchDefault;
+ } else if ("searchDefault" in json.default) {
+ this._searchDefault = json.default.searchDefault;
}
if (searchRegion && searchRegion in searchSettings &&
"searchOrder" in searchSettings[searchRegion]) {
this._searchOrder = searchSettings[searchRegion].searchOrder;
} else if ("searchOrder" in searchSettings.default) {
this._searchOrder = searchSettings.default.searchOrder;
+ } else if ("searchOrder" in json.default) {
+ this._searchOrder = json.default.searchOrder;
}
},
_parseListTxt: function SRCH_SVC_parseListTxt(list, uris) {
let names = list.split("\n").filter(n => !!n);
// This maps the names of our built-in engines to a boolean
// indicating whether it should be hidden by default.
let jarNames = new Map();
@@ -4481,16 +4507,17 @@ SearchService.prototype = {
}
break;
case QUIT_APPLICATION_TOPIC:
this._removeObservers();
break;
case REQ_LOCALES_CHANGED_TOPIC:
+ case TOPIC_LOCALES_CHANGE:
// Locale changed. Re-init. We rely on observers, because we can't
// return this promise to anyone.
this._asyncReInit();
break;
}
},
// nsITimerCallback
@@ -4541,16 +4568,17 @@ SearchService.prototype = {
this._observersAdded = true;
Services.obs.addObserver(this, SEARCH_ENGINE_TOPIC);
Services.obs.addObserver(this, QUIT_APPLICATION_TOPIC);
if (AppConstants.MOZ_BUILD_APP == "mobile/android") {
Services.obs.addObserver(this, REQ_LOCALES_CHANGED_TOPIC);
}
+ Services.obs.addObserver(this, TOPIC_LOCALES_CHANGE);
// The current stage of shutdown. Used to help analyze crash
// signatures in case of shutdown timeout.
let shutdownState = {
step: "Not started",
latestError: {
message: undefined,
stack: undefined