зеркало из https://github.com/mozilla/gecko-dev.git
Bug 552965 and bug 553455: Display notifications for add-on download failures and prompt the user to restart after installation. r=gavin
This commit is contained in:
Родитель
4df955ab2a
Коммит
2f164a09a3
|
@ -323,6 +323,7 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon {
|
#notification-popup-box[anchorid="geo-notification-icon"] > #geo-notification-icon,
|
||||||
|
#notification-popup-box[anchorid="addons-notification-icon"] > #addons-notification-icon {
|
||||||
display: -moz-box;
|
display: -moz-box;
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,15 @@ __defineGetter__("gPrefService", function() {
|
||||||
return this.gPrefService = Services.prefs;
|
return this.gPrefService = Services.prefs;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
__defineGetter__("AddonManager", function() {
|
||||||
|
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||||
|
return this.AddonManager;
|
||||||
|
});
|
||||||
|
__defineSetter__("AddonManager", function (val) {
|
||||||
|
delete this.AddonManager;
|
||||||
|
return this.AddonManager = val;
|
||||||
|
});
|
||||||
|
|
||||||
__defineGetter__("PluralForm", function() {
|
__defineGetter__("PluralForm", function() {
|
||||||
Cu.import("resource://gre/modules/PluralForm.jsm");
|
Cu.import("resource://gre/modules/PluralForm.jsm");
|
||||||
return this.PluralForm;
|
return this.PluralForm;
|
||||||
|
@ -623,26 +632,35 @@ const gXPInstallObserver = {
|
||||||
observe: function (aSubject, aTopic, aData)
|
observe: function (aSubject, aTopic, aData)
|
||||||
{
|
{
|
||||||
var brandBundle = document.getElementById("bundle_brand");
|
var brandBundle = document.getElementById("bundle_brand");
|
||||||
switch (aTopic) {
|
|
||||||
case "addon-install-blocked":
|
|
||||||
var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
|
var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
|
||||||
var win = installInfo.originatingWindow;
|
var win = installInfo.originatingWindow;
|
||||||
var shell = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
var shell = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||||
.getInterface(Components.interfaces.nsIWebNavigation)
|
.getInterface(Components.interfaces.nsIWebNavigation)
|
||||||
.QueryInterface(Components.interfaces.nsIDocShell);
|
.QueryInterface(Components.interfaces.nsIDocShell);
|
||||||
var browser = this._getBrowser(shell);
|
var browser = this._getBrowser(shell);
|
||||||
if (browser) {
|
if (!browser)
|
||||||
var host = installInfo.originatingURI.host;
|
return;
|
||||||
|
const anchorID = "addons-notification-icon";
|
||||||
|
var messageString, action;
|
||||||
var brandShortName = brandBundle.getString("brandShortName");
|
var brandShortName = brandBundle.getString("brandShortName");
|
||||||
var notificationName, messageString, buttons;
|
var host = installInfo.originatingURI ? installInfo.originatingURI.host : browser.currentURI.host;
|
||||||
|
|
||||||
|
var notificationID = aTopic;
|
||||||
|
|
||||||
|
switch (aTopic) {
|
||||||
|
case "addon-install-blocked":
|
||||||
var enabled = true;
|
var enabled = true;
|
||||||
try {
|
try {
|
||||||
enabled = gPrefService.getBoolPref("xpinstall.enabled");
|
enabled = gPrefService.getBoolPref("xpinstall.enabled");
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
notificationName = "xpinstall-disabled"
|
notificationID = "xpinstall-disabled"
|
||||||
|
if (PopupNotifications.getNotification(notificationID, browser))
|
||||||
|
return;
|
||||||
|
|
||||||
if (gPrefService.prefIsLocked("xpinstall.enabled")) {
|
if (gPrefService.prefIsLocked("xpinstall.enabled")) {
|
||||||
messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked");
|
messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked");
|
||||||
buttons = [];
|
buttons = [];
|
||||||
|
@ -651,41 +669,105 @@ const gXPInstallObserver = {
|
||||||
messageString = gNavigatorBundle.getFormattedString("xpinstallDisabledMessage",
|
messageString = gNavigatorBundle.getFormattedString("xpinstallDisabledMessage",
|
||||||
[brandShortName, host]);
|
[brandShortName, host]);
|
||||||
|
|
||||||
buttons = [{
|
action = {
|
||||||
label: gNavigatorBundle.getString("xpinstallDisabledButton"),
|
label: gNavigatorBundle.getString("xpinstallDisabledButton"),
|
||||||
accessKey: gNavigatorBundle.getString("xpinstallDisabledButton.accesskey"),
|
accessKey: gNavigatorBundle.getString("xpinstallDisabledButton.accesskey"),
|
||||||
popup: null,
|
|
||||||
callback: function editPrefs() {
|
callback: function editPrefs() {
|
||||||
gPrefService.setBoolPref("xpinstall.enabled", true);
|
gPrefService.setBoolPref("xpinstall.enabled", true);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}];
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
notificationName = "xpinstall"
|
if (PopupNotifications.getNotification(notificationID, browser))
|
||||||
|
return;
|
||||||
|
|
||||||
messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
|
messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
|
||||||
[brandShortName, host]);
|
[brandShortName, host]);
|
||||||
|
|
||||||
buttons = [{
|
action = {
|
||||||
label: gNavigatorBundle.getString("xpinstallPromptAllowButton"),
|
label: gNavigatorBundle.getString("xpinstallPromptAllowButton"),
|
||||||
accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"),
|
accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"),
|
||||||
popup: null,
|
|
||||||
callback: function() {
|
callback: function() {
|
||||||
installInfo.install();
|
installInfo.install();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}];
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
var notificationBox = gBrowser.getNotificationBox(browser);
|
PopupNotifications.show(browser, notificationID, messageString, anchorID,
|
||||||
if (!notificationBox.getNotificationWithValue(notificationName)) {
|
action);
|
||||||
const priority = notificationBox.PRIORITY_WARNING_MEDIUM;
|
break;
|
||||||
const iconURL = "chrome://mozapps/skin/update/update.png";
|
case "addon-install-failed":
|
||||||
notificationBox.appendNotification(messageString, notificationName,
|
// TODO This isn't terribly ideal for the multiple failure case
|
||||||
iconURL, priority, buttons);
|
installInfo.installs.forEach(function(aInstall) {
|
||||||
|
var error = "addonError";
|
||||||
|
if (aInstall.error != 0)
|
||||||
|
error += aInstall.error;
|
||||||
|
else if (aInstall.addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
|
||||||
|
error += "Blocklisted";
|
||||||
|
else
|
||||||
|
error += "Incompatible";
|
||||||
|
|
||||||
|
messageString = gNavigatorBundle.getString(error);
|
||||||
|
messageString = messageString.replace("#1", aInstall.name);
|
||||||
|
messageString = messageString.replace("#2", host);
|
||||||
|
messageString = messageString.replace("#3", brandShortName);
|
||||||
|
messageString = messageString.replace("#4", Services.appinfo.version);
|
||||||
|
|
||||||
|
PopupNotifications.show(browser, notificationID, messageString, anchorID,
|
||||||
|
action);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "addon-install-complete":
|
||||||
|
var notification = PopupNotifications.getNotification(notificationID, browser);
|
||||||
|
if (notification)
|
||||||
|
PopupNotifications.remove(notification);
|
||||||
|
|
||||||
|
var needsRestart = installInfo.installs.some(function(i) {
|
||||||
|
return (i.addon.pendingOperations & AddonManager.PENDING_INSTALL) != 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (needsRestart) {
|
||||||
|
messageString = gNavigatorBundle.getString("addonsInstalledNeedsRestart");
|
||||||
|
action = {
|
||||||
|
label: gNavigatorBundle.getString("addonInstallRestartButton"),
|
||||||
|
accessKey: gNavigatorBundle.getString("addonInstallRestartButton.accesskey"),
|
||||||
|
callback: function() {
|
||||||
|
Application.restart();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
messageString = gNavigatorBundle.getString("addonsInstalled");
|
||||||
|
action = {
|
||||||
|
label: gNavigatorBundle.getString("addonInstallManage"),
|
||||||
|
accessKey: gNavigatorBundle.getString("addonInstallManage.accesskey"),
|
||||||
|
callback: function() {
|
||||||
|
// Calculate the add-on type that is most popular in the list of
|
||||||
|
// installs
|
||||||
|
var types = {};
|
||||||
|
var bestType = null;
|
||||||
|
installInfo.installs.forEach(function(aInstall) {
|
||||||
|
if (aInstall.type in types)
|
||||||
|
types[aInstall.type]++;
|
||||||
|
else
|
||||||
|
types[aInstall.type] = 1;
|
||||||
|
if (!bestType || types[aInstall.type] > types[bestType])
|
||||||
|
bestType = aInstall.type;
|
||||||
|
});
|
||||||
|
|
||||||
|
BrowserOpenAddonsMgr("addons://list/" + bestType);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
messageString = PluralForm.get(installInfo.installs.length, messageString);
|
||||||
|
messageString = messageString.replace("#1", installInfo.installs[0].name);
|
||||||
|
messageString = messageString.replace("#2", installInfo.installs.length);
|
||||||
|
messageString = messageString.replace("#3", brandShortName);
|
||||||
|
|
||||||
|
PopupNotifications.show(browser, notificationID, messageString, anchorID,
|
||||||
|
action);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1218,6 +1300,8 @@ function prepareForStartup() {
|
||||||
function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
function delayedStartup(isLoadingBlank, mustLoadSidebar) {
|
||||||
Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
|
Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history", false);
|
||||||
Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
|
Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
|
||||||
|
Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
|
||||||
|
Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
|
||||||
|
|
||||||
BrowserOffline.init();
|
BrowserOffline.init();
|
||||||
OfflineApps.init();
|
OfflineApps.init();
|
||||||
|
@ -1438,6 +1522,8 @@ function BrowserShutdown()
|
||||||
|
|
||||||
Services.obs.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
|
Services.obs.removeObserver(gSessionHistoryObserver, "browser:purge-session-history");
|
||||||
Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked");
|
Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked");
|
||||||
|
Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed");
|
||||||
|
Services.obs.removeObserver(gXPInstallObserver, "addon-install-complete");
|
||||||
Services.obs.removeObserver(gPluginHandler.pluginCrashed, "plugin-crashed");
|
Services.obs.removeObserver(gPluginHandler.pluginCrashed, "plugin-crashed");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -608,6 +608,7 @@
|
||||||
onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
|
onblur="setTimeout(function() document.getElementById('identity-box').style.MozUserFocus = '', 0);">
|
||||||
<box id="notification-popup-box" hidden="true" align="center">
|
<box id="notification-popup-box" hidden="true" align="center">
|
||||||
<image id="geo-notification-icon" class="notification-anchor-icon"/>
|
<image id="geo-notification-icon" class="notification-anchor-icon"/>
|
||||||
|
<image id="addons-notification-icon" class="notification-anchor-icon"/>
|
||||||
</box>
|
</box>
|
||||||
<!-- Use onclick instead of normal popup= syntax since the popup
|
<!-- Use onclick instead of normal popup= syntax since the popup
|
||||||
code fires onmousedown, and hence eats our favicon drag events.
|
code fires onmousedown, and hence eats our favicon drag events.
|
||||||
|
|
|
@ -129,6 +129,7 @@ _BROWSER_FILES = \
|
||||||
browser_bug521216.js \
|
browser_bug521216.js \
|
||||||
browser_bug537474.js \
|
browser_bug537474.js \
|
||||||
browser_bug550565.js \
|
browser_bug550565.js \
|
||||||
|
browser_bug553455.js \
|
||||||
browser_bug555224.js \
|
browser_bug555224.js \
|
||||||
browser_bug555767.js \
|
browser_bug555767.js \
|
||||||
browser_bug556061.js \
|
browser_bug556061.js \
|
||||||
|
|
|
@ -0,0 +1,270 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
*/
|
||||||
|
|
||||||
|
const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
|
||||||
|
const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
|
||||||
|
|
||||||
|
function wait_for_notification(aCallback) {
|
||||||
|
PopupNotifications.panel.addEventListener("popupshown", function() {
|
||||||
|
PopupNotifications.panel.removeEventListener("popupshown", arguments.callee, false);
|
||||||
|
aCallback(PopupNotifications.panel);
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wait_for_install_dialog(aCallback) {
|
||||||
|
Services.wm.addListener({
|
||||||
|
onOpenWindow: function(aXULWindow) {
|
||||||
|
Services.wm.removeListener(this);
|
||||||
|
|
||||||
|
var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindowInternal);
|
||||||
|
domwindow.addEventListener("load", function() {
|
||||||
|
domwindow.removeEventListener("load", arguments.callee, false);
|
||||||
|
|
||||||
|
is(domwindow.document.location.href, XPINSTALL_URL, "Should have seen the right window open");
|
||||||
|
|
||||||
|
// Allow other window load listeners to execute before passing to callback
|
||||||
|
executeSoon(function() {
|
||||||
|
// Override the countdown timer on the accept button
|
||||||
|
var button = domwindow.document.documentElement.getButton("accept");
|
||||||
|
button.disabled = false;
|
||||||
|
|
||||||
|
aCallback(domwindow);
|
||||||
|
});
|
||||||
|
}, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
onCloseWindow: function(aXULWindow) {
|
||||||
|
},
|
||||||
|
|
||||||
|
onWindowTitleChange: function(aXULWindow, aNewTitle) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var TESTS = [
|
||||||
|
function test_blocked_install() {
|
||||||
|
var triggers = encodeURIComponent(JSON.stringify({
|
||||||
|
"XPI": "unsigned.xpi"
|
||||||
|
}));
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||||
|
|
||||||
|
// Wait for the blocked notification
|
||||||
|
wait_for_notification(function(aPanel) {
|
||||||
|
let notification = aPanel.childNodes[0];
|
||||||
|
is(notification.id, "addon-install-blocked", "Should have seen the install blocked");
|
||||||
|
is(notification.button.label, "Allow", "Should have seen the right button");
|
||||||
|
|
||||||
|
// Click on Allow
|
||||||
|
EventUtils.synthesizeMouse(notification.button, 20, 10, {});
|
||||||
|
|
||||||
|
// Wait for the install confirmation dialog
|
||||||
|
wait_for_install_dialog(function(aWindow) {
|
||||||
|
aWindow.document.documentElement.acceptDialog();
|
||||||
|
|
||||||
|
// Wait for the complete notification
|
||||||
|
wait_for_notification(function(aPanel) {
|
||||||
|
let notification = aPanel.childNodes[0];
|
||||||
|
is(notification.id, "addon-install-complete", "Should have seen the install complete");
|
||||||
|
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||||
|
|
||||||
|
AddonManager.getAllInstalls(function(aInstalls) {
|
||||||
|
is(aInstalls.length, 1, "Should be one pending install");
|
||||||
|
aInstalls[0].cancel();
|
||||||
|
|
||||||
|
gBrowser.removeTab(gBrowser.selectedTab);
|
||||||
|
runNextTest();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function test_whitelisted_install() {
|
||||||
|
var pm = Services.perms;
|
||||||
|
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||||
|
|
||||||
|
var triggers = encodeURIComponent(JSON.stringify({
|
||||||
|
"XPI": "unsigned.xpi"
|
||||||
|
}));
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||||
|
|
||||||
|
// Wait for the install confirmation dialog
|
||||||
|
wait_for_install_dialog(function(aWindow) {
|
||||||
|
aWindow.document.documentElement.acceptDialog();
|
||||||
|
|
||||||
|
// Wait for the complete notification
|
||||||
|
wait_for_notification(function(aPanel) {
|
||||||
|
let notification = aPanel.childNodes[0];
|
||||||
|
is(notification.id, "addon-install-complete", "Should have seen the install complete");
|
||||||
|
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||||
|
|
||||||
|
AddonManager.getAllInstalls(function(aInstalls) {
|
||||||
|
is(aInstalls.length, 1, "Should be one pending install");
|
||||||
|
aInstalls[0].cancel();
|
||||||
|
|
||||||
|
gBrowser.removeTab(gBrowser.selectedTab);
|
||||||
|
Services.perms.remove("example.com", "install");
|
||||||
|
runNextTest();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function test_failed_download() {
|
||||||
|
var pm = Services.perms;
|
||||||
|
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||||
|
|
||||||
|
var triggers = encodeURIComponent(JSON.stringify({
|
||||||
|
"XPI": "missing.xpi"
|
||||||
|
}));
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||||
|
|
||||||
|
// Wait for the failed notification
|
||||||
|
wait_for_notification(function(aPanel) {
|
||||||
|
let notification = aPanel.childNodes[0];
|
||||||
|
is(notification.id, "addon-install-failed", "Should have seen the install fail");
|
||||||
|
|
||||||
|
gBrowser.removeTab(gBrowser.selectedTab);
|
||||||
|
Services.perms.remove("example.com", "install");
|
||||||
|
runNextTest();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function test_corrupt_file() {
|
||||||
|
var pm = Services.perms;
|
||||||
|
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||||
|
|
||||||
|
var triggers = encodeURIComponent(JSON.stringify({
|
||||||
|
"XPI": "corrupt.xpi"
|
||||||
|
}));
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||||
|
|
||||||
|
// Wait for the failed notification
|
||||||
|
wait_for_notification(function(aPanel) {
|
||||||
|
let notification = aPanel.childNodes[0];
|
||||||
|
is(notification.id, "addon-install-failed", "Should have seen the install fail");
|
||||||
|
|
||||||
|
gBrowser.removeTab(gBrowser.selectedTab);
|
||||||
|
Services.perms.remove("example.com", "install");
|
||||||
|
runNextTest();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function test_incompatible() {
|
||||||
|
var pm = Services.perms;
|
||||||
|
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||||
|
|
||||||
|
var triggers = encodeURIComponent(JSON.stringify({
|
||||||
|
"XPI": "incompatible.xpi"
|
||||||
|
}));
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||||
|
|
||||||
|
// Wait for the failed notification
|
||||||
|
wait_for_notification(function(aPanel) {
|
||||||
|
let notification = aPanel.childNodes[0];
|
||||||
|
is(notification.id, "addon-install-failed", "Should have seen the install fail");
|
||||||
|
|
||||||
|
gBrowser.removeTab(gBrowser.selectedTab);
|
||||||
|
Services.perms.remove("example.com", "install");
|
||||||
|
runNextTest();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function test_restartless() {
|
||||||
|
var pm = Services.perms;
|
||||||
|
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||||
|
|
||||||
|
var triggers = encodeURIComponent(JSON.stringify({
|
||||||
|
"XPI": "restartless.xpi"
|
||||||
|
}));
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||||
|
|
||||||
|
// Wait for the install confirmation dialog
|
||||||
|
wait_for_install_dialog(function(aWindow) {
|
||||||
|
aWindow.document.documentElement.acceptDialog();
|
||||||
|
|
||||||
|
// Wait for the complete notification
|
||||||
|
wait_for_notification(function(aPanel) {
|
||||||
|
let notification = aPanel.childNodes[0];
|
||||||
|
is(notification.id, "addon-install-complete", "Should have seen the install complete");
|
||||||
|
is(notification.button.label, "Open Add-ons Manager", "Should have seen the right button");
|
||||||
|
|
||||||
|
AddonManager.getAllInstalls(function(aInstalls) {
|
||||||
|
is(aInstalls.length, 0, "Should be no pending installs");
|
||||||
|
|
||||||
|
AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(aAddon) {
|
||||||
|
aAddon.uninstall();
|
||||||
|
|
||||||
|
gBrowser.removeTab(gBrowser.selectedTab);
|
||||||
|
Services.perms.remove("example.com", "install");
|
||||||
|
runNextTest();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
function test_multiple() {
|
||||||
|
var pm = Services.perms;
|
||||||
|
pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
|
||||||
|
|
||||||
|
var triggers = encodeURIComponent(JSON.stringify({
|
||||||
|
"Unsigned XPI": "unsigned.xpi",
|
||||||
|
"Restartless XPI": "restartless.xpi"
|
||||||
|
}));
|
||||||
|
gBrowser.selectedTab = gBrowser.addTab();
|
||||||
|
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
|
||||||
|
|
||||||
|
// Wait for the install confirmation dialog
|
||||||
|
wait_for_install_dialog(function(aWindow) {
|
||||||
|
aWindow.document.documentElement.acceptDialog();
|
||||||
|
|
||||||
|
// Wait for the complete notification
|
||||||
|
wait_for_notification(function(aPanel) {
|
||||||
|
let notification = aPanel.childNodes[0];
|
||||||
|
is(notification.id, "addon-install-complete", "Should have seen the install complete");
|
||||||
|
is(notification.button.label, "Restart Now", "Should have seen the right button");
|
||||||
|
|
||||||
|
AddonManager.getAllInstalls(function(aInstalls) {
|
||||||
|
is(aInstalls.length, 1, "Should be one pending install");
|
||||||
|
aInstalls[0].cancel();
|
||||||
|
|
||||||
|
AddonManager.getAddonByID("restartless-xpi@tests.mozilla.org", function(aAddon) {
|
||||||
|
aAddon.uninstall();
|
||||||
|
|
||||||
|
gBrowser.removeTab(gBrowser.selectedTab);
|
||||||
|
Services.perms.remove("example.com", "install");
|
||||||
|
runNextTest();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
function runNextTest() {
|
||||||
|
AddonManager.getAllInstalls(function(aInstalls) {
|
||||||
|
is(aInstalls.length, 0, "Should be no active installs");
|
||||||
|
|
||||||
|
if (TESTS.length == 0) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TESTS.shift()();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
waitForExplicitFinish();
|
||||||
|
|
||||||
|
runNextTest();
|
||||||
|
}
|
|
@ -35,6 +35,27 @@ xpinstallDisabledMessage=Software installation is currently disabled. Click Enab
|
||||||
xpinstallDisabledButton=Enable
|
xpinstallDisabledButton=Enable
|
||||||
xpinstallDisabledButton.accesskey=n
|
xpinstallDisabledButton.accesskey=n
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (addonsInstalled, addonsInstalledNeedsRestart):
|
||||||
|
# Semi-colon list of plural forms. See:
|
||||||
|
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||||
|
# #1 first add-on's name, #2 number of add-ons, #3 application name
|
||||||
|
addonsInstalled=#1 has been installed successfully.;#2 add-ons have been installed successfully.
|
||||||
|
addonsInstalledNeedsRestart=#1 will be installed after you restart #3.;#2 add-ons will be installed after you restart #3.
|
||||||
|
addonInstallRestartButton=Restart Now
|
||||||
|
addonInstallRestartButton.accesskey=R
|
||||||
|
addonInstallManage=Open Add-ons Manager
|
||||||
|
addonInstallManage.accesskey=O
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (addonError-1, addonError-2, addonError-3, addonError-4, addonErrorIncompatible, addonErrorBlocklisted):
|
||||||
|
# #1 is the add-on name, #2 is the host name, #3 is the application name
|
||||||
|
# #4 is the application version
|
||||||
|
addonError-1=The add-on could not be downloaded because of a connection failure on #2.
|
||||||
|
addonError-2=The add-on from #2 could not be installed because it does not match the add-on #3 expected.
|
||||||
|
addonError-3=The add-on downloaded from #2 could not be installed because it appears to be corrupt.
|
||||||
|
addonError-4=#1 could not be installed because Firefox cannot modify the needed file.
|
||||||
|
addonErrorIncompatible=#1 could not be installed because it is not compatible with #3 #4.
|
||||||
|
addonErrorBlocklisted=#1 could not be installed because it has a high risk of causing stability or security problems.
|
||||||
|
|
||||||
# LOCALIZATION NOTE (lwthemeInstallRequest.message): %S will be replaced with
|
# LOCALIZATION NOTE (lwthemeInstallRequest.message): %S will be replaced with
|
||||||
# the host name of the site.
|
# the host name of the site.
|
||||||
lwthemeInstallRequest.message=This site (%S) attempted to install a theme.
|
lwthemeInstallRequest.message=This site (%S) attempted to install a theme.
|
||||||
|
|
|
@ -988,17 +988,33 @@ toolbar[iconsize="small"] #fullscreen-button {
|
||||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||||
|
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||||
|
.popup-notification-icon[popupid="addon-install-failed"],
|
||||||
|
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||||
|
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Notification icon box */
|
/* Notification icon box */
|
||||||
#notification-popup-box {
|
#notification-popup-box {
|
||||||
margin: 0 3px;
|
margin: 0 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#geo-notification-icon {
|
.notification-anchor-icon {
|
||||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#geo-notification-icon {
|
||||||
|
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#addons-notification-icon {
|
||||||
|
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||||
|
}
|
||||||
|
|
||||||
/* Feed icon */
|
/* Feed icon */
|
||||||
#feed-button,
|
#feed-button,
|
||||||
#feed-button > .button-box,
|
#feed-button > .button-box,
|
||||||
|
|
|
@ -1822,13 +1822,20 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||||
margin: 0 3px;
|
margin: 0 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#geo-notification-icon {
|
.notification-anchor-icon {
|
||||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
margin: 0 2px;
|
margin: 0 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#geo-notification-icon {
|
||||||
|
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#addons-notification-icon {
|
||||||
|
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||||
|
}
|
||||||
|
|
||||||
.popup-notification-description {
|
.popup-notification-description {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
@ -1843,6 +1850,15 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
||||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||||
|
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||||
|
.popup-notification-icon[popupid="addon-install-failed"],
|
||||||
|
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||||
|
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
#identity-popup-container,
|
#identity-popup-container,
|
||||||
#identity-popup-notification-container {
|
#identity-popup-notification-container {
|
||||||
margin: 4px 3px 2px -30px;
|
margin: 4px 3px 2px -30px;
|
||||||
|
|
|
@ -1606,17 +1606,33 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
|
||||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popup-notification-icon[popupid="xpinstall-disabled"],
|
||||||
|
.popup-notification-icon[popupid="addon-install-blocked"],
|
||||||
|
.popup-notification-icon[popupid="addon-install-failed"],
|
||||||
|
.popup-notification-icon[popupid="addon-install-complete"] {
|
||||||
|
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Notification icon box */
|
/* Notification icon box */
|
||||||
#notification-popup-box {
|
#notification-popup-box {
|
||||||
margin: 0 3px;
|
margin: 0 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#geo-notification-icon {
|
.notification-anchor-icon {
|
||||||
list-style-image: url(chrome://browser/skin/Geo.png);
|
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#geo-notification-icon {
|
||||||
|
list-style-image: url(chrome://browser/skin/Geo.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
#addons-notification-icon {
|
||||||
|
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png);
|
||||||
|
}
|
||||||
|
|
||||||
#identity-popup-container {
|
#identity-popup-container {
|
||||||
min-width: 280px;
|
min-width: 280px;
|
||||||
padding: 9px;
|
padding: 9px;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче