зеркало из https://github.com/mozilla/pjs.git
Unify update download/checking error generation and reporting, more work on update history view, fix various polish bugs in downloading page, etc.
This commit is contained in:
Родитель
e865635624
Коммит
adbdd8367b
|
@ -448,7 +448,7 @@ function checkForUpdates()
|
|||
{
|
||||
var prompter = Components.classes["@mozilla.org/updates/update-prompt;1"]
|
||||
.createInstance(Components.interfaces.nsIUpdatePrompt);
|
||||
prompter.checkForUpdates();
|
||||
prompter.checkForUpdates(window);
|
||||
}
|
||||
|
||||
function buildHelpMenu()
|
||||
|
|
|
@ -138,14 +138,14 @@ var gAdvancedPane = {
|
|||
{
|
||||
var prompter = Components.classes["@mozilla.org/updates/update-prompt;1"]
|
||||
.createInstance(Components.interfaces.nsIUpdatePrompt);
|
||||
prompter.checkForUpdates();
|
||||
prompter.checkForUpdates(window);
|
||||
},
|
||||
|
||||
showUpdates: function ()
|
||||
{
|
||||
var prompter = Components.classes["@mozilla.org/updates/update-prompt;1"]
|
||||
.createInstance(Components.interfaces.nsIUpdatePrompt);
|
||||
prompter.showUpdateHistory();
|
||||
prompter.showUpdateHistory(window);
|
||||
},
|
||||
|
||||
showLanguages: function ()
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<!ENTITY checkNow.label "Check Now...">
|
||||
<!ENTITY appCheckNow.accesskey "C">
|
||||
<!ENTITY extensionsCheckNow.accesskey "h">
|
||||
<!ENTITY showUpdates.label "Show Updates">
|
||||
<!ENTITY showUpdates.label "Show Update History">
|
||||
<!ENTITY showUpdates.accesskey "U">
|
||||
|
||||
<!ENTITY securityTab.label "Security">
|
||||
|
|
|
@ -38,8 +38,9 @@
|
|||
<!ENTITY downloading.title "Downloading Update">
|
||||
<!ENTITY downloading.intro "Downloading the update...">
|
||||
<!ENTITY connecting.label "Connecting to the update server...">
|
||||
<!ENTITY showCompletedUpdates.label "Show old updates in this list">
|
||||
<!ENTITY showCompletedUpdates.accesskey "o">
|
||||
<!ENTITY verificationFailedText.label "&brandShortName; was unable to verify the integrity of the
|
||||
incremental update it downloaded, so it is now downloading
|
||||
the complete update package.">
|
||||
|
||||
<!ENTITY details.link "Details">
|
||||
<!ENTITY pause.label "Pause">
|
||||
|
@ -66,4 +67,9 @@
|
|||
<!ENTITY finishedBackground.instruction2 "Click Later to continue without restarting. The update will be installed
|
||||
the next time you start &brandShortName;.">
|
||||
|
||||
<!ENTITY installed.title "Update Installed">
|
||||
<!ENTITY installed.intro "The update was successfully installed.">
|
||||
|
||||
<!ENTITY update.details.label "Details">
|
||||
<!ENTITY update.installedOn.label "Installed on:">
|
||||
<!ENTITY update.status.label "Status:">
|
||||
|
|
|
@ -23,19 +23,22 @@ app.update.url.manual=http://www.mozilla.org/update
|
|||
app.update.url.override=
|
||||
closeButtonLabel=Close
|
||||
|
||||
statusFormatKBKB=#1 of #2 KB
|
||||
statusFormatKBMB=#1 KB of #2 MB
|
||||
statusFormatMBMB=#1 of #2 MB
|
||||
statusFormatUnknownKB=#1 KB
|
||||
statusFormatUnknownMB=#1 MB
|
||||
progressFormatKBKB=#1 of #2 KB
|
||||
progressFormatKBMB=#1 KB of #2 MB
|
||||
progressFormatMBMB=#1 of #2 MB
|
||||
progressFormatUnknownKB=#1 KB
|
||||
progressFormatUnknownMB=#1 MB
|
||||
pausedStatus=%S downloaded so far
|
||||
remain=remain
|
||||
unknownFilesize=unknown file size
|
||||
rateFormatKBSec=#1 KB/sec
|
||||
rateFormatMBSec=#1 MB/sec
|
||||
statusFormat=#1 at #2; #3 #4
|
||||
longTimeFormat=#1:#2:#3
|
||||
shortTimeFormat=#2:#3
|
||||
rateFormat= at #1
|
||||
progressFormat=#1#2
|
||||
timeFormat=; #1 #2
|
||||
statusFormat=#1#2
|
||||
downloadingPrefix=Downloading %S...
|
||||
pausedName=Paused downloading %S
|
||||
|
||||
|
@ -63,4 +66,4 @@ checker_error-2152398849=Failed (Unknown Reason)
|
|||
checker_error-2152398868=AUS: No data was received (Please try again)
|
||||
checker_error-2152398919=AUS: Data transfer was interrupted (Please try again)
|
||||
checker_error-2152398867=AUS: Port not allowed (Contact your Administrator)
|
||||
|
||||
checker_error-verification_failed=The integrity of the update could not be verified (Contact your Administrator)
|
||||
|
|
|
@ -38,44 +38,34 @@
|
|||
const NS_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
var gUpdateHistory = {
|
||||
_children: null,
|
||||
_view: null,
|
||||
|
||||
/**
|
||||
* Initialize the User Interface
|
||||
*/
|
||||
onLoad: function() {
|
||||
this._children = document.getElementById("historyChildren");
|
||||
this._view = document.getElementById("historyItems");
|
||||
|
||||
var um =
|
||||
Components.classes["@mozilla.org/updates/update-manager;1"].
|
||||
getService(Components.interfaces.nsIUpdateManager);
|
||||
var uc = um.updateCount;
|
||||
if (uc) {
|
||||
while (this._children.hasChildNodes())
|
||||
this._children.removeChild(this._children.firstChild);
|
||||
while (this._view.hasChildNodes())
|
||||
this._view.removeChild(this._view.firstChild);
|
||||
|
||||
var bundle = document.getElementById("updateBundle");
|
||||
|
||||
for (var i = 0; i < uc; ++i) {
|
||||
var update = um.getUpdateAt(i);
|
||||
|
||||
var treeitem = document.createElementNS(NS_XUL, "treeitem");
|
||||
var treerow = document.createElementNS(NS_XUL, "treerow");
|
||||
var nameCell = document.createElementNS(NS_XUL, "treecell");
|
||||
nameCell.setAttribute("label", update.name);
|
||||
var dateCell = document.createElementNS(NS_XUL, "treecell");
|
||||
var formattedDate = this._formatDate(update.installDate);
|
||||
dateCell.setAttribute("label", formattedDate);
|
||||
var typeCell = document.createElementNS(NS_XUL, "treecell");
|
||||
typeCell.setAttribute("label", update.type);
|
||||
dump("*** name = " + update.name + ", date = " + update.installDate + ", type = " + update.type + ", state = " + update.state + "\n");
|
||||
var stateCell = document.createElementNS(NS_XUL, "treecell");
|
||||
stateCell.setAttribute("label", update.selectedPatch.state);
|
||||
treerow.appendChild(nameCell);
|
||||
treerow.appendChild(dateCell);
|
||||
treerow.appendChild(typeCell);
|
||||
treerow.appendChild(stateCell);
|
||||
treeitem.appendChild(treerow);
|
||||
|
||||
this._children.appendChild(treeitem);
|
||||
var element = document.createElementNS(NS_XUL, "update");
|
||||
this._view.appendChild(element);
|
||||
element.name = update.name;
|
||||
element.type = bundle.getString("updateType_" + update.type);
|
||||
element.installDate = this._formatDate(update.installDate);
|
||||
element.detailsURL = update.detailsURL;
|
||||
element.status = update.statusText;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,20 +94,6 @@ var gUpdateHistory = {
|
|||
date.getHours(),
|
||||
date.getMinutes(),
|
||||
date.getSeconds());
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when a tree row is selected
|
||||
*/
|
||||
onTreeSelect: function() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the Details page for an item
|
||||
*/
|
||||
showDetails: function() {
|
||||
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -61,34 +61,10 @@
|
|||
src="chrome://mozapps/locale/update/updates.properties"/>
|
||||
|
||||
<label>&history.intro;</label>
|
||||
<separator/>
|
||||
<tree id="historyItems" rows="10" hidecolumnpicker="true" seltype="single"
|
||||
onselect="gUpdateHistory.onTreeSelect()">
|
||||
<treecols>
|
||||
<treecol id="updateNameCol" flex="1" primary="true" label="&name.header;"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol id="updateDate" label="&date.header;"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol id="updateType" label="&type.header;"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol id="updateState" label="&state.header;"/>
|
||||
</treecols>
|
||||
<treechildren id="historyChildren">
|
||||
<treeitem>
|
||||
<treerow>
|
||||
<treecell>&noupdates.label;</treecell>
|
||||
<treecell/>
|
||||
<treecell/>
|
||||
<treecell/>
|
||||
</treerow>
|
||||
</treeitem>
|
||||
</treechildren>
|
||||
</tree>
|
||||
<separator/>
|
||||
<hbox>
|
||||
<button id="details"
|
||||
label="&detailsButton.label;" accesskey="&detailsButton.accesskey;"
|
||||
oncommand="gUpdateHistory.showDetails();"/>
|
||||
</hbox>
|
||||
<separator class="thin"/>
|
||||
<richlistbox id="historyItems" flex="1">
|
||||
<label>&noupdates.label;</label>
|
||||
</richlistbox>
|
||||
<separator class="thin"/>
|
||||
</dialog>
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ wizard[currentpageid="updatesfound"] .wizard-page-box {
|
|||
|
||||
#downloadStatus {
|
||||
margin-top: 6px;
|
||||
height: 3em !important;
|
||||
}
|
||||
#downloadThrobber {
|
||||
margin: 5px 3px 0px 5px;
|
||||
|
@ -135,6 +136,11 @@ wizard[currentpageid="updatesfound"] .wizard-page-box {
|
|||
list-style-image: url("chrome://global/skin/throbber/Throbber-small.gif");
|
||||
}
|
||||
|
||||
#verificationFailedIcon {
|
||||
list-style-image: url("chrome://global/skin/icons/notfound.png");
|
||||
margin: 5px 3px 0px 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error Page
|
||||
*/
|
||||
|
@ -146,3 +152,40 @@ wizard[currentpageid="updatesfound"] .wizard-page-box {
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update History Window
|
||||
*/
|
||||
update {
|
||||
-moz-binding: url("chrome://mozapps/content/update/updates.xml#update");
|
||||
display: -moz-box;
|
||||
-moz-box-orient: vertical;
|
||||
border-bottom: 1px dotted #C0C0C0;
|
||||
}
|
||||
|
||||
.update-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.update-label-column {
|
||||
-moz-box-align: end;
|
||||
}
|
||||
|
||||
.update-details-link {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.update-type {
|
||||
font-weight: bold;
|
||||
color: #990000;
|
||||
}
|
||||
|
||||
#historyItems {
|
||||
-moz-appearance: listbox;
|
||||
height: 200px;
|
||||
margin: 1px 5px 4px 5px;
|
||||
}
|
||||
|
||||
#historyItems > scrollbox {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
|
||||
|
|
|
@ -97,18 +97,36 @@ function getPref(func, preference, defaultValue) {
|
|||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* A set of shared data and control functions for the wizard as a whole.
|
||||
*/
|
||||
var gUpdates = {
|
||||
update : null,
|
||||
strings : null,
|
||||
brandName : null,
|
||||
wiz : null,
|
||||
sourceEvent : SRCEVT_FOREGROUND,
|
||||
/**
|
||||
* The nsIUpdate object being used by this window (either for downloading,
|
||||
* notification or both).
|
||||
*/
|
||||
update: null,
|
||||
|
||||
/**
|
||||
* The updates.properties <stringbundle> element.
|
||||
*/
|
||||
strings: null,
|
||||
|
||||
/**
|
||||
* The Application brandShortName (e.g. "Firefox")
|
||||
*/
|
||||
brandName: null,
|
||||
|
||||
/**
|
||||
* The <wizard> element
|
||||
*/
|
||||
wiz: null,
|
||||
|
||||
/**
|
||||
* A hash of |pageid| attribute to page object. Can be used to dispatch
|
||||
* function calls to the appropriate page.
|
||||
*/
|
||||
_pages : { },
|
||||
_pages: { },
|
||||
|
||||
/**
|
||||
* Called when the user presses the "Finish" button on the wizard, dispatches
|
||||
|
@ -144,6 +162,12 @@ var gUpdates = {
|
|||
*/
|
||||
sourceEvent: SRCEVT_FOREGROUND,
|
||||
|
||||
/**
|
||||
* The global error message - the reason the update failed. This is human
|
||||
* readable text, used to initialize the error page.
|
||||
*/
|
||||
errorMessage: "",
|
||||
|
||||
/**
|
||||
* Called when the wizard UI is loaded.
|
||||
*/
|
||||
|
@ -178,7 +202,8 @@ var gUpdates = {
|
|||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Initialize Logging preferences, formatted like so:
|
||||
* app.update.log.<moduleName> = <true|false>
|
||||
*/
|
||||
_initLoggingPrefs: function() {
|
||||
try {
|
||||
|
@ -203,7 +228,9 @@ var gUpdates = {
|
|||
*
|
||||
* U'Prompt Method: Arg0: Update State: Src Event:
|
||||
* showUpdateAvailable nsIUpdate obj -- background
|
||||
* showUpdateComplete nsIUpdate obj pending background
|
||||
* showUpdateDownloaded nsIUpdate obj pending background
|
||||
* showUpdateInstalled nsIUpdate obj succeeded either
|
||||
* showUpdateError nsIUpdate obj failed either
|
||||
* checkForUpdates null -- foreground
|
||||
*/
|
||||
get startPage() {
|
||||
|
@ -214,10 +241,18 @@ var gUpdates = {
|
|||
// user that the background checking found an update that requires
|
||||
// their permission to install, and it's ready for download.
|
||||
this.update = arg0;
|
||||
this.sourceEvent = SRCEVT_BACKGROUND;
|
||||
if (this.update.selectedPatch &&
|
||||
this.update.selectedPatch.state == STATE_PENDING)
|
||||
return document.getElementById("finishedBackground");
|
||||
var p = this.update.selectedPatch;
|
||||
if (p) {
|
||||
switch (p.state) {
|
||||
case STATE_PENDING:
|
||||
this.sourceEvent = SRCEVT_BACKGROUND;
|
||||
return document.getElementById("finishedBackground");
|
||||
case STATE_SUCCEEDED:
|
||||
return document.getElementById("installed");
|
||||
case STATE_FAILED:
|
||||
return document.getElementById("errors");
|
||||
}
|
||||
}
|
||||
return document.getElementById("updatesfound");
|
||||
}
|
||||
}
|
||||
|
@ -233,57 +268,6 @@ var gUpdates = {
|
|||
return document.getElementById("checking");
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the errors page.
|
||||
* @param reason
|
||||
* A text message explaining what the error was
|
||||
*/
|
||||
advanceToErrorPage: function(reason) {
|
||||
var errorReason = document.getElementById("errorReason");
|
||||
errorReason.value = reason;
|
||||
var errorLink = document.getElementById("errorLink");
|
||||
var pref = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch2);
|
||||
var manualURL = pref.getComplexValue(PREF_UPDATE_MANUAL_URL,
|
||||
Components.interfaces.nsIPrefLocalizedString);
|
||||
errorLink.href = manualURL.data;
|
||||
var errorLinkLabel = document.getElementById("errorLinkLabel");
|
||||
errorLinkLabel.value = manualURL.data;
|
||||
|
||||
var pageTitle = this.strings.getString("errorsPageHeader");
|
||||
|
||||
var errorPage = document.getElementById("errors");
|
||||
errorPage.setAttribute("label", pageTitle);
|
||||
gUpdates.wiz.currentPage = document.getElementById("errors");
|
||||
gUpdates.wiz.setAttribute("label", pageTitle);
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a network error message.
|
||||
* @param code
|
||||
* An error code to look up in the properties file, either
|
||||
* a Necko error code or a HTTP response code
|
||||
* @param defaultCode
|
||||
* The error code to fall back to if the specified code has no error
|
||||
* text associated with it in the properties file.
|
||||
*/
|
||||
advanceToErrorPageWithCode: function(code, defaultCode) {
|
||||
var sbs =
|
||||
Components.classes["@mozilla.org/intl/stringbundle;1"].
|
||||
getService(Components.interfaces.nsIStringBundleService);
|
||||
var updateBundle = sbs.createBundle(URI_UPDATES_PROPERTIES);
|
||||
var reason = updateBundle.GetStringFromName("checker_error-" + defaultCode);
|
||||
try {
|
||||
reason = updateBundle.GetStringFromName("checker_error-" + code);
|
||||
LOG("General", "Transfer Error: " + reason + ", code: " + code);
|
||||
}
|
||||
catch (e) {
|
||||
// Use the default reason
|
||||
LOG("General", "Transfer Error: " + reason + ", code: " + defaultCode);
|
||||
}
|
||||
this.advanceToErrorPage(reason);
|
||||
},
|
||||
|
||||
/**
|
||||
* Registers a timer to nag the user about something relating to update
|
||||
* @param timerID
|
||||
|
@ -347,6 +331,10 @@ var gUpdates = {
|
|||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* The "Checking for Updates" page. Provides feedback on the update checking
|
||||
* process.
|
||||
*/
|
||||
var gCheckingPage = {
|
||||
/**
|
||||
* The nsIUpdateChecker that is currently checking for updates. We hold onto
|
||||
|
@ -377,6 +365,10 @@ var gCheckingPage = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* An object implementing nsIUpdateCheckListener that is notified as the
|
||||
* update check commences.
|
||||
*/
|
||||
updateListener: {
|
||||
/**
|
||||
* See nsIUpdateCheckListener
|
||||
|
@ -407,21 +399,12 @@ var gCheckingPage = {
|
|||
/**
|
||||
* See nsIUpdateCheckListener
|
||||
*/
|
||||
onError: function(request) {
|
||||
onError: function(request, update) {
|
||||
LOG("UI:CheckingPage", "UpdateCheckListener: error");
|
||||
|
||||
try {
|
||||
var status = request.status;
|
||||
}
|
||||
catch (e) {
|
||||
var req = request.channel.QueryInterface(Components.interfaces.nsIRequest);
|
||||
status = req.status;
|
||||
}
|
||||
gUpdates.update = update;
|
||||
|
||||
// If we can't find an error string specific to this status code,
|
||||
// just use the 200 message from above, which means everything
|
||||
// "looks" fine but there was probably an XML error or a bogus file.
|
||||
gUpdates.advanceToErrorPageWithCode(status, 200);
|
||||
gUpdates.wiz.currentPage = document.getElementById("errors");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -436,7 +419,13 @@ var gCheckingPage = {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The "No Updates Are Available" page
|
||||
*/
|
||||
var gNoUpdatesPage = {
|
||||
/**
|
||||
* Initialize
|
||||
*/
|
||||
onPageShow: function() {
|
||||
gUpdates.wiz.getButton("back").disabled = true;
|
||||
gUpdates.wiz.getButton("cancel").disabled = true;
|
||||
|
@ -444,6 +433,11 @@ var gNoUpdatesPage = {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The "Updates Are Available" page. Provides the user information about the
|
||||
* available update, extensions it might make incompatible, and a means to
|
||||
* continue downloading and installing it.
|
||||
*/
|
||||
var gUpdatesAvailablePage = {
|
||||
/**
|
||||
* An array of installed addons incompatible with this update.
|
||||
|
@ -539,8 +533,20 @@ var gUpdatesAvailablePage = {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The page which shows the user a license associated with an update. The
|
||||
* user must agree to the terms of the license before continuing to install
|
||||
* the update.
|
||||
*/
|
||||
var gLicensePage = {
|
||||
/**
|
||||
* The <license> element
|
||||
*/
|
||||
_licenseContent: null,
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
*/
|
||||
onPageShow: function() {
|
||||
this._licenseContent = document.getElementById("licenseContent");
|
||||
|
||||
|
@ -559,11 +565,20 @@ var gLicensePage = {
|
|||
gUpdates.wiz._wizardButtons.removeAttribute("type");
|
||||
},
|
||||
|
||||
/**
|
||||
* When the license document has loaded
|
||||
*/
|
||||
onLicenseLoad: function() {
|
||||
// Now that the license text is available, the user is in a position to
|
||||
// agree to it, so enable the Agree button.
|
||||
gUpdates.wiz.getButton("next").disabled = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* When the user cancels the wizard
|
||||
*/
|
||||
onWizardCancel: function() {
|
||||
// If the license was downloading, stop it.
|
||||
this._licenseContent.stopDownloading();
|
||||
|
||||
// The user said "Do Not Agree", so stop all update checks for this session
|
||||
|
@ -587,17 +602,24 @@ function DownloadStatusFormatter() {
|
|||
|
||||
var us = gUpdates.strings;
|
||||
this._statusFormat = us.getString("statusFormat");
|
||||
this._statusFormatKBMB = us.getString("statusFormatKBMB");
|
||||
this._statusFormatKBKB = us.getString("statusFormatKBKB");
|
||||
this._statusFormatMBMB = us.getString("statusFormatMBMB");
|
||||
this._statusFormatUnknownMB = us.getString("statusFormatUnknownMB");
|
||||
this._statusFormatUnknownKB = us.getString("statusFormatUnknownKB");
|
||||
|
||||
this._progressFormat = us.getString("progressFormat");
|
||||
this._progressFormatKBMB = us.getString("progressFormatKBMB");
|
||||
this._progressFormatKBKB = us.getString("progressFormatKBKB");
|
||||
this._progressFormatMBMB = us.getString("progressFormatMBMB");
|
||||
this._progressFormatUnknownMB = us.getString("progressFormatUnknownMB");
|
||||
this._progressFormatUnknownKB = us.getString("progressFormatUnknownKB");
|
||||
|
||||
this._rateFormat = us.getString("rateFormat");
|
||||
this._rateFormatKBSec = us.getString("rateFormatKBSec");
|
||||
this._rateFormatMBSec = us.getString("rateFormatMBSec");
|
||||
this._remain = us.getString("remain");
|
||||
this._unknownFilesize = us.getString("unknownFilesize");
|
||||
|
||||
this._timeFormat = us.getString("timeFormat");
|
||||
this._longTimeFormat = us.getString("longTimeFormat");
|
||||
this._shortTimeFormat = us.getString("shortTimeFormat");
|
||||
|
||||
this._remain = us.getString("remain");
|
||||
this._unknownFilesize = us.getString("unknownFilesize");
|
||||
}
|
||||
DownloadStatusFormatter.prototype = {
|
||||
/**
|
||||
|
@ -620,6 +642,11 @@ DownloadStatusFormatter.prototype = {
|
|||
*/
|
||||
_rateFormatted: "",
|
||||
|
||||
/**
|
||||
* Transfer rate, formatted into text container
|
||||
*/
|
||||
_rateFormattedContainer: "",
|
||||
|
||||
/**
|
||||
* Number of Kilobytes downloaded so far in the form:
|
||||
* 376KB of 9.3MB
|
||||
|
@ -643,6 +670,9 @@ DownloadStatusFormatter.prototype = {
|
|||
var total = parseInt(finalSize/1024 + 0.5);
|
||||
this.progress = this._formatKBytes(parseInt(currSize/1024 + 0.5), total);
|
||||
|
||||
var progress = this._replaceInsert(this._progressFormat, 1, this.progress);
|
||||
var rateFormatted = "";
|
||||
|
||||
// 2) Determine the Transfer Rate
|
||||
var oldElapsed = this._elapsed;
|
||||
this._elapsed = now - this._startTime;
|
||||
|
@ -656,26 +686,38 @@ DownloadStatusFormatter.prototype = {
|
|||
if (this._rate > 100)
|
||||
this._rate = Math.round(this._rate);
|
||||
|
||||
if (this._rate == 0)
|
||||
this._rateFormatted = "??.?";
|
||||
else {
|
||||
if (this._rate) {
|
||||
var format = isKB ? this._rateFormatKBSec : this._rateFormatMBSec;
|
||||
this._rateFormatted = this._replaceInsert(format, 1, this._rate);
|
||||
this._rateFormattedContainer = this._replaceInsert(" " + this._rateFormat, 1, this._rateFormatted);
|
||||
}
|
||||
}
|
||||
progress = this._replaceInsert(progress, 2, this._rateFormattedContainer);
|
||||
|
||||
|
||||
// 3) Determine the Time Remaining
|
||||
var remainingTime = this._unknownFileSize;
|
||||
var remainingTime = "";
|
||||
if (this._rate && (finalSize > 0)) {
|
||||
remainingTime = Math.floor(((finalSize - currSize) / 1024) / this._rate);
|
||||
remainingTime = this._formatSeconds(remainingTime);
|
||||
remainingTime = this._replaceInsert(this._timeFormat, 1, remainingTime)
|
||||
remainingTime = this._replaceInsert(remainingTime, 2, this._remain);
|
||||
}
|
||||
|
||||
//
|
||||
// [statusFormat:
|
||||
// [progressFormat:
|
||||
// [[progressFormatKBKB|
|
||||
// progressFormatKBMB|
|
||||
// progressFormatMBMB|
|
||||
// progressFormatUnknownKB|
|
||||
// progressFormatUnknownMB
|
||||
// ][rateFormat]]
|
||||
// ][timeFormat]
|
||||
// ]
|
||||
var status = this._statusFormat;
|
||||
status = this._replaceInsert(status, 1, this.progress);
|
||||
status = this._replaceInsert(status, 2, this._rateFormatted);
|
||||
status = this._replaceInsert(status, 3, remainingTime);
|
||||
status = this._replaceInsert(status, 4, this._remain);
|
||||
status = this._replaceInsert(status, 1, progress);
|
||||
status = this._replaceInsert(status, 2, remainingTime);
|
||||
return status;
|
||||
},
|
||||
|
||||
|
@ -709,33 +751,33 @@ DownloadStatusFormatter.prototype = {
|
|||
* x, < 1MB y >= 1MB x KB of y MB
|
||||
* x, >= 1MB y >= 1MB x of y MB
|
||||
*/
|
||||
_formatKBytes: function(currentKB, totalKB) {
|
||||
_formatKBytes: function(currentKB, totalKB) {
|
||||
var progressHasMB = parseInt(currentKB / 1024) > 0;
|
||||
var totalHasMB = parseInt(totalKB / 1024) > 0;
|
||||
|
||||
var format = "";
|
||||
if (!progressHasMB && !totalHasMB) {
|
||||
if (!totalKB) {
|
||||
format = this._statusFormatUnknownKB;
|
||||
format = this._progressFormatUnknownKB;
|
||||
format = this._replaceInsert(format, 1, currentKB);
|
||||
} else {
|
||||
format = this._statusFormatKBKB;
|
||||
format = this._progressFormatKBKB;
|
||||
format = this._replaceInsert(format, 1, currentKB);
|
||||
format = this._replaceInsert(format, 2, totalKB);
|
||||
}
|
||||
}
|
||||
else if (progressHasMB && totalHasMB) {
|
||||
format = this._statusFormatMBMB;
|
||||
format = this._progressFormatMBMB;
|
||||
format = this._replaceInsert(format, 1, (currentKB / 1024).toFixed(1));
|
||||
format = this._replaceInsert(format, 2, (totalKB / 1024).toFixed(1));
|
||||
}
|
||||
else if (totalHasMB && !progressHasMB) {
|
||||
format = this._statusFormatKBMB;
|
||||
format = this._progressFormatKBMB;
|
||||
format = this._replaceInsert(format, 1, currentKB);
|
||||
format = this._replaceInsert(format, 2, (totalKB / 1024).toFixed(1));
|
||||
}
|
||||
else if (progressHasMB && !totalHasMB) {
|
||||
format = this._statusFormatUnknownMB;
|
||||
format = this._progressFormatUnknownMB;
|
||||
format = this._replaceInsert(format, 1, (currentKB / 1024).toFixed(1));
|
||||
}
|
||||
return format;
|
||||
|
@ -772,6 +814,10 @@ DownloadStatusFormatter.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The "Update is Downloading" page - provides feedback for the download
|
||||
* process plus a pause/resume UI
|
||||
*/
|
||||
var gDownloadingPage = {
|
||||
/**
|
||||
* DOM Elements
|
||||
|
@ -786,9 +832,14 @@ var gDownloadingPage = {
|
|||
* An instance of the status formatter object
|
||||
*/
|
||||
_statusFormatter : null,
|
||||
get statusFormatter() {
|
||||
if (!this._statusFormatter)
|
||||
this._statusFormatter = new DownloadStatusFormatter();
|
||||
return this._statusFormatter;
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Initialize
|
||||
*/
|
||||
onPageShow: function() {
|
||||
gUpdates.wiz._wizardButtons.removeAttribute("type");
|
||||
|
@ -843,7 +894,7 @@ var gDownloadingPage = {
|
|||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Updates the text status message
|
||||
*/
|
||||
_setStatus: function(status) {
|
||||
while (this._downloadStatus.hasChildNodes())
|
||||
|
@ -851,9 +902,24 @@ var gDownloadingPage = {
|
|||
this._downloadStatus.appendChild(document.createTextNode(status));
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether or not we are currently paused
|
||||
*/
|
||||
_paused : false,
|
||||
|
||||
/**
|
||||
* The status before we were paused
|
||||
*/
|
||||
_oldStatus : null,
|
||||
|
||||
/**
|
||||
* The mode of the <progressmeter> before we were paused
|
||||
*/
|
||||
_oldMode : null,
|
||||
|
||||
/**
|
||||
* The progress through the download before we were paused
|
||||
*/
|
||||
_oldProgress : 0,
|
||||
|
||||
/**
|
||||
|
@ -887,7 +953,7 @@ var gDownloadingPage = {
|
|||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* When the user clicks the Pause/Resume button
|
||||
*/
|
||||
onPause: function() {
|
||||
var updates =
|
||||
|
@ -900,7 +966,7 @@ var gDownloadingPage = {
|
|||
patch.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
|
||||
patch.setProperty("status",
|
||||
gUpdates.strings.getFormattedString("pausedStatus",
|
||||
[this._statusFormatter.progress]));
|
||||
[this.statusFormatter.progress]));
|
||||
updates.pauseDownload();
|
||||
}
|
||||
this._paused = !this._paused;
|
||||
|
@ -910,7 +976,7 @@ var gDownloadingPage = {
|
|||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* When the user closes the Wizard UI
|
||||
*/
|
||||
onWizardCancel: function() {
|
||||
// Remove ourself as a download listener so that we don't continue to be
|
||||
|
@ -950,19 +1016,29 @@ var gDownloadingPage = {
|
|||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* When the data transfer begins
|
||||
* @param request
|
||||
* The nsIRequest object for the transfer
|
||||
* @param context
|
||||
* Additional data
|
||||
*/
|
||||
onStartRequest: function(request, context) {
|
||||
request.QueryInterface(nsIIncrementalDownload);
|
||||
LOG("UI:DownloadingPage", "onStartRequest: " + request.URI.spec);
|
||||
|
||||
this._statusFormatter = new DownloadStatusFormatter();
|
||||
|
||||
this._downloadThrobber.setAttribute("state", "loading");
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* When new data has been downloaded
|
||||
* @param request
|
||||
* The nsIRequest object for the transfer
|
||||
* @param context
|
||||
* Additional data
|
||||
* @param progress
|
||||
* The current number of bytes transferred
|
||||
* @param maxProgress
|
||||
* The total number of bytes that must be transferred
|
||||
*/
|
||||
onProgress: function(request, context, progress, maxProgress) {
|
||||
request.QueryInterface(nsIIncrementalDownload);
|
||||
|
@ -973,7 +1049,7 @@ var gDownloadingPage = {
|
|||
p.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
|
||||
p.setProperty("progress", Math.round(100 * (progress/maxProgress)));
|
||||
p.setProperty("status",
|
||||
this._statusFormatter.formatStatus(progress, maxProgress));
|
||||
this.statusFormatter.formatStatus(progress, maxProgress));
|
||||
|
||||
this._downloadProgress.mode = "normal";
|
||||
this._downloadProgress.value = parseInt(p.getProperty("progress"));
|
||||
|
@ -984,16 +1060,31 @@ var gDownloadingPage = {
|
|||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* When we have new status text
|
||||
* @param request
|
||||
* The nsIRequest object for the transfer
|
||||
* @param context
|
||||
* Additional data
|
||||
* @param status
|
||||
* A status code
|
||||
* @param statusText
|
||||
* Human readable version of |status|
|
||||
*/
|
||||
onStatus: function(request, context, status, statusText) {
|
||||
request.QueryInterface(nsIIncrementalDownload);
|
||||
LOG("UI:DownloadingPage", "onStatus: " + request.URI.spec + " status = " +
|
||||
status + ", text = " + statusText);
|
||||
this._setStatus(statusText);
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* When data transfer ceases
|
||||
* @param request
|
||||
* The nsIRequest object for the transfer
|
||||
* @param context
|
||||
* Additional data
|
||||
* @param status
|
||||
* Status code containing the reason for the cessation.
|
||||
*/
|
||||
onStopRequest: function(request, context, status) {
|
||||
request.QueryInterface(nsIIncrementalDownload);
|
||||
|
@ -1002,14 +1093,16 @@ var gDownloadingPage = {
|
|||
|
||||
this._downloadThrobber.removeAttribute("state");
|
||||
|
||||
var u = gUpdates.update;
|
||||
const NS_BINDING_ABORTED = 0x804b0002;
|
||||
switch (status) {
|
||||
case Components.results.NS_ERROR_UNEXPECTED:
|
||||
LOG("UI:DownloadingPage", "STATE = " + gUpdates.update.selectedPatch.state);
|
||||
if (gUpdates.update.selectedPatch.state == STATE_FAILED)
|
||||
this.showVerificationError();
|
||||
if (u.selectedPatch.state == STATE_FAILED && u.isCompleteUpdate) {
|
||||
// Verification error of complete patch, informational text is held in
|
||||
// the update object.
|
||||
gUpdates.wiz.currentPage = document.getElementById("errors");
|
||||
}
|
||||
else {
|
||||
LOG("UI:DownloadingPage", "TYPE = " + gUpdates.update.selectedPatch.type);
|
||||
// Verification failed for a partial patch, complete patch is now
|
||||
// downloading so return early and do NOT remove the download listener!
|
||||
|
||||
|
@ -1017,6 +1110,11 @@ var gDownloadingPage = {
|
|||
// show old progress for the new download of the "complete" patch.
|
||||
this._downloadProgress.mode = "undetermined";
|
||||
this._pauseButton.disabled = true;
|
||||
|
||||
var verificationFailed = document.getElementById("verificationFailed");
|
||||
verificationFailed.hidden = false;
|
||||
|
||||
this._statusFormatter = null;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
@ -1032,7 +1130,7 @@ var gDownloadingPage = {
|
|||
default:
|
||||
LOG("UI:DownloadingPage", "onStopRequest: Transfer failed");
|
||||
// Some kind of transfer error, die.
|
||||
gUpdates.advanceToErrorPageWithCode(status, 2152398849);
|
||||
gUpdates.wiz.currentPage = document.getElementById("errors");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1042,16 +1140,6 @@ var gDownloadingPage = {
|
|||
updates.removeDownloadListener(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Advance the wizard to the "Verification Error" page
|
||||
*/
|
||||
showVerificationError: function() {
|
||||
var verificationError = gUpdates.strings.getFormattedString(
|
||||
"verificationError", [gUpdates.brandName]);
|
||||
var downloadingPage = document.getElementById("downloading");
|
||||
gUpdates.advanceToErrorPage(verificationError);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsISupports.idl
|
||||
*/
|
||||
|
@ -1064,14 +1152,35 @@ var gDownloadingPage = {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The "There was an error during the update" page.
|
||||
*/
|
||||
var gErrorsPage = {
|
||||
/**
|
||||
* Initialize
|
||||
*/
|
||||
onPageShow: function() {
|
||||
gUpdates.wiz.getButton("back").disabled = true;
|
||||
gUpdates.wiz.getButton("cancel").disabled = true;
|
||||
gUpdates.wiz.getButton("finish").focus();
|
||||
}
|
||||
|
||||
var errorReason = document.getElementById("errorReason");
|
||||
errorReason.value = gUpdates.update.statusText;
|
||||
var errorLink = document.getElementById("errorLink");
|
||||
var pref = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch2);
|
||||
var manualURL = pref.getComplexValue(PREF_UPDATE_MANUAL_URL,
|
||||
Components.interfaces.nsIPrefLocalizedString);
|
||||
errorLink.href = manualURL.data;
|
||||
var errorLinkLabel = document.getElementById("errorLinkLabel");
|
||||
errorLinkLabel.value = manualURL.data;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* The "Update has been downloaded" page. Shows information about what
|
||||
* was downloaded.
|
||||
*/
|
||||
var gFinishedPage = {
|
||||
/**
|
||||
* Called to initialize the Wizard Page.
|
||||
|
@ -1177,6 +1286,18 @@ var gFinishedPage = {
|
|||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* The "Update was Installed Successfully" page.
|
||||
*/
|
||||
var gInstalledPage = {
|
||||
/**
|
||||
* Initialize
|
||||
*/
|
||||
onPageShow: function() {
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Called as the application shuts down due to being quit from the File->Quit
|
||||
* menu item.
|
||||
|
|
|
@ -321,5 +321,59 @@
|
|||
</method>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
<binding id="update" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
|
||||
<content>
|
||||
<xul:hbox>
|
||||
<xul:label class="update-name" xbl:inherits="value=name" flex="1" crop="right"/>
|
||||
<xul:link xbl:inherits="href=detailsURL" class="update-details-link">
|
||||
<xul:label>&update.details.label;</xul:label>
|
||||
</xul:link>
|
||||
</xul:hbox>
|
||||
<xul:label class="update-type" xbl:inherits="value=type"/>
|
||||
<xul:grid>
|
||||
<xul:columns>
|
||||
<xul:column class="update-label-column"/>
|
||||
<xul:column flex="1"/>
|
||||
</xul:columns>
|
||||
<xul:rows>
|
||||
<xul:row>
|
||||
<xul:label class="update-installedOn-label">&update.installedOn.label;</xul:label>
|
||||
<xul:label class="update-installedOn-value" xbl:inherits="value=installDate" flex="1" crop="right"/>
|
||||
</xul:row>
|
||||
<xul:row>
|
||||
<xul:label class="update-status-label">&update.status.label;</xul:label>
|
||||
<xul:description class="update-status-value" flex="1"/>
|
||||
</xul:row>
|
||||
</xul:rows>
|
||||
</xul:grid>
|
||||
</content>
|
||||
<implementation>
|
||||
<property name="name"
|
||||
onget="return this.getAttribute('name');"
|
||||
onset="this.setAttribute('name', val); return val;"/>
|
||||
<property name="detailsURL"
|
||||
onget="return this.getAttribute('detailsURL');"
|
||||
onset="this.setAttribute('detailsURL', val); return val;"/>
|
||||
<property name="installDate"
|
||||
onget="return this.getAttribute('installDate');"
|
||||
onset="this.setAttribute('installDate', val); return val;"/>
|
||||
<property name="type"
|
||||
onget="return this.getAttribute('type');"
|
||||
onset="this.setAttribute('type', val); return val;"/>
|
||||
<property name="status"
|
||||
onget="return this.getAttribute('status');">
|
||||
<setter><![CDATA[
|
||||
this.setAttribute("status", val);
|
||||
var field = document.getAnonymousElementByAttribute(this, "class", "update-status-value");
|
||||
while (field.hasChildNodes())
|
||||
field.removeChild(field.firstChild);
|
||||
field.appendChild(document.createTextNode(val));
|
||||
return val;
|
||||
]]></setter>
|
||||
</property>
|
||||
onset="this.setAttribute('status', val); return val;"/>
|
||||
</implementation>
|
||||
</binding>
|
||||
</bindings>
|
||||
|
||||
|
|
|
@ -147,7 +147,12 @@
|
|||
<image id="downloadThrobber"/>
|
||||
<description id="downloadStatus" flex="1">&connecting.label;</description>
|
||||
<button id="pauseButton" oncommand="gDownloadingPage.onPause();"
|
||||
label="&pause.label;" accesskey="&pause.accesskey;"/>
|
||||
disabled="true" label="&pause.label;" accesskey="&pause.accesskey;"/>
|
||||
</hbox>
|
||||
<separator/>
|
||||
<hbox id="verificationFailed" align="start" hidden="true">
|
||||
<image id="verificationFailedIcon"/>
|
||||
<description flex="1">&verificationFailedText.label;</description>
|
||||
</hbox>
|
||||
</wizardpage>
|
||||
|
||||
|
@ -190,4 +195,10 @@
|
|||
<label>&finishedBackground.instruction2;</label>
|
||||
</wizardpage>
|
||||
|
||||
<wizardpage id="installed" pageid="installed"
|
||||
label="&installed.title;" object="gInstalledPage"
|
||||
onpageshow="gInstalledPage.onPageShow();">
|
||||
<label>&installed.intro;</label>
|
||||
</wizardpage>
|
||||
|
||||
</wizard>
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
interface nsIDOMDocument;
|
||||
interface nsIDOMElement;
|
||||
interface nsIDOMWindow;
|
||||
interface nsIRequest;
|
||||
interface nsIRequestObserver;
|
||||
interface nsISimpleEnumerator;
|
||||
|
@ -141,7 +142,12 @@ interface nsIUpdate : nsISupports
|
|||
attribute long long installDate;
|
||||
|
||||
/**
|
||||
*
|
||||
* A message associated with this update, if any.
|
||||
*/
|
||||
attribute AString statusText;
|
||||
|
||||
/**
|
||||
* The currently selected patch for this update.
|
||||
*/
|
||||
readonly attribute nsIUpdatePatch selectedPatch;
|
||||
|
||||
|
@ -198,8 +204,12 @@ interface nsIUpdateCheckListener : nsISupports
|
|||
* An error occurred while loading the remote update service file.
|
||||
* @param request
|
||||
* The nsIXMLHttpRequest handling the update check.
|
||||
* @param update
|
||||
* A nsIUpdate object that contains details about the
|
||||
* error in its |statusText| property.
|
||||
*/
|
||||
void onError(in nsIXMLHttpRequest request);
|
||||
void onError(in nsIXMLHttpRequest request,
|
||||
in nsIUpdate update);
|
||||
};
|
||||
|
||||
[scriptable, uuid(22b00276-ec23-4034-a764-395da539b4be)]
|
||||
|
@ -208,30 +218,55 @@ interface nsIUpdatePrompt : nsISupports
|
|||
/**
|
||||
* Shows a user interface that checks for and then displays the available
|
||||
* updates.
|
||||
* @param parent
|
||||
* A parent window to anchor this window to. Can be null.
|
||||
*/
|
||||
void checkForUpdates();
|
||||
void checkForUpdates(in nsIDOMWindow parent);
|
||||
|
||||
/**
|
||||
* Show a message advising that an update is available for download and
|
||||
* install.
|
||||
* @param parent
|
||||
* A parent window to anchor this window to. Can be null.
|
||||
* @param update
|
||||
* The update to be downloaded and installed
|
||||
*/
|
||||
void showUpdateAvailable(in nsIUpdate update);
|
||||
void showUpdateAvailable(in nsIDOMWindow parent,
|
||||
in nsIUpdate update);
|
||||
|
||||
/**
|
||||
* Show a message advising that an update has now been downloaded and that
|
||||
* the user should restart their software should be restarted so that the
|
||||
* update can be installed.
|
||||
* @param parent
|
||||
* A parent window to anchor this window to. Can be null.
|
||||
* @param update
|
||||
* The update that was downloaded
|
||||
*/
|
||||
void showUpdateComplete(in nsIUpdate update);
|
||||
void showUpdateDownloaded(in nsIDOMWindow parent,
|
||||
in nsIUpdate update);
|
||||
|
||||
/**
|
||||
* Shows a message detailing the update which was installed.
|
||||
* @param update
|
||||
* The nsIUpdate object which was just installed
|
||||
*/
|
||||
void showUpdateInstalled(in nsIUpdate update);
|
||||
|
||||
/**
|
||||
* Shows an error message UI telling the user about some kind of update
|
||||
* failure, e.g. failure to apply patch.
|
||||
* @param update
|
||||
* The nsIUpdate object which we could not install
|
||||
*/
|
||||
void showUpdateError(in nsIUpdate update);
|
||||
|
||||
/**
|
||||
* Shows a list of all updates installed to date.
|
||||
* @param parent
|
||||
* A parent window to anchor this window to. Can be null.
|
||||
*/
|
||||
void showUpdateHistory();
|
||||
void showUpdateHistory(in nsIDOMWindow parent);
|
||||
};
|
||||
|
||||
[scriptable, uuid(877ace25-8bc5-452a-8586-9c1cf2871994)]
|
||||
|
|
|
@ -80,6 +80,7 @@ const MODE_TRUNCATE = 0x20;
|
|||
const PERMS_FILE = 0644;
|
||||
const PERMS_DIRECTORY = 0755;
|
||||
|
||||
const STATE_NONE = null;
|
||||
const STATE_DOWNLOADING = "downloading";
|
||||
const STATE_PENDING = "pending";
|
||||
const STATE_APPLYING = "applying";
|
||||
|
@ -240,6 +241,90 @@ function closeSafeOutputStream(fos) {
|
|||
fos.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns human readable status text from the updates.propreties bundle
|
||||
* based on an error code
|
||||
* @param code
|
||||
* The error code to look up human readable status text for
|
||||
* @param defaultCode
|
||||
* The default code to look up should human readable status text
|
||||
* not exist for |code|
|
||||
* @returns A human readable status text string
|
||||
*/
|
||||
function getStatusTextFromCode(code, defaultCode) {
|
||||
var sbs =
|
||||
Components.classes["@mozilla.org/intl/stringbundle;1"].
|
||||
getService(Components.interfaces.nsIStringBundleService);
|
||||
var updateBundle = sbs.createBundle(URI_UPDATES_PROPERTIES);
|
||||
var reason = updateBundle.GetStringFromName("checker_error-" + defaultCode);
|
||||
try {
|
||||
reason = updateBundle.GetStringFromName("checker_error-" + code);
|
||||
LOG("General", "Transfer Error: " + reason + ", code: " + code);
|
||||
}
|
||||
catch (e) {
|
||||
// Use the default reason
|
||||
LOG("General", "Transfer Error: " + reason + ", code: " + defaultCode);
|
||||
}
|
||||
return reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Active Updates directory
|
||||
* @returns The active updates directory, as a nsIFile object
|
||||
*/
|
||||
function getUpdatesDir() {
|
||||
// Right now, we only support downloading one patch at a time, so we always
|
||||
// use the same target directory.
|
||||
var fileLocator =
|
||||
Components.classes["@mozilla.org/file/directory_service;1"].
|
||||
getService(Components.interfaces.nsIProperties);
|
||||
var appDir = fileLocator.get(KEY_APPDIR, Components.interfaces.nsIFile);
|
||||
appDir.append(DIR_UPDATES);
|
||||
appDir.append("0");
|
||||
if (!appDir.exists())
|
||||
appDir.create(nsILocalFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
|
||||
return appDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the update state from the update.status file in the specified
|
||||
* directory.
|
||||
* @param dir
|
||||
* The dir to look for an update.status file in
|
||||
* @returns The status value of the update.
|
||||
*/
|
||||
function readStatusFile(dir) {
|
||||
var statusFile = dir.clone();
|
||||
statusFile.append(FILE_UPDATE_STATUS);
|
||||
LOG("General", "Reading Status File: " + statusFile.path);
|
||||
return readStringFromFile(statusFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the Updates Directory
|
||||
*/
|
||||
function cleanUpUpdatesDir() {
|
||||
var updateDir = getUpdatesDir();
|
||||
|
||||
var e = updateDir.directoryEntries;
|
||||
while (e.hasMoreElements()) {
|
||||
var f = e.getNext().QueryInterface(Components.interfaces.nsIFile);
|
||||
try {
|
||||
f.remove(false);
|
||||
}
|
||||
catch (e) {
|
||||
LOG("General", "Failed to remove file: " + f.path);
|
||||
}
|
||||
}
|
||||
try {
|
||||
updateDir.remove(false);
|
||||
} catch (e) {
|
||||
LOG("General", "Failed to remove update directory: " + updateDir.path +
|
||||
" - This is almost always bad. Exception = " + e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An enumeration of items in a JS array.
|
||||
* @constructor
|
||||
|
@ -321,7 +406,10 @@ function readStringFromFile(file) {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* An object which can prompt the user with information about updates, request
|
||||
* action, etc. Embedding clients can override this component with one that
|
||||
* invokes a native front end.
|
||||
* @constructor
|
||||
*/
|
||||
function UpdatePrompt() {
|
||||
}
|
||||
|
@ -329,31 +417,59 @@ UpdatePrompt.prototype = {
|
|||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
checkForUpdates: function() {
|
||||
this._showUI(URI_UPDATE_PROMPT_DIALOG, "Update:Wizard", null);
|
||||
checkForUpdates: function(parent) {
|
||||
this._showUI(parent, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard", null);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
showUpdateAvailable: function(update) {
|
||||
this._showUI(URI_UPDATE_PROMPT_DIALOG, "Update:Wizard", update);
|
||||
showUpdateAvailable: function(parent, update) {
|
||||
this._showUI(parent, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard", update);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
showUpdateComplete: function(update) {
|
||||
this._showUI(URI_UPDATE_PROMPT_DIALOG, "Update:Wizard", update);
|
||||
showUpdateDownloaded: function(parent, update) {
|
||||
this._showUI(parent, URI_UPDATE_PROMPT_DIALOG, null, "Update:Wizard", update);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
showUpdateInstalled: function(update) {
|
||||
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, "modal", "Update:Wizard", update);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
showUpdateError: function(update) {
|
||||
this._showUI(null, URI_UPDATE_PROMPT_DIALOG, "modal", "Update:Wizard", update);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
showUpdateHistory: function(parent) {
|
||||
this._showUI(parent, URI_UPDATE_HISTORY_DIALOG, "modal", "Update:History", null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Show the Update Checking UI
|
||||
* @param parent
|
||||
* A parent window, can be null
|
||||
* @param uri
|
||||
* The URI string of the dialog to show
|
||||
* @param name
|
||||
* The Window Name of the dialog to show, in case it is already open
|
||||
* and can merely be focused
|
||||
* @param update
|
||||
* An update to pass to the UI in the window arguments.
|
||||
* Can be null.
|
||||
* Can be null
|
||||
*/
|
||||
_showUI: function(uri, name, update) {
|
||||
_showUI: function(parent, uri, features, name, update) {
|
||||
var ary = null;
|
||||
if (update) {
|
||||
ary = Components.classes["@mozilla.org/supports-array;1"]
|
||||
|
@ -367,20 +483,15 @@ UpdatePrompt.prototype = {
|
|||
if (win)
|
||||
win.focus();
|
||||
else {
|
||||
var openFeatures = "chrome,centerscreen,dialog";
|
||||
if (features)
|
||||
openFeatures += "," + features;
|
||||
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
||||
.getService(Components.interfaces.nsIWindowWatcher);
|
||||
ww.openWindow(null, uri,
|
||||
"", "chrome,centerscreen,dialog,titlebar,dependent", ary);
|
||||
ww.openWindow(parent, uri, "", openFeatures, ary);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
showUpdateHistory: function() {
|
||||
this._showUI(URI_UPDATE_HISTORY_DIALOG, "Update:History", null);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsISupports.idl
|
||||
*/
|
||||
|
@ -414,6 +525,43 @@ function UpdateService() {
|
|||
// Observe xpcom-shutdown to unhook pref branch observers above to avoid
|
||||
// shutdown leaks.
|
||||
gOS.addObserver(this, "xpcom-shutdown", false);
|
||||
/*
|
||||
// Detect installation failures and notify
|
||||
var status = readStatusFile(getUpdatesDir());
|
||||
if (status != null) {
|
||||
// null status means the update.status file is not present, because either:
|
||||
// 1) no update was performed, and so there's no UI to show
|
||||
// 2) an update was attempted but failed during checking, transfer or
|
||||
// verification, and was cleaned up at that point, and UI notifying of
|
||||
// that error was shown at that stage.
|
||||
var um =
|
||||
Components.classes["@mozilla.org/updates/update-manager;1"].
|
||||
getService(Components.interfaces.nsIUpdateManager);
|
||||
var prompter =
|
||||
Components.classes["@mozilla.org/updates/update-prompt;1"].
|
||||
createInstance(Components.interfaces.nsIUpdatePrompt);
|
||||
|
||||
var update = um.activeUpdate;
|
||||
if (!update)
|
||||
update = new Update(null);
|
||||
if (status == STATE_SUCCEEDED) {
|
||||
update.statusText = "Install Succeeded";
|
||||
//prompter.showUpdateInstalled(update);
|
||||
}
|
||||
else {
|
||||
// Something went wrong with the patch application process.
|
||||
update.statusText = "goats";
|
||||
// XXXben todo: synthesize the best message
|
||||
//prompter.showUpdateError(update);
|
||||
}*/
|
||||
|
||||
// Move the update from the Active Update list into the Past Updates list.
|
||||
um.activeUpdate = null;
|
||||
um.saveUpdates();
|
||||
|
||||
// Now trash the updates directory, since we're done with it
|
||||
cleanUpUpdatesDir();
|
||||
}
|
||||
|
||||
this._initLoggingPrefs();
|
||||
}
|
||||
|
@ -450,7 +598,8 @@ UpdateService.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Initialize Logging preferences, formatted like so:
|
||||
* app.update.log.<moduleName> = <true|false>
|
||||
*/
|
||||
_initLoggingPrefs: function() {
|
||||
try {
|
||||
|
@ -514,8 +663,8 @@ UpdateService.prototype = {
|
|||
/**
|
||||
* See nsIUpdateService.idl
|
||||
*/
|
||||
onError: function(request) {
|
||||
LOG("Checker", "Error during background update");
|
||||
onError: function(request, update) {
|
||||
LOG("Checker", "Error during background update: " + update.statusText);
|
||||
},
|
||||
}
|
||||
this.backgroundChecker.checkForUpdates(listener, false);
|
||||
|
@ -1014,6 +1163,13 @@ UpdatePatch.prototype = {
|
|||
*/
|
||||
function Update(update) {
|
||||
this._patches = [];
|
||||
this.installDate = 0;
|
||||
this.isCompleteUpdate = false;
|
||||
|
||||
// Null <update>, assume this is a message container and do no
|
||||
// further initialization
|
||||
if (!update)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < update.childNodes.length; ++i) {
|
||||
var patchElement = update.childNodes.item(i);
|
||||
|
@ -1025,13 +1181,21 @@ function Update(update) {
|
|||
this._patches.push(new UpdatePatch(patchElement));
|
||||
}
|
||||
|
||||
this.type = update.getAttribute("type");
|
||||
this.version = update.getAttribute("version");
|
||||
this.extensionVersion = update.getAttribute("extensionVersion");
|
||||
this.detailsURL = update.getAttribute("detailsURL");
|
||||
this.licenseURL = update.getAttribute("licenseURL");
|
||||
this.installDate = update.hasAttribute("installDate") ? parseInt(update.getAttribute("installDate")) : 0;
|
||||
this.isCompleteUpdate = false;
|
||||
for (var i = 0; i < update.attributes.length; ++i) {
|
||||
var attr = update.attributes[i];
|
||||
switch (attr.name) {
|
||||
case "installDate":
|
||||
if (attr.value)
|
||||
this.installDate = parseInt(attr.value);
|
||||
break;
|
||||
case "isCompleteUpdate":
|
||||
this.isCompleteUpdate = attr.value == "true";
|
||||
break;
|
||||
default:
|
||||
this[attr.name] = attr.value;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
// The Update Name is either the string provided by the <update> element, or
|
||||
// the string: "<App Name> <Update App Version>"
|
||||
|
@ -1047,7 +1211,6 @@ function Update(update) {
|
|||
name = updateBundle.formatStringFromName("updateName",
|
||||
[appName, this.version], 2);
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
}
|
||||
Update.prototype = {
|
||||
|
@ -1085,19 +1248,70 @@ Update.prototype = {
|
|||
update.setAttribute("detailsURL", this.detailsURL);
|
||||
update.setAttribute("licenseURL", this.licenseURL);
|
||||
update.setAttribute("installDate", this.installDate);
|
||||
update.setAttribute("statusText", this.statusText);
|
||||
update.setAttribute("isCompleteUpdate", this.isCompleteUpdate);
|
||||
updates.documentElement.appendChild(update);
|
||||
|
||||
for (var p in this._properties) {
|
||||
if (this._properties[p].present)
|
||||
patch.setAttribute(p, this._properties[p].data);
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.patchCount; ++i)
|
||||
update.appendChild(this.getPatchAt(i).serialize(updates));
|
||||
|
||||
return update;
|
||||
},
|
||||
|
||||
/**
|
||||
* A hash of custom properties
|
||||
*/
|
||||
_properties: { },
|
||||
|
||||
/**
|
||||
* See nsIWritablePropertyBag.idl
|
||||
*/
|
||||
setProperty: function(name, value) {
|
||||
this._properties[name] = { data: value, present: true };
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIWritablePropertyBag.idl
|
||||
*/
|
||||
deleteProperty: function(name) {
|
||||
if (name in this._properties)
|
||||
this._properties[name].present = false;
|
||||
else
|
||||
throw Components.results.NS_ERROR_FAILURE;
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIPropertyBag.idl
|
||||
*/
|
||||
get enumerator() {
|
||||
var properties = [];
|
||||
for (var p in this._properties)
|
||||
properties.push(this._properties[p].data);
|
||||
return new ArrayEnumerator(properties);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIPropertyBag.idl
|
||||
*/
|
||||
getProperty: function(name) {
|
||||
if (name in this._properties &&
|
||||
this._properties[name].present)
|
||||
return this._properties[name].data;
|
||||
throw Components.results.NS_ERROR_FAILURE;
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsISupports.idl
|
||||
*/
|
||||
QueryInterface: function(iid) {
|
||||
if (!iid.equals(Components.interfaces.nsIUpdate) &&
|
||||
!iid.equals(Components.interfaces.nsIPropertyBag) &&
|
||||
!iid.equals(Components.interfaces.nsIWritablePropertyBag) &&
|
||||
!iid.equals(Components.interfaces.nsISupports))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
return this;
|
||||
|
@ -1106,6 +1320,8 @@ Update.prototype = {
|
|||
|
||||
/**
|
||||
* Checker
|
||||
* Checks for new Updates
|
||||
* @constructor
|
||||
*/
|
||||
function Checker() {
|
||||
}
|
||||
|
@ -1116,15 +1332,10 @@ Checker.prototype = {
|
|||
_request : null,
|
||||
|
||||
/**
|
||||
*
|
||||
* The nsIUpdateCheckListener callback
|
||||
*/
|
||||
_callback : null,
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
observer : null,
|
||||
|
||||
/**
|
||||
* The URL of the update service XML file to connect to that contains details
|
||||
* about available updates.
|
||||
|
@ -1190,7 +1401,9 @@ Checker.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* When progress associated with the XMLHttpRequest is received.
|
||||
* @param event
|
||||
* The nsIDOMLSProgressEvent for the load.
|
||||
*/
|
||||
onProgress: function(event) {
|
||||
LOG("Checker", "onProgress: " + event.position + "/" + event.totalSize);
|
||||
|
@ -1198,7 +1411,7 @@ Checker.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* Returns an array of nsIUpdate objects discovered by the update check.
|
||||
*/
|
||||
get _updates() {
|
||||
var updatesElement = this._request.responseXML.documentElement;
|
||||
|
@ -1227,15 +1440,13 @@ Checker.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* The XMLHttpRequest succeeded and the document was loaded.
|
||||
* @param event
|
||||
* The nsIDOMLSEvent for the load
|
||||
*/
|
||||
onLoad: function(event) {
|
||||
LOG("Checker", "onLoad: request completed downloading document");
|
||||
|
||||
// Notify the front end that we're complete
|
||||
if (this.observer)
|
||||
this.observer.onLoad(event.target);
|
||||
|
||||
// Analyze the resulting DOM and determine the set of updates to install
|
||||
try {
|
||||
var updates = this._updates;
|
||||
|
@ -1248,17 +1459,36 @@ Checker.prototype = {
|
|||
catch (e) {
|
||||
LOG("Checker", "There was a problem with the update service URL specified, " +
|
||||
"either the XML file was malformed or it does not exist at the location " +
|
||||
"specified");
|
||||
this._callback.onError(event.target);
|
||||
"specified. Exception: " + e);
|
||||
var update = new Update(null);
|
||||
update.statusText = getStatusTextFromCode(404, 404);
|
||||
this._callback.onError(event.target, update);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* There was an error of some kind during the XMLHttpRequest
|
||||
* @param event
|
||||
* The nsIDOMLSEvent for the load
|
||||
*/
|
||||
onError: function(event) {
|
||||
LOG("Checker", "onError: error during load");
|
||||
this._callback.onError(event.target);
|
||||
|
||||
var request = event.target;
|
||||
try {
|
||||
var status = request.status;
|
||||
}
|
||||
catch (e) {
|
||||
var req = request.channel.QueryInterface(Components.interfaces.nsIRequest);
|
||||
status = req.status;
|
||||
}
|
||||
|
||||
// If we can't find an error string specific to this status code,
|
||||
// just use the 200 message from above, which means everything
|
||||
// "looks" fine but there was probably an XML error or a bogus file.
|
||||
var update = new Update(null);
|
||||
update.statusText = getStatusTextFromCode(status, 200);
|
||||
this._callback.onError(request, update);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1350,23 +1580,6 @@ Downloader.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieves the active Updates directory, as a nsIFile object.
|
||||
*/
|
||||
get _updatesDir() {
|
||||
// Right now, we only support downloading one patch at a time, so we always
|
||||
// use the same target directory.
|
||||
var fileLocator =
|
||||
Components.classes["@mozilla.org/file/directory_service;1"].
|
||||
getService(Components.interfaces.nsIProperties);
|
||||
var appDir = fileLocator.get(KEY_APPDIR, Components.interfaces.nsIFile);
|
||||
appDir.append(DIR_UPDATES);
|
||||
appDir.append("0");
|
||||
if (!appDir.exists())
|
||||
appDir.create(nsILocalFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
|
||||
return appDir;
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes the current update operation/state to a file in the patch
|
||||
* directory, indicating to the patching system that operations need
|
||||
|
@ -1383,21 +1596,11 @@ Downloader.prototype = {
|
|||
writeStringToFile(statusFile, state);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reads the current update state...
|
||||
*/
|
||||
_readStatusFile: function(dir) {
|
||||
var statusFile = dir.clone();
|
||||
statusFile.append(FILE_UPDATE_STATUS);
|
||||
LOG("Downloader", "Reading Status File: " + statusFile.path);
|
||||
return readStringFromFile(statusFile);
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether or not a patch has been downloaded and staged for installation.
|
||||
*/
|
||||
get patchIsStaged() {
|
||||
return this._readStatusFile(this._updatesDir) == STATE_PENDING;
|
||||
return readStatusFile(getUpdatesDir()) == STATE_PENDING;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1417,7 +1620,7 @@ Downloader.prototype = {
|
|||
createInstance(nsICryptoHash);
|
||||
var hashFunction = nsICryptoHash[this._patch.hashFunction.toUpperCase()];
|
||||
if (hashFunction == undefined)
|
||||
return false;
|
||||
throw Components.results.NS_ERROR_UNEXPECTED;
|
||||
hash.init(hashFunction);
|
||||
hash.updateFromStream(fileStream, -1);
|
||||
// NOTE: For now, we assume that the format of _patch.hashValue is hex
|
||||
|
@ -1468,7 +1671,7 @@ Downloader.prototype = {
|
|||
// to select ourselves.
|
||||
var selectedPatch = update.selectedPatch;
|
||||
|
||||
var state = this._readStatusFile(updateDir)
|
||||
var state = readStatusFile(updateDir)
|
||||
|
||||
// If this is a patch that we know about, then select it. If it is a patch
|
||||
// that we do not know about, then remove it and use our default logic.
|
||||
|
@ -1484,6 +1687,7 @@ Downloader.prototype = {
|
|||
return null;
|
||||
case STATE_FAILED:
|
||||
case STATE_APPLYING:
|
||||
case STATE_NONE:
|
||||
// Something went wrong when we tried to apply the previous patch.
|
||||
// Try the complete patch next time.
|
||||
if (update && selectedPatch.type == "partial") {
|
||||
|
@ -1509,31 +1713,8 @@ Downloader.prototype = {
|
|||
selectedPatch = getPatchOfType("complete");
|
||||
}
|
||||
|
||||
// The patch is no longer known to us, so we should assume that it is
|
||||
// no longer valid. Remove all from the updateDir.
|
||||
// XXX We may want to preserve an update.log file from a failed update.
|
||||
// We expect this operation may fail since some files
|
||||
// (e.g., updater.exe) may still be in use. That's ok.
|
||||
|
||||
var e = updateDir.directoryEntries;
|
||||
while (e.hasMoreElements()) {
|
||||
var f = e.getNext().QueryInterface(Components.interfaces.nsIFile);
|
||||
try {
|
||||
f.remove(false);
|
||||
}
|
||||
catch (e) {
|
||||
LOG("Downloader", "Failed to remove file: " + f.path);
|
||||
}
|
||||
}
|
||||
try {
|
||||
updateDir.remove(false);
|
||||
} catch (e) {
|
||||
LOG("Downloader", "Failed to remove update directory: " + updateDir.path +
|
||||
" - This is almost always bad. Exception = " + e);
|
||||
throw e;
|
||||
}
|
||||
// Restore the updateDir since we may have deleted it.
|
||||
updateDir = this._updatesDir;
|
||||
updateDir = getUpdatesDir();
|
||||
|
||||
selectedPatch.selected = true;
|
||||
update.isCompleteUpdate = useComplete;
|
||||
|
@ -1563,7 +1744,7 @@ Downloader.prototype = {
|
|||
if (!update)
|
||||
throw Components.results.NS_ERROR_NULL_POINTER;
|
||||
|
||||
var updateDir = this._updatesDir;
|
||||
var updateDir = getUpdatesDir();
|
||||
|
||||
this._update = update;
|
||||
|
||||
|
@ -1572,7 +1753,7 @@ Downloader.prototype = {
|
|||
this._patch = this._selectPatch(update, updateDir);
|
||||
if (!this._patch) {
|
||||
LOG("Downloader", "no patch to download");
|
||||
return this._readStatusFile(updateDir);
|
||||
return readStatusFile(updateDir);
|
||||
}
|
||||
this.isCompleteUpdate = this._patch.type == "complete";
|
||||
|
||||
|
@ -1682,6 +1863,8 @@ Downloader.prototype = {
|
|||
|
||||
var state;
|
||||
var shouldShowPrompt = false;
|
||||
var deleteActiveUpdate = false;
|
||||
const NS_BINDING_ABORTED = 0x804b0002;
|
||||
if (Components.isSuccessCode(status)) {
|
||||
if (this._verifyDownload()) {
|
||||
state = STATE_PENDING;
|
||||
|
@ -1691,21 +1874,64 @@ Downloader.prototype = {
|
|||
// that UI will notify.
|
||||
if (this.background)
|
||||
shouldShowPrompt = true;
|
||||
|
||||
// Tell the updater.exe we're ready to apply.
|
||||
this._writeStatusFile(getUpdatesDir(), state);
|
||||
this._update.installDate = (new Date()).getTime();
|
||||
this._update.statusText = "Install Pending";
|
||||
} else {
|
||||
LOG("Downloader", "onStopRequest: download verification failed");
|
||||
state = STATE_FAILED;
|
||||
|
||||
var sbs =
|
||||
Components.classes["@mozilla.org/intl/stringbundle;1"].
|
||||
getService(Components.interfaces.nsIStringBundleService);
|
||||
var updateStrings = sbs.createBundle(URI_UPDATES_PROPERTIES);
|
||||
var brandStrings = sbs.createBundle(URI_BRAND_PROPERTIES);
|
||||
var brandShortName = brandStrings.GetStringFromName("brandShortName");
|
||||
this._update.statusText = updateStrings.
|
||||
formatStringFromName("verificationError", [brandShortName], 1);
|
||||
|
||||
// TODO: use more informative error code here
|
||||
status = Components.results.NS_ERROR_UNEXPECTED;
|
||||
|
||||
var message = getStatusTextFromCode("verification_failed",
|
||||
"verification_failed");
|
||||
this._update.statusText = message;
|
||||
|
||||
if (this._update.isCompleteUpdate)
|
||||
deleteActiveUpdate = true;
|
||||
|
||||
// Destroy the updates directory, since we're done with it.
|
||||
cleanUpUpdatesDir();
|
||||
}
|
||||
this._writeStatusFile(this._updatesDir, state);
|
||||
this._patch.QueryInterface(Components.interfaces.nsIWritablePropertyBag);
|
||||
this._patch.state = state;
|
||||
this._update.installDate = (new Date()).getTime();
|
||||
var um = Components.classes["@mozilla.org/updates/update-manager;1"]
|
||||
.getService(Components.interfaces.nsIUpdateManager);
|
||||
um.activeUpdate = null;
|
||||
um.saveUpdates();
|
||||
}
|
||||
else if (status != NS_BINDING_ABORTED) {
|
||||
LOG("Downloader", "onStopRequest: Non-verification failure");
|
||||
// Some sort of other failure, log this in the |statusText| property
|
||||
state = STATE_FAILED;
|
||||
|
||||
// XXXben - if |request| (The Incremental Download) provided a means
|
||||
// for accessing the http channel we could do more here.
|
||||
|
||||
const NS_BINDING_FAILED = 2152398849;
|
||||
this._update.statusText = getStatusTextFromCode(status,
|
||||
NS_BINDING_FAILED);
|
||||
|
||||
// Destroy the updates directory, since we're done with it.
|
||||
cleanUpUpdatesDir();
|
||||
|
||||
deleteActiveUpdate = true;
|
||||
}
|
||||
this._patch.state = state;
|
||||
var um =
|
||||
Components.classes["@mozilla.org/updates/update-manager;1"].
|
||||
getService(Components.interfaces.nsIUpdateManager);
|
||||
if (deleteActiveUpdate) {
|
||||
this._update.installDate = (new Date()).getTime();
|
||||
um.activeUpdate = null;
|
||||
}
|
||||
um.saveUpdates();
|
||||
|
||||
var listenerCount = this._listeners.length;
|
||||
for (var i = 0; i < listenerCount; ++i)
|
||||
|
@ -1732,7 +1958,7 @@ Downloader.prototype = {
|
|||
var prompter =
|
||||
Components.classes["@mozilla.org/updates/update-prompt;1"].
|
||||
createInstance(Components.interfaces.nsIUpdatePrompt);
|
||||
prompter.showUpdateComplete(this._update);
|
||||
prompter.showUpdateDownloaded(this._update);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче