зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1642404 - add an option to show that an update is being downloaded r=bytesized,fluent-reviewers,flod
Add support for a hidden preference named app.update.notifyDuringDownload that, when set to true, causes a "Downloading update" message to appear in the app menu during a MAR download. Clicking the message opens the about box so the user can see detailed progress information. Differential Revision: https://phabricator.services.mozilla.com/D77688
This commit is contained in:
Родитель
e8562a8631
Коммит
a7683d117e
|
@ -127,6 +127,10 @@ pref("app.update.download.promptMaxAttempts", 2);
|
|||
// download a fresh installer.
|
||||
pref("app.update.elevation.promptMaxAttempts", 2);
|
||||
|
||||
// If set to true, a message will be displayed in the hamburger menu while
|
||||
// an update is being downloaded.
|
||||
pref("app.update.notifyDuringDownload", false);
|
||||
|
||||
// If set to true, the Update Service will automatically download updates if the
|
||||
// user can apply updates. This pref is no longer used on Windows, except as the
|
||||
// default value to migrate to the new location that this data is now stored
|
||||
|
|
|
@ -782,6 +782,7 @@ const global = this;
|
|||
|
||||
const listeners = {
|
||||
observers: {
|
||||
"update-downloading": ["UpdateListener"],
|
||||
"update-staged": ["UpdateListener"],
|
||||
"update-downloaded": ["UpdateListener"],
|
||||
"update-available": ["UpdateListener"],
|
||||
|
|
|
@ -223,6 +223,8 @@
|
|||
<vbox class="panel-subview-body">
|
||||
<vbox id="appMenu-addon-banners"/>
|
||||
<toolbarbutton id="appMenu-update-banner" class="panel-banner-item"
|
||||
data-l10n-id="appmenuitem-update-banner"
|
||||
data-l10n-attrs="label-update-downloading"
|
||||
label-update-available="&updateAvailable.panelUI.label;"
|
||||
label-update-manual="&updateManual.panelUI.label;"
|
||||
label-update-unsupported="&updateUnsupported.panelUI.label;"
|
||||
|
|
|
@ -65,6 +65,7 @@ const PanelUI = {
|
|||
|
||||
Services.obs.addObserver(this, "fullscreen-nav-toolbox");
|
||||
Services.obs.addObserver(this, "appMenu-notifications");
|
||||
Services.obs.addObserver(this, "show-update-progress");
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
|
@ -182,6 +183,7 @@ const PanelUI = {
|
|||
|
||||
Services.obs.removeObserver(this, "fullscreen-nav-toolbox");
|
||||
Services.obs.removeObserver(this, "appMenu-notifications");
|
||||
Services.obs.removeObserver(this, "show-update-progress");
|
||||
|
||||
window.removeEventListener("MozDOMFullscreen:Entered", this);
|
||||
window.removeEventListener("MozDOMFullscreen:Exited", this);
|
||||
|
@ -271,6 +273,9 @@ const PanelUI = {
|
|||
this._notifications = AppMenuNotifications.notifications;
|
||||
this._updateNotifications(true);
|
||||
break;
|
||||
case "show-update-progress":
|
||||
openAboutDialog();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -156,6 +156,68 @@ add_task(async function testSecondaryActionWorkflow() {
|
|||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* This tests that the PanelUI update downloading badge and banner
|
||||
* notification are correctly displayed and that clicking the banner
|
||||
* item calls the main action.
|
||||
*/
|
||||
add_task(async function testDownloadingBadge() {
|
||||
let options = {
|
||||
gBrowser: window.gBrowser,
|
||||
url: "about:blank",
|
||||
};
|
||||
|
||||
await BrowserTestUtils.withNewTab(options, async function(browser) {
|
||||
let mainActionCalled = false;
|
||||
let mainAction = {
|
||||
callback: () => {
|
||||
mainActionCalled = true;
|
||||
},
|
||||
};
|
||||
// The downloading notification is always displayed in a dismissed state.
|
||||
AppMenuNotifications.showNotification(
|
||||
"update-downloading",
|
||||
mainAction,
|
||||
undefined,
|
||||
{ dismissed: true }
|
||||
);
|
||||
is(PanelUI.notificationPanel.state, "closed", "doorhanger is closed.");
|
||||
|
||||
is(
|
||||
PanelUI.menuButton.getAttribute("badge-status"),
|
||||
"update-downloading",
|
||||
"Downloading badge is displaying on PanelUI button."
|
||||
);
|
||||
|
||||
await gCUITestUtils.openMainMenu();
|
||||
isnot(
|
||||
PanelUI.menuButton.getAttribute("badge-status"),
|
||||
"update-downloading",
|
||||
"Downloading badge is hidden on PanelUI button."
|
||||
);
|
||||
let menuItem = PanelUI.mainView.querySelector(".panel-banner-item");
|
||||
is(
|
||||
menuItem.label,
|
||||
menuItem.getAttribute("label-update-downloading"),
|
||||
"Showing correct label (downloading)"
|
||||
);
|
||||
is(menuItem.hidden, false, "update-downloading menu item is showing.");
|
||||
|
||||
await gCUITestUtils.hideMainMenu();
|
||||
is(
|
||||
PanelUI.menuButton.getAttribute("badge-status"),
|
||||
"update-downloading",
|
||||
"Downloading badge is shown on PanelUI button."
|
||||
);
|
||||
|
||||
await gCUITestUtils.openMainMenu();
|
||||
menuItem.click();
|
||||
ok(mainActionCalled, "Main action callback was called");
|
||||
|
||||
AppMenuNotifications.removeNotification(/.*/);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* We want to ensure a few things with this:
|
||||
* - Adding a doorhanger will make a badge disappear
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
## App Menu
|
||||
|
||||
appmenuitem-update-banner =
|
||||
.label-update-downloading = Downloading { -brand-shorter-name } update
|
||||
appmenuitem-protection-dashboard-title = Protections Dashboard
|
||||
appmenuitem-customize-mode =
|
||||
.label = Customize…
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
}
|
||||
|
||||
#PanelUI-menu-button[badge-status="update-available"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-downloading"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-manual"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-restart"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-unsupported"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
|
@ -80,6 +81,7 @@
|
|||
}
|
||||
|
||||
#PanelUI-menu-button[badge-status="update-available"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-downloading"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-manual"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-restart"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center;
|
||||
|
@ -90,6 +92,7 @@
|
|||
}
|
||||
|
||||
.panel-banner-item[notificationid="update-available"]::after,
|
||||
.panel-banner-item[notificationid="update-downloading"]::after,
|
||||
.panel-banner-item[notificationid="update-manual"]::after,
|
||||
.panel-banner-item[notificationid="update-restart"]::after {
|
||||
background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center;
|
||||
|
|
|
@ -401,6 +401,7 @@ html|*#webRTC-previewVideo {
|
|||
|
||||
/* UPDATE */
|
||||
.popup-notification-icon[popupid="update-available"],
|
||||
.popup-notification-icon[popupid="update-downloading"],
|
||||
.popup-notification-icon[popupid="update-manual"],
|
||||
.popup-notification-icon[popupid="update-restart"] {
|
||||
background: #74BF43 url(chrome://browser/skin/notification-icons/update.svg) no-repeat center;
|
||||
|
|
|
@ -290,6 +290,7 @@ toolbar[brighttext] {
|
|||
}
|
||||
|
||||
#PanelUI-menu-button[badge-status="update-available"],
|
||||
#PanelUI-menu-button[badge-status="update-downloading"],
|
||||
#PanelUI-menu-button[badge-status="update-manual"],
|
||||
#PanelUI-menu-button[badge-status="update-restart"] {
|
||||
list-style-image: url("chrome://browser/skin/menu-badged.svg");
|
||||
|
|
|
@ -113,16 +113,18 @@ var UpdateListener = {
|
|||
mainAction,
|
||||
beforeShowDoorhanger
|
||||
) {
|
||||
const addTelemetry = id => {
|
||||
// No telemetry for the "downloading" state.
|
||||
if (type !== "downloading") {
|
||||
Services.telemetry.getHistogramById(id).add(type);
|
||||
}
|
||||
};
|
||||
let action = {
|
||||
callback(win, fromDoorhanger) {
|
||||
if (fromDoorhanger) {
|
||||
Services.telemetry
|
||||
.getHistogramById("UPDATE_NOTIFICATION_MAIN_ACTION_DOORHANGER")
|
||||
.add(type);
|
||||
addTelemetry("UPDATE_NOTIFICATION_MAIN_ACTION_DOORHANGER");
|
||||
} else {
|
||||
Services.telemetry
|
||||
.getHistogramById("UPDATE_NOTIFICATION_MAIN_ACTION_MENU")
|
||||
.add(type);
|
||||
addTelemetry("UPDATE_NOTIFICATION_MAIN_ACTION_MENU");
|
||||
}
|
||||
mainAction(win);
|
||||
},
|
||||
|
@ -131,13 +133,10 @@ var UpdateListener = {
|
|||
|
||||
let secondaryAction = {
|
||||
callback() {
|
||||
Services.telemetry
|
||||
.getHistogramById("UPDATE_NOTIFICATION_DISMISSED")
|
||||
.add(type);
|
||||
addTelemetry("UPDATE_NOTIFICATION_DISMISSED");
|
||||
},
|
||||
dismiss: true,
|
||||
};
|
||||
|
||||
AppMenuNotifications.showNotification(
|
||||
"update-" + type,
|
||||
action,
|
||||
|
@ -145,13 +144,9 @@ var UpdateListener = {
|
|||
{ dismissed, beforeShowDoorhanger }
|
||||
);
|
||||
if (dismissed) {
|
||||
Services.telemetry
|
||||
.getHistogramById("UPDATE_NOTIFICATION_BADGE_SHOWN")
|
||||
.add(type);
|
||||
addTelemetry("UPDATE_NOTIFICATION_BADGE_SHOWN");
|
||||
} else {
|
||||
Services.telemetry
|
||||
.getHistogramById("UPDATE_NOTIFICATION_SHOWN")
|
||||
.add(type);
|
||||
addTelemetry("UPDATE_NOTIFICATION_SHOWN");
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -205,6 +200,15 @@ var UpdateListener = {
|
|||
}
|
||||
},
|
||||
|
||||
showUpdateDownloadingNotification() {
|
||||
this.showUpdateNotification("downloading", true, true, () => {
|
||||
// The user clicked on the "Downloading update" app menu item.
|
||||
// Code in browser/components/customizableui/content/panelUI.js
|
||||
// receives the following notification and opens the about dialog.
|
||||
Services.obs.notifyObservers(null, "show-update-progress");
|
||||
});
|
||||
},
|
||||
|
||||
handleUpdateError(update, status) {
|
||||
switch (status) {
|
||||
case "download-attempt-failed":
|
||||
|
@ -287,6 +291,17 @@ var UpdateListener = {
|
|||
}
|
||||
},
|
||||
|
||||
handleUpdateDownloading(status) {
|
||||
switch (status) {
|
||||
case "downloading":
|
||||
this.showUpdateDownloadingNotification();
|
||||
break;
|
||||
case "idle":
|
||||
this.reset();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
observe(subject, topic, status) {
|
||||
let update = subject && subject.QueryInterface(Ci.nsIUpdate);
|
||||
|
||||
|
@ -299,6 +314,9 @@ var UpdateListener = {
|
|||
}
|
||||
this.handleUpdateAvailable(update, status);
|
||||
break;
|
||||
case "update-downloading":
|
||||
this.handleUpdateDownloading(status);
|
||||
break;
|
||||
case "update-staged":
|
||||
case "update-downloaded":
|
||||
// An update check has found an update and downloaded / staged the
|
||||
|
|
|
@ -59,6 +59,7 @@ const PREF_APP_UPDATE_ELEVATE_ATTEMPTS = "app.update.elevate.attempts";
|
|||
const PREF_APP_UPDATE_ELEVATE_MAXATTEMPTS = "app.update.elevate.maxAttempts";
|
||||
const PREF_APP_UPDATE_LOG = "app.update.log";
|
||||
const PREF_APP_UPDATE_LOG_FILE = "app.update.log.file";
|
||||
const PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD = "app.update.notifyDuringDownload";
|
||||
const PREF_APP_UPDATE_PROMPTWAITTIME = "app.update.promptWaitTime";
|
||||
const PREF_APP_UPDATE_SERVICE_ENABLED = "app.update.service.enabled";
|
||||
const PREF_APP_UPDATE_SERVICE_ERRORS = "app.update.service.errors";
|
||||
|
@ -4432,6 +4433,24 @@ Downloader.prototype = {
|
|||
return selectedPatch;
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether or not the user wants to be notified that an update is being
|
||||
* downloaded.
|
||||
*/
|
||||
get _notifyDuringDownload() {
|
||||
return Services.prefs.getBoolPref(
|
||||
PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD,
|
||||
false
|
||||
);
|
||||
},
|
||||
|
||||
_notifyDownloadStatusObservers: function Downloader_notifyDownloadStatusObservers() {
|
||||
if (this._notifyDuringDownload) {
|
||||
let status = this.updateService.isDownloading ? "downloading" : "idle";
|
||||
Services.obs.notifyObservers(this._update, "update-downloading", status);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether or not we are currently downloading something.
|
||||
*/
|
||||
|
@ -4673,6 +4692,9 @@ Downloader.prototype = {
|
|||
.getService(Ci.nsIUpdateManager)
|
||||
.saveUpdates();
|
||||
}
|
||||
|
||||
this._notifyDownloadStatusObservers();
|
||||
|
||||
return STATE_DOWNLOADING;
|
||||
},
|
||||
|
||||
|
@ -5175,6 +5197,11 @@ Downloader.prototype = {
|
|||
|
||||
this._request = null;
|
||||
|
||||
// This notification must happen after _request is set to null so that
|
||||
// the correct this.updateService.isDownloading value is available in
|
||||
// _notifyDownloadStatusObservers().
|
||||
this._notifyDownloadStatusObservers();
|
||||
|
||||
if (state == STATE_DOWNLOAD_FAILED) {
|
||||
var allFailed = true;
|
||||
// If we haven't already, attempt to download without BITS
|
||||
|
|
|
@ -21,6 +21,7 @@ prefs =
|
|||
# About Dialog Application Update Tests
|
||||
[browser_aboutDialog_bc_downloading.js]
|
||||
[browser_aboutDialog_bc_downloading_staging.js]
|
||||
[browser_aboutDialog_bc_downloading_notify.js]
|
||||
[browser_aboutDialog_bc_downloaded.js]
|
||||
[browser_aboutDialog_bc_downloaded_staging.js]
|
||||
[browser_aboutDialog_bc_downloaded_staged.js]
|
||||
|
|
|
@ -15,6 +15,7 @@ prefs =
|
|||
# About Dialog Application Update Tests
|
||||
[browser_aboutDialog_bc_downloading.js]
|
||||
[browser_aboutDialog_bc_downloading_staging.js]
|
||||
[browser_aboutDialog_bc_downloading_notify.js]
|
||||
[browser_aboutDialog_bc_downloaded.js]
|
||||
[browser_aboutDialog_bc_downloaded_staging.js]
|
||||
[browser_aboutDialog_bc_downloaded_stagingFailure.js]
|
||||
|
|
|
@ -20,6 +20,7 @@ prefs =
|
|||
# About Dialog Application Update Tests
|
||||
[browser_aboutDialog_bc_downloading.js]
|
||||
[browser_aboutDialog_bc_downloading_staging.js]
|
||||
[browser_aboutDialog_bc_downloading_notify.js]
|
||||
[browser_aboutDialog_bc_downloaded.js]
|
||||
[browser_aboutDialog_bc_downloaded_staging.js]
|
||||
[browser_aboutDialog_bc_downloaded_staged.js]
|
||||
|
|
|
@ -14,6 +14,7 @@ prefs =
|
|||
# About Dialog Application Update Tests
|
||||
[browser_aboutDialog_bc_downloading.js]
|
||||
[browser_aboutDialog_bc_downloading_staging.js]
|
||||
[browser_aboutDialog_bc_downloading_notify.js]
|
||||
[browser_aboutDialog_bc_downloaded.js]
|
||||
[browser_aboutDialog_bc_downloaded_staging.js]
|
||||
[browser_aboutDialog_bc_downloaded_stagingFailure.js]
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
// Test for About Dialog background check for updates
|
||||
// with the About Dialog opened during downloading.
|
||||
add_task(async function aboutDialog_backgroundCheck_downloading() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [[PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD, false]],
|
||||
});
|
||||
|
||||
let downloadInfo = [];
|
||||
if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) {
|
||||
downloadInfo[0] = { patchType: "partial", bitsResult: "0" };
|
||||
|
@ -21,6 +25,17 @@ add_task(async function aboutDialog_backgroundCheck_downloading() {
|
|||
waitForUpdateState: STATE_DOWNLOADING,
|
||||
};
|
||||
await runAboutDialogUpdateTest(params, [
|
||||
async function aboutDialog_downloading() {
|
||||
is(
|
||||
PanelUI.notificationPanel.state,
|
||||
"closed",
|
||||
"The window's doorhanger is closed."
|
||||
);
|
||||
ok(
|
||||
!PanelUI.menuButton.hasAttribute("badge-status"),
|
||||
"The window does not have a badge."
|
||||
);
|
||||
},
|
||||
{
|
||||
panelId: "downloading",
|
||||
checkActiveUpdate: { state: STATE_DOWNLOADING },
|
||||
|
@ -33,4 +48,6 @@ add_task(async function aboutDialog_backgroundCheck_downloading() {
|
|||
continueFile: null,
|
||||
},
|
||||
]);
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test for About Dialog background check for updates with the
|
||||
// "notify during download" feature turned on.
|
||||
add_task(async function aboutDialog_backgroundCheck_downloading_notify() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [[PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD, true]],
|
||||
});
|
||||
|
||||
let downloadInfo = [];
|
||||
if (Services.prefs.getBoolPref(PREF_APP_UPDATE_BITS_ENABLED)) {
|
||||
downloadInfo[0] = { patchType: "partial", bitsResult: "0" };
|
||||
} else {
|
||||
downloadInfo[0] = { patchType: "partial", internalResult: "0" };
|
||||
}
|
||||
|
||||
// Since the partial should be successful specify an invalid size for the
|
||||
// complete update.
|
||||
let params = {
|
||||
queryString: "&useSlowDownloadMar=1&invalidCompleteSize=1",
|
||||
backgroundUpdate: true,
|
||||
waitForUpdateState: STATE_DOWNLOADING,
|
||||
};
|
||||
await runAboutDialogUpdateTest(params, [
|
||||
async function aboutDialog_downloading_notification() {
|
||||
is(
|
||||
PanelUI.notificationPanel.state,
|
||||
"closed",
|
||||
"The window's doorhanger is closed."
|
||||
);
|
||||
ok(
|
||||
PanelUI.menuButton.hasAttribute("badge-status"),
|
||||
"The window has a badge."
|
||||
);
|
||||
is(
|
||||
PanelUI.menuButton.getAttribute("badge-status"),
|
||||
"update-downloading",
|
||||
"The downloading badge is showing for the background window"
|
||||
);
|
||||
},
|
||||
{
|
||||
panelId: "downloading",
|
||||
checkActiveUpdate: { state: STATE_DOWNLOADING },
|
||||
continueFile: CONTINUE_DOWNLOAD,
|
||||
downloadInfo,
|
||||
},
|
||||
{
|
||||
panelId: "apply",
|
||||
checkActiveUpdate: { state: STATE_PENDING },
|
||||
continueFile: null,
|
||||
},
|
||||
]);
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
});
|
|
@ -40,6 +40,7 @@ const PREF_APP_UPDATE_INTERVAL = "app.update.interval";
|
|||
const PREF_APP_UPDATE_LASTUPDATETIME =
|
||||
"app.update.lastUpdateTime.background-update-timer";
|
||||
const PREF_APP_UPDATE_LOG = "app.update.log";
|
||||
const PREF_APP_UPDATE_NOTIFYDURINGDOWNLOAD = "app.update.notifyDuringDownload";
|
||||
const PREF_APP_UPDATE_PROMPTWAITTIME = "app.update.promptWaitTime";
|
||||
const PREF_APP_UPDATE_RETRYTIMEOUT = "app.update.socket.retryTimeout";
|
||||
const PREF_APP_UPDATE_SERVICE_ENABLED = "app.update.service.enabled";
|
||||
|
|
Загрузка…
Ссылка в новой задаче