зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1359733 - (pt. 2) Refactor gMenuButtonUpdateBadge r=rstrong
Since we now have a store of notifications that is global across all windows, it no longer makes sense to consume the API from within browser.js. This patch moves the browser.js logic out into a jsm file that is wired up through nsBrowserGlue, such that it will be lazily instantiated on the first update event it would receive[1]. We decided to move this into toolkit, as this piece of the system is fairly generic and shouldn't differ between applications. [1]: There is a change to nsBrowserGlue to use "global[module]" instead of this[module]. This mirrors the code for all the other types of notifications, and I suspect it was just a latent bug, since the original diff that includes this line makes no use of it. MozReview-Commit-ID: 8EQdM9BOpgl --HG-- rename : browser/base/content/test/appUpdate/.eslintrc.js => toolkit/mozapps/update/tests/browser/.eslintrc.js rename : browser/base/content/test/appUpdate/browser.ini => toolkit/mozapps/update/tests/browser/browser.ini rename : browser/base/content/test/appUpdate/browser_updatesBackgroundWindow.js => toolkit/mozapps/update/tests/browser/browser_updatesBackgroundWindow.js rename : browser/base/content/test/appUpdate/browser_updatesBackgroundWindowFailures.js => toolkit/mozapps/update/tests/browser/browser_updatesBackgroundWindowFailures.js rename : browser/base/content/test/appUpdate/browser_updatesBasicPrompt.js => toolkit/mozapps/update/tests/browser/browser_updatesBasicPrompt.js rename : browser/base/content/test/appUpdate/browser_updatesBasicPromptNoStaging.js => toolkit/mozapps/update/tests/browser/browser_updatesBasicPromptNoStaging.js rename : browser/base/content/test/appUpdate/browser_updatesCantApply.js => toolkit/mozapps/update/tests/browser/browser_updatesCantApply.js rename : browser/base/content/test/appUpdate/browser_updatesCompleteAndPartialPatchesWithBadCompleteSize.js => toolkit/mozapps/update/tests/browser/browser_updatesCompleteAndPartialPatchesWithBadCompleteSize.js rename : browser/base/content/test/appUpdate/browser_updatesCompleteAndPartialPatchesWithBadPartialSize.js => toolkit/mozapps/update/tests/browser/browser_updatesCompleteAndPartialPatchesWithBadPartialSize.js rename : browser/base/content/test/appUpdate/browser_updatesCompleteAndPartialPatchesWithBadSizes.js => toolkit/mozapps/update/tests/browser/browser_updatesCompleteAndPartialPatchesWithBadSizes.js rename : browser/base/content/test/appUpdate/browser_updatesCompletePatchApplyFailure.js => toolkit/mozapps/update/tests/browser/browser_updatesCompletePatchApplyFailure.js rename : browser/base/content/test/appUpdate/browser_updatesCompletePatchWithBadCompleteSize.js => toolkit/mozapps/update/tests/browser/browser_updatesCompletePatchWithBadCompleteSize.js rename : browser/base/content/test/appUpdate/browser_updatesDownloadFailures.js => toolkit/mozapps/update/tests/browser/browser_updatesDownloadFailures.js rename : browser/base/content/test/appUpdate/browser_updatesMalformedXml.js => toolkit/mozapps/update/tests/browser/browser_updatesMalformedXml.js rename : browser/base/content/test/appUpdate/browser_updatesPartialPatchApplyFailure.js => toolkit/mozapps/update/tests/browser/browser_updatesPartialPatchApplyFailure.js rename : browser/base/content/test/appUpdate/browser_updatesPartialPatchApplyFailureWithCompleteAvailable.js => toolkit/mozapps/update/tests/browser/browser_updatesPartialPatchApplyFailureWithCompleteAvailable.js rename : browser/base/content/test/appUpdate/browser_updatesPartialPatchApplyFailureWithCompleteValidationFailure.js => toolkit/mozapps/update/tests/browser/browser_updatesPartialPatchApplyFailureWithCompleteValidationFailure.js rename : browser/base/content/test/appUpdate/browser_updatesPartialPatchWithBadPartialSize.js => toolkit/mozapps/update/tests/browser/browser_updatesPartialPatchWithBadPartialSize.js extra : rebase_source : 24048650b23eff0a1da9679d1e9b5e1db1900287
This commit is contained in:
Родитель
646edb5fab
Коммит
82301632cc
|
@ -138,6 +138,10 @@ pref("app.update.enabled", true);
|
|||
// Whether or not to use the doorhanger application update UI.
|
||||
pref("app.update.doorhanger", true);
|
||||
|
||||
// Ids of the links to the "What's new" update documentation
|
||||
pref("app.update.link.updateAvailableWhatsNew", "update-available-whats-new");
|
||||
pref("app.update.link.updateManualWhatsNew", "update-manual-whats-new");
|
||||
|
||||
// How many times we should let downloads fail before prompting the user to
|
||||
// download a fresh installer.
|
||||
pref("app.update.download.promptMaxAttempts", 2);
|
||||
|
|
|
@ -1637,8 +1637,6 @@ var gBrowserInit = {
|
|||
|
||||
gBrowserThumbnails.init();
|
||||
|
||||
gMenuButtonUpdateBadge.init();
|
||||
|
||||
gExtensionsNotifications.init();
|
||||
|
||||
let wasMinimized = window.windowState == window.STATE_MINIMIZED;
|
||||
|
@ -1800,8 +1798,6 @@ var gBrowserInit = {
|
|||
|
||||
CaptivePortalWatcher.uninit();
|
||||
|
||||
gMenuButtonUpdateBadge.uninit();
|
||||
|
||||
SidebarUI.uninit();
|
||||
|
||||
// Now either cancel delayedStartup, or clean up the services initialized from
|
||||
|
@ -2857,224 +2853,6 @@ function PageProxyClickHandler(aEvent) {
|
|||
middleMousePaste(aEvent);
|
||||
}
|
||||
|
||||
// Setup the hamburger button badges for updates, if enabled.
|
||||
var gMenuButtonUpdateBadge = {
|
||||
kTopics: [
|
||||
"update-staged",
|
||||
"update-downloaded",
|
||||
"update-available",
|
||||
"update-error",
|
||||
],
|
||||
|
||||
timeouts: [],
|
||||
|
||||
get enabled() {
|
||||
return Services.prefs.getBoolPref("app.update.doorhanger", false);
|
||||
},
|
||||
|
||||
get badgeWaitTime() {
|
||||
return Services.prefs.getIntPref("app.update.badgeWaitTime", 4 * 24 * 3600); // 4 days
|
||||
},
|
||||
|
||||
init() {
|
||||
if (this.enabled) {
|
||||
this.kTopics.forEach(t => {
|
||||
Services.obs.addObserver(this, t);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
uninit() {
|
||||
if (this.enabled) {
|
||||
this.kTopics.forEach(t => {
|
||||
Services.obs.removeObserver(this, t);
|
||||
});
|
||||
}
|
||||
|
||||
this.reset();
|
||||
},
|
||||
|
||||
reset() {
|
||||
PanelUI.removeNotification(/^update-/);
|
||||
this.clearCallbacks();
|
||||
},
|
||||
|
||||
clearCallbacks() {
|
||||
this.timeouts.forEach(t => clearTimeout(t));
|
||||
this.timeouts = [];
|
||||
},
|
||||
|
||||
addTimeout(time, callback) {
|
||||
this.timeouts.push(setTimeout(() => {
|
||||
this.clearCallbacks();
|
||||
callback();
|
||||
}, time));
|
||||
},
|
||||
|
||||
replaceReleaseNotes(update, whatsNewId) {
|
||||
let whatsNewLink = document.getElementById(whatsNewId);
|
||||
if (update && update.detailsURL) {
|
||||
whatsNewLink.href = update.detailsURL;
|
||||
} else {
|
||||
whatsNewLink.href = Services.urlFormatter.formatURLPref("app.update.url.details");
|
||||
}
|
||||
},
|
||||
|
||||
requestRestart() {
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
openManualUpdateUrl() {
|
||||
let manualUpdateUrl = Services.urlFormatter.formatURLPref("app.update.url.manual");
|
||||
openUILinkIn(manualUpdateUrl, "tab");
|
||||
},
|
||||
|
||||
showUpdateNotification(type, dismissed, mainAction) {
|
||||
let action = {
|
||||
callback(fromDoorhanger) {
|
||||
if (fromDoorhanger) {
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_MAIN_ACTION_DOORHANGER").add(type);
|
||||
} else {
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_MAIN_ACTION_MENU").add(type);
|
||||
}
|
||||
mainAction();
|
||||
}
|
||||
};
|
||||
|
||||
let secondaryAction = {
|
||||
callback() {
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_DISMISSED").add(type);
|
||||
},
|
||||
dismiss: true
|
||||
};
|
||||
|
||||
PanelUI.showNotification("update-" + type, action, [secondaryAction], { dismissed });
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_SHOWN").add(type);
|
||||
},
|
||||
|
||||
showRestartNotification(dismissed) {
|
||||
this.showUpdateNotification("restart", dismissed, () => gMenuButtonUpdateBadge.requestRestart());
|
||||
},
|
||||
|
||||
showUpdateAvailableNotification(update, dismissed) {
|
||||
this.replaceReleaseNotes(update, "update-available-whats-new");
|
||||
this.showUpdateNotification("available", dismissed, () => {
|
||||
let updateService = Cc["@mozilla.org/updates/update-service;1"]
|
||||
.getService(Ci.nsIApplicationUpdateService);
|
||||
updateService.downloadUpdate(update, true);
|
||||
});
|
||||
},
|
||||
|
||||
showManualUpdateNotification(update, dismissed) {
|
||||
this.replaceReleaseNotes(update, "update-manual-whats-new");
|
||||
|
||||
this.showUpdateNotification("manual", dismissed, () => gMenuButtonUpdateBadge.openManualUpdateUrl());
|
||||
},
|
||||
|
||||
handleUpdateError(update, status) {
|
||||
switch (status) {
|
||||
case "download-attempt-failed":
|
||||
this.clearCallbacks();
|
||||
this.showUpdateAvailableNotification(update, false);
|
||||
break;
|
||||
case "download-attempts-exceeded":
|
||||
this.clearCallbacks();
|
||||
this.showManualUpdateNotification(update, false);
|
||||
break;
|
||||
case "elevation-attempt-failed":
|
||||
this.clearCallbacks();
|
||||
this.showRestartNotification(update, false);
|
||||
break;
|
||||
case "elevation-attempts-exceeded":
|
||||
this.clearCallbacks();
|
||||
this.showManualUpdateNotification(update, false);
|
||||
break;
|
||||
case "check-attempts-exceeded":
|
||||
case "unknown":
|
||||
// Background update has failed, let's show the UI responsible for
|
||||
// prompting the user to update manually.
|
||||
this.clearCallbacks();
|
||||
this.showManualUpdateNotification(update, false);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleUpdateStagedOrDownloaded(update, status) {
|
||||
switch (status) {
|
||||
case "applied":
|
||||
case "pending":
|
||||
case "applied-service":
|
||||
case "pending-service":
|
||||
case "success":
|
||||
this.clearCallbacks();
|
||||
|
||||
let badgeWaitTimeMs = this.badgeWaitTime * 1000;
|
||||
let doorhangerWaitTimeMs = update.promptWaitTime * 1000;
|
||||
|
||||
if (badgeWaitTimeMs < doorhangerWaitTimeMs) {
|
||||
this.addTimeout(badgeWaitTimeMs, () => {
|
||||
this.showRestartNotification(true);
|
||||
|
||||
// doorhangerWaitTimeMs is relative to when we initially received
|
||||
// the event. Since we've already waited badgeWaitTimeMs, subtract
|
||||
// that from doorhangerWaitTimeMs.
|
||||
let remainingTime = doorhangerWaitTimeMs - badgeWaitTimeMs;
|
||||
this.addTimeout(remainingTime, () => {
|
||||
this.showRestartNotification(false);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.addTimeout(doorhangerWaitTimeMs, () => {
|
||||
this.showRestartNotification(false);
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleUpdateAvailable(update, status) {
|
||||
switch (status) {
|
||||
case "show-prompt":
|
||||
// If an update is available and had the showPrompt flag set, then
|
||||
// show an update available doorhanger.
|
||||
this.clearCallbacks();
|
||||
this.showUpdateAvailableNotification(update, false);
|
||||
break;
|
||||
case "cant-apply":
|
||||
this.clearCallbacks();
|
||||
this.showManualUpdateNotification(update, false);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
observe(subject, topic, status) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let update = subject && subject.QueryInterface(Ci.nsIUpdate);
|
||||
|
||||
switch (topic) {
|
||||
case "update-available":
|
||||
this.handleUpdateAvailable(update, status);
|
||||
break;
|
||||
case "update-staged":
|
||||
case "update-downloaded":
|
||||
this.handleUpdateStagedOrDownloaded(update, status);
|
||||
break;
|
||||
case "update-error":
|
||||
this.handleUpdateError(update, status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json
|
||||
const TLS_ERROR_REPORT_TELEMETRY_AUTO_CHECKED = 2;
|
||||
const TLS_ERROR_REPORT_TELEMETRY_AUTO_UNCHECKED = 3;
|
||||
|
|
|
@ -28,9 +28,6 @@ with Files("pageinfo/**"):
|
|||
with Files("test/alerts/**"):
|
||||
BUG_COMPONENT = ("Toolkit", "Notifications and Alerts")
|
||||
|
||||
with Files("test/appUpdate/**"):
|
||||
BUG_COMPONENT = ("Toolkit", "Application Update")
|
||||
|
||||
with Files("test/captivePortal/**"):
|
||||
BUG_COMPONENT = ("Firefox", "General")
|
||||
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
Cu.import("resource://gre/modules/FileUtils.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AppMenuNotifications",
|
||||
"resource://gre/modules/AppMenuNotifications.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UpdateListener",
|
||||
"resource://gre/modules/UpdateListener.jsm");
|
||||
|
||||
const IS_MACOSX = ("nsILocalFileMac" in Ci);
|
||||
const IS_WIN = ("@mozilla.org/windows-registry-key;1" in Cc);
|
||||
|
||||
|
@ -13,16 +18,18 @@ const PREF_APP_UPDATE_LASTUPDATETIME = "app.update.lastUpdateTime.background-upd
|
|||
|
||||
let gRembemberedPrefs = [];
|
||||
|
||||
const DATA_URI_SPEC = "chrome://mochitests/content/browser/browser/base/content/test/appUpdate/";
|
||||
const DATA_URI_SPEC = "chrome://mochitests/content/browser/toolkit/mozapps/update/tests/browser/";
|
||||
|
||||
var DEBUG_AUS_TEST = true;
|
||||
var gUseTestUpdater = false;
|
||||
|
||||
const LOG_FUNCTION = info;
|
||||
|
||||
const MAX_UPDATE_COPY_ATTEMPTS = 10;
|
||||
|
||||
/* import-globals-from testConstants.js */
|
||||
Services.scriptloader.loadSubScript(DATA_URI_SPEC + "testConstants.js", this);
|
||||
/* import-globals-from ../../../../../toolkit/mozapps/update/tests/data/shared.js */
|
||||
/* import-globals-from ../data/shared.js */
|
||||
Services.scriptloader.loadSubScript(DATA_URI_SPEC + "shared.js", this);
|
||||
|
||||
var gURLData = URL_HOST + "/" + REL_PATH_DATA;
|
||||
|
@ -104,8 +111,7 @@ function runUpdateTest(updateParams, checkAttempts, steps) {
|
|||
return (async function() {
|
||||
registerCleanupFunction(() => {
|
||||
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
|
||||
gMenuButtonUpdateBadge.uninit();
|
||||
gMenuButtonUpdateBadge.init();
|
||||
UpdateListener.reset();
|
||||
cleanUpUpdates();
|
||||
});
|
||||
|
||||
|
@ -161,7 +167,7 @@ function runUpdateProcessingTest(updates, steps) {
|
|||
return (async function() {
|
||||
registerCleanupFunction(() => {
|
||||
gEnv.set("MOZ_TEST_SKIP_UPDATE_STAGE", "");
|
||||
gMenuButtonUpdateBadge.reset();
|
||||
UpdateListener.reset();
|
||||
cleanUpUpdates();
|
||||
});
|
||||
|
||||
|
@ -203,7 +209,7 @@ function processStep(step) {
|
|||
return (async function() {
|
||||
|
||||
await BrowserTestUtils.waitForEvent(PanelUI.notificationPanel, "popupshown");
|
||||
const shownNotification = PanelUI.activeNotification.id;
|
||||
const shownNotification = AppMenuNotifications.activeNotification.id;
|
||||
|
||||
is(shownNotification, notificationId, "The right notification showed up.");
|
||||
if (shownNotification != notificationId) {
|
||||
|
@ -335,7 +341,7 @@ function moveRealUpdater() {
|
|||
* since Windows debug builds at times leave the file in use. After success it
|
||||
* will call runTest to continue the test.
|
||||
*/
|
||||
function copyTestUpdater() {
|
||||
function copyTestUpdater(attempt = 0) {
|
||||
return (async function() {
|
||||
try {
|
||||
// Copy the test updater
|
||||
|
@ -349,12 +355,15 @@ function copyTestUpdater() {
|
|||
|
||||
let testUpdater = testUpdaterDir.clone();
|
||||
testUpdater.append(FILE_UPDATER_BIN);
|
||||
|
||||
testUpdater.copyToFollowingLinks(baseAppDir, FILE_UPDATER_BIN);
|
||||
} catch (e) {
|
||||
logTestInfo("Attempt to copy the test updater failed... " +
|
||||
"will try again, Exception: " + e);
|
||||
await delay();
|
||||
await copyTestUpdater();
|
||||
if (attempt < MAX_UPDATE_COPY_ATTEMPTS) {
|
||||
logTestInfo("Attempt to copy the test updater failed... " +
|
||||
"will try again, Exception: " + e);
|
||||
await delay();
|
||||
await copyTestUpdater(attempt + 1);
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const REL_PATH_DATA = "browser/browser/base/content/test/appUpdate/";
|
||||
const REL_PATH_DATA = "browser/toolkit/mozapps/update/tests/browser/";
|
||||
const URL_HOST = "http://example.com";
|
||||
const URL_PATH_UPDATE_XML = "/" + REL_PATH_DATA + "update.sjs";
|
||||
const URL_HTTP_UPDATE_SJS = URL_HOST + URL_PATH_UPDATE_XML;
|
||||
|
|
|
@ -41,9 +41,6 @@ BROWSER_CHROME_MANIFESTS += [
|
|||
'content/test/webrtc/browser.ini',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_UPDATER']:
|
||||
BROWSER_CHROME_MANIFESTS += ['content/test/appUpdate/browser.ini']
|
||||
|
||||
DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
|
||||
DEFINES['MOZ_APP_VERSION_DISPLAY'] = CONFIG['MOZ_APP_VERSION_DISPLAY']
|
||||
|
||||
|
@ -58,11 +55,4 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'cocoa'):
|
|||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('windows', 'gtk2', 'gtk3'):
|
||||
DEFINES['MENUBAR_CAN_AUTOHIDE'] = 1
|
||||
|
||||
TEST_HARNESS_FILES.testing.mochitest.browser.browser.base.content.test.appUpdate += [
|
||||
'/toolkit/mozapps/update/tests/chrome/update.sjs',
|
||||
'/toolkit/mozapps/update/tests/data/shared.js',
|
||||
'/toolkit/mozapps/update/tests/data/sharedUpdateXML.js',
|
||||
'/toolkit/mozapps/update/tests/data/simple.mar',
|
||||
]
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
|
|
@ -729,6 +729,10 @@ const PanelUI = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (notification.options.beforeShowDoorhanger) {
|
||||
notification.options.beforeShowDoorhanger(document);
|
||||
}
|
||||
|
||||
let anchor = this._getPanelAnchor(this.menuButton);
|
||||
|
||||
this.notificationPanel.hidden = false;
|
||||
|
|
|
@ -36,7 +36,7 @@ XPCOMUtils.defineLazyGetter(this, "WeaveService", () =>
|
|||
ProcessHangMonitor:false, ReaderParent:false, RecentWindow:false,
|
||||
RemotePrompt:false, SessionStore:false,
|
||||
ShellService:false, SimpleServiceDiscovery:false, TabCrashHandler:false,
|
||||
Task:false, UITour:false, WebChannel:false,
|
||||
Task:false, UITour:false, UpdateListener:false, WebChannel:false,
|
||||
WindowsRegistry:false, webrtcUI:false */
|
||||
|
||||
/**
|
||||
|
@ -89,6 +89,7 @@ let initializedModules = {};
|
|||
["TabCrashHandler", "resource:///modules/ContentCrashHandlers.jsm"],
|
||||
["Task", "resource://gre/modules/Task.jsm"],
|
||||
["UITour", "resource:///modules/UITour.jsm"],
|
||||
["UpdateListener", "resource://gre/modules/UpdateListener.jsm", "init"],
|
||||
["WebChannel", "resource://gre/modules/WebChannel.jsm"],
|
||||
["WindowsRegistry", "resource://gre/modules/WindowsRegistry.jsm"],
|
||||
["webrtcUI", "resource:///modules/webrtcUI.jsm", "init"],
|
||||
|
@ -124,6 +125,13 @@ XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
|
|||
const global = this;
|
||||
|
||||
const listeners = {
|
||||
observers: {
|
||||
"update-staged": ["UpdateListener"],
|
||||
"update-downloaded": ["UpdateListener"],
|
||||
"update-available": ["UpdateListener"],
|
||||
"update-error": ["UpdateListener"],
|
||||
},
|
||||
|
||||
ppmm: {
|
||||
// PLEASE KEEP THIS LIST IN SYNC WITH THE LISTENERS ADDED IN ContentPrefServiceParent.init
|
||||
"ContentPrefs:FunctionCall": ["ContentPrefServiceParent"],
|
||||
|
@ -165,6 +173,16 @@ const listeners = {
|
|||
"webrtc:UpdateBrowserIndicators": ["webrtcUI"],
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
for (let module of this.observers[topic]) {
|
||||
try {
|
||||
global[module].observe(subject, topic, data);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage(modules, data) {
|
||||
let val;
|
||||
for (let module of modules[data.name]) {
|
||||
|
@ -178,6 +196,10 @@ const listeners = {
|
|||
},
|
||||
|
||||
init() {
|
||||
for (let observer of Object.keys(this.observers)) {
|
||||
Services.obs.addObserver(this, observer);
|
||||
}
|
||||
|
||||
let receiveMessageMM = this.receiveMessage.bind(this, this.mm);
|
||||
for (let message of Object.keys(this.mm)) {
|
||||
Services.mm.addMessageListener(message, receiveMessageMM);
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
/* 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";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["UpdateListener"];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AppMenuNotifications",
|
||||
"resource://gre/modules/AppMenuNotifications.jsm");
|
||||
|
||||
// Setup the hamburger button badges for updates, if enabled.
|
||||
var UpdateListener = {
|
||||
timeouts: [],
|
||||
|
||||
get enabled() {
|
||||
return Services.prefs.getBoolPref("app.update.doorhanger", false);
|
||||
},
|
||||
|
||||
get badgeWaitTime() {
|
||||
return Services.prefs.getIntPref("app.update.badgeWaitTime", 4 * 24 * 3600); // 4 days
|
||||
},
|
||||
|
||||
init() {
|
||||
},
|
||||
|
||||
uninit() {
|
||||
this.reset();
|
||||
},
|
||||
|
||||
reset() {
|
||||
AppMenuNotifications.removeNotification(/^update-/);
|
||||
this.clearCallbacks();
|
||||
},
|
||||
|
||||
clearCallbacks() {
|
||||
this.timeouts.forEach(t => clearTimeout(t));
|
||||
this.timeouts = [];
|
||||
},
|
||||
|
||||
addTimeout(time, callback) {
|
||||
this.timeouts.push(setTimeout(() => {
|
||||
this.clearCallbacks();
|
||||
callback();
|
||||
}, time));
|
||||
},
|
||||
|
||||
replaceReleaseNotes(doc, update, whatsNewId) {
|
||||
let whatsNewLinkId = Services.prefs.getCharPref(`app.update.link.${whatsNewId}`, "");
|
||||
if (whatsNewLinkId) {
|
||||
let whatsNewLink = doc.getElementById(whatsNewLinkId);
|
||||
if (update && update.detailsURL) {
|
||||
whatsNewLink.href = update.detailsURL;
|
||||
} else {
|
||||
whatsNewLink.href = Services.urlFormatter.formatURLPref("app.update.url.details");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
requestRestart() {
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
openManualUpdateUrl(win) {
|
||||
let manualUpdateUrl = Services.urlFormatter.formatURLPref("app.update.url.manual");
|
||||
win.openURL(manualUpdateUrl);
|
||||
},
|
||||
|
||||
showUpdateNotification(type, dismissed, mainAction, beforeShowDoorhanger) {
|
||||
let action = {
|
||||
callback(win, fromDoorhanger) {
|
||||
if (fromDoorhanger) {
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_MAIN_ACTION_DOORHANGER").add(type);
|
||||
} else {
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_MAIN_ACTION_MENU").add(type);
|
||||
}
|
||||
mainAction(win);
|
||||
}
|
||||
};
|
||||
|
||||
let secondaryAction = {
|
||||
callback() {
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_DISMISSED").add(type);
|
||||
},
|
||||
dismiss: true
|
||||
};
|
||||
|
||||
AppMenuNotifications.showNotification("update-" + type,
|
||||
action,
|
||||
secondaryAction,
|
||||
{ dismissed, beforeShowDoorhanger });
|
||||
Services.telemetry.getHistogramById("UPDATE_NOTIFICATION_SHOWN").add(type);
|
||||
},
|
||||
|
||||
showRestartNotification(dismissed) {
|
||||
this.showUpdateNotification("restart", dismissed, () => this.requestRestart());
|
||||
},
|
||||
|
||||
showUpdateAvailableNotification(update, dismissed) {
|
||||
this.showUpdateNotification("available", dismissed, () => {
|
||||
let updateService = Cc["@mozilla.org/updates/update-service;1"]
|
||||
.getService(Ci.nsIApplicationUpdateService);
|
||||
updateService.downloadUpdate(update, true);
|
||||
}, doc => this.replaceReleaseNotes(doc, update, "updateAvailableWhatsNew"));
|
||||
},
|
||||
|
||||
showManualUpdateNotification(update, dismissed) {
|
||||
this.showUpdateNotification("manual",
|
||||
dismissed,
|
||||
win => this.openManualUpdateUrl(win),
|
||||
doc => this.replaceReleaseNotes(doc, update, "updateManualWhatsNew"));
|
||||
},
|
||||
|
||||
handleUpdateError(update, status) {
|
||||
switch (status) {
|
||||
case "download-attempt-failed":
|
||||
this.clearCallbacks();
|
||||
this.showUpdateAvailableNotification(update, false);
|
||||
break;
|
||||
case "download-attempts-exceeded":
|
||||
this.clearCallbacks();
|
||||
this.showManualUpdateNotification(update, false);
|
||||
break;
|
||||
case "elevation-attempt-failed":
|
||||
this.clearCallbacks();
|
||||
this.showRestartNotification(update, false);
|
||||
break;
|
||||
case "elevation-attempts-exceeded":
|
||||
this.clearCallbacks();
|
||||
this.showManualUpdateNotification(update, false);
|
||||
break;
|
||||
case "check-attempts-exceeded":
|
||||
case "unknown":
|
||||
// Background update has failed, let's show the UI responsible for
|
||||
// prompting the user to update manually.
|
||||
this.clearCallbacks();
|
||||
this.showManualUpdateNotification(update, false);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleUpdateStagedOrDownloaded(update, status) {
|
||||
switch (status) {
|
||||
case "applied":
|
||||
case "pending":
|
||||
case "applied-service":
|
||||
case "pending-service":
|
||||
case "success":
|
||||
this.clearCallbacks();
|
||||
|
||||
let badgeWaitTimeMs = this.badgeWaitTime * 1000;
|
||||
let doorhangerWaitTimeMs = update.promptWaitTime * 1000;
|
||||
|
||||
if (badgeWaitTimeMs < doorhangerWaitTimeMs) {
|
||||
this.addTimeout(badgeWaitTimeMs, () => {
|
||||
this.showRestartNotification(true);
|
||||
|
||||
// doorhangerWaitTimeMs is relative to when we initially received
|
||||
// the event. Since we've already waited badgeWaitTimeMs, subtract
|
||||
// that from doorhangerWaitTimeMs.
|
||||
let remainingTime = doorhangerWaitTimeMs - badgeWaitTimeMs;
|
||||
this.addTimeout(remainingTime, () => {
|
||||
this.showRestartNotification(false);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.addTimeout(doorhangerWaitTimeMs, () => {
|
||||
this.showRestartNotification(false);
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleUpdateAvailable(update, status) {
|
||||
switch (status) {
|
||||
case "show-prompt":
|
||||
// If an update is available and had the showPrompt flag set, then
|
||||
// show an update available doorhanger.
|
||||
this.clearCallbacks();
|
||||
this.showUpdateAvailableNotification(update, false);
|
||||
break;
|
||||
case "cant-apply":
|
||||
this.clearCallbacks();
|
||||
this.showManualUpdateNotification(update, false);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
observe(subject, topic, status) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
let update = subject && subject.QueryInterface(Ci.nsIUpdate);
|
||||
|
||||
switch (topic) {
|
||||
case "update-available":
|
||||
this.handleUpdateAvailable(update, status);
|
||||
break;
|
||||
case "update-staged":
|
||||
case "update-downloaded":
|
||||
this.handleUpdateStagedOrDownloaded(update, status);
|
||||
break;
|
||||
case "update-error":
|
||||
this.handleUpdateError(update, status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -24,6 +24,7 @@ EXTRA_COMPONENTS += [
|
|||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'UpdateListener.jsm',
|
||||
'UpdateTelemetry.jsm',
|
||||
]
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ add_task(async function testUpdatesBackgroundWindow() {
|
|||
notificationId: "update-restart",
|
||||
button: "secondarybutton",
|
||||
cleanup() {
|
||||
PanelUI.removeNotification(/.*/);
|
||||
AppMenuNotifications.removeNotification(/.*/);
|
||||
}
|
||||
},
|
||||
]);
|
|
@ -40,7 +40,6 @@ add_task(async function testBackgroundWindowFailures() {
|
|||
is(gBrowser.selectedBrowser.currentURI.spec,
|
||||
URL_MANUAL_UPDATE, "Landed on manual update page.");
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
gMenuButtonUpdateBadge.reset();
|
||||
}
|
||||
},
|
||||
]);
|
|
@ -15,7 +15,7 @@ add_task(async function testBasicPrompt() {
|
|||
notificationId: "update-restart",
|
||||
button: "secondarybutton",
|
||||
cleanup() {
|
||||
PanelUI.removeNotification(/.*/);
|
||||
AppMenuNotifications.removeNotification(/.*/);
|
||||
}
|
||||
},
|
||||
]);
|
|
@ -15,7 +15,7 @@ add_task(async function testBasicPromptNoStaging() {
|
|||
notificationId: "update-restart",
|
||||
button: "secondarybutton",
|
||||
cleanup() {
|
||||
PanelUI.removeNotification(/.*/);
|
||||
AppMenuNotifications.removeNotification(/.*/);
|
||||
}
|
||||
},
|
||||
]);
|
|
@ -6,7 +6,7 @@ add_task(async function testCompleteAndPartialPatchesWithBadCompleteSize() {
|
|||
notificationId: "update-restart",
|
||||
button: "secondarybutton",
|
||||
cleanup() {
|
||||
PanelUI.removeNotification(/.*/);
|
||||
AppMenuNotifications.removeNotification(/.*/);
|
||||
}
|
||||
},
|
||||
]);
|
|
@ -6,7 +6,7 @@ add_task(async function testCompleteAndPartialPatchesWithBadPartialSize() {
|
|||
notificationId: "update-restart",
|
||||
button: "secondarybutton",
|
||||
cleanup() {
|
||||
PanelUI.removeNotification(/.*/);
|
||||
AppMenuNotifications.removeNotification(/.*/);
|
||||
}
|
||||
},
|
||||
]);
|
|
@ -25,7 +25,6 @@ add_task(async function testDownloadFailures() {
|
|||
is(gBrowser.selectedBrowser.currentURI.spec,
|
||||
URL_MANUAL_UPDATE, "Landed on manual update page.");
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
gMenuButtonUpdateBadge.reset();
|
||||
}
|
||||
},
|
||||
]);
|
|
@ -22,7 +22,6 @@ add_task(async function testMalformedXml() {
|
|||
is(gBrowser.selectedBrowser.currentURI.spec,
|
||||
URL_MANUAL_UPDATE, "Landed on manual update page.")
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
gMenuButtonUpdateBadge.reset();
|
||||
}
|
||||
},
|
||||
]);
|
|
@ -15,7 +15,7 @@ add_task(async function testPartialPatchApplyFailureWithCompleteAvailable() {
|
|||
notificationId: "update-restart",
|
||||
button: "secondarybutton",
|
||||
cleanup() {
|
||||
PanelUI.removeNotification(/.*/);
|
||||
AppMenuNotifications.removeNotification(/.*/);
|
||||
}
|
||||
},
|
||||
]);
|
|
@ -8,6 +8,9 @@ HAS_MISC_RULE = True
|
|||
|
||||
FINAL_TARGET = '_tests/xpcshell/toolkit/mozapps/update/tests/data'
|
||||
|
||||
if not CONFIG['MOZ_SUITE']:
|
||||
BROWSER_CHROME_MANIFESTS += ['browser/browser.ini']
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['chrome/chrome.ini']
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += [
|
||||
|
@ -60,6 +63,13 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||
if CONFIG['GNU_CC']:
|
||||
WIN32_EXE_LDFLAGS += ['-municode']
|
||||
|
||||
TEST_HARNESS_FILES.testing.mochitest.browser.toolkit.mozapps.update.tests.browser += [
|
||||
'chrome/update.sjs',
|
||||
'data/shared.js',
|
||||
'data/sharedUpdateXML.js',
|
||||
'data/simple.mar',
|
||||
]
|
||||
|
||||
TEST_HARNESS_FILES.testing.mochitest.chrome.toolkit.mozapps.update.tests.data += [
|
||||
'data/shared.js',
|
||||
'data/sharedUpdateXML.js',
|
||||
|
|
|
@ -9,7 +9,7 @@ XPCSHELLTESTDIR = $(topobjdir)/_tests/xpcshell/toolkit/mozapps/update/tests
|
|||
MOCHITESTCHROMEDIR = $(topobjdir)/_tests/testing/mochitest/chrome/toolkit/mozapps/update/tests
|
||||
|
||||
ifeq (,$(MOZ_SUITE)$(MOZ_THUNDERBIRD))
|
||||
MOCHITESTBROWSERDIR = $(topobjdir)/_tests/testing/mochitest/browser/browser/base/content/test/appUpdate
|
||||
MOCHITESTBROWSERDIR = $(topobjdir)/_tests/testing/mochitest/browser/toolkit/mozapps/update/tests/browser
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
Загрузка…
Ссылка в новой задаче