diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 144cde7319f2..a10863ad9842 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -182,6 +182,9 @@ pref("app.update.metro.enabled", true); // If set to true, the Update Service will present no UI for any event. pref("app.update.silent", false); +// If set to true, the hamburger button will show badges for update events. +pref("app.update.badge", false); + // If set to true, the Update Service will apply updates in the background // when it finishes downloading them. pref("app.update.staging.enabled", true); diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 18328742bf36..172b9f9aaa83 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -1324,6 +1324,8 @@ var gBrowserInit = { // Add Devtools menuitems and listeners gDevToolsBrowser.registerBrowserWindow(window); + gMenuButtonUpdateBadge.init(); + window.addEventListener("mousemove", MousePosTracker, false); window.addEventListener("dragover", MousePosTracker, false); @@ -1470,6 +1472,8 @@ var gBrowserInit = { DevEdition.uninit(); + gMenuButtonUpdateBadge.uninit(); + var enumerator = Services.wm.getEnumerator(null); enumerator.getNext(); if (!enumerator.hasMoreElements()) { @@ -2439,6 +2443,118 @@ function PageProxyClickHandler(aEvent) middleMousePaste(aEvent); } +// Setup the hamburger button badges for updates, if enabled. +let gMenuButtonUpdateBadge = { + enabled: false, + + init: function () { + try { + this.enabled = Services.prefs.getBoolPref("app.update.badge"); + } catch (e) {} + if (this.enabled) { + PanelUI.menuButton.classList.add("badged-button"); + Services.obs.addObserver(this, "update-staged", false); + } + }, + + uninit: function () { + if (this.enabled) { + Services.obs.removeObserver(this, "update-staged"); + PanelUI.panel.removeEventListener("popupshowing", this, true); + this.enabled = false; + } + }, + + onMenuPanelCommand: function(event) { + if (event.originalTarget.getAttribute("update-status") === "succeeded") { + // restart the app + let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"] + .createInstance(Ci.nsISupportsPRBool); + Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart"); + + if (!cancelQuit.data) { + Services.startup.quit(Services.startup.eAttemptQuit | Services.startup.eRestart); + } + } else { + // open the page for manual update + let url = Services.urlFormatter.formatURLPref("app.update.url.manual"); + openUILinkIn(url, "tab"); + } + }, + + observe: function (subject, topic, status) { + const STATE_DOWNLOADING = "downloading"; + const STATE_PENDING = "pending"; + const STATE_PENDING_SVC = "pending-service"; + const STATE_APPLIED = "applied"; + const STATE_APPLIED_SVC = "applied-service"; + const STATE_FAILED = "failed"; + + let updateButton = document.getElementById("PanelUI-update-status"); + + let updateButtonText; + let stringId; + + // Update the UI when the background updater is finished. + switch (status) { + case STATE_APPLIED: + case STATE_APPLIED_SVC: + case STATE_PENDING: + case STATE_PENDING_SVC: + // If the update is successfully applied, or if the updater has fallen back + // to non-staged updates, add a badge to the hamburger menu to indicate an + // update will be applied once the browser restarts. + let badge = document.getAnonymousElementByAttribute(PanelUI.menuButton, + "class", + "toolbarbutton-badge"); + badge.style.backgroundColor = 'green'; + PanelUI.menuButton.setAttribute("badge", "\u2605"); + + let brandBundle = document.getElementById("bundle_brand"); + let brandShortName = brandBundle.getString("brandShortName"); + stringId = "appmenu.restartNeeded.description"; + updateButtonText = gNavigatorBundle.getFormattedString(stringId, + [brandShortName]); + + updateButton.label = updateButtonText; + updateButton.hidden = false; + updateButton.setAttribute("update-status", "succeeded"); + + PanelUI.panel.addEventListener("popupshowing", this, true); + + break; + case STATE_FAILED: + // Background update has failed, let's show the UI responsible for + // prompting the user to update manually. + PanelUI.menuButton.setAttribute("badge", "!"); + + stringId = "appmenu.updateFailed.description"; + updateButtonText = gNavigatorBundle.getString(stringId); + + updateButton.label = updateButtonText; + updateButton.hidden = false; + updateButton.setAttribute("update-status", "failed"); + + PanelUI.panel.addEventListener("popupshowing", this, true); + + break; + case STATE_DOWNLOADING: + // We've fallen back to downloading the full update because the partial + // update failed to get staged in the background. Therefore we need to keep + // our observer. + return; + } + this.uninit(); + }, + + handleEvent: function(e) { + if (e.type === "popupshowing") { + PanelUI.menuButton.removeAttribute("badge"); + PanelUI.panel.removeEventListener("popupshowing", this, true); + } + } +}; + /** * Handle command events bubbling up from error page content * or from about:newtab or from remote error pages that invoke diff --git a/browser/components/customizableui/content/panelUI.inc.xul b/browser/components/customizableui/content/panelUI.inc.xul index 9b2546838693..4c7fb50738ad 100644 --- a/browser/components/customizableui/content/panelUI.inc.xul +++ b/browser/components/customizableui/content/panelUI.inc.xul @@ -16,6 +16,10 @@