Bug 1265841 - Remove persistent notifications from storage. r?wchen draft
authorKit Cambridge <kcambridge@mozilla.com>
Wed, 20 Apr 2016 17:13:21 -0700
changeset 354496 86afae76dd987eeee4730781e4c4c1c59674dc38
parent 353712 ae7413abfa4d3954a6a4ce7c1613a7100f367f9a
child 354497 a474f3c09a63a897ed271cf8743d98d1e4166d58
push id16094
push userkcambridge@mozilla.com
push dateThu, 21 Apr 2016 00:47:23 +0000
reviewerswchen
bugs1265841
milestone48.0a1
Bug 1265841 - Remove persistent notifications from storage. r?wchen MozReview-Commit-ID: DmegHA1YVsB
dom/notification/Notification.cpp
dom/workers/test/serviceworkers/test_notification_get.html
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -1279,30 +1279,48 @@ NS_IMPL_ISUPPORTS_INHERITED0(WorkerNotif
 class ServiceWorkerNotificationObserver final : public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   ServiceWorkerNotificationObserver(const nsAString& aScope,
                                     nsIPrincipal* aPrincipal,
-                                    const nsAString& aID)
-    : mScope(aScope), mID(aID), mPrincipal(aPrincipal)
+                                    const nsAString& aID,
+                                    const nsAString& aTitle,
+                                    const nsAString& aDir,
+                                    const nsAString& aLang,
+                                    const nsAString& aBody,
+                                    const nsAString& aTag,
+                                    const nsAString& aIcon,
+                                    const nsAString& aData,
+                                    const nsAString& aBehavior)
+    : mScope(aScope), mID(aID), mPrincipal(aPrincipal), mTitle(aTitle)
+    , mDir(aDir), mLang(aLang), mBody(aBody), mTag(aTag), mIcon(aIcon)
+    , mData(aData), mBehavior(aBehavior)
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(aPrincipal);
   }
 
 private:
   ~ServiceWorkerNotificationObserver()
   {}
 
   const nsString mScope;
   const nsString mID;
   nsCOMPtr<nsIPrincipal> mPrincipal;
+  const nsString mTitle;
+  const nsString mDir;
+  const nsString mLang;
+  const nsString mBody;
+  const nsString mTag;
+  const nsString mIcon;
+  const nsString mData;
+  const nsString mBehavior;
 };
 
 NS_IMPL_ISUPPORTS(ServiceWorkerNotificationObserver, nsIObserver)
 
 // For ServiceWorkers.
 bool
 Notification::DispatchNotificationClickEvent()
 {
@@ -1549,112 +1567,61 @@ WorkerNotificationObserver::Observe(nsIS
 
   MOZ_ASSERT(r);
   if (!r->Dispatch()) {
     NS_WARNING("Could not dispatch event to worker notification");
   }
   return NS_OK;
 }
 
-class NotificationClickEventCallback final : public nsINotificationStorageCallback
+NS_IMETHODIMP
+ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
+                                           const char* aTopic,
+                                           const char16_t* aData)
 {
-public:
-  NS_DECL_ISUPPORTS
-
-  NotificationClickEventCallback(nsIPrincipal* aPrincipal,
-                                 const nsAString& aScope)
-  : mPrincipal(aPrincipal), mScope(aScope)
-  {
-    MOZ_ASSERT(aPrincipal);
-  }
+  AssertIsOnMainThread();
 
-  NS_IMETHOD Handle(const nsAString& aID,
-                    const nsAString& aTitle,
-                    const nsAString& aDir,
-                    const nsAString& aLang,
-                    const nsAString& aBody,
-                    const nsAString& aTag,
-                    const nsAString& aIcon,
-                    const nsAString& aData,
-                    const nsAString& aBehavior,
-                    const nsAString& aServiceWorkerRegistrationID) override
-  {
-    MOZ_ASSERT(!aID.IsEmpty());
-    MOZ_ASSERT(mScope.Equals(aServiceWorkerRegistrationID));
-
-    AssertIsOnMainThread();
-
+  if (!strcmp("alertclickcallback", aTopic)) {
     nsAutoCString originSuffix;
     nsresult rv = mPrincipal->GetOriginSuffix(originSuffix);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     nsCOMPtr<nsIServiceWorkerManager> swm =
       mozilla::services::GetServiceWorkerManager();
 
     if (swm) {
       swm->SendNotificationClickEvent(originSuffix,
                                       NS_ConvertUTF16toUTF8(mScope),
-                                      aID,
-                                      aTitle,
-                                      aDir,
-                                      aLang,
-                                      aBody,
-                                      aTag,
-                                      aIcon,
-                                      aData,
-                                      aBehavior);
+                                      mID,
+                                      mTitle,
+                                      mDir,
+                                      mLang,
+                                      mBody,
+                                      mTag,
+                                      mIcon,
+                                      mData,
+                                      mBehavior);
     }
     return NS_OK;
   }
 
-  NS_IMETHOD Done() override
-  {
-    return NS_OK;
-  }
-
-private:
-  ~NotificationClickEventCallback()
-  {
-  }
-
-  nsCOMPtr<nsIPrincipal> mPrincipal;
-  nsString mScope;
-};
-
-NS_IMPL_ISUPPORTS(NotificationClickEventCallback, nsINotificationStorageCallback)
-
-NS_IMETHODIMP
-ServiceWorkerNotificationObserver::Observe(nsISupports* aSubject,
-                                           const char* aTopic,
-                                           const char16_t* aData)
-{
-  AssertIsOnMainThread();
-  // Persistent notifications only care about the click event.
-  if (!strcmp("alertclickcallback", aTopic)) {
-    nsresult rv;
-    nsCOMPtr<nsINotificationStorage> notificationStorage =
-      do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID, &rv);
+  if (!strcmp("alertfinished", aTopic)) {
+    nsString origin;
+    nsresult rv = Notification::GetOrigin(mPrincipal, origin);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    nsCOMPtr<nsINotificationStorageCallback> callback =
-      new NotificationClickEventCallback(mPrincipal, mScope);
-
-    nsAutoString origin;
-    rv = Notification::GetOrigin(mPrincipal, origin);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    rv = notificationStorage->GetByID(origin, mID, callback);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+    // Remove closed or dismissed persistent notifications.
+    nsCOMPtr<nsINotificationStorage> notificationStorage =
+      do_GetService(NS_NOTIFICATION_STORAGE_CONTRACTID);
+    if (notificationStorage) {
+      notificationStorage->Delete(origin, mID);
     }
   }
 
   return NS_OK;
 }
 
 bool
 Notification::IsInPrivateBrowsing()
@@ -1752,17 +1719,31 @@ Notification::ShowInternal()
     } else {
       observer = new MainThreadNotificationObserver(Move(ownership));
     }
   } else {
     // This observer does not care about the Notification. It will be released
     // at the end of this function.
     //
     // The observer is wholly owned by the NotificationObserver passed to the alert service.
-    observer = new ServiceWorkerNotificationObserver(mScope, GetPrincipal(), mID);
+    nsAutoString behavior;
+    if (NS_WARN_IF(!mBehavior.ToJSON(behavior))) {
+      behavior.Truncate();
+    }
+    observer = new ServiceWorkerNotificationObserver(mScope,
+                                                     GetPrincipal(),
+                                                     mID,
+                                                     mTitle,
+                                                     DirectionToString(mDir),
+                                                     mLang,
+                                                     mBody,
+                                                     mTag,
+                                                     iconUrl,
+                                                     mDataAsBase64,
+                                                     behavior);
   }
   MOZ_ASSERT(observer);
   nsCOMPtr<nsIObserver> alertObserver = new NotificationObserver(observer,
                                                                  GetPrincipal(),
                                                                  IsInPrivateBrowsing());
 
 
 #ifdef MOZ_B2G
--- a/dom/workers/test/serviceworkers/test_notification_get.html
+++ b/dom/workers/test/serviceworkers/test_notification_get.html
@@ -54,16 +54,50 @@
   }
 
   function unregisterAlternateSWAndAddNotification() {
     return testFrame('notification_alt/unregister.html').then(function() {
       ok(true, "unregistered alternate service worker.");
     });
   }
 
+  function testDismiss() {
+    // Dismissed persistent notifications should be removed from the
+    // notification list.
+    var alertsService = SpecialPowers.Cc["@mozilla.org/alerts-service;1"]
+                                     .getService(SpecialPowers.Ci.nsIAlertsService);
+    return navigator.serviceWorker.getRegistration("./notification/")
+      .then(function(reg) {
+        return reg.showNotification(
+          "This is a notification that will be closed", { tag: "dismiss" })
+          .then(function() {
+            return reg;
+          });
+      }).then(function(reg) {
+        return reg.getNotifications()
+          .then(function(notifications) {
+            is(notifications.length, 1, "There should be one visible notification");
+            is(notifications[0].tag, "dismiss", "Tag should match");
+
+            // Simulate dismissing the notification by using the alerts service
+            // directly, instead of `Notification#close`.
+            var principal = SpecialPowers.wrap(document).nodePrincipal;
+            var id = principal.origin + "#tag:dismiss";
+            alertsService.closeAlert(id, principal);
+
+            return reg;
+          });
+      }).then(function(reg) {
+        return reg.getNotifications();
+      }).then(function(notifications) {
+        // Make sure dismissed notifications are no longer retrieved.
+        is(notifications.length, 0, "There should be no more stored notifications");
+      });
+  }
+
   function testGet() {
     // Non persistent notifications will not show up in getNotification().
     var n = new Notification("Scope does not match");
     var options = NotificationTest.payload;
     return navigator.serviceWorker.getRegistration("./notification/")
       .then(function(reg) {
         return reg.showNotification("This is a title", options)
                  .then(function() {
@@ -162,16 +196,17 @@
     ["dom.webnotifications.serviceworker.enabled", true],
     ["notification.prompt.testing", true],
   ]}, function() {
     registerSW()
       .then(testGet)
       .then(testGetWorker)
       .then(testGetServiceWorker)
       .then(testAcrossThreads)
+      .then(testDismiss)
       .then(unregisterSW)
       .then(function() {
         MockServices.unregister();
         SimpleTest.finish();
       });
   });
 </script>
 </body>