Bug 1264815 - Add a 'showPersistentAlertNotification' method to GeckoAppShell. r=wchen
☠☠ backed out by dfaeab92707e ☠ ☠
authorSUN Haitao <sunhaitao@devtaste.com>
Sun, 17 Apr 2016 21:18:20 +0800
changeset 338532 20d0b05e708bdf6f76450f147d706def62b0e158
parent 338531 9bcbe80a4a7aacc9447d2bd60ecb6383242f584c
child 338533 d049a47c24c1889cb547d4d899e998c75367e315
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswchen
bugs1264815
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1264815 - Add a 'showPersistentAlertNotification' method to GeckoAppShell. r=wchen
dom/notification/Notification.cpp
mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
toolkit/components/alerts/nsAlertsService.cpp
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/GeneratedJNIWrappers.cpp
widget/android/GeneratedJNIWrappers.h
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "mozilla/dom/Notification.h"
 
+#include "mozilla/JSONWriter.h"
 #include "mozilla/Move.h"
 #include "mozilla/OwningNonNull.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/unused.h"
 
 #include "mozilla/dom/AppNotificationServiceOptionsBinding.h"
@@ -1661,16 +1662,29 @@ Notification::IsInPrivateBrowsing()
                                   getter_AddRefs(loadContext));
     return loadContext && loadContext->UsePrivateBrowsing();
   }
 
   //XXXnsm Should this default to true?
   return false;
 }
 
+namespace {
+  struct StringWriteFunc : public JSONWriteFunc
+  {
+    nsAString& mBuffer; // This struct must not outlive this buffer
+    StringWriteFunc(nsAString& buffer) : mBuffer(buffer) {}
+
+    void Write(const char* aStr)
+    {
+      mBuffer.Append(NS_ConvertUTF8toUTF16(aStr));
+    }
+  };
+}
+
 void
 Notification::ShowInternal()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(mTempRef, "Notification should take ownership of itself before"
                        "calling ShowInternal!");
   // A notification can only have one observer and one call to ShowInternal.
   MOZ_ASSERT(!mObserver);
@@ -1712,30 +1726,32 @@ Notification::ShowInternal()
     }
     return;
   }
 
   nsAutoString iconUrl;
   nsAutoString soundUrl;
   ResolveIconAndSoundURL(iconUrl, soundUrl);
 
+  bool isPersistent = false;
   nsCOMPtr<nsIObserver> observer;
   if (mScope.IsEmpty()) {
     // Ownership passed to observer.
     if (mWorkerPrivate) {
       // Scope better be set on ServiceWorker initiated requests.
       MOZ_ASSERT(!mWorkerPrivate->IsServiceWorker());
       // Keep a pointer so that the feature can tell the observer not to release
       // the notification.
       mObserver = new WorkerNotificationObserver(Move(ownership));
       observer = mObserver;
     } else {
       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.
     //
     // The observer is wholly owned by the NotificationObserver passed to the alert service.
     nsAutoString behavior;
     if (NS_WARN_IF(!mBehavior.ToJSON(behavior))) {
       behavior.Truncate();
     }
@@ -1809,26 +1825,49 @@ Notification::ShowInternal()
   uniqueCookie.AppendInt(sCount++);
   bool inPrivateBrowsing = IsInPrivateBrowsing();
 
   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);
   NS_ENSURE_SUCCESS_VOID(rv);
-  alertService->ShowAlert(alert, alertObserver);
+
+  if (isPersistent) {
+    nsAutoString persistentData;
+
+    JSONWriter w(MakeUnique<StringWriteFunc>(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
 Notification::RequestPermissionEnabledForScope(JSContext* aCx, JSObject* /* unused */)
 {
   // requestPermission() is not allowed on workers. The calling page should ask
   // for permission on the worker's behalf. This is to prevent 'which window
   // should show the browser pop-up'. See discussion:
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
@@ -890,16 +890,29 @@ public class GeckoAppShell
     public static void setNotificationClient(NotificationClient client) {
         if (notificationClient == null) {
             notificationClient = client;
         } else {
             Log.d(LOGTAG, "Notification client already set");
         }
     }
 
+    @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
         Intent notificationIntent = new Intent(GeckoApp.ACTION_ALERT_CALLBACK);
         notificationIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
         notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
         int notificationID = aAlertName.hashCode();
--- a/toolkit/components/alerts/nsAlertsService.cpp
+++ b/toolkit/components/alerts/nsAlertsService.cpp
@@ -247,18 +247,24 @@ NS_IMETHODIMP nsAlertsService::ShowPersi
   nsAutoString name;
   rv = aAlert->GetName(name);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIPrincipal> principal;
   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
   if (mBackend) {
     rv = ShowWithBackend(mBackend, aAlert, aAlertListener);
     if (NS_SUCCEEDED(rv)) {
       return rv;
     }
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -503,16 +503,32 @@ AndroidBridge::GetClipboardText(nsAStrin
 
     if (text) {
         aText = text->ToString();
     }
     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,
                                      const nsAString& aAlertText,
                                      const nsAString& aAlertCookie,
                                      nsIObserver *aAlertListener,
                                      const nsAString& aAlertName,
                                      nsIPrincipal* aPrincipal)
 {
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -172,20 +172,28 @@ public:
     bool GetHWEncoderCapability();
     bool GetHWDecoderCapability();
 
     void GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType);
     void GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt);
 
     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);
 
     int GetDPI();
     int GetScreenDepth();
 
     void Vibrate(const nsTArray<uint32_t>& aPattern);
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -680,16 +680,24 @@ auto GeckoAppShell::SetURITitle(mozilla:
 constexpr char GeckoAppShell::ShowAlertNotificationWrapper_t::name[];
 constexpr char GeckoAppShell::ShowAlertNotificationWrapper_t::signature[];
 
 auto GeckoAppShell::ShowAlertNotificationWrapper(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) -> void
 {
     return mozilla::jni::Method<ShowAlertNotificationWrapper_t>::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<ShowPersistentAlertNotificationWrapper_t>::Call(GeckoAppShell::Context(), nullptr, a0, a1, a2, a3, a4, a5, a6);
+}
+
 constexpr char GeckoAppShell::StartMonitoringGamepad_t::name[];
 constexpr char GeckoAppShell::StartMonitoringGamepad_t::signature[];
 
 auto GeckoAppShell::StartMonitoringGamepad() -> void
 {
     return mozilla::jni::Method<StartMonitoringGamepad_t>::Call(GeckoAppShell::Context(), nullptr);
 }
 
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -1425,16 +1425,38 @@ public:
                 "(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 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;
         typedef void SetterType;
         typedef mozilla::jni::Args<> Args;
         static constexpr char name[] = "startMonitoringGamepad";
         static constexpr char signature[] =
                 "()V";