From 389e436044838c6ad51e7fb47436b2d8318636d7 Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Mon, 29 Sep 2014 20:56:20 -0700 Subject: [PATCH] Bug 1065891 - (Part 2) Update the search activity default engine when the gecko default search engine changes. r=bnicholson --- mobile/android/chrome/content/browser.js | 46 ++++++++++++++++++- .../search/providers/SearchEngineManager.java | 26 +++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 8e51a1b1aaa2..b26da6d30800 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -98,6 +98,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetErrorHelper", XPCOMUtils.defineLazyModuleGetter(this, "PermissionsUtils", "resource://gre/modules/PermissionsUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "SharedPreferences", + "resource://gre/modules/SharedPreferences.jsm"); + // Lazily-loaded browser scripts: [ ["SelectHelper", "chrome://browser/content/SelectHelper.js"], @@ -6764,12 +6767,16 @@ var SearchEngines = { PREF_SUGGEST_ENABLED: "browser.search.suggest.enabled", PREF_SUGGEST_PROMPTED: "browser.search.suggest.prompted", + // Shared preference key used for search activity default engine. + PREF_SEARCH_ACTIVITY_ENGINE_KEY: "search.engines.default", + init: function init() { Services.obs.addObserver(this, "SearchEngines:Add", false); Services.obs.addObserver(this, "SearchEngines:GetVisible", false); Services.obs.addObserver(this, "SearchEngines:Remove", false); Services.obs.addObserver(this, "SearchEngines:RestoreDefaults", false); Services.obs.addObserver(this, "SearchEngines:SetDefault", false); + Services.obs.addObserver(this, "browser-search-engine-modified", false); let filter = { matches: function (aElement) { @@ -6814,6 +6821,7 @@ var SearchEngines = { Services.obs.removeObserver(this, "SearchEngines:Remove"); Services.obs.removeObserver(this, "SearchEngines:RestoreDefaults"); Services.obs.removeObserver(this, "SearchEngines:SetDefault"); + Services.obs.removeObserver(this, "browser-search-engine-modified"); if (this._contextMenuId != null) NativeWindow.contextmenus.remove(this._contextMenuId); }, @@ -6894,13 +6902,49 @@ var SearchEngines = { Services.search.moveEngine(engine, 0); Services.search.defaultEngine = engine; break; - + case "browser-search-engine-modified": + if (aData == "engine-default") { + this._setSearchActivityDefaultPref(aSubject.QueryInterface(Ci.nsISearchEngine)); + } + break; default: dump("Unexpected message type observed: " + aTopic); break; } }, + // Updates the search activity pref when the default engine changes. + _setSearchActivityDefaultPref: function _setSearchActivityDefaultPref(engine) { + // Helper function copied from nsSearchService.js. This is the logic that is used + // to create file names for search plugin XML serialized to disk. + function sanitizeName(aName) { + const maxLength = 60; + const minLength = 1; + let name = aName.toLowerCase(); + name = name.replace(/\s+/g, "-"); + name = name.replace(/[^-a-z0-9]/g, ""); + + if (name.length < minLength) { + // Well, in this case, we're kinda screwed. In this case, the search service + // generates a random file name, so to do this the right way, we'd need + // to open up search.json and see what file name is stored. + Cu.reportError("Couldn't create search plugin file name from engine name: " + aName); + return null; + } + + // Force max length. + return name.substring(0, maxLength); + } + + let identifier = engine.identifier; + if (identifier === null) { + // The identifier will be null for non-built-in engines. In this case, we need to + // figure out an identifier to store from the engine name. + identifier = sanitizeName(engine.name); + } + SharedPreferences.forApp().setCharPref(this.PREF_SEARCH_ACTIVITY_ENGINE_KEY, identifier); + }, + // Display context menu listing names of the search engines available to be added. displaySearchEnginesList: function displaySearchEnginesList(aData) { let data = JSON.parse(aData); diff --git a/mobile/android/search/java/org/mozilla/search/providers/SearchEngineManager.java b/mobile/android/search/java/org/mozilla/search/providers/SearchEngineManager.java index a91defaafbaf..d09517f6488c 100644 --- a/mobile/android/search/java/org/mozilla/search/providers/SearchEngineManager.java +++ b/mobile/android/search/java/org/mozilla/search/providers/SearchEngineManager.java @@ -12,12 +12,16 @@ import android.util.Log; import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.BrowserLocaleManager; +import org.mozilla.gecko.GeckoProfile; import org.mozilla.gecko.GeckoSharedPrefs; import org.mozilla.gecko.util.GeckoJarReader; import org.mozilla.search.Constants; import org.xmlpull.v1.XmlPullParserException; import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -177,6 +181,10 @@ public class SearchEngineManager implements SharedPreferences.OnSharedPreference private SearchEngine createEngine(String identifier) { InputStream in = getInputStreamFromJar(identifier + ".xml"); + if (in == null) { + in = getEngineFromProfile(identifier); + } + // Fallback for standalone search activity. if (in == null) { in = getEngineFromAssets(identifier); @@ -262,4 +270,22 @@ public class SearchEngineManager implements SharedPreferences.OnSharedPreference final String path = "!/chrome/" + locale + "/locale/" + locale + "/browser/searchplugins/" + fileName; return "jar:jar:file://" + context.getPackageResourcePath() + "!/" + AppConstants.OMNIJAR_NAME + path; } + + /** + * Opens the search plugin XML file from the searchplugins directory in the Gecko profile. + * + * @param identifier + * @return InputStream for search plugin file + */ + private InputStream getEngineFromProfile(String identifier) { + final File f = GeckoProfile.get(context).getFile("searchplugins/" + identifier + ".xml"); + if (f.exists()) { + try { + return new FileInputStream(f); + } catch (FileNotFoundException e) { + Log.e(LOG_TAG, "Exception getting search engine from profile", e); + } + } + return null; + } }