diff options
author | peter <peter@chromium.org> | 2015-04-17 06:52:23 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-17 13:52:40 +0000 |
commit | 08f04f149112e624606dda88d63951942348c5a4 (patch) | |
tree | 6d16853cbad5984981bf1305a2d79f89fd2c07d5 | |
parent | 19fe7d34353d35464a6c31622fe4cdfb0d819022 (diff) | |
download | chromium_src-08f04f149112e624606dda88d63951942348c5a4.zip chromium_src-08f04f149112e624606dda88d63951942348c5a4.tar.gz chromium_src-08f04f149112e624606dda88d63951942348c5a4.tar.bz2 |
Implement the ability to get all notifications in Chromium.
This patch implements the SWR.getNotifications() API in Chromium,
by hooking it up to the Notification database. All functionality,
including the filter-by-tag option, are supported.
This CL is part of a two-sided patch:
[1] This CL.
[2] https://codereview.chromium.org/1056573002/
BUG=442143
Review URL: https://codereview.chromium.org/1057573002
Cr-Commit-Position: refs/heads/master@{#325626}
7 files changed, 228 insertions, 9 deletions
diff --git a/content/browser/notifications/notification_message_filter.cc b/content/browser/notifications/notification_message_filter.cc index 200dff0..622fd1e 100644 --- a/content/browser/notifications/notification_message_filter.cc +++ b/content/browser/notifications/notification_message_filter.cc @@ -175,14 +175,44 @@ void NotificationMessageFilter::OnGetNotifications( const GURL& origin, const std::string& filter_tag) { DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (GetPermissionForOriginOnIO(origin) != + blink::WebNotificationPermissionAllowed) { + // No permission has been granted for the given origin. It is harmless to + // try to get notifications without permission, so return an empty vector + // indicating that no (accessible) notifications exist at this time. + Send(new PlatformNotificationMsg_DidGetNotifications( + request_id, std::vector<PersistentNotificationInfo>())); + return; + } + + notification_context_->ReadAllNotificationDataForServiceWorkerRegistration( + origin, + service_worker_registration_id, + base::Bind(&NotificationMessageFilter::DidGetNotifications, + weak_factory_io_.GetWeakPtr(), + request_id, + filter_tag)); +} - // TODO(peter): Implement retrieval of persistent Web Notifications from the - // database. Reply with an empty vector until this has been implemented. - // Tracked in https://crbug.com/442143. +void NotificationMessageFilter::DidGetNotifications( + int request_id, + const std::string& filter_tag, + bool success, + const std::vector<NotificationDatabaseData>& notifications) { + std::vector<PersistentNotificationInfo> persistent_notifications; + for (const NotificationDatabaseData& database_data : notifications) { + if (!filter_tag.empty()) { + const std::string& tag = database_data.notification_data.tag; + if (tag != filter_tag) + continue; + } + + persistent_notifications.push_back(std::make_pair( + database_data.notification_id, database_data.notification_data)); + } Send(new PlatformNotificationMsg_DidGetNotifications( - request_id, - std::vector<PersistentNotificationInfo>())); + request_id, persistent_notifications)); } void NotificationMessageFilter::OnClosePlatformNotification( diff --git a/content/browser/notifications/notification_message_filter.h b/content/browser/notifications/notification_message_filter.h index 5eaed3c..c5ad0a4ac 100644 --- a/content/browser/notifications/notification_message_filter.h +++ b/content/browser/notifications/notification_message_filter.h @@ -10,6 +10,7 @@ #include "base/callback_forward.h" #include "base/memory/weak_ptr.h" #include "content/public/browser/browser_message_filter.h" +#include "content/public/browser/notification_database_data.h" #include "third_party/WebKit/public/platform/modules/notifications/WebNotificationPermission.h" class GURL; @@ -81,6 +82,16 @@ class NotificationMessageFilter : public BrowserMessageFilter { bool success, int64_t persistent_notification_id); + // Callback to be invoked when all notifications belonging to a Service Worker + // registration have been read from the database. The |success| argument + // indicates whether the data could be read successfully, whereas the actual + // notifications will be stored in |notifications|. + void DidGetNotifications( + int request_id, + const std::string& filter_tag, + bool success, + const std::vector<NotificationDatabaseData>& notifications); + // Callback to be invoked when the data associated with a persistent // notification has been removed by the database, unless an error occurred, // which will be indicated by |success|. diff --git a/content/browser/notifications/platform_notification_context_impl.cc b/content/browser/notifications/platform_notification_context_impl.cc index a4c04a5..db6f136 100644 --- a/content/browser/notifications/platform_notification_context_impl.cc +++ b/content/browser/notifications/platform_notification_context_impl.cc @@ -118,6 +118,58 @@ void PlatformNotificationContextImpl::DoReadNotificationData( base::Bind(callback, false /* success */, NotificationDatabaseData())); } +void PlatformNotificationContextImpl:: + ReadAllNotificationDataForServiceWorkerRegistration( + const GURL& origin, + int64_t service_worker_registration_id, + const ReadAllResultCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + LazyInitialize( + base::Bind(&PlatformNotificationContextImpl:: + DoReadAllNotificationDataForServiceWorkerRegistration, + this, origin, service_worker_registration_id, callback), + base::Bind(callback, + false /* success */, + std::vector<NotificationDatabaseData>())); +} + +void PlatformNotificationContextImpl:: + DoReadAllNotificationDataForServiceWorkerRegistration( + const GURL& origin, + int64_t service_worker_registration_id, + const ReadAllResultCallback& callback) { + DCHECK(task_runner_->RunsTasksOnCurrentThread()); + + std::vector<NotificationDatabaseData> notification_datas; + + NotificationDatabase::Status status = + database_->ReadAllNotificationDataForServiceWorkerRegistration( + origin, service_worker_registration_id, ¬ification_datas); + + UMA_HISTOGRAM_ENUMERATION("Notifications.Database.ReadForServiceWorkerResult", + status, NotificationDatabase::STATUS_COUNT); + + if (status == NotificationDatabase::STATUS_OK) { + BrowserThread::PostTask(BrowserThread::IO, + FROM_HERE, + base::Bind(callback, + true /* success */, + notification_datas)); + return; + } + + // Blow away the database if reading data failed due to corruption. + if (status == NotificationDatabase::STATUS_ERROR_CORRUPTED) + DestroyDatabase(); + + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(callback, + false /* success */, + std::vector<NotificationDatabaseData>())); +} + void PlatformNotificationContextImpl::WriteNotificationData( const GURL& origin, const NotificationDatabaseData& database_data, @@ -284,8 +336,9 @@ void PlatformNotificationContextImpl::OpenDatabase( if (DestroyDatabase()) { status = database_->Open(true /* create_if_missing */); - // TODO(peter): Record UMA on |status| for re-opening the database after - // corruption was detected. + UMA_HISTOGRAM_ENUMERATION( + "Notifications.Database.OpenAfterCorruptionResult", + status, NotificationDatabase::STATUS_COUNT); } } diff --git a/content/browser/notifications/platform_notification_context_impl.h b/content/browser/notifications/platform_notification_context_impl.h index 757d22e..e208324 100644 --- a/content/browser/notifications/platform_notification_context_impl.h +++ b/content/browser/notifications/platform_notification_context_impl.h @@ -62,6 +62,10 @@ class CONTENT_EXPORT PlatformNotificationContextImpl void DeleteNotificationData(int64_t notification_id, const GURL& origin, const DeleteResultCallback& callback) override; + void ReadAllNotificationDataForServiceWorkerRegistration( + const GURL& origin, + int64_t service_worker_registration_id, + const ReadAllResultCallback& callback) override; // ServiceWorkerContextObserver implementation. void OnRegistrationDeleted(int64_t registration_id, @@ -100,6 +104,14 @@ class CONTENT_EXPORT PlatformNotificationContextImpl const GURL& origin, const ReadResultCallback& callback); + // Actually reads all notification data from the database. Must only be + // called on the |task_runner_| thread. |callback| will be invoked on the + // IO thread when the operation has completed. + void DoReadAllNotificationDataForServiceWorkerRegistration( + const GURL& origin, + int64_t service_worker_registration_id, + const ReadAllResultCallback& callback); + // Actually writes the notification database to the database. Must only be // called on the |task_runner_| thread. |callback| will be invoked on the // IO thread when the operation has completed. diff --git a/content/browser/notifications/platform_notification_context_unittest.cc b/content/browser/notifications/platform_notification_context_unittest.cc index fc088c6..6dca0d0 100644 --- a/content/browser/notifications/platform_notification_context_unittest.cc +++ b/content/browser/notifications/platform_notification_context_unittest.cc @@ -20,6 +20,9 @@ namespace content { // Fake render process id to use in tests requiring one. const int kFakeRenderProcessId = 99; +// Fake Service Worker registration id to use in tests requiring one. +const int64_t kFakeServiceWorkerRegistrationId = 42; + class PlatformNotificationContextTest : public ::testing::Test { public: PlatformNotificationContextTest() @@ -64,6 +67,19 @@ class PlatformNotificationContextTest : public ::testing::Test { *store_status = status; } + // Callback to provide when reading multiple notifications from the database. + // Will store the success value in the class member, and write the read + // notification datas to |store_notification_datas|. + void DidReadAllNotificationDatas( + std::vector<NotificationDatabaseData>* store_notification_datas, + bool success, + const std::vector<NotificationDatabaseData>& notification_datas) { + DCHECK(store_notification_datas); + + success_ = success; + *store_notification_datas = notification_datas; + } + protected: // Creates a new PlatformNotificationContextImpl instance. When using this // method, the underlying database will always be created in memory. The @@ -352,4 +368,71 @@ TEST_F(PlatformNotificationContextTest, DestroyOnDiskDatabase) { EXPECT_TRUE(IsDirectoryEmpty(database_dir.path())); } +TEST_F(PlatformNotificationContextTest, ReadAllServiceWorkerDataEmpty) { + scoped_refptr<PlatformNotificationContextImpl> context = + CreatePlatformNotificationContext(); + + GURL origin("https://example.com"); + + std::vector<NotificationDatabaseData> notification_database_datas; + context->ReadAllNotificationDataForServiceWorkerRegistration( + origin, + kFakeServiceWorkerRegistrationId, + base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas, + base::Unretained(this), + ¬ification_database_datas)); + + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(success()); + EXPECT_EQ(0u, notification_database_datas.size()); +} + +TEST_F(PlatformNotificationContextTest, ReadAllServiceWorkerDataFilled) { + scoped_refptr<PlatformNotificationContextImpl> context = + CreatePlatformNotificationContext(); + + GURL origin("https://example.com"); + + NotificationDatabaseData notification_database_data; + notification_database_data.origin = origin; + notification_database_data.service_worker_registration_id = + kFakeServiceWorkerRegistrationId; + + // Insert ten notifications into the database belonging to origin and the + // test Service Worker Registration id. + for (int i = 0; i < 10; ++i) { + context->WriteNotificationData( + origin, + notification_database_data, + base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData, + base::Unretained(this))); + + base::RunLoop().RunUntilIdle(); + + ASSERT_TRUE(success()); + } + + // Now read the notifications from the database again. There should be ten, + // all set with the correct origin and Service Worker Registration id. + std::vector<NotificationDatabaseData> notification_database_datas; + context->ReadAllNotificationDataForServiceWorkerRegistration( + origin, + kFakeServiceWorkerRegistrationId, + base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas, + base::Unretained(this), + ¬ification_database_datas)); + + base::RunLoop().RunUntilIdle(); + + ASSERT_TRUE(success()); + ASSERT_EQ(10u, notification_database_datas.size()); + + for (int i = 0; i < 10; ++i) { + EXPECT_EQ(origin, notification_database_datas[i].origin); + EXPECT_EQ(kFakeServiceWorkerRegistrationId, + notification_database_datas[i].service_worker_registration_id); + } +} + } // namespace content diff --git a/content/public/browser/platform_notification_context.h b/content/public/browser/platform_notification_context.h index 660ff19..74dd471 100644 --- a/content/public/browser/platform_notification_context.h +++ b/content/public/browser/platform_notification_context.h @@ -6,15 +6,15 @@ #define CONTENT_PUBLIC_BROWSER_PLATFORM_NOTIFICATION_CONTEXT_H_ #include <stdint.h> +#include <vector> #include "base/callback.h" +#include "content/public/browser/notification_database_data.h" class GURL; namespace content { -struct NotificationDatabaseData; - // Represents the storage context for persistent Web Notifications, specific to // the storage partition owning the instance. All methods defined in this // interface may only be used on the IO thread. @@ -24,6 +24,10 @@ class PlatformNotificationContext { base::Callback<void(bool /* success */, const NotificationDatabaseData&)>; + using ReadAllResultCallback = + base::Callback<void(bool /* success */, + const std::vector<NotificationDatabaseData>&)>; + using WriteResultCallback = base::Callback<void(bool /* success */, int64_t /* notification_id */)>; @@ -37,6 +41,14 @@ class PlatformNotificationContext { const GURL& origin, const ReadResultCallback& callback) = 0; + // Reads all data associated with |service_worker_registration_id| belonging + // to |origin| from the database. |callback| will be invoked with the success + // status and a vector with all read notification data when completed. + virtual void ReadAllNotificationDataForServiceWorkerRegistration( + const GURL& origin, + int64_t service_worker_registration_id, + const ReadAllResultCallback& callback) = 0; + // Writes the data associated with a notification to a database. When this // action completed, |callback| will be invoked with the success status and // the persistent notification id when written successfully. diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 18b8e4a..4976ad2 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -24353,6 +24353,15 @@ Therefore, the affected-histogram name has to have at least one dot in it. </summary> </histogram> +<histogram name="Notifications.Database.OpenAfterCorruptionResult" + enum="NotificationDatabaseStatus"> + <owner>peter@chromium.org</owner> + <summary> + Records the result status codes of opening the Web Notification database + after it has been destroyed in response to data corruption. + </summary> +</histogram> + <histogram name="Notifications.Database.OpenResult" enum="NotificationDatabaseStatus"> <owner>peter@chromium.org</owner> @@ -24361,6 +24370,15 @@ Therefore, the affected-histogram name has to have at least one dot in it. </summary> </histogram> +<histogram name="Notifications.Database.ReadForServiceWorkerResult" + enum="NotificationDatabaseStatus"> + <owner>peter@chromium.org</owner> + <summary> + Records the result status codes of reading data of all notifications + associated with a Service Worker from the Web Notification database. + </summary> +</histogram> + <histogram name="Notifications.Database.ReadResult" enum="NotificationDatabaseStatus"> <owner>peter@chromium.org</owner> |