Commit f5ae28ee authored by Anita Woodruff's avatar Anita Woodruff Committed by Commit Bot

[Mojoification] Non-persistent notification events

- All non-persistent notification events (onshow, onclick, and
onclose) now go through Mojo when the NotificationsWithMojo
blink feature flag is enabled.

- Layout tests with mojo enabled that rely on
 non-persistent notification events now pass and are re-enabled.
(Except for those relying on the Notification.close() path which
still needs to be migrated to mojo).

- Interactive ui tests with mojo enabled are simplified to wait
 for the show event rather than NotificationDisplayService
 mutation.

BUG=796990

Change-Id: Id99cd7b936b2ef18fd4be270aa76e4732e137db9
Reviewed-on: https://chromium-review.googlesource.com/878744Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Commit-Queue: Anita Woodruff <awdf@chromium.org>
Cr-Commit-Position: refs/heads/master@{#531953}
parent df898168
...@@ -1008,9 +1008,8 @@ IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest, ...@@ -1008,9 +1008,8 @@ IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest,
// 'RunScript("DisplayNonPersistentNotification(...' once the show event is // 'RunScript("DisplayNonPersistentNotification(...' once the show event is
// implemented via mojo, here and elsewhere in this test. // implemented via mojo, here and elsewhere in this test.
RunScriptAndWaitForNotificationAdded( RunScriptAndWaitForNotificationAdded(
"DisplayNonPersistentNotificationWithoutWaitingForEvent('Title')", "DisplayNonPersistentNotification('Title')", &script_result);
&script_result); EXPECT_EQ("ok", script_result);
EXPECT_EQ("sync-ok", script_result);
std::vector<message_center::Notification> notifications = std::vector<message_center::Notification> notifications =
GetDisplayedNotifications(false /* is_persistent */); GetDisplayedNotifications(false /* is_persistent */);
...@@ -1038,7 +1037,7 @@ IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest, ...@@ -1038,7 +1037,7 @@ IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest,
// Now, test the non-default values. // Now, test the non-default values.
RunScriptAndWaitForNotificationAdded( RunScriptAndWaitForNotificationAdded(
R"(DisplayNonPersistentNotificationWithoutWaitingForEvent('Title2', { R"(DisplayNonPersistentNotification('Title2', {
body: 'Contents', body: 'Contents',
tag: 'replace-id', tag: 'replace-id',
dir: 'rtl', dir: 'rtl',
...@@ -1055,7 +1054,7 @@ IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest, ...@@ -1055,7 +1054,7 @@ IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest,
] ]
}))", }))",
&script_result); &script_result);
EXPECT_EQ("sync-ok", script_result); EXPECT_EQ("ok", script_result);
notifications = GetDisplayedNotifications(false /* is_persistent */); notifications = GetDisplayedNotifications(false /* is_persistent */);
ASSERT_EQ(2u, notifications.size()); ASSERT_EQ(2u, notifications.size());
...@@ -1091,11 +1090,11 @@ IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest, ...@@ -1091,11 +1090,11 @@ IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest,
// identical ids. // identical ids.
RunScriptAndWaitForNotificationAdded( RunScriptAndWaitForNotificationAdded(
R"(DisplayNonPersistentNotificationWithoutWaitingForEvent('Title3', { R"(DisplayNonPersistentNotification('Title3', {
tag: 'replace-id' tag: 'replace-id'
}))", }))",
&script_result); &script_result);
EXPECT_EQ("sync-ok", script_result); EXPECT_EQ("ok", script_result);
notifications = GetDisplayedNotifications(false /* is_persistent */); notifications = GetDisplayedNotifications(false /* is_persistent */);
ASSERT_EQ(2u, notifications.size()); ASSERT_EQ(2u, notifications.size());
......
...@@ -31,18 +31,10 @@ ...@@ -31,18 +31,10 @@
domAutomationController.send('could not show notification')); domAutomationController.send('could not show notification'));
} }
// Instantiates a new non-persistent notification with the given |title|
// and |options| and then forwards script result 'sync-ok', without
// waiting for a notification shown or error event.
function DisplayNonPersistentNotificationWithoutWaitingForEvent(title, options) {
const notification = new Notification(title, options || {});
domAutomationController.send('sync-ok');
}
// Renews the registered Service Worker registration for this page, then // Renews the registered Service Worker registration for this page, then
// displays a notification on the activated ServiceWorkerRegistration. // displays a notification on the activated ServiceWorkerRegistration.
function DisplayPersistentNotification(title, options) { function DisplayPersistentNotification(title, options) {
options = options || { body: 'Hello, world!', options = options || { body: 'Hello, world!',
icon: 'icon.png' }; icon: 'icon.png' };
GetActivatedServiceWorker('platform_notification_service.js', GetActivatedServiceWorker('platform_notification_service.js',
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "content/browser/notifications/notification_event_dispatcher_impl.h"
#include "content/browser/notifications/platform_notification_context_impl.h" #include "content/browser/notifications/platform_notification_context_impl.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h" #include "content/public/browser/content_browser_client.h"
...@@ -39,7 +40,8 @@ BlinkNotificationServiceImpl::BlinkNotificationServiceImpl( ...@@ -39,7 +40,8 @@ BlinkNotificationServiceImpl::BlinkNotificationServiceImpl(
resource_context_(resource_context), resource_context_(resource_context),
render_process_id_(render_process_id), render_process_id_(render_process_id),
origin_(origin), origin_(origin),
binding_(this, std::move(request)) { binding_(this, std::move(request)),
weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(notification_context_); DCHECK(notification_context_);
DCHECK(browser_context_); DCHECK(browser_context_);
...@@ -76,7 +78,8 @@ void BlinkNotificationServiceImpl::OnConnectionError() { ...@@ -76,7 +78,8 @@ void BlinkNotificationServiceImpl::OnConnectionError() {
void BlinkNotificationServiceImpl::DisplayNonPersistentNotification( void BlinkNotificationServiceImpl::DisplayNonPersistentNotification(
const PlatformNotificationData& platform_notification_data, const PlatformNotificationData& platform_notification_data,
const NotificationResources& notification_resources) { const NotificationResources& notification_resources,
blink::mojom::NonPersistentNotificationListenerPtr event_listener_ptr) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (!Service()) if (!Service())
return; return;
...@@ -92,13 +95,29 @@ void BlinkNotificationServiceImpl::DisplayNonPersistentNotification( ...@@ -92,13 +95,29 @@ void BlinkNotificationServiceImpl::DisplayNonPersistentNotification(
origin_.GetURL(), platform_notification_data.tag, request_id, origin_.GetURL(), platform_notification_data.tag, request_id,
render_process_id_); render_process_id_);
// Using base::Unretained is safe because Service() returns a singleton.
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, BrowserThread::UI, FROM_HERE,
base::BindOnce(&PlatformNotificationService::DisplayNotification, base::BindOnce(&BlinkNotificationServiceImpl::
base::Unretained(Service()), browser_context_, DisplayNonPersistentNotificationOnUIThread,
notification_id, origin_.GetURL(), weak_ptr_factory_.GetWeakPtr(), notification_id,
platform_notification_data, notification_resources)); origin_.GetURL(), platform_notification_data,
notification_resources,
event_listener_ptr.PassInterface()));
}
void BlinkNotificationServiceImpl::DisplayNonPersistentNotificationOnUIThread(
const std::string& notification_id,
const GURL& origin,
const content::PlatformNotificationData& notification_data,
const content::NotificationResources& notification_resources,
blink::mojom::NonPersistentNotificationListenerPtrInfo listener_ptr_info) {
NotificationEventDispatcherImpl* event_dispatcher =
NotificationEventDispatcherImpl::GetInstance();
event_dispatcher->RegisterNonPersistentNotificationListener(
notification_id, std::move(listener_ptr_info));
Service()->DisplayNotification(browser_context_, notification_id, origin,
notification_data, notification_resources);
} }
} // namespace content } // namespace content
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_NOTIFICATIONS_BLINK_NOTIFICATION_SERVICE_IMPL_H_ #define CONTENT_BROWSER_NOTIFICATIONS_BLINK_NOTIFICATION_SERVICE_IMPL_H_
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/interface_request.h"
...@@ -36,12 +37,20 @@ class BlinkNotificationServiceImpl : public blink::mojom::NotificationService { ...@@ -36,12 +37,20 @@ class BlinkNotificationServiceImpl : public blink::mojom::NotificationService {
void GetPermissionStatus(GetPermissionStatusCallback callback) override; void GetPermissionStatus(GetPermissionStatusCallback callback) override;
void DisplayNonPersistentNotification( void DisplayNonPersistentNotification(
const PlatformNotificationData& platform_notification_data, const PlatformNotificationData& platform_notification_data,
const NotificationResources& notification_resources) override; const NotificationResources& notification_resources,
blink::mojom::NonPersistentNotificationListenerPtr listener_ptr) override;
private: private:
// Called when an error is detected on binding_. // Called when an error is detected on binding_.
void OnConnectionError(); void OnConnectionError();
void DisplayNonPersistentNotificationOnUIThread(
const std::string& notification_id,
const GURL& origin,
const content::PlatformNotificationData& notification_data,
const content::NotificationResources& notification_resources,
blink::mojom::NonPersistentNotificationListenerPtrInfo listener_ptr_info);
// The notification context that owns this service instance. // The notification context that owns this service instance.
PlatformNotificationContextImpl* notification_context_; PlatformNotificationContextImpl* notification_context_;
...@@ -56,6 +65,8 @@ class BlinkNotificationServiceImpl : public blink::mojom::NotificationService { ...@@ -56,6 +65,8 @@ class BlinkNotificationServiceImpl : public blink::mojom::NotificationService {
mojo::Binding<blink::mojom::NotificationService> binding_; mojo::Binding<blink::mojom::NotificationService> binding_;
base::WeakPtrFactory<BlinkNotificationServiceImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BlinkNotificationServiceImpl); DISALLOW_COPY_AND_ASSIGN(BlinkNotificationServiceImpl);
}; };
......
...@@ -419,19 +419,54 @@ void NotificationEventDispatcherImpl::RegisterNonPersistentNotification( ...@@ -419,19 +419,54 @@ void NotificationEventDispatcherImpl::RegisterNonPersistentNotification(
int request_id) { int request_id) {
if (request_ids_.count(notification_id) && if (request_ids_.count(notification_id) &&
request_ids_[notification_id] != request_id) { request_ids_[notification_id] != request_id) {
// Notify close for a previously displayed notification with the same // Dispatch the close event for any previously displayed notification with
// request id, this can happen when replacing a non-persistent notification // the same notification id. This happens whenever a non-persistent
// with the same tag since from the JS point of view there will be two // notification is replaced (by creating another with the same tag), since
// notification objects and the old one needs to receive the close event. // from the JavaScript point of view there will be two notification objects,
// TODO(miguelg) this is probably not the right layer to do this. // and the old one needs to receive a close event before the new one
// receives a show event.
DispatchNonPersistentCloseEvent(notification_id); DispatchNonPersistentCloseEvent(notification_id);
} }
renderer_ids_[notification_id] = renderer_id; renderer_ids_[notification_id] = renderer_id;
request_ids_[notification_id] = request_id; request_ids_[notification_id] = request_id;
} }
void NotificationEventDispatcherImpl::RegisterNonPersistentNotificationListener(
const std::string& notification_id,
blink::mojom::NonPersistentNotificationListenerPtrInfo listener_ptr_info) {
if (non_persistent_notification_listeners_.count(notification_id)) {
// Dispatch the close event for any previously displayed notification with
// the same notification id. This happens whenever a non-persistent
// notification is replaced (by creating another with the same tag), since
// from the JavaScript point of view there will be two notification objects,
// and the old one needs to receive a close event before the new one
// receives a show event.
DispatchNonPersistentCloseEvent(notification_id);
}
blink::mojom::NonPersistentNotificationListenerPtr listener_ptr(
std::move(listener_ptr_info));
// Observe connection errors, which occur when the JavaScript object or the
// renderer hosting them goes away. (For example through navigation.) The
// listener gets freed together with |this|, thus the Unretained is safe.
listener_ptr.set_connection_error_handler(base::BindOnce(
&NotificationEventDispatcherImpl::
HandleConnectionErrorForNonPersistentNotificationListener,
base::Unretained(this), notification_id));
non_persistent_notification_listeners_.emplace(notification_id,
std::move(listener_ptr));
}
void NotificationEventDispatcherImpl::DispatchNonPersistentShowEvent( void NotificationEventDispatcherImpl::DispatchNonPersistentShowEvent(
const std::string& notification_id) { const std::string& notification_id) {
if (non_persistent_notification_listeners_.count(notification_id)) {
non_persistent_notification_listeners_[notification_id]->OnShow();
return;
}
// TODO(https://crbug.com/796990): Delete the legacy IPC code below, once
// fully migrated to mojo for non-persistent notifications.
if (!renderer_ids_.count(notification_id)) if (!renderer_ids_.count(notification_id))
return; return;
DCHECK(request_ids_.count(notification_id)); DCHECK(request_ids_.count(notification_id));
...@@ -447,6 +482,12 @@ void NotificationEventDispatcherImpl::DispatchNonPersistentShowEvent( ...@@ -447,6 +482,12 @@ void NotificationEventDispatcherImpl::DispatchNonPersistentShowEvent(
void NotificationEventDispatcherImpl::DispatchNonPersistentClickEvent( void NotificationEventDispatcherImpl::DispatchNonPersistentClickEvent(
const std::string& notification_id) { const std::string& notification_id) {
if (non_persistent_notification_listeners_.count(notification_id)) {
non_persistent_notification_listeners_[notification_id]->OnClick();
return;
}
// TODO(https://crbug.com/796990): Delete the legacy IPC code below, once
// fully migrated to mojo for non-persistent notifications.
if (!renderer_ids_.count(notification_id)) if (!renderer_ids_.count(notification_id))
return; return;
DCHECK(request_ids_.count(notification_id)); DCHECK(request_ids_.count(notification_id));
...@@ -465,6 +506,13 @@ void NotificationEventDispatcherImpl::DispatchNonPersistentClickEvent( ...@@ -465,6 +506,13 @@ void NotificationEventDispatcherImpl::DispatchNonPersistentClickEvent(
void NotificationEventDispatcherImpl::DispatchNonPersistentCloseEvent( void NotificationEventDispatcherImpl::DispatchNonPersistentCloseEvent(
const std::string& notification_id) { const std::string& notification_id) {
if (non_persistent_notification_listeners_.count(notification_id)) {
non_persistent_notification_listeners_[notification_id]->OnClose();
non_persistent_notification_listeners_.erase(notification_id);
return;
}
// TODO(https://crbug.com/796990): Delete the legacy IPC code below, once
// fully migrated to mojo for non-persistent notifications.
if (!renderer_ids_.count(notification_id)) if (!renderer_ids_.count(notification_id))
return; return;
DCHECK(request_ids_.count(notification_id)); DCHECK(request_ids_.count(notification_id));
...@@ -497,4 +545,11 @@ void NotificationEventDispatcherImpl::RendererGone(int renderer_id) { ...@@ -497,4 +545,11 @@ void NotificationEventDispatcherImpl::RendererGone(int renderer_id) {
} }
} }
void NotificationEventDispatcherImpl::
HandleConnectionErrorForNonPersistentNotificationListener(
const std::string& notification_id) {
DCHECK(non_persistent_notification_listeners_.count(notification_id));
non_persistent_notification_listeners_.erase(notification_id);
}
} // namespace content } // namespace content
...@@ -9,12 +9,15 @@ ...@@ -9,12 +9,15 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "content/common/content_export.h"
#include "content/public/browser/notification_database_data.h" #include "content/public/browser/notification_database_data.h"
#include "content/public/browser/notification_event_dispatcher.h" #include "content/public/browser/notification_event_dispatcher.h"
#include "third_party/WebKit/public/platform/modules/notifications/notification_service.mojom.h"
namespace content { namespace content {
class NotificationEventDispatcherImpl : public NotificationEventDispatcher { class CONTENT_EXPORT NotificationEventDispatcherImpl
: public NotificationEventDispatcher {
public: public:
// Returns the instance of the NotificationEventDispatcherImpl. Must be called // Returns the instance of the NotificationEventDispatcherImpl. Must be called
// on the UI thread. // on the UI thread.
...@@ -50,17 +53,34 @@ class NotificationEventDispatcherImpl : public NotificationEventDispatcher { ...@@ -50,17 +53,34 @@ class NotificationEventDispatcherImpl : public NotificationEventDispatcher {
int renderer_id, int renderer_id,
int request_id); int request_id);
// Registers |listener| to receive the show, click and close events of the
// non-persistent notification identified by |notification_id|.
void RegisterNonPersistentNotificationListener(
const std::string& notification_id,
blink::mojom::NonPersistentNotificationListenerPtrInfo listener_ptr_info);
private: private:
friend class NotificationEventDispatcherImplTest;
friend struct base::DefaultSingletonTraits<NotificationEventDispatcherImpl>;
NotificationEventDispatcherImpl(); NotificationEventDispatcherImpl();
~NotificationEventDispatcherImpl() override; ~NotificationEventDispatcherImpl() override;
// Removes all references to the listener registered to receive events
// from the non-persistent notification identified by |notification_id|.
// Should be called when the connection to this listener goes away.
void HandleConnectionErrorForNonPersistentNotificationListener(
const std::string& notification_id);
// Notification Id -> renderer Id. // Notification Id -> renderer Id.
std::map<std::string, int> renderer_ids_; std::map<std::string, int> renderer_ids_;
// Notification Id -> request Id. // Notification Id -> request Id.
std::map<std::string, int> request_ids_; std::map<std::string, int> request_ids_;
friend struct base::DefaultSingletonTraits<NotificationEventDispatcherImpl>; // Notification Id -> listener.
std::map<std::string, blink::mojom::NonPersistentNotificationListenerPtr>
non_persistent_notification_listeners_;
DISALLOW_COPY_AND_ASSIGN(NotificationEventDispatcherImpl); DISALLOW_COPY_AND_ASSIGN(NotificationEventDispatcherImpl);
}; };
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/notifications/notification_event_dispatcher_impl.h"
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/macros.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/modules/notifications/notification_service.mojom.h"
namespace content {
namespace {
const char kPrimaryUniqueId[] = "this_should_be_a_unique_id";
const char kSomeOtherUniqueId[] = "and_this_one_is_different_and_also_unique";
class TestNotificationListener
: public blink::mojom::NonPersistentNotificationListener {
public:
TestNotificationListener() : binding_(this) {}
~TestNotificationListener() override = default;
// Closes the bindings associated with this listener.
void Close() { binding_.Close(); }
// Returns an InterfacePtr to this listener.
blink::mojom::NonPersistentNotificationListenerPtr GetPtr() {
blink::mojom::NonPersistentNotificationListenerPtr ptr;
binding_.Bind(mojo::MakeRequest(&ptr));
return ptr;
}
// Returns the number of OnShow events received by this listener.
int on_show_count() const { return on_show_count_; }
// Returns the number of OnClick events received by this listener.
int on_click_count() const { return on_click_count_; }
// Returns the number of OnClose events received by this listener.
int on_close_count() const { return on_close_count_; }
// blink::mojom::NonPersistentNotificationListener implementation.
void OnShow() override { on_show_count_++; }
void OnClick() override { on_click_count_++; }
void OnClose() override { on_close_count_++; }
private:
int on_show_count_ = 0;
int on_click_count_ = 0;
int on_close_count_ = 0;
mojo::Binding<blink::mojom::NonPersistentNotificationListener> binding_;
DISALLOW_COPY_AND_ASSIGN(TestNotificationListener);
};
} // anonymous namespace
class NotificationEventDispatcherImplTest : public ::testing::Test {
public:
NotificationEventDispatcherImplTest()
: task_runner_(new base::TestSimpleTaskRunner),
handle_(task_runner_),
dispatcher_(new NotificationEventDispatcherImpl()) {}
~NotificationEventDispatcherImplTest() override { delete dispatcher_; }
// Waits until the task runner managing the Mojo connection has finished.
void WaitForMojoTasksToComplete() { task_runner_->RunUntilIdle(); }
protected:
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle handle_;
// Using a raw pointer because NotificationEventDispatcherImpl is a singleton
// with private constructor and destructor, so unique_ptr is not an option.
NotificationEventDispatcherImpl* dispatcher_;
private:
DISALLOW_COPY_AND_ASSIGN(NotificationEventDispatcherImplTest);
};
TEST_F(NotificationEventDispatcherImplTest,
DispatchNonPersistentShowEvent_NotifiesCorrectRegisteredListener) {
auto listener = std::make_unique<TestNotificationListener>();
dispatcher_->RegisterNonPersistentNotificationListener(
kPrimaryUniqueId, listener->GetPtr().PassInterface());
auto other_listener = std::make_unique<TestNotificationListener>();
dispatcher_->RegisterNonPersistentNotificationListener(
kSomeOtherUniqueId, other_listener->GetPtr().PassInterface());
dispatcher_->DispatchNonPersistentShowEvent(kPrimaryUniqueId);
WaitForMojoTasksToComplete();
EXPECT_EQ(listener->on_show_count(), 1);
EXPECT_EQ(other_listener->on_show_count(), 0);
dispatcher_->DispatchNonPersistentShowEvent(kSomeOtherUniqueId);
WaitForMojoTasksToComplete();
EXPECT_EQ(listener->on_show_count(), 1);
EXPECT_EQ(other_listener->on_show_count(), 1);
}
TEST_F(NotificationEventDispatcherImplTest,
RegisterReplacementNonPersistentListener_FirstListenerGetsOnClose) {
auto original_listener = std::make_unique<TestNotificationListener>();
dispatcher_->RegisterNonPersistentNotificationListener(
kPrimaryUniqueId, original_listener->GetPtr().PassInterface());
dispatcher_->DispatchNonPersistentShowEvent(kPrimaryUniqueId);
ASSERT_EQ(original_listener->on_close_count(), 0);
auto replacement_listener = std::make_unique<TestNotificationListener>();
dispatcher_->RegisterNonPersistentNotificationListener(
kPrimaryUniqueId, replacement_listener->GetPtr().PassInterface());
WaitForMojoTasksToComplete();
EXPECT_EQ(original_listener->on_close_count(), 1);
EXPECT_EQ(replacement_listener->on_close_count(), 0);
}
TEST_F(NotificationEventDispatcherImplTest,
DispatchNonPersistentClickEvent_NotifiesCorrectRegisteredListener) {
auto listener = std::make_unique<TestNotificationListener>();
dispatcher_->RegisterNonPersistentNotificationListener(
kPrimaryUniqueId, listener->GetPtr().PassInterface());
auto other_listener = std::make_unique<TestNotificationListener>();
dispatcher_->RegisterNonPersistentNotificationListener(
kSomeOtherUniqueId, other_listener->GetPtr().PassInterface());
dispatcher_->DispatchNonPersistentClickEvent(kPrimaryUniqueId);
WaitForMojoTasksToComplete();
EXPECT_EQ(listener->on_click_count(), 1);
EXPECT_EQ(other_listener->on_click_count(), 0);
dispatcher_->DispatchNonPersistentClickEvent(kSomeOtherUniqueId);
WaitForMojoTasksToComplete();
EXPECT_EQ(listener->on_click_count(), 1);
EXPECT_EQ(other_listener->on_click_count(), 1);
}
TEST_F(NotificationEventDispatcherImplTest,
DispatchNonPersistentCloseEvent_NotifiesCorrectRegisteredListener) {
auto listener = std::make_unique<TestNotificationListener>();
dispatcher_->RegisterNonPersistentNotificationListener(
kPrimaryUniqueId, listener->GetPtr().PassInterface());
auto other_listener = std::make_unique<TestNotificationListener>();
dispatcher_->RegisterNonPersistentNotificationListener(
kSomeOtherUniqueId, other_listener->GetPtr().PassInterface());
dispatcher_->DispatchNonPersistentCloseEvent(kPrimaryUniqueId);
WaitForMojoTasksToComplete();
EXPECT_EQ(listener->on_close_count(), 1);
EXPECT_EQ(other_listener->on_close_count(), 0);
dispatcher_->DispatchNonPersistentCloseEvent(kSomeOtherUniqueId);
WaitForMojoTasksToComplete();
EXPECT_EQ(listener->on_close_count(), 1);
EXPECT_EQ(other_listener->on_close_count(), 1);
}
TEST_F(NotificationEventDispatcherImplTest,
DispatchMultipleNonPersistentEvents_StopsNotifyingAfterClose) {
auto listener = std::make_unique<TestNotificationListener>();
dispatcher_->RegisterNonPersistentNotificationListener(
kPrimaryUniqueId, listener->GetPtr().PassInterface());
dispatcher_->DispatchNonPersistentShowEvent(kPrimaryUniqueId);
dispatcher_->DispatchNonPersistentClickEvent(kPrimaryUniqueId);
dispatcher_->DispatchNonPersistentCloseEvent(kPrimaryUniqueId);
WaitForMojoTasksToComplete();
EXPECT_EQ(listener->on_show_count(), 1);
EXPECT_EQ(listener->on_click_count(), 1);
EXPECT_EQ(listener->on_close_count(), 1);
// Should not be counted as the notification was already closed.
dispatcher_->DispatchNonPersistentClickEvent(kPrimaryUniqueId);
WaitForMojoTasksToComplete();
EXPECT_EQ(listener->on_click_count(), 1);
}
} // namespace content
...@@ -1343,6 +1343,7 @@ test("content_unittests") { ...@@ -1343,6 +1343,7 @@ test("content_unittests") {
"../browser/notification_service_impl_unittest.cc", "../browser/notification_service_impl_unittest.cc",
"../browser/notifications/notification_database_data_unittest.cc", "../browser/notifications/notification_database_data_unittest.cc",
"../browser/notifications/notification_database_unittest.cc", "../browser/notifications/notification_database_unittest.cc",
"../browser/notifications/notification_event_dispatcher_impl_unittest.cc",
"../browser/notifications/notification_id_generator_unittest.cc", "../browser/notifications/notification_id_generator_unittest.cc",
"../browser/notifications/platform_notification_context_unittest.cc", "../browser/notifications/platform_notification_context_unittest.cc",
"../browser/origin_manifest/origin_manifest_parser_unittest.cc", "../browser/origin_manifest/origin_manifest_parser_unittest.cc",
......
...@@ -1667,23 +1667,10 @@ crbug.com/711529 http/tests/workers/shared-worker-performance-timeline.html [ Ti ...@@ -1667,23 +1667,10 @@ crbug.com/711529 http/tests/workers/shared-worker-performance-timeline.html [ Ti
crbug.com/758385 http/tests/performance-timing/custom-user-timing/po-customusertiming-mark.html [ Skip ] crbug.com/758385 http/tests/performance-timing/custom-user-timing/po-customusertiming-mark.html [ Skip ]
# Expected failures during incremental implementation of mojo notification. # Expected failures during incremental implementation of mojo notification.
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/click-dedicated-worker.html [ Skip ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/click-document.html [ Skip ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/click-shared-worker.html [ Skip ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/click-window-focus-document.html [ Skip ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/close-dedicated-worker.html [ Skip ] crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/close-dedicated-worker.html [ Skip ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/close-dispatch-asynchronous.html [ Skip ] crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/close-dispatch-asynchronous.html [ Skip ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/close-document.html [ Skip ] crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/close-document.html [ Skip ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/close-shared-worker.html [ Skip ] crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/close-shared-worker.html [ Skip ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/request-permission-granted.html [ Timeout ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/serviceworkerregistration-page-notification-fetch-resources.html [ Timeout ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/show-dedicated-worker.html [ Timeout ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/show-document.html [ Timeout ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/show-shared-worker.html [ Timeout ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/update-dedicated-worker.html [ Timeout ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/update-document.html [ Timeout ]
crbug.com/595685 virtual/mojo-notifications/http/tests/notifications/update-shared-worker.html [ Timeout ]
crbug.com/713587 external/wpt/css/css-ui/caret-color-006.html [ Skip ] crbug.com/713587 external/wpt/css/css-ui/caret-color-006.html [ Skip ]
......
...@@ -7,5 +7,6 @@ include_rules = [ ...@@ -7,5 +7,6 @@ include_rules = [
"+modules/permissions", "+modules/permissions",
"+modules/serviceworkers", "+modules/serviceworkers",
"+modules/vibration", "+modules/vibration",
"+mojo/public/cpp/bindings",
"+skia/ext", "+skia/ext",
] ]
...@@ -154,7 +154,8 @@ Notification::Notification(ExecutionContext* context, ...@@ -154,7 +154,8 @@ Notification::Notification(ExecutionContext* context,
: ContextLifecycleObserver(context), : ContextLifecycleObserver(context),
type_(type), type_(type),
state_(State::kLoading), state_(State::kLoading),
data_(data) { data_(data),
listener_binding_(this) {
DCHECK(GetWebNotificationManager()); DCHECK(GetWebNotificationManager());
} }
...@@ -196,8 +197,12 @@ void Notification::DidLoadResources(NotificationResourcesLoader* loader) { ...@@ -196,8 +197,12 @@ void Notification::DidLoadResources(NotificationResourcesLoader* loader) {
DCHECK(origin); DCHECK(origin);
if (RuntimeEnabledFeatures::NotificationsWithMojoEnabled()) { if (RuntimeEnabledFeatures::NotificationsWithMojoEnabled()) {
mojom::blink::NonPersistentNotificationListenerPtr event_listener;
listener_binding_.Bind(mojo::MakeRequest(&event_listener));
NotificationManager::From(execution_context) NotificationManager::From(execution_context)
->DisplayNonPersistentNotification(data_, loader->GetResources()); ->DisplayNonPersistentNotification(data_, loader->GetResources(),
std::move(event_listener));
} else { } else {
GetWebNotificationManager()->Show(WebSecurityOrigin(origin), data_, GetWebNotificationManager()->Show(WebSecurityOrigin(origin), data_,
loader->GetResources(), this); loader->GetResources(), this);
...@@ -214,17 +219,17 @@ void Notification::close() { ...@@ -214,17 +219,17 @@ void Notification::close() {
// Schedule the "close" event to be fired for non-persistent notifications. // Schedule the "close" event to be fired for non-persistent notifications.
// Persistent notifications won't get such events for programmatic closes. // Persistent notifications won't get such events for programmatic closes.
if (type_ == Type::kNonPersistent) { if (type_ == Type::kNonPersistent) {
if (RuntimeEnabledFeatures::NotificationsWithMojoEnabled()) {
// TODO(crbug.com/796990): Implement Close path via Mojo.
return;
}
GetExecutionContext() GetExecutionContext()
->GetTaskRunner(TaskType::kUserInteraction) ->GetTaskRunner(TaskType::kUserInteraction)
->PostTask(FROM_HERE, WTF::Bind(&Notification::DispatchCloseEvent, ->PostTask(FROM_HERE, WTF::Bind(&Notification::DispatchCloseEvent,
WrapPersistent(this))); WrapPersistent(this)));
state_ = State::kClosing; state_ = State::kClosing;
if (RuntimeEnabledFeatures::NotificationsWithMojoEnabled()) { GetWebNotificationManager()->Close(this);
// TODO(crbug.com/595685): Implement Close path via Mojo.
} else {
GetWebNotificationManager()->Close(this);
}
return; return;
} }
...@@ -237,6 +242,18 @@ void Notification::close() { ...@@ -237,6 +242,18 @@ void Notification::close() {
data_.tag, notification_id_); data_.tag, notification_id_);
} }
void Notification::OnShow() {
DispatchShowEvent();
}
void Notification::OnClick() {
DispatchClickEvent();
}
void Notification::OnClose() {
DispatchCloseEvent();
}
void Notification::DispatchShowEvent() { void Notification::DispatchShowEvent() {
DispatchEvent(Event::Create(EventTypeNames::show)); DispatchEvent(Event::Create(EventTypeNames::show));
} }
...@@ -458,6 +475,8 @@ const AtomicString& Notification::InterfaceName() const { ...@@ -458,6 +475,8 @@ const AtomicString& Notification::InterfaceName() const {
} }
void Notification::ContextDestroyed(ExecutionContext*) { void Notification::ContextDestroyed(ExecutionContext*) {
listener_binding_.Close();
GetWebNotificationManager()->NotifyDelegateDestroyed(this); GetWebNotificationManager()->NotifyDelegateDestroyed(this);
state_ = State::kClosed; state_ = State::kClosed;
......
...@@ -40,11 +40,13 @@ ...@@ -40,11 +40,13 @@
#include "modules/EventTargetModules.h" #include "modules/EventTargetModules.h"
#include "modules/ModulesExport.h" #include "modules/ModulesExport.h"
#include "modules/vibration/NavigatorVibration.h" #include "modules/vibration/NavigatorVibration.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "platform/AsyncMethodRunner.h" #include "platform/AsyncMethodRunner.h"
#include "platform/heap/Handle.h" #include "platform/heap/Handle.h"
#include "platform/weborigin/KURL.h" #include "platform/weborigin/KURL.h"
#include "public/platform/modules/notifications/WebNotificationData.h" #include "public/platform/modules/notifications/WebNotificationData.h"
#include "public/platform/modules/notifications/WebNotificationDelegate.h" #include "public/platform/modules/notifications/WebNotificationDelegate.h"
#include "public/platform/modules/notifications/notification_service.mojom-blink.h"
#include "public/platform/modules/permissions/permission.mojom-blink.h" #include "public/platform/modules/permissions/permission.mojom-blink.h"
#include "public/platform/modules/permissions/permission_status.mojom-blink.h" #include "public/platform/modules/permissions/permission_status.mojom-blink.h"
...@@ -60,7 +62,8 @@ class MODULES_EXPORT Notification final ...@@ -60,7 +62,8 @@ class MODULES_EXPORT Notification final
: public EventTargetWithInlineData, : public EventTargetWithInlineData,
public ActiveScriptWrappable<Notification>, public ActiveScriptWrappable<Notification>,
public ContextLifecycleObserver, public ContextLifecycleObserver,
public WebNotificationDelegate { public WebNotificationDelegate,
public mojom::blink::NonPersistentNotificationListener {
USING_GARBAGE_COLLECTED_MIXIN(Notification); USING_GARBAGE_COLLECTED_MIXIN(Notification);
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
...@@ -89,6 +92,11 @@ class MODULES_EXPORT Notification final ...@@ -89,6 +92,11 @@ class MODULES_EXPORT Notification final
DEFINE_ATTRIBUTE_EVENT_LISTENER(error); DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
DEFINE_ATTRIBUTE_EVENT_LISTENER(close); DEFINE_ATTRIBUTE_EVENT_LISTENER(close);
// NonPersistentNotificationListener interface.
void OnShow() override;
void OnClick() override;
void OnClose() override;
// WebNotificationDelegate interface. // WebNotificationDelegate interface.
void DispatchShowEvent() override; void DispatchShowEvent() override;
void DispatchClickEvent() override; void DispatchClickEvent() override;
...@@ -179,6 +187,9 @@ class MODULES_EXPORT Notification final ...@@ -179,6 +187,9 @@ class MODULES_EXPORT Notification final
Member<AsyncMethodRunner<Notification>> prepare_show_method_runner_; Member<AsyncMethodRunner<Notification>> prepare_show_method_runner_;
Member<NotificationResourcesLoader> loader_; Member<NotificationResourcesLoader> loader_;
mojo::Binding<mojom::blink::NonPersistentNotificationListener>
listener_binding_;
}; };
} // namespace blink } // namespace blink
......
...@@ -111,10 +111,11 @@ void NotificationManager::OnPermissionServiceConnectionError() { ...@@ -111,10 +111,11 @@ void NotificationManager::OnPermissionServiceConnectionError() {
void NotificationManager::DisplayNonPersistentNotification( void NotificationManager::DisplayNonPersistentNotification(
const WebNotificationData& notification_data, const WebNotificationData& notification_data,
std::unique_ptr<WebNotificationResources> notification_resources) { std::unique_ptr<WebNotificationResources> notification_resources,
mojom::blink::NonPersistentNotificationListenerPtr event_listener) {
DCHECK(notification_resources); DCHECK(notification_resources);
GetNotificationService()->DisplayNonPersistentNotification( GetNotificationService()->DisplayNonPersistentNotification(
notification_data, *notification_resources); notification_data, *notification_resources, std::move(event_listener));
} }
const mojom::blink::NotificationServicePtr& const mojom::blink::NotificationServicePtr&
......
...@@ -46,7 +46,8 @@ class NotificationManager final ...@@ -46,7 +46,8 @@ class NotificationManager final
// Shows a notification that is not tied to any service worker. // Shows a notification that is not tied to any service worker.
void DisplayNonPersistentNotification( void DisplayNonPersistentNotification(
const WebNotificationData&, const WebNotificationData&,
std::unique_ptr<WebNotificationResources>); std::unique_ptr<WebNotificationResources>,
mojom::blink::NonPersistentNotificationListenerPtr);
virtual void Trace(blink::Visitor*); virtual void Trace(blink::Visitor*);
......
...@@ -8,6 +8,19 @@ import "mojo/common/string16.mojom"; ...@@ -8,6 +8,19 @@ import "mojo/common/string16.mojom";
import "third_party/WebKit/public/platform/modules/notifications/notification.mojom"; import "third_party/WebKit/public/platform/modules/notifications/notification.mojom";
import "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom"; import "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom";
// Interface for receiving events relating to non-persistent notifications.
interface NonPersistentNotificationListener {
// Called when the notification has been shown.
OnShow();
// Called when the notification was clicked upon.
OnClick();
// Called when the notification was closed; either programatically, or by the
// developer calling Notification.close().
OnClose();
};
// Service through which Blink can request notifications to be shown, closed or // Service through which Blink can request notifications to be shown, closed or
// retrieved from the embedder. // retrieved from the embedder.
interface NotificationService { interface NotificationService {
...@@ -17,7 +30,9 @@ interface NotificationService { ...@@ -17,7 +30,9 @@ interface NotificationService {
[Sync] GetPermissionStatus() => (PermissionStatus status); [Sync] GetPermissionStatus() => (PermissionStatus status);
// Shows a notification that is not associated with a service worker. // Shows a notification that is not associated with a service worker.
// Notifies |event_listener| when the notification is shown/clicked/closed.
DisplayNonPersistentNotification( DisplayNonPersistentNotification(
NotificationData notification_data, NotificationData notification_data,
NotificationResources notification_resources); NotificationResources notification_resources,
NonPersistentNotificationListener event_listener);
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment