From e4d838cd8b2c4905c5d41b0b1f9d2d04c60f5105 Mon Sep 17 00:00:00 2001 From: Mario Danic Date: Thu, 20 Feb 2020 13:45:14 +0100 Subject: [PATCH] Fix most of message notifications Signed-off-by: Mario Danic --- .../firebase/MagicFirebaseMessagingService.kt | 15 ++- .../talk/jobs/MessageNotificationWorker.kt | 124 +++++++++++++++--- ...fication.java => SignatureVerification.kt} | 28 ++-- .../json/notifications/Notification.java | 4 + .../domain/usecases/GetNotificationUseCase.kt | 2 +- 5 files changed, 137 insertions(+), 36 deletions(-) rename app/src/main/java/com/nextcloud/talk/models/{SignatureVerification.java => SignatureVerification.kt} (61%) diff --git a/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt b/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt index db8182afa..3e67c3828 100644 --- a/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt @@ -44,6 +44,7 @@ import com.nextcloud.talk.jobs.MessageNotificationWorker import com.nextcloud.talk.models.SignatureVerification import com.nextcloud.talk.models.json.push.DecryptedPushMessage import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository +import com.nextcloud.talk.newarch.utils.MagicJson import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.NotificationUtils.cancelAllNotificationsForAccount import com.nextcloud.talk.utils.NotificationUtils.cancelExistingNotificationWithId @@ -52,6 +53,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FROM_NOTIFICATION_START_CALL import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY import com.nextcloud.talk.utils.preferences.AppPreferences +import kotlinx.serialization.json.Json import okhttp3.OkHttpClient import org.greenrobot.eventbus.EventBus import org.koin.core.KoinComponent @@ -114,13 +116,12 @@ class MagicFirebaseMessagingService : FirebaseMessagingService(), KoinComponent val decryptedSubject = cipher.doFinal(base64DecodedSubject) decryptedPushMessage = LoganSquare.parse(String(decryptedSubject), DecryptedPushMessage::class.java) decryptedPushMessage.apply { - val timestamp = decryptedPushMessage.timestamp when { delete -> { - cancelExistingNotificationWithId(applicationContext, signatureVerification.userEntity, notificationId!!) + cancelExistingNotificationWithId(applicationContext, signatureVerification.userEntity!!, notificationId!!) } deleteAll -> { - cancelAllNotificationsForAccount(applicationContext, signatureVerification.userEntity) + cancelAllNotificationsForAccount(applicationContext, signatureVerification.userEntity!!) } type == "call" -> { val fullScreenIntent = Intent(applicationContext, MagicCallActivity::class.java) @@ -145,7 +146,7 @@ class MagicFirebaseMessagingService : FirebaseMessagingService(), KoinComponent NotificationManagerCompat.IMPORTANCE_HIGH, soundUri!!, audioAttributesBuilder.build(), vibrationEffect, false, null) - val userBaseUrl = Uri.parse(signatureVerification.userEntity.baseUrl).toString() + val userBaseUrl = Uri.parse(signatureVerification.userEntity!!.baseUrl).toString() val notificationBuilder = NotificationCompat.Builder(this@MagicFirebaseMessagingService, notificationChannelId) .setPriority(NotificationCompat.PRIORITY_HIGH) @@ -153,7 +154,7 @@ class MagicFirebaseMessagingService : FirebaseMessagingService(), KoinComponent .setSmallIcon(R.drawable.ic_call_black_24dp) .setSubText(userBaseUrl) .setShowWhen(true) - .setWhen(timestamp) + .setWhen(System.currentTimeMillis()) .setContentTitle(EmojiCompat.get().process(decryptedPushMessage.subject.toString())) .setAutoCancel(true) .setOngoing(true) @@ -173,9 +174,11 @@ class MagicFirebaseMessagingService : FirebaseMessagingService(), KoinComponent startForeground(timestamp.toInt(), notification) } else -> { + val json = Json(MagicJson.customJsonConfiguration) + val messageData = Data.Builder() .putString(BundleKeys.KEY_DECRYPTED_PUSH_MESSAGE, LoganSquare.serialize(decryptedPushMessage)) - .putString(BundleKeys.KEY_SIGNATURE_VERIFICATION, LoganSquare.serialize(signatureVerification)) + .putString(BundleKeys.KEY_SIGNATURE_VERIFICATION, json.stringify(SignatureVerification.serializer(), signatureVerification)) .build() val pushNotificationWork = OneTimeWorkRequest.Builder(MessageNotificationWorker::class.java).setInputData(messageData).build() WorkManager.getInstance().enqueue(pushNotificationWork) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/MessageNotificationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/MessageNotificationWorker.kt index 77fceea9e..21452bf2c 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/MessageNotificationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/MessageNotificationWorker.kt @@ -44,15 +44,28 @@ import com.bluelinelabs.logansquare.LoganSquare import com.nextcloud.talk.R import com.nextcloud.talk.activities.MainActivity import com.nextcloud.talk.models.SignatureVerification +import com.nextcloud.talk.models.json.chat.ChatUtils import com.nextcloud.talk.models.json.conversations.Conversation +import com.nextcloud.talk.models.json.notifications.NotificationOverall import com.nextcloud.talk.models.json.push.DecryptedPushMessage +import com.nextcloud.talk.models.json.push.NotificationUser +import com.nextcloud.talk.newarch.data.model.ErrorModel +import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler +import com.nextcloud.talk.newarch.domain.usecases.GetNotificationUseCase +import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse import com.nextcloud.talk.newarch.utils.Images +import com.nextcloud.talk.newarch.utils.MagicJson +import com.nextcloud.talk.newarch.utils.NextcloudRepositoryWithNoCookies import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.preferences.AppPreferences +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.coroutineScope +import kotlinx.serialization.json.Json import org.koin.core.KoinComponent import org.koin.core.inject +import org.koin.core.parameter.parametersOf import java.util.function.Consumer class MessageNotificationWorker( @@ -60,14 +73,17 @@ class MessageNotificationWorker( workerParams: WorkerParameters ) : CoroutineWorker(context, workerParams), KoinComponent { val appPreferences: AppPreferences by inject() + private val nextcloudRepositoryWithNoCookies: NextcloudRepositoryWithNoCookies by inject() + private val apiErrorHandler: ApiErrorHandler by inject() - override suspend fun doWork(): Result { + override suspend fun doWork(): Result = coroutineScope { val data = inputData val decryptedPushMessageString: String = data.getString(BundleKeys.KEY_DECRYPTED_PUSH_MESSAGE)!! val signatureVerificationString: String = data.getString(BundleKeys.KEY_SIGNATURE_VERIFICATION)!! + val json = Json(MagicJson.customJsonConfiguration) val decryptedPushMessage = LoganSquare.parse(decryptedPushMessageString, DecryptedPushMessage::class.java) - val signatureVerification = LoganSquare.parse(signatureVerificationString, SignatureVerification::class.java) + val signatureVerification = json.parse(SignatureVerification.serializer(), signatureVerificationString) // we support Nextcloud Talk 4.0 and up so assuming "no-ping" capability here val intent = Intent(applicationContext, MainActivity::class.java) @@ -78,30 +94,97 @@ class MessageNotificationWorker( when (decryptedPushMessage.type) { "room" -> { - showNotificationWithObjectData(decryptedPushMessage, signatureVerification, intent) + showNotificationWithObjectData(this, decryptedPushMessage, signatureVerification, intent) } "chat" -> { - if (decryptedPushMessage.notificationId != null) { - showNotificationWithObjectData(decryptedPushMessage, signatureVerification, intent) - } else { - showNotification(decryptedPushMessage, signatureVerification, null, intent) - } + showNotificationWithObjectData(this, decryptedPushMessage, signatureVerification, intent) } else -> { // do nothing } } - return Result.success() + + Result.success() } - private fun showNotificationWithObjectData(decryptedPushMessage: DecryptedPushMessage, signatureVerification: SignatureVerification, intent: Intent) { + private fun showNotificationWithObjectData(coroutineScope: CoroutineScope, decryptedPushMessage: DecryptedPushMessage, signatureVerification: SignatureVerification, intent: Intent) { + val nextcloudTalkRepository = nextcloudRepositoryWithNoCookies.getRepository() + val getNotificationUseCase = GetNotificationUseCase(nextcloudTalkRepository, apiErrorHandler) + getNotificationUseCase.invoke(coroutineScope, parametersOf(signatureVerification.userEntity, decryptedPushMessage.notificationId.toString()), object : UseCaseResponse { + override suspend fun onSuccess(result: NotificationOverall) { + var conversationTypeString = "one2one" + val notification = result.ocs.notification + notification.messageRichParameters?.let { messageRichParameters -> + if (messageRichParameters.size > 0) { + decryptedPushMessage.text = ChatUtils.getParsedMessage(notification.messageRich, messageRichParameters) + } else { + decryptedPushMessage.text = notification.message + } + } ?: run { + decryptedPushMessage.text = notification.message + } + + val subjectRichParameters = notification.subjectRichParameters + val callHashMap = subjectRichParameters?.get("call") + val userHashMap = subjectRichParameters?.get("user") + val guestHashMap = subjectRichParameters?.get("guest") + + if (callHashMap?.containsKey("name") == true) { + if (notification.objectType == "chat") { + decryptedPushMessage.subject = callHashMap["name"] + } else { + decryptedPushMessage.subject = notification.subject + } + + if (callHashMap.containsKey("call-type")) { + conversationTypeString = callHashMap["call-type"]!! + } + } + + val notificationUser = NotificationUser() + userHashMap?.let { userHashMap -> + notificationUser.id = userHashMap["id"] + notificationUser.type = userHashMap["type"] + notificationUser.name = userHashMap["name"] + } + + guestHashMap?.let { guestHashMap -> + notificationUser.id = guestHashMap["id"] + notificationUser.type = guestHashMap["type"] + notificationUser.name = guestHashMap["name"] + } + + var conversationType: Conversation.ConversationType = Conversation.ConversationType.ONE_TO_ONE_CONVERSATION + when (conversationTypeString) { + "public" -> { + conversationType = Conversation.ConversationType.PUBLIC_CONVERSATION + } + "group" -> { + conversationType = Conversation.ConversationType.GROUP_CONVERSATION + } + else -> { + // one2one + // do nothing + } + } + decryptedPushMessage.timestamp = notification.datetime.millis + decryptedPushMessage.notificationUser = notificationUser + showNotification(decryptedPushMessage, signatureVerification, conversationType, intent) + } + + override suspend fun onError(errorModel: ErrorModel?) { + decryptedPushMessage.timestamp = System.currentTimeMillis() + showNotification(decryptedPushMessage, signatureVerification, intent = intent) + } + + }) } private fun showNotification( decryptedPushMessage: DecryptedPushMessage, signatureVerification: SignatureVerification, - conversationType: Conversation.ConversationType?, intent: Intent) { + conversationType: Conversation.ConversationType = Conversation.ConversationType.ONE_TO_ONE_CONVERSATION, intent: Intent) { val largeIcon = when (conversationType) { Conversation.ConversationType.PUBLIC_CONVERSATION -> { BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_link_black_24px) @@ -122,7 +205,7 @@ class MessageNotificationWorker( val pendingIntent: PendingIntent? = PendingIntent.getActivity(applicationContext, 0, intent, 0) - val userBaseUrl = Uri.parse(signatureVerification.userEntity.baseUrl).toString() + val userBaseUrl = Uri.parse(signatureVerification.userEntity!!.baseUrl).toString() val soundUri = NotificationUtils.getMessageSoundUri(applicationContext, appPreferences) val audioAttributesBuilder: AudioAttributes.Builder = @@ -138,12 +221,19 @@ class MessageNotificationWorker( NotificationManagerCompat.IMPORTANCE_HIGH, soundUri!!, audioAttributesBuilder.build(), vibrationEffect, false, null) + val uri: Uri = Uri.parse(signatureVerification.userEntity?.baseUrl) + var baseUrl = uri.host + + if (baseUrl == null) { + baseUrl = signatureVerification.userEntity?.baseUrl + } + val notificationBuilder = NotificationCompat.Builder(applicationContext, notificationChannelId) .setPriority(NotificationCompat.PRIORITY_HIGH) .setCategory(Notification.CATEGORY_MESSAGE) .setSmallIcon(R.drawable.ic_logo) .setLargeIcon(largeIcon) - .setSubText(userBaseUrl) + .setSubText(baseUrl) .setShowWhen(true) .setWhen(decryptedPushMessage.timestamp) .setContentTitle(EmojiCompat.get().process(decryptedPushMessage.subject.toString())) @@ -169,7 +259,7 @@ class MessageNotificationWorker( val activeStatusBarNotification = NotificationUtils.findNotificationForRoom( applicationContext, - signatureVerification.userEntity, decryptedMessageId) + signatureVerification.userEntity!!, decryptedMessageId) activeStatusBarNotification?.let { activeStatusBarNotification -> notificationId = activeStatusBarNotification.id style = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(activeStatusBarNotification.notification) @@ -179,17 +269,17 @@ class MessageNotificationWorker( notificationBuilder.setOnlyAlertOnce(true) decryptedPushMessage.notificationUser?.let { notificationUser -> - val person = Person.Builder().setKey(signatureVerification.userEntity.id.toString() + "@" + notificationUser.id) + val person = Person.Builder().setKey(signatureVerification.userEntity!!.id.toString() + "@" + notificationUser.id) .setName(EmojiCompat.get().process(notificationUser.name)) .setBot(notificationUser.type == "bot") if (notificationUser.type == "user" || notificationUser.type == "guest") { val avatarUrl = when (notificationUser.type) { "user" -> { - ApiUtils.getUrlForAvatarWithName(signatureVerification.userEntity.baseUrl, notificationUser.id, R.dimen.avatar_size) + ApiUtils.getUrlForAvatarWithName(signatureVerification.userEntity!!.baseUrl, notificationUser.id, R.dimen.avatar_size) } else -> { - ApiUtils.getUrlForAvatarWithNameForGuests(signatureVerification.userEntity.baseUrl, notificationUser.name, R.dimen.avatar_size) + ApiUtils.getUrlForAvatarWithNameForGuests(signatureVerification.userEntity!!.baseUrl, notificationUser.name, R.dimen.avatar_size) } } diff --git a/app/src/main/java/com/nextcloud/talk/models/SignatureVerification.java b/app/src/main/java/com/nextcloud/talk/models/SignatureVerification.kt similarity index 61% rename from app/src/main/java/com/nextcloud/talk/models/SignatureVerification.java rename to app/src/main/java/com/nextcloud/talk/models/SignatureVerification.kt index 0c3848321..906fb2c80 100644 --- a/app/src/main/java/com/nextcloud/talk/models/SignatureVerification.java +++ b/app/src/main/java/com/nextcloud/talk/models/SignatureVerification.kt @@ -17,20 +17,24 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +package com.nextcloud.talk.models -package com.nextcloud.talk.models; - -import com.bluelinelabs.logansquare.annotation.JsonObject; -import com.nextcloud.talk.newarch.local.models.UserNgEntity; - -import org.parceler.Parcel; - -import lombok.Data; +import android.os.Parcelable +import com.bluelinelabs.logansquare.annotation.JsonObject +import com.nextcloud.talk.newarch.local.models.UserNgEntity +import kotlinx.android.parcel.Parcelize +import kotlinx.serialization.Serializable +import lombok.Data +import org.parceler.Parcel @Data @Parcel @JsonObject -public class SignatureVerification { - public boolean signatureValid; - public UserNgEntity userEntity; -} +@Serializable +@Parcelize +data class SignatureVerification ( + @JvmField + var signatureValid: Boolean = false, + @JvmField + var userEntity: UserNgEntity? = null +): Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/models/json/notifications/Notification.java b/app/src/main/java/com/nextcloud/talk/models/json/notifications/Notification.java index dbf033b20..3491f749c 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/notifications/Notification.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/notifications/Notification.java @@ -30,6 +30,8 @@ import org.parceler.Parcel; import java.util.HashMap; import java.util.List; +import javax.annotation.Nullable; + import lombok.Data; @Data @@ -54,12 +56,14 @@ public class Notification { public String subject; @JsonField(name = "subjectRich") public String subjectRich; + @Nullable @JsonField(name = "subjectRichParameters") public HashMap> subjectRichParameters; @JsonField(name = "message") public String message; @JsonField(name = "messageRich") public String messageRich; + @Nullable @JsonField(name = "messageRichParameters") public HashMap> messageRichParameters; @JsonField(name = "link") diff --git a/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetNotificationUseCase.kt b/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetNotificationUseCase.kt index e26fd575a..57d691ea8 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetNotificationUseCase.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetNotificationUseCase.kt @@ -34,6 +34,6 @@ class GetNotificationUseCase constructor( ) : UseCase(apiErrorHandler) { override suspend fun run(params: Any?): NotificationOverall { val definitionParameters = params as DefinitionParameters - return nextcloudTalkRepository.getNotificationForUser(definitionParameters[0], definitionParameters[0]) + return nextcloudTalkRepository.getNotificationForUser(definitionParameters[0], definitionParameters[1]) } }