Bug 1202933, Part 1 - Show the origin for XUL notifications. r=MattN,wchen

--HG--
extra : commitid : KWwQzH1zUEU
extra : rebase_source : 499d130bfc4c7a5f576beffaf38bf95fa0c047fe
This commit is contained in:
Kit Cambridge 2015-10-05 19:45:04 -07:00
Родитель 763411093a
Коммит 529b10c68f
13 изменённых файлов: 273 добавлений и 8 удалений

Просмотреть файл

@ -12,8 +12,13 @@ XPIDL_SOURCES += [
XPIDL_MODULE = 'alerts'
EXPORTS += [
'nsAlertsUtils.h',
]
UNIFIED_SOURCES += [
'nsAlertsService.cpp',
'nsAlertsUtils.cpp',
'nsXULAlerts.cpp',
]

Просмотреть файл

@ -120,7 +120,7 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
// Use XUL notifications as a fallback if above methods have failed.
rv = mXULAlerts.ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
aAlertCookie, aAlertListener, aAlertName,
aBidi, aLang, aInPrivateBrowsing);
aBidi, aLang, aPrincipal, aInPrivateBrowsing);
return rv;
#endif // !MOZ_WIDGET_ANDROID
}

Просмотреть файл

@ -0,0 +1,74 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsAlertsUtils.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsIStringBundle.h"
#include "nsIURI.h"
#include "nsXPIDLString.h"
#define ALERTS_BUNDLE "chrome://alerts/locale/alert.properties"
/* static */
bool
nsAlertsUtils::IsActionablePrincipal(nsIPrincipal* aPrincipal)
{
return aPrincipal &&
!nsContentUtils::IsSystemOrExpandedPrincipal(aPrincipal) &&
!aPrincipal->GetIsNullPrincipal();
}
/* static */
void
nsAlertsUtils::GetSource(nsIPrincipal* aPrincipal, nsAString& aSource)
{
nsAutoString hostPort;
GetSourceHostPort(aPrincipal, hostPort);
if (hostPort.IsEmpty()) {
return;
}
nsCOMPtr<nsIStringBundleService> stringService(
mozilla::services::GetStringBundleService());
if (!stringService) {
return;
}
nsCOMPtr<nsIStringBundle> alertsBundle;
if (NS_WARN_IF(NS_FAILED(stringService->CreateBundle(ALERTS_BUNDLE,
getter_AddRefs(alertsBundle))))) {
return;
}
const char16_t* params[1] = { hostPort.get() };
nsXPIDLString result;
if (NS_WARN_IF(NS_FAILED(
alertsBundle->FormatStringFromName(MOZ_UTF16("source.label"), params, 1,
getter_Copies(result))))) {
return;
}
aSource = result;
}
/* static */
void
nsAlertsUtils::GetSourceHostPort(nsIPrincipal* aPrincipal,
nsAString& aHostPort)
{
if (!IsActionablePrincipal(aPrincipal)) {
return;
}
nsCOMPtr<nsIURI> principalURI;
if (NS_WARN_IF(NS_FAILED(
aPrincipal->GetURI(getter_AddRefs(principalURI))))) {
return;
}
if (!principalURI) {
return;
}
nsAutoCString hostPort;
if (NS_WARN_IF(NS_FAILED(principalURI->GetHostPort(hostPort)))) {
return;
}
CopyUTF8toUTF16(hostPort, aHostPort);
}

Просмотреть файл

@ -0,0 +1,39 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsAlertsUtils_h
#define nsAlertsUtils_h
#include "nsIPrincipal.h"
#include "nsString.h"
class nsAlertsUtils final
{
private:
nsAlertsUtils() = delete;
public:
/**
* Indicates whether an alert from |aPrincipal| should include the source
* string and action buttons. Returns false if |aPrincipal| is |nullptr|, or
* a system, expanded, or null principal.
*/
static bool
IsActionablePrincipal(nsIPrincipal* aPrincipal);
/**
* Sets |aSource| to the localized notification source string, or an empty
* string if |aPrincipal| is not actionable.
*/
static void
GetSource(nsIPrincipal* aPrincipal, nsAString& aSource);
/**
* Sets |aHostPort| to the host and port from |aPrincipal|'s URI, or an
* empty string if |aPrincipal| is not actionable.
*/
static void
GetSourceHostPort(nsIPrincipal* aPrincipal, nsAString& aHostPort);
};
#endif /* nsAlertsUtils_h */

Просмотреть файл

@ -8,6 +8,7 @@
#include "nsAutoPtr.h"
#include "mozilla/LookAndFeel.h"
#include "nsIServiceManager.h"
#include "nsAlertsUtils.h"
#include "nsISupportsArray.h"
#include "nsISupportsPrimitives.h"
#include "nsPIDOMWindow.h"
@ -44,7 +45,8 @@ nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString&
const nsAString& aAlertText, bool aAlertTextClickable,
const nsAString& aAlertCookie, nsIObserver* aAlertListener,
const nsAString& aAlertName, const nsAString& aBidi,
const nsAString& aLang, bool aInPrivateBrowsing)
const nsAString& aLang, nsIPrincipal* aPrincipal,
bool aInPrivateBrowsing)
{
nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
@ -134,6 +136,16 @@ nsXULAlerts::ShowAlertNotification(const nsAString& aImageUrl, const nsAString&
rv = argsArray->AppendElement(ifptr);
NS_ENSURE_SUCCESS(rv, rv);
// The source contains the host and port of the site that sent the
// notification. It is empty for system alerts.
nsCOMPtr<nsISupportsString> scriptableAlertSource (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
NS_ENSURE_TRUE(scriptableAlertSource, NS_ERROR_FAILURE);
nsAutoString source;
nsAlertsUtils::GetSource(aPrincipal, source);
scriptableAlertSource->SetData(source);
rv = argsArray->AppendElement(scriptableAlertSource);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMWindow> newWindow;
nsAutoCString features("chrome,dialog=yes,titlebar=no,popup=yes");
if (aInPrivateBrowsing) {

Просмотреть файл

@ -25,7 +25,8 @@ public:
const nsAString& aAlertText, bool aAlertTextClickable,
const nsAString& aAlertCookie, nsIObserver* aAlertListener,
const nsAString& aAlertName, const nsAString& aBidi,
const nsAString& aLang, bool aInPrivateBrowsing);
const nsAString& aLang, nsIPrincipal* aPrincipal,
bool aInPrivateBrowsing);
nsresult CloseAlert(const nsAString& aAlertName);
protected:

Просмотреть файл

@ -32,9 +32,19 @@ function prefillAlertInfo() {
// arguments[7] --> lang
// arguments[8] --> replaced alert window (nsIDOMWindow)
// arguments[9] --> an optional callback listener (nsIObserver)
// arguments[10] -> the localized alert source string
switch (window.arguments.length) {
default:
case 11: {
let label = document.getElementById('alertSourceLabel');
if (window.arguments[10]) {
label.hidden = false;
label.setAttribute('value', window.arguments[10]);
} else {
label.hidden = true;
}
}
case 10:
gAlertListener = window.arguments[9];
case 9:

Просмотреть файл

@ -32,6 +32,8 @@
<vbox id="alertTextBox" class="alertTextBox">
<label id="alertTitleLabel" class="alertTitle plain"/>
<label id="alertTextLabel" class="alertText plain"/>
<spacer flex="1"/>
<label id="alertSourceLabel" class="alertSource plain"/>
</vbox>
</box>

Просмотреть файл

@ -1,5 +1,5 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
skip-if = buildapp == 'b2g' || buildapp == 'mulet'
# Synchronous tests like test_alerts.html must come before
# asynchronous tests like test_alerts_noobserve.html!
@ -8,3 +8,5 @@ skip-if = toolkit == 'android'
[test_alerts_noobserve.html]
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
[test_multiple_alerts.html]
[test_principal.html]
skip-if = toolkit == 'android'

Просмотреть файл

@ -22,7 +22,8 @@
var observer = {
alertShow: false,
observe: function (aSubject, aTopic, aData) {
if (aTopic == "alertclickcallback") {
is(aData, "foobarcookie", "Checking whether the alert cookie was passed correctly");
if (aTopic == "alertclickcallback") {
todo(false, "Did someone click the notification while running mochitests? (Please don't.)");
} else if (aTopic == "alertshow") {
ok(!this.alertShow, "Alert should not be shown more than once");
@ -31,7 +32,6 @@ var observer = {
is(aTopic, "alertfinished", "Checking the topic for a finished notification");
SimpleTest.finish();
}
is(aData, "foobarcookie", "Checking whether the alert cookie was passed correctly");
}
};
@ -62,9 +62,10 @@ function runTest() {
SimpleTest.waitForExplicitFinish();
notifier.showAlertNotification(null, "Notification test",
"Surprise! I'm here to test notifications!",
false, "foobarcookie", observer, alertname);
false, "foobarcookie", observer, alertName);
ok(true, "showAlertNotification() succeeded. Waiting for notification...");
if (MAC) {
if (SpecialPowers.Services.appinfo.OS == "Darwin") {
// Notifications are native on OS X 10.8 and later, and when they are they
// persist in the Notification Center. We need to close explicitly to avoid a hang.
// This also works for XUL notifications when running this test on OS X < 10.8.

Просмотреть файл

@ -0,0 +1,111 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 1202933</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="text/javascript">
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
const Services = SpecialPowers.Services;
const notifier = Cc["@mozilla.org/alerts-service;1"]
.getService(Ci.nsIAlertsService);
function notify(alertName, principal) {
return new Promise((resolve, reject) => {
var source;
function observe(subject, topic, data) {
if (topic == "alertclickcallback") {
reject(new Error("Alerts should not be clicked during test"));
} else if (topic == "alertshow") {
var alertWindows = Services.wm.getEnumerator("alert:alert");
ok(alertWindows.hasMoreElements(), "Should show alert");
var alertWindow = alertWindows.getNext();
source = alertWindow.document.getElementById("alertSourceLabel").getAttribute("value");
} else {
is(topic, "alertfinished", "Should hide alert");
resolve(source);
}
}
notifier.showAlertNotification(null, "Notification test",
"Surprise! I'm here to test notifications!",
false, alertName, observe, alertName,
null, null, null, principal);
if (SpecialPowers.Services.appinfo.OS == "Darwin") {
notifier.closeAlert(alertName);
}
});
}
function* testNoPrincipal() {
var source = yield notify("noPrincipal", null);
ok(!source, "Should omit source without principal");
}
function* testSystemPrincipal() {
var principal = Services.scriptSecurityManager.getSystemPrincipal();
var source = yield notify("systemPrincipal", principal);
ok(!source, "Should omit source for system principal");
}
function* testExpandedPrincipal() {
var principal = Services.scriptSecurityManager.createExpandedPrincipal([], 0);
var source = yield notify("expandedPrincipal", principal);
ok(!source, "Should omit source for expanded principal");
}
function* testNullPrincipal() {
var principal = Services.scriptSecurityManager.createNullPrincipal({});
var source = yield notify("nullPrincipal", principal);
ok(!source, "Should omit source for null principal");
}
function* testNodePrincipal() {
var principal = SpecialPowers.wrap(document).nodePrincipal;
var source = yield notify("nodePrincipal", principal);
var stringBundle = Services.strings.createBundle(
"chrome://alerts/locale/alert.properties"
);
var localizedSource = stringBundle.formatStringFromName(
"source.label", [principal.URI.hostPort], 1);
is(source, localizedSource, "Should include source for node principal");
}
function runTest() {
if (!("@mozilla.org/alerts-service;1" in Cc)) {
todo(false, "Alerts service does not exist in this application");
return;
}
if ("@mozilla.org/system-alerts-service;1" in Cc) {
todo(false, "Native alerts service exists in this application");
return;
}
ok(true, "Alerts service exists in this application");
ok(!Services.wm.getEnumerator("alert:alert").hasMoreElements(),
"Alerts should not be present at the start of the test.");
add_task(testNoPrincipal);
add_task(testSystemPrincipal);
add_task(testExpandedPrincipal);
add_task(testNullPrincipal);
add_task(testNodePrincipal);
}
runTest();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -9,4 +9,8 @@ closeButton.title = Close
# LOCALIZATION NOTE(actionButton.label): Used as the button label to provide more actions on OS X notifications. OS X will truncate this if it's too long.
actionButton.label =
webActions.disable.label = Disable notifications from this site
# LOCALIZATION NOTE(source.label): Used to show the URL of the site that
# sent the notification (e.g., "via mozilla.org"). "%1$S" is the source host
# and port.
source.label=via %1$S
webActions.settings.label = Notification settings

Просмотреть файл

@ -38,6 +38,10 @@
font-size: 110%;
}
.alertSource {
color: gray;
}
#alertImage {
max-width: 48px;
max-height: 48px;