Bug 593535 - Failure to download extension causes about:addons to list the addon with no way to restart the download; frontend; f=dtownsend r=dtownsend,robert.bugzilla a=blocking2.0

This commit is contained in:
Blair McBride 2011-01-10 15:58:10 +13:00
parent 4e731ec33a
commit f69ece5d30
9 changed files with 304 additions and 46 deletions

View File

@ -36,11 +36,11 @@ notification.install=%1$S will be installed after you restart %2$S.
notification.uninstall=%1$S will be uninstalled after you restart %2$S.
#LOCALIZATION NOTE (notification.upgrade) %1$S is the add-on name, %2$S is brand name
notification.upgrade=%1$S will be updated after you restart %2$S.
#LOCALIZATION NOTE (notification.downloadError) %1$S is the add-on name. Not yet implemented - see https://bug593535.bugzilla.mozilla.org/attachment.cgi?id=475403
#LOCALIZATION NOTE (notification.downloadError) %1$S is the add-on name.
notification.downloadError=There was an error downloading %1$S.
notification.downloadError.retry=Try again
notification.downloadError.retry.tooltip=Try downloading this add-on again
#LOCALIZATION NOTE (notification.installError) %1$S is the add-on name. Not yet implemented - see https://bug593535.bugzilla.mozilla.org/attachment.cgi?id=475403
#LOCALIZATION NOTE (notification.installError) %1$S is the add-on name.
notification.installError=There was an error installing %1$S.
notification.installError.retry=Try again
notification.installError.retry.tooltip=Try downloading and installing this add-on again

View File

@ -60,6 +60,7 @@ xhtml|link {
}
.addon[status="installing"] {
-moz-box-orient: vertical;
-moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#addon-installing");
}

View File

@ -531,10 +531,6 @@
class="addon-control install" label="&addon.install.label;"
tooltiptext="&addon.install.tooltip;"
oncommand="document.getBindingParent(this).installRemote();"/>
<xul:button anonid="restart-install-btn" hidden="true"
class="addon-control install" label="&addon.install.label;"
tooltiptext="&addon.install.tooltip;"
oncommand="document.getBindingParent(this).restartInstall();"/>
</content>
<implementation>
@ -570,10 +566,6 @@
document.getAnonymousElementByAttribute(this, "anonid",
"restart-needed");
</field>
<field name="_restartInstall">
document.getAnonymousElementByAttribute(this, "anonid",
"restart-install-btn");
</field>
<field name="_undo">
document.getAnonymousElementByAttribute(this, "anonid",
"undo-btn");
@ -595,7 +587,6 @@
<method name="refreshState">
<body><![CDATA[
var showInstallRemote = false;
var showRestartInstall = false;
var showPurchase = false;
if (this.mInstall) {
@ -630,7 +621,6 @@
break;
case AddonManager.STATE_CANCELLED:
this.showMessage("installCancelled", true);
showRestartInstall = true;
break;
}
@ -646,7 +636,9 @@
this._purchaseRemote.hidden = !showPurchase;
this._installRemote.hidden = !showInstallRemote;
this._restartInstall.hidden = !showRestartInstall;
if ("refreshInfo" in this.mControl)
this.mControl.refreshInfo();
]]></body>
</method>
@ -694,12 +686,6 @@
]]></body>
</method>
<method name="restartInstall">
<body><![CDATA[
this.mInstall.install();
]]></body>
</method>
<method name="undoAction">
<body><![CDATA[
if (!this.mAddon)
@ -808,6 +794,7 @@
<xul:image class="warning-icon"/>
<xul:label anonid="warning" flex="1"/>
<xul:label anonid="warning-link" class="text-link"/>
<xul:button anonid="warning-btn" class="button-link"/>
<xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap -->
</xul:hbox>
<xul:hbox anonid="error-container" align="center"
@ -960,6 +947,10 @@
document.getAnonymousElementByAttribute(this, "anonid",
"warning-link");
</field>
<field name="_warningBtn">
document.getAnonymousElementByAttribute(this, "anonid",
"warning-btn");
</field>
<field name="_errorContainer">
document.getAnonymousElementByAttribute(this, "anonid",
"error-container");
@ -1199,8 +1190,31 @@
this.removeAttribute("pending");
var isUpgrade = this.hasAttribute("upgrade");
var install = this._installStatus.mInstall;
if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) {
if (install && install.state == AddonManager.STATE_DOWNLOAD_FAILED) {
this.setAttribute("notification", "warning");
this._warning.textContent = gStrings.ext.formatStringFromName(
"notification.downloadError",
[this.mAddon.name], 1
);
this._warningBtn.label = gStrings.ext.GetStringFromName("notification.downloadError.retry");
this._warningBtn.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip");
this._warningBtn.setAttribute("oncommand", "document.getBindingParent(this).retryInstall();");
this._warningBtn.hidden = false;
this._warningLink.hidden = true;
} else if (install && install.state == AddonManager.STATE_INSTALL_FAILED) {
this.setAttribute("notification", "warning");
this._warning.textContent = gStrings.ext.formatStringFromName(
"notification.installError",
[this.mAddon.name], 1
);
this._warningBtn.label = gStrings.ext.GetStringFromName("notification.installError.retry");
this._warningBtn.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip");
this._warningBtn.setAttribute("oncommand", "document.getBindingParent(this).retryInstall();");
this._warningBtn.hidden = false;
this._warningLink.hidden = true;
} else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) {
this.setAttribute("notification", "error");
this._error.textContent = gStrings.ext.formatStringFromName(
"notification.blocked",
@ -1216,6 +1230,7 @@
[this.mAddon.name, gStrings.brandShortName, gStrings.appVersion], 3
);
this._warningLink.hidden = true;
this._warningBtn.hidden = true;
} else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) {
this.setAttribute("notification", "warning");
this._warning.textContent = gStrings.ext.formatStringFromName(
@ -1225,6 +1240,7 @@
this._warningLink.value = gStrings.ext.GetStringFromName("notification.softblocked.link");
this._warningLink.href = Services.urlFormatter.formatURLPref("extensions.blocklist.detailsURL");
this._warningLink.hidden = false;
this._warningBtn.hidden = true;
} else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) {
this.setAttribute("notification", "warning");
this._warning.textContent = gStrings.ext.formatStringFromName(
@ -1234,6 +1250,7 @@
this._warningLink.value = gStrings.ext.GetStringFromName("notification.outdated.link");
this._warningLink.href = Services.urlFormatter.formatURLPref("plugins.update.url");
this._warningLink.hidden = false;
this._warningBtn.hidden = true;
} else {
this.removeAttribute("notification");
}
@ -1445,6 +1462,18 @@
]]></body>
</method>
<method name="retryInstall">
<body><![CDATA[
var install = this._installStatus.mInstall;
if (!install)
return;
if (install.state != AddonManager.STATE_DOWNLOAD_FAILED &&
install.state != AddonManager.STATE_INSTALL_FAILED)
return;
install.install();
]]></body>
</method>
<method name="showInDetailView">
<body><![CDATA[
gViewController.loadView("addons://detail/" +
@ -1550,6 +1579,7 @@
<method name="onDownloadStarted">
<parameter name="aInstall"/>
<body><![CDATA[
this._updateState();
this._showStatus("progress");
this._installStatus.initWithInstall(aInstall);
]]></body>
@ -1558,6 +1588,7 @@
<method name="onInstallStarted">
<parameter name="aInstall"/>
<body><![CDATA[
this._updateState();
this._showStatus("progress");
this._installStatus.initWithInstall(aInstall);
]]></body>
@ -1575,6 +1606,24 @@
this._updateState();
]]></body>
</method>
<method name="onDownloadFailed">
<body><![CDATA[
this._updateState();
]]></body>
</method>
<method name="onInstallFailed">
<body><![CDATA[
this._updateState();
]]></body>
</method>
<method name="onInstallCancelled">
<body><![CDATA[
this._updateState();
]]></body>
</method>
</implementation>
<handlers>
@ -1698,14 +1747,30 @@
<binding id="addon-installing"
extends="chrome://mozapps/content/extensions/extensions.xml#addon-base">
<content>
<xul:vbox pack="center">
<xul:vbox align="center" pack="center" class="icon-container">
<xul:image anonid="icon" class="icon"/>
<xul:hbox anonid="warning-container" align="center"
class="warning">
<xul:image class="warning-icon"/>
<xul:label anonid="warning" flex="1"/>
<xul:button anonid="warning-link" class="button-link"
oncommand="document.getBindingParent(this).retryInstall();"/>
<xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap -->
</xul:hbox>
<xul:hbox align="stretch">
<xul:vbox pack="start">
<xul:vbox align="center" pack="center" class="icon-container">
<xul:image anonid="icon" class="icon"/>
</xul:vbox>
</xul:vbox>
</xul:vbox>
<xul:label anonid="name" class="name"/>
<xul:spacer flex="1"/>
<xul:hbox anonid="install-status" class="install-status"/>
<xul:vbox flex="1" class="fade" align="stretch" pack="center">
<xul:hbox class="name-container" align="end">
<xul:label anonid="name" class="name"/>
<xul:label anonid="version" class="version" hidden="true"/>
</xul:hbox>
</xul:vbox>
<xul:vbox align="end" pack="end">
<xul:hbox anonid="install-status" class="install-status"/>
</xul:vbox>
</xul:hbox>
</content>
<implementation>
@ -1721,6 +1786,15 @@
<field name="_name">
document.getAnonymousElementByAttribute(this, "anonid", "name");
</field>
<field name="_version">
document.getAnonymousElementByAttribute(this, "anonid", "version");
</field>
<field name="_warning">
document.getAnonymousElementByAttribute(this, "anonid", "warning");
</field>
<field name="_warningLink">
document.getAnonymousElementByAttribute(this, "anonid", "warning-link");
</field>
<field name="_installStatus">
document.getAnonymousElementByAttribute(this, "anonid",
"install-status");
@ -1742,12 +1816,20 @@
this._icon.src = this.mAddon.iconURL ||
(this.mInstall ? this.mInstall.iconURL : "");
this._name.value = this.mAddon.name;
if (this.mAddon.version) {
this._version.value = this.mAddon.version;
this._version.hidden = false;
} else {
this._version.hidden = true;
}
} else {
this._icon.src = this.mInstall.iconURL;
// AddonInstall.name isn't always available - fallback to filename
if (this.mInstall.name) {
this._name.value = this.mInstall.name;
} else {
} else if (this.mInstall.sourceURI) {
var url = Components.classes["@mozilla.org/network/standard-url;1"]
.createInstance(Components.interfaces.nsIStandardURL);
url.init(url.URLTYPE_STANDARD, 80, this.mInstall.sourceURI.spec,
@ -1755,7 +1837,40 @@
url.QueryInterface(Components.interfaces.nsIURL);
this._name.value = url.fileName;
}
if (this.mInstall.version) {
this._version.value = this.mInstall.version;
this._version.hidden = false;
} else {
this._version.hidden = true;
}
}
if (this.mInstall.state == AddonManager.STATE_DOWNLOAD_FAILED) {
this.setAttribute("notification", "warning");
this._warning.textContent = gStrings.ext.formatStringFromName(
"notification.downloadError",
[this._name.value], 1
);
this._warningLink.label = gStrings.ext.GetStringFromName("notification.downloadError.retry");
this._warningLink.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip");
} else if (this.mInstall.state == AddonManager.STATE_INSTALL_FAILED) {
this.setAttribute("notification", "warning");
this._warning.textContent = gStrings.ext.formatStringFromName(
"notification.installError",
[this._name.value], 1
);
this._warningLink.label = gStrings.ext.GetStringFromName("notification.installError.retry");
this._warningLink.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip");
} else {
this.removeAttribute("notification");
}
]]></body>
</method>
<method name="retryInstall">
<body><![CDATA[
this.mInstall.install();
]]></body>
</method>
</implementation>

View File

@ -60,6 +60,7 @@ _MAIN_TEST_FILES = \
browser_bug587970.js \
browser_bug591465.js \
browser_bug591663.js \
browser_bug593535.js \
browser_bug596336.js \
browser_bug608316.js \
browser_bug610764.js \
@ -93,6 +94,7 @@ _TEST_RESOURCES = \
browser_bug557956_8_2.xpi \
browser_bug557956_9_2.xpi \
browser_bug591465.xml \
browser_bug593535.xml \
browser_searching.xml \
browser_searching_empty.xml \
browser_updatessl.rdf \

View File

@ -0,0 +1,121 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Bug 593535 - Failure to download extension causes about:addons to list the
// addon with no way to restart the download
const PREF_GETADDONS_GETSEARCHRESULTS = "extensions.getAddons.search.url";
const SEARCH_URL = TESTROOT + "browser_bug593535.xml";
const QUERY = "NOTFOUND";
var gProvider;
function test() {
return;
waitForExplicitFinish();
// Turn on searching for this test
Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
open_manager("addons://list/extension", function(aWindow) {
gManagerWindow = aWindow;
run_next_test();
});
}
function end_test() {
close_manager(gManagerWindow, function() {
AddonManager.getAllInstalls(function(aInstallsList) {
for (var i = 0; i < aInstallsList.length; i++) {
var install = aInstallsList[i];
var sourceURI = install.sourceURI.spec;
if (sourceURI.match(/^http:\/\/example\.com\/(.+)\.xpi$/) != null)
install.cancel();
}
finish();
});
});
}
function search(aQuery, aCallback) {
// Point search to the correct xml test file
Services.prefs.setCharPref(PREF_GETADDONS_GETSEARCHRESULTS, SEARCH_URL);
var searchBox = gManagerWindow.document.getElementById("header-search");
searchBox.value = aQuery;
EventUtils.synthesizeMouseAtCenter(searchBox, { }, gManagerWindow);
EventUtils.synthesizeKey("VK_RETURN", { }, gManagerWindow);
wait_for_view_load(gManagerWindow, function() {
var remoteFilter = gManagerWindow.document.getElementById("search-filter-remote");
EventUtils.synthesizeMouseAtCenter(remoteFilter, { }, gManagerWindow);
aCallback();
});
}
function get_addon_item(aName) {
var id = aName + "@tests.mozilla.org";
var list = gManagerWindow.document.getElementById("search-list");
var rows = list.getElementsByTagName("richlistitem");
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
if (row.mAddon && row.mAddon.id == id)
return row;
}
return null;
}
function get_install_button(aItem) {
isnot(aItem, null, "Item should not be null when checking state of install button");
var installStatus = getAnonymousElementByAttribute(aItem, "anonid", "install-status");
return getAnonymousElementByAttribute(installStatus, "anonid", "install-remote-btn");
}
function getAnonymousElementByAttribute(aElement, aName, aValue) {
return gManagerWindow.document.getAnonymousElementByAttribute(aElement,
aName,
aValue);
}
// Tests that a failed install for a remote add-on will ask to retry the install
add_test(function() {
var remoteItem;
var listener = {
onDownloadFailed: function(aInstall) {
aInstall.removeListener(this);
ok(true, "Install failed as expected");
executeSoon(function() {
is(remoteItem.getAttribute("notification"), "warning", "Item should have notification attribute set to 'warning'");
is_element_visible(remoteItem._warning, "Warning text should be visible");
is(remoteItem._warning.textContent, "There was an error downloading NOTFOUND.", "Warning should show correct message");
is_element_visible(remoteItem._warningLink, "Retry button should be visible");
run_next_test();
});
},
onInstallEnded: function() {
ok(false, "Install should have failed");
}
}
search(QUERY, function() {
var list = gManagerWindow.document.getElementById("search-list");
remoteItem = get_addon_item("notfound1");
list.ensureElementIsVisible(remoteItem);
remoteItem.mAddon.install.addListener(listener);
var installBtn = get_install_button(remoteItem);
EventUtils.synthesizeMouseAtCenter(installBtn, { }, gManagerWindow);
});
});

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8" ?>
<searchresults total_results="100">
<addon>
<name>NOTFOUND</name>
<type id='1'>Extension</type>
<guid>notfound1@tests.mozilla.org</guid>
<version>1.0</version>
<authors>
<author>
<name>Test Creator</name>
<link>http://example.com/creator.html</link>
</author>
</authors>
<status id='4'>Public</status>
<summary>Install file not found - NOTFOUND</summary>
<description>Test description</description>
<compatible_applications>
<application>
<name>Firefox</name>
<appID>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</appID>
<min_version>0</min_version>
<max_version>*</max_version>
</application>
<application>
<name>SeaMonkey</name>
<appID>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</appID>
<min_version>0</min_version>
<max_version>*</max_version>
</application>
</compatible_applications>
<compatible_os>ALL</compatible_os>
<install size="1">http://example.com/file_not_found.xpi</install>
</addon>
</searchresults>

View File

@ -406,10 +406,6 @@
padding: 5px;
}
.addon[status="installing"] {
-moz-box-align: center;
}
.addon[selected] .text-link,
.addon[selected] .button-link {
color: inherit;
@ -449,8 +445,7 @@
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
}
.name-container,
.addon[status="installing"] .name {
.name-container {
font-size: 150%;
margin-bottom: 0;
font-weight: bold;

View File

@ -437,10 +437,6 @@
color: #373D48;
}
.addon[status="installing"] {
-moz-box-align: center;
}
.details {
cursor: pointer;
margin: 0;
@ -475,8 +471,7 @@
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
}
.name-container,
.addon[status="installing"] .name {
.name-container {
font-size: 150%;
margin-bottom: 0;
font-weight: bold;

View File

@ -510,10 +510,6 @@
-moz-border-bottom-colors: rgba(0, 0, 0, 0.1) rgba(255, 255, 255, 0.1);
}
.addon[status="installing"] {
-moz-box-align: center;
}
.details {
cursor: pointer;
margin: 0;
@ -549,8 +545,7 @@
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.png");
}
.name-container,
.addon[status="installing"] .name {
.name-container {
font-size: 150%;
font-weight: bold;
color: #3F3F3F;