Bug 1212611 - Use system notification for website notifications in Android. r=mfinkle
authorChenxia Liu <liuche@mozilla.com>
Thu, 03 Dec 2015 10:56:04 -0500
changeset 276597 e564d6f8056de7f11e0d7ba1def66635c6cefb8f
parent 276596 ebabcb64dab69728255088dffb73c15355ff1f21
child 276598 2c0d64cea673b90bc49aa8d4cfa63787931782cc
push id16678
push usercliu@mozilla.com
push dateWed, 16 Dec 2015 18:47:47 +0000
treeherderfx-team@e564d6f8056d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs1212611
milestone46.0a1
Bug 1212611 - Use system notification for website notifications in Android. r=mfinkle
mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
mobile/android/base/java/org/mozilla/gecko/NotificationClient.java
mobile/android/base/java/org/mozilla/gecko/NotificationHandler.java
toolkit/components/alerts/nsAlertsService.cpp
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/GeneratedJNIWrappers.cpp
widget/android/GeneratedJNIWrappers.h
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
@@ -1301,22 +1301,20 @@ public class GeckoAppShell
         if (notificationClient == null) {
             notificationClient = client;
         } else {
             Log.d(LOGTAG, "Notification client already set");
         }
     }
 
     @WrapForJNI(stubName = "ShowAlertNotificationWrapper")
-    public static void showAlertNotification(String aImageUrl, String aAlertTitle, String aAlertText,
-                                             String aAlertCookie, String aAlertName) {
+    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
-        String app = getContext().getClass().getName();
         Intent notificationIntent = new Intent(GeckoApp.ACTION_ALERT_CALLBACK);
-        notificationIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, app);
+        notificationIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
         notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
         int notificationID = aAlertName.hashCode();
 
         // Put the strings into the intent as an URI "alert:?name=<alertName>&app=<appName>&cookie=<cookie>"
         Uri.Builder b = new Uri.Builder();
         Uri dataUri = b.scheme("alert").path(Integer.toString(notificationID))
                                        .appendQueryParameter("name", aAlertName)
@@ -1324,17 +1322,17 @@ public class GeckoAppShell
                                        .build();
         notificationIntent.setData(dataUri);
         PendingIntent contentIntent = PendingIntent.getActivity(
                 getContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
 
         ALERT_COOKIES.put(aAlertName, aAlertCookie);
         callObserver(aAlertName, "alertshow", aAlertCookie);
 
-        notificationClient.add(notificationID, aImageUrl, aAlertTitle, aAlertText, contentIntent);
+        notificationClient.add(notificationID, aImageUrl, aHost, aAlertTitle, aAlertText, contentIntent);
     }
 
     @WrapForJNI
     public static void alertsProgressListener_OnProgress(String aAlertName, long aProgress, long aProgressMax, String aAlertText) {
         int notificationID = aAlertName.hashCode();
         notificationClient.update(notificationID, aProgress, aProgressMax, aAlertText);
     }
 
--- a/mobile/android/base/java/org/mozilla/gecko/NotificationClient.java
+++ b/mobile/android/base/java/org/mozilla/gecko/NotificationClient.java
@@ -69,22 +69,22 @@ public abstract class NotificationClient
         }
     };
 
     /**
      * Adds a notification.
      *
      * @see NotificationHandler#add(int, String, String, String, PendingIntent, PendingIntent)
      */
-    public synchronized void add(final int notificationID, final String aImageUrl,
+    public synchronized void add(final int notificationID, final String aImageUrl, final String aHost,
             final String aAlertTitle, final String aAlertText, final PendingIntent contentIntent) {
         mTaskQueue.add(new Runnable() {
             @Override
             public void run() {
-                mHandler.add(notificationID, aImageUrl, aAlertTitle, aAlertText, contentIntent);
+                mHandler.add(notificationID, aImageUrl, aHost, aAlertTitle, aAlertText, contentIntent);
             }
         });
         notify();
 
         if (!mReady) {
             bind();
         }
     }
--- a/mobile/android/base/java/org/mozilla/gecko/NotificationHandler.java
+++ b/mobile/android/base/java/org/mozilla/gecko/NotificationHandler.java
@@ -1,29 +1,28 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko;
 
-import org.mozilla.gecko.gfx.BitmapUtils;
+import android.graphics.Bitmap;
 
 import android.app.Notification;
-import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.Context;
-import android.net.Uri;
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.app.NotificationManagerCompat;
-import android.util.Log;
+import org.mozilla.gecko.gfx.BitmapUtils;
 
 import java.util.concurrent.ConcurrentHashMap;
 
 public class NotificationHandler {
+    private static String LOGTAG = "GeckoNotifHandler";
     private final ConcurrentHashMap<Integer, Notification>
             mNotifications = new ConcurrentHashMap<Integer, Notification>();
     private final Context mContext;
     private final NotificationManagerCompat mNotificationManager;
 
     /**
      * Notification associated with this service's foreground state.
      *
@@ -46,31 +45,39 @@ public class NotificationHandler {
      * Adds a notification.
      *
      * @param notificationID the unique ID of the notification
      * @param aImageUrl      URL of the image to use
      * @param aAlertTitle    title of the notification
      * @param aAlertText     text of the notification
      * @param contentIntent  Intent used when the notification is clicked
      */
-    public void add(int notificationID, String aImageUrl, String aAlertTitle,
+    public void add(final int notificationID, String aImageUrl, String aHost, String aAlertTitle,
                     String aAlertText, PendingIntent contentIntent) {
         // Remove the old notification with the same ID, if any
         remove(notificationID);
 
-        Uri imageUri = Uri.parse(aImageUrl);
-        int icon = BitmapUtils.getResource(imageUri, R.drawable.ic_status_logo);
-
-        Notification notification = new NotificationCompat.Builder(mContext)
+        final NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext)
                 .setContentTitle(aAlertTitle)
                 .setContentText(aAlertText)
-                .setSmallIcon(icon)
-                .setWhen(System.currentTimeMillis())
+                .setSmallIcon(R.drawable.ic_status_logo)
                 .setContentIntent(contentIntent)
-                .build();
+                .setAutoCancel(true)
+                .setStyle(new NotificationCompat.InboxStyle()
+                          .addLine(aAlertText)
+                          .setSummaryText(aHost));
+
+        // Fetch icon.
+        if (!aImageUrl.isEmpty()) {
+            final Bitmap image = BitmapUtils.decodeUrl(aImageUrl);
+            builder.setLargeIcon(image);
+        }
+
+        builder.setWhen(System.currentTimeMillis());
+        final Notification notification = builder.build();
 
         mNotificationManager.notify(notificationID, notification);
         mNotifications.put(notificationID, notification);
     }
 
     /**
      * Adds a notification.
      *
--- a/toolkit/components/alerts/nsAlertsService.cpp
+++ b/toolkit/components/alerts/nsAlertsService.cpp
@@ -89,17 +89,17 @@ NS_IMETHODIMP nsAlertsService::ShowAlert
                                    PromiseFlatString(aData),
                                    IPC::Principal(aPrincipal),
                                    aInPrivateBrowsing);
     return NS_OK;
   }
 
 #ifdef MOZ_WIDGET_ANDROID
   mozilla::AndroidBridge::Bridge()->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertCookie,
-                                                          aAlertListener, aAlertName);
+                                                          aAlertListener, aAlertName, aPrincipal);
   return NS_OK;
 #else
   // Check if there is an optional service that handles system-level notifications
   nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID));
   nsresult rv;
   if (sysAlerts) {
     rv = sysAlerts->ShowAlertNotification(aImageUrl, aAlertTitle, aAlertText, aAlertTextClickable,
                                           aAlertCookie, aAlertListener, aAlertName,
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -13,16 +13,17 @@
 
 #include "mozilla/Hal.h"
 #include "nsXULAppAPI.h"
 #include <prthread.h>
 #include "nsXPCOMStrings.h"
 #include "AndroidBridge.h"
 #include "AndroidJNIWrapper.h"
 #include "AndroidBridgeUtilities.h"
+#include "nsAlertsUtils.h"
 #include "nsAppShell.h"
 #include "nsOSHelperAppService.h"
 #include "nsWindow.h"
 #include "mozilla/Preferences.h"
 #include "nsThreadUtils.h"
 #include "nsIThreadManager.h"
 #include "mozilla/dom/mobilemessage/PSms.h"
 #include "gfxPlatform.h"
@@ -514,25 +515,29 @@ AndroidBridge::GetClipboardText(nsAStrin
 }
 
 void
 AndroidBridge::ShowAlertNotification(const nsAString& aImageUrl,
                                      const nsAString& aAlertTitle,
                                      const nsAString& aAlertText,
                                      const nsAString& aAlertCookie,
                                      nsIObserver *aAlertListener,
-                                     const nsAString& aAlertName)
+                                     const nsAString& aAlertName,
+                                     nsIPrincipal* aPrincipal)
 {
     if (nsAppShell::gAppShell && aAlertListener) {
         // This will remove any observers already registered for this id
         nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeAddObserver(aAlertName, aAlertListener));
     }
 
+    nsAutoString host;
+    nsAlertsUtils::GetSourceHostPort(aPrincipal, host);
+
     GeckoAppShell::ShowAlertNotificationWrapper
-           (aImageUrl, aAlertTitle, aAlertText, aAlertCookie, aAlertName);
+           (aImageUrl, aAlertTitle, aAlertText, aAlertCookie, aAlertName, host);
 }
 
 int
 AndroidBridge::GetDPI()
 {
     static int sDPI = 0;
     if (sDPI)
         return sDPI;
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -201,17 +201,18 @@ public:
 
     bool GetClipboardText(nsAString& aText);
 
     void ShowAlertNotification(const nsAString& aImageUrl,
                                const nsAString& aAlertTitle,
                                const nsAString& aAlertText,
                                const nsAString& aAlertData,
                                nsIObserver *aAlertListener,
-                               const nsAString& aAlertName);
+                               const nsAString& aAlertName,
+                               nsIPrincipal* aPrincipal);
 
     int GetDPI();
     int GetScreenDepth();
 
     void Vibrate(const nsTArray<uint32_t>& aPattern);
 
     void GetSystemColors(AndroidSystemColors *aColors);
 
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -652,19 +652,19 @@ constexpr char GeckoAppShell::SetURITitl
 auto GeckoAppShell::SetURITitle(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1) -> void
 {
     return mozilla::jni::Method<SetURITitle_t>::Call(nullptr, nullptr, a0, a1);
 }
 
 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) -> void
+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(nullptr, nullptr, a0, a1, a2, a3, a4);
+    return mozilla::jni::Method<ShowAlertNotificationWrapper_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4, a5);
 }
 
 constexpr char GeckoAppShell::ShowInputMethodPicker_t::name[];
 constexpr char GeckoAppShell::ShowInputMethodPicker_t::signature[];
 
 auto GeckoAppShell::ShowInputMethodPicker() -> void
 {
     return mozilla::jni::Method<ShowInputMethodPicker_t>::Call(nullptr, nullptr);
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -1566,27 +1566,28 @@ public:
         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> Args;
         static constexpr char name[] = "showAlertNotification";
         static constexpr char signature[] =
-                "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V";
+                "(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 bool isMultithreaded = false;
         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) -> void;
+    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;
 
 public:
     struct ShowInputMethodPicker_t {
         typedef GeckoAppShell Owner;
         typedef void ReturnType;
         typedef void SetterType;
         typedef mozilla::jni::Args<> Args;
         static constexpr char name[] = "showInputMethodPicker";