From 1d98bd4988eea2de0b83b111c6389c051453c8a3 Mon Sep 17 00:00:00 2001 From: Martin Santangelo Date: Fri, 25 May 2018 18:29:54 -0300 Subject: [PATCH 1/2] (feat) support for remote large icon and big picture added --- .../core/BitmapLoader.java | 68 +++++++++++++++ .../core/notification/PushNotification.java | 87 ++++++++++++------- .../notification/PushNotificationProps.java | 8 ++ 3 files changed, 133 insertions(+), 30 deletions(-) create mode 100644 android/src/main/java/com/wix/reactnativenotifications/core/BitmapLoader.java diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/BitmapLoader.java b/android/src/main/java/com/wix/reactnativenotifications/core/BitmapLoader.java new file mode 100644 index 000000000..e61cfefea --- /dev/null +++ b/android/src/main/java/com/wix/reactnativenotifications/core/BitmapLoader.java @@ -0,0 +1,68 @@ +package com.wix.reactnativenotifications.core; + +import android.content.Context; +import android.graphics.Bitmap; +import android.net.Uri; +import android.util.Log; + +import com.facebook.common.executors.CallerThreadExecutor; +import com.facebook.common.references.CloseableReference; +import com.facebook.datasource.BaseDataSubscriber; +import com.facebook.datasource.DataSource; +//import com.facebook.datasource.DataSubscriber; +import com.facebook.drawee.backends.pipeline.Fresco; +import com.facebook.imagepipeline.core.ImagePipeline; +import com.facebook.imagepipeline.image.CloseableBitmap; +import com.facebook.imagepipeline.image.CloseableImage; +import com.facebook.imagepipeline.request.ImageRequest; +import com.facebook.imagepipeline.request.ImageRequestBuilder; +import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber; + +import static com.wix.reactnativenotifications.Defs.LOGTAG; + +public class BitmapLoader { + public interface OnBitmapLoadedCallback { + // The lifetime of the Bitmap is only valid for the duration of the callback. If the Bitmap + // is required for a longer duration it should be copied. + void onBitmapLoaded(Bitmap bitmap); + } + + private final Context mContext; + + public BitmapLoader(Context context) { + mContext = context; + } + + public void loadUri(final Uri uri, final OnBitmapLoadedCallback callback) { + final ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri) + .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH) + .setProgressiveRenderingEnabled(false) + .build(); + + // fix: Fresco not initilized if app is closed + if (!Fresco.hasBeenInitialized()) { + Fresco.initialize(mContext); + } + + final ImagePipeline imagePipeline = Fresco.getImagePipeline(); + final DataSource> dataSource = imagePipeline.fetchDecodedImage(request, mContext); + + final BaseBitmapDataSubscriber dataSubscriber = new BaseBitmapDataSubscriber() { + + @Override + protected void onNewResultImpl(Bitmap bitmap) { + if (dataSource.isFinished()) { + callback.onBitmapLoaded(bitmap); + } + } + + @Override + protected void onFailureImpl(final DataSource> dataSource) { + Log.e(LOGTAG, "Failed to load image from " + uri, dataSource.getFailureCause()); + dataSource.close(); + } + }; + + dataSource.subscribe(dataSubscriber, CallerThreadExecutor.getInstance()); + } +} \ No newline at end of file diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java index 3bf6b9e48..873bd02d2 100644 --- a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java +++ b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java @@ -26,7 +26,9 @@ import com.wix.reactnativenotifications.core.JsIOHelper; import com.wix.reactnativenotifications.core.NotificationIntentAdapter; import com.wix.reactnativenotifications.core.ProxyService; +import com.wix.reactnativenotifications.core.BitmapLoader; +import static com.wix.reactnativenotifications.Defs.LOGTAG; import static com.wix.reactnativenotifications.Defs.NOTIFICATION_OPENED_EVENT_NAME; import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME; @@ -34,6 +36,7 @@ public class PushNotification implements IPushNotification { + final protected BitmapLoader mImageLoader; final protected Bundle mBundle; final protected Context mContext; final protected AppLifecycleFacade mAppLifecycleFacade; @@ -57,16 +60,17 @@ public static IPushNotification get(Context context, Bundle bundle) { if (appContext instanceof INotificationsApplication) { return ((INotificationsApplication) appContext).getPushNotification(context, bundle, AppLifecycleFacadeHolder.get(), new AppLaunchHelper()); } - return new PushNotification(context, bundle, AppLifecycleFacadeHolder.get(), new AppLaunchHelper(), new JsIOHelper()); + return new PushNotification(context, bundle, AppLifecycleFacadeHolder.get(), new AppLaunchHelper(), new JsIOHelper(), new BitmapLoader(appContext)); } - protected PushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper JsIOHelper) { + protected PushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper JsIOHelper, BitmapLoader imageLoader) { mContext = context; mBundle = bundle; mAppLifecycleFacade = appLifecycleFacade; mAppLaunchHelper = appLaunchHelper; mJsIOHelper = JsIOHelper; mNotificationProps = createProps(bundle); + mImageLoader = imageLoader; } @Override @@ -95,24 +99,21 @@ public PushNotificationProps asProps() { protected int postNotification(Integer notificationId) { final PendingIntent pendingIntent = getCTAPendingIntent(); - final Notification notification = buildNotification(pendingIntent); - return postNotification(notification, notificationId); - } + //final Notification notification = buildNotification(pendingIntent); + int id = notificationId != null ? notificationId : createNotificationId(); - protected int postNotification(Notification notification, Integer notificationId) { - int id = notificationId != null ? notificationId : createNotificationId(notification); int badge = mNotificationProps.getBadge(); if (badge >= 0) { ApplicationBadgeHelper.INSTANCE.setApplicationIconBadgeNumber(mContext, badge); } - postNotification(id, notification); + + setLargeIconThenPostNotification(id, getNotificationBuilder(pendingIntent)); return id; } protected void postNotification(int id, Notification notification) { final NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); - Log.d("PUSHMARTIN", "- emitiendo "+notification.getGroup()); notificationManager.notify(notification.getGroup(), id, notification); stackNotificationIfNeeded(notification); @@ -170,6 +171,47 @@ protected Notification buildNotification(PendingIntent intent) { return getNotificationBuilder(intent).build(); } + protected void setLargeIconThenPostNotification(final int notificationId, final Notification.Builder notificationBuilder) { + final String icon = mNotificationProps.getLargeIcon(); + + if (icon != null && (icon.startsWith("http://") || icon.startsWith("https://") || icon.startsWith("file://"))) { + mImageLoader.loadUri(Uri.parse(icon), new BitmapLoader.OnBitmapLoadedCallback() { + @Override + public void onBitmapLoaded(Bitmap bitmap) { + notificationBuilder.setLargeIcon(bitmap); + setBigPictureThenPostNotification(notificationId, notificationBuilder); + } + }); + } else { + if (icon != null) { + final int id = mContext.getResources().getIdentifier(icon, "drawable", mContext.getPackageName()); + final Bitmap bitmap = id != 0 ? BitmapFactory.decodeResource(mContext.getResources(), id) : null; + + if (bitmap != null) { + notificationBuilder.setLargeIcon(bitmap); + } + } + + setBigPictureThenPostNotification(notificationId, notificationBuilder); + } + } + + protected void setBigPictureThenPostNotification(final int notificationId, final Notification.Builder notificationBuilder) { + final String bigPicture = mNotificationProps.getBigPicture(); + + if (bigPicture != null && (bigPicture.startsWith("http://") || bigPicture.startsWith("https://") || bigPicture.startsWith("file://"))) { + mImageLoader.loadUri(Uri.parse(bigPicture), new BitmapLoader.OnBitmapLoadedCallback() { + @Override + public void onBitmapLoaded(Bitmap bitmap) { + notificationBuilder.setStyle(new Notification.BigPictureStyle().bigPicture(bitmap).setSummaryText(mNotificationProps.getBody())); + postNotification(notificationId, notificationBuilder.build()); + } + }); + } else { + postNotification(notificationId, notificationBuilder.build()); + } + } + protected Notification.Builder getNotificationBuilder(PendingIntent intent) { Resources res = mContext.getResources(); String packageName = mContext.getPackageName(); @@ -195,17 +237,6 @@ protected Notification.Builder getNotificationBuilder(PendingIntent intent) { int smallIconResId = getSmallIconResId(); - int largeIconResId; - - String largeIcon = mBundle.getString("largeIcon"); - - if (largeIcon != null) { - largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName); - } else { - largeIconResId = res.getIdentifier("ic_launcher", "mipmap", packageName); - } - - Bitmap largeIconBitmap = BitmapFactory.decodeResource(res, largeIconResId); String title = mNotificationProps.getTitle(); if (title == null) { @@ -223,17 +254,11 @@ protected Notification.Builder getNotificationBuilder(PendingIntent intent) { .setSound(soundUri) .setAutoCancel(true); - // we group by uri if it exists - if (mNotificationProps.getUri() != null) { - notificationBuilder.setGroup(mNotificationProps.getUri()); - } else { + // we group if it exists + if (mNotificationProps.getGroup() != null){ notificationBuilder.setGroup(mNotificationProps.getGroup()); } - if (largeIconResId != 0 && (largeIcon != null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)) { - notificationBuilder.setLargeIcon(largeIconBitmap); - } - return notificationBuilder; } @@ -310,9 +335,11 @@ private void stackNotificationIfNeeded(Notification notification) { .setPriority(Notification.PRIORITY_HIGH); builder.setContentIntent(getCTAPendingIntent()); - + builder.setSmallIcon(smallIconResId); + if (notification.getLargeIcon() != null) builder.setLargeIcon(notification.getLargeIcon()); + Notification stackNotification = builder.build(); stackNotification.defaults = Notification.DEFAULT_ALL; @@ -329,7 +356,7 @@ protected void clearAllNotifications() { notificationManager.cancelAll(); } - protected int createNotificationId(Notification notification) { + protected int createNotificationId() { return (int) System.nanoTime(); } diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationProps.java b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationProps.java index 8838d8573..e741fb552 100644 --- a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationProps.java +++ b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationProps.java @@ -45,6 +45,14 @@ public String getBody() { return mBundle.getString("body"); } + public String getBigPicture() { + return mBundle.getString("bigPicture"); + } + + public String getLargeIcon() { + return mBundle.getString("largeIcon"); + } + public boolean isVisible() { String title = getTitle(); String sound = getSound(); From 6d5c5d35e88bc7920e0e40c814aed04ebaed5001 Mon Sep 17 00:00:00 2001 From: Martin Santangelo Date: Tue, 29 May 2018 11:49:10 -0300 Subject: [PATCH 2/2] (fix) grouping and badge update --- .../core/notification/PushNotification.java | 2 +- .../core/notification/PushNotificationProps.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java index 873bd02d2..d89fccf69 100644 --- a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java +++ b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java @@ -314,7 +314,7 @@ private void stackNotificationIfNeeded(Notification notification) { Notification.InboxStyle inbox = new Notification.InboxStyle(); { for (StatusBarNotification activeSbn : groupedNotifications) { - String stackNotificationLine = (String)activeSbn.getNotification().extras.get(Notification.EXTRA_TITLE); + String stackNotificationLine = (String)activeSbn.getNotification().extras.get(Notification.EXTRA_TEXT); if (stackNotificationLine != null) { inbox.addLine(stackNotificationLine); } diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationProps.java b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationProps.java index e741fb552..147b6ab25 100644 --- a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationProps.java +++ b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationProps.java @@ -26,7 +26,7 @@ public PushNotificationProps(Bundle bundle) { public int getBadge() { if (mBundle.containsKey("badge")) { - return mBundle.getInt("badge"); + return Integer.parseInt(mBundle.getString("badge")); } return -1; }