fx115: Fix "Check for Updates" window
Also: - Tweak text to be less alarming (fixes #3074) - Don't show "No updates found" if update was already downloaded (fixes #3148) Download progress still isn't shown (#3130) but I'll fix that later
This commit is contained in:
parent
b42e412c4f
commit
827bcd704d
4 changed files with 207 additions and 114 deletions
|
@ -1,10 +1,3 @@
|
||||||
/* Hide the wizard's header so the size of the billboard can size the window
|
|
||||||
on creation. A custom header will be used in its place when a header is
|
|
||||||
needed. */
|
|
||||||
.wizard-header {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Display the custom header */
|
/* Display the custom header */
|
||||||
.update-header {
|
.update-header {
|
||||||
display: -moz-box !important;
|
display: -moz-box !important;
|
||||||
|
@ -18,12 +11,6 @@ needed. */
|
||||||
-moz-box-flex: 1;
|
-moz-box-flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update History Window */
|
|
||||||
richlistitem.update {
|
|
||||||
display: -moz-box;
|
|
||||||
-moz-box-orient: vertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
.update-name {
|
.update-name {
|
||||||
-moz-box-flex: 1;
|
-moz-box-flex: 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,79 @@ function openUpdateURL(event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AbortError extends Error {
|
||||||
|
constructor(...params) {
|
||||||
|
super(...params);
|
||||||
|
this.name = this.constructor.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `AbortablePromise`s automatically add themselves to this set on construction
|
||||||
|
* and remove themselves when they settle.
|
||||||
|
*/
|
||||||
|
var gPendingAbortablePromises = new Set();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Promise that can be resolved immediately with an abort method.
|
||||||
|
*
|
||||||
|
* Note that the underlying Promise will probably still run to completion since
|
||||||
|
* there isn't any general way to abort Promises. So if it is possible to abort
|
||||||
|
* the operation instead or in addition to using this class, that is preferable.
|
||||||
|
*/
|
||||||
|
class AbortablePromise {
|
||||||
|
#abortFn;
|
||||||
|
#promise;
|
||||||
|
#hasCompleted = false;
|
||||||
|
|
||||||
|
constructor(promise) {
|
||||||
|
let abortPromise = new Promise((resolve, reject) => {
|
||||||
|
this.#abortFn = () => reject(new AbortError());
|
||||||
|
});
|
||||||
|
this.#promise = Promise.race([promise, abortPromise]);
|
||||||
|
this.#promise = this.#promise.finally(() => {
|
||||||
|
this.#hasCompleted = true;
|
||||||
|
gPendingAbortablePromises.delete(this);
|
||||||
|
});
|
||||||
|
gPendingAbortablePromises.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
abort() {
|
||||||
|
if (this.#hasCompleted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.#abortFn();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This can be `await`ed on to get the result of the `AbortablePromise`. It
|
||||||
|
* will resolve with the value that the Promise provided to the constructor
|
||||||
|
* resolves with.
|
||||||
|
*/
|
||||||
|
get promise() {
|
||||||
|
return this.#promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will be `true` if the Promise provided to the constructor has resolved or
|
||||||
|
* `abort()` has been called. Otherwise `false`.
|
||||||
|
*/
|
||||||
|
get hasCompleted() {
|
||||||
|
return this.#hasCompleted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeAbortable(promise) {
|
||||||
|
let abortable = new AbortablePromise(promise);
|
||||||
|
return abortable.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
function abortAllPromises() {
|
||||||
|
for (const promise of gPendingAbortablePromises) {
|
||||||
|
promise.abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of shared data and control functions for the wizard as a whole.
|
* A set of shared data and control functions for the wizard as a whole.
|
||||||
*/
|
*/
|
||||||
|
@ -522,8 +595,9 @@ var gUpdates = {
|
||||||
var um = Cc["@mozilla.org/updates/update-manager;1"].getService(
|
var um = Cc["@mozilla.org/updates/update-manager;1"].getService(
|
||||||
Ci.nsIUpdateManager
|
Ci.nsIUpdateManager
|
||||||
);
|
);
|
||||||
if (um.activeUpdate) {
|
let activeUpdate = um.downloadingUpdate || um.readyUpdate;
|
||||||
this.setUpdate(um.activeUpdate);
|
if (activeUpdate) {
|
||||||
|
this.setUpdate(activeUpdate);
|
||||||
aCallback("downloading");
|
aCallback("downloading");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -569,61 +643,57 @@ var gCheckingPage = {
|
||||||
/**
|
/**
|
||||||
* Initialize
|
* Initialize
|
||||||
*/
|
*/
|
||||||
onPageShow() {
|
async onPageShow() {
|
||||||
gUpdates.setButtons(null, null, null, false, true);
|
gUpdates.setButtons(null, null, null, false, true);
|
||||||
gUpdates.wiz.getButton("cancel").focus();
|
gUpdates.wiz.getButton("cancel").focus();
|
||||||
|
|
||||||
// Clear elevation never prefs to handle the scenario where the user clicked
|
try {
|
||||||
// "never" for an update and then canceled a manual update check. If the
|
|
||||||
// preference isn't cleared then future notifications will never happen.
|
|
||||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ELEVATE_NEVER)) {
|
|
||||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_ELEVATE_NEVER);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The user will be notified if there is an error so clear the background
|
|
||||||
// check error count.
|
|
||||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS)) {
|
|
||||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_BACKGROUNDERRORS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The preference will be set back to true if the system is still
|
|
||||||
// unsupported.
|
|
||||||
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED)) {
|
|
||||||
Services.prefs.clearUserPref(PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._checker = Cc["@mozilla.org/updates/update-checker;1"].createInstance(
|
this._checker = Cc["@mozilla.org/updates/update-checker;1"].createInstance(
|
||||||
Ci.nsIUpdateChecker
|
Ci.nsIUpdateChecker
|
||||||
);
|
);
|
||||||
this._checker.checkForUpdates(this.updateListener, true);
|
let check = await this._checker.checkForUpdates(this._checker.FOREGROUND_CHECK);
|
||||||
},
|
let result;
|
||||||
|
try {
|
||||||
|
result = await makeAbortable(check.result);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
// If we are aborting, stop the update check on our way out.
|
||||||
|
if (e instanceof AbortError) {
|
||||||
|
this._checker.stopCheck(check.id);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
if (!result.checksAllowed) {
|
||||||
* The user has closed the window, either by pressing cancel or using a Window
|
// This shouldn't happen. The cases where this can happen should be
|
||||||
* Manager control, so stop checking for updates.
|
// handled specifically, above.
|
||||||
*/
|
LOG("gCheckingPage:onPageShow - !checksAllowed; INTERNAL_ERROR");
|
||||||
onWizardCancel() {
|
gUpdates.wiz.goTo("errors");
|
||||||
this._checker.stopCurrentCheck();
|
return;
|
||||||
},
|
}
|
||||||
|
|
||||||
|
if (!result.succeeded) {
|
||||||
|
LOG("gCheckingPage:onPageShow - Update check failed; CHECKING_FAILED");
|
||||||
|
gUpdates.wiz.goTo("errors");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG("gCheckingPage:onPageShow - Update check succeeded");
|
||||||
|
gUpdates.setUpdate(gAUS.selectUpdate(result.updates));
|
||||||
|
if (!gUpdates.update) {
|
||||||
|
LOG("gCheckingPage:onPageShow - result: NO_UPDATES_FOUND");
|
||||||
|
gUpdates.wiz.goTo("noupdatesfound");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* An object implementing nsIUpdateCheckListener that is notified as the
|
|
||||||
* update check commences.
|
|
||||||
*/
|
|
||||||
updateListener: {
|
|
||||||
/**
|
|
||||||
* See nsIUpdateCheckListener
|
|
||||||
*/
|
|
||||||
async onCheckComplete(request, updates) {
|
|
||||||
gUpdates.setUpdate(gAUS.selectUpdate(updates));
|
|
||||||
if (gUpdates.update) {
|
|
||||||
LOG("gCheckingPage", "onCheckComplete - update found");
|
|
||||||
if (gUpdates.update.unsupported) {
|
if (gUpdates.update.unsupported) {
|
||||||
|
LOG("gCheckingPage:onPageShow - result: UNSUPPORTED SYSTEM");
|
||||||
gUpdates.wiz.goTo("unsupported");
|
gUpdates.wiz.goTo("unsupported");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gUpdates.update.elevationFailure) {
|
if (gUpdates.update.elevationFailure) {
|
||||||
|
LOG("gCheckingPage:onPageShow - result: elevationFailure")
|
||||||
// Prevent multiple notifications for the same update when the client
|
// Prevent multiple notifications for the same update when the client
|
||||||
// has had an elevation failure.
|
// has had an elevation failure.
|
||||||
gUpdates.never();
|
gUpdates.never();
|
||||||
|
@ -632,31 +702,62 @@ var gCheckingPage = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gAUS.canApplyUpdates) {
|
if (!gAUS.canApplyUpdates) {
|
||||||
|
LOG("gCheckingPage:onPageShow - result: MANUAL_UPDATE");
|
||||||
gUpdates.wiz.goTo("manualUpdate");
|
gUpdates.wiz.goTo("manualUpdate");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gUpdates.wiz.goTo(gUpdates.updatesFoundPageId);
|
/*let updateAuto = await makeAbortable(
|
||||||
return;
|
lazy.UpdateUtils.getAppUpdateAutoEnabled()
|
||||||
|
);
|
||||||
|
if (!updateAuto || this.aus.manualUpdateOnly) {
|
||||||
|
LOG(
|
||||||
|
"gCheckingPage:onPageShow - Need to wait for user approval to start the " +
|
||||||
|
"download."
|
||||||
|
);
|
||||||
|
|
||||||
|
let downloadPermissionPromise = new Promise(resolve => {
|
||||||
|
this.#permissionToDownloadGivenFn = resolve;
|
||||||
|
});
|
||||||
|
// There are other interfaces through which the user can start the
|
||||||
|
// download, so we want to listen both for permission, and for the
|
||||||
|
// download to independently start.
|
||||||
|
let downloadStartPromise = Promise.race([
|
||||||
|
downloadPermissionPromise,
|
||||||
|
this.aus.stateTransition,
|
||||||
|
]);
|
||||||
|
|
||||||
|
this.#setStatus(AppUpdater.STATUS.DOWNLOAD_AND_INSTALL);
|
||||||
|
|
||||||
|
await makeAbortable(downloadStartPromise);
|
||||||
|
LOG("gCheckingPage:onPageShow - Got user approval. Proceeding with download");
|
||||||
|
// If we resolved because of `aus.stateTransition`, we may actually be
|
||||||
|
// downloading a different update now.
|
||||||
|
if (this.um.downloadingUpdate) {
|
||||||
|
this.#update = this.um.downloadingUpdate;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
LOG("gCheckingPage", "onCheckComplete - no update found");
|
LOG(
|
||||||
gUpdates.wiz.goTo("noupdatesfound");
|
"gCheckingPage:onPageShow - updateAuto is active and " +
|
||||||
},
|
"manualUpdateOnlydateOnly is inactive. Start the download."
|
||||||
|
);
|
||||||
/**
|
}
|
||||||
* See nsIUpdateCheckListener
|
await this.#downloadUpdate();*/
|
||||||
*/
|
gUpdates.wiz.goTo(gUpdates.updatesFoundPageId);
|
||||||
async onError(request, update) {
|
}
|
||||||
LOG("gCheckingPage", "onError - proceeding to error page");
|
catch (e) {
|
||||||
gUpdates.setUpdate(update);
|
LOG("gCheckingPage:onPageShow - result: Exception");
|
||||||
|
LOG(e);
|
||||||
gUpdates.wiz.goTo("errors");
|
gUpdates.wiz.goTo("errors");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See nsISupports.idl
|
* The user has closed the window, either by pressing cancel or using a Window
|
||||||
|
* Manager control, so stop checking for updates.
|
||||||
*/
|
*/
|
||||||
QueryInterface: ChromeUtils.generateQI(["nsIUpdateCheckListener"]),
|
onWizardCancel() {
|
||||||
|
this._checker.stopCurrentCheck();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -732,7 +833,7 @@ var gUpdatesFoundBasicPage = {
|
||||||
/**
|
/**
|
||||||
* Initialize
|
* Initialize
|
||||||
*/
|
*/
|
||||||
onPageShow() {
|
async onPageShow() {
|
||||||
gUpdates.wiz.canRewind = false;
|
gUpdates.wiz.canRewind = false;
|
||||||
var update = gUpdates.update;
|
var update = gUpdates.update;
|
||||||
gUpdates.setButtons(
|
gUpdates.setButtons(
|
||||||
|
@ -745,23 +846,21 @@ var gUpdatesFoundBasicPage = {
|
||||||
btn.focus();
|
btn.focus();
|
||||||
|
|
||||||
var updateName = update.name;
|
var updateName = update.name;
|
||||||
if (update.channel == "nightly") {
|
|
||||||
updateName = gUpdates.getAUSString("updateNightlyName", [
|
|
||||||
gUpdates.brandName,
|
|
||||||
update.displayVersion,
|
|
||||||
update.buildID,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
var updateNameElement = document.getElementById("updateName");
|
var updateNameElement = document.getElementById("updateName");
|
||||||
updateNameElement.value = updateName;
|
updateNameElement.value = updateName;
|
||||||
|
|
||||||
var introText = gUpdates.getAUSString("intro_" + update.type, [
|
var introElem = document.getElementById("updatesFoundIntro");
|
||||||
|
introElem.setAttribute("severity", update.type);
|
||||||
|
if (update.type == 'major') {
|
||||||
|
let introText = gUpdates.getAUSString("intro_" + update.type, [
|
||||||
gUpdates.brandName,
|
gUpdates.brandName,
|
||||||
update.displayVersion,
|
update.displayVersion,
|
||||||
]);
|
]);
|
||||||
var introElem = document.getElementById("updatesFoundInto");
|
|
||||||
introElem.setAttribute("severity", update.type);
|
|
||||||
introElem.textContent = introText;
|
introElem.textContent = introText;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
document.l10n.setAttributes(introElem, 'update-updates-found-intro-minor');
|
||||||
|
}
|
||||||
|
|
||||||
var updateMoreInfoURL = document.getElementById("updateMoreInfoURL");
|
var updateMoreInfoURL = document.getElementById("updateMoreInfoURL");
|
||||||
if (update.detailsURL) {
|
if (update.detailsURL) {
|
||||||
|
@ -823,18 +922,16 @@ var gDownloadingPage = {
|
||||||
var um = Cc["@mozilla.org/updates/update-manager;1"].getService(
|
var um = Cc["@mozilla.org/updates/update-manager;1"].getService(
|
||||||
Ci.nsIUpdateManager
|
Ci.nsIUpdateManager
|
||||||
);
|
);
|
||||||
var activeUpdate = um.activeUpdate;
|
var activeUpdate = um.downloadingUpdate || um.readyUpdate;
|
||||||
if (activeUpdate) {
|
if (activeUpdate) {
|
||||||
gUpdates.setUpdate(activeUpdate);
|
gUpdates.setUpdate(activeUpdate);
|
||||||
|
|
||||||
// It's possible the update has already been downloaded and is being
|
// It's possible the update has already been downloaded and is being
|
||||||
// applied by the time this page is shown, depending on how fast the
|
// applied by the time this page is shown, depending on how fast the
|
||||||
// download goes and how quickly the 'next' button is clicked to get here.
|
// download goes and how quickly the 'next' button is clicked to get here.
|
||||||
if (
|
if (activeUpdate.state == STATE_PENDING
|
||||||
activeUpdate.state == STATE_PENDING ||
|
|| activeUpdate.state == STATE_PENDING_ELEVATE
|
||||||
activeUpdate.state == STATE_PENDING_ELEVATE ||
|
|| activeUpdate.state == STATE_PENDING_SERVICE) {
|
||||||
activeUpdate.state == STATE_PENDING_SERVICE
|
|
||||||
) {
|
|
||||||
if (!activeUpdate.getProperty("stagingFailed")) {
|
if (!activeUpdate.getProperty("stagingFailed")) {
|
||||||
gUpdates.setButtons("hideButton", null, null, false);
|
gUpdates.setButtons("hideButton", null, null, false);
|
||||||
gUpdates.wiz.getButton("extra1").focus();
|
gUpdates.wiz.getButton("extra1").focus();
|
||||||
|
@ -846,6 +943,11 @@ var gDownloadingPage = {
|
||||||
gUpdates.wiz.goTo("finished");
|
gUpdates.wiz.goTo("finished");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (activeUpdate.state == STATE_APPLIED
|
||||||
|
|| activeUpdate.state == STATE_APPLIED_SERVICE) {
|
||||||
|
gUpdates.wiz.goTo("finished");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gUpdates.update) {
|
if (!gUpdates.update) {
|
||||||
|
@ -978,7 +1080,7 @@ var gDownloadingPage = {
|
||||||
var um = Cc["@mozilla.org/updates/update-manager;1"].getService(
|
var um = Cc["@mozilla.org/updates/update-manager;1"].getService(
|
||||||
Ci.nsIUpdateManager
|
Ci.nsIUpdateManager
|
||||||
);
|
);
|
||||||
um.activeUpdate = gUpdates.update;
|
um.readyUpdate = gUpdates.update;
|
||||||
|
|
||||||
// Continue download in the background at full speed.
|
// Continue download in the background at full speed.
|
||||||
LOG(
|
LOG(
|
||||||
|
@ -1161,7 +1263,7 @@ var gErrorsPage = {
|
||||||
gUpdates.setButtons(null, null, "okButton", true);
|
gUpdates.setButtons(null, null, "okButton", true);
|
||||||
gUpdates.wiz.getButton("finish").focus();
|
gUpdates.wiz.getButton("finish").focus();
|
||||||
|
|
||||||
var statusText = gUpdates.update.statusText;
|
var statusText = gUpdates.update?.statusText || "";
|
||||||
LOG("gErrorsPage", "onPageShow - update.statusText: " + statusText);
|
LOG("gErrorsPage", "onPageShow - update.statusText: " + statusText);
|
||||||
|
|
||||||
var errorReason = document.getElementById("errorReason");
|
var errorReason = document.getElementById("errorReason");
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
<wizard width="500" height="400">
|
<wizard width="500" height="400">
|
||||||
<linkset>
|
<linkset>
|
||||||
|
<html:link rel="localization" href="zotero.ftl"/>
|
||||||
<html:link rel="localization" href="toolkit/global/wizard.ftl"/>
|
<html:link rel="localization" href="toolkit/global/wizard.ftl"/>
|
||||||
</linkset>
|
</linkset>
|
||||||
|
|
||||||
|
@ -91,11 +92,11 @@
|
||||||
object="gUpdatesFoundBasicPage" next="downloading">
|
object="gUpdatesFoundBasicPage" next="downloading">
|
||||||
<update-header id="updatesFoundBasicHeader" label=""/>
|
<update-header id="updatesFoundBasicHeader" label=""/>
|
||||||
<vbox class="update-content" flex="1">
|
<vbox class="update-content" flex="1">
|
||||||
<label id="updatesFoundInto"/>
|
<label id="updatesFoundIntro"/>
|
||||||
<separator class="thin"/>
|
<separator class="thin"/>
|
||||||
<label id="updateName" crop="right" value=""/>
|
<label id="updateName" crop="right" value=""/>
|
||||||
<separator id="updateNameSep" class="thin"/>
|
<separator id="updateNameSep" class="thin"/>
|
||||||
<label id="upgradeEvangelism">&evangelism.desc;</label>
|
<label data-l10n-id="update-updates-found-desc"/>
|
||||||
<separator id="upgradeEvangelismSep" flex="1"/>
|
<separator id="upgradeEvangelismSep" flex="1"/>
|
||||||
<vbox flex="1">
|
<vbox flex="1">
|
||||||
<hbox id="moreInfoURL">
|
<hbox id="moreInfoURL">
|
||||||
|
|
|
@ -104,6 +104,9 @@ itembox-button-options =
|
||||||
reader-use-dark-mode-for-content =
|
reader-use-dark-mode-for-content =
|
||||||
.label = Use Dark Mode for Content
|
.label = Use Dark Mode for Content
|
||||||
|
|
||||||
|
update-updates-found-intro-minor = An update for { -app-name } is available:
|
||||||
|
update-updates-found-desc = It is recommended that you apply this update as soon as possible.
|
||||||
|
|
||||||
import-window =
|
import-window =
|
||||||
.title = Import
|
.title = Import
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue