Bug 1369833 - Make `nsIAlertNotification` properties writable. r?MattN draft
authorLina Cambridge <lina@yakshaving.ninja>
Sat, 30 Jun 2018 20:05:37 -0700
changeset 813296 25102b0be84031505685d7148798825f73457333
parent 812819 e8664442920191ef7536bda215681281d6daaa56
push id114852
push userbmo:kit@mozilla.com
push dateMon, 02 Jul 2018 21:35:37 +0000
reviewersMattN
bugs1369833
milestone63.0a1
Bug 1369833 - Make `nsIAlertNotification` properties writable. r?MattN This commit removes `nsIAlertNotification.init`, and makes alert notifications' properties writable instead. This is a bit more cumbersome to use from C++, but nicer from JS, and doesn't require folks to memorize the argument order. MozReview-Commit-ID: AmUNhnUwj7c
dom/ipc/ContentParent.cpp
dom/notification/Notification.cpp
toolkit/components/alerts/AlertNotification.cpp
toolkit/components/alerts/AlertNotification.h
toolkit/components/alerts/AlertNotificationIPCSerializer.h
toolkit/components/alerts/nsAlertsService.cpp
toolkit/components/alerts/nsIAlertsService.idl
toolkit/components/alerts/nsXULAlerts.cpp
toolkit/components/alerts/test/test_image.html
toolkit/system/gnome/nsAlertsIconListener.cpp
toolkit/system/gnome/nsSystemAlertsService.cpp
widget/android/AndroidAlerts.cpp
widget/cocoa/OSXNotificationCenter.mm
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3752,23 +3752,23 @@ ContentParent::HasNotificationPermission
 {
   return true;
 }
 
 mozilla::ipc::IPCResult
 ContentParent::RecvShowAlert(nsIAlertNotification* aAlert)
 {
   if (!aAlert) {
-    return IPC_FAIL_NO_REASON(this);
-  }
-  nsCOMPtr<nsIPrincipal> principal;
-  nsresult rv = aAlert->GetPrincipal(getter_AddRefs(principal));
-  if (NS_WARN_IF(NS_FAILED(rv)) ||
-      !HasNotificationPermission(IPC::Principal(principal))) {
-
+    // Receiving a `ShowAlert` message without an alert likely means we failed
+    // to serialize the alert. Ignore the message instead of crashing the
+    // content process.
+    return IPC_OK();
+  }
+  nsCOMPtr<nsIPrincipal> principal = aAlert->GetPrincipal();
+  if (!HasNotificationPermission(IPC::Principal(principal))) {
       return IPC_OK();
   }
 
   nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_ALERTSERVICE_CONTRACTID));
   if (sysAlerts) {
       sysAlerts->ShowAlert(aAlert, this);
   }
   return IPC_OK();
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -1730,26 +1730,28 @@ Notification::ShowInternal()
   }
 
   nsAutoString alertName;
   GetAlertName(alertName);
   nsCOMPtr<nsIAlertNotification> alert =
     do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
   NS_ENSURE_TRUE_VOID(alert);
   nsIPrincipal* principal = GetPrincipal();
-  rv = alert->Init(alertName, iconUrl, mTitle, mBody,
-                   true,
-                   uniqueCookie,
-                   DirectionToString(mDir),
-                   mLang,
-                   mDataAsBase64,
-                   GetPrincipal(),
-                   inPrivateBrowsing,
-                   requireInteraction);
-  NS_ENSURE_SUCCESS_VOID(rv);
+  alert->SetName(alertName);
+  alert->SetImageURL(iconUrl);
+  alert->SetTitle(mTitle);
+  alert->SetText(mBody);
+  alert->SetTextClickable(true);
+  alert->SetCookie(uniqueCookie);
+  alert->SetDir(DirectionToString(mDir));
+  alert->SetLang(mLang);
+  alert->SetData(mDataAsBase64);
+  alert->SetPrincipal(principal);
+  alert->SetInPrivateBrowsing(inPrivateBrowsing);
+  alert->SetRequireInteraction(requireInteraction);
 
   if (isPersistent) {
     nsAutoString persistentData;
 
     JSONWriter w(MakeUnique<StringWriteFunc>(persistentData));
     w.Start();
 
     nsAutoString origin;
--- a/toolkit/components/alerts/AlertNotification.cpp
+++ b/toolkit/components/alerts/AlertNotification.cpp
@@ -17,123 +17,178 @@
 #include "mozilla/Unused.h"
 
 namespace mozilla {
 
 NS_IMPL_ISUPPORTS(AlertNotification, nsIAlertNotification)
 
 AlertNotification::AlertNotification()
   : mTextClickable(false)
+  , mRequireInteraction(false)
   , mInPrivateBrowsing(false)
 {}
 
 AlertNotification::~AlertNotification()
 {}
 
 NS_IMETHODIMP
-AlertNotification::Init(const nsAString& aName, const nsAString& aImageURL,
-                        const nsAString& aTitle, const nsAString& aText,
-                        bool aTextClickable, const nsAString& aCookie,
-                        const nsAString& aDir, const nsAString& aLang,
-                        const nsAString& aData, nsIPrincipal* aPrincipal,
-                        bool aInPrivateBrowsing, bool aRequireInteraction)
-{
-  mName = aName;
-  mImageURL = aImageURL;
-  mTitle = aTitle;
-  mText = aText;
-  mTextClickable = aTextClickable;
-  mCookie = aCookie;
-  mDir = aDir;
-  mLang = aLang;
-  mData = aData;
-  mPrincipal = aPrincipal;
-  mInPrivateBrowsing = aInPrivateBrowsing;
-  mRequireInteraction = aRequireInteraction;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 AlertNotification::GetName(nsAString& aName)
 {
   aName = mName;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetName(const nsAString& aName)
+{
+  mName = aName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetImageURL(nsAString& aImageURL)
 {
   aImageURL = mImageURL;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetImageURL(const nsAString& aImageURL)
+{
+  mImageURL = aImageURL;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetTitle(nsAString& aTitle)
 {
   aTitle = mTitle;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetTitle(const nsAString& aTitle)
+{
+  mTitle = aTitle;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetText(nsAString& aText)
 {
   aText = mText;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetText(const nsAString& aText)
+{
+  mText = aText;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetTextClickable(bool* aTextClickable)
 {
   *aTextClickable = mTextClickable;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetTextClickable(bool aTextClickable)
+{
+  mTextClickable = aTextClickable;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetCookie(nsAString& aCookie)
 {
   aCookie = mCookie;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetCookie(const nsAString& aCookie)
+{
+  mCookie = aCookie;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetDir(nsAString& aDir)
 {
   aDir = mDir;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetDir(const nsAString& aDir)
+{
+  mDir = aDir;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetLang(nsAString& aLang)
 {
   aLang = mLang;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetLang(const nsAString& aLang)
+{
+  mLang = aLang;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetRequireInteraction(bool* aRequireInteraction)
 {
   *aRequireInteraction = mRequireInteraction;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetRequireInteraction(bool aRequireInteraction)
+{
+  mRequireInteraction = aRequireInteraction;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetData(nsAString& aData)
 {
   aData = mData;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetData(const nsAString& aData)
+{
+  mData = aData;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetPrincipal(nsIPrincipal** aPrincipal)
 {
   NS_IF_ADDREF(*aPrincipal = mPrincipal);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetPrincipal(nsIPrincipal* aPrincipal)
+{
+  mPrincipal = aPrincipal;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetURI(nsIURI** aURI)
 {
   if (!nsAlertsUtils::IsActionablePrincipal(mPrincipal)) {
     *aURI = nullptr;
     return NS_OK;
   }
   return mPrincipal->GetURI(aURI);
 }
@@ -141,16 +196,23 @@ AlertNotification::GetURI(nsIURI** aURI)
 NS_IMETHODIMP
 AlertNotification::GetInPrivateBrowsing(bool* aInPrivateBrowsing)
 {
   *aInPrivateBrowsing = mInPrivateBrowsing;
   return NS_OK;
 }
 
 NS_IMETHODIMP
+AlertNotification::SetInPrivateBrowsing(bool aInPrivateBrowsing)
+{
+  mInPrivateBrowsing = aInPrivateBrowsing;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 AlertNotification::GetActionable(bool* aActionable)
 {
   *aActionable = nsAlertsUtils::IsActionablePrincipal(mPrincipal);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 AlertNotification::GetSource(nsAString& aSource)
--- a/toolkit/components/alerts/AlertNotification.h
+++ b/toolkit/components/alerts/AlertNotification.h
@@ -34,17 +34,17 @@ public:
   AlertImageRequest(nsIURI* aURI, nsIPrincipal* aPrincipal,
                     bool aInPrivateBrowsing, uint32_t aTimeout,
                     nsIAlertNotificationImageListener* aListener,
                     nsISupports* aUserData);
 
   nsresult Start();
 
 private:
-  virtual ~AlertImageRequest();
+  ~AlertImageRequest();
 
   nsresult NotifyMissing();
   nsresult NotifyComplete();
 
   nsCOMPtr<nsIURI> mURI;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   bool mInPrivateBrowsing;
   uint32_t mTimeout;
@@ -56,20 +56,19 @@ private:
 
 class AlertNotification final : public nsIAlertNotification
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIALERTNOTIFICATION
   AlertNotification();
 
-protected:
-  virtual ~AlertNotification();
+private:
+  ~AlertNotification();
 
-private:
   nsString mName;
   nsString mImageURL;
   nsString mTitle;
   nsString mText;
   bool mTextClickable;
   nsString mCookie;
   nsString mDir;
   nsString mLang;
--- a/toolkit/components/alerts/AlertNotificationIPCSerializer.h
+++ b/toolkit/components/alerts/AlertNotificationIPCSerializer.h
@@ -17,58 +17,52 @@
 
 namespace IPC {
 
 template <>
 struct ParamTraits<nsIAlertNotification>
 {
   static void Write(Message* aMsg, nsIAlertNotification* aParam)
   {
-    bool isNull = !aParam;
-    if (isNull) {
-      WriteParam(aMsg, isNull);
+    if (!aParam) {
+      WriteParam(aMsg, /* isNull */ true);
       return;
     }
 
     nsString name, imageURL, title, text, cookie, dir, lang, data;
-    bool textClickable, inPrivateBrowsing, requireInteraction;
-    nsCOMPtr<nsIPrincipal> principal;
+    nsCOMPtr<nsIPrincipal> principal = aParam->GetPrincipal();
 
     if (NS_WARN_IF(NS_FAILED(aParam->GetName(name))) ||
         NS_WARN_IF(NS_FAILED(aParam->GetImageURL(imageURL))) ||
         NS_WARN_IF(NS_FAILED(aParam->GetTitle(title))) ||
         NS_WARN_IF(NS_FAILED(aParam->GetText(text))) ||
-        NS_WARN_IF(NS_FAILED(aParam->GetTextClickable(&textClickable))) ||
         NS_WARN_IF(NS_FAILED(aParam->GetCookie(cookie))) ||
         NS_WARN_IF(NS_FAILED(aParam->GetDir(dir))) ||
         NS_WARN_IF(NS_FAILED(aParam->GetLang(lang))) ||
-        NS_WARN_IF(NS_FAILED(aParam->GetData(data))) ||
-        NS_WARN_IF(NS_FAILED(aParam->GetPrincipal(getter_AddRefs(principal)))) ||
-        NS_WARN_IF(NS_FAILED(aParam->GetInPrivateBrowsing(&inPrivateBrowsing))) ||
-        NS_WARN_IF(NS_FAILED(aParam->GetRequireInteraction(&requireInteraction)))) {
+        NS_WARN_IF(NS_FAILED(aParam->GetData(data)))) {
 
       // Write a `null` object if any getter returns an error. Otherwise, the
       // receiver will try to deserialize an incomplete object and crash.
       WriteParam(aMsg, /* isNull */ true);
       return;
     }
 
-    WriteParam(aMsg, isNull);
+    WriteParam(aMsg, /* isNull */ false);
     WriteParam(aMsg, name);
     WriteParam(aMsg, imageURL);
     WriteParam(aMsg, title);
     WriteParam(aMsg, text);
-    WriteParam(aMsg, textClickable);
+    WriteParam(aMsg, aParam->GetTextClickable());
     WriteParam(aMsg, cookie);
     WriteParam(aMsg, dir);
     WriteParam(aMsg, lang);
     WriteParam(aMsg, data);
     WriteParam(aMsg, IPC::Principal(principal));
-    WriteParam(aMsg, inPrivateBrowsing);
-    WriteParam(aMsg, requireInteraction);
+    WriteParam(aMsg, aParam->GetInPrivateBrowsing());
+    WriteParam(aMsg, aParam->GetRequireInteraction());
   }
 
   static bool Read(const Message* aMsg, PickleIterator* aIter, RefPtr<nsIAlertNotification>* aResult)
   {
     bool isNull;
     NS_ENSURE_TRUE(ReadParam(aMsg, aIter, &isNull), false);
     if (isNull) {
       *aResult = nullptr;
@@ -96,23 +90,29 @@ struct ParamTraits<nsIAlertNotification>
     }
 
     nsCOMPtr<nsIAlertNotification> alert =
       do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
     if (NS_WARN_IF(!alert)) {
       *aResult = nullptr;
       return true;
     }
-    nsresult rv = alert->Init(name, imageURL, title, text, textClickable,
-                              cookie, dir, lang, data, principal,
-                              inPrivateBrowsing, requireInteraction);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      *aResult = nullptr;
-      return true;
-    }
+    alert->SetName(name);
+    alert->SetImageURL(imageURL);
+    alert->SetTitle(title);
+    alert->SetText(text);
+    alert->SetTextClickable(textClickable);
+    alert->SetCookie(cookie);
+    alert->SetDir(dir);
+    alert->SetLang(lang);
+    alert->SetData(data);
+    alert->SetPrincipal(principal);
+    alert->SetInPrivateBrowsing(inPrivateBrowsing);
+    alert->SetRequireInteraction(requireInteraction);
+
     *aResult = alert.forget();
     return true;
   }
 };
 
 } // namespace IPC
 
 #endif /* mozilla_AlertNotificationIPCSerializer_h__ */
--- a/toolkit/components/alerts/nsAlertsService.cpp
+++ b/toolkit/components/alerts/nsAlertsService.cpp
@@ -192,22 +192,28 @@ NS_IMETHODIMP nsAlertsService::ShowAlert
                                                      const nsAString & aData,
                                                      nsIPrincipal * aPrincipal,
                                                      bool aInPrivateBrowsing,
                                                      bool aRequireInteraction)
 {
   nsCOMPtr<nsIAlertNotification> alert =
     do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
   NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
-  nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
-                            aAlertText, aAlertTextClickable,
-                            aAlertCookie, aBidi, aLang, aData,
-                            aPrincipal, aInPrivateBrowsing,
-                            aRequireInteraction);
-  NS_ENSURE_SUCCESS(rv, rv);
+  alert->SetName(aAlertName);
+  alert->SetImageURL(aImageUrl);
+  alert->SetTitle(aAlertTitle);
+  alert->SetText(aAlertText);
+  alert->SetTextClickable(aAlertTextClickable);
+  alert->SetCookie(aAlertCookie);
+  alert->SetDir(aBidi);
+  alert->SetLang(aLang);
+  alert->SetData(aData);
+  alert->SetPrincipal(aPrincipal);
+  alert->SetInPrivateBrowsing(aInPrivateBrowsing);
+  alert->SetRequireInteraction(aRequireInteraction);
   return ShowAlert(alert, aAlertListener);
 }
 
 
 NS_IMETHODIMP nsAlertsService::ShowAlert(nsIAlertNotification * aAlert,
                                          nsIObserver * aAlertListener)
 {
   return ShowPersistentNotification(EmptyString(), aAlert, aAlertListener);
--- a/toolkit/components/alerts/nsIAlertsService.idl
+++ b/toolkit/components/alerts/nsIAlertsService.idl
@@ -30,114 +30,100 @@ interface nsIAlertNotificationImageListe
    * Called if the alert doesn't have an image, or if the image request times
    * out or fails.
    *
    * @param aUserData An opaque parameter passed to |loadImage|.
    */
   void onImageMissing(in nsISupports aUserData);
 };
 
-[scriptable, uuid(cf2e4cb6-4b8f-4eca-aea9-d51a8f9f7a50)]
+[scriptable, builtinclass, uuid(cf2e4cb6-4b8f-4eca-aea9-d51a8f9f7a50)]
 interface nsIAlertNotification : nsISupports
 {
-  /** Initializes an alert notification. */
-  void init([optional] in AString aName,
-            [optional] in AString aImageURL,
-            [optional] in AString aTitle,
-            [optional] in AString aText,
-            [optional] in boolean aTextClickable,
-            [optional] in AString aCookie,
-            [optional] in AString aDir,
-            [optional] in AString aLang,
-            [optional] in AString aData,
-            [optional] in nsIPrincipal aPrincipal,
-            [optional] in boolean aInPrivateBrowsing,
-            [optional] in boolean aRequireInteraction);
-
   /**
    * The name of the notification. On Android, the name is hashed and used as
    * a notification ID. Notifications will replace previous notifications with
    * the same name.
    */
-  readonly attribute AString name;
+  attribute AString name;
 
   /**
    * A URL identifying the image to put in the alert. The OS X backend limits
    * the amount of time it will wait for the image to load to six seconds. After
    * that time, the alert will show without an image.
    */
-  readonly attribute AString imageURL;
+  attribute AString imageURL;
 
   /** The title for the alert. */
-  readonly attribute AString title;
+  attribute AString title;
 
   /** The contents of the alert. */
-  readonly attribute AString text;
+  attribute AString text;
 
   /**
    * Controls the click behavior. If true, the alert listener will be notified
    * when the user clicks on the alert.
    */
-  readonly attribute boolean textClickable;
+  [infallible] attribute boolean textClickable;
 
   /**
    * An opaque cookie that will be passed to the alert listener for each
    * callback.
    */
-  readonly attribute AString cookie;
+  attribute AString cookie;
 
   /**
    * Bidi override for the title and contents. Valid values are "auto", "ltr",
    * or "rtl". Ignored if the backend doesn't support localization.
    */
-  readonly attribute AString dir;
+  attribute AString dir;
 
   /**
    * Language of the title and text. Ignored if the backend doesn't support
    * localization.
    */
-  readonly attribute AString lang;
+  attribute AString lang;
 
   /**
    * A Base64-encoded structured clone buffer containing data associated with
    * this alert. Only used for web notifications. Chrome callers should use a
    * cookie instead.
    */
-  readonly attribute AString data;
+  attribute AString data;
 
   /**
    * The principal of the page that created the alert. Used for IPC security
    * checks, and to determine whether the alert is actionable.
    */
-  readonly attribute nsIPrincipal principal;
+  [infallible] attribute nsIPrincipal principal;
 
   /**
    * The URI of the page that created the alert. |null| if the alert is not
    * actionable.
    */
   readonly attribute nsIURI URI;
 
   /**
    * Controls the image loading behavior. If true, the image request will be
    * loaded anonymously (without cookies or authorization tokens).
    */
-  readonly attribute boolean inPrivateBrowsing;
+  [infallible] attribute boolean inPrivateBrowsing;
 
   /**
    * Indicates that the notification should remain readily available until
    * the user activates or dismisses the notification.
    */
-  readonly attribute boolean requireInteraction;
+  [infallible] attribute boolean requireInteraction;
 
   /**
    * Indicates whether this alert should show the source string and action
    * buttons. False for system alerts (which can omit the principal), or
    * expanded, system, and null principals.
    */
-  readonly attribute boolean actionable;
+  [infallible] readonly attribute boolean actionable;
 
   /**
    * The host and port of the originating page, or an empty string if the alert
    * is not actionable.
    */
   readonly attribute AString source;
 
   /**
--- a/toolkit/components/alerts/nsXULAlerts.cpp
+++ b/toolkit/components/alerts/nsXULAlerts.cpp
@@ -100,22 +100,28 @@ nsXULAlerts::ShowAlertNotification(const
                                    const nsAString& aAlertName, const nsAString& aBidi,
                                    const nsAString& aLang, const nsAString& aData,
                                    nsIPrincipal* aPrincipal, bool aInPrivateBrowsing,
                                    bool aRequireInteraction)
 {
   nsCOMPtr<nsIAlertNotification> alert =
     do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
   NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
-  nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
-                            aAlertText, aAlertTextClickable,
-                            aAlertCookie, aBidi, aLang, aData,
-                            aPrincipal, aInPrivateBrowsing,
-                            aRequireInteraction);
-  NS_ENSURE_SUCCESS(rv, rv);
+  alert->SetName(aAlertName);
+  alert->SetImageURL(aImageUrl);
+  alert->SetTitle(aAlertTitle);
+  alert->SetText(aAlertText);
+  alert->SetTextClickable(aAlertTextClickable);
+  alert->SetCookie(aAlertCookie);
+  alert->SetDir(aBidi);
+  alert->SetLang(aLang);
+  alert->SetData(aData);
+  alert->SetPrincipal(aPrincipal);
+  alert->SetInPrivateBrowsing(aInPrivateBrowsing);
+  alert->SetRequireInteraction(aRequireInteraction);
   return ShowAlert(alert, aAlertListener);
 }
 
 NS_IMETHODIMP
 nsXULAlerts::ShowPersistentNotification(const nsAString& aPersistentData,
                                         nsIAlertNotification* aAlert,
                                         nsIObserver* aAlertListener)
 {
@@ -150,43 +156,35 @@ nsXULAlerts::ShowAlert(nsIAlertNotificat
         }
 
         mPendingPersistentAlerts[i].Init(aAlert, aAlertListener);
         return NS_OK;
       }
     }
   }
 
-  bool requireInteraction;
-  rv = aAlert->GetRequireInteraction(&requireInteraction);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (requireInteraction &&
+  if (aAlert->GetRequireInteraction() &&
       !mNamedWindows.Contains(name) &&
       static_cast<int32_t>(mPersistentAlertCount) >=
         Preferences::GetInt("dom.webnotifications.requireinteraction.count", 0)) {
     PendingAlert* pa = mPendingPersistentAlerts.AppendElement();
     pa->Init(aAlert, aAlertListener);
     return NS_OK;
   } else {
     return ShowAlertWithIconURI(aAlert, aAlertListener, nullptr);
   }
 }
 
 NS_IMETHODIMP
 nsXULAlerts::ShowAlertWithIconURI(nsIAlertNotification* aAlert,
                                   nsIObserver* aAlertListener,
                                   nsIURI* aIconURI)
 {
-  bool inPrivateBrowsing;
-  nsresult rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   nsAutoString cookie;
-  rv = aAlert->GetCookie(cookie);
+  nsresult rv = aAlert->GetCookie(cookie);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mDoNotDisturb) {
     if (aAlertListener)
       aAlertListener->Observe(nullptr, "alertfinished", cookie.get());
     return NS_OK;
   }
 
@@ -201,35 +199,29 @@ nsXULAlerts::ShowAlertWithIconURI(nsIAle
   nsAutoString title;
   rv = aAlert->GetTitle(title);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString text;
   rv = aAlert->GetText(text);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  bool textClickable;
-  rv = aAlert->GetTextClickable(&textClickable);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   nsAutoString bidi;
   rv = aAlert->GetDir(bidi);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString lang;
   rv = aAlert->GetLang(lang);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoString source;
   rv = aAlert->GetSource(source);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  bool requireInteraction;
-  rv = aAlert->GetRequireInteraction(&requireInteraction);
-  NS_ENSURE_SUCCESS(rv, rv);
+  bool requireInteraction = aAlert->GetRequireInteraction();
 
   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
 
   nsCOMPtr<nsIMutableArray> argsArray = nsArray::Create();
 
   // create scriptable versions of our strings that we can store in our nsIMutableArray....
   nsCOMPtr<nsISupportsString> scriptableImageUrl (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
   NS_ENSURE_TRUE(scriptableImageUrl, NS_ERROR_FAILURE);
@@ -250,17 +242,17 @@ nsXULAlerts::ShowAlertWithIconURI(nsIAle
 
   scriptableAlertText->SetData(text);
   rv = argsArray->AppendElement(scriptableAlertText);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsISupportsPRBool> scriptableIsClickable (do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID));
   NS_ENSURE_TRUE(scriptableIsClickable, NS_ERROR_FAILURE);
 
-  scriptableIsClickable->SetData(textClickable);
+  scriptableIsClickable->SetData(aAlert->GetTextClickable());
   rv = argsArray->AppendElement(scriptableIsClickable);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsISupportsString> scriptableAlertCookie (do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
   NS_ENSURE_TRUE(scriptableAlertCookie, NS_ERROR_FAILURE);
 
   scriptableAlertCookie->SetData(cookie);
   rv = argsArray->AppendElement(scriptableAlertCookie);
@@ -339,17 +331,17 @@ nsXULAlerts::ShowAlertWithIconURI(nsIAle
     NS_ENSURE_SUCCESS(rv, rv);
     scriptableIconURL->SetData(iconURL);
   }
   rv = argsArray->AppendElement(scriptableIconURL);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<mozIDOMWindowProxy> newWindow;
   nsAutoCString features("chrome,dialog=yes,titlebar=no,popup=yes");
-  if (inPrivateBrowsing) {
+  if (aAlert->GetInPrivateBrowsing()) {
     features.AppendLiteral(",private");
   }
   rv = wwatch->OpenWindow(nullptr, ALERT_CHROME_URL, "_blank", features.get(),
                           argsArray, getter_AddRefs(newWindow));
   NS_ENSURE_SUCCESS(rv, rv);
 
   mNamedWindows.Put(name, newWindow);
   alertObserver->SetAlertWindow(newWindow);
--- a/toolkit/components/alerts/test/test_image.html
+++ b/toolkit/components/alerts/test/test_image.html
@@ -14,23 +14,16 @@
 <script class="testbody" type="text/javascript">
 
 const Cc = SpecialPowers.Cc;
 const Ci = SpecialPowers.Ci;
 const Services = SpecialPowers.Services;
 
 const imageServerURL = "http://mochi.test:8888/tests/toolkit/components/alerts/test/image_server.sjs";
 
-function makeAlert(...params) {
-  var alert = Cc["@mozilla.org/alert-notification;1"]
-                .createInstance(Ci.nsIAlertNotification);
-  alert.init(...params);
-  return alert;
-}
-
 function promiseImage(alert, timeout = 0, userData = null) {
   return new Promise(resolve => {
     var isDone = false;
     function done(value) {
       ok(!isDone, "Should call the image listener once");
       isDone = true;
       resolve(value);
     }
@@ -45,49 +38,59 @@ function promiseImage(alert, timeout = 0
   });
 }
 
 add_task(async function testContext() {
   var inUserData = Cc["@mozilla.org/supports-PRInt64;1"]
                      .createInstance(Ci.nsISupportsPRInt64);
   inUserData.data = 123;
 
-  var alert = makeAlert(null, imageServerURL + "?f=image.png");
+  var alert = Cc["@mozilla.org/alert-notification;1"]
+                .createInstance(Ci.nsIAlertNotification);
+  alert.imageURL = imageServerURL + "?f=image.png";
   var [ready, , userData] = await promiseImage(alert, 0, inUserData);
   ok(ready, "Should load requested image");
   is(userData.QueryInterface(Ci.nsISupportsPRInt64).data, 123,
      "Should pass user data for loaded image");
 
-  alert = makeAlert(null, imageServerURL + "?s=404");
+  alert = Cc["@mozilla.org/alert-notification;1"]
+                .createInstance(Ci.nsIAlertNotification);
+  alert.imageURL = imageServerURL + "?s=404";
   [ready, userData] = await promiseImage(alert, 0, inUserData);
   ok(!ready, "Should not load missing image");
   is(userData.QueryInterface(Ci.nsISupportsPRInt64).data, 123,
      "Should pass user data for missing image");
 });
 
 add_task(async function testTimeout() {
-  var alert = makeAlert(null, imageServerURL + "?f=image.png&t=3");
+  var alert = Cc["@mozilla.org/alert-notification;1"]
+                .createInstance(Ci.nsIAlertNotification);
+  alert.imageURL = imageServerURL + "?f=image.png&t=3";
   var [ready] = await promiseImage(alert, 1000);
   ok(!ready, "Should cancel request if timeout fires");
 
   [ready] = await promiseImage(alert, 45000);
   ok(ready, "Should load image if request finishes before timeout");
 });
 
 add_task(async function testAnimatedGIF() {
-  var alert = makeAlert(null, imageServerURL + "?f=image.gif");
+  var alert = Cc["@mozilla.org/alert-notification;1"]
+                .createInstance(Ci.nsIAlertNotification);
+  alert.imageURL = imageServerURL + "?f=image.gif";
   var [ready, request] = await promiseImage(alert);
   ok(ready, "Should load first animated GIF frame");
   is(request.mimeType, "image/gif", "Should report correct GIF MIME type");
   is(request.image.width, 256, "GIF width should be 256px");
   is(request.image.height, 256, "GIF height should be 256px");
 });
 
 add_task(async function testCancel() {
-  var alert = makeAlert(null, imageServerURL + "?f=image.gif&t=180");
+  var alert = Cc["@mozilla.org/alert-notification;1"]
+                .createInstance(Ci.nsIAlertNotification);
+  alert.imageURL = imageServerURL + "?f=image.gif&t=180";
   await new Promise((resolve, reject) => {
     var request = alert.loadImage(0, SpecialPowers.wrapCallbackObject({
       onImageReady() {
         reject(new Error("Should not load cancelled request"));
       },
       onImageMissing() {
         resolve();
       },
@@ -97,19 +100,20 @@ add_task(async function testCancel() {
 });
 
 add_task(async function testMixedContent() {
   // Loading principal is HTTPS; image URL is HTTP.
   var origin = "https://mochi.test:8888";
   var principal = Services.scriptSecurityManager
                           .createCodebasePrincipalFromOrigin(origin);
 
-  var alert = makeAlert(null, imageServerURL + "?f=image.png",
-                        null, null, false, null, null, null,
-                        null, principal);
+  var alert = Cc["@mozilla.org/alert-notification;1"]
+                .createInstance(Ci.nsIAlertNotification);
+  alert.imageURL = imageServerURL + "?f=image.png";
+  alert.principal = principal;
   var [ready, request] = await promiseImage(alert);
   ok(ready, "Should load cross-protocol image");
   is(request.mimeType, "image/png", "Should report correct MIME type");
   is(request.image.width, 32, "Width should be 32px");
   is(request.image.height, 32, "Height should be 32px");
 });
 
 </script>
--- a/toolkit/system/gnome/nsAlertsIconListener.cpp
+++ b/toolkit/system/gnome/nsAlertsIconListener.cpp
@@ -297,23 +297,22 @@ nsAlertsIconListener::InitAlertAsync(nsI
   }
 
   if (!gHasCaps) {
     // if notify_get_server_caps() failed above we need to assume
     // there is no notification-server to display anything
     return NS_ERROR_FAILURE;
   }
 
-  nsresult rv = aAlert->GetTextClickable(&mAlertHasAction);
-  NS_ENSURE_SUCCESS(rv, rv);
+  mAlertHasAction = aAlert->GetTextClickable();
   if (!gHasActions && mAlertHasAction)
     return NS_ERROR_FAILURE; // No good, fallback to XUL
 
   nsAutoString title;
-  rv = aAlert->GetTitle(title);
+  nsresult rv = aAlert->GetTitle(title);
   NS_ENSURE_SUCCESS(rv, rv);
   // Workaround for a libnotify bug - blank titles aren't dealt with
   // properly so we use a space
   if (title.IsEmpty()) {
     mAlertTitle = NS_LITERAL_CSTRING(" ");
   } else {
     mAlertTitle = NS_ConvertUTF16toUTF8(title);
   }
--- a/toolkit/system/gnome/nsSystemAlertsService.cpp
+++ b/toolkit/system/gnome/nsSystemAlertsService.cpp
@@ -39,22 +39,28 @@ NS_IMETHODIMP nsSystemAlertsService::Sho
                                                            const nsAString & aData,
                                                            nsIPrincipal * aPrincipal,
                                                            bool aInPrivateBrowsing,
                                                            bool aRequireInteraction)
 {
   nsCOMPtr<nsIAlertNotification> alert =
     do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
   NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
-  nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
-                            aAlertText, aAlertTextClickable,
-                            aAlertCookie, aBidi, aLang, aData,
-                            aPrincipal, aInPrivateBrowsing,
-                            aRequireInteraction);
-  NS_ENSURE_SUCCESS(rv, rv);
+  alert->SetName(aAlertName);
+  alert->SetImageURL(aImageUrl);
+  alert->SetTitle(aAlertTitle);
+  alert->SetText(aAlertText);
+  alert->SetTextClickable(aAlertTextClickable);
+  alert->SetCookie(aAlertCookie);
+  alert->SetDir(aBidi);
+  alert->SetLang(aLang);
+  alert->SetData(aData);
+  alert->SetPrincipal(aPrincipal);
+  alert->SetInPrivateBrowsing(aInPrivateBrowsing);
+  alert->SetRequireInteraction(aRequireInteraction);
   return ShowAlert(alert, aAlertListener);
 }
 
 NS_IMETHODIMP nsSystemAlertsService::ShowPersistentNotification(const nsAString& aPersistentData,
                                                                 nsIAlertNotification* aAlert,
                                                                 nsIObserver* aAlertListener)
 {
   return ShowAlert(aAlert, aAlertListener);
--- a/widget/android/AndroidAlerts.cpp
+++ b/widget/android/AndroidAlerts.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: c++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4; -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "AndroidAlerts.h"
 #include "GeneratedJNIWrappers.h"
-#include "nsAlertsUtils.h"
 
 namespace mozilla {
 namespace widget {
 
 NS_IMPL_ISUPPORTS(AndroidAlerts, nsIAlertsService)
 
 StaticAutoPtr<AndroidAlerts::ListenerMap> AndroidAlerts::sListenerMap;
 
@@ -65,33 +64,30 @@ AndroidAlerts::ShowPersistentNotificatio
     nsAutoString cookie;
     rv = aAlert->GetCookie(cookie);
     NS_ENSURE_SUCCESS(rv, NS_OK);
 
     nsAutoString name;
     rv = aAlert->GetName(name);
     NS_ENSURE_SUCCESS(rv, NS_OK);
 
-    nsCOMPtr<nsIPrincipal> principal;
-    rv = aAlert->GetPrincipal(getter_AddRefs(principal));
+    nsAutoString source;
+    aAlert->GetSource(source);
     NS_ENSURE_SUCCESS(rv, NS_OK);
 
-    nsAutoString host;
-    nsAlertsUtils::GetSourceHostPort(principal, host);
-
     if (aPersistentData.IsEmpty() && aAlertListener) {
         if (!sListenerMap) {
             sListenerMap = new ListenerMap();
         }
         // This will remove any observers already registered for this name.
         sListenerMap->Put(name, aAlertListener);
     }
 
     java::GeckoAppShell::ShowNotification(
-            name, cookie, title, text, host, imageUrl,
+            name, cookie, title, text, source, imageUrl,
             !aPersistentData.IsEmpty() ? jni::StringParam(aPersistentData)
                                        : jni::StringParam(nullptr));
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidAlerts::CloseAlert(const nsAString& aAlertName,
                           nsIPrincipal* aPrincipal)
--- a/widget/cocoa/OSXNotificationCenter.mm
+++ b/widget/cocoa/OSXNotificationCenter.mm
@@ -242,22 +242,28 @@ OSXNotificationCenter::ShowAlertNotifica
                                              const nsAString & aData,
                                              nsIPrincipal * aPrincipal,
                                              bool aInPrivateBrowsing,
                                              bool aRequireInteraction)
 {
   nsCOMPtr<nsIAlertNotification> alert =
     do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID);
   NS_ENSURE_TRUE(alert, NS_ERROR_FAILURE);
-  nsresult rv = alert->Init(aAlertName, aImageUrl, aAlertTitle,
-                            aAlertText, aAlertTextClickable,
-                            aAlertCookie, aBidi, aLang, aData,
-                            aPrincipal, aInPrivateBrowsing,
-                            aRequireInteraction);
-  NS_ENSURE_SUCCESS(rv, rv);
+  alert->SetName(aAlertName);
+  alert->SetImageURL(aImageUrl);
+  alert->SetTitle(aAlertTitle);
+  alert->SetText(aAlertText);
+  alert->SetTextClickable(aAlertTextClickable);
+  alert->SetCookie(aAlertCookie);
+  alert->SetDir(aBidi);
+  alert->SetLang(aLang);
+  alert->SetData(aData);
+  alert->SetPrincipal(aPrincipal);
+  alert->SetInPrivateBrowsing(aInPrivateBrowsing);
+  alert->SetRequireInteraction(aRequireInteraction);
   return ShowAlert(alert, aAlertListener);
 }
 
 NS_IMETHODIMP
 OSXNotificationCenter::ShowPersistentNotification(const nsAString& aPersistentData,
                                                   nsIAlertNotification* aAlert,
                                                   nsIObserver* aAlertListener)
 {
@@ -310,18 +316,17 @@ OSXNotificationCenter::ShowAlertWithIcon
   rv = aAlert->GetText(text);
   NS_ENSURE_SUCCESS(rv, rv);
   notification.informativeText = nsCocoaUtils::ToNSString(text);
 
   notification.soundName = NSUserNotificationDefaultSoundName;
   notification.hasActionButton = NO;
 
   // If this is not an application/extension alert, show additional actions dealing with permissions.
-  bool isActionable;
-  if (bundle && NS_SUCCEEDED(aAlert->GetActionable(&isActionable)) && isActionable) {
+  if (bundle && aAlert->GetActionable()) {
     nsAutoString closeButtonTitle, actionButtonTitle, disableButtonTitle, settingsButtonTitle;
     bundle->GetStringFromName("closeButton.title", closeButtonTitle);
     bundle->GetStringFromName("actionButton.label", actionButtonTitle);
     if (!hostPort.IsEmpty()) {
       const char16_t* formatStrings[] = { hostPort.get() };
       bundle->FormatStringFromName("webActions.disableForOrigin.label",
                                    formatStrings,
                                    ArrayLength(formatStrings),
@@ -380,20 +385,16 @@ OSXNotificationCenter::ShowAlertWithIcon
 
     NSData *iconData = [NSData dataWithBytes:aIconData length:aIconSize];
     NSImage *icon = [[[NSImage alloc] initWithData:iconData] autorelease];
 
     [(NSObject*)notification setValue:icon forKey:@"_identityImage"];
     [(NSObject*)notification setValue:@(NO) forKey:@"_identityImageHasBorder"];
   }
 
-  bool inPrivateBrowsing;
-  rv = aAlert->GetInPrivateBrowsing(&inPrivateBrowsing);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   // Show the notification without waiting for an image if there is no icon URL or
   // notification icons are not supported on this version of OS X.
   if (![unClass instancesRespondToSelector:@selector(setContentImage:)]) {
     CloseAlertCocoaString(alertName);
     mActiveAlerts.AppendElement(osxni);
     [GetNotificationCenter() deliverNotification:notification];
     [notification release];
     if (aAlertListener) {