diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index ed3d49a0976e..4db10f1ffc05 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -6,6 +6,7 @@ #include "mozilla/dom/Notification.h" +#include "mozilla/JSONWriter.h" #include "mozilla/Move.h" #include "mozilla/OwningNonNull.h" #include "mozilla/Preferences.h" @@ -1665,6 +1666,19 @@ Notification::IsInPrivateBrowsing() return false; } +namespace { + struct StringWriteFunc : public JSONWriteFunc + { + nsAString& mBuffer; // This struct must not outlive this buffer + explicit StringWriteFunc(nsAString& buffer) : mBuffer(buffer) {} + + void Write(const char* aStr) + { + mBuffer.Append(NS_ConvertUTF8toUTF16(aStr)); + } + }; +} + void Notification::ShowInternal() { @@ -1716,6 +1730,7 @@ Notification::ShowInternal() nsAutoString soundUrl; ResolveIconAndSoundURL(iconUrl, soundUrl); + bool isPersistent = false; nsCOMPtr observer; if (mScope.IsEmpty()) { // Ownership passed to observer. @@ -1730,6 +1745,7 @@ Notification::ShowInternal() observer = new MainThreadNotificationObserver(Move(ownership)); } } else { + isPersistent = true; // This observer does not care about the Notification. It will be released // at the end of this function. // @@ -1813,6 +1829,7 @@ Notification::ShowInternal() nsCOMPtr alert = do_CreateInstance(ALERT_NOTIFICATION_CONTRACTID); NS_ENSURE_TRUE_VOID(alert); + nsIPrincipal* principal = GetPrincipal(); rv = alert->Init(alertName, iconUrl, mTitle, mBody, true, uniqueCookie, @@ -1822,7 +1839,29 @@ Notification::ShowInternal() GetPrincipal(), inPrivateBrowsing); NS_ENSURE_SUCCESS_VOID(rv); - alertService->ShowAlert(alert, alertObserver); + + if (isPersistent) { + nsAutoString persistentData; + + JSONWriter w(MakeUnique(persistentData)); + w.Start(); + + nsAutoString origin; + Notification::GetOrigin(principal, origin); + w.StringProperty("origin", NS_ConvertUTF16toUTF8(origin).get()); + + w.StringProperty("id", NS_ConvertUTF16toUTF8(mID).get()); + + nsAutoCString originSuffix; + principal->GetOriginSuffix(originSuffix); + w.StringProperty("originSuffix", originSuffix.get()); + + w.End(); + + alertService->ShowPersistentNotification(persistentData, alert, alertObserver); + } else { + alertService->ShowAlert(alert, alertObserver); + } } /* static */ bool diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java b/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java index f8db7427ed0d..06190e46c851 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java @@ -896,6 +896,19 @@ public class GeckoAppShell } } + @WrapForJNI(stubName = "ShowPersistentAlertNotificationWrapper") + public static void showPersistentAlertNotification( + String aPersistentData, + String aImageUrl, String aAlertTitle, String aAlertText, + String aAlertCookie, String aAlertName, String aHost) { + Intent notificationIntent = GeckoService.getIntentToCreateServices( + getApplicationContext(), "persistent-notification-click", aPersistentData); + int notificationID = aAlertName.hashCode(); + PendingIntent contentIntent = PendingIntent.getService( + getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT); + notificationClient.add(notificationID, aImageUrl, aHost, aAlertTitle, aAlertText, contentIntent); + } + @WrapForJNI(stubName = "ShowAlertNotificationWrapper") public static void showAlertNotification(String aImageUrl, String aAlertTitle, String aAlertText, String aAlertCookie, String aAlertName, String aHost) { // The intent to launch when the user clicks the expanded notification diff --git a/toolkit/components/alerts/nsAlertsService.cpp b/toolkit/components/alerts/nsAlertsService.cpp index 865a9278ba11..d5e7476b560f 100644 --- a/toolkit/components/alerts/nsAlertsService.cpp +++ b/toolkit/components/alerts/nsAlertsService.cpp @@ -252,8 +252,14 @@ NS_IMETHODIMP nsAlertsService::ShowPersistentNotification(const nsAString & aPer rv = aAlert->GetPrincipal(getter_AddRefs(principal)); NS_ENSURE_SUCCESS(rv, rv); - mozilla::AndroidBridge::Bridge()->ShowAlertNotification(imageUrl, title, text, cookie, - aAlertListener, name, principal); + if (!aPersistentData.IsEmpty()) { + mozilla::AndroidBridge::Bridge()->ShowPersistentAlertNotification + (aPersistentData, imageUrl, title, text, cookie, name, principal); + } else { + mozilla::AndroidBridge::Bridge()->ShowAlertNotification + (imageUrl, title, text, cookie, aAlertListener, name, principal); + } + return NS_OK; #else // Check if there is an optional service that handles system-level notifications diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 1d21440275f5..f3a1b441471a 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -507,6 +507,22 @@ AndroidBridge::GetClipboardText(nsAString& aText) return !!text; } +void +AndroidBridge::ShowPersistentAlertNotification(const nsAString& aPersistentData, + const nsAString& aImageUrl, + const nsAString& aAlertTitle, + const nsAString& aAlertText, + const nsAString& aAlertCookie, + const nsAString& aAlertName, + nsIPrincipal* aPrincipal) +{ + nsAutoString host; + nsAlertsUtils::GetSourceHostPort(aPrincipal, host); + + GeckoAppShell::ShowPersistentAlertNotificationWrapper + (aPersistentData, aImageUrl, aAlertTitle, aAlertText, aAlertCookie, aAlertName, host); +} + void AndroidBridge::ShowAlertNotification(const nsAString& aImageUrl, const nsAString& aAlertTitle, diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index bd0e4444d119..48c44d6cb5a2 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -177,10 +177,18 @@ public: bool GetClipboardText(nsAString& aText); + void ShowPersistentAlertNotification(const nsAString& aPersistentData, + const nsAString& aImageUrl, + const nsAString& aAlertTitle, + const nsAString& aAlertText, + const nsAString& aAlertCookie, + const nsAString& aAlertName, + nsIPrincipal* aPrincipal); + void ShowAlertNotification(const nsAString& aImageUrl, const nsAString& aAlertTitle, const nsAString& aAlertText, - const nsAString& aAlertData, + const nsAString& aAlertCookie, nsIObserver *aAlertListener, const nsAString& aAlertName, nsIPrincipal* aPrincipal); diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index 3a75dbb9f00f..1de054ad3666 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -685,6 +685,14 @@ auto GeckoAppShell::ShowAlertNotificationWrapper(mozilla::jni::String::Param a0, return mozilla::jni::Method::Call(GeckoAppShell::Context(), nullptr, a0, a1, a2, a3, a4, a5); } +constexpr char GeckoAppShell::ShowPersistentAlertNotificationWrapper_t::name[]; +constexpr char GeckoAppShell::ShowPersistentAlertNotificationWrapper_t::signature[]; + +auto GeckoAppShell::ShowPersistentAlertNotificationWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2, mozilla::jni::String::Param a3, mozilla::jni::String::Param a4, mozilla::jni::String::Param a5, mozilla::jni::String::Param a6) -> void +{ + return mozilla::jni::Method::Call(GeckoAppShell::Context(), nullptr, a0, a1, a2, a3, a4, a5, a6); +} + constexpr char GeckoAppShell::StartMonitoringGamepad_t::name[]; constexpr char GeckoAppShell::StartMonitoringGamepad_t::signature[]; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index 095cda99e4a7..69e4f64bc202 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -1430,6 +1430,28 @@ public: static auto ShowAlertNotificationWrapper(mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param) -> void; + struct ShowPersistentAlertNotificationWrapper_t { + typedef GeckoAppShell Owner; + typedef void ReturnType; + typedef void SetterType; + typedef mozilla::jni::Args< + mozilla::jni::String::Param, + mozilla::jni::String::Param, + mozilla::jni::String::Param, + mozilla::jni::String::Param, + mozilla::jni::String::Param, + mozilla::jni::String::Param, + mozilla::jni::String::Param> Args; + static constexpr char name[] = "showPersistentAlertNotification"; + static constexpr char signature[] = + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"; + static const bool isStatic = true; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + static auto ShowPersistentAlertNotificationWrapper(mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param, mozilla::jni::String::Param) -> void; + struct StartMonitoringGamepad_t { typedef GeckoAppShell Owner; typedef void ReturnType;