Bug 1265841 - Implement the `notificationclose` service worker event. r=wchen,baku

MozReview-Commit-ID: EQfCbQKqn9H

--HG--
extra : rebase_source : 2dad51a3c148db794769fb7c64c28f81ea2ca6ff
extra : histedit_source : 254e2e372ba605f74c1f5106f40b207e492e85e1
This commit is contained in:
Kit Cambridge 2016-04-19 22:04:09 -07:00
Родитель 02d8a1e5d9
Коммит d9d287a14e
13 изменённых файлов: 299 добавлений и 78 удалений

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

@ -856,6 +856,7 @@ GK_ATOM(onmapsendmessagereq, "onmapsendmessagereq")
GK_ATOM(onmapmessageupdatereq, "onmapmessageupdatereq")
GK_ATOM(onnewrdsgroup, "onnewrdsgroup")
GK_ATOM(onnotificationclick, "onnotificationclick")
GK_ATOM(onnotificationclose, "onnotificationclose")
GK_ATOM(onnoupdate, "onnoupdate")
GK_ATOM(onobexpasswordreq, "onobexpasswordreq")
GK_ATOM(onobsolete, "onobsolete")

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

@ -185,6 +185,19 @@ interface nsIServiceWorkerManager : nsISupports
in AString aIcon,
in AString aData,
in AString aBehavior);
void sendNotificationCloseEvent(in ACString aOriginSuffix,
in ACString scope,
in AString aID,
in AString aTitle,
in AString aDir,
in AString aLang,
in AString aBody,
in AString aTag,
in AString aIcon,
in AString aData,
in AString aBehavior);
[optional_argc] void sendPushEvent(in ACString aOriginAttributes,
in ACString aScope,
[optional] in uint32_t aDataLength,

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

@ -1590,29 +1590,31 @@ ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
{
AssertIsOnMainThread();
nsAutoCString originSuffix;
nsresult rv = mPrincipal->GetOriginSuffix(originSuffix);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIServiceWorkerManager> swm =
mozilla::services::GetServiceWorkerManager();
if (NS_WARN_IF(!swm)) {
return NS_ERROR_FAILURE;
}
if (!strcmp("alertclickcallback", aTopic)) {
nsAutoCString originSuffix;
nsresult rv = mPrincipal->GetOriginSuffix(originSuffix);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsCOMPtr<nsIServiceWorkerManager> swm =
mozilla::services::GetServiceWorkerManager();
if (swm) {
swm->SendNotificationClickEvent(originSuffix,
NS_ConvertUTF16toUTF8(mScope),
mID,
mTitle,
mDir,
mLang,
mBody,
mTag,
mIcon,
mData,
mBehavior);
}
rv = swm->SendNotificationClickEvent(originSuffix,
NS_ConvertUTF16toUTF8(mScope),
mID,
mTitle,
mDir,
mLang,
mBody,
mTag,
mIcon,
mData,
mBehavior);
Unused << NS_WARN_IF(NS_FAILED(rv));
return NS_OK;
}
@ -1629,6 +1631,20 @@ ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
if (notificationStorage) {
notificationStorage->Delete(origin, mID);
}
rv = swm->SendNotificationCloseEvent(originSuffix,
NS_ConvertUTF16toUTF8(mScope),
mID,
mTitle,
mDir,
mLang,
mBody,
mTag,
mIcon,
mData,
mBehavior);
Unused << NS_WARN_IF(NS_FAILED(rv));
return NS_OK;
}
return NS_OK;

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

@ -23,4 +23,5 @@ dictionary NotificationEventInit : ExtendableEventInit {
partial interface ServiceWorkerGlobalScope {
attribute EventHandler onnotificationclick;
attribute EventHandler onnotificationclose;
};

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

@ -959,6 +959,37 @@ ServiceWorkerManager::SendPushSubscriptionChangeEvent(const nsACString& aOriginA
#endif
}
nsresult
ServiceWorkerManager::SendNotificationEvent(const nsAString& aEventName,
const nsACString& aOriginSuffix,
const nsACString& aScope,
const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aBehavior)
{
PrincipalOriginAttributes attrs;
if (!attrs.PopulateFromSuffix(aOriginSuffix)) {
return NS_ERROR_INVALID_ARG;
}
ServiceWorkerInfo* info = GetActiveWorkerInfoForScope(attrs, aScope);
if (!info) {
return NS_ERROR_FAILURE;
}
ServiceWorkerPrivate* workerPrivate = info->WorkerPrivate();
return workerPrivate->SendNotificationEvent(aEventName, aID, aTitle, aDir,
aLang, aBody, aTag,
aIcon, aData, aBehavior,
NS_ConvertUTF8toUTF16(aScope));
}
NS_IMETHODIMP
ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix,
const nsACString& aScope,
@ -972,21 +1003,27 @@ ServiceWorkerManager::SendNotificationClickEvent(const nsACString& aOriginSuffix
const nsAString& aData,
const nsAString& aBehavior)
{
PrincipalOriginAttributes attrs;
if (!attrs.PopulateFromSuffix(aOriginSuffix)) {
return NS_ERROR_INVALID_ARG;
}
return SendNotificationEvent(NS_LITERAL_STRING(NOTIFICATION_CLICK_EVENT_NAME),
aOriginSuffix, aScope, aID, aTitle, aDir, aLang,
aBody, aTag, aIcon, aData, aBehavior);
}
ServiceWorkerInfo* info = GetActiveWorkerInfoForScope(attrs, aScope);
if (!info) {
return NS_ERROR_FAILURE;
}
ServiceWorkerPrivate* workerPrivate = info->WorkerPrivate();
return workerPrivate->SendNotificationClickEvent(aID, aTitle, aDir,
aLang, aBody, aTag,
aIcon, aData, aBehavior,
NS_ConvertUTF8toUTF16(aScope));
NS_IMETHODIMP
ServiceWorkerManager::SendNotificationCloseEvent(const nsACString& aOriginSuffix,
const nsACString& aScope,
const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aBehavior)
{
return SendNotificationEvent(NS_LITERAL_STRING(NOTIFICATION_CLOSE_EVENT_NAME),
aOriginSuffix, aScope, aID, aTitle, aDir, aLang,
aBody, aTag, aIcon, aData, aBehavior);
}
NS_IMETHODIMP

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

@ -431,6 +431,20 @@ private:
void
MaybeSendUnregister(nsIPrincipal* aPrincipal, const nsACString& aScope);
nsresult
SendNotificationEvent(const nsAString& aEventName,
const nsACString& aOriginSuffix,
const nsACString& aScope,
const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aBehavior);
};
} // namespace workers

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

@ -1079,8 +1079,9 @@ ClearWindowAllowedRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPriv
return true;
}
class SendNotificationClickEventRunnable final : public ExtendableEventWorkerRunnable
class SendNotificationEventRunnable final : public ExtendableEventWorkerRunnable
{
const nsString mEventName;
const nsString mID;
const nsString mTitle;
const nsString mDir;
@ -1093,19 +1094,21 @@ class SendNotificationClickEventRunnable final : public ExtendableEventWorkerRun
const nsString mScope;
public:
SendNotificationClickEventRunnable(WorkerPrivate* aWorkerPrivate,
KeepAliveToken* aKeepAliveToken,
const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aBehavior,
const nsAString& aScope)
SendNotificationEventRunnable(WorkerPrivate* aWorkerPrivate,
KeepAliveToken* aKeepAliveToken,
const nsAString& aEventName,
const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aBehavior,
const nsAString& aScope)
: ExtendableEventWorkerRunnable(aWorkerPrivate, aKeepAliveToken)
, mEventName(aEventName)
, mID(aID)
, mTitle(aTitle)
, mDir(aDir)
@ -1144,8 +1147,7 @@ public:
nei.mCancelable = false;
RefPtr<NotificationEvent> event =
NotificationEvent::Constructor(target,
NS_LITERAL_STRING("notificationclick"),
NotificationEvent::Constructor(target, mEventName,
nei, result);
if (NS_WARN_IF(result.Failed())) {
return false;
@ -1170,27 +1172,37 @@ public:
} // namespace anonymous
nsresult
ServiceWorkerPrivate::SendNotificationClickEvent(const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aBehavior,
const nsAString& aScope)
ServiceWorkerPrivate::SendNotificationEvent(const nsAString& aEventName,
const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aBehavior,
const nsAString& aScope)
{
nsresult rv = SpawnWorkerIfNeeded(NotificationClickEvent, nullptr);
WakeUpReason why;
if (aEventName.EqualsLiteral(NOTIFICATION_CLICK_EVENT_NAME)) {
why = NotificationClickEvent;
gDOMDisableOpenClickDelay = Preferences::GetInt("dom.disable_open_click_delay");
} else if (aEventName.EqualsLiteral(NOTIFICATION_CLOSE_EVENT_NAME)) {
why = NotificationCloseEvent;
} else {
MOZ_ASSERT_UNREACHABLE("Invalid notification event name");
return NS_ERROR_FAILURE;
}
nsresult rv = SpawnWorkerIfNeeded(why, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
gDOMDisableOpenClickDelay = Preferences::GetInt("dom.disable_open_click_delay");
RefPtr<WorkerRunnable> r =
new SendNotificationClickEventRunnable(mWorkerPrivate, mKeepAliveToken,
aID, aTitle, aDir, aLang,
aBody, aTag, aIcon, aData,
aBehavior, aScope);
new SendNotificationEventRunnable(mWorkerPrivate, mKeepAliveToken,
aEventName, aID, aTitle, aDir, aLang,
aBody, aTag, aIcon, aData, aBehavior,
aScope);
if (NS_WARN_IF(!r->Dispatch())) {
return NS_ERROR_FAILURE;
}

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

@ -11,6 +11,9 @@
#include "WorkerPrivate.h"
#define NOTIFICATION_CLICK_EVENT_NAME "notificationclick"
#define NOTIFICATION_CLOSE_EVENT_NAME "notificationclose"
class nsIInterceptedChannel;
namespace mozilla {
@ -93,16 +96,17 @@ public:
SendPushSubscriptionChangeEvent();
nsresult
SendNotificationClickEvent(const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aBehavior,
const nsAString& aScope);
SendNotificationEvent(const nsAString& aEventName,
const nsAString& aID,
const nsAString& aTitle,
const nsAString& aDir,
const nsAString& aLang,
const nsAString& aBody,
const nsAString& aTag,
const nsAString& aIcon,
const nsAString& aData,
const nsAString& aBehavior,
const nsAString& aScope);
nsresult
SendFetchEvent(nsIInterceptedChannel* aChannel,
@ -149,6 +153,7 @@ private:
PushSubscriptionChangeEvent,
MessageEvent,
NotificationClickEvent,
NotificationCloseEvent,
LifeCycleEvent,
AttachEvent
};

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

@ -243,6 +243,7 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServiceWorkerGlobalScope,
WorkerGlobalScope)
IMPL_EVENT_HANDLER(notificationclick)
IMPL_EVENT_HANDLER(notificationclose)
ServiceWorkerGlobalScope(WorkerPrivate* aWorkerPrivate, const nsACString& aScope);

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

@ -133,6 +133,8 @@ support-files =
notificationclick.js
notificationclick_focus.html
notificationclick_focus.js
notificationclose.html
notificationclose.js
worker_updatefoundevent.js
worker_updatefoundevent2.js
updatefoundevent.html
@ -249,6 +251,7 @@ tags = mcb
[test_notificationclick.html]
[test_notificationclick_focus.html]
[test_notificationclick-otherwindow.html]
[test_notificationclose.html]
[test_opaque_intercept.html]
[test_openWindow.html]
[test_origin_after_redirect.html]

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

@ -0,0 +1,37 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1265841 - controlled page</title>
<script class="testbody" type="text/javascript">
var testWindow = parent;
if (opener) {
testWindow = opener;
}
navigator.serviceWorker.ready.then(function(swr) {
return swr.showNotification(
"Hi there. The ServiceWorker should receive a close event for this.",
{ data: { complex: ["jsval", 5] }}).then(function() {
return swr;
});
}).then(function(swr) {
return swr.getNotifications();
}).then(function(notifications) {
notifications.forEach(function(notification) {
notification.close();
});
});
navigator.serviceWorker.onmessage = function(msg) {
testWindow.callback(msg.data.result);
};
</script>
</head>
<body>
</body>
</html>

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

@ -0,0 +1,19 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/publicdomain/zero/1.0/
//
onnotificationclose = function(e) {
self.clients.matchAll().then(function(clients) {
if (clients.length === 0) {
dump("********************* CLIENTS LIST EMPTY! Test will timeout! ***********************\n");
return;
}
clients.forEach(function(client) {
client.postMessage({ result: e.notification.data &&
e.notification.data['complex'] &&
e.notification.data['complex'][0] == "jsval" &&
e.notification.data['complex'][1] == 5 });
});
});
}

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

@ -0,0 +1,62 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1265841
-->
<head>
<title>Bug 1265841 - Test ServiceWorkerGlobalScope.notificationclose event.</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/MockServices.js"></script>
<script type="text/javascript" src="/tests/dom/tests/mochitest/notification/NotificationTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1265841">Bug 1265841</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<script type="text/javascript">
SimpleTest.requestFlakyTimeout("Mock alert service dispatches show, click, and close events.");
function testFrame(src) {
var iframe = document.createElement("iframe");
iframe.src = src;
window.callback = function(result) {
window.callback = null;
document.body.removeChild(iframe);
iframe = null;
ok(result, "Got notificationclose event with correct data.");
MockServices.unregister();
registration.unregister().then(function() {
SimpleTest.finish();
});
};
document.body.appendChild(iframe);
}
var registration;
function runTest() {
MockServices.register();
testFrame('notificationclose.html');
navigator.serviceWorker.register("notificationclose.js", { scope: "notificationclose.html" }).then(function(reg) {
registration = reg;
}, function(e) {
ok(false, "registration should have passed!");
});
};
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.exemptFromPerDomainMax", true],
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.webnotifications.workers.enabled", true],
["dom.webnotifications.serviceworker.enabled", true],
["notification.prompt.testing", true],
]}, runTest);
</script>
</body>
</html>