Bug 1139656 - Implement the first pieces of the all-doorhanger install flow for add-ons installed from websites. r=dtownsend

This commit is contained in:
Dão Gottwald 2015-03-24 18:54:59 +01:00
parent b1507a1904
commit 91d498fddb
21 changed files with 423 additions and 306 deletions

View File

@ -37,6 +37,8 @@ pref("extensions.minCompatibleAppVersion", "4.0");
// extensions.checkCompatibility=false has been set.
pref("extensions.checkCompatibility.temporaryThemeOverride_minAppVersion", "29.0a1");
pref("xpinstall.customConfirmationUI", true);
// Preferences for AMO integration
pref("extensions.getAddons.cache.enabled", true);
pref("extensions.getAddons.maxResults", 15);

View File

@ -48,9 +48,15 @@ const gXPInstallObserver = {
timeout: Date.now() + 30000
};
try {
options.originHost = installInfo.originatingURI.host;
} catch (e) {
// originatingURI might be missing or 'host' might throw for non-nsStandardURL nsIURIs.
}
switch (aTopic) {
case "addon-install-disabled":
notificationID = "xpinstall-disabled"
case "addon-install-disabled": {
notificationID = "xpinstall-disabled";
if (gPrefService.prefIsLocked("xpinstall.enabled")) {
messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked");
@ -70,18 +76,15 @@ const gXPInstallObserver = {
PopupNotifications.show(browser, notificationID, messageString, anchorID,
action, null, options);
break;
case "addon-install-blocked":
let originatingHost;
try {
originatingHost = installInfo.originatingURI.host;
} catch (ex) {
break; }
case "addon-install-blocked": {
if (!options.originHost) {
// Need to deal with missing originatingURI and with about:/data: URIs more gracefully,
// see bug 1063418 - but for now, bail:
return;
}
messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
[brandShortName, originatingHost]);
messageString = gNavigatorBundle.getFormattedString("xpinstallPromptMessage",
[brandShortName]);
let secHistogram = Components.classes["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry).getHistogramById("SECURITY_UI");
action = {
@ -96,9 +99,9 @@ const gXPInstallObserver = {
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_ADDON_ASKING_PREVENTED);
PopupNotifications.show(browser, notificationID, messageString, anchorID,
action, null, options);
break;
case "addon-install-started":
var needsDownload = function needsDownload(aInstall) {
break; }
case "addon-install-started": {
let needsDownload = function needsDownload(aInstall) {
return aInstall.state != AddonManager.STATE_DOWNLOADED;
}
// If all installs have already been downloaded then there is no need to
@ -106,25 +109,35 @@ const gXPInstallObserver = {
if (!installInfo.installs.some(needsDownload))
return;
notificationID = "addon-progress";
messageString = gNavigatorBundle.getString("addonDownloading");
messageString = gNavigatorBundle.getString("addonDownloadingAndVerifying");
messageString = PluralForm.get(installInfo.installs.length, messageString);
options.installs = installInfo.installs;
options.contentWindow = browser.contentWindow;
options.sourceURI = browser.currentURI;
options.eventCallback = function(aEvent) {
if (aEvent != "removed")
return;
options.eventCallback = (aEvent) => {
switch (aEvent) {
case "removed":
options.contentWindow = null;
options.sourceURI = null;
};
PopupNotifications.show(browser, notificationID, messageString, anchorID,
null, null, options);
break;
case "addon-install-failed":
}
};
let notification = PopupNotifications.show(browser, notificationID, messageString,
anchorID, null, null, options);
notification._startTime = Date.now();
let cancelButton = document.getElementById("addon-progress-cancel");
cancelButton.label = gNavigatorBundle.getString("addonInstall.cancelButton.label");
cancelButton.accessKey = gNavigatorBundle.getString("addonInstall.cancelButton.accesskey");
let acceptButton = document.getElementById("addon-progress-accept");
acceptButton.label = gNavigatorBundle.getString("addonInstall.acceptButton.label");
acceptButton.accessKey = gNavigatorBundle.getString("addonInstall.acceptButton.accesskey");
break; }
case "addon-install-failed": {
// TODO This isn't terribly ideal for the multiple failure case
for (let install of installInfo.installs) {
let host = (installInfo.originatingURI instanceof Ci.nsIStandardURL) &&
installInfo.originatingURI.host;
let host = options.originHost;
if (!host)
host = (install.sourceURI instanceof Ci.nsIStandardURL) &&
install.sourceURI.host;
@ -147,9 +160,100 @@ const gXPInstallObserver = {
PopupNotifications.show(browser, notificationID, messageString, anchorID,
action, null, options);
}
this._removeProgressNotification(browser);
break; }
case "addon-install-confirmation": {
options.eventCallback = (aEvent) => {
switch (aEvent) {
case "removed":
if (installInfo) {
for (let install of installInfo.installs)
install.cancel();
}
this.acceptInstallation = null;
break;
case "addon-install-complete":
var needsRestart = installInfo.installs.some(function(i) {
case "shown":
let addonList = document.getElementById("addon-install-confirmation-content");
while (addonList.firstChild)
addonList.firstChild.remove();
for (let install of installInfo.installs) {
let container = document.createElement("hbox");
let name = document.createElement("label");
let author = document.createElement("label");
name.setAttribute("value", install.addon.name);
author.setAttribute("value", !install.addon.creator ? "" :
gNavigatorBundle.getFormattedString("addonConfirmInstall.author", [install.addon.creator]));
name.setAttribute("class", "addon-install-confirmation-name");
author.setAttribute("class", "addon-install-confirmation-author");
container.appendChild(name);
container.appendChild(author);
addonList.appendChild(container);
}
this.acceptInstallation = () => {
for (let install of installInfo.installs)
install.install();
installInfo = null;
Services.telemetry
.getHistogramById("SECURITY_UI")
.add(Ci.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL_CLICK_THROUGH);
};
break;
}
};
messageString = gNavigatorBundle.getString("addonConfirmInstall.message");
messageString = PluralForm.get(installInfo.installs.length, messageString);
messageString = messageString.replace("#1", brandShortName);
messageString = messageString.replace("#2", installInfo.installs.length);
let cancelButton = document.getElementById("addon-install-confirmation-cancel");
cancelButton.label = gNavigatorBundle.getString("addonInstall.cancelButton.label");
cancelButton.accessKey = gNavigatorBundle.getString("addonInstall.cancelButton.accesskey");
let acceptButton = document.getElementById("addon-install-confirmation-accept");
acceptButton.label = gNavigatorBundle.getString("addonInstall.acceptButton.label");
acceptButton.accessKey = gNavigatorBundle.getString("addonInstall.acceptButton.accesskey");
let showNotification = () => {
// The download may have been cancelled during the security delay
if (!PopupNotifications.getNotification("addon-progress", browser))
return;
let tab = gBrowser.getTabForBrowser(browser);
if (tab)
gBrowser.selectedTab = tab;
if (PopupNotifications.isPanelOpen) {
let rect = document.getElementById("addon-progress-notification").getBoundingClientRect();
let notification = document.getElementById("addon-install-confirmation-notification");
notification.style.minHeight = rect.height + "px";
}
PopupNotifications.show(browser, notificationID, messageString, anchorID,
action, null, options);
this._removeProgressNotification(browser);
Services.telemetry
.getHistogramById("SECURITY_UI")
.add(Ci.nsISecurityUITelemetry.WARNING_CONFIRM_ADDON_INSTALL);
};
let downloadDuration = 0;
let progressNotification = PopupNotifications.getNotification("addon-progress", browser);
if (progressNotification)
downloadDuration = Date.now() - progressNotification._startTime;
let securityDelay = Services.prefs.getIntPref("security.dialog_enable_delay") - downloadDuration;
if (securityDelay > 0)
setTimeout(showNotification, securityDelay);
else
showNotification();
break; }
case "addon-install-complete": {
let needsRestart = installInfo.installs.some(function(i) {
return i.addon.pendingOperations != AddonManager.PENDING_NONE;
});
@ -180,8 +284,13 @@ const gXPInstallObserver = {
PopupNotifications.show(browser, notificationID, messageString, anchorID,
action, null, options);
break;
break; }
}
},
_removeProgressNotification(aBrowser) {
let notification = PopupNotifications.getNotification("addon-progress", aBrowser);
if (notification)
notification.remove();
}
};

View File

@ -1223,6 +1223,7 @@ var gBrowserInit = {
Services.obs.addObserver(gXPInstallObserver, "addon-install-started", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-confirmation", false);
Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
window.messageManager.addMessageListener("Browser:URIFixup", gKeywordURIFixup);
@ -1534,6 +1535,7 @@ var gBrowserInit = {
Services.obs.removeObserver(gXPInstallObserver, "addon-install-started");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-blocked");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-failed");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-confirmation");
Services.obs.removeObserver(gXPInstallObserver, "addon-install-complete");
window.messageManager.removeMessageListener("Browser:URIFixup", gKeywordURIFixup);
window.messageManager.removeMessageListener("Browser:LoadURI", RedirectLoad);

View File

@ -10,7 +10,6 @@
<popupnotification id="webRTC-shareDevices-notification" hidden="true">
<popupnotificationcontent id="webRTC-selectCamera" orient="vertical">
<separator class="thin"/>
<label value="&getUserMedia.selectCamera.label;"
accesskey="&getUserMedia.selectCamera.accesskey;"
control="webRTC-selectCamera-menulist"/>
@ -20,7 +19,6 @@
</popupnotificationcontent>
<popupnotificationcontent id="webRTC-selectWindowOrScreen" orient="vertical">
<separator class="thin"/>
<label id="webRTC-selectWindow-label"
control="webRTC-selectWindow-menulist"/>
<menulist id="webRTC-selectWindow-menulist"
@ -31,7 +29,6 @@
</popupnotificationcontent>
<popupnotificationcontent id="webRTC-selectMicrophone" orient="vertical">
<separator class="thin"/>
<label value="&getUserMedia.selectMicrophone.label;"
accesskey="&getUserMedia.selectMicrophone.accesskey;"
control="webRTC-selectMicrophone-menulist"/>
@ -42,9 +39,7 @@
</popupnotification>
<popupnotification id="webapps-install-progress-notification" hidden="true">
<popupnotificationcontent id="webapps-install-progress-content" orient="vertical" align="start">
<separator class="thin"/>
</popupnotificationcontent>
<popupnotificationcontent id="webapps-install-progress-content" orient="vertical" align="start"/>
</popupnotification>
<popupnotification id="servicesInstall-notification" hidden="true">
@ -55,7 +50,6 @@
<popupnotification id="pointerLock-notification" hidden="true">
<popupnotificationcontent orient="vertical" align="start">
<separator class="thin"/>
<label id="pointerLock-cancel">&pointerLock.notification.message;</label>
</popupnotificationcontent>
</popupnotification>
@ -73,3 +67,18 @@
<popupnotificationcontent orient="vertical"/>
</popupnotification>
#endif
<popupnotification id="addon-progress-notification" hidden="true">
<button id="addon-progress-cancel"
oncommand="this.parentNode.cancel();"/>
<button id="addon-progress-accept" disabled="true"/>
</popupnotification>
<popupnotification id="addon-install-confirmation-notification" hidden="true">
<popupnotificationcontent id="addon-install-confirmation-content" orient="vertical"/>
<button id="addon-install-confirmation-cancel"
oncommand="PopupNotifications.getNotification('addon-install-confirmation').remove();"/>
<button id="addon-install-confirmation-accept"
oncommand="gXPInstallObserver.acceptInstallation();
PopupNotifications.getNotification('addon-install-confirmation').remove();"/>
</popupnotification>

View File

@ -5,9 +5,8 @@
const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
const TESTROOT2 = "http://example.org/browser/toolkit/mozapps/extensions/test/xpinstall/";
const SECUREROOT = "https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
const PROGRESS_NOTIFICATION = "addon-progress-notification";
const PROGRESS_NOTIFICATION = "addon-progress";
var rootDir = getRootDirectory(gTestPath);
var path = rootDir.split('/');
@ -22,7 +21,15 @@ const CHROMEROOT = croot;
var gApp = document.getElementById("bundle_brand").getString("brandShortName");
var gVersion = Services.appinfo.version;
var check_notification;
function get_observer_topic(aNotificationId) {
let topic = aNotificationId;
if (topic == "xpinstall-disabled")
topic = "addon-install-disabled";
else if (topic == "addon-progress")
topic = "addon-install-started";
return topic;
}
function wait_for_progress_notification(aCallback) {
wait_for_notification(PROGRESS_NOTIFICATION, aCallback, "popupshowing");
@ -30,19 +37,45 @@ function wait_for_progress_notification(aCallback) {
function wait_for_notification(aId, aCallback, aEvent = "popupshown") {
info("Waiting for " + aId + " notification");
check_notification = function() {
let topic = get_observer_topic(aId);
function observer(aSubject, aTopic, aData) {
// Ignore the progress notification unless that is the notification we want
if (aId != PROGRESS_NOTIFICATION && PopupNotifications.panel.childNodes[0].id == PROGRESS_NOTIFICATION)
if (aId != PROGRESS_NOTIFICATION &&
aTopic == get_observer_topic(PROGRESS_NOTIFICATION))
return;
PopupNotifications.panel.removeEventListener(aEvent, check_notification, false);
Services.obs.removeObserver(observer, topic);
if (PopupNotifications.isPanelOpen)
executeSoon(verify);
else
PopupNotifications.panel.addEventListener(aEvent, event_listener);
}
function event_listener() {
// Ignore the progress notification unless that is the notification we want
if (aId != PROGRESS_NOTIFICATION &&
PopupNotifications.panel.childNodes[0].id == PROGRESS_NOTIFICATION + "-notification")
return;
PopupNotifications.panel.removeEventListener(aEvent, event_listener);
verify();
}
function verify() {
info("Saw a notification");
ok(PopupNotifications.isPanelOpen, "Panel should be open");
is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
if (PopupNotifications.panel.childNodes.length)
is(PopupNotifications.panel.childNodes[0].id, aId, "Should have seen the right notification");
if (PopupNotifications.panel.childNodes.length) {
is(PopupNotifications.panel.childNodes[0].id,
aId + "-notification", "Should have seen the right notification");
}
aCallback(PopupNotifications.panel);
};
PopupNotifications.panel.addEventListener(aEvent, check_notification, false);
}
Services.obs.addObserver(observer, topic, false);
}
function wait_for_notification_close(aCallback) {
@ -53,35 +86,6 @@ function wait_for_notification_close(aCallback) {
}, false);
}
function wait_for_install_dialog(aCallback) {
info("Waiting for install dialog");
Services.wm.addListener({
onOpenWindow: function(aXULWindow) {
info("Install dialog opened, waiting for focus");
Services.wm.removeListener(this);
var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
waitForFocus(function() {
info("Saw install dialog");
is(domwindow.document.location.href, XPINSTALL_URL, "Should have seen the right window open");
// Override the countdown timer on the accept button
var button = domwindow.document.documentElement.getButton("accept");
button.disabled = false;
aCallback(domwindow);
}, domwindow);
},
onCloseWindow: function(aXULWindow) {
},
onWindowTitleChange: function(aXULWindow, aNewTitle) {
}
});
}
function wait_for_single_notification(aCallback) {
function inner_waiter() {
info("Waiting for single notification");
@ -114,7 +118,7 @@ function test_disabled_install() {
Services.prefs.setBoolPref("xpinstall.enabled", false);
// Wait for the disabled notification
wait_for_notification("xpinstall-disabled-notification", function(aPanel) {
wait_for_notification("xpinstall-disabled", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.button.label, "Enable", "Should have seen the right button");
is(notification.getAttribute("label"),
@ -151,18 +155,19 @@ function test_disabled_install() {
function test_blocked_install() {
// Wait for the blocked notification
wait_for_notification("addon-install-blocked-notification", function(aPanel) {
wait_for_notification("addon-install-blocked", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.button.label, "Allow", "Should have seen the right button");
is(notification.getAttribute("originhost"), "example.com",
"Should have seen the right origin host");
is(notification.getAttribute("label"),
gApp + " prevented this site (example.com) from asking you to install " +
"software on your computer.",
gApp + " prevented this site from asking you to install software on your computer.",
"Should have seen the right message");
// Wait for the install confirmation dialog
wait_for_install_dialog(function(aWindow) {
wait_for_notification("addon-install-confirmation", function(aPanel) {
// Wait for the complete notification
wait_for_notification("addon-install-complete-notification", function(aPanel) {
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
is(notification.getAttribute("label"),
@ -178,7 +183,7 @@ function test_blocked_install() {
});
});
aWindow.document.documentElement.acceptDialog();
document.getElementById("addon-install-confirmation-accept").click();
});
// Click on Allow
@ -188,7 +193,6 @@ function test_blocked_install() {
ok(PopupNotifications.isPanelOpen, "Notification should still be open");
notification = aPanel.childNodes[0];
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
});
var triggers = encodeURIComponent(JSON.stringify({
@ -201,10 +205,15 @@ function test_blocked_install() {
function test_whitelisted_install() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
gBrowser.selectedTab = originalTab;
// Wait for the install confirmation dialog
wait_for_install_dialog(function(aWindow) {
wait_for_notification("addon-install-confirmation", function(aPanel) {
is(gBrowser.selectedTab, tab,
"tab selected in response to the addon-install-confirmation notification");
// Wait for the complete notification
wait_for_notification("addon-install-complete-notification", function(aPanel) {
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
is(notification.getAttribute("label"),
@ -221,7 +230,7 @@ function test_whitelisted_install() {
});
});
aWindow.document.documentElement.acceptDialog();
document.getElementById("addon-install-confirmation-accept").click();
});
});
@ -231,7 +240,9 @@ function test_whitelisted_install() {
var triggers = encodeURIComponent(JSON.stringify({
"XPI": "unsigned.xpi"
}));
gBrowser.selectedTab = gBrowser.addTab();
let originalTab = gBrowser.selectedTab;
let tab = gBrowser.addTab();
gBrowser.selectedTab = tab;
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
},
@ -239,7 +250,7 @@ function test_failed_download() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the failed notification
wait_for_notification("addon-install-failed-notification", function(aPanel) {
wait_for_notification("addon-install-failed", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.getAttribute("label"),
"The add-on could not be downloaded because of a connection failure " +
@ -266,7 +277,7 @@ function test_corrupt_file() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the failed notification
wait_for_notification("addon-install-failed-notification", function(aPanel) {
wait_for_notification("addon-install-failed", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.getAttribute("label"),
"The add-on downloaded from example.com could not be installed " +
@ -293,7 +304,7 @@ function test_incompatible() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the failed notification
wait_for_notification("addon-install-failed-notification", function(aPanel) {
wait_for_notification("addon-install-failed", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.getAttribute("label"),
"XPI Test could not be installed because it is not compatible with " +
@ -320,9 +331,9 @@ function test_restartless() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_install_dialog(function(aWindow) {
wait_for_notification("addon-install-confirmation", function(aPanel) {
// Wait for the complete notification
wait_for_notification("addon-install-complete-notification", function(aPanel) {
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.getAttribute("label"),
"XPI Test has been installed successfully.",
@ -341,7 +352,7 @@ function test_restartless() {
});
});
aWindow.document.documentElement.acceptDialog();
document.getElementById("addon-install-confirmation-accept").click();
});
});
@ -359,9 +370,9 @@ function test_multiple() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_install_dialog(function(aWindow) {
wait_for_notification("addon-install-confirmation", function(aPanel) {
// Wait for the complete notification
wait_for_notification("addon-install-complete-notification", function(aPanel) {
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
is(notification.getAttribute("label"),
@ -382,7 +393,7 @@ function test_multiple() {
});
});
aWindow.document.documentElement.acceptDialog();
document.getElementById("addon-install-confirmation-accept").click();
});
});
@ -401,9 +412,9 @@ function test_url() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_install_dialog(function(aWindow) {
wait_for_notification("addon-install-confirmation", function(aPanel) {
// Wait for the complete notification
wait_for_notification("addon-install-complete-notification", function(aPanel) {
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
is(notification.getAttribute("label"),
@ -419,7 +430,7 @@ function test_url() {
});
});
aWindow.document.documentElement.acceptDialog();
document.getElementById("addon-install-confirmation-accept").click();
});
});
@ -467,7 +478,7 @@ function test_wronghost() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the complete notification
wait_for_notification("addon-install-failed-notification", function(aPanel) {
wait_for_notification("addon-install-failed", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.getAttribute("label"),
"The add-on downloaded from example.com could not be installed " +
@ -488,9 +499,9 @@ function test_reload() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_install_dialog(function(aWindow) {
wait_for_notification("addon-install-confirmation", function(aPanel) {
// Wait for the complete notification
wait_for_notification("addon-install-complete-notification", function(aPanel) {
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
is(notification.getAttribute("label"),
@ -523,7 +534,7 @@ function test_reload() {
gBrowser.loadURI(TESTROOT2 + "enabled.html");
});
aWindow.document.documentElement.acceptDialog();
document.getElementById("addon-install-confirmation-accept").click();
});
});
@ -541,9 +552,9 @@ function test_theme() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_install_dialog(function(aWindow) {
wait_for_notification("addon-install-confirmation", function(aPanel) {
// Wait for the complete notification
wait_for_notification("addon-install-complete-notification", function(aPanel) {
wait_for_notification("addon-install-complete", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
is(notification.getAttribute("label"),
@ -566,7 +577,7 @@ function test_theme() {
});
});
aWindow.document.documentElement.acceptDialog();
document.getElementById("addon-install-confirmation-accept").click();
});
});
@ -582,13 +593,13 @@ function test_theme() {
function test_renotify_blocked() {
// Wait for the blocked notification
wait_for_notification("addon-install-blocked-notification", function(aPanel) {
wait_for_notification("addon-install-blocked", function(aPanel) {
let notification = aPanel.childNodes[0];
wait_for_notification_close(function () {
info("Timeouts after this probably mean bug 589954 regressed");
executeSoon(function () {
wait_for_notification("addon-install-blocked-notification", function(aPanel) {
wait_for_notification("addon-install-blocked", function(aPanel) {
AddonManager.getAllInstalls(function(aInstalls) {
is(aInstalls.length, 2, "Should be two pending installs");
aInstalls[0].cancel();
@ -619,9 +630,9 @@ function test_renotify_installed() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_install_dialog(function(aWindow) {
wait_for_notification("addon-install-confirmation", function(aPanel) {
// Wait for the complete notification
wait_for_notification("addon-install-complete-notification", function(aPanel) {
wait_for_notification("addon-install-complete", function(aPanel) {
// Dismiss the notification
wait_for_notification_close(function () {
// Install another
@ -629,11 +640,11 @@ function test_renotify_installed() {
// Wait for the progress notification
wait_for_progress_notification(function(aPanel) {
// Wait for the install confirmation dialog
wait_for_install_dialog(function(aWindow) {
wait_for_notification("addon-install-confirmation", function(aPanel) {
info("Timeouts after this probably mean bug 589954 regressed");
// Wait for the complete notification
wait_for_notification("addon-install-complete-notification", function(aPanel) {
wait_for_notification("addon-install-complete", function(aPanel) {
AddonManager.getAllInstalls(function(aInstalls) {
is(aInstalls.length, 1, "Should be one pending installs");
aInstalls[0].cancel();
@ -644,7 +655,7 @@ function test_renotify_installed() {
});
});
aWindow.document.documentElement.acceptDialog();
document.getElementById("addon-install-confirmation-accept").click();
});
});
@ -656,7 +667,7 @@ function test_renotify_installed() {
aPanel.hidePopup();
});
aWindow.document.documentElement.acceptDialog();
document.getElementById("addon-install-confirmation-accept").click();
});
});
@ -670,7 +681,7 @@ function test_renotify_installed() {
gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
},
function test_cancel_restart() {
function test_cancel() {
function complete_install(callback) {
let url = TESTROOT + "slowinstall.sjs?continue=true"
NetUtil.asyncFetch(url, callback || (() => {}));
@ -687,10 +698,9 @@ function test_cancel_restart() {
ok(PopupNotifications.isPanelOpen, "Notification should still be open");
is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
isnot(notification, aPanel.childNodes[0], "Should have reconstructed the notification UI");
notification = aPanel.childNodes[0];
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
let button = document.getAnonymousElementByAttribute(notification, "anonid", "cancel");
let button = document.getElementById("addon-progress-cancel");
// Wait for the install to fully cancel
let install = notification.notification.options.installs[0];
@ -699,46 +709,16 @@ function test_cancel_restart() {
install.removeListener(this);
executeSoon(function() {
ok(PopupNotifications.isPanelOpen, "Notification should still be open");
is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
isnot(notification, aPanel.childNodes[0], "Should have reconstructed the notification UI");
notification = aPanel.childNodes[0];
is(notification.id, "addon-install-cancelled-notification", "Should have seen the cancelled notification");
// Wait for the install confirmation dialog
wait_for_install_dialog(function(aWindow) {
// Wait for the complete notification
wait_for_notification("addon-install-complete-notification", function(aPanel) {
let notification = aPanel.childNodes[0];
is(notification.button.label, "Restart Now", "Should have seen the right button");
is(notification.getAttribute("label"),
"XPI Test will be installed after you restart " + gApp + ".",
"Should have seen the right message");
ok(!PopupNotifications.isPanelOpen, "Notification should be closed");
AddonManager.getAllInstalls(function(aInstalls) {
is(aInstalls.length, 1, "Should be one pending install");
aInstalls[0].cancel();
is(aInstalls.length, 0, "Should be no pending install");
Services.perms.remove("example.com", "install");
wait_for_notification_close(runNextTest);
gBrowser.removeTab(gBrowser.selectedTab);
runNextTest();
});
});
aWindow.document.documentElement.acceptDialog();
});
// Restart the download
EventUtils.synthesizeMouseAtCenter(notification.button, {});
// Should be back to a progress notification
ok(PopupNotifications.isPanelOpen, "Notification should still be open");
is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
notification = aPanel.childNodes[0];
is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
complete_install();
});
}
});
@ -764,7 +744,7 @@ function test_failed_security() {
});
// Wait for the blocked notification
wait_for_notification("addon-install-blocked-notification", function(aPanel) {
wait_for_notification("addon-install-blocked", function(aPanel) {
let notification = aPanel.childNodes[0];
// Click on Allow
@ -841,6 +821,7 @@ function test() {
Services.prefs.setBoolPref("extensions.logging.enabled", true);
Services.prefs.setBoolPref("extensions.strictCompatibility", true);
Services.prefs.setBoolPref("extensions.install.requireSecureOrigin", false);
Services.prefs.setIntPref("security.dialog_enable_delay", 0);
Services.obs.addObserver(XPInstallObserver, "addon-install-started", false);
Services.obs.addObserver(XPInstallObserver, "addon-install-blocked", false);
@ -850,7 +831,6 @@ function test() {
registerCleanupFunction(function() {
// Make sure no more test parts run in case we were timed out
TESTS = [];
PopupNotifications.panel.removeEventListener("popupshown", check_notification, false);
AddonManager.getAllInstalls(function(aInstalls) {
aInstalls.forEach(function(aInstall) {
@ -861,6 +841,7 @@ function test() {
Services.prefs.clearUserPref("extensions.logging.enabled");
Services.prefs.clearUserPref("extensions.strictCompatibility");
Services.prefs.clearUserPref("extensions.install.requireSecureOrigin");
Services.prefs.clearUserPref("security.dialog_enable_delay");
Services.obs.removeObserver(XPInstallObserver, "addon-install-started");
Services.obs.removeObserver(XPInstallObserver, "addon-install-blocked");

View File

@ -1573,16 +1573,17 @@
<xul:image class="popup-notification-icon"
xbl:inherits="popupid,src=icon"/>
<xul:vbox flex="1">
<xul:description class="popup-notification-description addon-progress-description"
xbl:inherits="xbl:text=label"/>
<xul:spacer flex="1"/>
<xul:hbox align="center">
<xul:label class="popup-notification-originHost header"
xbl:inherits="value=originhost"
crop="end"/>
<xul:description class="popup-notification-description"
xbl:inherits="xbl:text=label,popupid"/>
<xul:progressmeter anonid="progressmeter" flex="1" mode="undetermined" class="popup-progress-meter"/>
<xul:button anonid="cancel" class="popup-progress-cancel" oncommand="document.getBindingParent(this).cancel()"/>
</xul:hbox>
<xul:label anonid="progresstext" class="popup-progress-label"/>
<xul:label anonid="progresstext" class="popup-progress-label" flex="1" crop="end"/>
<xul:spacer flex="1"/>
<xul:hbox class="popup-notification-button-container"
pack="end" align="center">
<children includes="button"/>
<xul:button anonid="button"
class="popup-notification-menubutton"
type="menu-button"
@ -1606,7 +1607,8 @@
</content>
<implementation>
<constructor><![CDATA[
this.cancelbtn.setAttribute("tooltiptext", gNavigatorBundle.getString("addonDownloadCancelTooltip"));
if (!this.notification)
return;
this.notification.options.installs.forEach(function(aInstall) {
aInstall.addListener(this);
@ -1631,9 +1633,6 @@
<field name="progresstext" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "progresstext");
</field>
<field name="cancelbtn" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "cancel");
</field>
<field name="DownloadUtils" readonly="true">
let utils = {};
Components.utils.import("resource://gre/modules/DownloadUtils.jsm", utils);
@ -1642,6 +1641,9 @@
<method name="destroy">
<body><![CDATA[
if (!this.notification)
return;
this.notification.options.installs.forEach(function(aInstall) {
aInstall.removeListener(this);
}, this);
@ -1686,17 +1688,12 @@
let status = null;
[status, this.notification.last] = this.DownloadUtils.getDownloadStatus(aProgress, aMaxProgress, speed, this.notification.last);
this.progresstext.value = status;
this.progresstext.value = this.progresstext.tooltipText = status;
]]></body>
</method>
<method name="cancel">
<body><![CDATA[
// Cache these as cancelling the installs will remove this
// notification which will drop these references
let browser = this.notification.browser;
let sourceURI = this.notification.options.sourceURI;
let installs = this.notification.options.installs;
installs.forEach(function(aInstall) {
try {
@ -1707,35 +1704,15 @@
}
}, this);
let anchorID = "addons-notification-icon";
let notificationID = "addon-install-cancelled";
let messageString = gNavigatorBundle.getString("addonDownloadCancelled");
messageString = PluralForm.get(installs.length, messageString);
let buttonText = gNavigatorBundle.getString("addonDownloadRestart");
buttonText = PluralForm.get(installs.length, buttonText);
let action = {
label: buttonText,
accessKey: gNavigatorBundle.getString("addonDownloadRestart.accessKey"),
callback: function() {
let weblistener = Cc["@mozilla.org/addons/web-install-listener;1"].
getService(Ci.amIWebInstallListener);
if (weblistener.onWebInstallRequested(browser, sourceURI,
installs, installs.length)) {
installs.forEach(function(aInstall) {
aInstall.install();
});
}
}
};
PopupNotifications.show(browser, notificationID, messageString,
anchorID, action);
PopupNotifications.remove(this.notification);
]]></body>
</method>
<method name="updateProgress">
<body><![CDATA[
if (!this.notification)
return;
let downloadingCount = 0;
let progress = 0;
let maxProgress = 0;
@ -1752,8 +1729,14 @@
if (downloadingCount == 0) {
this.destroy();
if (Preferences.get("xpinstall.customConfirmationUI", false)) {
this.progressmeter.mode = "undetermined";
this.progresstext.value = this.progresstext.tooltipText =
gNavigatorBundle.getString("addonDownloadVerifying");
} else {
PopupNotifications.remove(this.notification);
}
}
else {
this.setProgress(progress, maxProgress);
}

View File

@ -19,7 +19,7 @@ contextMenuSearch.accesskey=S
bookmarkAllTabsDefault=[Folder Name]
xpinstallPromptWarning=%S prevented this site (%S) from asking you to install software on your computer.
xpinstallPromptMessage=%S prevented this site from asking you to install software on your computer.
xpinstallPromptAllowButton=Allow
# Accessibility Note:
# Be sure you do not choose an accesskey that is used elsewhere in the active context (e.g. main menu bar, submenu of the warning popup button)
@ -30,15 +30,27 @@ xpinstallDisabledMessage=Software installation is currently disabled. Click Enab
xpinstallDisabledButton=Enable
xpinstallDisabledButton.accesskey=n
# LOCALIZATION NOTE (addonDownloading, addonDownloadCancelled, addonDownloadRestart):
# LOCALIZATION NOTE (addonDownloading):
# Semicolon-separated list of plural forms. See:
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
# Also see https://bugzilla.mozilla.org/show_bug.cgi?id=570012 for mockups
addonDownloading=Add-on downloading;Add-ons downloading
addonDownloadCancelled=Add-on download cancelled.;Add-on downloads cancelled.
addonDownloadRestart=Restart Download;Restart Downloads
addonDownloadRestart.accessKey=R
addonDownloadCancelTooltip=Cancel
addonDownloadingAndVerifying=Downloading and verifying add-on…;Downloading and verifying add-ons…
addonDownloadVerifying=Verifying
addonInstall.cancelButton.label=Cancel
addonInstall.cancelButton.accesskey=C
addonInstall.acceptButton.label=Install
addonInstall.acceptButton.accesskey=I
# LOCALIZATION NOTE (addonConfirmInstallMessage):
# Semicolon-separated list of plural forms. See:
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #1 is brandShortName
# #2 is the number of add-ons being installed
addonConfirmInstall.message=This site would like to install an add-on in #1:;This site would like to install #2 add-ons in #1:
# LOCALIZATION NOTE (addonConfirmInstall.author):
# %S is the add-on author's name
addonConfirmInstall.author=by %S
addonwatch.slow=%1$S might be making %2$S run slowly
addonwatch.disable.label=Disable %S

View File

@ -1132,11 +1132,6 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
margin-top: 5px;
}
/* Notification popup */
#notification-popup {
min-width: 280px;
}
.popup-notification-icon {
width: 64px;
height: 64px;
@ -1149,15 +1144,29 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
.popup-notification-icon[popupid="xpinstall-disabled"],
.popup-notification-icon[popupid="addon-progress"],
.popup-notification-icon[popupid="addon-install-cancelled"],
.popup-notification-icon[popupid="addon-install-blocked"],
.popup-notification-icon[popupid="addon-install-failed"],
.popup-notification-icon[popupid="addon-install-confirmation"],
.popup-notification-icon[popupid="addon-install-complete"] {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
width: 32px;
height: 32px;
}
.popup-notification-description[popupid="addon-progress"],
.popup-notification-description[popupid="addon-install-confirmation"] {
width: 27em;
max-width: 27em;
}
.popup-progress-meter {
margin-top: .5em;
}
.addon-install-confirmation-name {
font-weight: bold;
}
.popup-notification-icon[popupid="click-to-play-plugins"] {
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
}
@ -1166,29 +1175,6 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
list-style-image: url(chrome://browser/skin/notification-64.png);
}
.addon-progress-description {
width: 350px;
max-width: 350px;
}
.popup-progress-label,
.popup-progress-meter {
-moz-margin-start: 0;
-moz-margin-end: 0;
}
.popup-progress-cancel {
-moz-appearance: none;
background: transparent;
border: none;
padding: 0;
margin: 0;
-moz-margin-start: 5px;
min-height: 0;
min-width: 0;
list-style-image: url("moz-icon://stock/gtk-cancel?size=menu");
}
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
.popup-notification-icon[popupid*="offline-app-requested"],
.popup-notification-icon[popupid="offline-app-usage"] {

View File

@ -4150,22 +4150,19 @@ notification[value="loop-sharing-notification"] .messageImage {
.popup-notification-icon[popupid="xpinstall-disabled"],
.popup-notification-icon[popupid="addon-progress"],
.popup-notification-icon[popupid="addon-install-cancelled"],
.popup-notification-icon[popupid="addon-install-blocked"],
.popup-notification-icon[popupid="addon-install-failed"],
.popup-notification-icon[popupid="addon-install-confirmation"],
.popup-notification-icon[popupid="addon-install-complete"] {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
width: 32px;
height: 32px;
}
.popup-notification-icon[popupid="click-to-play-plugins"] {
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
}
.addon-progress-description {
width: 350px;
max-width: 350px;
.popup-notification-description[popupid="addon-progress"],
.popup-notification-description[popupid="addon-install-confirmation"] {
width: 27em;
max-width: 27em;
}
.popup-progress-label,
@ -4174,24 +4171,18 @@ notification[value="loop-sharing-notification"] .messageImage {
-moz-margin-end: 0;
}
.popup-progress-cancel {
-moz-appearance: none;
min-height: 16px;
min-width: 16px;
max-height: 16px;
max-width: 16px;
padding: 0;
margin: 0 1px 0 1px;
list-style-image: url(chrome://mozapps/skin/downloads/buttons.png);
-moz-image-region: rect(0px, 16px, 16px, 0px);
.popup-progress-meter,
#addon-install-confirmation-content {
margin-top: 1em;
}
.popup-progress-cancel:hover {
-moz-image-region: rect(0px, 32px, 16px, 16px);
.addon-install-confirmation-name {
font-weight: bold;
-moz-margin-start: 0 !important; /* override default label margin to match description margin */
}
.popup-progress-cancel:active {
-moz-image-region: rect(0px, 48px, 16px, 32px);
.popup-notification-icon[popupid="click-to-play-plugins"] {
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
}
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],

View File

@ -2158,15 +2158,30 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
.popup-notification-icon[popupid="xpinstall-disabled"],
.popup-notification-icon[popupid="addon-progress"],
.popup-notification-icon[popupid="addon-install-cancelled"],
.popup-notification-icon[popupid="addon-install-blocked"],
.popup-notification-icon[popupid="addon-install-failed"],
.popup-notification-icon[popupid="addon-install-confirmation"],
.popup-notification-icon[popupid="addon-install-complete"] {
list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric.png);
width: 32px;
height: 32px;
}
.popup-notification-description[popupid="addon-progress"],
.popup-notification-description[popupid="addon-install-confirmation"] {
width: 27em;
max-width: 27em;
}
.popup-progress-meter,
#addon-install-confirmation-content {
margin-top: 1em;
}
.addon-install-confirmation-name {
font-weight: bold;
}
.popup-notification-icon[popupid="click-to-play-plugins"] {
list-style-image: url(chrome://mozapps/skin/plugins/pluginBlocked-64.png);
}
@ -2175,37 +2190,6 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
list-style-image: url(chrome://browser/skin/notification-64.png);
}
.addon-progress-description {
width: 350px;
max-width: 350px;
}
.popup-progress-label,
.popup-progress-meter {
-moz-margin-start: 0;
-moz-margin-end: 0;
}
.popup-progress-cancel {
-moz-appearance: none;
background: transparent;
border: none;
padding: 0;
margin: 0;
min-height: 0;
min-width: 0;
list-style-image: url(chrome://mozapps/skin/downloads/downloadButtons.png);
-moz-image-region: rect(0px, 32px, 16px, 16px);
}
.popup-progress-cancel:hover {
-moz-image-region: rect(16px, 32px, 32px, 16px);
}
.popup-progress-cancel:active {
-moz-image-region: rect(32px, 32px, 48px, 16px);
}
.popup-notification-icon[popupid="indexedDB-permissions-prompt"],
.popup-notification-icon[popupid*="offline-app-requested"],
.popup-notification-icon[popupid="offline-app-usage"] {

View File

@ -470,18 +470,24 @@
</binding>
<binding id="popup-notification">
<content align="start">
<content>
<xul:vbox>
<xul:image class="popup-notification-icon"
xbl:inherits="popupid,src=icon"/>
</xul:vbox>
<xul:vbox flex="1">
<xul:label class="popup-notification-originHost header"
xbl:inherits="value=originhost"
crop="end"/>
<xul:description class="popup-notification-description"
xbl:inherits="xbl:text=label"/>
xbl:inherits="xbl:text=label,popupid"/>
<children includes="popupnotificationcontent"/>
<xul:label class="text-link popup-notification-learnmore-link"
xbl:inherits="href=learnmoreurl">&learnMore;</xul:label>
<xul:spacer flex="1"/>
<xul:hbox class="popup-notification-button-container"
pack="end" align="center">
<children includes="button"/>
<xul:button anonid="button"
class="popup-notification-menubutton"
type="menu-button"

View File

@ -270,6 +270,8 @@ PopupNotifications.prototype = {
* A string URL. Setting this property will make the
* prompt display a "Learn More" link that, when clicked,
* opens the URL in a new tab.
* originHost: The host name of the page the notification came from.
* If present, this will be displayed above the message.
* @returns the Notification object corresponding to the added notification.
*/
show: function PopupNotifications_show(browser, id, message, anchorID,
@ -499,12 +501,12 @@ PopupNotifications.prototype = {
popupnotification.notification = null;
// Remove nodes dynamically added to the notification's menu button
// in _refreshPanel. Keep popupnotificationcontent nodes; they are
// provided by the chrome document.
// in _refreshPanel.
let contentNode = popupnotification.lastChild;
while (contentNode) {
let previousSibling = contentNode.previousSibling;
if (contentNode.nodeName != "popupnotificationcontent")
if (contentNode.nodeName == "menuitem" ||
contentNode.nodeName == "menuseparator")
popupnotification.removeChild(contentNode);
contentNode = previousSibling;
}
@ -559,11 +561,17 @@ PopupNotifications.prototype = {
if (n.options.popupIconURL)
popupnotification.setAttribute("icon", n.options.popupIconURL);
if (n.options.learnMoreURL)
popupnotification.setAttribute("learnmoreurl", n.options.learnMoreURL);
else
popupnotification.removeAttribute("learnmoreurl");
if (n.options.originHost)
popupnotification.setAttribute("originhost", n.options.originHost);
else
popupnotification.removeAttribute("originhost");
popupnotification.notification = n;
if (n.secondaryActions) {

View File

@ -19,6 +19,7 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PromptUtils", "resource://gre/modules/SharedPromptUtils.jsm");
@ -154,6 +155,11 @@ Installer.prototype = {
if (this.downloads.length == 0)
return;
if (Preferences.get("xpinstall.customConfirmationUI", false)) {
notifyObservers("addon-install-confirmation", this.browser, this.url, this.downloads);
return;
}
// Check for a custom installation prompt that may be provided by the
// applicaton
if ("@mozilla.org/addons/web-install-prompt;1" in Cc) {

View File

@ -32,6 +32,7 @@ const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane";
const PREF_XPI_ENABLED = "xpinstall.enabled";
const PREF_UPDATEURL = "extensions.update.url";
const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
const PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI = "xpinstall.customConfirmationUI";
const MANAGER_URI = "about:addons";
const INSTALL_URI = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
@ -62,6 +63,7 @@ var gTestStart = null;
var gUseInContentUI = !gTestInWindow && ("switchToTabHavingURI" in window);
var gRestorePrefs = [{name: PREF_LOGGING_ENABLED},
{name: PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI},
{name: "extensions.webservice.discoverURL"},
{name: "extensions.update.url"},
{name: "extensions.update.background.url"},
@ -95,6 +97,8 @@ for (let pref of gRestorePrefs) {
// Turn logging on for all tests
Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true);
Services.prefs.setBoolPref(PREF_CUSTOM_XPINSTALL_CONFIRMATION_UI, false);
// Helper to register test failures and close windows if any are left open
function checkOpenWindows(aWindowID) {
let windows = Services.wm.getEnumerator(aWindowID);

View File

@ -8,6 +8,7 @@ const ADDONS_URL = "chrome://mozapps/content/extensions/extensions.xul";
const PREF_LOGGING_ENABLED = "extensions.logging.enabled";
const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
const PREF_INSTALL_REQUIRESECUREORIGIN = "extensions.install.requireSecureOrigin";
const PREF_CUSTOM_CONFIRMATION_UI = "xpinstall.customConfirmationUI";
const CHROME_NAME = "mochikit";
function getChromeRoot(path) {
@ -27,6 +28,11 @@ function extractChromeRoot(path) {
return chromeRootPath;
}
Services.prefs.setBoolPref(PREF_CUSTOM_CONFIRMATION_UI, false);
registerCleanupFunction(() => {
Services.prefs.clearUserPref(PREF_CUSTOM_CONFIRMATION_UI);
});
/**
* This is a test harness designed to handle responding to UI during the process
* of installing an XPI. A test can set callbacks to hear about specific parts

View File

@ -281,6 +281,10 @@ notification > button {
margin-bottom: 0;
}
popupnotificationcontent {
margin-top: .5em;
}
/* :::::: autoscroll popup ::::: */
.autoscroller {

View File

@ -67,14 +67,19 @@ notification[type="critical"] {
max-width: 24em;
}
.popup-notification-learnmore-link {
margin-top: 1em !important;
}
.popup-notification-originHost:not([value]),
.popup-notification-learnmore-link:not([href]) {
display: none;
}
.popup-notification-originHost {
margin-bottom: .3em !important;
}
.popup-notification-learnmore-link {
margin-top: .5em !important;
}
.popup-notification-button-container {
margin-top: 17px;
}

View File

@ -266,6 +266,10 @@ notification > button > .button-box > .button-text {
margin: 0 !important;
}
popupnotificationcontent {
margin-top: .5em;
}
/* :::::: autoscroll popup ::::: */
.autoscroller {

View File

@ -105,13 +105,19 @@ notification[type="info"]:not([value="translation"]) .close-icon:not(:hover) {
max-width: 24em;
}
.popup-notification-learnmore-link {
margin-top: 1em !important;
.popup-notification-originHost:not([value]),
.popup-notification-learnmore-link:not([href]) {
display: none;
}
.popup-notification-originHost {
margin-bottom: .3em !important;
-moz-margin-start: 0 !important; /* override default label margin to match description margin */
}
.popup-notification-learnmore-link:not([href]) {
display: none;
.popup-notification-learnmore-link {
margin-top: .5em !important;
-moz-margin-start: 0 !important; /* override default label margin to match description margin */
}
.popup-notification-button-container {

View File

@ -286,6 +286,10 @@ label[disabled="true"]:-moz-system-metric(windows-classic) {
border: 1px dotted -moz-DialogText;
}
popupnotificationcontent {
margin-top: .5em;
}
/* :::::: autoscroll popup ::::: */
.autoscroller {

View File

@ -62,14 +62,19 @@ notification[type="critical"] {
max-width: 24em;
}
.popup-notification-learnmore-link {
margin-top: 1em !important;
}
.popup-notification-originHost:not([value]),
.popup-notification-learnmore-link:not([href]) {
display: none;
}
.popup-notification-originHost {
margin-bottom: .3em !important;
}
.popup-notification-learnmore-link {
margin-top: .5em !important;
}
.popup-notification-button-container {
margin-top: 17px;
}