Make PlatformNotificationContext display all notifications.

This hands off the display call to PlatformNotificationContext which
gets rid of some code duplication as we always want to show a
notification after writing it into the NotificationDatabase.

Bug: 891339
Change-Id: If0787fcd9668cb0e419edcc16a56c91649983dcc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1511416
Reviewed-by: Avi Drissman <avi@chromium.org>
Reviewed-by: Peter Beverloo <peter@chromium.org>
Commit-Queue: Richard Knoll <knollr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#643370}
diff --git a/chrome/browser/push_messaging/push_messaging_notification_manager.cc b/chrome/browser/push_messaging/push_messaging_notification_manager.cc
index d99fb36..75096c2 100644
--- a/chrome/browser/push_messaging/push_messaging_notification_manager.cc
+++ b/chrome/browser/push_messaging/push_messaging_notification_manager.cc
@@ -270,30 +270,16 @@
       database_data,
       base::BindOnce(
           &PushMessagingNotificationManager::DidWriteNotificationData,
-          weak_factory_.GetWeakPtr(), origin, database_data.notification_data,
-          std::move(message_handled_closure)));
+          weak_factory_.GetWeakPtr(), std::move(message_handled_closure)));
 }
 
 void PushMessagingNotificationManager::DidWriteNotificationData(
-    const GURL& origin,
-    const blink::PlatformNotificationData& notification_data,
     base::OnceClosure message_handled_closure,
     bool success,
     const std::string& notification_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!success) {
+  if (!success)
     DLOG(ERROR) << "Writing forced notification to database should not fail";
-    std::move(message_handled_closure).Run();
-    return;
-  }
-
-  // Do not pass service worker scope. The origin will be used instead of the
-  // service worker scope to determine whether a notification should be
-  // attributed to a WebAPK on Android. This is OK because this code path is hit
-  // rarely.
-  PlatformNotificationServiceImpl::GetInstance()->DisplayPersistentNotification(
-      profile_, notification_id, GURL() /* service_worker_scope */, origin,
-      notification_data, blink::NotificationResources());
 
   std::move(message_handled_closure).Run();
 }
diff --git a/chrome/browser/push_messaging/push_messaging_notification_manager.h b/chrome/browser/push_messaging/push_messaging_notification_manager.h
index 626d82a..fe054ef0 100644
--- a/chrome/browser/push_messaging/push_messaging_notification_manager.h
+++ b/chrome/browser/push_messaging/push_messaging_notification_manager.h
@@ -25,11 +25,7 @@
 namespace content {
 struct NotificationDatabaseData;
 class WebContents;
-}
-
-namespace blink {
-struct PlatformNotificationData;
-}
+}  // namespace content
 
 // Developers may be required to display a Web Notification in response to an
 // incoming push message in order to clarify to the user that something has
@@ -82,12 +78,9 @@
                          base::OnceClosure message_handled_closure,
                          bool silent_push_allowed);
 
-  void DidWriteNotificationData(
-      const GURL& origin,
-      const blink::PlatformNotificationData& notification_data,
-      base::OnceClosure message_handled_closure,
-      bool success,
-      const std::string& notification_id);
+  void DidWriteNotificationData(base::OnceClosure message_handled_closure,
+                                bool success,
+                                const std::string& notification_id);
 
 #if defined(OS_CHROMEOS)
   bool ShouldSkipUserVisibleOnlyRequirements(const GURL& origin);
diff --git a/content/browser/notifications/blink_notification_service_impl.cc b/content/browser/notifications/blink_notification_service_impl.cc
index f251139..5f000b2 100644
--- a/content/browser/notifications/blink_notification_service_impl.cc
+++ b/content/browser/notifications/blink_notification_service_impl.cc
@@ -207,93 +207,26 @@
   database_data.origin = origin_.GetURL();
   database_data.service_worker_registration_id = service_worker_registration_id;
   database_data.notification_data = platform_notification_data;
+  database_data.notification_resources = notification_resources;
 
   // TODO(https://crbug.com/870258): Validate resources are not too big (either
   // here or in the mojo struct traits).
 
-  if (platform_notification_data.show_trigger_timestamp &&
-      base::FeatureList::IsEnabled(features::kNotificationTriggers)) {
-    // TODO(knollr): Let PlatformNotificationContext display all notifications,
-    // even non scheduled ones and always set resources here.
-    database_data.notification_resources = notification_resources;
-  }
-
   notification_context_->WriteNotificationData(
       next_persistent_id, service_worker_registration_id, origin_.GetURL(),
       database_data,
-      base::BindOnce(
-          &BlinkNotificationServiceImpl::DisplayPersistentNotificationWithId,
-          weak_factory_for_ui_.GetWeakPtr(), service_worker_registration_id,
-          platform_notification_data, notification_resources,
-          std::move(callback)));
+      base::BindOnce(&BlinkNotificationServiceImpl::DidWriteNotificationData,
+                     weak_factory_for_ui_.GetWeakPtr(), std::move(callback)));
 }
 
-void BlinkNotificationServiceImpl::DisplayPersistentNotificationWithId(
-    int64_t service_worker_registration_id,
-    const blink::PlatformNotificationData& platform_notification_data,
-    const blink::NotificationResources& notification_resources,
+void BlinkNotificationServiceImpl::DidWriteNotificationData(
     DisplayPersistentNotificationCallback callback,
     bool success,
     const std::string& notification_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!success) {
-    std::move(callback).Run(PersistentNotificationError::INTERNAL_ERROR);
-    return;
-  }
-
-  if (platform_notification_data.show_trigger_timestamp &&
-      base::FeatureList::IsEnabled(features::kNotificationTriggers)) {
-    // This notification will be handled by the |notification_context_| because
-    // it has to be scheduled rather than displayed immediately.
-    // TODO(knollr): Let PlatformNotificationContext display all notifications,
-    // even non scheduled ones to make this code path go away.
-    std::move(callback).Run(PersistentNotificationError::NONE);
-    return;
-  }
-
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::IO},
-      base::BindOnce(
-          &ServiceWorkerContextWrapper::FindReadyRegistrationForId,
-          service_worker_context_, service_worker_registration_id,
-          origin_.GetURL(),
-          base::BindOnce(
-              &BlinkNotificationServiceImpl::
-                  DisplayPersistentNotificationWithServiceWorkerOnIOThread,
-              weak_factory_for_io_.GetWeakPtr(), notification_id,
-              platform_notification_data, notification_resources,
-              std::move(callback))));
-}
-
-void BlinkNotificationServiceImpl::
-    DisplayPersistentNotificationWithServiceWorkerOnIOThread(
-        const std::string& notification_id,
-        const blink::PlatformNotificationData& platform_notification_data,
-        const blink::NotificationResources& notification_resources,
-        DisplayPersistentNotificationCallback callback,
-        blink::ServiceWorkerStatusCode service_worker_status,
-        scoped_refptr<ServiceWorkerRegistration> registration) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  PersistentNotificationError error =
-      PersistentNotificationError::INTERNAL_ERROR;
-
-  // Display the notification if the Service Worker's origin matches the origin
-  // of the notification's sender.
-  if (service_worker_status == blink::ServiceWorkerStatusCode::kOk &&
-      registration->scope().GetOrigin() == origin_.GetURL()) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(
-            &PlatformNotificationService::DisplayPersistentNotification,
-            base::Unretained(GetNotificationService()), browser_context_,
-            notification_id, registration->scope(), origin_.GetURL(),
-            platform_notification_data, notification_resources));
-
-    error = PersistentNotificationError::NONE;
-  }
-
-  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                           base::BindOnce(std::move(callback), error));
+  std::move(callback).Run(success
+                              ? PersistentNotificationError::NONE
+                              : PersistentNotificationError::INTERNAL_ERROR);
 }
 
 void BlinkNotificationServiceImpl::ClosePersistentNotification(
diff --git a/content/browser/notifications/blink_notification_service_impl.h b/content/browser/notifications/blink_notification_service_impl.h
index f816022..574b038 100644
--- a/content/browser/notifications/blink_notification_service_impl.h
+++ b/content/browser/notifications/blink_notification_service_impl.h
@@ -73,21 +73,9 @@
   bool ValidateNotificationResources(
       const blink::NotificationResources& notification_resources);
 
-  void DisplayPersistentNotificationWithId(
-      int64_t service_worker_registration_id,
-      const blink::PlatformNotificationData& platform_notification_data,
-      const blink::NotificationResources& notification_resources,
-      DisplayPersistentNotificationCallback callback,
-      bool success,
-      const std::string& notification_id);
-
-  void DisplayPersistentNotificationWithServiceWorkerOnIOThread(
-      const std::string& notification_id,
-      const blink::PlatformNotificationData& platform_notification_data,
-      const blink::NotificationResources& notification_resources,
-      DisplayPersistentNotificationCallback callback,
-      blink::ServiceWorkerStatusCode service_worker_status,
-      scoped_refptr<ServiceWorkerRegistration> registration);
+  void DidWriteNotificationData(DisplayPersistentNotificationCallback callback,
+                                bool success,
+                                const std::string& notification_id);
 
   void DidGetNotifications(
       const std::string& filter_tag,
diff --git a/content/browser/notifications/platform_notification_context_impl.cc b/content/browser/notifications/platform_notification_context_impl.cc
index 739a98f..5fd9ea9 100644
--- a/content/browser/notifications/platform_notification_context_impl.cc
+++ b/content/browser/notifications/platform_notification_context_impl.cc
@@ -495,7 +495,7 @@
     bool initialized) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   DCHECK(database_data.notification_id.empty());
-  if (!initialized) {
+  if (!initialized || !service_proxy_) {
     base::PostTaskWithTraits(
         FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE},
         base::BindOnce(std::move(callback), /* success= */ false,
@@ -552,6 +552,10 @@
     return;
   }
 
+  // Only store resources for notifications that will be scheduled.
+  if (!CanTrigger(write_database_data))
+    write_database_data.notification_resources = base::nullopt;
+
   NotificationDatabase::Status status =
       database_->WriteNotificationData(origin, write_database_data);
 
@@ -559,19 +563,27 @@
                             NotificationDatabase::STATUS_COUNT);
 
   if (status == NotificationDatabase::STATUS_OK) {
-    if (CanTrigger(write_database_data) && service_proxy_) {
+    if (CanTrigger(write_database_data)) {
       if (replaces_existing)
         service_proxy_->CloseNotification(notification_id);
+
       // Schedule notification to be shown.
       service_proxy_->ScheduleTrigger(
           write_database_data.notification_data.show_trigger_timestamp.value());
+
+      // Respond with success as this notification got scheduled successfully.
+      base::PostTaskWithTraits(
+          FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE},
+          base::BindOnce(std::move(callback), /* success= */ true,
+                         write_database_data.notification_id));
+      return;
     }
 
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE},
-        base::BindOnce(std::move(callback), /* success= */ true,
-                       write_database_data.notification_id));
-
+    // Display the notification immediately.
+    write_database_data.notification_resources =
+        database_data.notification_resources;
+    service_proxy_->DisplayNotification(std::move(write_database_data),
+                                        std::move(callback));
     return;
   }
 
diff --git a/content/browser/notifications/platform_notification_context_unittest.cc b/content/browser/notifications/platform_notification_context_unittest.cc
index 95ac6c16..f3c43b4 100644
--- a/content/browser/notifications/platform_notification_context_unittest.cc
+++ b/content/browser/notifications/platform_notification_context_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/notifications/platform_notification_context_impl.h"
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
@@ -115,6 +116,22 @@
     context->SetTaskRunnerForTesting(base::ThreadTaskRunnerHandle::Get());
   }
 
+  // Gets the currently displayed notifications from |service| synchronously.
+  std::set<std::string> GetDisplayedNotificationsSync(
+      PlatformNotificationService* service) {
+    std::set<std::string> displayed_notification_ids;
+    base::RunLoop run_loop;
+    service->GetDisplayedNotifications(
+        browser_context(),
+        base::BindLambdaForTesting(
+            [&](std::set<std::string> notification_ids, bool supports_sync) {
+              displayed_notification_ids = std::move(notification_ids);
+              run_loop.QuitClosure().Run();
+            }));
+    run_loop.Run();
+    return displayed_notification_ids;
+  }
+
   // Returns the testing browsing context that can be used for this test.
   BrowserContext* browser_context() { return &browser_context_; }
 
@@ -585,4 +602,35 @@
   EXPECT_FALSE(success());
 }
 
+TEST_F(PlatformNotificationContextTest, WriteDisplaysNotification) {
+  NotificationBrowserClient notification_browser_client;
+  SetBrowserClientForTesting(&notification_browser_client);
+
+  scoped_refptr<PlatformNotificationContextImpl> context =
+      CreatePlatformNotificationContext();
+
+  GURL origin("https://example.com");
+  NotificationDatabaseData notification_database_data;
+
+  context->WriteNotificationData(
+      next_persistent_notification_id(), kFakeServiceWorkerRegistrationId,
+      origin, notification_database_data,
+      base::BindOnce(&PlatformNotificationContextTest::DidWriteNotificationData,
+                     base::Unretained(this)));
+
+  base::RunLoop().RunUntilIdle();
+
+  // The write operation should have succeeded with a notification id.
+  ASSERT_TRUE(success());
+  EXPECT_FALSE(notification_id().empty());
+
+  // The written notification should be shown now.
+  std::set<std::string> displayed_notification_ids =
+      GetDisplayedNotificationsSync(
+          notification_browser_client.GetPlatformNotificationService());
+
+  ASSERT_EQ(1u, displayed_notification_ids.size());
+  EXPECT_EQ(notification_id(), *displayed_notification_ids.begin());
+}
+
 }  // namespace content
diff --git a/content/public/browser/platform_notification_context.h b/content/public/browser/platform_notification_context.h
index be8cfd6..dd3d703 100644
--- a/content/public/browser/platform_notification_context.h
+++ b/content/public/browser/platform_notification_context.h
@@ -90,10 +90,12 @@
       int64_t service_worker_registration_id,
       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 notification id when written successfully. The notification ID field
-  // for |database_data| will be generated, and thus must be empty.
+  // Writes the data associated with a notification to a database and displays
+  // it either immediately or at the desired time if the notification has a show
+  // trigger defined. When this action is completed, |callback| will be invoked
+  // with the success status and the notification id when written successfully.
+  // The notification ID field for |database_data| will be generated, and thus
+  // must be empty.
   virtual void WriteNotificationData(
       int64_t persistent_notification_id,
       int64_t service_worker_registration_id,