зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
763411093a
Коммит
529b10c68f
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче