Bug 1018240 - Part 1: Reinitialize nsSearchService when the browser locale changes. r=adw, a=sledru
authorRichard Newman <rnewman@mozilla.com>
Mon, 21 Jul 2014 10:54:55 -0700
changeset 208176 bbfebb4ec504
parent 208175 ecfc5bee1685
child 208177 d1e5cb0fbe70
push id3754
push userryanvm@gmail.com
push date2014-07-28 15:24 +0000
treeherdermozilla-beta@61b30b605194 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersadw, sledru
bugs1018240
milestone32.0
Bug 1018240 - Part 1: Reinitialize nsSearchService when the browser locale changes. r=adw, a=sledru This patch makes nsSearchService watch for changes in the general.useragent.locale pref, asynchronously reiniting itself when the pref changes. reinit-complete and reinit-failed events are broadcast on the usual search service topic.
toolkit/components/search/nsSearchService.js
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -138,16 +138,17 @@ const URLTYPE_OPENSEARCH   = "applicatio
 // Empty base document used to serialize engines to file.
 const EMPTY_DOC = "<?xml version=\"1.0\"?>\n" +
                   "<" + MOZSEARCH_LOCALNAME +
                   " xmlns=\"" + MOZSEARCH_NS_10 + "\"" +
                   " xmlns:os=\"" + OPENSEARCH_NS_11 + "\"" +
                   "/>";
 
 const BROWSER_SEARCH_PREF = "browser.search.";
+const LOCALE_PREF = "general.useragent.locale";
 
 const USER_DEFINED = "{searchTerms}";
 
 // Custom search parameters
 #ifdef MOZ_OFFICIAL_BRANDING
 const MOZ_OFFICIAL = "official";
 #else
 const MOZ_OFFICIAL = "unofficial";
@@ -585,23 +586,22 @@ function sherlockBytesToLines(aBytes, aC
 }
 
 /**
  * Gets the current value of the locale.  It's possible for this preference to
  * be localized, so we have to do a little extra work here.  Similar code
  * exists in nsHttpHandler.cpp when building the UA string.
  */
 function getLocale() {
-  const localePref = "general.useragent.locale";
-  var locale = getLocalizedPref(localePref);
+  let locale = getLocalizedPref(LOCALE_PREF);
   if (locale)
     return locale;
 
-  // Not localized
-  return Services.prefs.getCharPref(localePref);
+  // Not localized.
+  return Services.prefs.getCharPref(LOCALE_PREF);
 }
 
 /**
  * Wrapper for nsIPrefBranch::getComplexValue.
  * @param aPrefName
  *        The name of the pref to get.
  * @returns aDefault if the requested pref doesn't exist.
  */
@@ -3151,16 +3151,37 @@ SearchService.prototype = {
       LOG("_asyncLoadEngines: loading from cache directories");
       for each (let dir in cache.directories)
         this._loadEnginesFromCache(dir);
 
       LOG("_asyncLoadEngines: done");
     }.bind(this));
   },
 
+  _asyncReInit: function () {
+    // Start by clearing the initialized state, so we don't abort early.
+    gInitialized = false;
+
+    // Clear the engines, too, so we don't stick with the stale ones.
+    this._engines = {};
+    this.__sortedEngines = null;
+
+    // Typically we'll re-init as a result of a pref observer,
+    // so signal to 'callers' that we're done. 
+    return this._asyncLoadEngines()
+               .then(() => {
+                       Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "reinit-complete");
+                       gInitialized = true;
+                     },
+                     (err) => {
+                       LOG("Reinit failed: " + err);
+                       Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "reinit-failed");
+                     });
+  },
+
   _readCacheFile: function SRCH_SVC__readCacheFile(aFile) {
     let stream = Cc["@mozilla.org/network/file-input-stream;1"].
                  createInstance(Ci.nsIFileInputStream);
     let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
 
     try {
       stream.init(aFile, MODE_RDONLY, PERMS_FILE, 0);
       return json.decodeFromStream(stream, stream.available());
@@ -4111,21 +4132,31 @@ SearchService.prototype = {
         }
         break;
 
       case QUIT_APPLICATION_TOPIC:
         this._removeObservers();
         break;
 
       case "nsPref:changed":
+        if (aVerb == LOCALE_PREF) {
+          // Locale changed. Re-init. We rely on observers, because we can't
+          // return this promise to anyone.
+          this._asyncReInit();
+          break;
+        }
+
         let currPref = BROWSER_SEARCH_PREF + "selectedEngine";
-        let defPref = BROWSER_SEARCH_PREF + "defaultenginename";
         if (aVerb == currPref && !this._changingCurrentEngine) {
           this._setEngineByPref("currentEngine", currPref);
-        } else if (aVerb == defPref && !this._changingDefaultEngine) {
+          break;
+        }
+
+        let defPref = BROWSER_SEARCH_PREF + "defaultenginename";
+        if (aVerb == defPref && !this._changingDefaultEngine) {
           this._setEngineByPref("defaultEngine", defPref);
         }
         break;
     }
   },
 
   // nsITimerCallback
   notify: function SRCH_SVC_notify(aTimer) {
@@ -4166,16 +4197,17 @@ SearchService.prototype = {
     } // end engine iteration
   },
 
   _addObservers: function SRCH_SVC_addObservers() {
     Services.obs.addObserver(this, SEARCH_ENGINE_TOPIC, false);
     Services.obs.addObserver(this, QUIT_APPLICATION_TOPIC, false);
     Services.prefs.addObserver(BROWSER_SEARCH_PREF + "defaultenginename", this, false);
     Services.prefs.addObserver(BROWSER_SEARCH_PREF + "selectedEngine", this, false);
+    Services.prefs.addObserver(LOCALE_PREF, this, false);
 
     // 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
@@ -4213,16 +4245,17 @@ SearchService.prototype = {
     );
   },
 
   _removeObservers: function SRCH_SVC_removeObservers() {
     Services.obs.removeObserver(this, SEARCH_ENGINE_TOPIC);
     Services.obs.removeObserver(this, QUIT_APPLICATION_TOPIC);
     Services.prefs.removeObserver(BROWSER_SEARCH_PREF + "defaultenginename", this);
     Services.prefs.removeObserver(BROWSER_SEARCH_PREF + "selectedEngine", this);
+    Services.prefs.removeObserver(LOCALE_PREF, this);
   },
 
   QueryInterface: function SRCH_SVC_QI(aIID) {
     if (aIID.equals(Ci.nsIBrowserSearchService) ||
         aIID.equals(Ci.nsIObserver)             ||
         aIID.equals(Ci.nsITimerCallback)        ||
         aIID.equals(Ci.nsISupports))
       return this;