Bug 1018240 - Part 1: reinitialize nsSearchService when the browser locale changes. r=adw
authorRichard Newman <rnewman@mozilla.com>
Mon, 21 Jul 2014 10:54:55 -0700
changeset 195372 0234ad055a7b978dd0a9a43561ee9f1a701d1061
parent 195371 278e109b79f5f363cd90b4da473ec49f249ffb51
child 195373 476a0455e0e816fe60cc1a6d0dfb893400873041
push id46575
push userkwierso@gmail.com
push dateTue, 22 Jul 2014 00:35:21 +0000
treeherdermozilla-inbound@fee5c4bdd713 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersadw
bugs1018240
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1018240 - Part 1: reinitialize nsSearchService when the browser locale changes. r=adw 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.
  */
@@ -3185,16 +3185,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());
@@ -4145,21 +4166,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) {
@@ -4200,16 +4231,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
@@ -4247,16 +4279,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;