From 2583a1b4d30ab4e1c8bbd78b0e6172b7e37f427e Mon Sep 17 00:00:00 2001 From: Petru-Mugurel Lingurar Date: Mon, 4 Mar 2019 17:39:53 +0000 Subject: [PATCH] Bug 1507427 - Apply size restrictions for the largeIcon used in NotificationClient; r=JanH There are crash reports for large heap allocations for Bitmaps from the NotificationClient#add method. As more of a speculative fix this patch introduces bitmap size constraints for the largeIcon of the notification this method posts. Previously the app would happily load any image from the passed in image URL even though the maximum size the largeIcon can be is 256x256 pixels. Differential Revision: https://phabricator.services.mozilla.com/D21666 --HG-- extra : moz-landing-system : lando --- .../notifications/NotificationClient.java | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java index 0a14ecb5f45d..41d8f8337c28 100644 --- a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java +++ b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java @@ -11,20 +11,24 @@ import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.graphics.Bitmap; import android.net.Uri; import android.support.annotation.NonNull; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; +import com.squareup.picasso.Picasso; + import org.mozilla.gecko.AppConstants; import org.mozilla.gecko.GeckoActivityMonitor; import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoService; import org.mozilla.gecko.NotificationListener; import org.mozilla.gecko.R; -import org.mozilla.gecko.util.BitmapUtils; +import org.mozilla.gecko.util.ThreadUtils; +import java.io.IOException; import java.util.HashMap; /** @@ -40,6 +44,8 @@ public final class NotificationClient implements NotificationListener { private final NotificationManagerCompat mNotificationManager; private final HashMap mNotifications = new HashMap<>(); + private final int notificationLargeIconHeight; + private final int notificationLargeIconWidth; /** * Notification associated with this service's foreground state. @@ -56,6 +62,12 @@ public final class NotificationClient implements NotificationListener { public NotificationClient(Context context) { mContext = context.getApplicationContext(); mNotificationManager = NotificationManagerCompat.from(mContext); + + Resources resources = mContext.getResources(); + notificationLargeIconHeight = resources + .getDimensionPixelSize(android.R.dimen.notification_large_icon_height); + notificationLargeIconWidth = resources + .getDimensionPixelSize(android.R.dimen.notification_large_icon_width); } @Override // NotificationListener @@ -161,8 +173,22 @@ public final class NotificationClient implements NotificationListener { // Fetch icon. if (!imageUrl.isEmpty()) { - final Bitmap image = BitmapUtils.decodeUrl(imageUrl); - builder.setLargeIcon(image); + ThreadUtils.postToBackgroundThread(() -> { + Bitmap largeIcon = null; + try { + largeIcon = Picasso.with(mContext) + .load(imageUrl) + .resize(notificationLargeIconWidth, notificationLargeIconHeight) + .centerInside() + .get(); + } catch (IOException e) { + e.printStackTrace(); + } + + if (largeIcon != null) { + updateLargeIconForExistingNotification(name, largeIcon, builder); + } + }); } builder.setWhen(System.currentTimeMillis()); @@ -363,4 +389,30 @@ public final class NotificationClient implements NotificationListener { removeForegroundNotificationLocked(); } + + /** + * Update the largeIcon for an already posted {@link NotificationCompat}. + *
+ * It may be a foreground notification or not and it may have already been removed + * in which case nothing will happen. + * + * @param notificationName the unique name by which to identify a particular notification + * @param largeIcon image to be used as {@link Notification#getLargeIcon()} + * @param builder the builder for the original notification. Holds all previous configuration. + */ + private synchronized void updateLargeIconForExistingNotification(@NonNull final String notificationName, + @NonNull final Bitmap largeIcon, + @NonNull final NotificationCompat.Builder builder) { + // check if the notification hasn't been removed in the meantime + Notification notification = mNotifications.get(notificationName); + + if (notification == null) { + return; + } + + builder.setOnlyAlertOnce(true) + .setLargeIcon(largeIcon); + + add(notificationName, builder.build()); + } }