summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpeter <peter@chromium.org>2015-04-17 06:52:23 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-17 13:52:40 +0000
commit08f04f149112e624606dda88d63951942348c5a4 (patch)
tree6d16853cbad5984981bf1305a2d79f89fd2c07d5
parent19fe7d34353d35464a6c31622fe4cdfb0d819022 (diff)
downloadchromium_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}
-rw-r--r--content/browser/notifications/notification_message_filter.cc40
-rw-r--r--content/browser/notifications/notification_message_filter.h11
-rw-r--r--content/browser/notifications/platform_notification_context_impl.cc57
-rw-r--r--content/browser/notifications/platform_notification_context_impl.h12
-rw-r--r--content/browser/notifications/platform_notification_context_unittest.cc83
-rw-r--r--content/public/browser/platform_notification_context.h16
-rw-r--r--tools/metrics/histograms/histograms.xml18
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, &notification_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),
+ &notification_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),
+ &notification_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>