diff --git a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java index c9112583b..aeb057dd1 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.java +++ b/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> 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) { diff --git a/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt b/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt index 88b85fb22..24249c5e1 100644 --- a/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt +++ b/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>) { - // 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) diff --git a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt index d4a942f89..a73a76179 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt +++ b/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? + 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,