Merge b2g-inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 15 Apr 2014 22:28:29 -0400
changeset 197140 16e9cda442500ee95535e9b951adbd6deb664ac7
parent 197087 661f96cbf4cef409e3805d3dc29a418d62b87204 (diff)
parent 197139 0a62b1b96edd15e0cef582f12c686a6990ebc02f (current diff)
child 197141 ea50c3918fa1af0848a4c11c6d38f3993acb0baf
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone31.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
Merge b2g-inbound to m-c.
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4459,16 +4459,19 @@ var TabsInTitlebar = {
     for (let something in this._disallowed) {
       allowed = false;
       break;
     }
 
     let titlebar = $("titlebar");
     let titlebarContent = $("titlebar-content");
     let menubar = $("toolbar-menubar");
+#ifdef XP_MACOSX
+    let secondaryButtonsWidth = rect($("titlebar-secondary-buttonbox")).width;
+#endif
 
     if (allowed) {
       // We set the tabsintitlebar attribute first so that our CSS for
       // tabsintitlebar manifests before we do our measurements.
       document.documentElement.setAttribute("tabsintitlebar", "true");
       updateTitlebarDisplay();
 
       // Try to avoid reflows in this code by calculating dimensions first and
@@ -4476,17 +4479,16 @@ var TabsInTitlebar = {
 
       // Get the full height of the tabs toolbar:
       let tabsToolbar = $("TabsToolbar");
       let fullTabsHeight = rect(tabsToolbar).height;
       // Buttons first:
       let captionButtonsBoxWidth = rect($("titlebar-buttonbox-container")).width;
 
 #ifdef XP_MACOSX
-      let secondaryButtonsWidth = rect($("titlebar-secondary-buttonbox")).width;
       // No need to look up the menubar stuff on OS X:
       let menuHeight = 0;
       let fullMenuHeight = 0;
       // Instead, look up the titlebar padding:
       let titlebarPadding = parseInt(window.getComputedStyle(titlebar).paddingTop, 10);
 #else
       // Otherwise, get the height and margins separately for the menubar
       let menuHeight = rect(menubar).height;
@@ -4551,19 +4553,16 @@ var TabsInTitlebar = {
         titlebarContentHeight += extraMargin;
       }
 
       // Then we bring up the titlebar by the same amount, but we add any negative margin:
       titlebar.style.marginBottom = "-" + titlebarContentHeight + "px";
 
 
       // Finally, size the placeholders:
-#ifdef XP_MACOSX
-      this._sizePlaceholder("fullscreen-button", secondaryButtonsWidth);
-#endif
       this._sizePlaceholder("caption-buttons", captionButtonsBoxWidth);
 
       if (!this._draghandles) {
         this._draghandles = {};
         let tmp = {};
         Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
 
         let mouseDownCheck = function () {
@@ -4581,16 +4580,20 @@ var TabsInTitlebar = {
       updateTitlebarDisplay();
 
       // Reset the margins and padding that might have been modified:
       titlebarContent.style.marginTop = "";
       titlebarContent.style.marginBottom = "";
       titlebar.style.marginBottom = "";
       menubar.style.paddingBottom = "";
     }
+
+#ifdef XP_MACOSX
+    this._sizePlaceholder("fullscreen-button", secondaryButtonsWidth);
+#endif
   },
 
   _sizePlaceholder: function (type, width) {
     Array.forEach(document.querySelectorAll(".titlebar-placeholder[type='"+ type +"']"),
                   function (node) { node.width = width; });
   },
 #endif
 
--- a/browser/components/customizableui/src/CustomizableUI.jsm
+++ b/browser/components/customizableui/src/CustomizableUI.jsm
@@ -292,31 +292,37 @@ let CustomizableUIInternal = {
 
   registerArea: function(aName, aProperties, aInternalCaller) {
     if (typeof aName != "string" || !/^[a-z0-9-_]{1,}$/i.test(aName)) {
       throw new Error("Invalid area name");
     }
 
     let areaIsKnown = gAreas.has(aName);
     let props = areaIsKnown ? gAreas.get(aName) : new Map();
+    if (areaIsKnown && aProperties["type"] &&
+        props.get("type") != aProperties["type"]) {
+      throw new Error("An area cannot change types");
+    }
     for (let key in aProperties) {
       //XXXgijs for special items, we need to make sure they have an appropriate ID
       // so we aren't perpetually in a non-default state:
       if (key == "defaultPlacements" && Array.isArray(aProperties[key])) {
         props.set(key, aProperties[key].map(x => this.isSpecialWidget(x) ? this.ensureSpecialWidgetId(x) : x ));
       } else {
         props.set(key, aProperties[key]);
       }
     }
     // Default to a toolbar:
     if (!props.has("type")) {
       props.set("type", CustomizableUI.TYPE_TOOLBAR);
     }
     if (props.get("type") == CustomizableUI.TYPE_TOOLBAR) {
-      if (!aInternalCaller && props.has("defaultCollapsed")) {
+      // Check aProperties instead of props because this check is only interested
+      // in the passed arguments, not the state of a potentially pre-existing area.
+      if (!aInternalCaller && aProperties["defaultCollapsed"]) {
         throw new Error("defaultCollapsed is only allowed for default toolbars.")
       }
       if (!props.has("defaultCollapsed")) {
         props.set("defaultCollapsed", true);
       }
     } else if (props.has("defaultCollapsed")) {
       throw new Error("defaultCollapsed only applies for TYPE_TOOLBAR areas.");
     }
--- a/browser/components/customizableui/test/browser.ini
+++ b/browser/components/customizableui/test/browser.ini
@@ -100,10 +100,11 @@ skip-if = os == "linux"
 [browser_985815_propagate_setToolbarVisibility.js]
 [browser_981305_separator_insertion.js]
 [browser_987177_destroyWidget_xul.js]
 [browser_987177_xul_wrapper_updating.js]
 [browser_987492_window_api.js]
 [browser_992747_toggle_noncustomizable_toolbar.js]
 [browser_993322_widget_notoolbar.js]
 [browser_995164_registerArea_during_customize_mode.js]
+[browser_996364_defaultCollapsed.js]
 [browser_bootstrapped_custom_toolbar.js]
 [browser_panel_toggle.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/customizableui/test/browser_996364_defaultCollapsed.js
@@ -0,0 +1,56 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+// Calling CustomizableUI.registerArea twice with no
+// properties should not throw an exception.
+add_task(function() {
+  try {
+    CustomizableUI.registerArea("area-996364", {});
+    CustomizableUI.registerArea("area-996364", {});
+  } catch (ex) {
+    ok(false, ex.message);
+  }
+
+  CustomizableUI.unregisterArea("area-996364", true);
+});
+
+add_task(function() {
+  let exceptionThrown = false;
+  try {
+    CustomizableUI.registerArea("area-996364-2", {"type": CustomizableUI.TYPE_TOOLBAR, "defaultCollapsed": "false"});
+  } catch (ex) {
+    exceptionThrown = true;
+  }
+  ok(exceptionThrown, "defaultCollapsed is not allowed as an external property");
+
+  // No need to unregister the area because registration fails.
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996364-3", {"type": CustomizableUI.TYPE_TOOLBAR});
+    CustomizableUI.registerArea("area-996364-3", {"type": CustomizableUI.TYPE_MENU_PANEL});
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+
+  CustomizableUI.unregisterArea("area-996364-3", true);
+});
+
+add_task(function() {
+  let exceptionThrown;
+  try {
+    CustomizableUI.registerArea("area-996364-4", {"type": CustomizableUI.TYPE_MENU_PANEL});
+    CustomizableUI.registerArea("area-996364-4", {"type": CustomizableUI.TYPE_TOOLBAR});
+  } catch (ex) {
+    exceptionThrown = ex;
+  }
+  ok(exceptionThrown, "Exception expected, an area cannot change types: " + (exceptionThrown ? exceptionThrown : "[no exception]"));
+
+  CustomizableUI.unregisterArea("area-996364-4", true);
+});
--- a/browser/experiments/Experiments.jsm
+++ b/browser/experiments/Experiments.jsm
@@ -53,16 +53,17 @@ const OBSERVER_TOPIC            = "exper
 const MANIFEST_VERSION          = 1;
 const CACHE_VERSION             = 1;
 
 const KEEP_HISTORY_N_DAYS       = 180;
 const MIN_EXPERIMENT_ACTIVE_SECONDS = 60;
 
 const PREF_BRANCH               = "experiments.";
 const PREF_ENABLED              = "enabled"; // experiments.enabled
+const PREF_ACTIVE_EXPERIMENT    = "activeExperiment"; // whether we have an active experiment
 const PREF_LOGGING              = "logging";
 const PREF_LOGGING_LEVEL        = PREF_LOGGING + ".level"; // experiments.logging.level
 const PREF_LOGGING_DUMP         = PREF_LOGGING + ".dump"; // experiments.logging.dump
 const PREF_MANIFEST_URI         = "manifest.uri"; // experiments.logging.manifest.uri
 const PREF_MANIFEST_CHECKCERT   = "manifest.cert.checkAttributes"; // experiments.manifest.cert.checkAttributes
 const PREF_MANIFEST_REQUIREBUILTIN = "manifest.cert.requireBuiltin"; // experiments.manifest.cert.requireBuiltin
 const PREF_FORCE_SAMPLE = "force-sample-value"; // experiments.force-sample-value
 
@@ -970,16 +971,21 @@ Experiments.Experiments.prototype = {
 
       yield uninstallAddons(unknownAddons);
     }
 
     let activeExperiment = this._getActiveExperiment();
     let activeChanged = false;
     let now = this._policy.now();
 
+    if (!activeExperiment) {
+      // Avoid this pref staying out of sync if there were e.g. crashes.
+      gPrefs.set(PREF_ACTIVE_EXPERIMENT, false);
+    }
+
     if (activeExperiment) {
       this._pendingUninstall = activeExperiment._addonId;
       try {
         let wasStopped;
         if (this._terminateReason) {
           yield activeExperiment.stop(this._terminateReason);
           wasStopped = true;
         } else {
@@ -1479,16 +1485,17 @@ Experiments.ExperimentEntry.prototype = 
       let addons = yield installedExperimentAddons();
       if (addons.length > 0) {
         this._log.error("start() - there are already "
                         + addons.length + " experiment addons installed");
         yield uninstallAddons(addons);
       }
 
       yield this._installAddon();
+      gPrefs.set(PREF_ACTIVE_EXPERIMENT, true);
     }.bind(this));
   },
 
   // Async install of the addon for this experiment, part of the start task above.
   _installAddon: function* () {
     let deferred = Promise.defer();
 
     let install = yield addonInstallForURL(this._manifestData.xpiURL,
@@ -1599,16 +1606,18 @@ Experiments.ExperimentEntry.prototype = 
   stop: function (terminationKind, terminationReason) {
     this._log.trace("stop() - id=" + this.id + ", terminationKind=" + terminationKind);
     if (!this._enabled) {
       this._log.warning("stop() - experiment not enabled: " + id);
       return Promise.reject();
     }
 
     this._enabled = false;
+    gPrefs.set(PREF_ACTIVE_EXPERIMENT, false);
+
     let deferred = Promise.defer();
     let updateDates = () => {
       let now = this._policy.now();
       this._lastChangedDate = now;
       this._endDate = now;
     };
 
     this._getAddon().then((addon) => {
@@ -1846,18 +1855,16 @@ ExperimentsProvider.prototype = Object.f
     ExperimentsLastActiveMeasurement1,
   ],
 
   _OBSERVERS: [
     OBSERVER_TOPIC,
   ],
 
   postInit: function () {
-    this._experiments = Experiments.instance();
-
     for (let o of this._OBSERVERS) {
       Services.obs.addObserver(this, o, false);
     }
 
     return Promise.resolve();
   },
 
   onShutdown: function () {
@@ -1876,16 +1883,24 @@ ExperimentsProvider.prototype = Object.f
     }
   },
 
   collectDailyData: function () {
     return this.recordLastActiveExperiment();
   },
 
   recordLastActiveExperiment: function () {
+    if (!gExperimentsEnabled) {
+      return Promise.resolve();
+    }
+
+    if (!this._experiments) {
+      this._experiments = Experiments.instance();
+    }
+
     let m = this.getMeasurement(ExperimentsLastActiveMeasurement1.prototype.name,
                                 ExperimentsLastActiveMeasurement1.prototype.version);
 
     return this.enqueueStorageOperation(() => {
       return Task.spawn(function* recordTask() {
         let todayActive = yield this._experiments.lastActiveToday();
         if (!todayActive) {
           this._log.info("No active experiment on this day: " +
--- a/browser/experiments/ExperimentsService.js
+++ b/browser/experiments/ExperimentsService.js
@@ -3,59 +3,96 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Preferences.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
                                   "resource:///modules/experiments/Experiments.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "CommonUtils",
+                                  "resource://services-common/utils.js");
 
 const PREF_EXPERIMENTS_ENABLED  = "experiments.enabled";
+const PREF_ACTIVE_EXPERIMENT    = "experiments.activeExperiment"; // whether we have an active experiment
 const PREF_HEALTHREPORT_ENABLED = "datareporting.healthreport.service.enabled";
 const PREF_TELEMETRY_ENABLED    = "toolkit.telemetry.enabled";
+const DELAY_INIT_MS             = 30 * 1000;
+
+XPCOMUtils.defineLazyGetter(
+  this, "gPrefs", () => {
+    return new Preferences();
+  });
 
 XPCOMUtils.defineLazyGetter(
   this, "gExperimentsEnabled", () => {
-    try {
-      let prefs = Services.prefs;
-      return prefs.getBoolPref(PREF_EXPERIMENTS_ENABLED) &&
-             prefs.getBoolPref(PREF_TELEMETRY_ENABLED) &&
-             prefs.getBoolPref(PREF_HEALTHREPORT_ENABLED);
-    } catch (e) {
-      return false;
-    }
+    return gPrefs.get(PREF_EXPERIMENTS_ENABLED, false) &&
+           gPrefs.get(PREF_TELEMETRY_ENABLED, false) &&
+           gPrefs.get(PREF_HEALTHREPORT_ENABLED, false);
+  });
+
+XPCOMUtils.defineLazyGetter(
+  this, "gActiveExperiment", () => {
+    return gPrefs.get(PREF_ACTIVE_EXPERIMENT);
   });
 
 function ExperimentsService() {
+  this._initialized = false;
+  this._delayedInitTimer = null;
 }
 
 ExperimentsService.prototype = {
   classID: Components.ID("{f7800463-3b97-47f9-9341-b7617e6d8d49}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback, Ci.nsIObserver]),
 
   notify: function (timer) {
     if (!gExperimentsEnabled) {
       return;
     }
     if (OS.Constants.Path.profileDir === undefined) {
       throw Error("Update timer fired before profile was initialized?");
     }
     Experiments.instance().updateManifest();
   },
 
+  _delayedInit: function () {
+    if (!this._initialized) {
+      this._initialized = true;
+      Experiments.instance(); // for side effects
+    }
+  },
+
   observe: function (subject, topic, data) {
     switch (topic) {
       case "profile-after-change":
         if (gExperimentsEnabled) {
-          Experiments.instance(); // for side effects
+          Services.obs.addObserver(this, "quit-application", false);
+          Services.obs.addObserver(this, "sessionstore-state-finalized", false);
+
+          if (gActiveExperiment) {
+            this._initialized = true;
+            Experiments.instance(); // for side effects
+          }
+        }
+        break;
+      case "sessionstore-state-finalized":
+        if (!this._initialized) {
+          CommonUtils.namedTimer(this._delayedInit, DELAY_INIT_MS, this, "_delayedInitTimer");
+        }
+        break;
+      case "quit-application":
+        Services.obs.removeObserver(this, "quit-application");
+        Services.obs.removeObserver(this, "sessionstore-state-finalized");
+        if (this._delayedInitTimer) {
+          this._delayedInitTimer.clear();
         }
         break;
     }
   },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ExperimentsService]);
--- a/browser/experiments/test/xpcshell/head.js
+++ b/browser/experiments/test/xpcshell/head.js
@@ -7,16 +7,24 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource://services-sync/healthreport.jsm", this);
 Cu.import("resource://testing-common/services/healthreport/utils.jsm", this);
 Cu.import("resource://gre/modules/services/healthreport/providers.jsm");
 
+const PREF_EXPERIMENTS_ENABLED  = "experiments.enabled";
+const PREF_LOGGING_LEVEL        = "experiments.logging.level";
+const PREF_LOGGING_DUMP         = "experiments.logging.dump";
+const PREF_MANIFEST_URI         = "experiments.manifest.uri";
+const PREF_FETCHINTERVAL        = "experiments.manifest.fetchIntervalSeconds";
+const PREF_TELEMETRY_ENABLED    = "toolkit.telemetry.enabled";
+const PREF_HEALTHREPORT_ENABLED = "datareporting.healthreport.service.enabled";
+
 function getExperimentPath(base) {
   let p = do_get_cwd();
   p.append(base);
   return p.path;
 }
 
 function sha1File(path) {
   let f = Cc["@mozilla.org/file/local;1"]
--- a/browser/experiments/test/xpcshell/test_activate.js
+++ b/browser/experiments/test/xpcshell/test_activate.js
@@ -2,21 +2,16 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 Cu.import("resource://testing-common/httpd.js");
 Cu.import("resource:///modules/experiments/Experiments.jsm");
 
 const FILE_MANIFEST            = "experiments.manifest";
-const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
-const PREF_LOGGING_LEVEL       = "experiments.logging.level";
-const PREF_LOGGING_DUMP        = "experiments.logging.dump";
-const PREF_MANIFEST_URI        = "experiments.manifest.uri";
-
 const SEC_IN_ONE_DAY  = 24 * 60 * 60;
 const MS_IN_ONE_DAY   = SEC_IN_ONE_DAY * 1000;
 
 let gProfileDir = null;
 let gHttpServer = null;
 let gHttpRoot   = null;
 let gReporter   = null;
 let gPolicy     = null;
--- a/browser/experiments/test/xpcshell/test_api.js
+++ b/browser/experiments/test/xpcshell/test_api.js
@@ -5,22 +5,16 @@
 
 Cu.import("resource://testing-common/httpd.js");
 Cu.import("resource://testing-common/AddonManagerTesting.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
   "resource:///modules/experiments/Experiments.jsm");
 
 const FILE_MANIFEST            = "experiments.manifest";
-const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
-const PREF_LOGGING_LEVEL       = "experiments.logging.level";
-const PREF_LOGGING_DUMP        = "experiments.logging.dump";
-const PREF_MANIFEST_URI        = "experiments.manifest.uri";
-const PREF_FETCHINTERVAL       = "experiments.manifest.fetchIntervalSeconds";
-
 const MANIFEST_HANDLER         = "manifests/handler";
 
 const SEC_IN_ONE_DAY  = 24 * 60 * 60;
 const MS_IN_ONE_DAY   = SEC_IN_ONE_DAY * 1000;
 
 let gProfileDir          = null;
 let gHttpServer          = null;
 let gHttpRoot            = null;
--- a/browser/experiments/test/xpcshell/test_cache.js
+++ b/browser/experiments/test/xpcshell/test_cache.js
@@ -3,22 +3,16 @@
 
 "use strict";
 
 Cu.import("resource://testing-common/httpd.js");
 XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
   "resource:///modules/experiments/Experiments.jsm");
 
 const FILE_MANIFEST            = "experiments.manifest";
-const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
-const PREF_LOGGING_LEVEL       = "experiments.logging.level";
-const PREF_LOGGING_DUMP        = "experiments.logging.dump";
-const PREF_MANIFEST_URI        = "experiments.manifest.uri";
-const PREF_FETCHINTERVAL       = "experiments.manifest.fetchIntervalSeconds";
-
 const MANIFEST_HANDLER         = "manifests/handler";
 
 const SEC_IN_ONE_DAY  = 24 * 60 * 60;
 const MS_IN_ONE_DAY   = SEC_IN_ONE_DAY * 1000;
 
 let gProfileDir          = null;
 let gHttpServer          = null;
 let gHttpRoot            = null;
--- a/browser/experiments/test/xpcshell/test_conditions.js
+++ b/browser/experiments/test/xpcshell/test_conditions.js
@@ -2,21 +2,16 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 
 Cu.import("resource:///modules/experiments/Experiments.jsm");
 
 const FILE_MANIFEST            = "experiments.manifest";
-const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
-const PREF_LOGGING_LEVEL       = "experiments.logging.level";
-const PREF_LOGGING_DUMP        = "experiments.logging.dump";
-const PREF_MANIFEST_URI        = "experiments.manifest.uri";
-
 const SEC_IN_ONE_DAY = 24 * 60 * 60;
 const MS_IN_ONE_DAY  = SEC_IN_ONE_DAY * 1000;
 
 let gProfileDir = null;
 let gHttpServer = null;
 let gHttpRoot   = null;
 let gReporter   = null;
 let gPolicy     = null;
--- a/browser/experiments/test/xpcshell/test_disableExperiments.js
+++ b/browser/experiments/test/xpcshell/test_disableExperiments.js
@@ -5,22 +5,16 @@
 
 Cu.import("resource://testing-common/httpd.js");
 Cu.import("resource://testing-common/AddonManagerTesting.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
   "resource:///modules/experiments/Experiments.jsm");
 
 const FILE_MANIFEST            = "experiments.manifest";
-const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
-const PREF_LOGGING_LEVEL       = "experiments.logging.level";
-const PREF_LOGGING_DUMP        = "experiments.logging.dump";
-const PREF_MANIFEST_URI        = "experiments.manifest.uri";
-const PREF_FETCHINTERVAL       = "experiments.manifest.fetchIntervalSeconds";
-
 const MANIFEST_HANDLER         = "manifests/handler";
 
 const SEC_IN_ONE_DAY  = 24 * 60 * 60;
 const MS_IN_ONE_DAY   = SEC_IN_ONE_DAY * 1000;
 
 let gProfileDir          = null;
 let gHttpServer          = null;
 let gHttpRoot            = null;
--- a/browser/experiments/test/xpcshell/test_fetch.js
+++ b/browser/experiments/test/xpcshell/test_fetch.js
@@ -3,22 +3,16 @@
 
 "use strict";
 
 Cu.import("resource://testing-common/httpd.js");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource:///modules/experiments/Experiments.jsm");
 
-const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
-const PREF_LOGGING_LEVEL       = "experiments.logging.level";
-const PREF_LOGGING_DUMP        = "experiments.logging.dump";
-const PREF_MANIFEST_URI        = "experiments.manifest.uri";
-
-
 let gProfileDir = null;
 let gHttpServer = null;
 let gHttpRoot   = null;
 let gPolicy     = new Experiments.Policy();
 
 function run_test() {
   loadAddonManager();
   gProfileDir = do_get_profile();
--- a/browser/experiments/test/xpcshell/test_healthreport.js
+++ b/browser/experiments/test/xpcshell/test_healthreport.js
@@ -22,20 +22,26 @@ function getStorageAndProvider(name) {
 function run_test() {
   run_next_test();
 }
 
 add_test(function setup() {
   do_get_profile();
   initTestLogging();
 
+  Services.prefs.setBoolPref(PREF_EXPERIMENTS_ENABLED, true);
+  Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true);
+  Services.prefs.setBoolPref(PREF_HEALTHREPORT_ENABLED, true);
+
   run_next_test();
 });
 
 add_task(function test_constructor() {
+  Experiments.instance();
+  yield Experiments._mainTask;
   let provider = new ExperimentsProvider();
 });
 
 add_task(function* test_init() {
   let storage = yield Metrics.Storage("init");
   let provider = new ExperimentsProvider();
   yield provider.init(storage);
   yield provider.shutdown();
--- a/browser/experiments/test/xpcshell/test_telemetry.js
+++ b/browser/experiments/test/xpcshell/test_telemetry.js
@@ -5,22 +5,16 @@
 
 Cu.import("resource://testing-common/httpd.js");
 Cu.import("resource://gre/modules/TelemetryLog.jsm");
 Cu.import("resource://gre/modules/TelemetryPing.jsm");
 Cu.import("resource:///modules/experiments/Experiments.jsm");
 
 
 const FILE_MANIFEST            = "experiments.manifest";
-const PREF_EXPERIMENTS_ENABLED = "experiments.enabled";
-const PREF_LOGGING_LEVEL       = "experiments.logging.level";
-const PREF_LOGGING_DUMP        = "experiments.logging.dump";
-const PREF_MANIFEST_URI        = "experiments.manifest.uri";
-const PREF_FETCHINTERVAL       = "experiments.manifest.fetchIntervalSeconds";
-
 const MANIFEST_HANDLER         = "manifests/handler";
 
 const SEC_IN_ONE_DAY  = 24 * 60 * 60;
 const MS_IN_ONE_DAY   = SEC_IN_ONE_DAY * 1000;
 
 
 let gProfileDir          = null;
 let gHttpServer          = null;
--- a/browser/themes/linux/preferences/in-content/preferences.css
+++ b/browser/themes/linux/preferences/in-content/preferences.css
@@ -16,48 +16,40 @@ button[type="menu"] > .button-box > .but
 menulist:not([editable="true"]) > .menulist-dropmarker {
   display: -moz-box;
   margin-top: 6px;
   margin-bottom: 6px;
 }
 
 checkbox {
   -moz-binding: url("chrome://global/content/bindings/checkbox.xml#checkbox");
-}
-
-.checkbox-check {
-  max-height: 23px;
+  -moz-box-align: center;
 }
 
 checkbox:hover::before,
 checkbox[checked]::before {
-  max-height: 10px;
   margin-top: 7px;
   margin-bottom: 6px;
   -moz-margin-end: -19px;
   -moz-margin-start: 4px;
   background-repeat: no-repeat;
 }
 
 radio {
   -moz-binding: url("chrome://global/content/bindings/radio.xml#radio");
+  -moz-box-align: center;
   margin: 7px 0;
 }
 
-.radio-check {
-  max-height: 23px;
-}
-
 .radio-label-box {
   -moz-appearance: none;
 }
 
 radio:hover::before,
 radio[selected]::before {
-  max-height: 11px;
   margin-top: 6px;
   margin-bottom: 6px;
   -moz-margin-end: -17px;
   -moz-margin-start: 6px;
 }
 
 .numberbox-input-box {
   -moz-appearance: none;
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/BrowserLocaleManager.java
@@ -0,0 +1,285 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.util.Log;
+
+import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * This class manages persistence, application, and otherwise handling of
+ * user-specified locales.
+ *
+ * Of note:
+ *
+ * * It's a singleton, because its scope extends to that of the application,
+ *   and definitionally all changes to the locale of the app must go through
+ *   this.
+ * * It's lazy.
+ * * It has ties into the Gecko event system, because it has to tell Gecko when
+ *   to switch locale.
+ * * It relies on using the SharedPreferences file owned by the browser (in
+ *   Fennec's case, "GeckoApp") for performance.
+ */
+public class BrowserLocaleManager implements LocaleManager {
+    private static final String LOG_TAG = "GeckoLocales";
+
+    private static final String EVENT_LOCALE_CHANGED = "Locale:Changed";
+    private static final String PREF_LOCALE = "locale";
+
+    // This is volatile because we don't impose restrictions
+    // over which thread calls our methods.
+    private volatile Locale currentLocale = null;
+
+    private AtomicBoolean inited = new AtomicBoolean(false);
+    private boolean systemLocaleDidChange = false;
+    private BroadcastReceiver receiver;
+
+    private static AtomicReference<LocaleManager> instance = new AtomicReference<LocaleManager>();
+
+    public static LocaleManager getInstance() {
+        LocaleManager localeManager = instance.get();
+        if (localeManager != null) {
+            return localeManager;
+        }
+
+        localeManager = new BrowserLocaleManager();
+        if (instance.compareAndSet(null, localeManager)) {
+            return localeManager;
+        } else {
+            return instance.get();
+        }
+    }
+
+    /**
+     * Gecko uses locale codes like "es-ES", whereas a Java {@link Locale}
+     * stringifies as "es_ES".
+     *
+     * This method approximates the Java 7 method <code>Locale#toLanguageTag()</code>.
+     *
+     * @return a locale string suitable for passing to Gecko.
+     */
+    public static String getLanguageTag(final Locale locale) {
+        // If this were Java 7:
+        // return locale.toLanguageTag();
+
+        String language = locale.getLanguage();  // Can, but should never be, an empty string.
+        // Modernize certain language codes.
+        if (language.equals("iw")) {
+            language = "he";
+        } else if (language.equals("in")) {
+            language = "id";
+        } else if (language.equals("ji")) {
+            language = "yi";
+        }
+
+        String country = locale.getCountry();    // Can be an empty string.
+        if (country.equals("")) {
+            return language;
+        }
+        return language + "-" + country;
+    }
+
+    private static Locale parseLocaleCode(final String localeCode) {
+        int index;
+        if ((index = localeCode.indexOf('-')) != -1 ||
+            (index = localeCode.indexOf('_')) != -1) {
+            final String langCode = localeCode.substring(0, index);
+            final String countryCode = localeCode.substring(index + 1);
+            return new Locale(langCode, countryCode);
+        } else {
+            return new Locale(localeCode);
+        }
+    }
+
+    /**
+     * Ensure that you call this early in your application startup,
+     * and with a context that's sufficiently long-lived (typically
+     * the application context).
+     *
+     * Calling multiple times is harmless.
+     */
+    @Override
+    public void initialize(final Context context) {
+        if (!inited.compareAndSet(false, true)) {
+            return;
+        }
+
+        receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                systemLocaleDidChange = true;
+            }
+        };
+        context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
+    }
+
+    @Override
+    public boolean systemLocaleDidChange() {
+        return systemLocaleDidChange;
+    }
+
+    /**
+     * Every time the system gives us a new configuration, it
+     * carries the external locale. Fix it.
+     */
+    @Override
+    public void correctLocale(Context context, Resources res, Configuration config) {
+        final Locale current = getCurrentLocale(context);
+        if (current == null) {
+            return;
+        }
+
+        // I know it's tempting to short-circuit here if the config seems to be
+        // up-to-date, but the rest is necessary.
+
+        config.locale = current;
+
+        // The following two lines are heavily commented in case someone
+        // decides to chase down performance improvements and decides to
+        // question what's going on here.
+        // Both lines should be cheap, *but*...
+
+        // This is unnecessary for basic string choice, but it almost
+        // certainly comes into play when rendering numbers, deciding on RTL,
+        // etc. Take it out if you can prove that's not the case.
+        Locale.setDefault(current);
+
+        // This seems to be a no-op, but every piece of documentation under the
+        // sun suggests that it's necessary, and it certainly makes sense.
+        res.updateConfiguration(config, res.getDisplayMetrics());
+    }
+
+    @Override
+    public String getAndApplyPersistedLocale(Context context) {
+        initialize(context);
+
+        final long t1 = android.os.SystemClock.uptimeMillis();
+        final String localeCode = getPersistedLocale(context);
+        if (localeCode == null) {
+            return null;
+        }
+
+        // Note that we don't tell Gecko about this. We notify Gecko when the
+        // locale is set, not when we update Java.
+        final String resultant = updateLocale(context, localeCode);
+
+        if (resultant == null) {
+            // Update the configuration anyway.
+            updateConfiguration(context, currentLocale);
+        }
+
+        final long t2 = android.os.SystemClock.uptimeMillis();
+        Log.i(LOG_TAG, "Locale read and update took: " + (t2 - t1) + "ms.");
+        return resultant;
+    }
+
+    /**
+     * Returns the set locale if it changed.
+     *
+     * Always persists and notifies Gecko.
+     */
+    @Override
+    public String setSelectedLocale(Context context, String localeCode) {
+        final String resultant = updateLocale(context, localeCode);
+
+        // We always persist and notify Gecko, even if nothing seemed to
+        // change. This might happen if you're picking a locale that's the same
+        // as the current OS locale. The OS locale might change next time we
+        // launch, and we need the Gecko pref and persisted locale to have been
+        // set by the time that happens.
+        persistLocale(context, localeCode);
+
+        // Tell Gecko.
+        GeckoEvent ev = GeckoEvent.createBroadcastEvent(EVENT_LOCALE_CHANGED, BrowserLocaleManager.getLanguageTag(getCurrentLocale(context)));
+        GeckoAppShell.sendEventToGecko(ev);
+
+        return resultant;
+    }
+
+    /**
+     * This is public to allow for an activity to force the
+     * current locale to be applied if necessary (e.g., when
+     * a new activity launches).
+     */
+    @Override
+    public void updateConfiguration(Context context, Locale locale) {
+        Resources res = context.getResources();
+        Configuration config = res.getConfiguration();
+        config.locale = locale;
+        res.updateConfiguration(config, res.getDisplayMetrics());
+    }
+
+    private SharedPreferences getSharedPreferences(Context context) {
+        return GeckoSharedPrefs.forApp(context);
+    }
+
+    private String getPersistedLocale(Context context) {
+        final SharedPreferences settings = getSharedPreferences(context);
+        final String locale = settings.getString(PREF_LOCALE, "");
+
+        if ("".equals(locale)) {
+            return null;
+        }
+        return locale;
+    }
+
+    private void persistLocale(Context context, String localeCode) {
+        final SharedPreferences settings = getSharedPreferences(context);
+        settings.edit().putString(PREF_LOCALE, localeCode).commit();
+    }
+
+    private Locale getCurrentLocale(Context context) {
+        if (currentLocale != null) {
+            return currentLocale;
+        }
+
+        final String current = getPersistedLocale(context);
+        if (current == null) {
+            return null;
+        }
+        return currentLocale = parseLocaleCode(current);
+    }
+
+    /**
+     * Updates the Java locale and the Android configuration.
+     *
+     * Returns the persisted locale if it differed.
+     *
+     * Does not notify Gecko.
+     */
+    private String updateLocale(Context context, String localeCode) {
+        // Fast path.
+        final Locale defaultLocale = Locale.getDefault();
+        if (defaultLocale.toString().equals(localeCode)) {
+            return null;
+        }
+
+        final Locale locale = parseLocaleCode(localeCode);
+
+        // Fast path.
+        if (defaultLocale.equals(locale)) {
+            return null;
+        }
+
+        Locale.setDefault(locale);
+        currentLocale = locale;
+
+        // Update resources.
+        updateConfiguration(context, locale);
+
+        return locale.toString();
+    }
+}
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -1253,17 +1253,17 @@ public abstract class GeckoApp
             Log.e(LOGTAG, "Exception starting favicon cache. Corrupt resources?", e);
         }
 
         // Did the OS locale change while we were backgrounded? If so,
         // we need to die so that Gecko will re-init add-ons that touch
         // the UI.
         // This is using a sledgehammer to crack a nut, but it'll do for
         // now.
-        if (LocaleManager.systemLocaleDidChange()) {
+        if (BrowserLocaleManager.getInstance().systemLocaleDidChange()) {
             Log.i(LOGTAG, "System locale changed. Restarting.");
             doRestart();
             GeckoAppShell.systemExit();
             return;
         }
 
         if (GeckoThread.isCreated()) {
             // This happens when the GeckoApp activity is destroyed by Android
@@ -1331,18 +1331,18 @@ public abstract class GeckoApp
 
         // Perform background initialization.
         ThreadUtils.postToBackgroundThread(new Runnable() {
             @Override
             public void run() {
                 final SharedPreferences prefs = GeckoApp.this.getSharedPreferences();
 
                 // Wait until now to set this, because we'd rather throw an exception than 
-                // have a caller of LocaleManager regress startup.
-                LocaleManager.initialize(getApplicationContext());
+                // have a caller of BrowserLocaleManager regress startup.
+                BrowserLocaleManager.getInstance().initialize(getApplicationContext());
 
                 SessionInformation previousSession = SessionInformation.fromSharedPrefs(prefs);
                 if (previousSession.wasKilled()) {
                     Telemetry.HistogramAdd("FENNEC_WAS_KILLED", 1);
                 }
 
                 SharedPreferences.Editor editor = prefs.edit();
                 editor.putBoolean(GeckoApp.PREFS_OOM_EXCEPTION, false);
@@ -1356,17 +1356,17 @@ public abstract class GeckoApp
                 // The lifecycle of mHealthRecorder is "shortly after onCreate"
                 // through "onDestroy" -- essentially the same as the lifecycle
                 // of the activity itself.
                 final String profilePath = getProfile().getDir().getAbsolutePath();
                 final EventDispatcher dispatcher = GeckoAppShell.getEventDispatcher();
                 Log.i(LOGTAG, "Creating HealthRecorder.");
 
                 final String osLocale = Locale.getDefault().toString();
-                String appLocale = LocaleManager.getAndApplyPersistedLocale(GeckoApp.this);
+                String appLocale = BrowserLocaleManager.getInstance().getAndApplyPersistedLocale(GeckoApp.this);
                 Log.d(LOGTAG, "OS locale is " + osLocale + ", app locale is " + appLocale);
 
                 if (appLocale == null) {
                     appLocale = osLocale;
                 }
 
                 mHealthRecorder = GeckoApp.this.createHealthRecorder(GeckoApp.this,
                                                                      profilePath,
@@ -2204,17 +2204,17 @@ public abstract class GeckoApp
         for (File file : files) {
             file.delete();
         }
     }
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         Log.d(LOGTAG, "onConfigurationChanged: " + newConfig.locale);
-        LocaleManager.correctLocale(this, getResources(), newConfig);
+        BrowserLocaleManager.getInstance().correctLocale(this, getResources(), newConfig);
 
         // onConfigurationChanged is not called for 180 degree orientation changes,
         // we will miss such rotations and the screen orientation will not be
         // updated.
         if (GeckoScreenOrientation.getInstance().update(newConfig.orientation)) {
             if (mFormAssistPopup != null)
                 mFormAssistPopup.hide();
             refreshChrome();
@@ -2796,24 +2796,24 @@ public abstract class GeckoApp
         // return (flags & android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE) != 0;
     }
 
     // FHR reason code for a session end prior to a restart for a
     // locale change.
     private static final String SESSION_END_LOCALE_CHANGED = "L";
 
     /**
-     * Use LocaleManager to change our persisted and current locales,
+     * Use BrowserLocaleManager to change our persisted and current locales,
      * and poke HealthRecorder to tell it of our changed state.
      */
     private void setLocale(final String locale) {
         if (locale == null) {
             return;
         }
-        final String resultant = LocaleManager.setSelectedLocale(this, locale);
+        final String resultant = BrowserLocaleManager.getInstance().setSelectedLocale(this, locale);
         if (resultant == null) {
             return;
         }
 
         final boolean startNewSession = true;
         final boolean shouldRestart = false;
 
         // If the HealthRecorder is not yet initialized (unlikely), the locale change won't
--- a/mobile/android/base/GeckoApplication.java
+++ b/mobile/android/base/GeckoApplication.java
@@ -62,19 +62,19 @@ public class GeckoApplication extends Ap
         if (mInBackground) {
             super.onConfigurationChanged(config);
             return;
         }
 
         // Otherwise, correct the locale. This catches some cases that GeckoApp
         // doesn't get a chance to.
         try {
-            LocaleManager.correctLocale(this, getResources(), config);
+            BrowserLocaleManager.getInstance().correctLocale(this, getResources(), config);
         } catch (IllegalStateException ex) {
-            // GeckoApp hasn't started, so we have no ContextGetter in LocaleManager.
+            // GeckoApp hasn't started, so we have no ContextGetter in BrowserLocaleManager.
             Log.w(LOG_TAG, "Couldn't correct locale.", ex);
         }
 
         super.onConfigurationChanged(config);
     }
 
     public void onActivityPause(GeckoActivityStatus activity) {
         mInBackground = true;
--- a/mobile/android/base/LocaleManager.java
+++ b/mobile/android/base/LocaleManager.java
@@ -1,248 +1,20 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.util.Log;
-
 import java.util.Locale;
 
-/**
- * This class manages persistence, application, and otherwise handling of
- * user-specified locales.
- *
- * Of note:
- * 
- * * It's a singleton, because its scope extends to that of the application,
- *   and definitionally all changes to the locale of the app must go through
- *   this.
- * * It's lazy.
- * * It has ties into the Gecko event system, because it has to tell Gecko when
- *   to switch locale.
- * * It relies on using the SharedPreferences file owned by the browser (in
- *   Fennec's case, "GeckoApp") for performance.
- */
-public class LocaleManager {
-    private static final String LOG_TAG = "GeckoLocales";
-    private static final String PREF_LOCALE = "locale";
-
-    // This is volatile because we don't impose restrictions
-    // over which thread calls our methods.
-    private static volatile Locale currentLocale = null;
-
-    private static volatile boolean inited = false;
-    private static boolean systemLocaleDidChange = false;
-    private static BroadcastReceiver receiver;
-
-    /**
-     * Ensure that you call this early in your application startup,
-     * and with a context that's sufficiently long-lived (typically
-     * the application context).
-     *
-     * Calling multiple times is harmless.
-     */
-    public static void initialize(final Context context) {
-        if (inited) {
-            return;
-        }
-
-        receiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                systemLocaleDidChange = true;
-            }
-        };
-        context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
-        inited = true;
-    }
-
-    public static boolean systemLocaleDidChange() {
-        return systemLocaleDidChange;
-    }
-
-    /**
-     * Every time the system gives us a new configuration, it
-     * carries the external locale. Fix it.
-     */
-    public static void correctLocale(Context context, Resources res, Configuration config) {
-        final Locale current = getCurrentLocale(context);
-        if (current == null) {
-            return;
-        }
-
-        // I know it's tempting to short-circuit here if the config seems to be
-        // up-to-date, but the rest is necessary.
-
-        config.locale = current;
-
-        // The following two lines are heavily commented in case someone
-        // decides to chase down performance improvements and decides to
-        // question what's going on here.
-        // Both lines should be cheap, *but*...
-
-        // This is unnecessary for basic string choice, but it almost
-        // certainly comes into play when rendering numbers, deciding on RTL,
-        // etc. Take it out if you can prove that's not the case.
-        Locale.setDefault(current);
-
-        // This seems to be a no-op, but every piece of documentation under the
-        // sun suggests that it's necessary, and it certainly makes sense.
-        res.updateConfiguration(config, res.getDisplayMetrics());
-    }
-
-    private static Locale parseLocaleCode(final String localeCode) {
-        int index;
-        if ((index = localeCode.indexOf('-')) != -1 ||
-            (index = localeCode.indexOf('_')) != -1) {
-            final String langCode = localeCode.substring(0, index);
-            final String countryCode = localeCode.substring(index + 1);
-            return new Locale(langCode, countryCode);
-        } else {
-            return new Locale(localeCode);
-        }
-    }
-
-    /**
-     * Gecko uses locale codes like "es-ES", whereas a Java {@link Locale}
-     * stringifies as "es_ES".
-     *
-     * This method approximates the Java 7 method <code>Locale#toLanguageTag()</code>.
-     *
-     * @return a locale string suitable for passing to Gecko.
-     */
-    public static String getLanguageTag(final Locale locale) {
-        // If this were Java 7:
-        // return locale.toLanguageTag();
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 
-        String language = locale.getLanguage();  // Can, but should never be, an empty string.
-        // Modernize certain language codes.
-        if (language.equals("iw")) {
-            language = "he";
-        } else if (language.equals("in")) {
-            language = "id";
-        } else if (language.equals("ji")) {
-            language = "yi";
-        }
-
-        String country = locale.getCountry();    // Can be an empty string.
-        if (country.equals("")) {
-            return language;
-        }
-        return language + "-" + country;
-    }
-
-    public static Locale getCurrentLocale(Context context) {
-        if (currentLocale != null) {
-            return currentLocale;
-        }
-
-        final String current = getPersistedLocale(context);
-        if (current == null) {
-            return null;
-        }
-        return currentLocale = parseLocaleCode(current);
-    }
-
-    /**
-     * Updates the Java locale and the Android configuration.
-     *
-     * Returns the persisted locale if it differed.
-     *
-     * Does not notify Gecko.
-     */
-    private static String updateLocale(Context context, String localeCode) {
-        // Fast path.
-        final Locale defaultLocale = Locale.getDefault();
-        if (defaultLocale.toString().equals(localeCode)) {
-            return null;
-        }
-
-        final Locale locale = parseLocaleCode(localeCode);
-
-        // Fast path.
-        if (defaultLocale.equals(locale)) {
-            return null;
-        }
-
-        Locale.setDefault(locale);
-        currentLocale = locale;
-
-        // Update resources.
-        Resources res = context.getResources();
-        Configuration config = res.getConfiguration();
-        config.locale = locale;
-        res.updateConfiguration(config, res.getDisplayMetrics());
-
-        return locale.toString();
-    }
-
-    public static void notifyGeckoOfLocaleChange(Locale locale) {
-        // Tell Gecko.
-        GeckoEvent ev = GeckoEvent.createBroadcastEvent("Locale:Changed", getLanguageTag(locale));
-        GeckoAppShell.sendEventToGecko(ev);
-    }
-
-    public static String getPersistedLocale(Context context) {
-        final SharedPreferences settings = getSharedPreferences(context);
-        final String locale = settings.getString(PREF_LOCALE, "");
-
-        if ("".equals(locale)) {
-            return null;
-        }
-        return locale;
-    }
-
-    private static void persistLocale(Context context, String localeCode) {
-        final SharedPreferences settings = getSharedPreferences(context);
-        settings.edit().putString(PREF_LOCALE, localeCode).commit();
-    }
-
-    private static SharedPreferences getSharedPreferences(Context context) {
-        // TODO: this should be per-profile, but we don't want to pay the price.
-        return GeckoSharedPrefs.forApp(context);
-    }
-
-    public static String getAndApplyPersistedLocale(Context context) {
-        final long t1 = android.os.SystemClock.uptimeMillis();
-        final String localeCode = getPersistedLocale(context);
-        if (localeCode == null) {
-            return null;
-        }
-
-        // Note that we don't tell Gecko about this. We notify Gecko when the
-        // locale is set, not when we update Java.
-        final String resultant = updateLocale(context, localeCode);
-
-        final long t2 = android.os.SystemClock.uptimeMillis();
-        Log.i(LOG_TAG, "Locale read and update took: " + (t2 - t1) + "ms.");
-        return resultant;
-    }
-
-    /**
-     * Returns the set locale if it changed.
-     *
-     * Always persists and notifies Gecko.
-     */
-    public static String setSelectedLocale(Context context, String localeCode) {
-        final String resultant = updateLocale(context, localeCode);
-
-        // We always persist and notify Gecko, even if nothing seemed to
-        // change. This might happen if you're picking a locale that's the same
-        // as the current OS locale. The OS locale might change next time we
-        // launch, and we need the Gecko pref and persisted locale to have been
-        // set by the time that happens.
-        persistLocale(context, localeCode);
-        notifyGeckoOfLocaleChange(getCurrentLocale(context));
-        return resultant;
-    }
+public interface LocaleManager {
+    void initialize(Context context);
+    String getAndApplyPersistedLocale(Context context);
+    void correctLocale(Context context, Resources resources, Configuration newConfig);
+    void updateConfiguration(Context context, Locale locale);
+    String setSelectedLocale(Context context, String localeCode);
+    boolean systemLocaleDidChange();
 }
-
--- a/mobile/android/base/android-services.mozbuild
+++ b/mobile/android/base/android-services.mozbuild
@@ -769,16 +769,17 @@ sync_java_files = [
     'sync/repositories/StoreFailedException.java',
     'sync/repositories/StoreTracker.java',
     'sync/repositories/StoreTrackingRepositorySession.java',
     'sync/Server11PreviousPostFailedException.java',
     'sync/Server11RecordPostFailedException.java',
     'sync/setup/activities/AccountActivity.java',
     'sync/setup/activities/ActivityUtils.java',
     'sync/setup/activities/ClientRecordArrayAdapter.java',
+    'sync/setup/activities/LocaleAware.java',
     'sync/setup/activities/RedirectToSetupActivity.java',
     'sync/setup/activities/SendTabActivity.java',
     'sync/setup/activities/SendTabData.java',
     'sync/setup/activities/SetupFailureActivity.java',
     'sync/setup/activities/SetupSuccessActivity.java',
     'sync/setup/activities/SetupSyncActivity.java',
     'sync/setup/activities/SyncActivity.java',
     'sync/setup/activities/WebURLFinder.java',
--- a/mobile/android/base/background/announcements/AnnouncementsService.java
+++ b/mobile/android/base/background/announcements/AnnouncementsService.java
@@ -5,16 +5,17 @@
 package org.mozilla.gecko.background.announcements;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.net.URI;
 import java.util.List;
 import java.util.Locale;
 
+import org.mozilla.gecko.BrowserLocaleManager;
 import org.mozilla.gecko.background.BackgroundService;
 import org.mozilla.gecko.background.common.GlobalConstants;
 import org.mozilla.gecko.background.common.log.Logger;
 
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.IBinder;
 
@@ -123,16 +124,20 @@ public class AnnouncementsService extend
       return;
     }
 
     if (!shouldFetchAnnouncements()) {
       Logger.debug(LOG_TAG, "Not fetching.");
       return;
     }
 
+    // Ensure that our locale is up to date, so that the fetcher's
+    // Accept-Language header is, too.
+    BrowserLocaleManager.getInstance().getAndApplyPersistedLocale(getApplicationContext());
+
     // Otherwise, grab our announcements URL and process the contents.
     AnnouncementsFetcher.fetchAndProcessAnnouncements(getLastLaunch(), this);
   }
 
   @Override
   public IBinder onBind(Intent intent) {
     return null;
   }
--- a/mobile/android/base/background/healthreport/HealthReportGenerator.java
+++ b/mobile/android/base/background/healthreport/HealthReportGenerator.java
@@ -31,22 +31,26 @@ public class HealthReportGenerator {
   }
 
   @SuppressWarnings("static-method")
   protected long now() {
     return System.currentTimeMillis();
   }
 
   /**
+   * Ensure that you have initialized the Locale to your satisfaction
+   * prior to calling this method.
+   *
    * @return null if no environment could be computed, or else the resulting document.
    * @throws JSONException if there was an error adding environment data to the resulting document.
    */
   public JSONObject generateDocument(long since, long lastPingTime, String profilePath) throws JSONException {
     Logger.info(LOG_TAG, "Generating FHR document from " + since + "; last ping " + lastPingTime);
     Logger.pii(LOG_TAG, "Generating for profile " + profilePath);
+
     ProfileInformationCache cache = new ProfileInformationCache(profilePath);
     if (!cache.restoreUnlessInitialized()) {
       Logger.warn(LOG_TAG, "Not enough profile information to compute current environment.");
       return null;
     }
     Environment current = EnvironmentBuilder.getCurrentEnvironment(cache);
     return generateDocument(since, lastPingTime, current);
   }
--- a/mobile/android/base/background/healthreport/upload/AndroidSubmissionClient.java
+++ b/mobile/android/base/background/healthreport/upload/AndroidSubmissionClient.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko.background.hea
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collection;
 
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.mozilla.gecko.BrowserLocaleManager;
 import org.mozilla.gecko.background.bagheera.BagheeraClient;
 import org.mozilla.gecko.background.bagheera.BagheeraRequestDelegate;
 import org.mozilla.gecko.background.common.GlobalConstants;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.healthreport.Environment;
 import org.mozilla.gecko.background.healthreport.EnvironmentBuilder;
 import org.mozilla.gecko.background.healthreport.HealthReportConstants;
 import org.mozilla.gecko.background.healthreport.HealthReportDatabaseStorage;
@@ -394,16 +395,20 @@ public class AndroidSubmissionClient imp
     public class TrackingGenerator extends HealthReportGenerator {
       public TrackingGenerator() {
         super(storage);
       }
 
       @Override
       public JSONObject generateDocument(long since, long lastPingTime,
           String generationProfilePath) throws JSONException {
+
+        // Let's make sure we have an accurate locale.
+        BrowserLocaleManager.getInstance().getAndApplyPersistedLocale(context);
+
         final JSONObject document;
         // If the given profilePath matches the one we cached for the tracker, use the cached env.
         if (profilePath != null && profilePath.equals(generationProfilePath)) {
           final Environment environment = getCurrentEnvironment();
           document = super.generateDocument(since, lastPingTime, environment);
         } else {
           document = super.generateDocument(since, lastPingTime, generationProfilePath);
         }
--- a/mobile/android/base/db/BrowserDB.java
+++ b/mobile/android/base/db/BrowserDB.java
@@ -2,28 +2,25 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.db;
 
 import java.util.List;
 
-import org.mozilla.gecko.db.BrowserContract.Bookmarks;
 import org.mozilla.gecko.db.BrowserContract.ExpirePriority;
 import org.mozilla.gecko.favicons.decoders.LoadFaviconResult;
 import org.mozilla.gecko.mozglue.RobocopTarget;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.database.ContentObserver;
 import android.database.Cursor;
-import android.database.CursorWrapper;
 import android.graphics.drawable.BitmapDrawable;
-import android.util.SparseArray;
 
 public class BrowserDB {
     private static boolean sAreContentProvidersEnabled = true;
 
     public static interface URLColumns {
         public static String URL = "url";
         public static String TITLE = "title";
         public static String FAVICON = "favicon";
@@ -353,188 +350,9 @@ public class BrowserDB {
 
     public static boolean areContentProvidersDisabled() {
         return sAreContentProvidersEnabled;
     }
 
     public static void setEnableContentProviders(boolean enableContentProviders) {
         sAreContentProvidersEnabled = enableContentProviders;
     }
-
-    public static class PinnedSite {
-        public String title = "";
-        public String url = "";
-
-        public PinnedSite(String aTitle, String aUrl) {
-            title = aTitle;
-            url = aUrl;
-        }
-    }
-
-    /* Cursor wrapper that forces top sites to contain at least
-     * mNumberOfTopSites entries. For rows outside the wrapped cursor
-     * will return empty strings and zero.
-     */
-    public static class TopSitesCursorWrapper extends CursorWrapper {
-        int mIndex = -1; // Current position of the cursor
-        Cursor mCursor = null;
-        int mSize = 0;
-        private SparseArray<PinnedSite> mPinnedSites = null;
-
-        public TopSitesCursorWrapper(Cursor pinnedCursor, Cursor normalCursor, int minSize) {
-            super(normalCursor);
-
-            setPinnedSites(pinnedCursor);
-            mCursor = normalCursor;
-            mSize = Math.max(minSize, mPinnedSites.size() + mCursor.getCount());
-        }
-
-        public void setPinnedSites(Cursor c) {
-            mPinnedSites = new SparseArray<PinnedSite>();
-
-            if (c == null) {
-                return;
-            }
-
-            try {
-                if (c.getCount() <= 0) {
-                    return;
-                }
-                c.moveToPosition(0);
-                do {
-                    int pos = c.getInt(c.getColumnIndex(Bookmarks.POSITION));
-                    String url = c.getString(c.getColumnIndex(URLColumns.URL));
-                    String title = c.getString(c.getColumnIndex(URLColumns.TITLE));
-                    mPinnedSites.put(pos, new PinnedSite(title, url));
-                } while (c.moveToNext());
-            } finally {
-                c.close();
-            }
-        }
-
-        public boolean hasPinnedSites() {
-            return mPinnedSites != null && mPinnedSites.size() > 0;
-        }
-
-        public PinnedSite getPinnedSite(int position) {
-            if (!hasPinnedSites()) {
-                return null;
-            }
-            return mPinnedSites.get(position);
-        }
-
-        public boolean isPinned() {
-            return mPinnedSites.get(mIndex) != null;
-        }
-
-        private int getPinnedBefore(int position) {
-            int numFound = 0;
-            if (!hasPinnedSites()) {
-                return numFound;
-            }
-
-            for (int i = 0; i < position; i++) {
-                if (mPinnedSites.get(i) != null) {
-                    numFound++;
-                }
-            }
-
-            return numFound;
-        }
-
-        @Override
-        public int getPosition() { return mIndex; }
-        @Override
-        public int getCount() { return mSize; }
-        @Override
-        public boolean isAfterLast() { return mIndex >= mSize; }
-        @Override
-        public boolean isBeforeFirst() { return mIndex < 0; }
-        @Override
-        public boolean isLast() { return mIndex == mSize - 1; }
-        @Override
-        public boolean moveToNext() { return moveToPosition(mIndex + 1); }
-        @Override
-        public boolean moveToPrevious() { return moveToPosition(mIndex - 1); }
-
-        @Override
-        public boolean moveToPosition(int position) {
-            mIndex = position;
-
-            // Move the real cursor as if we were stepping through it to this position.
-            // Account for pinned sites, and be careful to update its position to the
-            // minimum or maximum position, even if we're moving beyond its bounds.
-            int before = getPinnedBefore(position);
-            int p2 = position - before;
-            if (p2 <= -1) {
-                super.moveToPosition(-1);
-            } else if (p2 >= mCursor.getCount()) {
-                super.moveToPosition(mCursor.getCount());
-            } else {
-                super.moveToPosition(p2);
-            }
-
-            return !(isBeforeFirst() || isAfterLast());
-        }
-
-        @Override
-        public long getLong(int columnIndex) {
-            if (hasPinnedSites()) {
-                PinnedSite site = getPinnedSite(mIndex);
-                if (site != null) {
-                    return 0;
-                }
-            }
-
-            if (!super.isBeforeFirst() && !super.isAfterLast())
-                return super.getLong(columnIndex);
-            return 0;
-        }
-
-        @Override
-        public int getInt(int columnIndex) {
-            if (hasPinnedSites()) {
-                PinnedSite site = getPinnedSite(mIndex);
-                if (site != null) {
-                    return 0;
-                }
-            }
-
-            if (!super.isBeforeFirst() && !super.isAfterLast())
-                return super.getInt(columnIndex);
-            return 0;
-        }
-
-        @Override
-        public String getString(int columnIndex) {
-            if (hasPinnedSites()) {
-                PinnedSite site = getPinnedSite(mIndex);
-                if (site != null) {
-                    if (columnIndex == mCursor.getColumnIndex(URLColumns.URL)) {
-                        return site.url;
-                    } else if (columnIndex == mCursor.getColumnIndex(URLColumns.TITLE)) {
-                        return site.title;
-                    }
-                    return "";
-                }
-            }
-
-            if (!super.isBeforeFirst() && !super.isAfterLast())
-                return super.getString(columnIndex);
-            return "";
-        }
-
-        @Override
-        public boolean move(int offset) {
-            return moveToPosition(mIndex + offset);
-        }
-
-        @Override
-        public boolean moveToFirst() {
-            return moveToPosition(0);
-        }
-
-        @Override
-        public boolean moveToLast() {
-            return moveToPosition(mSize-1);
-        }
-    }
 }
--- a/mobile/android/base/db/HomeProvider.java
+++ b/mobile/android/base/db/HomeProvider.java
@@ -1,23 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.db;
 
 import java.io.IOException;
-import java.io.InputStream;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.db.BrowserContract.HomeItems;
 import org.mozilla.gecko.sqlite.SQLiteBridge;
+import org.mozilla.gecko.util.RawResource;
 
 import android.content.ContentValues;
 import android.content.UriMatcher;
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.net.Uri;
 import android.util.Log;
 
@@ -78,17 +78,18 @@ public class HomeProvider extends SQLite
     }
 
     /**
      * Returns a cursor populated with static fake data.
      */
     private Cursor queryFakeItems(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
         JSONArray items = null;
         try {
-            items = new JSONArray(getRawFakeItems());
+            final String jsonString = RawResource.get(getContext(), R.raw.fake_home_items);
+            items = new JSONArray(jsonString);
         } catch (IOException e) {
             Log.e(LOGTAG, "Error getting fake home items", e);
             return null;
         } catch (JSONException e) {
             Log.e(LOGTAG, "Error parsing fake_home_items.json", e);
             return null;
         }
 
@@ -117,28 +118,16 @@ public class HomeProvider extends SQLite
                 });
             } catch (JSONException e) {
                 Log.e(LOGTAG, "Error creating cursor row for fake home item", e);
             }
         }
         return c;
     }
 
-    private String getRawFakeItems() throws IOException {
-        final InputStream inputStream = getContext().getResources().openRawResource(R.raw.fake_home_items);
-        final byte[] buffer = new byte[1024];
-        StringBuilder s = new StringBuilder();
-        int count;
-
-        while ((count = inputStream.read(buffer)) != -1) {
-            s.append(new String(buffer, 0, count));
-        }
-        return s.toString();
-    }
-
     /**
      * SQLiteBridgeContentProvider implementation
      */
 
     @Override
     protected String getDBName(){
         return DB_FILENAME;
     }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/db/TopSitesCursorWrapper.java
@@ -0,0 +1,231 @@
+package org.mozilla.gecko.db;
+
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import android.util.SparseArray;
+
+import org.mozilla.gecko.db.BrowserContract.Bookmarks;
+import org.mozilla.gecko.db.BrowserDB.URLColumns;
+
+/**
+ * {@TopSitesCursorWrapper} is a cursor wrapper that merges
+ * the top and pinned sites cursors into one. It ensures the
+ * cursor will contain at least a given minimum number of
+ * entries.
+ */
+public class TopSitesCursorWrapper extends CursorWrapper {
+
+    private static class PinnedSite {
+        public final String title;
+        public final String url;
+
+        public PinnedSite(String title, String url) {
+            this.title = (title == null ? "" : title);
+            this.url = (url == null ? "" : url);
+        }
+    }
+
+    // The cursor for the top sites query
+    private final Cursor topCursor;
+
+    // Associates pinned sites and their respective positions
+    private SparseArray<PinnedSite> pinnedSites;
+
+    // Current position of the cursor
+    private int currentPosition = -1;
+
+    // The size of the cursor wrapper
+    private final int count;
+
+    public TopSitesCursorWrapper(Cursor pinnedCursor, Cursor topCursor, int minSize) {
+        super(topCursor);
+
+        setPinnedSites(pinnedCursor);
+        this.topCursor = topCursor;
+
+        count = Math.max(minSize, pinnedSites.size() + topCursor.getCount());
+    }
+
+    public void setPinnedSites(Cursor c) {
+        pinnedSites = new SparseArray<PinnedSite>();
+
+        if (c == null) {
+            return;
+        }
+
+        try {
+            if (c.getCount() <= 0) {
+                return;
+            }
+
+            c.moveToPosition(0);
+            do {
+                final int pos = c.getInt(c.getColumnIndex(Bookmarks.POSITION));
+                final String url = c.getString(c.getColumnIndex(URLColumns.URL));
+                final String title = c.getString(c.getColumnIndex(URLColumns.TITLE));
+                pinnedSites.put(pos, new PinnedSite(title, url));
+            } while (c.moveToNext());
+        } finally {
+            c.close();
+        }
+    }
+
+    public boolean hasPinnedSites() {
+        return (pinnedSites != null && pinnedSites.size() > 0);
+    }
+
+    public PinnedSite getPinnedSite(int position) {
+        if (!hasPinnedSites()) {
+            return null;
+        }
+
+        return pinnedSites.get(position);
+    }
+
+    public boolean isPinned() {
+        return (pinnedSites.get(currentPosition) != null);
+    }
+
+    private int getPinnedBefore(int position) {
+        int numFound = 0;
+        if (!hasPinnedSites()) {
+            return numFound;
+        }
+
+        for (int i = 0; i < position; i++) {
+            if (pinnedSites.get(i) != null) {
+                numFound++;
+            }
+        }
+
+        return numFound;
+    }
+
+    @Override
+    public int getPosition() {
+        return currentPosition;
+    }
+
+    @Override
+    public int getCount() {
+        return count;
+    }
+
+    @Override
+    public boolean isAfterLast() {
+        return (currentPosition >= count);
+    }
+
+    @Override
+    public boolean isBeforeFirst() {
+        return (currentPosition < 0);
+    }
+
+    @Override
+    public boolean isLast() {
+        return (currentPosition == count - 1);
+    }
+
+    @Override
+    public boolean moveToNext() {
+        return moveToPosition(currentPosition + 1);
+    }
+
+    @Override
+    public boolean moveToPrevious() {
+        return moveToPosition(currentPosition - 1);
+    }
+
+    @Override
+    public boolean move(int offset) {
+        return moveToPosition(currentPosition + offset);
+    }
+
+    @Override
+    public boolean moveToFirst() {
+        return moveToPosition(0);
+    }
+
+    @Override
+    public boolean moveToLast() {
+        return moveToPosition(count - 1);
+    }
+
+    @Override
+    public boolean moveToPosition(int position) {
+        currentPosition = position;
+
+        // Move the real cursor as if we were stepping through it to this position.
+        // Account for pinned sites, and be careful to update its position to the
+        // minimum or maximum position, even if we're moving beyond its bounds.
+        final int before = getPinnedBefore(position);
+        final int p2 = position - before;
+
+        if (p2 <= -1) {
+            super.moveToPosition(-1);
+        } else if (p2 >= topCursor.getCount()) {
+            super.moveToPosition(topCursor.getCount());
+        } else {
+            super.moveToPosition(p2);
+        }
+
+        return (!isBeforeFirst() && !isAfterLast());
+    }
+
+    @Override
+    public long getLong(int columnIndex) {
+        if (hasPinnedSites()) {
+            final PinnedSite site = getPinnedSite(currentPosition);
+
+            if (site != null) {
+                return 0;
+            }
+        }
+
+        if (!super.isBeforeFirst() && !super.isAfterLast()) {
+            return super.getLong(columnIndex);
+        }
+
+        return 0;
+    }
+
+    @Override
+    public int getInt(int columnIndex) {
+        if (hasPinnedSites()) {
+            final PinnedSite site = getPinnedSite(currentPosition);
+
+            if (site != null) {
+                return 0;
+            }
+        }
+
+        if (!super.isBeforeFirst() && !super.isAfterLast()) {
+            return super.getInt(columnIndex);
+        }
+
+        return 0;
+    }
+
+    @Override
+    public String getString(int columnIndex) {
+        if (hasPinnedSites()) {
+            final PinnedSite site = getPinnedSite(currentPosition);
+
+            if (site != null) {
+                if (columnIndex == topCursor.getColumnIndex(URLColumns.URL)) {
+                    return site.url;
+                } else if (columnIndex == topCursor.getColumnIndex(URLColumns.TITLE)) {
+                    return site.title;
+                }
+
+                return "";
+            }
+        }
+
+        if (!super.isBeforeFirst() && !super.isAfterLast()) {
+            return super.getString(columnIndex);
+        }
+
+        return "";
+    }
+}
--- a/mobile/android/base/fxa/activities/FxAccountAbstractActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountAbstractActivity.java
@@ -4,26 +4,27 @@
 
 package org.mozilla.gecko.fxa.activities;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
+import org.mozilla.gecko.sync.setup.activities.LocaleAware.LocaleAwareActivity;
 
 import android.accounts.Account;
 import android.app.Activity;
 import android.content.Intent;
 import android.os.SystemClock;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.TextView;
 
-public abstract class FxAccountAbstractActivity extends Activity {
+public abstract class FxAccountAbstractActivity extends LocaleAwareActivity {
   private static final String LOG_TAG = FxAccountAbstractActivity.class.getSimpleName();
 
   protected final boolean cannotResumeWhenAccountsExist;
   protected final boolean cannotResumeWhenNoAccountsExist;
   protected final boolean cannotResumeWhenLockedOut;
 
   public static final int CAN_ALWAYS_RESUME = 0;
   public static final int CANNOT_RESUME_WHEN_ACCOUNTS_EXIST = 1 << 0;
--- a/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountGetStartedActivity.java
@@ -9,16 +9,17 @@ import java.util.Locale;
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.fxa.FxAccountAgeLockoutHelper;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
+import org.mozilla.gecko.sync.setup.activities.LocaleAware;
 
 import android.accounts.AccountAuthenticatorActivity;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.TextView;
@@ -34,17 +35,20 @@ public class FxAccountGetStartedActivity
   /**
    * {@inheritDoc}
    */
   @Override
   public void onCreate(Bundle icicle) {
     Logger.setThreadLogTag(FxAccountConstants.GLOBAL_LOG_TAG);
     Logger.debug(LOG_TAG, "onCreate(" + icicle + ")");
 
+    LocaleAware.initializeLocale(getApplicationContext());
+
     super.onCreate(icicle);
+
     setContentView(R.layout.fxaccount_get_started);
 
     linkifyOldFirefoxLink();
 
     View button = findViewById(R.id.get_started_button);
     button.setOnClickListener(new OnClickListener() {
       @Override
       public void onClick(View v) {
@@ -102,15 +106,15 @@ public class FxAccountGetStartedActivity
     }
   }
 
   protected void linkifyOldFirefoxLink() {
     TextView oldFirefox = (TextView) findViewById(R.id.old_firefox);
     String text = getResources().getString(R.string.fxaccount_getting_started_old_firefox);
     String VERSION = AppConstants.MOZ_APP_VERSION;
     String OS = AppConstants.OS_TARGET;
-    // We'll need to adjust this when we have active locale switching.
+
     String LOCALE = Utils.getLanguageTag(Locale.getDefault());
     String url = getResources().getString(R.string.fxaccount_link_old_firefox, VERSION, OS, LOCALE);
     FxAccountConstants.pii(LOG_TAG, "Old Firefox url is: " + url); // Don't want to leak locale in particular.
     ActivityUtils.linkTextView(oldFirefox, text, url);
   }
 }
--- a/mobile/android/base/fxa/activities/FxAccountStatusActivity.java
+++ b/mobile/android/base/fxa/activities/FxAccountStatusActivity.java
@@ -2,30 +2,30 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.activities;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
+import org.mozilla.gecko.sync.setup.activities.LocaleAware.LocaleAwareFragmentActivity;
 
 import android.accounts.Account;
 import android.annotation.TargetApi;
 import android.app.ActionBar;
 import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
 import android.view.MenuItem;
 
 /**
  * Activity which displays account status.
  */
-public class FxAccountStatusActivity extends FragmentActivity {
+public class FxAccountStatusActivity extends LocaleAwareFragmentActivity {
   private static final String LOG_TAG = FxAccountStatusActivity.class.getSimpleName();
 
   protected FxAccountStatusFragment statusFragment;
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
 
--- a/mobile/android/base/fxa/sync/FxAccountNotificationManager.java
+++ b/mobile/android/base/fxa/sync/FxAccountNotificationManager.java
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.fxa.sync;
 
+import org.mozilla.gecko.BrowserLocaleManager;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.activities.FxAccountStatusActivity;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.fxa.login.State;
 import org.mozilla.gecko.fxa.login.State.Action;
 
@@ -29,16 +30,19 @@ import android.support.v4.app.Notificati
  * <li>messages from other clients.</li>
  * </ul>
  */
 public class FxAccountNotificationManager {
   private static final String LOG_TAG = FxAccountNotificationManager.class.getSimpleName();
 
   protected final int notificationId;
 
+  // We're lazy about updating our locale info, because most syncs don't notify.
+  private volatile boolean localeUpdated;
+
   public FxAccountNotificationManager(int notificationId) {
     this.notificationId = notificationId;
   }
 
   /**
    * Reflect new Firefox Account state to the notification manager: show or hide
    * notifications reflecting the state of a Firefox Account.
    *
@@ -53,16 +57,21 @@ public class FxAccountNotificationManage
     final State state = fxAccount.getState();
     final Action action = state.getNeededAction();
     if (action == Action.None) {
       Logger.info(LOG_TAG, "State " + state.getStateLabel() + " needs no action; cancelling any existing notification.");
       notificationManager.cancel(notificationId);
       return;
     }
 
+    if (!localeUpdated) {
+      localeUpdated = true;
+      BrowserLocaleManager.getInstance().getAndApplyPersistedLocale(context);
+    }
+
     final String title = context.getResources().getString(R.string.fxaccount_sync_sign_in_error_notification_title);
     final String text = context.getResources().getString(R.string.fxaccount_sync_sign_in_error_notification_text, state.email);
     Logger.info(LOG_TAG, "State " + state.getStateLabel() + " needs action; offering notification with title: " + title);
     FxAccountConstants.pii(LOG_TAG, "And text: " + text);
 
     final Intent notificationIntent = new Intent(context, FxAccountStatusActivity.class);
     final PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
 
--- a/mobile/android/base/home/DynamicPanel.java
+++ b/mobile/android/base/home/DynamicPanel.java
@@ -408,18 +408,21 @@ public class DynamicPanel extends HomeFr
             } else {
                 selection = DBUtils.concatenateWhere(HomeItems.DATASET_ID + " = ?", HomeItems.FILTER + " = ?");
                 selectionArgs = new String[] { mRequest.getDatasetId(), mRequest.getFilter() };
             }
 
             // XXX: You can use CONTENT_FAKE_URI for development to pull items from fake_home_items.json.
             final Cursor c = cr.query(HomeItems.CONTENT_URI, null, selection, selectionArgs, null);
 
-            final Uri notificationUri = getDatasetNotificationUri(mRequest.getDatasetId());
-            c.setNotificationUri(cr, notificationUri);
+            // SQLiteBridgeContentProvider may return a null Cursor if the database hasn't been created yet.
+            if (c != null) {
+                final Uri notificationUri = getDatasetNotificationUri(mRequest.getDatasetId());
+                c.setNotificationUri(cr, notificationUri);
+            }
 
             return c;
         }
     }
 
     /**
      * LoaderCallbacks implementation that interacts with the LoaderManager.
      */
--- a/mobile/android/base/home/HomeConfig.java
+++ b/mobile/android/base/home/HomeConfig.java
@@ -607,70 +607,83 @@ public final class HomeConfig {
     public static class ViewConfig implements Parcelable {
         private final int mIndex;
         private final ViewType mType;
         private final String mDatasetId;
         private final ItemType mItemType;
         private final ItemHandler mItemHandler;
         private final String mBackImageUrl;
         private final String mFilter;
+        private final EmptyViewConfig mEmptyViewConfig;
 
         private static final String JSON_KEY_TYPE = "type";
         private static final String JSON_KEY_DATASET = "dataset";
         private static final String JSON_KEY_ITEM_TYPE = "itemType";
         private static final String JSON_KEY_ITEM_HANDLER = "itemHandler";
         private static final String JSON_KEY_BACK_IMAGE_URL = "backImageUrl";
         private static final String JSON_KEY_FILTER = "filter";
+        private static final String JSON_KEY_EMPTY = "empty";
 
         public ViewConfig(int index, JSONObject json) throws JSONException, IllegalArgumentException {
             mIndex = index;
             mType = ViewType.fromId(json.getString(JSON_KEY_TYPE));
             mDatasetId = json.getString(JSON_KEY_DATASET);
             mItemType = ItemType.fromId(json.getString(JSON_KEY_ITEM_TYPE));
             mItemHandler = ItemHandler.fromId(json.getString(JSON_KEY_ITEM_HANDLER));
             mBackImageUrl = json.optString(JSON_KEY_BACK_IMAGE_URL, null);
             mFilter = json.optString(JSON_KEY_FILTER, null);
 
+            final JSONObject jsonEmptyViewConfig = json.optJSONObject(JSON_KEY_EMPTY);
+            if (jsonEmptyViewConfig != null) {
+                mEmptyViewConfig = new EmptyViewConfig(jsonEmptyViewConfig);
+            } else {
+                mEmptyViewConfig = null;
+            }
+
             validate();
         }
 
         @SuppressWarnings("unchecked")
         public ViewConfig(Parcel in) {
             mIndex = in.readInt();
             mType = (ViewType) in.readParcelable(getClass().getClassLoader());
             mDatasetId = in.readString();
             mItemType = (ItemType) in.readParcelable(getClass().getClassLoader());
             mItemHandler = (ItemHandler) in.readParcelable(getClass().getClassLoader());
             mBackImageUrl = in.readString();
             mFilter = in.readString();
+            mEmptyViewConfig = (EmptyViewConfig) in.readParcelable(getClass().getClassLoader());
 
             validate();
         }
 
         public ViewConfig(ViewConfig viewConfig) {
             mIndex = viewConfig.mIndex;
             mType = viewConfig.mType;
             mDatasetId = viewConfig.mDatasetId;
             mItemType = viewConfig.mItemType;
             mItemHandler = viewConfig.mItemHandler;
             mBackImageUrl = viewConfig.mBackImageUrl;
             mFilter = viewConfig.mFilter;
+            mEmptyViewConfig = viewConfig.mEmptyViewConfig;
 
             validate();
         }
 
         public ViewConfig(int index, ViewType type, String datasetId, ItemType itemType,
-                          ItemHandler itemHandler, String backImageUrl, String filter) {
+                          ItemHandler itemHandler, String backImageUrl, String filter,
+                          EmptyViewConfig emptyViewConfig) {
             mIndex = index;
             mType = type;
             mDatasetId = datasetId;
             mItemType = itemType;
             mItemHandler = itemHandler;
             mBackImageUrl = backImageUrl;
             mFilter = filter;
+            mEmptyViewConfig = emptyViewConfig;
 
             validate();
         }
 
         private void validate() {
             if (mType == null) {
                 throw new IllegalArgumentException("Can't create ViewConfig with null type");
             }
@@ -711,32 +724,40 @@ public final class HomeConfig {
         public String getBackImageUrl() {
             return mBackImageUrl;
         }
 
         public String getFilter() {
             return mFilter;
         }
 
+        public EmptyViewConfig getEmptyViewConfig() {
+            return mEmptyViewConfig;
+        }
+
         public JSONObject toJSON() throws JSONException {
             final JSONObject json = new JSONObject();
 
             json.put(JSON_KEY_TYPE, mType.toString());
             json.put(JSON_KEY_DATASET, mDatasetId);
             json.put(JSON_KEY_ITEM_TYPE, mItemType.toString());
             json.put(JSON_KEY_ITEM_HANDLER, mItemHandler.toString());
 
             if (!TextUtils.isEmpty(mBackImageUrl)) {
                 json.put(JSON_KEY_BACK_IMAGE_URL, mBackImageUrl);
             }
 
             if (!TextUtils.isEmpty(mFilter)) {
                 json.put(JSON_KEY_FILTER, mFilter);
             }
 
+            if (mEmptyViewConfig != null) {
+                json.put(JSON_KEY_EMPTY, mEmptyViewConfig.toJSON());
+            }
+
             return json;
         }
 
         @Override
         public int describeContents() {
             return 0;
         }
 
@@ -744,31 +765,101 @@ public final class HomeConfig {
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(mIndex);
             dest.writeParcelable(mType, 0);
             dest.writeString(mDatasetId);
             dest.writeParcelable(mItemType, 0);
             dest.writeParcelable(mItemHandler, 0);
             dest.writeString(mBackImageUrl);
             dest.writeString(mFilter);
+            dest.writeParcelable(mEmptyViewConfig, 0);
         }
 
         public static final Creator<ViewConfig> CREATOR = new Creator<ViewConfig>() {
             @Override
             public ViewConfig createFromParcel(final Parcel in) {
                 return new ViewConfig(in);
             }
 
             @Override
             public ViewConfig[] newArray(final int size) {
                 return new ViewConfig[size];
             }
         };
     }
 
+    public static class EmptyViewConfig implements Parcelable {
+        private final String mText;
+        private final String mImageUrl;
+
+        private static final String JSON_KEY_TEXT = "text";
+        private static final String JSON_KEY_IMAGE_URL = "imageUrl";
+
+        public EmptyViewConfig(JSONObject json) throws JSONException, IllegalArgumentException {
+            mText = json.optString(JSON_KEY_TEXT, null);
+            mImageUrl = json.optString(JSON_KEY_IMAGE_URL, null);
+        }
+
+        @SuppressWarnings("unchecked")
+        public EmptyViewConfig(Parcel in) {
+            mText = in.readString();
+            mImageUrl = in.readString();
+        }
+
+        public EmptyViewConfig(EmptyViewConfig emptyViewConfig) {
+            mText = emptyViewConfig.mText;
+            mImageUrl = emptyViewConfig.mImageUrl;
+        }
+
+        public EmptyViewConfig(String text, String imageUrl) {
+            mText = text;
+            mImageUrl = imageUrl;
+        }
+
+        public String getText() {
+            return mText;
+        }
+
+        public String getImageUrl() {
+            return mImageUrl;
+        }
+
+        public JSONObject toJSON() throws JSONException {
+            final JSONObject json = new JSONObject();
+
+            json.put(JSON_KEY_TEXT, mText);
+            json.put(JSON_KEY_IMAGE_URL, mImageUrl);
+
+            return json;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(mText);
+            dest.writeString(mImageUrl);
+        }
+
+        public static final Creator<EmptyViewConfig> CREATOR = new Creator<EmptyViewConfig>() {
+            @Override
+            public EmptyViewConfig createFromParcel(final Parcel in) {
+                return new EmptyViewConfig(in);
+            }
+
+            @Override
+            public EmptyViewConfig[] newArray(final int size) {
+                return new EmptyViewConfig[size];
+            }
+        };
+    }
+
     public static class AuthConfig implements Parcelable {
         private final String mMessageText;
         private final String mButtonText;
         private final String mImageUrl;
 
         private static final String JSON_KEY_MESSAGE_TEXT = "messageText";
         private static final String JSON_KEY_BUTTON_TEXT = "buttonText";
         private static final String JSON_KEY_IMAGE_URL = "imageUrl";
--- a/mobile/android/base/home/PanelLayout.java
+++ b/mobile/android/base/home/PanelLayout.java
@@ -2,38 +2,46 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.home;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
+import org.mozilla.gecko.home.HomeConfig.EmptyViewConfig;
 import org.mozilla.gecko.home.HomeConfig.ItemHandler;
 import org.mozilla.gecko.home.HomeConfig.PanelConfig;
 import org.mozilla.gecko.home.HomeConfig.ViewConfig;
 import org.mozilla.gecko.util.StringUtils;
 
 import android.content.Context;
 import android.database.Cursor;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.KeyEvent;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import java.lang.ref.SoftReference;
 import java.util.EnumSet;
 import java.util.LinkedList;
 import java.util.Map;
 import java.util.WeakHashMap;
 
+import com.squareup.picasso.Picasso;
+
 /**
  * {@code PanelLayout} is the base class for custom layouts to be
  * used in {@code DynamicPanel}. It provides the basic framework
  * that enables custom layouts to request and reset datasets and
  * create panel views. Furthermore, it automates most of the process
  * of binding panel views with their respective datasets.
  *
  * {@code PanelLayout} abstracts the implemention details of how
@@ -259,19 +267,34 @@ abstract class PanelLayout extends Frame
             case FILTER_PUSH:
                 viewState.pushFilter(request.getFilterDetail());
                 break;
             case FILTER_POP:
                 viewState.popFilter();
                 break;
         }
 
-        final View view = viewState.getView();
-        if (view != null) {
-            maybeSetDataset(view, cursor);
+        final View activeView = viewState.getActiveView();
+        if (activeView == null) {
+            throw new IllegalStateException("No active view for view state: " + viewState.getIndex());
+        }
+
+        final ViewConfig viewConfig = viewState.getViewConfig();
+
+        final View newView;
+        if (cursor == null || cursor.getCount() == 0) {
+            newView = createEmptyView(viewConfig);
+            maybeSetDataset(activeView, null);
+        } else {
+            newView = createPanelView(viewConfig);
+            maybeSetDataset(newView, cursor);
+        }
+
+        if (activeView != newView) {
+            replacePanelView(activeView, newView);
         }
     }
 
     /**
      * Releases any references to the given dataset from all
      * existing panel views.
      */
     public final void releaseDataset(int viewIndex) {
@@ -378,49 +401,126 @@ abstract class PanelLayout extends Frame
 
     private void maybeSetDataset(View view, Cursor cursor) {
         if (view instanceof DatasetBacked) {
             final DatasetBacked dsb = (DatasetBacked) view;
             dsb.setDataset(cursor);
         }
     }
 
+    private View createEmptyView(ViewConfig viewConfig) {
+        Log.d(LOGTAG, "Creating empty view: " + viewConfig.getType());
+
+        ViewState viewState = mViewStates.get(viewConfig.getIndex());
+        if (viewState == null) {
+            throw new IllegalStateException("No view state found for view index: " + viewConfig.getIndex());
+        }
+
+        View view = viewState.getEmptyView();
+        if (view == null) {
+            view = LayoutInflater.from(getContext()).inflate(R.layout.home_empty_panel, null);
+
+            final EmptyViewConfig emptyViewConfig = viewConfig.getEmptyViewConfig();
+
+            // XXX: Refactor this into a custom view (bug 985134)
+            final String text = (emptyViewConfig == null) ? null : emptyViewConfig.getText();
+            final TextView textView = (TextView) view.findViewById(R.id.home_empty_text);
+            if (TextUtils.isEmpty(text)) {
+                textView.setText(R.string.home_default_empty);
+            } else {
+                textView.setText(text);
+            }
+
+            final String imageUrl = (emptyViewConfig == null) ? null : emptyViewConfig.getImageUrl();
+            final ImageView imageView = (ImageView) view.findViewById(R.id.home_empty_image);
+
+            if (imageUrl == null) {
+                Picasso.with(getContext())
+                       .load(R.drawable.icon_home_empty_firefox)
+                       .into(imageView);
+            } else {
+                Picasso.with(getContext())
+                       .load(imageUrl)
+                       .error(R.drawable.icon_home_empty_firefox)
+                       .into(imageView);
+            }
+
+            viewState.setEmptyView(view);
+        }
+
+        return view;
+    }
+
+    private void replacePanelView(View currentView, View newView) {
+        final ViewGroup parent = (ViewGroup) currentView.getParent();
+        parent.addView(newView, parent.indexOfChild(currentView), currentView.getLayoutParams());
+        parent.removeView(currentView);
+    }
+
     /**
      * Must be implemented by {@code PanelLayout} subclasses to define
      * what happens then the layout is first loaded. Should set initial
      * UI state and request any necessary datasets.
      */
     public abstract void load();
 
     /**
      * Represents a 'live' instance of a panel view associated with
      * the {@code PanelLayout}. Is responsible for tracking the history stack of filters.
      */
     protected class ViewState {
         private final ViewConfig mViewConfig;
         private SoftReference<View> mView;
+        private SoftReference<View> mEmptyView;
         private LinkedList<FilterDetail> mFilterStack;
 
         public ViewState(ViewConfig viewConfig) {
             mViewConfig = viewConfig;
             mView = new SoftReference<View>(null);
+            mEmptyView = new SoftReference<View>(null);
+        }
+
+        public ViewConfig getViewConfig() {
+            return mViewConfig;
         }
 
         public int getIndex() {
             return mViewConfig.getIndex();
         }
 
         public View getView() {
             return mView.get();
         }
 
         public void setView(View view) {
             mView = new SoftReference<View>(view);
         }
 
+        public View getEmptyView() {
+            return mEmptyView.get();
+        }
+
+        public void setEmptyView(View view) {
+            mEmptyView = new SoftReference<View>(view);
+        }
+
+        public View getActiveView() {
+            final View view = getView();
+            if (view != null && view.getParent() != null) {
+                return view;
+            }
+
+            final View emptyView = getEmptyView();
+            if (emptyView != null && emptyView.getParent() != null) {
+                return emptyView;
+            }
+
+            return null;
+        }
+
         public String getDatasetId() {
             return mViewConfig.getDatasetId();
         }
 
         public ItemHandler getItemHandler() {
             return mViewConfig.getItemHandler();
         }
 
--- a/mobile/android/base/home/TopSitesGridView.java
+++ b/mobile/android/base/home/TopSitesGridView.java
@@ -4,18 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.home;
 
 import java.util.EnumSet;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.ThumbnailHelper;
-import org.mozilla.gecko.db.BrowserDB.TopSitesCursorWrapper;
 import org.mozilla.gecko.db.BrowserDB.URLColumns;
+import org.mozilla.gecko.db.TopSitesCursorWrapper;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
 
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.database.Cursor;
 import android.graphics.Rect;
 import android.text.TextUtils;
 import android.util.AttributeSet;
--- a/mobile/android/base/home/TopSitesPanel.java
+++ b/mobile/android/base/home/TopSitesPanel.java
@@ -11,18 +11,18 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.db.BrowserContract.Combined;
 import org.mozilla.gecko.db.BrowserContract.Thumbnails;
 import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.BrowserDB.TopSitesCursorWrapper;
 import org.mozilla.gecko.db.BrowserDB.URLColumns;
+import org.mozilla.gecko.db.TopSitesCursorWrapper;
 import org.mozilla.gecko.favicons.Favicons;
 import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
 import org.mozilla.gecko.home.PinSiteDialog.OnSiteSelectedListener;
 import org.mozilla.gecko.home.TopSitesGridView.OnEditPinnedSiteListener;
 import org.mozilla.gecko.home.TopSitesGridView.TopSitesGridContextMenuInfo;
 import org.mozilla.gecko.util.ThreadUtils;
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -61,16 +61,17 @@ gujar.sources += [
     'util/INISection.java',
     'util/JSONUtils.java',
     'util/MenuUtils.java',
     'util/NativeEventListener.java',
     'util/NativeJSContainer.java',
     'util/NativeJSObject.java',
     'util/NonEvictingLruCache.java',
     'util/ProxySelector.java',
+    'util/RawResource.java',
     'util/StringUtils.java',
     'util/ThreadUtils.java',
     'util/UiAsyncTask.java',
 ]
 gujar.extra_jars = [
     'gecko-mozglue.jar'
 ]
 gujar.javac_flags += ['-Xlint:all,-deprecation']
@@ -112,16 +113,17 @@ gbjar.sources += [
     'animation/HeightChangeAnimation.java',
     'animation/PropertyAnimator.java',
     'animation/Rotate3DAnimation.java',
     'animation/ViewHelper.java',
     'ANRReporter.java',
     'AppNotificationClient.java',
     'BaseGeckoInterface.java',
     'BrowserApp.java',
+    'BrowserLocaleManager.java',
     'ContactService.java',
     'ContextGetter.java',
     'CustomEditText.java',
     'DataReportingNotification.java',
     'db/AbstractPerProfileDatabaseProvider.java',
     'db/AbstractTransactionalProvider.java',
     'db/BrowserContract.java',
     'db/BrowserDatabaseHelper.java',
@@ -133,16 +135,17 @@ gbjar.sources += [
     'db/LocalBrowserDB.java',
     'db/PasswordsProvider.java',
     'db/PerProfileDatabaseProvider.java',
     'db/PerProfileDatabases.java',
     'db/ReadingListProvider.java',
     'db/SharedBrowserDatabaseProvider.java',
     'db/SQLiteBridgeContentProvider.java',
     'db/TabsProvider.java',
+    'db/TopSitesCursorWrapper.java',
     'Distribution.java',
     'DoorHangerPopup.java',
     'DynamicToolbar.java',
     'EditBookmarkDialog.java',
     'EventDispatcher.java',
     'favicons/cache/FaviconCache.java',
     'favicons/cache/FaviconCacheElement.java',
     'favicons/cache/FaviconsForURL.java',
--- a/mobile/android/base/resources/menu-large-v11/browser_app_menu.xml
+++ b/mobile/android/base/resources/menu-large-v11/browser_app_menu.xml
@@ -51,16 +51,19 @@
           android:title="@string/page"
           android:icon="@drawable/ic_menu_tools">
 
         <menu>
 
             <item android:id="@+id/subscribe"
                   android:title="@string/contextmenu_subscribe"/>
 
+            <item android:id="@+id/save_as_pdf"
+                  android:title="@string/save_as_pdf"/>
+
             <item android:id="@+id/add_search_engine"
                   android:title="@string/contextmenu_add_search_engine"/>
 
             <item android:id="@+id/site_settings"
                   android:title="@string/contextmenu_site_settings" />
 
             <item android:id="@+id/add_to_launcher"
                   android:title="@string/contextmenu_add_to_launcher"/>
@@ -70,20 +73,16 @@
     </item>
 
     <item android:id="@+id/tools"
           android:title="@string/tools"
           android:icon="@drawable/ic_menu_tools">
 
         <menu>
 
-            <item android:id="@+id/save_as_pdf"
-                  android:icon="@drawable/ic_menu_save_as_pdf"
-                  android:title="@string/save_as_pdf" />
-
             <item android:id="@+id/downloads"
                   android:icon="@drawable/ic_menu_downloads"
                   android:title="@string/downloads"/>
 
             <item android:id="@+id/addons"
                   android:icon="@drawable/ic_menu_addons"
                   android:title="@string/addons"/>
 
--- a/mobile/android/base/resources/menu-v11/browser_app_menu.xml
+++ b/mobile/android/base/resources/menu-v11/browser_app_menu.xml
@@ -51,16 +51,19 @@
           android:title="@string/page"
           android:icon="@drawable/ic_menu_tools">
 
         <menu>
 
             <item android:id="@+id/subscribe"
                   android:title="@string/contextmenu_subscribe"/>
 
+            <item android:id="@+id/save_as_pdf"
+                  android:title="@string/save_as_pdf"/>
+
             <item android:id="@+id/add_search_engine"
                   android:title="@string/contextmenu_add_search_engine"/>
 
             <item android:id="@+id/site_settings"
                   android:title="@string/contextmenu_site_settings" />
 
             <item android:id="@+id/add_to_launcher"
                   android:title="@string/contextmenu_add_to_launcher"/>
@@ -70,20 +73,16 @@
     </item>
 
     <item android:id="@+id/tools"
           android:title="@string/tools"
           android:icon="@drawable/ic_menu_tools">
 
         <menu>
 
-            <item android:id="@+id/save_as_pdf"
-                  android:icon="@drawable/ic_menu_save_as_pdf"
-                  android:title="@string/save_as_pdf" />
-
             <item android:id="@+id/downloads"
                   android:icon="@drawable/ic_menu_downloads"
                   android:title="@string/downloads"/>
 
             <item android:id="@+id/addons"
                   android:icon="@drawable/ic_menu_addons"
                   android:title="@string/addons"/>
 
--- a/mobile/android/base/resources/menu-xlarge-v11/browser_app_menu.xml
+++ b/mobile/android/base/resources/menu-xlarge-v11/browser_app_menu.xml
@@ -52,16 +52,19 @@
           android:title="@string/page"
           android:icon="@drawable/ic_menu_tools">
 
         <menu>
 
             <item android:id="@+id/subscribe"
                   android:title="@string/contextmenu_subscribe"/>
 
+            <item android:id="@+id/save_as_pdf"
+                  android:title="@string/save_as_pdf"/>
+
             <item android:id="@+id/add_search_engine"
                   android:title="@string/contextmenu_add_search_engine"/>
 
             <item android:id="@+id/site_settings"
                   android:title="@string/contextmenu_site_settings" />
 
             <item android:id="@+id/add_to_launcher"
                   android:title="@string/contextmenu_add_to_launcher"/>
@@ -71,20 +74,16 @@
     </item>
 
     <item android:id="@+id/tools"
           android:title="@string/tools"
           android:icon="@drawable/ic_menu_tools">
 
         <menu>
 
-            <item android:id="@+id/save_as_pdf"
-                  android:icon="@drawable/ic_menu_save_as_pdf"
-                  android:title="@string/save_as_pdf" />
-
             <item android:id="@+id/downloads"
                   android:icon="@drawable/ic_menu_downloads"
                   android:title="@string/downloads"/>
 
             <item android:id="@+id/addons"
                   android:icon="@drawable/ic_menu_addons"
                   android:title="@string/addons"/>
 
--- a/mobile/android/base/sync/CommandProcessor.java
+++ b/mobile/android/base/sync/CommandProcessor.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko.sync;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
+import org.mozilla.gecko.BrowserLocaleManager;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
 import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
 
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -234,33 +235,42 @@ public class CommandProcessor {
       db.store(clientID, command);
     } catch (NullCursorException e) {
       Logger.error(LOG_TAG, "NullCursorException: Unable to send command.");
     } finally {
       db.close();
     }
   }
 
+  private static volatile boolean didUpdateLocale = false;
+
   @SuppressWarnings("deprecation")
   public static void displayURI(final List<String> args, final Context context) {
     // We trust the client sender that these exist.
     final String uri = args.get(0);
     final String clientId = args.get(1);
 
     Logger.pii(LOG_TAG, "Received a URI for display: " + uri + " from " + clientId);
 
     String title = null;
     if (args.size() == 3) {
       title = args.get(2);
     }
 
+    // We don't care too much about races, but let's try to avoid
+    // unnecessary work.
+    if (!didUpdateLocale) {
+      BrowserLocaleManager.getInstance().getAndApplyPersistedLocale(context);
+      didUpdateLocale = true;
+    }
+
     final String ns = Context.NOTIFICATION_SERVICE;
     final NotificationManager notificationManager = (NotificationManager) context.getSystemService(ns);
 
-    // Create a Notificiation.
+    // Create a Notification.
     final int icon = R.drawable.icon;
     String notificationTitle = context.getString(R.string.sync_new_tab);
     if (title != null) {
       notificationTitle = notificationTitle.concat(": " + title);
     }
 
     final long when = System.currentTimeMillis();
     Notification notification = new Notification(icon, notificationTitle, when);
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/sync/setup/activities/LocaleAware.java
@@ -0,0 +1,59 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.sync.setup.activities;
+
+import org.mozilla.gecko.BrowserLocaleManager;
+import org.mozilla.gecko.LocaleManager;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.StrictMode;
+import android.support.v4.app.FragmentActivity;
+
+/**
+ * This is a helper class to do typical locale switching operations
+ * without hitting StrictMode errors or adding boilerplate to common
+ * activity subclasses.
+ *
+ * Either call {@link LocaleAware#initializeLocale(Context)} in your
+ * <code>onCreate</code> method, or inherit from <code>LocaleAwareFragmentActivity</code>
+ * or <code>LocaleAwareActivity</code>.
+ */
+public class LocaleAware {
+  @TargetApi(Build.VERSION_CODES.GINGERBREAD)
+  public static void initializeLocale(Context context) {
+    final LocaleManager localeManager = BrowserLocaleManager.getInstance();
+    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
+      localeManager.getAndApplyPersistedLocale(context);
+    } else {
+      final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+      StrictMode.allowThreadDiskWrites();
+      try {
+        localeManager.getAndApplyPersistedLocale(context);
+      } finally {
+        StrictMode.setThreadPolicy(savedPolicy);
+      }
+    }
+  }
+
+  public static class LocaleAwareFragmentActivity extends FragmentActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+      LocaleAware.initializeLocale(getApplicationContext());
+      super.onCreate(savedInstanceState);
+    }
+  }
+
+  public static class LocaleAwareActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+      LocaleAware.initializeLocale(getApplicationContext());
+      super.onCreate(savedInstanceState);
+    }
+  }
+}
--- a/mobile/android/base/sync/setup/activities/SendTabActivity.java
+++ b/mobile/android/base/sync/setup/activities/SendTabActivity.java
@@ -22,33 +22,34 @@ import org.mozilla.gecko.sync.CommandPro
 import org.mozilla.gecko.sync.CommandRunner;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.SyncConstants;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
 import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
+import org.mozilla.gecko.sync.setup.activities.LocaleAware.LocaleAwareActivity;
 import org.mozilla.gecko.sync.stage.SyncClientsEngineStage;
 import org.mozilla.gecko.sync.syncadapter.SyncAdapter;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.view.View;
 import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Toast;
 
-public class SendTabActivity extends Activity {
+public class SendTabActivity extends LocaleAwareActivity {
   private interface TabSender {
     static final String[] CLIENTS_STAGE = new String[] { SyncClientsEngineStage.COLLECTION_NAME };
 
     /**
      * @return Return null if the account isn't correctly initialized. Return
      *         the account GUID otherwise.
      */
     String getAccountGUID();
--- a/mobile/android/base/toolbar/ToolbarDisplayLayout.java
+++ b/mobile/android/base/toolbar/ToolbarDisplayLayout.java
@@ -439,24 +439,24 @@ public class ToolbarDisplayLayout extend
 
     private void setSiteSecurityVisibility(boolean visible, EnumSet<UpdateFlags> flags) {
         if (visible == mSiteSecurityVisible) {
             return;
         }
 
         mSiteSecurityVisible = visible;
 
+        mTitle.clearAnimation();
+        mSiteSecurity.clearAnimation();
+
         if (flags.contains(UpdateFlags.DISABLE_ANIMATIONS)) {
             mSiteSecurity.setVisibility(visible ? View.VISIBLE : View.GONE);
             return;
         }
 
-        mTitle.clearAnimation();
-        mSiteSecurity.clearAnimation();
-
         // If any of these animations were cancelled as a result of the
         // clearAnimation() calls above, we need to reset them.
         mLockFadeIn.reset();
         mTitleSlideLeft.reset();
         mTitleSlideRight.reset();
 
         if (mForwardAnim != null) {
             long delay = mForwardAnim.getRemainingTime();
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/util/RawResource.java
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.util;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+
+public final class RawResource {
+    public static String get(Context context, int id) throws IOException {
+        InputStreamReader reader = null;
+
+        try {
+            final Resources res = context.getResources();
+            final InputStream is = res.openRawResource(id);
+            if (is == null) {
+                return null;
+            }
+
+            reader = new InputStreamReader(is);
+
+            final char[] buffer = new char[1024];
+            final StringWriter s = new StringWriter();
+
+            int n;
+            while ((n = reader.read(buffer, 0, buffer.length)) != -1) {
+                s.write(buffer, 0, n);
+            }
+
+            return s.toString();
+        } finally {
+            if (reader != null) {
+                reader.close();
+            }
+        }
+    }
+}
\ No newline at end of file
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -126,17 +126,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
     Services.obs.addObserver(function(s, t, d) {
         window[name].observe(s, t, d)
     }, aNotification, false);
   });
 });
 
 // Lazily-loaded JS modules that use observer notifications
 [
-  ["Home", ["HomePanels:Get", "HomePanels:Authenticate",
+  ["Home", ["HomeBanner:Get", "HomePanels:Get", "HomePanels:Authenticate",
             "HomePanels:Installed", "HomePanels:Uninstalled"], "resource://gre/modules/Home.jsm"],
 ].forEach(module => {
   let [name, notifications, resource] = module;
   XPCOMUtils.defineLazyModuleGetter(this, name, resource);
   notifications.forEach(notification => {
     Services.obs.addObserver((s,t,d) => {
       this[name].observe(s,t,d)
     }, notification, false);
--- a/mobile/android/modules/Home.jsm
+++ b/mobile/android/modules/Home.jsm
@@ -46,33 +46,53 @@ function BannerMessage(options) {
 
   if ("onclick" in options && typeof options.onclick === "function")
     this.onclick = options.onclick;
 
   if ("ondismiss" in options && typeof options.ondismiss === "function")
     this.ondismiss = options.ondismiss;
 }
 
+// We need this object to have access to the HomeBanner
+// private members without leaking it outside Home.jsm.
+let HomeBannerMessageHandlers;
+
 let HomeBanner = (function () {
+  // Whether there is a "HomeBanner:Get" request we couldn't fulfill.
+  let _pendingRequest = false;
+
+  // Functions used to handle messages sent from Java.
+  HomeBannerMessageHandlers = {
+    "HomeBanner:Get": function handleBannerGet(data) {
+      if (!_sendBannerData()) {
+        _pendingRequest = true;
+      }
+    }
+  };
+
   // Holds the messages that will rotate through the banner.
   let _messages = {};
 
+  let _sendBannerData = function() {
+    let keys = Object.keys(_messages);
+    if (!keys.length) {
+      return false;
+    }
 
-  let _handleGet = function() {
     // Choose a message at random.
-    let keys = Object.keys(_messages);
     let randomId = keys[Math.floor(Math.random() * keys.length)];
     let message = _messages[randomId];
 
     sendMessageToJava({
       type: "HomeBanner:Data",
       id: message.id,
       text: message.text,
       iconURI: message.iconURI
     });
+    return true;
   };
 
   let _handleShown = function(id) {
     let message = _messages[id];
     if (message.onshown)
       message.onshown();
   };
 
@@ -86,20 +106,16 @@ let HomeBanner = (function () {
     let message = _messages[id];
     if (message.ondismiss)
       message.ondismiss();
   };
 
   return Object.freeze({
     observe: function(subject, topic, data) {
       switch(topic) {
-        case "HomeBanner:Get":
-          _handleGet();
-          break;
-
         case "HomeBanner:Shown":
           _handleShown(data);
           break;
 
         case "HomeBanner:Click":
           _handleClick(data);
           break;
 
@@ -116,24 +132,25 @@ let HomeBanner = (function () {
      */
     add: function(options) {
       let message = new BannerMessage(options);
       _messages[message.id] = message;
 
       // If this is the first message we're adding, add
       // observers to listen for requests from the Java UI.
       if (Object.keys(_messages).length == 1) {
-        Services.obs.addObserver(this, "HomeBanner:Get", false);
         Services.obs.addObserver(this, "HomeBanner:Shown", false);
         Services.obs.addObserver(this, "HomeBanner:Click", false);
         Services.obs.addObserver(this, "HomeBanner:Dismiss", false);
 
-        // Send a message to Java, in case there's an active HomeBanner
-        // waiting for a response.
-        _handleGet();
+        // Send a message to Java if there's a pending "HomeBanner:Get" request.
+        if (_pendingRequest) {
+          _pendingRequest = false;
+          _sendBannerData();
+        }
       }
 
       return message.id;
     },
 
     /**
      * Removes a banner message from the rotation.
      *
@@ -143,17 +160,16 @@ let HomeBanner = (function () {
       if (!(id in _messages)) {
         throw "Home.banner: Can't remove message that doesn't exist: id = " + id;
       }
 
       delete _messages[id];
 
       // If there are no more messages, remove the observers.
       if (Object.keys(_messages).length == 0) {
-        Services.obs.removeObserver(this, "HomeBanner:Get");
         Services.obs.removeObserver(this, "HomeBanner:Shown");
         Services.obs.removeObserver(this, "HomeBanner:Click");
         Services.obs.removeObserver(this, "HomeBanner:Dismiss");
       }
     }
   });
 })();
 
@@ -407,15 +423,17 @@ let HomePanels = (function () {
 
 // Public API
 this.Home = Object.freeze({
   banner: HomeBanner,
   panels: HomePanels,
 
   // Lazy notification observer registered in browser.js
   observe: function(subject, topic, data) {
-    if (topic in HomePanelsMessageHandlers) {
+    if (topic in HomeBannerMessageHandlers) {
+      HomeBannerMessageHandlers[topic](data);
+    } else if (topic in HomePanelsMessageHandlers) {
       HomePanelsMessageHandlers[topic](data);
     } else {
       Cu.reportError("Home.observe: message handler not found for topic: " + topic);
     }
   }
 });
--- a/mobile/android/services/manifests/SyncAndroidManifest_activities.xml.in
+++ b/mobile/android/services/manifests/SyncAndroidManifest_activities.xml.in
@@ -72,24 +72,21 @@
             <intent-filter>
                 <action android:name="@MOZ_ANDROID_SHARED_ACCOUNT_TYPE@.accounts.SYNC_ACCOUNT_DELETED_ACTION"/>
             </intent-filter>
         </receiver>
 
         <activity
             android:theme="@style/SyncTheme"
             android:excludeFromRecents="true"
-            android:exported="true"
             android:icon="@drawable/icon"
             android:label="@string/sync_app_name"
             android:configChanges="keyboardHidden|orientation|screenSize"
             android:windowSoftInputMode="adjustResize|stateHidden"
             android:taskAffinity="org.mozilla.gecko.sync.setup"
             android:name="org.mozilla.gecko.sync.setup.activities.SendTabActivity" >
 
-#ifndef RELEASE_BUILD
             <intent-filter>
                 <action android:name="android.intent.action.SEND" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:mimeType="text/plain" />
             </intent-filter>
-#endif
         </activity>
--- a/mobile/android/tests/browser/junit3/moz.build
+++ b/mobile/android/tests/browser/junit3/moz.build
@@ -8,16 +8,17 @@ DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG
 
 jar = add_java_jar('browser-junit3')
 jar.sources += [
     'src/harness/BrowserInstrumentationTestRunner.java',
     'src/harness/BrowserTestListener.java',
     'src/tests/BrowserTestCase.java',
     'src/tests/TestGeckoSharedPrefs.java',
     'src/tests/TestJarReader.java',
+    'src/tests/TestTopSitesCursorWrapper.java',
 ]
 jar.generated_sources = [] # None yet -- try to keep it this way.
 jar.javac_flags += ['-Xlint:all,-unchecked']
 
 # Android Eclipse project.
 main = add_android_eclipse_project('BrowserInstrumentationTests', OBJDIR + '/AndroidManifest.xml')
 # The package name doesn't really matter, but it looks nicest if the
 # generated classes (org.mozilla.gecko.browser.tests.{BuildConfig,R})
new file mode 100644
--- /dev/null
+++ b/mobile/android/tests/browser/junit3/src/tests/TestTopSitesCursorWrapper.java
@@ -0,0 +1,197 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+package org.mozilla.gecko.browser.tests;
+
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.text.TextUtils;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.mozilla.gecko.db.BrowserContract.Bookmarks;
+import org.mozilla.gecko.db.BrowserContract.Combined;
+import org.mozilla.gecko.db.TopSitesCursorWrapper;
+
+public class TestTopSitesCursorWrapper extends BrowserTestCase {
+
+    private String[] TOP_SITES_COLUMNS = new String[] { Combined._ID,
+                                                        Combined.URL,
+                                                        Combined.TITLE,
+                                                        Combined.DISPLAY,
+                                                        Combined.BOOKMARK_ID,
+                                                        Combined.HISTORY_ID };
+
+    private String[] PINNED_SITES_COLUMNS = new String[] { Bookmarks._ID,
+                                                           Bookmarks.URL,
+                                                           Bookmarks.TITLE,
+                                                           Bookmarks.POSITION };
+
+    private final int MIN_COUNT = 6;
+
+    private final String TOP_PREFIX = "top-";
+    private final String PINNED_PREFIX = "pinned-";
+
+    private Cursor createTopSitesCursor(int count) {
+        MatrixCursor c = new MatrixCursor(TOP_SITES_COLUMNS);
+
+        for (int i = 0; i < count; i++) {
+            RowBuilder row = c.newRow();
+            row.add(-1);
+            row.add(TOP_PREFIX + "url" + i);
+            row.add(TOP_PREFIX + "title" + i);
+            row.add(Combined.DISPLAY_NORMAL);
+            row.add(i);
+            row.add(i);
+        }
+
+        return c;
+    }
+
+    private Cursor createPinnedSitesCursor(Integer[] positions) {
+        MatrixCursor c = new MatrixCursor(PINNED_SITES_COLUMNS);
+
+        if (positions == null) {
+            return c;
+        }
+
+        for (int i = 0; i < positions.length; i++) {
+            int position = positions[i];
+
+            RowBuilder row = c.newRow();
+            row.add(-1);
+            row.add(PINNED_PREFIX + "url" + i);
+            row.add(PINNED_PREFIX + "title" + i);
+            row.add(position);
+        }
+
+        return c;
+    }
+
+    private TopSitesCursorWrapper createTopSitesCursorWrapper(int topSitesCount, Integer[] pinnedPositions) {
+        Cursor pinnedSites = createPinnedSitesCursor(pinnedPositions);
+        Cursor topSites = createTopSitesCursor(topSitesCount);
+
+        return new TopSitesCursorWrapper(pinnedSites, topSites, MIN_COUNT);
+    }
+
+    private void assertUrlAndTitle(Cursor c, String prefix, int index) {
+        String url = c.getString(c.getColumnIndex(Combined.URL));
+        String title = c.getString(c.getColumnIndex(Combined.TITLE));
+
+        assertEquals(prefix + "url" + index, url);
+        assertEquals(prefix + "title" + index, title);
+    }
+
+    private void assertBlank(Cursor c) {
+        String url = c.getString(c.getColumnIndex(Combined.URL));
+        String title = c.getString(c.getColumnIndex(Combined.TITLE));
+
+        assertTrue(TextUtils.isEmpty(url));
+        assertTrue(TextUtils.isEmpty(title));
+    }
+
+    public void testCount() {
+        // The sum of top and pinned sites is smaller than MIN_COUNT
+        Cursor c = createTopSitesCursorWrapper(2, new Integer[] { 0, 1 });
+        assertEquals(MIN_COUNT, c.getCount());
+        c.close();
+
+        // No top sites, some pinned sites, still smaller than MIN_COUNT
+        c = createTopSitesCursorWrapper(0, new Integer[] { 0, 1, 2 });
+        assertEquals(MIN_COUNT, c.getCount());
+        c.close();
+
+        // Some top sites, no pinned sites, still smaller than MIN_COUNT
+        c = createTopSitesCursorWrapper(3, null);
+        assertEquals(MIN_COUNT, c.getCount());
+        c.close();
+
+        // The sum of top and pinned sites is greater than MIN_COUNT
+        c = createTopSitesCursorWrapper(10, new Integer[] { 0, 1, 2 });
+        assertEquals(13, c.getCount());
+        c.close();
+    }
+
+    public void testClosedPinnedSites() {
+        Cursor pinnedSites = createPinnedSitesCursor(new Integer[] { 0, 1 });
+        Cursor topSites = createTopSitesCursor(2);
+        Cursor wrapper = new TopSitesCursorWrapper(pinnedSites, topSites, MIN_COUNT);
+
+        // The pinned sites cursor is closed immediately
+        // when a TopSitesCursorWrapper is created.
+        assertTrue(pinnedSites.isClosed());
+
+        // But not the topsites cursor, of course.
+        assertFalse(topSites.isClosed());
+
+        wrapper.close();
+
+        // Closing wrapper closes wrapped cursor
+        assertTrue(topSites.isClosed());
+    }
+
+    public void testIsPinned() {
+        Integer[] pinnedPositions = new Integer[] { 0, 1 };
+        TopSitesCursorWrapper c = createTopSitesCursorWrapper(2, pinnedPositions);
+
+        List<Integer> pinnedList = Arrays.asList(pinnedPositions);
+
+        c.moveToPosition(-1);
+        while (c.moveToNext()) {
+            boolean isPinnedPosition = pinnedList.contains(c.getPosition());
+            assertEquals(isPinnedPosition, c.isPinned());
+        }
+
+        c.close();
+    }
+
+    public void testBlankPositions() {
+        Integer[] pinnedPositions = new Integer[] { 0, 1, 4 };
+        TopSitesCursorWrapper c = createTopSitesCursorWrapper(0, pinnedPositions);
+
+        c.moveToPosition(-1);
+        while (c.moveToNext()) {
+            if (!c.isPinned()) {
+                assertBlank(c);
+            }
+        }
+
+        c.close();
+    }
+
+    public void testColumnValues() {
+        Integer[] pinnedPositions = new Integer[] { 0, 1, 4 };
+        TopSitesCursorWrapper c = createTopSitesCursorWrapper(2, pinnedPositions);
+
+        int topIndex = 0;
+        int pinnedIndex = 0;
+
+        c.moveToPosition(-1);
+        while (c.moveToNext()) {
+            int position = c.getPosition();
+
+            // Last position should be blank
+            if (position == MIN_COUNT - 1) {
+                assertBlank(c);
+            } else {
+                int index;
+                String prefix;
+
+                if (c.isPinned()) {
+                    index = pinnedIndex++;
+                    prefix = PINNED_PREFIX;
+                } else {
+                    index = topIndex++;
+                    prefix = TOP_PREFIX;
+                }
+
+                assertUrlAndTitle(c, prefix, index);
+            }
+        }
+
+        c.close();
+    }
+}
\ No newline at end of file
index 4e5cc647ab24d7038d524c1b5c5d610507949e9c..75caa046e715eb63c24749cfaf688bf3efad0325
GIT binary patch
literal 121856
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
--- a/toolkit/devtools/Console.jsm
+++ b/toolkit/devtools/Console.jsm
@@ -461,17 +461,17 @@ function dumpMessage(aConsole, aLevel, a
  */
 function createDumper(aLevel) {
   return function() {
     if (!shouldLog(aLevel, this.maxLogLevel)) {
       return;
     }
     let args = Array.prototype.slice.call(arguments, 0);
     let frame = getStack(Components.stack.caller, 1)[0];
-    sendConsoleAPIMessage(aLevel, frame, args);
+    sendConsoleAPIMessage(this, aLevel, frame, args);
     let data = args.map(function(arg) {
       return stringify(arg, true);
     });
     dumpMessage(this, aLevel, data.join(" "));
   };
 }
 
 /**
@@ -488,47 +488,49 @@ function createDumper(aLevel) {
 function createMultiLineDumper(aLevel) {
   return function() {
     if (!shouldLog(aLevel, this.maxLogLevel)) {
       return;
     }
     dumpMessage(this, aLevel, "");
     let args = Array.prototype.slice.call(arguments, 0);
     let frame = getStack(Components.stack.caller, 1)[0];
-    sendConsoleAPIMessage(aLevel, frame, args);
+    sendConsoleAPIMessage(this, aLevel, frame, args);
     args.forEach(function(arg) {
       this.dump(log(arg));
     }, this);
   };
 }
 
 /**
  * Send a Console API message. This function will send a console-api-log-event
  * notification through the nsIObserverService.
  *
+ * @param {object} aConsole
+ *        The instance of ConsoleAPI performing the logging.
  * @param {string} aLevel
  *        Message severity level. This is usually the name of the console method
  *        that was called.
  * @param {object} aFrame
  *        The youngest stack frame coming from Components.stack, as formatted by
  *        getStack().
  * @param {array} aArgs
  *        The arguments given to the console method.
  * @param {object} aOptions
  *        Object properties depend on the console method that was invoked:
  *        - timer: for time() and timeEnd(). Holds the timer information.
  *        - groupName: for group(), groupCollapsed() and groupEnd().
  *        - stacktrace: for trace(). Holds the array of stack frames as given by
  *        getStack().
  */
-function sendConsoleAPIMessage(aLevel, aFrame, aArgs, aOptions = {})
+function sendConsoleAPIMessage(aConsole, aLevel, aFrame, aArgs, aOptions = {})
 {
   let consoleEvent = {
     ID: "jsm",
-    innerID: aFrame.filename,
+    innerID: aConsole.innerID || aFrame.filename,
     level: aLevel,
     filename: aFrame.filename,
     lineNumber: aFrame.lineNumber,
     functionName: aFrame.functionName,
     timeStamp: Date.now(),
     arguments: aArgs,
   };
 
@@ -573,25 +575,28 @@ function sendConsoleAPIMessage(aLevel, a
  *        - maxLogLevel {string} : String identifier (See LOG_LEVELS for
  *                            possible values) that allows to filter which
  *                            messages are logged based on their log level.
  *                            If falsy value, all messages will be logged.
  *                            If wrong value that doesn't match any key of
  *                            LOG_LEVELS, no message will be logged
  *        - dump {function} : An optional function to intercept all strings
  *                            written to stdout
+ *        - innerID {string}: An ID representing the source of the message.
+ *                            Normally the inner ID of a DOM window.
  * @return {object}
  *        A console API instance object
  */
 function ConsoleAPI(aConsoleOptions = {}) {
   // Normalize console options to set default values
   // in order to avoid runtime checks on each console method call.
   this.dump = aConsoleOptions.dump || dump;
   this.prefix = aConsoleOptions.prefix || "";
   this.maxLogLevel = aConsoleOptions.maxLogLevel || "all";
+  this.innerID = aConsoleOptions.innerID || null;
 
   // Bind all the functions to this object.
   for (let prop in this) {
     if (typeof(this[prop]) === "function") {
       this[prop] = this[prop].bind(this);
     }
   }
 }
@@ -605,17 +610,17 @@ ConsoleAPI.prototype = {
   exception: createMultiLineDumper("error"),
 
   trace: function Console_trace() {
     if (!shouldLog("trace", this.maxLogLevel)) {
       return;
     }
     let args = Array.prototype.slice.call(arguments, 0);
     let trace = getStack(Components.stack.caller);
-    sendConsoleAPIMessage("trace", trace[0], args,
+    sendConsoleAPIMessage(this, "trace", trace[0], args,
                           { stacktrace: trace });
     dumpMessage(this, "trace", "\n" + formatTrace(trace));
   },
   clear: function Console_clear() {},
 
   dir: createMultiLineDumper("dir"),
   dirxml: createMultiLineDumper("dirxml"),
   group: createDumper("group"),
@@ -623,28 +628,28 @@ ConsoleAPI.prototype = {
 
   time: function Console_time() {
     if (!shouldLog("time", this.maxLogLevel)) {
       return;
     }
     let args = Array.prototype.slice.call(arguments, 0);
     let frame = getStack(Components.stack.caller, 1)[0];
     let timer = startTimer(args[0]);
-    sendConsoleAPIMessage("time", frame, args, { timer: timer });
+    sendConsoleAPIMessage(this, "time", frame, args, { timer: timer });
     dumpMessage(this, "time",
                 "'" + timer.name + "' @ " + (new Date()));
   },
 
   timeEnd: function Console_timeEnd() {
     if (!shouldLog("timeEnd", this.maxLogLevel)) {
       return;
     }
     let args = Array.prototype.slice.call(arguments, 0);
     let frame = getStack(Components.stack.caller, 1)[0];
     let timer = stopTimer(args[0]);
-    sendConsoleAPIMessage("timeEnd", frame, args, { timer: timer });
+    sendConsoleAPIMessage(this, "timeEnd", frame, args, { timer: timer });
     dumpMessage(this, "timeEnd",
                 "'" + timer.name + "' " + timer.duration + "ms");
   },
 };
 
 this.console = new ConsoleAPI();
 this.ConsoleAPI = ConsoleAPI;
--- a/toolkit/devtools/webconsole/test/chrome.ini
+++ b/toolkit/devtools/webconsole/test/chrome.ini
@@ -4,16 +4,17 @@ support-files =
   data.json
   data.json^headers^
   network_requests_iframe.html
 
 [test_basics.html]
 [test_bug819670_getter_throws.html]
 [test_cached_messages.html]
 [test_consoleapi.html]
+[test_consoleapi_innerID.html]
 [test_file_uri.html]
 [test_reflow.html]
 [test_jsterm.html]
 [test_network_get.html]
 [test_network_longstring.html]
 [test_network_post.html]
 [test_nsiconsolemessage.html]
 [test_object_actor.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/webconsole/test/test_consoleapi_innerID.html
@@ -0,0 +1,164 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+  <meta charset="utf8">
+  <title>Test for the innerID property of the Console API</title>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript;version=1.8" src="common.js"></script>
+  <!-- Any copyright is dedicated to the Public Domain.
+     - http://creativecommons.org/publicdomain/zero/1.0/ -->
+</head>
+<body>
+<p>Test for the Console API</p>
+
+<script class="testbody" type="text/javascript;version=1.8">
+SimpleTest.waitForExplicitFinish();
+
+let expectedConsoleCalls = [];
+
+function doConsoleCalls(aState)
+{
+  let { ConsoleAPI } = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
+  let console = new ConsoleAPI({
+    innerID: window.QueryInterface(Ci.nsIInterfaceRequestor)
+                   .getInterface(Ci.nsIDOMWindowUtils)
+                   .currentInnerWindowID
+  });
+
+  let longString = (new Array(DebuggerServer.LONG_STRING_LENGTH + 2)).join("a");
+
+  console.log("foobarBaz-log", undefined);
+  console.info("foobarBaz-info", null);
+  console.warn("foobarBaz-warn", top.document.documentElement);
+  console.debug(null);
+  console.trace();
+  console.dir(top.document, top.location);
+  console.log("foo", longString);
+
+  expectedConsoleCalls = [
+    {
+      level: "log",
+      filename: /test_consoleapi/,
+      functionName: "doConsoleCalls",
+      timeStamp: /^\d+$/,
+      arguments: ["foobarBaz-log", { type: "undefined" }],
+    },
+    {
+      level: "info",
+      filename: /test_consoleapi/,
+      functionName: "doConsoleCalls",
+      timeStamp: /^\d+$/,
+      arguments: ["foobarBaz-info", { type: "null" }],
+    },
+    {
+      level: "warn",
+      filename: /test_consoleapi/,
+      functionName: "doConsoleCalls",
+      timeStamp: /^\d+$/,
+      arguments: ["foobarBaz-warn", { type: "object", actor: /[a-z]/ }],
+    },
+    {
+      level: "debug",
+      filename: /test_consoleapi/,
+      functionName: "doConsoleCalls",
+      timeStamp: /^\d+$/,
+      arguments: [{ type: "null" }],
+    },
+    {
+      level: "trace",
+      filename: /test_consoleapi/,
+      functionName: "doConsoleCalls",
+      timeStamp: /^\d+$/,
+      stacktrace: [
+        {
+          filename: /test_consoleapi/,
+          functionName: "doConsoleCalls",
+        },
+        {
+          filename: /test_consoleapi/,
+          functionName: "onAttach",
+        },
+      ],
+    },
+    {
+      level: "dir",
+      filename: /test_consoleapi/,
+      functionName: "doConsoleCalls",
+      timeStamp: /^\d+$/,
+      arguments: [
+        {
+          type: "object",
+          actor: /[a-z]/,
+          class: "XULDocument",
+        },
+        {
+          type: "object",
+          actor: /[a-z]/,
+          class: "Location",
+        }
+      ],
+    },
+    {
+      level: "log",
+      filename: /test_consoleapi/,
+      functionName: "doConsoleCalls",
+      timeStamp: /^\d+$/,
+      arguments: [
+        "foo",
+        {
+          type: "longString",
+          initial: longString.substring(0,
+            DebuggerServer.LONG_STRING_INITIAL_LENGTH),
+          length: longString.length,
+          actor: /[a-z]/,
+        },
+      ],
+    },
+  ];
+}
+
+function startTest()
+{
+  removeEventListener("load", startTest);
+
+  attachConsole(["ConsoleAPI"], onAttach, true);
+}
+
+function onAttach(aState, aResponse)
+{
+  onConsoleAPICall = onConsoleAPICall.bind(null, aState);
+  aState.dbgClient.addListener("consoleAPICall", onConsoleAPICall);
+  doConsoleCalls(aState.actor);
+}
+
+let consoleCalls = [];
+
+function onConsoleAPICall(aState, aType, aPacket)
+{
+  info("received message level: " + aPacket.message.level);
+  is(aPacket.from, aState.actor, "console API call actor");
+
+  consoleCalls.push(aPacket.message);
+  if (consoleCalls.length != expectedConsoleCalls.length) {
+    return;
+  }
+
+  aState.dbgClient.removeListener("consoleAPICall", onConsoleAPICall);
+
+  expectedConsoleCalls.forEach(function(aMessage, aIndex) {
+    info("checking received console call #" + aIndex);
+    checkConsoleAPICall(consoleCalls[aIndex], expectedConsoleCalls[aIndex]);
+  });
+
+
+  consoleCalls = [];
+
+  closeDebugger(aState, function() {
+    SimpleTest.finish();
+  });
+}
+
+addEventListener("load", startTest);
+</script>
+</body>
+</html>
--- a/toolkit/devtools/webconsole/utils.js
+++ b/toolkit/devtools/webconsole/utils.js
@@ -1344,17 +1344,17 @@ ConsoleAPIListener.prototype =
   observe: function CAL_observe(aMessage, aTopic)
   {
     if (!this.owner) {
       return;
     }
 
     let apiMessage = aMessage.wrappedJSObject;
     if (this.window) {
-      let msgWindow = Services.wm.getOuterWindowWithId(apiMessage.ID);
+      let msgWindow = Services.wm.getCurrentInnerWindowWithId(apiMessage.innerID);
       if (!msgWindow || !this.layoutHelpers.isIncludedInTopLevelWindow(msgWindow)) {
         // Not the same window!
         return;
       }
     }
 
     this.owner.onConsoleAPICall(apiMessage);
   },
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -2243,20 +2243,26 @@ nsWindow::SetNonClientMargins(nsIntMargi
       mHideChrome)
     return NS_ERROR_INVALID_ARG;
 
   // Request for a reset
   if (margins.top == -1 && margins.left == -1 &&
       margins.right == -1 && margins.bottom == -1) {
     mCustomNonClient = false;
     mNonClientMargins = margins;
-    RemovePropW(mWnd, kManageWindowInfoProperty);
     // Force a reflow of content based on the new client
     // dimensions.
     ResetLayout();
+
+    int windowStatus =
+      reinterpret_cast<LONG_PTR>(GetPropW(mWnd, kManageWindowInfoProperty));
+    if (windowStatus) {
+      ::SendMessageW(mWnd, WM_NCACTIVATE, 1 != windowStatus, 0);
+    }
+
     return NS_OK;
   }
 
   if (margins.top < -1 || margins.bottom < -1 ||
       margins.left < -1 || margins.right < -1)
     return NS_ERROR_INVALID_ARG;
 
   mNonClientMargins = margins;
@@ -4666,37 +4672,36 @@ nsWindow::ProcessMessage(UINT msg, WPARA
       }
 
     case WM_NCACTIVATE:
     {
       /*
        * WM_NCACTIVATE paints nc areas. Avoid this and re-route painting
        * through WM_NCPAINT via InvalidateNonClientRegion.
        */
+      UpdateGetWindowInfoCaptionStatus(FALSE != wParam);
 
       if (!mCustomNonClient)
         break;
 
       // let the dwm handle nc painting on glass
       if(nsUXThemeData::CheckForCompositor())
         break;
 
       if (wParam == TRUE) {
         // going active
         *aRetValue = FALSE; // ignored
         result = true;
-        UpdateGetWindowInfoCaptionStatus(true);
         // invalidate to trigger a paint
         InvalidateNonClientRegion();
         break;
       } else {
         // going inactive
         *aRetValue = TRUE; // go ahead and deactive
         result = true;
-        UpdateGetWindowInfoCaptionStatus(false);
         // invalidate to trigger a paint
         InvalidateNonClientRegion();
         break;
       }
     }
 
     case WM_NCPAINT:
     {
@@ -5200,17 +5205,16 @@ nsWindow::ProcessMessage(UINT msg, WPARA
     break;
 
   case WM_DWMCOMPOSITIONCHANGED:
     // First, update the compositor state to latest one. All other methods
     // should use same state as here for consistency painting.
     nsUXThemeData::CheckForCompositor(true);
 
     UpdateNonClientMargins();
-    RemovePropW(mWnd, kManageWindowInfoProperty);
     BroadcastMsg(mWnd, WM_DWMCOMPOSITIONCHANGED);
     NotifyThemeChanged();
     UpdateGlass();
     Invalidate(true, true, true);
     break;
 
   case WM_UPDATEUISTATE:
   {