Back out bug 1426216 (show search suggestions above history in urlbar in some cases) and follow-ups on release. r=Mossop, a=ritu FIREFOX_59_0_BUILD5 FIREFOX_59_0_RELEASE
authorDrew Willcoxon <adw@mozilla.com>
Fri, 09 Mar 2018 18:54:17 -0800
changeset 766943 c61f5f5ead48c78a80c80db5c489bdc7cfaf8175
parent 765737 e9128973a480c8aedf3a2e1c67d3e168613fa17c
child 766944 534bbc15b9940ee0bdd25050e1b0d58fc78beb8b
push id102458
push usernalexander@mozilla.com
push dateTue, 13 Mar 2018 17:25:19 +0000
reviewersMossop, ritu
bugs1426216, 1432716, 1432263, 1429974
milestone59.0
Back out bug 1426216 (show search suggestions above history in urlbar in some cases) and follow-ups on release. r=Mossop, a=ritu There are four bugs that need to be backed out: 1. https://hg.mozilla.org/releases/mozilla-release/rev/152720a4efe7 (bug 1432716) 2. https://hg.mozilla.org/releases/mozilla-release/rev/84a24eb373fa (bug 1432263) 3. https://hg.mozilla.org/releases/mozilla-release/rev/4d423fdc33dd (bug 1429974) 4. https://hg.mozilla.org/releases/mozilla-release/rev/440dbdb51f94 (bug 1426216) The original bug implementing the problematic feature (pref migration + UI) is 4, and the others are improvements to it.
browser/components/nsBrowserGlue.js
browser/components/preferences/in-content/search.js
browser/components/preferences/in-content/search.xul
browser/components/preferences/in-content/tests/browser.ini
browser/components/preferences/in-content/tests/browser_searchShowSuggestionsFirst.js
browser/components/tests/browser/browser.ini
browser/components/tests/browser/browser_urlbar_matchBuckets_migration59.js
toolkit/components/places/PlacesUtils.jsm
toolkit/components/places/UnifiedComplete.js
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -29,17 +29,16 @@ XPCOMUtils.defineLazyModuleGetters(this,
   AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
   AutoCompletePopup: "resource://gre/modules/AutoCompletePopup.jsm",
   BookmarkHTMLUtils: "resource://gre/modules/BookmarkHTMLUtils.jsm",
   BookmarkJSONUtils: "resource://gre/modules/BookmarkJSONUtils.jsm",
   BrowserUITelemetry: "resource:///modules/BrowserUITelemetry.jsm",
   BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
   ContentClick: "resource:///modules/ContentClick.jsm",
   ContextualIdentityService: "resource://gre/modules/ContextualIdentityService.jsm",
-  CustomizableUI: "resource:///modules/CustomizableUI.jsm",
   DateTimePickerHelper: "resource://gre/modules/DateTimePickerHelper.jsm",
   DirectoryLinksProvider: "resource:///modules/DirectoryLinksProvider.jsm",
   ExtensionsUI: "resource:///modules/ExtensionsUI.jsm",
   Feeds: "resource:///modules/Feeds.jsm",
   FileUtils: "resource://gre/modules/FileUtils.jsm",
   FileSource: "resource://gre/modules/L10nRegistry.jsm",
   FormValidationHandler: "resource:///modules/FormValidationHandler.jsm",
   HybridContentTelemetry: "resource://gre/modules/HybridContentTelemetry.jsm",
@@ -436,18 +435,16 @@ BrowserGlue.prototype = {
         } else if (data == "mock-alerts-service") {
           Object.defineProperty(this, "AlertsService", {
             value: subject.wrappedJSObject
           });
         } else if (data == "places-browser-init-complete") {
           if (this._placesBrowserInitComplete) {
             Services.obs.notifyObservers(null, "places-browser-init-complete");
           }
-        } else if (data == "migrateMatchBucketsPrefForUIVersion60") {
-          this._migrateMatchBucketsPrefForUIVersion60(true);
         }
         break;
       case "initial-migration-will-import-default-bookmarks":
         this._migrationImportsDefaultBookmarks = true;
         break;
       case "initial-migration-did-import-default-bookmarks":
         this._initPlaces(true);
         break;
@@ -2246,19 +2243,18 @@ BrowserGlue.prototype = {
           }
         }
         Services.prefs.clearUserPref(SELECTED_LOCALE_PREF);
         Services.prefs.clearUserPref(MATCHOS_LOCALE_PREF);
       }
     }
 
     if (currentUIVersion < 60) {
-      // Set whether search suggestions or history results come first in the
-      // urlbar results.
-      this._migrateMatchBucketsPrefForUIVersion60();
+      // The changes made in this version were backed out on mozilla-release
+      // after subsequent versions were added.  See bug 1444548.
     }
 
     if (currentUIVersion < 61) {
       // Remove persisted toolbarset from navigator toolbox
       xulStore.removeValue(BROWSER_DOCURL, "navigator-toolbox", "toolbarset");
     }
 
     if (currentUIVersion < 62) {
@@ -2376,56 +2372,16 @@ BrowserGlue.prototype = {
                         .add(promptCount);
     } catch (ex) { /* Don't break the default prompt if telemetry is broken. */ }
 
     if (willPrompt) {
       DefaultBrowserCheck.prompt(RecentWindow.getMostRecentBrowserWindow());
     }
   },
 
-  _migrateMatchBucketsPrefForUIVersion60(forceCheck = false) {
-    function check() {
-      if (CustomizableUI.getPlacementOfWidget("search-container")) {
-        Services.prefs.setCharPref(prefName,
-                                   "general:5,suggestion:Infinity");
-      }
-    }
-    let prefName = "browser.urlbar.matchBuckets";
-    let pref = Services.prefs.getCharPref(prefName, "");
-    if (!pref) {
-      // Set the pref based on the search bar's current placement.  If it's
-      // placed (the urlbar and search bar are not unified), then set the pref
-      // (so that history results will come before search suggestions).  If it's
-      // not placed (the urlbar and search bar are unified), then leave the pref
-      // cleared so that UnifiedComplete.js uses the default value (so that
-      // search suggestions will come before history results).
-      if (forceCheck) {
-        // This is the case when this is called by the test.
-        check();
-      } else {
-        // This is the normal, non-test case.  At this point the first window
-        // has not been set up yet, so use a CUI listener to get the placement
-        // when the nav-bar is first registered.
-        let listener = {
-          onAreaNodeRegistered(area, container) {
-            if (CustomizableUI.AREA_NAVBAR == area) {
-              check();
-              CustomizableUI.removeListener(listener);
-            }
-          },
-        };
-        CustomizableUI.addListener(listener);
-      }
-    }
-    // Else, the pref has already been set.  Normally this pref does not exist.
-    // Either the user customized it, or they were enrolled in the Shield study
-    // in Firefox 57 that effectively already migrated the pref.  Either way,
-    // leave it at its current value.
-  },
-
   // ------------------------------
   // public nsIBrowserGlue members
   // ------------------------------
 
   sanitize: function BG_sanitize(aParentWindow) {
     this._sanitizer.sanitize(aParentWindow);
   },
 
--- a/browser/components/preferences/in-content/search.js
+++ b/browser/components/preferences/in-content/search.js
@@ -10,17 +10,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionSettingsStore",
                                   "resource://gre/modules/ExtensionSettingsStore.jsm");
 
 Preferences.addAll([
   { id: "browser.search.suggest.enabled", type: "bool" },
   { id: "browser.urlbar.suggest.searches", type: "bool" },
   { id: "browser.search.hiddenOneOffs", type: "unichar" },
   { id: "browser.search.widget.inNavBar", type: "bool" },
-  { id: "browser.urlbar.matchBuckets", type: "string" },
 ]);
 
 const ENGINE_FLAVOR = "text/x-moz-search-engine";
 const SEARCH_TYPE = "default_search";
 const SEARCH_KEY = "defaultSearch";
 
 var gEngineView = null;
 
@@ -54,86 +53,33 @@ var gSearchPane = {
     Services.obs.addObserver(this, "browser-search-engine-modified");
     window.addEventListener("unload", () => {
       Services.obs.removeObserver(this, "browser-search-engine-modified");
     });
 
     this._initAutocomplete();
 
     let suggestsPref = Preferences.get("browser.search.suggest.enabled");
-    let urlbarSuggestsPref = Preferences.get("browser.urlbar.suggest.searches");
-    let updateSuggestionCheckboxes = this._updateSuggestionCheckboxes.bind(this);
-    suggestsPref.on("change", updateSuggestionCheckboxes);
-    urlbarSuggestsPref.on("change", updateSuggestionCheckboxes);
-    this._initShowSearchSuggestionsFirst();
-    this._updateSuggestionCheckboxes();
-  },
-
-  _initShowSearchSuggestionsFirst() {
-    this._urlbarSuggestionsPosPref = Preferences.get("browser.urlbar.matchBuckets");
-    let checkbox =
-      document.getElementById("showSearchSuggestionsFirstCheckbox");
-
-    this._urlbarSuggestionsPosPref.on("change", () => {
-      this._syncFromShowSearchSuggestionsFirstPref(checkbox);
-    });
-    this._syncFromShowSearchSuggestionsFirstPref(checkbox);
-
-    checkbox.addEventListener("command", () => {
-      this._syncToShowSearchSuggestionsFirstPref(checkbox.checked);
-    });
+    suggestsPref.on("change", this.updateSuggestsCheckbox.bind(this));
+    this.updateSuggestsCheckbox();
   },
 
-  _syncFromShowSearchSuggestionsFirstPref(checkbox) {
-    if (!this._urlbarSuggestionsPosPref.value) {
-      // The pref is cleared, meaning search suggestions are shown first.
-      checkbox.checked = true;
-      return;
-    }
-    // The pref has a value.  If the first bucket in the pref is search
-    // suggestions, then check the checkbox.
-    let buckets = PlacesUtils.convertMatchBucketsStringToArray(this._urlbarSuggestionsPosPref.value);
-    checkbox.checked = buckets[0] && buckets[0][0] == "suggestion";
-  },
-
-  _syncToShowSearchSuggestionsFirstPref(checked) {
-    if (checked) {
-      // Show search suggestions first, so clear the pref since that's the
-      // default.
-      this._urlbarSuggestionsPosPref.reset();
-      return;
-    }
-    // Show history first.
-    this._urlbarSuggestionsPosPref.value = "general:5,suggestion:Infinity";
-  },
-
-  _updateSuggestionCheckboxes() {
+  updateSuggestsCheckbox() {
     let suggestsPref = Preferences.get("browser.search.suggest.enabled");
     let permanentPB =
       Services.prefs.getBoolPref("browser.privatebrowsing.autostart");
     let urlbarSuggests = document.getElementById("urlBarSuggestion");
-    let positionCheckbox =
-      document.getElementById("showSearchSuggestionsFirstCheckbox");
-
     urlbarSuggests.disabled = !suggestsPref.value || permanentPB;
 
     let urlbarSuggestsPref = Preferences.get("browser.urlbar.suggest.searches");
     urlbarSuggests.checked = urlbarSuggestsPref.value;
     if (urlbarSuggests.disabled) {
       urlbarSuggests.checked = false;
     }
 
-    if (urlbarSuggests.checked) {
-      positionCheckbox.disabled = false;
-      this._syncFromShowSearchSuggestionsFirstPref(positionCheckbox);
-    } else {
-      positionCheckbox.disabled = true;
-      positionCheckbox.checked = false;
-    }
-
     let permanentPBLabel =
       document.getElementById("urlBarSuggestionPermanentPBLabel");
     permanentPBLabel.hidden = urlbarSuggests.hidden || !permanentPB;
   },
 
   buildDefaultEngineDropDown() {
     // This is called each time something affects the list of engines.
     let list = document.getElementById("defaultEngine");
--- a/browser/components/preferences/in-content/search.xul
+++ b/browser/components/preferences/in-content/search.xul
@@ -41,18 +41,16 @@
       <checkbox id="suggestionsInSearchFieldsCheckbox"
                 label="&provideSearchSuggestions.label;"
                 accesskey="&provideSearchSuggestions.accesskey;"
                 preference="browser.search.suggest.enabled"/>
       <vbox class="indent">
         <checkbox id="urlBarSuggestion" label="&showURLBarSuggestions2.label;"
                   accesskey="&showURLBarSuggestions2.accesskey;"
                   preference="browser.urlbar.suggest.searches"/>
-        <checkbox id="showSearchSuggestionsFirstCheckbox"
-                  label="&showSearchSuggestionsAboveHistory.label;"/>
         <hbox id="urlBarSuggestionPermanentPBLabel"
               align="center" class="indent">
           <label flex="1">&urlBarSuggestionsPermanentPB.label;</label>
         </hbox>
       </vbox>
     </groupbox>
 
     <groupbox id="oneClickSearchProvidersGroup" data-category="paneSearch">
--- a/browser/components/preferences/in-content/tests/browser.ini
+++ b/browser/components/preferences/in-content/tests/browser.ini
@@ -65,17 +65,16 @@ skip-if = e10s
 [browser_permissions_urlFieldHidden.js]
 [browser_proxy_backup.js]
 [browser_privacypane_1.js]
 [browser_privacypane_3.js]
 [browser_privacypane_4.js]
 [browser_privacypane_5.js]
 [browser_privacypane_8.js]
 [browser_sanitizeOnShutdown_prefLocked.js]
-[browser_searchShowSuggestionsFirst.js]
 [browser_searchsuggestions.js]
 [browser_security-1.js]
 [browser_security-2.js]
 [browser_siteData.js]
 [browser_siteData2.js]
 [browser_siteData3.js]
 [browser_spotlight.js]
 [browser_site_login_exceptions.js]
deleted file mode 100644
--- a/browser/components/preferences/in-content/tests/browser_searchShowSuggestionsFirst.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-const PREF_NAME = "browser.urlbar.matchBuckets";
-const HISTORY_FIRST_PREF_VALUE = "general:5,suggestion:Infinity";
-const CHECKBOX_ID = "showSearchSuggestionsFirstCheckbox";
-
-// Open preferences with search suggestions shown first (the default).
-add_task(async function openWithSearchSuggestionsShownFirst() {
-  await SpecialPowers.pushPrefEnv({set: [["browser.urlbar.suggest.searches", true]]});
-
-  // The pref should be cleared initially so that search suggestions are shown
-  // first (the default).
-  Assert.equal(Services.prefs.getCharPref(PREF_NAME, ""), "",
-               "Pref should be cleared initially");
-
-  // Open preferences.  The checkbox should be checked.
-  await openPreferencesViaOpenPreferencesAPI("search", { leaveOpen: true });
-  let doc = gBrowser.selectedBrowser.contentDocument;
-  let checkbox = doc.getElementById(CHECKBOX_ID);
-  Assert.equal(checkbox.checked, true, "Checkbox should be checked");
-
-  // Uncheck the checkbox.
-  checkbox.checked = false;
-  checkbox.doCommand();
-
-  // The pref should now be set so that history is shown first.
-  Assert.equal(Services.prefs.getCharPref(PREF_NAME, ""),
-               HISTORY_FIRST_PREF_VALUE,
-               "Pref should now be set to show history first");
-
-  // Clear the pref.
-  Services.prefs.clearUserPref(PREF_NAME);
-
-  // The checkbox should have become checked again.
-  Assert.equal(checkbox.checked, true,
-               "Checkbox should become checked after clearing pref");
-
-  // Clean up.
-  gBrowser.removeCurrentTab();
-});
-
-// Open preferences with history shown first.
-add_task(async function openWithHistoryShownFirst() {
-  // Set the pref to show history first.
-  Services.prefs.setCharPref(PREF_NAME, HISTORY_FIRST_PREF_VALUE);
-
-  // Open preferences.  The checkbox should be unchecked.
-  await openPreferencesViaOpenPreferencesAPI("search", { leaveOpen: true });
-  let doc = gBrowser.selectedBrowser.contentDocument;
-  let checkbox = doc.getElementById(CHECKBOX_ID);
-  Assert.equal(checkbox.checked, false, "Checkbox should be unchecked");
-
-  // Check the checkbox.
-  checkbox.checked = true;
-  checkbox.doCommand();
-
-  // The pref should now be cleared so that search suggestions are shown first.
-  Assert.equal(Services.prefs.getCharPref(PREF_NAME, ""), "",
-               "Pref should now be cleared to show search suggestions first");
-
-  // Set the pref again.
-  Services.prefs.setCharPref(PREF_NAME, HISTORY_FIRST_PREF_VALUE);
-
-  // The checkbox should have become unchecked again.
-  Assert.equal(checkbox.checked, false,
-               "Checkbox should become unchecked after setting pref");
-
-  // Clean up.
-  gBrowser.removeCurrentTab();
-  Services.prefs.clearUserPref(PREF_NAME);
-});
--- a/browser/components/tests/browser/browser.ini
+++ b/browser/components/tests/browser/browser.ini
@@ -1,8 +1,7 @@
 [DEFAULT]
 
 [browser_bug538331.js]
 skip-if = !updater
 reason = test depends on update channel
 [browser_contentpermissionprompt.js]
 [browser_default_bookmark_toolbar_visibility.js]
-[browser_urlbar_matchBuckets_migration59.js]
deleted file mode 100644
--- a/browser/components/tests/browser/browser_urlbar_matchBuckets_migration59.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-// Makes sure the browser.urlbar.matchBuckets pref is set correctly starting in
-// Firefox 59 (nsBrowserGlue UI version 60).
-
-const SEARCHBAR_WIDGET_ID = "search-container";
-const PREF_NAME = "browser.urlbar.matchBuckets";
-const SEARCHBAR_PRESENT_PREF_VALUE = "general:5,suggestion:Infinity";
-
-add_task(async function test() {
-  // Initial checks.
-  Assert.equal(CustomizableUI.getPlacementOfWidget(SEARCHBAR_WIDGET_ID), null,
-               "Searchbar should not be placed initially");
-  Assert.equal(Services.prefs.getCharPref(PREF_NAME, ""), "",
-               "Pref should be cleared initially");
-
-  // Add the searchbar.
-  let widgetPromise = promiseWidget("onWidgetAdded");
-  CustomizableUI.addWidgetToArea(SEARCHBAR_WIDGET_ID,
-                                 CustomizableUI.AREA_NAVBAR);
-  info("Waiting for searchbar to be added");
-  await widgetPromise;
-
-  // Force nsBrowserGlue to attempt update the pref again via UI version
-  // migration.  It shouldn't actually though since the UI version has already
-  // been migrated.  If it erroneously does, then the matchBuckets pref will be
-  // set since the searchbar is now placed.
-  messageBrowserGlue("force-ui-migration");
-
-  // The pref should remain cleared since the migration already happened even
-  // though the searchbar is now present.
-  Assert.equal(Services.prefs.getCharPref(PREF_NAME, ""), "",
-               "Pref should remain cleared even though searchbar present");
-
-  // Force nsBrowserGlue to update the pref.
-  forceBrowserGlueUpdatePref();
-
-  // The pref should be set since the searchbar is present.
-  Assert.equal(Services.prefs.getCharPref(PREF_NAME, ""),
-               SEARCHBAR_PRESENT_PREF_VALUE,
-               "Pref should be set to show history first");
-
-  // Set the pref to something custom.
-  let customValue = "test:Infinity";
-  Services.prefs.setCharPref(PREF_NAME, customValue);
-
-  // Force nsBrowserGlue to update the pref again.
-  forceBrowserGlueUpdatePref();
-
-  // The pref should remain the custom value.
-  Assert.equal(Services.prefs.getCharPref(PREF_NAME, ""), customValue,
-               "Pref should remain the custom value");
-
-  // Remove the searchbar.
-  widgetPromise = promiseWidget("onWidgetRemoved");
-  CustomizableUI.removeWidgetFromArea(SEARCHBAR_WIDGET_ID);
-  info("Waiting for searchbar to be removed");
-  await widgetPromise;
-
-  // Force nsBrowserGlue to update the pref again.
-  forceBrowserGlueUpdatePref();
-
-  // The pref should remain the custom value.
-  Assert.equal(Services.prefs.getCharPref(PREF_NAME, ""), customValue,
-               "Pref should remain the custom value");
-
-  // Clear the pref.
-  Services.prefs.clearUserPref(PREF_NAME);
-
-  // Force nsBrowserGlue to update the pref again.
-  forceBrowserGlueUpdatePref();
-
-  // The pref should remain cleared since the searchbar isn't placed.
-  Assert.equal(Services.prefs.getCharPref(PREF_NAME, ""), "",
-               "Pref should remain cleared");
-});
-
-function promiseWidget(observerName) {
-  return new Promise(resolve => {
-    let listener = {};
-    listener[observerName] = widgetID => {
-      if (widgetID == SEARCHBAR_WIDGET_ID) {
-        CustomizableUI.removeListener(listener);
-        executeSoon(resolve);
-      }
-    };
-    CustomizableUI.addListener(listener);
-  });
-}
-
-function messageBrowserGlue(msgName) {
-  Cc["@mozilla.org/browser/browserglue;1"]
-    .getService(Ci.nsIObserver)
-    .observe(null, "browser-glue-test", msgName);
-}
-
-function forceBrowserGlueUpdatePref() {
-  messageBrowserGlue("migrateMatchBucketsPrefForUIVersion60");
-}
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -444,37 +444,16 @@ this.PlacesUtils = {
         continue;
       }
       encodedParams[key] = encodeURIComponent(params[key]);
     }
     return "moz-action:" + type + "," + JSON.stringify(encodedParams);
   },
 
   /**
-   * Parses matchBuckets strings (for example, "suggestion:4,general:Infinity")
-   * like those used in the browser.urlbar.matchBuckets preference.
-   *
-   * @param   str
-   *          A matchBuckets string.
-   * @returns An array of the form: [
-   *            [bucketName_0, bucketPriority_0],
-   *            [bucketName_1, bucketPriority_1],
-   *            ...
-   *            [bucketName_n, bucketPriority_n]
-   *          ]
-   */
-  convertMatchBucketsStringToArray(str) {
-    return str.split(",")
-              .map(v => {
-                let bucket = v.split(":");
-                return [ bucket[0].trim().toLowerCase(), Number(bucket[1]) ];
-              });
-  },
-
-  /**
    * Determines whether or not a ResultNode is a Bookmark folder.
    * @param   aNode
    *          A result node
    * @returns true if the node is a Bookmark folder, false otherwise
    */
   nodeIsFolder: function PU_nodeIsFolder(aNode) {
     return (aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER ||
             aNode.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT);
--- a/toolkit/components/places/UnifiedComplete.js
+++ b/toolkit/components/places/UnifiedComplete.js
@@ -45,17 +45,17 @@ const PREF_URLBAR_DEFAULTS = new Map([
   ["suggest.bookmark", true],
   ["suggest.openpage", true],
   ["suggest.history.onlyTyped", false],
   ["suggest.searches", false],
   ["maxCharsForSearchSuggestions", 20],
   ["maxHistoricalSearchSuggestions", 0],
   ["usepreloadedtopurls.enabled", true],
   ["usepreloadedtopurls.expire_days", 14],
-  ["matchBuckets", "suggestion:4,general:Infinity"],
+  ["matchBuckets", "general:5,suggestion:Infinity"],
   ["matchBucketsSearch", ""],
   ["insertMethod", INSERTMETHOD.MERGE_RELATED],
 ]);
 const PREF_OTHER_DEFAULTS = new Map([
   ["keyword.enabled", true],
 ]);
 
 // AutoComplete query type constants.
@@ -334,16 +334,24 @@ XPCOMUtils.defineLazyPreferenceGetter(th
                                       "services.sync.username");
 
 function setTimeout(callback, ms) {
   let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
   timer.initWithCallback(callback, ms, timer.TYPE_ONE_SHOT);
   return timer;
 }
 
+function convertBucketsCharPrefToArray(str) {
+  return str.split(",")
+            .map(v => {
+              let bucket = v.split(":");
+              return [ bucket[0].trim().toLowerCase(), Number(bucket[1]) ];
+            });
+}
+
 /**
  * Storage object for switch-to-tab entries.
  * This takes care of caching and registering open pages, that will be reused
  * by switch-to-tab queries.  It has an internal cache, so that the Sqlite
  * store is lazy initialized only on first use.
  * It has a simple API:
  *   initDatabase(conn): initializes the temporary Sqlite entities to store data
  *   add(uri): adds a given nsIURI to the store
@@ -475,31 +483,31 @@ XPCOMUtils.defineLazyGetter(this, "Prefs
   }
 
   function getPrefValue(pref) {
     switch (pref) {
       case "matchBuckets": {
         // Convert from pref char format to an array and add the default buckets.
         let val = readPref(pref);
         try {
-          val = PlacesUtils.convertMatchBucketsStringToArray(val);
+          val = convertBucketsCharPrefToArray(val);
         } catch (ex) {
-          val = PlacesUtils.convertMatchBucketsStringToArray(PREF_URLBAR_DEFAULTS.get(pref));
+          val = convertBucketsCharPrefToArray(PREF_URLBAR_DEFAULTS.get(pref));
         }
         return [ ...DEFAULT_BUCKETS_BEFORE,
                 ...val,
                 ...DEFAULT_BUCKETS_AFTER ];
       }
       case "matchBucketsSearch": {
         // Convert from pref char format to an array and add the default buckets.
         let val = readPref(pref);
         if (val) {
           // Convert from pref char format to an array and add the default buckets.
           try {
-            val = PlacesUtils.convertMatchBucketsStringToArray(val);
+            val = convertBucketsCharPrefToArray(val);
             return [ ...DEFAULT_BUCKETS_BEFORE,
                     ...val,
                     ...DEFAULT_BUCKETS_AFTER ];
           } catch (ex) { /* invalid format, will just return matchBuckets */ }
         }
         return store.get("matchBuckets");
       }
       case "suggest.history.onlyTyped": {