Merge fx-team to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 30 Aug 2013 21:00:08 -0400
changeset 145142 4ba8dda1ee31d519561ef39ad682e70da4baa93f
parent 145134 1ac8270f3f64731e2177b43009e512509a9a2d38 (current diff)
parent 145141 cb7653a95aa87d1444f260d8120821e7eed19b8a (diff)
child 145143 d08c4ec7ab82a104ba3c3cb698abf31cdeb437c2
child 145145 4b694a8b31099a1d64bbd4aa9e41a5792377de68
child 145147 f15a6ae7a3ac458db82775d02a1609f9672dde28
child 145151 7973c4b7cfd0678a8cd1b61c631bb65d725b943a
child 155712 a6fe43be166cfe04778a3a7248cba1f6fa161948
push id25195
push userryanvm@gmail.com
push dateSat, 31 Aug 2013 01:00:12 +0000
treeherdermozilla-central@4ba8dda1ee31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone26.0a1
first release with
nightly linux32
4ba8dda1ee31 / 26.0a1 / 20130831030224 / files
nightly linux64
4ba8dda1ee31 / 26.0a1 / 20130831030224 / files
nightly mac
4ba8dda1ee31 / 26.0a1 / 20130831030224 / files
nightly win32
4ba8dda1ee31 / 26.0a1 / 20130831030224 / files
nightly win64
4ba8dda1ee31 / 26.0a1 / 20130831030224 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge fx-team to m-c.
--- a/browser/base/content/abouthome/aboutHome.js
+++ b/browser/base/content/abouthome/aboutHome.js
@@ -148,17 +148,17 @@ const SNIPPETS_UPDATE_INTERVAL_MS = 8640
 const DATABASE_NAME = "abouthome";
 const DATABASE_VERSION = 1;
 const SNIPPETS_OBJECTSTORE_NAME = "snippets";
 
 // This global tracks if the page has been set up before, to prevent double inits
 let gInitialized = false;
 let gObserver = new MutationObserver(function (mutations) {
   for (let mutation of mutations) {
-    if (mutation.attributeName == "searchEngineURL") {
+    if (mutation.attributeName == "searchEngineName") {
       setupSearchEngine();
       if (!gInitialized) {
         ensureSnippetsMapThen(loadSnippets);
         gInitialized = true;
       }
       return;
     }
   }
@@ -290,62 +290,27 @@ function ensureSnippetsMapThen(aCallback
       setTimeout(invokeCallbacks, 0);
     }
   }
 }
 
 function onSearchSubmit(aEvent)
 {
   let searchTerms = document.getElementById("searchText").value;
-  let searchURL = document.documentElement.getAttribute("searchEngineURL");
-
-  if (searchURL && searchTerms.length > 0) {
-    // Send an event that a search was performed. This was originally
-    // added so Firefox Health Report could record that a search from
-    // about:home had occurred.
-    let engineName = document.documentElement.getAttribute("searchEngineName");
-    let event = new CustomEvent("AboutHomeSearchEvent", {detail: engineName});
-    document.dispatchEvent(event);
-
-    const SEARCH_TOKEN = "_searchTerms_";
-    let searchPostData = document.documentElement.getAttribute("searchEnginePostData");
-    if (searchPostData) {
-      // Check if a post form already exists. If so, remove it.
-      const POST_FORM_NAME = "searchFormPost";
-      let form = document.forms[POST_FORM_NAME];
-      if (form) {
-        form.parentNode.removeChild(form);
-      }
+  let engineName = document.documentElement.getAttribute("searchEngineName");
 
-      // Create a new post form.
-      form = document.body.appendChild(document.createElement("form"));
-      form.setAttribute("name", POST_FORM_NAME);
-      // Set the URL to submit the form to.
-      form.setAttribute("action", searchURL.replace(SEARCH_TOKEN, searchTerms));
-      form.setAttribute("method", "post");
-
-      // Create new <input type=hidden> elements for search param.
-      searchPostData = searchPostData.split("&");
-      for (let postVar of searchPostData) {
-        let [name, value] = postVar.split("=");
-        if (value == SEARCH_TOKEN) {
-          value = searchTerms;
-        }
-        let input = document.createElement("input");
-        input.setAttribute("type", "hidden");
-        input.setAttribute("name", name);
-        input.setAttribute("value", value);
-        form.appendChild(input);
-      }
-      // Submit the form.
-      form.submit();
-   } else {
-      searchURL = searchURL.replace(SEARCH_TOKEN, encodeURIComponent(searchTerms));
-      window.location.href = searchURL;
-    }
+  if (engineName && searchTerms.length > 0) {
+    // Send an event that will perform a search and Firefox Health Report will
+    // record that a search from about:home has occurred.
+    let eventData = JSON.stringify({
+      engineName: engineName,
+      searchTerms: searchTerms
+    });
+    let event = new CustomEvent("AboutHomeSearchEvent", {detail: eventData});
+    document.dispatchEvent(event);
   }
 
   aEvent.preventDefault();
 }
 
 
 function setupSearchEngine()
 {
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -106,17 +106,17 @@
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing"
       oncommand="OpenBrowserWindow({private: true});"/>
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
     <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
     <command id="Social:TogglePageMark" oncommand="SocialMark.togglePageMark();" disabled="true"/>
     <command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/>
-    <command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();"/>
+    <command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();" hidden="true"/>
     <command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/>
     <command id="Social:FocusChat" oncommand="SocialChatBar.focus();" hidden="true" disabled="true"/>
     <command id="Social:Toggle" oncommand="Social.toggle();" hidden="true"/>
     <command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/>
   </commandset>
 
   <commandset id="placesCommands">
     <command id="Browser:ShowAllBookmarks"
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -40,19 +40,19 @@ SocialUI = {
 
     Services.prefs.addObserver("social.sidebar.open", this, false);
     Services.prefs.addObserver("social.toast-notifications.enabled", this, false);
 
     gBrowser.addEventListener("ActivateSocialFeature", this._activationEventHandler.bind(this), true, true);
 
     if (!Social.initialized) {
       Social.init();
-    } else if (Social.enabled) {
-      // social was previously initialized, so it's not going to notify us of
-      // anything, so handle that now.
+    } else if (Social.providers.length > 0) {
+      // Social was initialized during startup in a previous window. If we have
+      // providers enabled initialize the UI for this window.
       this.observe(null, "social:providers-changed", null);
       this.observe(null, "social:provider-set", Social.provider ? Social.provider.origin : null);
     }
   },
 
   // Called on window unload
   uninit: function SocialUI_uninit() {
     Services.obs.removeObserver(this, "social:ambient-notification-changed");
@@ -317,17 +317,20 @@ SocialUI = {
     let win = linkNode.ownerDocument.defaultView;
     let container = win.QueryInterface(Ci.nsIInterfaceRequestor)
                                   .getInterface(Ci.nsIWebNavigation)
                                   .QueryInterface(Ci.nsIDocShell)
                                   .chromeEventHandler;
     let containerParent = container.parentNode;
     if (containerParent.classList.contains("social-panel") &&
         containerParent instanceof Ci.nsIDOMXULPopupElement) {
-      containerParent.hidePopup();
+      // allow the link traversal to finish before closing the panel
+      setTimeout(() => {
+        containerParent.hidePopup();
+      }, 0);
     }
   },
 
   get _chromeless() {
     // Is this a popup window that doesn't want chrome shown?
     let docElem = document.documentElement;
     // extrachrome is not restored during session restore, so we need
     // to check for the toolbar as well.
@@ -688,17 +691,17 @@ SocialShare = {
   },
 
   onShowing: function() {
     this.shareButton.setAttribute("open", "true");
   },
 
   onHidden: function() {
     this.shareButton.removeAttribute("open");
-    this.iframe.setAttribute("src", "data:text/plain;charset=utf8,")
+    this.iframe.setAttribute("src", "data:text/plain;charset=utf8,");
     this.currentShare = null;
   },
 
   setErrorMessage: function() {
     let iframe = this.iframe;
     if (!iframe)
       return;
 
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -85,29 +85,23 @@ let AboutHomeListener = {
     if (doc.documentURI.toLowerCase() != "about:home")
       return;
 
     if (aData.showRestoreLastSession && !PrivateBrowsingUtils.isWindowPrivate(content))
       doc.getElementById("launcher").setAttribute("session", "true");
 
     // Inject search engine and snippets URL.
     let docElt = doc.documentElement;
-    // set the following attributes BEFORE searchEngineURL, which triggers to
+    // set the following attributes BEFORE searchEngineName, which triggers to
     // show the snippets when it's set.
     docElt.setAttribute("snippetsURL", aData.snippetsURL);
     if (aData.showKnowYourRights)
       docElt.setAttribute("showKnowYourRights", "true");
     docElt.setAttribute("snippetsVersion", aData.snippetsVersion);
-
-    let engine = aData.defaultSearchEngine;
-    docElt.setAttribute("searchEngineName", engine.name);
-    docElt.setAttribute("searchEnginePostData", engine.postDataString || "");
-    // Again, keep the searchEngineURL as the last attribute, because the
-    // mutation observer in aboutHome.js is counting on that.
-    docElt.setAttribute("searchEngineURL", engine.searchURL);
+    docElt.setAttribute("searchEngineName", Services.search.defaultEngine.name);
   },
 
   onPageLoad: function() {
     let doc = content.document;
     if (doc.documentURI.toLowerCase() != "about:home" ||
         doc.documentElement.hasAttribute("hasBrowserHandlers")) {
       return;
     }
@@ -130,17 +124,17 @@ let AboutHomeListener = {
     // the hidden attribute set on the apps button in aboutHome.xhtml
     if (Services.prefs.getPrefType("browser.aboutHome.apps") == Services.prefs.PREF_BOOL &&
         Services.prefs.getBoolPref("browser.aboutHome.apps"))
       doc.getElementById("apps").removeAttribute("hidden");
 
     sendAsyncMessage("AboutHome:RequestUpdate");
 
     doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
-      sendAsyncMessage("AboutHome:Search", { engineName: e.detail });
+      sendAsyncMessage("AboutHome:Search", { searchData: e.detail });
     }, true, true);
   },
 
   onClick: function(aEvent) {
     if (!aEvent.isTrusted || // Don't trust synthetic events
         aEvent.button == 2 || aEvent.target.localName != "button") {
       return;
     }
@@ -275,9 +269,9 @@ let ClickEventHandler = {
       node = node.parentNode;
     }
 
     // In case of XLink, we don't return the node we got href from since
     // callers expect <a>-like elements.
     return [href ? makeURLAbsolute(baseURI, href) : null, null];
   }
 };
-ClickEventHandler.init();
\ No newline at end of file
+ClickEventHandler.init();
--- a/browser/base/content/test/browser_aboutHome.js
+++ b/browser/base/content/test/browser_aboutHome.js
@@ -102,17 +102,18 @@ let gTests = [
     }
 
     let numSearchesBefore = 0;
     let deferred = Promise.defer();
     let doc = gBrowser.contentDocument;
     let engineName = doc.documentElement.getAttribute("searchEngineName");
 
     doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
-      is(e.detail, engineName, "Detail is search engine name");
+      let data = JSON.parse(e.detail);
+      is(data.engineName, engineName, "Detail is search engine name");
 
       // We use executeSoon() to ensure that this code runs after the
       // count has been updated in browser.js, since it uses the same
       // event.
       executeSoon(function () {
         getNumberOfSearches(engineName).then(num => {
           is(num, numSearchesBefore + 1, "One more search recorded.");
           deferred.resolve();
@@ -282,17 +283,17 @@ let gTests = [
       let needle = "Search for something awesome.";
       let document = gBrowser.selectedTab.linkedBrowser.contentDocument;
       let searchText = document.getElementById("searchText");
 
       // We're about to change the search engine. Once the change has
       // propagated to the about:home content, we want to perform a search.
       let mutationObserver = new MutationObserver(function (mutations) {
         for (let mutation of mutations) {
-          if (mutation.attributeName == "searchEngineURL") {
+          if (mutation.attributeName == "searchEngineName") {
             searchText.value = needle;
             searchText.focus();
             EventUtils.synthesizeKey("VK_RETURN", {});
           }
         }
       });
       mutationObserver.observe(document.documentElement, { attributes: true });
 
@@ -440,17 +441,17 @@ function promiseBrowserAttributes(aTab)
       info("Got attribute mutation: " + mutation.attributeName +
                                     " from " + mutation.oldValue); 
       if (mutation.attributeName == "snippetsURL" &&
           docElt.getAttribute("snippetsURL") != "nonexistent://test") {
         docElt.setAttribute("snippetsURL", "nonexistent://test");
       }
 
       // Now we just have to wait for the last attribute.
-      if (mutation.attributeName == "searchEngineURL") {
+      if (mutation.attributeName == "searchEngineName") {
         info("Remove attributes observer");
         observer.disconnect();
         // Must be sure to continue after the page mutation observer.
         executeSoon(function() deferred.resolve());
         break;
       }
     }
   });
--- a/browser/base/content/test/social/browser_social_flyout.js
+++ b/browser/base/content/test/social/browser_social_flyout.js
@@ -128,38 +128,36 @@ var tests = {
     }
     port.postMessage({topic: "test-init"});
   },
 
   testCloseOnLinkTraversal: function(next) {
 
     function onTabOpen(event) {
       gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, true);
-      is(panel.state, "closed", "flyout should be closed");
-      ok(true, "Link should open a new tab");
-      executeSoon(function(){
+      waitForCondition(function() { return panel.state == "closed" }, function() {
         gBrowser.removeTab(event.target);
         next();
-      });
+      }, "panel should close after tab open");
     }
 
     let panel = document.getElementById("social-flyout-panel");
     let port = Social.provider.getWorkerPort();
     ok(port, "provider has a port");
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
         case "test-init-done":
           port.postMessage({topic: "test-flyout-open"});
           break;
         case "got-flyout-visibility":
           if (e.data.result == "shown") {
             // click on our test link
             is(panel.state, "open", "flyout should be open");
-            gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, true); 
+            gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, true);
             let iframe = panel.firstChild;
             iframe.contentDocument.getElementById('traversal').click();
           }
           break;
       }
     }
     port.postMessage({topic: "test-init"});
   }
--- a/browser/base/content/test/social/browser_social_window.js
+++ b/browser/base/content/test/social/browser_social_window.js
@@ -1,23 +1,24 @@
 // 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/.
 
 // Test the top-level window UI for social.
 
+let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
+
 // This function should "reset" Social such that the next time Social.init()
 // is called (eg, when a new window is opened), it re-performs all
 // initialization.
 function resetSocial() {
   Social.initialized = false;
   Social._provider = null;
   Social.providers = [];
   // *sob* - listeners keep getting added...
-  let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
   SocialService._providerListeners.clear();
 }
 
 let createdWindows = [];
 
 function openWindowAndWaitForInit(callback) {
   // this notification tells us SocialUI.init() has been run...
   let topic = "browser-delayed-startup-finished";
@@ -47,37 +48,39 @@ let manifest = { // normal provider
 };
 
 function test() {
   waitForExplicitFinish();
   runSocialTests(tests, undefined, postTestCleanup);
 }
 
 let tests = {
-  // check when social is totally disabled at startup (ie, no providers)
+  // check when social is totally disabled at startup (ie, no providers enabled)
   testInactiveStartup: function(cbnext) {
     is(Social.providers.length, 0, "needs zero providers to start this test.");
+    ok(!SocialService.hasEnabledProviders, "no providers are enabled");
     resetSocial();
     openWindowAndWaitForInit(function(w1) {
       checkSocialUI(w1);
       // Now social is (re-)initialized, open a secondary window and check that.
       openWindowAndWaitForInit(function(w2) {
         checkSocialUI(w2);
         checkSocialUI(w1);
         cbnext();
       });
     });
   },
 
-  // Check when providers exist and social is turned on at startup.
+  // Check when providers are enabled and social is turned on at startup.
   testEnabledStartup: function(cbnext) {
     runSocialTestWithProvider(manifest, function (finishcb) {
       resetSocial();
       openWindowAndWaitForInit(function(w1) {
         ok(Social.enabled, "social is enabled");
+        ok(SocialService.hasEnabledProviders, "providers are enabled");
         checkSocialUI(w1);
         // now init is complete, open a second window
         openWindowAndWaitForInit(function(w2) {
           checkSocialUI(w2);
           checkSocialUI(w1);
           // disable social and re-check
           Services.prefs.setBoolPref("social.enabled", false);
           executeSoon(function() { // let all the UI observers run...
@@ -86,59 +89,61 @@ let tests = {
             checkSocialUI(w1);
             finishcb();
           });
         });
       });
     }, cbnext);
   },
 
-  // Check when providers exist but social is turned off at startup.
+  // Check when providers are enabled but social is turned off at startup.
   testDisabledStartup: function(cbnext) {
-    runSocialTestWithProvider(manifest, function (finishcb) {
+    setManifestPref("social.manifest.test", manifest);
+    SocialService.addProvider(manifest, function (provider) {
       Services.prefs.setBoolPref("social.enabled", false);
       resetSocial();
+      ok(SocialService.hasEnabledProviders, "providers are enabled");
       openWindowAndWaitForInit(function(w1) {
         ok(!Social.enabled, "social is disabled");
         checkSocialUI(w1);
         // now init is complete, open a second window
         openWindowAndWaitForInit(function(w2) {
           checkSocialUI(w2);
           checkSocialUI(w1);
           // enable social and re-check
           Services.prefs.setBoolPref("social.enabled", true);
           executeSoon(function() { // let all the UI observers run...
             ok(Social.enabled, "social is enabled");
             checkSocialUI(w2);
             checkSocialUI(w1);
-            finishcb();
+            SocialService.removeProvider(manifest.origin, function() {
+              Services.prefs.clearUserPref("social.manifest.test");
+              cbnext();
+            });
           });
         });
       });
     }, cbnext);
   },
 
-  // Check when the last provider is removed.
+  // Check when the last provider is disabled.
   testRemoveProvider: function(cbnext) {
-    runSocialTestWithProvider(manifest, function (finishcb) {
+    setManifestPref("social.manifest.test", manifest);
+    SocialService.addProvider(manifest, function (provider) {
       openWindowAndWaitForInit(function(w1) {
         checkSocialUI(w1);
         // now init is complete, open a second window
         openWindowAndWaitForInit(function(w2) {
           checkSocialUI(w2);
-          // remove the current provider.
-          let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
+          // disable the current provider.
           SocialService.removeProvider(manifest.origin, function() {
             ok(!Social.enabled, "social is disabled");
             is(Social.providers.length, 0, "no providers");
             checkSocialUI(w2);
             checkSocialUI(w1);
-            // *sob* - runSocialTestWithProvider's cleanup fails when it can't
-            // remove the provider, so re-add it.
-            SocialService.addProvider(manifest, function() {
-              finishcb();
-            });
+            Services.prefs.clearUserPref("social.manifest.test");
+            cbnext();
           });
         });
       });
     }, cbnext);
   },
 }
--- a/browser/base/content/test/social/head.js
+++ b/browser/base/content/test/social/head.js
@@ -189,23 +189,32 @@ function runSocialTests(tests, cbPreTest
     });
   }
   runNextTest();
 }
 
 // A fairly large hammer which checks all aspects of the SocialUI for
 // internal consistency.
 function checkSocialUI(win) {
+  let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
   win = win || window;
   let doc = win.document;
   let provider = Social.provider;
   let enabled = win.SocialUI.enabled;
   let active = Social.providers.length > 0 && !win.SocialUI._chromeless &&
                !PrivateBrowsingUtils.isWindowPrivate(win);
 
+  // if we have enabled providers, we should also have instances of those
+  // providers
+  if (SocialService.hasEnabledProviders) {
+    ok(Social.providers.length > 0, "providers are enabled");
+  } else {
+    is(Social.providers.length, 0, "providers are not enabled");
+  }
+
   // some local helpers to avoid log-spew for the many checks made here.
   let numGoodTests = 0, numTests = 0;
   function _ok(what, msg) {
     numTests++;
     if (!ok)
       ok(what, msg)
     else
       ++numGoodTests;
@@ -241,16 +250,17 @@ function checkSocialUI(win) {
   // the menus should always have the provider name
   if (provider) {
     for (let id of ["menu_socialSidebar", "menu_socialAmbientMenu"])
       _is(document.getElementById(id).getAttribute("label"), Social.provider.name, "element has the provider name");
   }
 
   // and for good measure, check all the social commands.
   isbool(!doc.getElementById("Social:Toggle").hidden, active, "Social:Toggle visible?");
+  isbool(!doc.getElementById("Social:ToggleSidebar").hidden, enabled, "Social:ToggleSidebar visible?");
   isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?");
   isbool(!doc.getElementById("Social:FocusChat").hidden, enabled, "Social:FocusChat visible?");
   isbool(doc.getElementById("Social:FocusChat").getAttribute("disabled"), enabled ? "false" : "true", "Social:FocusChat disabled?");
   _is(doc.getElementById("Social:TogglePageMark").getAttribute("disabled"), canMark ? "false" : "true", "Social:TogglePageMark enabled?");
 
   // broadcasters.
   isbool(!doc.getElementById("socialActiveBroadcaster").hidden, active, "socialActiveBroadcaster hidden?");
   // and report on overall success of failure of the various checks here.
new file mode 100644
--- /dev/null
+++ b/browser/metro/base/content/bindings/notification.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+
+<!-- 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/. -->
+
+<!DOCTYPE bindings [
+<!ENTITY % notificationDTD SYSTEM "chrome://global/locale/notification.dtd">
+%notificationDTD;
+]>
+
+<bindings id="notificationBindings"
+          xmlns="http://www.mozilla.org/xbl"
+          xmlns:xbl="http://www.mozilla.org/xbl"
+          xmlns:html="http://www.w3.org/1999/xhtml"
+          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+  <binding id="notificationbox" extends="chrome://global/content/bindings/notification.xml#notificationbox">
+    <content>
+      <xul:stack xbl:inherits="hidden=notificationshidden"
+                 class="notificationbox-stack">
+        <xul:spacer/>
+        <children includes="notification"/>
+      </xul:stack>
+      <html:div anonid="layer1" class="notification-layer"></html:div>
+      <html:div anonid="layer2" class="notification-layer"></html:div>
+      <children/>
+    </content>
+
+    <implementation>
+      <constructor>
+        <![CDATA[
+          this.addEventListener("AlertActive", this.handleEvent, true);
+          this.addEventListener("AlertClose", this.handleEvent, true);
+          this.setAttribute("count", 0);
+        ]]>
+      </constructor>
+      <destructor>
+        <![CDATA[
+          this.removeEventListener("AlertActive", this.handleEvent, true);
+          this.removeEventListener("AlertClose", this.handleEvent, true);
+        ]]>
+      </destructor>
+      <method name="removeNotification">
+        <parameter name="aItem"/>
+        <parameter name="aSkipAnimation"/>
+        <body>
+          <![CDATA[
+            if (aItem == this.currentNotification)
+              this.removeCurrentNotification(aSkipAnimation);
+            else if (aItem != this._closedNotification)
+              this._removeNotificationElement(aItem);
+
+            // Fire notification closed event.
+            let event = new Event('AlertClose');
+            this.dispatchEvent(event);
+
+            return aItem;
+          ]]>
+        </body>
+      </method>
+      <method name="handleEvent">
+        <parameter name="aEvent"/>
+        <body>
+          <![CDATA[
+            switch (aEvent.type) {
+              case "AlertActive":
+              case "AlertClose":
+                this.setAttribute("count", this.allNotifications.length);
+                break;
+            }
+          ]]>
+        </body>
+      </method>
+    </implementation>
+  </binding>
+
+
+</bindings>
--- a/browser/metro/base/content/browser.css
+++ b/browser/metro/base/content/browser.css
@@ -41,16 +41,20 @@ settings {
 setting {
   display: none;
 }
 
 autoscroller {
   -moz-binding: url('chrome://browser/content/bindings/popup.xml#element-popup');
 }
 
+notificationbox {
+  -moz-binding: url('chrome://browser/content/bindings/notification.xml#notificationbox');
+}
+
 circularprogressindicator {
   -moz-binding: url('chrome://browser/content/bindings/circularprogress.xml#circular-progress-indicator');
 }
 
 setting[type="bool"] {
   display: -moz-box;
   -moz-binding: url("chrome://browser/content/bindings/toggleswitch.xml#setting-fulltoggle-bool");
 }
--- a/browser/metro/base/jar.mn
+++ b/browser/metro/base/jar.mn
@@ -23,16 +23,17 @@ chrome.jar:
   content/bindings/grid.xml                    (content/bindings/grid.xml)
   content/bindings/urlbar.xml                  (content/bindings/urlbar.xml)
   content/bindings/appbar.xml                  (content/bindings/appbar.xml)
   content/bindings/flyoutpanel.xml             (content/bindings/flyoutpanel.xml)
   content/bindings/selectionoverlay.xml        (content/bindings/selectionoverlay.xml)
   content/bindings/cssthrobber.xml             (content/bindings/cssthrobber.xml)
   content/bindings/popup.xml                   (content/bindings/popup.xml)
   content/bindings/circularprogress.xml        (content/bindings/circularprogress.xml)
+  content/bindings/notification.xml            (content/bindings/notification.xml)
 
 * content/flyoutpanels/FlyoutPanelsUI.js       (content/flyoutpanels/FlyoutPanelsUI.js)
 * content/flyoutpanels/AboutFlyoutPanel.js     (content/flyoutpanels/AboutFlyoutPanel.js)
   content/flyoutpanels/PrefsFlyoutPanel.js     (content/flyoutpanels/PrefsFlyoutPanel.js)
 
   content/helperui/AlertsHelper.js             (content/helperui/AlertsHelper.js)
   content/helperui/IndexedDB.js                (content/helperui/IndexedDB.js)
   content/helperui/MenuUI.js                   (content/helperui/MenuUI.js)
--- a/browser/metro/theme/platform.css
+++ b/browser/metro/theme/platform.css
@@ -442,18 +442,37 @@ richlistitem[typeName="message"] {
 
 notification {
   background: hsl(0, 0%, 98%);
   border-bottom: 1px solid hsla(0, 0%, 0%, .07);
   box-shadow: 0 0 10px hsla(0, 0%, 0%, .1);
   min-height: 64px;
 }
 
+notificationbox[count="0"] .notification-layer,
+notificationbox[count="1"] .notification-layer,
+notificationbox[count="2"] .notification-layer[anonid="layer2"] {
+  visibility: collapse;
+}
+
+notificationbox[count="2"] .notification-layer[anonid="layer1"],
+notificationbox[count="3"] .notification-layer[anonid="layer1"],
+notificationbox[count="3"] .notification-layer[anonid="layer2"] {
+  visibility: visible;
+}
+
+.notification-layer {
+  border: @metro_border_thin@ solid @field_disabled_foreground_color@;
+  border-bottom: none;
+  height:5px
+}
+
 .notification-inner {
   border-style: none;
+  border: @metro_border_thin@ solid @field_disabled_foreground_color@;
 }
 
 .notification-button {
   -moz-margin-start: 0;
   -moz-margin-end: 20px;
 }
 
 .messageImage {
--- a/browser/modules/AboutHome.jsm
+++ b/browser/modules/AboutHome.jsm
@@ -20,31 +20,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 const SNIPPETS_URL_PREF = "browser.aboutHomeSnippets.updateUrl";
 
 // Should be bumped up if the snippets content format changes.
 const STARTPAGE_VERSION = 4;
 
 this.AboutHomeUtils = {
   get snippetsVersion() STARTPAGE_VERSION,
 
-  /**
-   * Returns an object containing the name and searchURL of the original default
-   * search engine.
-   */
-  get defaultSearchEngine() {
-    let defaultEngine = Services.search.defaultEngine;
-    let submission = defaultEngine.getSubmission("_searchTerms_", null, "homepage");
-
-    return Object.freeze({
-      name: defaultEngine.name,
-      searchURL: submission.uri.spec,
-      postDataString: submission.postDataString
-    });
-  },
-
   /*
    * showKnowYourRights - Determines if the user should be shown the
    * about:rights notification. The notification should *not* be shown if
    * we've already shown the current version, or if the override pref says to
    * never show it. The notification *should* be shown if it's never been seen
    * before, if a newer version is available, or if the override pref says to
    * always show it.
    */
@@ -168,34 +153,43 @@ let AboutHome = {
         window.openPreferences();
         break;
 
       case "AboutHome:RequestUpdate":
         this.sendAboutHomeData(aMessage.target);
         break;
 
       case "AboutHome:Search":
+        let data;
+        try {
+          data = JSON.parse(aMessage.data.searchData);
+        } catch(ex) {
+          Cu.reportError(ex);
+          break;
+        }
 #ifdef MOZ_SERVICES_HEALTHREPORT
-        window.BrowserSearch.recordSearchInHealthReport(aMessage.data.engineName, "abouthome");
+        window.BrowserSearch.recordSearchInHealthReport(data.engineName, "abouthome");
 #endif
+        // Trigger a search through nsISearchEngine.getSubmission()
+        let submission = Services.search.currentEngine.getSubmission(data.searchTerms);
+        window.loadURI(submission.uri.spec, null, submission.postData);
         break;
     }
   },
 
   // Send all the chrome-privileged data needed by about:home. This
   // gets re-sent when the search engine changes.
   sendAboutHomeData: function(target) {
     let ss = Cc["@mozilla.org/browser/sessionstore;1"].
                getService(Ci.nsISessionStore);
     let data = {
       showRestoreLastSession: ss.canRestoreLastSession,
       snippetsURL: AboutHomeUtils.snippetsURL,
       showKnowYourRights: AboutHomeUtils.showKnowYourRights,
-      snippetsVersion: AboutHomeUtils.snippetsVersion,
-      defaultSearchEngine: AboutHomeUtils.defaultSearchEngine
+      snippetsVersion: AboutHomeUtils.snippetsVersion
     };
 
     if (AboutHomeUtils.showKnowYourRights) {
       // Set pref to indicate we've shown the notification.
       let currentVersion = Services.prefs.getIntPref("browser.rights.version");
       Services.prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true);
     }
 
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -153,18 +153,19 @@ this.Social = {
 
   init: function Social_init() {
     this._disabledForSafeMode = Services.appinfo.inSafeMode && this.enabled;
 
     if (this.initialized) {
       return;
     }
     this.initialized = true;
-
-    if (SocialService.enabled) {
+    // if SocialService.hasEnabledProviders, retreive the providers so the
+    // front-end can generate UI
+    if (SocialService.hasEnabledProviders) {
       // Retrieve the current set of providers, and set the current provider.
       SocialService.getOrderedProviderList(function (providers) {
         Social._updateProviderCache(providers);
         Social._updateWorkerState(true);
       });
     }
 
     // Register an observer for changes to the provider list
--- a/mobile/android/base/resources/layout/home_empty_page.xml
+++ b/mobile/android/base/resources/layout/home_empty_page.xml
@@ -6,21 +6,29 @@
               android:id="@+id/home_empty_view"
               android:layout_width="fill_parent"
               android:layout_height="fill_parent"
               android:orientation="vertical"
               android:gravity="center"
               android:paddingLeft="50dp"
               android:paddingRight="50dp">
 
+    <!-- Empty spacer view -->
+    <View android:layout_width="fill_parent"
+          android:layout_height="0dip"
+          android:layout_weight="1"/>
+
     <ImageView android:id="@+id/home_empty_image"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
-               android:paddingBottom="15dp"/>
+               android:gravity="top|center"
+               android:scaleType="center"
+               android:paddingBottom="10dp"/>
 
     <TextView android:id="@+id/home_empty_text"
               android:layout_width="fill_parent"
-              android:layout_height="wrap_content"
-              android:gravity="center"
-              android:textAppearance="@style/TextAppearance.EmptyMessage"/>
+              android:layout_height="0dip"
+              android:gravity="top|center"
+              android:textAppearance="@style/TextAppearance.EmptyMessage"
+              android:layout_weight="3"/>
 
 </LinearLayout>
 
--- a/netwerk/base/public/nsIBrowserSearchService.idl
+++ b/netwerk/base/public/nsIBrowserSearchService.idl
@@ -2,32 +2,26 @@
  * 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/. */
 
 #include "nsISupports.idl"
 
 interface nsIURI;
 interface nsIInputStream;
 
-[scriptable, uuid(82ec6ee8-68b5-49ef-87b7-0d5240f8a183)]
+[scriptable, uuid(5799251f-5b55-4df7-a9e7-0c27812c469a)]
 interface nsISearchSubmission : nsISupports
 {
   /**
    * The POST data associated with a search submission, wrapped in a MIME
    * input stream. May be null.
    */
   readonly attribute nsIInputStream postData;
 
   /**
-   * The POST data associated with a search submission as an
-   * application/x-www-form-urlencoded string. May be null.
-   */
-  readonly attribute AString postDataString;
-
-  /**
    * The URI to submit a search to.
    */
   readonly attribute nsIURI uri;
 };
 
 [scriptable, uuid(ccf6aa20-10a9-4a0c-a81d-31b10ea846de)]
 interface nsISearchEngine : nsISupports
 {
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -926,38 +926,37 @@ EngineURL.prototype = {
         continue;
 
       var value = ParamSubstitution(param.value, aSearchTerms, aEngine);
 
       dataString += (i > 0 ? "&" : "") + param.name + "=" + value;
     }
 
     var postData = null;
-    let postDataString = null;
     if (this.method == "GET") {
       // GET method requests have no post data, and append the encoded
       // query string to the url...
       if (url.indexOf("?") == -1 && dataString)
         url += "?";
       url += dataString;
     } else if (this.method == "POST") {
-      // For POST requests, specify the data as a MIME stream as well as a string.
-      postDataString = dataString;
+      // POST method requests must wrap the encoded text in a MIME
+      // stream and supply that as POSTDATA.
       var stringStream = Cc["@mozilla.org/io/string-input-stream;1"].
                          createInstance(Ci.nsIStringInputStream);
       stringStream.data = dataString;
 
       postData = Cc["@mozilla.org/network/mime-input-stream;1"].
                  createInstance(Ci.nsIMIMEInputStream);
       postData.addHeader("Content-Type", "application/x-www-form-urlencoded");
       postData.addContentLength = true;
       postData.setData(stringStream);
     }
 
-    return new Submission(makeURI(url), postData, postDataString);
+    return new Submission(makeURI(url), postData);
   },
 
   _hasRelation: function SRC_EURL__hasRelation(aRel)
     this.rels.some(function(e) e == aRel.toLowerCase()),
 
   _initWithJSON: function SRC_EURL__initWithJSON(aJson, aEngine) {
     if (!aJson.params)
       return;
@@ -2539,17 +2538,17 @@ Engine.prototype = {
 
     var url = this._getURLOfType(aResponseType);
 
     if (!url)
       return null;
 
     if (!aData) {
       // Return a dummy submission object with our searchForm attribute
-      return new Submission(makeURI(this.searchForm));
+      return new Submission(makeURI(this.searchForm), null);
     }
 
     LOG("getSubmission: In data: \"" + aData + "\"; Purpose: \"" + aPurpose + "\"");
     var textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"].
                        getService(Ci.nsITextToSubURI);
     var data = "";
     try {
       data = textToSubURI.ConvertAndEscape(this.queryCharset, aData);
@@ -2576,31 +2575,27 @@ Engine.prototype = {
 
   get wrappedJSObject() {
     return this;
   }
 
 };
 
 // nsISearchSubmission
-function Submission(aURI, aPostData = null, aPostDataString = null) {
+function Submission(aURI, aPostData = null) {
   this._uri = aURI;
   this._postData = aPostData;
-  this._postDataString = aPostDataString;
 }
 Submission.prototype = {
   get uri() {
     return this._uri;
   },
   get postData() {
     return this._postData;
   },
-  get postDataString() {
-    return this._postDataString;
-  },
   QueryInterface: function SRCH_SUBM_QI(aIID) {
     if (aIID.equals(Ci.nsISearchSubmission) ||
         aIID.equals(Ci.nsISupports))
       return this;
     throw Cr.NS_ERROR_NO_INTERFACE;
   }
 }
 
--- a/toolkit/components/social/SocialService.jsm
+++ b/toolkit/components/social/SocialService.jsm
@@ -345,16 +345,26 @@ function initService() {
 }
 
 function schedule(callback) {
   Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
 }
 
 // Public API
 this.SocialService = {
+  get hasEnabledProviders() {
+    // used as an optimization during startup, can be used to check if further
+    // initialization should be done (e.g. creating the instances of
+    // SocialProvider and turning on UI). ActiveProviders may have changed and
+    // not yet flushed so we check the active providers array
+    for (let p in ActiveProviders._providers) {
+      return true;
+    };
+    return false;
+  },
   get enabled() {
     return SocialServiceInternal.enabled;
   },
   set enabled(val) {
     let enable = !!val;
 
     // Allow setting to the same value when in safe mode so the
     // feature can be force enabled.
--- a/toolkit/mozapps/update/test/unit/head_update.js.in
+++ b/toolkit/mozapps/update/test/unit/head_update.js.in
@@ -313,16 +313,17 @@ if (APP_BIN_NAME == "xulrunner") {
     setUpdateChannel("test_channel");
   }
 }
 
 /**
  * Nulls out the most commonly used global vars used by tests as appropriate.
  */
 function cleanUp() {
+  logTestInfo("start - general test cleanup");
   removeUpdateDirsAndFiles();
 
   // Force the update manager to reload the update data to prevent it from
   // writing the old data to the files that have just been removed.
   reloadUpdateManagerData();
 
   if (gChannel) {
     gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer);
@@ -343,16 +344,17 @@ function cleanUp() {
     gXHR.onerror     = null;
     gXHR.onload      = null;
     gXHR.onprogress  = null;
 
     gXHR             = null;
   }
 
   gTestserver = null;
+  logTestInfo("finish - general test cleanup");
 }
 
 /**
  * Sets the most commonly used preferences used by tests
  */
 function setDefaultPrefs() {
   Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true);
   Services.prefs.setBoolPref(PREF_APP_UPDATE_METRO_ENABLED, true);
@@ -1557,24 +1559,51 @@ function removeCallbackCopy() {
   let appBinCopy = getAppDir();
   appBinCopy.append(TEST_ID + FILE_WIN_TEST_EXE);
   if (appBinCopy.exists()) {
     try {
       logTestInfo("attempting removal of file: " + appBinCopy.path);
       appBinCopy.remove(false);
     }
     catch (e) {
-      logTestInfo("non-fatal error removing file during cleanup (will try " +
-                  "again). File: " + appBinCopy.path + " Exception: " + e);
+      logTestInfo("non-fatal error removing file after test finished (will " +
+                  "try again). File: " + appBinCopy.path + " Exception: " + e);
       do_timeout(TEST_HELPER_TIMEOUT, removeCallbackCopy);
       return;
     }
   }
-  // Use a timeout to give any files that were in use additional 
-  // time to close.  Same as updater.exe without service tests.
+  logTestInfo("attempting removal of the updater binary");
+  removeUpdater();
+}
+
+
+/**
+ * Helper function for updater tests that removes the updater binary before
+ * ending the test so the updater binary isn't in use during test cleanup.
+ */
+function removeUpdater() {
+  if (IS_WIN) {
+    // Remove the copy of the application executable used for the test on
+    // Windows if it exists.
+    let updater = getUpdatesDir();
+    updater.append("0");
+    updater.append(UPDATER_BIN_FILE);
+    if (updater.exists()) {
+      try {
+        updater.remove(false);
+      }
+      catch (e) {
+        logTestInfo("non-fatal error removing file after test finished (will " +
+                    "try again). File: " + updater.path + " Exception: " + e);
+        do_timeout(TEST_HELPER_TIMEOUT, removeUpdater);
+        return;
+      }
+    }
+  }
+  logTestInfo("calling do_test_finished");
   do_test_finished();
 }
 
 // Waits until files that are in use that break tests are no longer in use and
 // then calls removeCallbackCopy.
 function waitForFilesInUse() {
   let maintSvcInstaller = getAppDir();
   maintSvcInstaller.append("MAINTENANCE_SERVICE_INSTALLER_BIN_FILE");
@@ -2108,18 +2137,20 @@ function adjustPathsOnWindows() {
           iid.equals(AUS_Ci.nsISupports))
         return this;
       throw AUS_Cr.NS_ERROR_NO_INTERFACE;
     }
   };
   let ds = Services.dirsvc.QueryInterface(AUS_Ci.nsIDirectoryService);
   ds.QueryInterface(AUS_Ci.nsIProperties).undefine(NS_GRE_DIR);
   ds.registerProvider(dirProvider);
-  do_register_cleanup(function() {
+  do_register_cleanup(function APOW_cleanup() {
+    logTestInfo("start - unregistering directory provider");
     ds.unregisterProvider(dirProvider);
+    logTestInfo("finish - unregistering directory provider");
   });
   logTestInfo("finish - setup new process directory");
 }
 
 let gWindowsBinDir = null;
 
 /**
  * This function makes XREExeF and UpdRootD point to unique locations so
--- a/toolkit/mozapps/update/test/unit/test_0202_app_launch_apply_update_dirlocked.js
+++ b/toolkit/mozapps/update/test/unit/test_0202_app_launch_apply_update_dirlocked.js
@@ -78,21 +78,23 @@ function symlinkUpdateFilesIntoBundleDir
   if (source2.exists()) {
     source2.remove(true);
   }
   ret = symlink(dest2.path, source2.path);
   do_check_eq(ret, 0);
   do_check_true(source2.exists());
 
   // Cleanup the symlinks when the test is finished.
-  do_register_cleanup(function() {
+  do_register_cleanup(function AUFIBD_cleanup() {
+    logTestInfo("start - unlinking symlinks");
     let ret = unlink(source.path);
     do_check_false(source.exists());
     let ret = unlink(source2.path);
     do_check_false(source2.exists());
+    logTestInfo("finish - unlinking symlinks");
   });
 
   // Now, make sure that getUpdatesRootDir returns the application bundle
   // directory, to make the various stuff in the test framework to work
   // correctly.
   getUpdatesRootDir = getAppDir;
 }
 
@@ -193,16 +195,17 @@ function run_test() {
     createInstance(AUS_Ci.nsIUpdateProcessor).
     processUpdate(gActiveUpdate);
 
   logTestInfo("processUpdate completed - calling checkUpdateApplied");
   checkUpdateApplied();
 }
 
 function end_test() {
+  logTestInfo("start - test cleanup");
   // Remove the files added by the update.
   let updateTestDir = getUpdateTestDir();
   try {
     logTestInfo("removing update test directory " + updateTestDir.path);
     removeDirRecursive(updateTestDir);
   }
   catch (e) {
     logTestInfo("unable to remove directory - path: " + updateTestDir.path +
@@ -225,16 +228,17 @@ function end_test() {
   }
 
   if (IS_UNIX) {
     // This will delete the launch script if it exists.
     getLaunchScript();
   }
 
   cleanUp();
+  logTestInfo("finish - test cleanup");
 }
 
 function shouldAdjustPathsOnMac() {
   // When running xpcshell tests locally, xpcshell and firefox-bin do not live
   // in the same directory.
   let dir = getCurrentProcessDir();
   return (IS_MACOSX && dir.leafName != "MacOS");
 }