Bläddra i källkod

Refactor - extracted common method to load avatars for notifications

Signed-off-by: Dariusz Olszewski <starypatyk@users.noreply.github.com>
Dariusz Olszewski 3 år sedan
förälder
incheckning
d4bdd88588

+ 8 - 37
app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java

@@ -37,14 +37,6 @@ import android.util.Base64;
 import android.util.Log;
 
 import com.bluelinelabs.logansquare.LoganSquare;
-import com.facebook.common.executors.UiThreadImmediateExecutorService;
-import com.facebook.common.references.CloseableReference;
-import com.facebook.datasource.DataSource;
-import com.facebook.drawee.backends.pipeline.Fresco;
-import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
-import com.facebook.imagepipeline.image.CloseableImage;
-import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor;
-import com.facebook.imagepipeline.request.ImageRequest;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.activities.CallActivity;
 import com.nextcloud.talk.activities.MainActivity;
@@ -61,7 +53,6 @@ import com.nextcloud.talk.models.json.push.DecryptedPushMessage;
 import com.nextcloud.talk.models.json.push.NotificationUser;
 import com.nextcloud.talk.receivers.DirectReplyReceiver;
 import com.nextcloud.talk.utils.ApiUtils;
-import com.nextcloud.talk.utils.DisplayUtils;
 import com.nextcloud.talk.utils.DoNotDisturbUtils;
 import com.nextcloud.talk.utils.NotificationUtils;
 import com.nextcloud.talk.utils.PushUtils;
@@ -93,7 +84,6 @@ import androidx.core.app.NotificationCompat.MessagingStyle;
 import androidx.core.app.NotificationManagerCompat;
 import androidx.core.app.Person;
 import androidx.core.app.RemoteInput;
-import androidx.core.graphics.drawable.IconCompat;
 import androidx.emoji.text.EmojiCompat;
 import androidx.work.Data;
 import androidx.work.Worker;
@@ -395,9 +385,10 @@ public class NotificationWorker extends Worker {
         final NotificationUser notificationUser = decryptedPushMessage.getNotificationUser();
         final String userType = notificationUser.getType();
 
-        MessagingStyle style = activeStatusBarNotification != null ?
-                MessagingStyle.extractMessagingStyleFromNotification(activeStatusBarNotification.getNotification()) :
-                null;
+        MessagingStyle style = null;
+        if (activeStatusBarNotification != null) {
+            style = MessagingStyle.extractMessagingStyleFromNotification(activeStatusBarNotification.getNotification());
+        }
 
         Person.Builder person =
                 new Person.Builder()
@@ -413,31 +404,11 @@ public class NotificationWorker extends Worker {
             String avatarUrl = "user".equals(userType) ?
                 ApiUtils.getUrlForAvatar(baseUrl, notificationUser.getId(), false) :
                 ApiUtils.getUrlForGuestAvatar(baseUrl, notificationUser.getName(), false);
-
-            ImageRequest imageRequest = DisplayUtils.getImageRequestForUrl(avatarUrl, null);
-            Fresco.getImagePipeline().fetchDecodedImage(imageRequest, context).subscribe(
-                    new BaseBitmapDataSubscriber() {
-                        @Override
-                        protected void onNewResultImpl(Bitmap bitmap) {
-                            if (bitmap != null) {
-                                new RoundAsCirclePostprocessor(true).process(bitmap);
-                                person.setIcon(IconCompat.createWithBitmap(bitmap));
-                                notificationBuilder.setStyle(getStyle(person.build(), style));
-                                sendNotificationWithId(notificationId, notificationBuilder.build());
-                            }
-                        }
-
-                        @Override
-                        protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
-                            notificationBuilder.setStyle(getStyle(person.build(), style));
-                            sendNotificationWithId(notificationId, notificationBuilder.build());
-                        }
-                    },
-                    UiThreadImmediateExecutorService.getInstance());
-        } else {
-            notificationBuilder.setStyle(getStyle(person.build(), style));
-            sendNotificationWithId(notificationId, notificationBuilder.build());
+            person.setIcon(NotificationUtils.INSTANCE.loadAvatarSync(avatarUrl));
         }
+
+        notificationBuilder.setStyle(getStyle(person.build(), style));
+        sendNotificationWithId(notificationId, notificationBuilder.build());
     }
 
     private void addReplyAction(NotificationCompat.Builder notificationBuilder, int notificationId) {

+ 4 - 35
app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt

@@ -25,28 +25,18 @@ import android.app.NotificationManager
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
-import android.graphics.Bitmap
 import android.os.Build
 import androidx.annotation.RequiresApi
 import androidx.core.app.NotificationCompat
 import androidx.core.app.NotificationManagerCompat
 import androidx.core.app.Person
 import androidx.core.app.RemoteInput
-import androidx.core.graphics.drawable.IconCompat
 import autodagger.AutoInjector
-import com.facebook.common.executors.UiThreadImmediateExecutorService
-import com.facebook.common.references.CloseableReference
-import com.facebook.datasource.DataSource
-import com.facebook.drawee.backends.pipeline.Fresco
-import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
-import com.facebook.imagepipeline.image.CloseableImage
-import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.models.json.generic.GenericOverall
 import com.nextcloud.talk.utils.ApiUtils
-import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.NotificationUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_ID
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
@@ -110,7 +100,7 @@ class DirectReplyReceiver : BroadcastReceiver() {
 
                 @RequiresApi(Build.VERSION_CODES.N)
                 override fun onNext(genericOverall: GenericOverall) {
-                    loadAvatar(::confirmReplySent)
+                    confirmReplySent()
                 }
 
                 override fun onError(e: Throwable) {
@@ -124,27 +114,6 @@ class DirectReplyReceiver : BroadcastReceiver() {
             })
     }
 
-    private fun loadAvatar(callback: (avatarIcon: IconCompat) -> Unit) {
-        val avatarUrl = ApiUtils.getUrlForAvatar(currentUser.baseUrl, currentUser.userId, false)
-        val imageRequest = DisplayUtils.getImageRequestForUrl(avatarUrl, currentUser)
-        val dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, null)
-        dataSource.subscribe(
-            object : BaseBitmapDataSubscriber() {
-                override fun onNewResultImpl(bitmap: Bitmap?) {
-                    if (bitmap != null) {
-                        RoundAsCirclePostprocessor(true).process(bitmap)
-                        callback(IconCompat.createWithBitmap(bitmap))
-                    }
-                }
-
-                override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage?>>) {
-                    // unused atm
-                }
-            },
-            UiThreadImmediateExecutorService.getInstance()
-        )
-    }
-
     @RequiresApi(Build.VERSION_CODES.N)
     private fun findActiveNotification(notificationId: Int): Notification? {
         val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@@ -152,7 +121,7 @@ class DirectReplyReceiver : BroadcastReceiver() {
     }
 
     @RequiresApi(Build.VERSION_CODES.N)
-    private fun confirmReplySent(avatarIcon: IconCompat) {
+    private fun confirmReplySent() {
         // Implementation inspired by the SO question and article below:
         // https://stackoverflow.com/questions/51549456/android-o-notification-for-direct-reply-message
         // https://medium.com/@sidorovroman3/android-how-to-use-messagingstyle-for-notifications-without-caching-messages-c414ef2b816c
@@ -171,10 +140,10 @@ class DirectReplyReceiver : BroadcastReceiver() {
             .extractMessagingStyleFromNotification(previousNotification)
 
         // Add reply
+        val avatarUrl = ApiUtils.getUrlForAvatar(currentUser.baseUrl, currentUser.userId, false)
         val me = Person.Builder()
             .setName(currentUser.displayName)
-            // .setIcon(IconCompat.createWithResource(context, R.drawable.ic_user))
-            .setIcon(avatarIcon)
+            .setIcon(NotificationUtils.loadAvatarSync(avatarUrl))
             .build()
         val message = NotificationCompat.MessagingStyle.Message(replyMessage, System.currentTimeMillis(), me)
         previousStyle?.addMessage(message)

+ 31 - 0
app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt

@@ -32,7 +32,13 @@ import android.net.Uri
 import android.os.Build
 import android.service.notification.StatusBarNotification
 import android.text.TextUtils
+import androidx.core.graphics.drawable.IconCompat
 import com.bluelinelabs.logansquare.LoganSquare
+import com.facebook.common.references.CloseableReference
+import com.facebook.datasource.DataSources
+import com.facebook.drawee.backends.pipeline.Fresco
+import com.facebook.imagepipeline.image.CloseableBitmap
+import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor
 import com.nextcloud.talk.BuildConfig
 import com.nextcloud.talk.R
 import com.nextcloud.talk.models.RingtoneSettings
@@ -297,6 +303,31 @@ object NotificationUtils {
         )
     }
 
+    /*
+    * Load user avatar synchronously.
+    * Inspired by:
+    * https://frescolib.org/docs/using-image-pipeline.html
+    * https://github.com/facebook/fresco/issues/830
+    * https://localcoder.org/using-facebooks-fresco-to-load-a-bitmap
+    */
+    fun loadAvatarSync(avatarUrl: String): IconCompat? {
+        // TODO - how to handle errors here?
+        var avatarIcon: IconCompat? = null
+        val imageRequest = DisplayUtils.getImageRequestForUrl(avatarUrl, null)
+        val dataSource = Fresco.getImagePipeline().fetchDecodedImage(imageRequest, null)
+        val closeableImageRef = DataSources.waitForFinalResult(dataSource) as CloseableReference<CloseableBitmap>?
+        val bitmap = closeableImageRef?.get()?.underlyingBitmap
+        if (bitmap != null) {
+            // According to Fresco documentation a copy of the bitmap should be made before closing the references.
+            // However, it seems to work without making a copy... ;-)
+            RoundAsCirclePostprocessor(true).process(bitmap)
+            avatarIcon = IconCompat.createWithBitmap(bitmap)
+        }
+        CloseableReference.closeSafely(closeableImageRef)
+        dataSource.close()
+        return avatarIcon
+    }
+
     private data class Channel(
         val id: String,
         val name: String,