Commit 108f6589 authored by Anita Woodruff's avatar Anita Woodruff Committed by Commit Bot

[Notifications] Implement GetNotifications via mojo

- Now when the '--enable-features=NotificationsWithMojo' flag is set,
  ServiceWorkerRegistration.getNotifications() will be routed through
  the notification mojo service, instead of via legacy IPC.

R=peter@chromium.org

Bug: 796991
Change-Id: Ie3d24ae753238da90c316187a4f2b84b4b52d531
Reviewed-on: https://chromium-review.googlesource.com/976222
Commit-Queue: Anita Woodruff <awdf@chromium.org>
Reviewed-by: default avatarOliver Chang <ochang@chromium.org>
Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#550372}
parent b89fef49
......@@ -1053,3 +1053,62 @@ IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest,
display_service_tester_->GetMetadataForNotification(notifications[0]))
->service_worker_scope);
}
IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceMojoEnabledBrowserTest,
GetDisplayedNotifications) {
RequestAndAcceptPermission();
std::string script_result;
std::string script_message;
ASSERT_TRUE(RunScript("DisplayNonPersistentNotification('NonPersistent')",
&script_result));
EXPECT_EQ("ok", script_result);
ASSERT_TRUE(RunScript("DisplayPersistentNotification('PersistentI')",
&script_result));
EXPECT_EQ("ok", script_result);
ASSERT_TRUE(RunScript("DisplayPersistentNotification('PersistentII')",
&script_result));
EXPECT_EQ("ok", script_result);
// Only the persistent ones should show.
ASSERT_TRUE(RunScript("GetDisplayedNotifications()", &script_result));
EXPECT_EQ("ok", script_result);
ASSERT_TRUE(RunScript("GetMessageFromWorker()", &script_message));
std::vector<std::string> notification_ids = base::SplitString(
script_message, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
ASSERT_EQ(2u, notification_ids.size());
const std::string first_id = notification_ids[0];
std::vector<message_center::Notification> notifications =
GetDisplayedNotifications(true /* is_persistent */);
ASSERT_EQ(notification_ids.size(), notifications.size());
// Now remove one of the notifications straight from the ui manager
// without going through the database.
const message_center::Notification& notification = notifications[1];
// p# is the prefix for persistent notifications. See
// content/browser/notifications/notification_id_generator.{h,cc} for details
ASSERT_TRUE(
base::StartsWith(notification.id(), "p#", base::CompareCase::SENSITIVE));
display_service_tester_->RemoveNotification(
NotificationHandler::Type::WEB_PERSISTENT, notification.id(),
false /* by_user */, true /* silent */);
ASSERT_TRUE(RunScript("GetDisplayedNotifications()", &script_result));
EXPECT_EQ("ok", script_result);
ASSERT_TRUE(RunScript("GetMessageFromWorker()", &script_message));
notification_ids = base::SplitString(
script_message, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
// The list of displayed notification Ids should have been updated.
ASSERT_EQ(1u, notification_ids.size());
ASSERT_EQ(notification_ids[0], first_id);
}
......@@ -245,4 +245,46 @@ void BlinkNotificationServiceImpl::
std::move(callback).Run(blink::mojom::PersistentNotificationError::NONE);
}
void BlinkNotificationServiceImpl::GetNotifications(
int64_t service_worker_registration_id,
const std::string& filter_tag,
GetNotificationsCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (CheckPermissionStatus() != blink::mojom::PermissionStatus::GRANTED) {
// No permission has been granted for the given origin. It is harmless to
// try to get notifications without permission, so return empty vectors
// indicating that no (accessible) notifications exist at this time.
std::move(callback).Run(std::vector<std::string>(),
std::vector<PlatformNotificationData>());
return;
}
notification_context_->ReadAllNotificationDataForServiceWorkerRegistration(
origin_.GetURL(), service_worker_registration_id,
base::AdaptCallbackForRepeating(base::BindOnce(
&BlinkNotificationServiceImpl::DidGetNotifications,
weak_ptr_factory_.GetWeakPtr(), filter_tag, std::move(callback))));
}
void BlinkNotificationServiceImpl::DidGetNotifications(
const std::string& filter_tag,
GetNotificationsCallback callback,
bool success,
const std::vector<NotificationDatabaseData>& notifications) {
std::vector<std::string> ids;
std::vector<PlatformNotificationData> datas;
for (const NotificationDatabaseData& database_data : notifications) {
// An empty filter tag matches all, else we need an exact match.
if (filter_tag.empty() ||
filter_tag == database_data.notification_data.tag) {
ids.push_back(database_data.notification_id);
datas.push_back(database_data.notification_data);
}
}
std::move(callback).Run(ids, datas);
}
} // namespace content
......@@ -17,6 +17,7 @@
namespace content {
struct NotificationDatabaseData;
class PlatformNotificationContextImpl;
struct PlatformNotificationData;
class ResourceContext;
......@@ -50,6 +51,9 @@ class CONTENT_EXPORT BlinkNotificationServiceImpl
const PlatformNotificationData& platform_notification_data,
const NotificationResources& notification_resources,
DisplayPersistentNotificationCallback) override;
void GetNotifications(int64_t service_worker_registration_id,
const std::string& filter_tag,
GetNotificationsCallback callback) override;
private:
// Called when an error is detected on binding_.
......@@ -83,6 +87,12 @@ class CONTENT_EXPORT BlinkNotificationServiceImpl
blink::mojom::PermissionStatus CheckPermissionStatus();
void DidGetNotifications(
const std::string& filter_tag,
GetNotificationsCallback callback,
bool success,
const std::vector<NotificationDatabaseData>& notifications);
// The notification context that owns this service instance.
PlatformNotificationContextImpl* notification_context_;
......
......@@ -204,6 +204,14 @@ class BlinkNotificationServiceImplTest : public ::testing::Test {
std::move(quit_closure).Run();
}
void DidGetNotifications(
base::OnceClosure quit_closure,
const std::vector<std::string>& notification_ids,
const std::vector<PlatformNotificationData>& notification_datas) {
get_notifications_callback_result_ = notification_ids;
std::move(quit_closure).Run();
}
void DidGetDisplayedNotifications(
base::OnceClosure quit_closure,
std::unique_ptr<std::set<std::string>> notification_ids,
......@@ -213,17 +221,31 @@ class BlinkNotificationServiceImplTest : public ::testing::Test {
}
void DisplayPersistentNotificationSync(
int64_t service_worker_registration_id) {
int64_t service_worker_registration_id,
const PlatformNotificationData& platform_notification_data,
const NotificationResources& notification_resources) {
base::RunLoop run_loop;
notification_service_->DisplayPersistentNotification(
service_worker_registration_id, PlatformNotificationData(),
NotificationResources(),
service_worker_registration_id, platform_notification_data,
notification_resources,
base::BindOnce(
&BlinkNotificationServiceImplTest::DidDisplayPersistentNotification,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
}
std::vector<std::string> GetNotificationsSync(
int64_t service_worker_registration_id,
const std::string& filter_tag) {
base::RunLoop run_loop;
notification_service_->GetNotifications(
service_worker_registration_id, filter_tag,
base::BindOnce(&BlinkNotificationServiceImplTest::DidGetNotifications,
base::Unretained(this), run_loop.QuitClosure()));
run_loop.Run();
return get_notifications_callback_result_;
}
// Synchronous wrapper of
// PlatformNotificationService::GetDisplayedNotifications
std::set<std::string> GetDisplayedNotifications() {
......@@ -262,6 +284,8 @@ class BlinkNotificationServiceImplTest : public ::testing::Test {
std::set<std::string> get_displayed_callback_result_;
std::vector<std::string> get_notifications_callback_result_;
MockResourceContext resource_context_;
DISALLOW_COPY_AND_ASSIGN(BlinkNotificationServiceImplTest);
......@@ -335,7 +359,8 @@ TEST_F(BlinkNotificationServiceImplTest,
scoped_refptr<ServiceWorkerRegistration> registration;
RegisterServiceWorker(&registration);
DisplayPersistentNotificationSync(registration->id());
DisplayPersistentNotificationSync(
registration->id(), PlatformNotificationData(), NotificationResources());
EXPECT_EQ(blink::mojom::PersistentNotificationError::NONE,
display_persistent_callback_result_);
......@@ -353,7 +378,8 @@ TEST_F(BlinkNotificationServiceImplTest,
scoped_refptr<ServiceWorkerRegistration> registration;
RegisterServiceWorker(&registration);
DisplayPersistentNotificationSync(registration->id());
DisplayPersistentNotificationSync(
registration->id(), PlatformNotificationData(), NotificationResources());
EXPECT_EQ(blink::mojom::PersistentNotificationError::PERMISSION_DENIED,
display_persistent_callback_result_);
......@@ -371,13 +397,82 @@ TEST_F(BlinkNotificationServiceImplTest,
scoped_refptr<ServiceWorkerRegistration> registration;
RegisterServiceWorker(&registration);
DisplayPersistentNotificationSync(registration->id());
DisplayPersistentNotificationSync(
registration->id(), PlatformNotificationData(), NotificationResources());
DisplayPersistentNotificationSync(registration->id());
DisplayPersistentNotificationSync(
registration->id(), PlatformNotificationData(), NotificationResources());
// Wait for service to receive all the Display calls.
RunAllTasksUntilIdle();
EXPECT_EQ(2u, GetDisplayedNotifications().size());
}
TEST_F(BlinkNotificationServiceImplTest, GetNotifications) {
mock_platform_service_.SetPermission(blink::mojom::PermissionStatus::GRANTED);
scoped_refptr<ServiceWorkerRegistration> registration;
RegisterServiceWorker(&registration);
EXPECT_EQ(
0u, GetNotificationsSync(registration->id(), "" /* filter_tag */).size());
DisplayPersistentNotificationSync(
registration->id(), PlatformNotificationData(), NotificationResources());
// Wait for service to receive all the Display calls.
RunAllTasksUntilIdle();
EXPECT_EQ(
1u, GetNotificationsSync(registration->id(), "" /* filter_tag */).size());
}
TEST_F(BlinkNotificationServiceImplTest, GetNotificationsWithoutPermission) {
mock_platform_service_.SetPermission(blink::mojom::PermissionStatus::GRANTED);
scoped_refptr<ServiceWorkerRegistration> registration;
RegisterServiceWorker(&registration);
DisplayPersistentNotificationSync(
registration->id(), PlatformNotificationData(), NotificationResources());
// Wait for service to receive all the Display calls.
RunAllTasksUntilIdle();
mock_platform_service_.SetPermission(blink::mojom::PermissionStatus::DENIED);
EXPECT_EQ(
0u, GetNotificationsSync(registration->id(), "" /* filter_tag */).size());
}
TEST_F(BlinkNotificationServiceImplTest, GetNotificationsWithFilter) {
mock_platform_service_.SetPermission(blink::mojom::PermissionStatus::GRANTED);
scoped_refptr<ServiceWorkerRegistration> registration;
RegisterServiceWorker(&registration);
PlatformNotificationData platform_notification_data;
platform_notification_data.tag = "tagA";
PlatformNotificationData other_platform_notification_data;
other_platform_notification_data.tag = "tagB";
DisplayPersistentNotificationSync(
registration->id(), platform_notification_data, NotificationResources());
DisplayPersistentNotificationSync(registration->id(),
other_platform_notification_data,
NotificationResources());
// Wait for service to receive all the Display calls.
RunAllTasksUntilIdle();
EXPECT_EQ(2u, GetNotificationsSync(registration->id(), "").size());
EXPECT_EQ(1u, GetNotificationsSync(registration->id(), "tagA").size());
EXPECT_EQ(1u, GetNotificationsSync(registration->id(), "tagB").size());
EXPECT_EQ(0u, GetNotificationsSync(registration->id(), "tagC").size());
EXPECT_EQ(0u, GetNotificationsSync(registration->id(), "tag").size());
}
} // namespace content
......@@ -2190,17 +2190,9 @@ crbug.com/738493 http/tests/performance-timing/longtask-v2/longtask-v8compile.ht
crbug.com/738493 http/tests/performance-timing/longtask-v2/longtask-executescript.html [ Skip ]
# Expected failures during incremental implementation of mojo notification.
crbug.com/796991 virtual/mojo-notifications/http/tests/notifications/serviceworker-notification-properties.html [ Skip ]
crbug.com/796991 virtual/mojo-notifications/http/tests/notifications/serviceworkerregistration-document-close.html [ Skip ]
crbug.com/796991 virtual/mojo-notifications/http/tests/notifications/serviceworkerregistration-document-data-invalid.html [ Skip ]
crbug.com/796991 virtual/mojo-notifications/http/tests/notifications/serviceworkerregistration-get-close.html [ Skip ]
crbug.com/796991 virtual/mojo-notifications/http/tests/notifications/serviceworkerregistration-get-empty.html [ Skip ]
crbug.com/796991 virtual/mojo-notifications/http/tests/notifications/serviceworkerregistration-get-filter.html [ Skip ]
crbug.com/796991 virtual/mojo-notifications/http/tests/notifications/serviceworkerregistration-get-from-service-worker.html [ Skip ]
crbug.com/796991 virtual/mojo-notifications/http/tests/notifications/serviceworkerregistration-get-replacement.html [ Skip ]
crbug.com/796991 virtual/mojo-notifications/http/tests/notifications/serviceworkerregistration-get.html [ Skip ]
crbug.com/796991 virtual/mojo-notifications/http/tests/notifications/serviceworkerregistration-service-worker-get-filter.html [ Skip ]
crbug.com/796991 virtual/mojo-notifications/http/tests/notifications/serviceworkerregistration-service-worker-get.html [ Skip ]
crbug.com/713587 external/wpt/css/css-ui/caret-color-006.html [ Skip ]
......
......@@ -65,4 +65,21 @@ interface NotificationService {
NotificationResources notification_resources)
=> (PersistentNotificationError error);
// Retrieves currently-displayed persistent notifications for a given
// service worker registration (i.e. notifications shown via
// DisplayPersistentNotification which were not yet closed or replaced).
//
// If |filter_tag| is non-empty an exact-match filter is applied against
// the notification tag, so 0 or 1 notifications will be returned (because
// notifications with the same tag replace each other).
//
// If |filter_tag| is empty no filtering is applied, so multiple
// notifications may be returned.
//
// Returns parallel lists of notification ids and their corresponding data.
GetNotifications(
int64 service_worker_registration_id,
string filter_tag)
=> (array<string> notification_ids,
array<NotificationData> notification_datas);
};
......@@ -162,6 +162,35 @@ void NotificationManager::DidDisplayPersistentNotification(
NOTREACHED();
}
void NotificationManager::GetNotifications(
WebServiceWorkerRegistration* service_worker_registration,
const WebString& filter_tag,
std::unique_ptr<WebNotificationGetCallbacks> callbacks) {
GetNotificationService()->GetNotifications(
service_worker_registration->RegistrationId(), filter_tag,
WTF::Bind(&NotificationManager::DidGetNotifications, WrapPersistent(this),
std::move(callbacks)));
}
void NotificationManager::DidGetNotifications(
std::unique_ptr<WebNotificationGetCallbacks> callbacks,
const Vector<String>& notification_ids,
const Vector<WebNotificationData>& notification_datas) {
DCHECK_EQ(notification_ids.size(), notification_datas.size());
WebVector<WebPersistentNotificationInfo> notifications(
notification_ids.size());
for (size_t i = 0; i < notification_ids.size(); ++i) {
WebPersistentNotificationInfo notification_info;
notification_info.notification_id = notification_ids[i];
notification_info.data = notification_datas[i];
notifications[i] = notification_info;
}
callbacks->OnSuccess(notifications);
}
const mojom::blink::NotificationServicePtr&
NotificationManager::GetNotificationService() {
if (!notification_service_) {
......
......@@ -66,6 +66,15 @@ class NotificationManager final
std::unique_ptr<blink::WebNotificationResources> notification_resources,
std::unique_ptr<blink::WebNotificationShowCallbacks> callbacks);
// Asynchronously gets the persistent notifications belonging to the Service
// Worker Registration. If |filter_tag| is not an empty string, only the
// notification with the given tag will be considered. Will take ownership of
// the WebNotificationGetCallbacks object.
void GetNotifications(
WebServiceWorkerRegistration* service_worker_registration,
const WebString& filter_tag,
std::unique_ptr<WebNotificationGetCallbacks> callbacks);
virtual void Trace(blink::Visitor* visitor);
private:
......@@ -75,6 +84,11 @@ class NotificationManager final
std::unique_ptr<blink::WebNotificationShowCallbacks> callbacks,
mojom::blink::PersistentNotificationError error);
void DidGetNotifications(
std::unique_ptr<WebNotificationGetCallbacks> callbacks,
const Vector<String>& notification_ids,
const Vector<WebNotificationData>& notification_datas);
// Returns an initialized NotificationServicePtr. A connection will be
// established the first time this method is called.
const mojom::blink::NotificationServicePtr& GetNotificationService();
......
......@@ -124,7 +124,10 @@ ScriptPromise ServiceWorkerRegistrationNotifications::getNotifications(
resolver);
if (RuntimeEnabledFeatures::NotificationsWithMojoEnabled()) {
// TODO(https://crbug.com/796991): Implement this via mojo.
ExecutionContext* execution_context = ExecutionContext::From(script_state);
NotificationManager::From(execution_context)
->GetNotifications(registration.WebRegistration(), options.tag(),
std::move(callbacks));
} else {
WebNotificationManager* notification_manager =
Platform::Current()->GetWebNotificationManager();
......
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