@@ -545,17 +545,20 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
545545 if ((TYPE_CHAT == pushMessage.type || TYPE_REMINDER == pushMessage.type) &&
546546 pushMessage.notificationUser != null
547547 ) {
548- val shortcut = addBubble(
549- notificationBuilder,
550- activeStatusBarNotification,
551- pushMessage.id
552- )
553548
554- shortcut?.let {
555- applyShortcutAndLocus(notificationBuilder, it)
556- addReplyAction(notificationBuilder, systemNotificationId)
557- addMarkAsReadAction(notificationBuilder, systemNotificationId)
558- }
549+ val shortcutId = " conversation_${id} "
550+ val roomToken = pushMessage.id
551+ val bubbleAllowed = roomToken?.let { shouldBubble(it) } ? : false
552+ val effectiveShortcutId = if (bubbleAllowed) shortcutId else null
553+
554+ notificationBuilder
555+ .addReplyAction(systemNotificationId)
556+ .addMarkAsReadAction(systemNotificationId)
557+ .addBubble(
558+ activeStatusBarNotification,
559+ effectiveShortcutId,
560+ bubbleAllowed
561+ )
559562 }
560563
561564 if (TYPE_RECORDING == pushMessage.type && ncNotification != null ) {
@@ -566,41 +569,39 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
566569 }
567570
568571 @Suppress(" ReturnCount" )
569- private fun addBubble (
570- notificationBuilder : NotificationCompat .Builder ,
572+ private fun NotificationCompat.Builder.addBubble (
571573 activeStatusBarNotification : StatusBarNotification ? ,
572- id : String?
573- ): String? {
574- val shortcutId = " conversation_${id} "
575- val roomToken = id
576- val bubbleAllowed = roomToken?.let { shouldBubble(it) } ? : false
577- var effectiveShortcutId = if (bubbleAllowed) shortcutId else null
574+ effectiveShortcutId : String? ,
575+ bubbleAllowed : Boolean
576+ ): NotificationCompat .Builder {
578577 val previousBubbleExists = (activeStatusBarNotification != null )
579578 val versionCheck = (Build .VERSION .SDK_INT >= Build .VERSION_CODES .R )
580579
581580 if (! versionCheck || ! bubbleAllowed) {
582- notificationBuilder.setBubbleMetadata(null )
583581 Log .e(TAG , " Error occurred in addBubble, check app version and if bubbling is allowed" )
584- return null
582+ return this
583+ .setBubbleMetadata(null )
585584 }
586585
587- notificationBuilder.setOnlyAlertOnce(false )
588- prepareChatNotification(notificationBuilder, activeStatusBarNotification)
586+ this
587+ .setOnlyAlertOnce(false )
588+ .prepareChatNotification(activeStatusBarNotification)
589589
590590 // Only add bubble metadata if there's no existing notification
591591 // If one exists, the bubble metadata will be preserved
592592
593593 if (! previousBubbleExists) {
594- addBubbleMetadata(notificationBuilder, false )
595- return effectiveShortcutId
594+ return this
595+ .addBubbleMetadata(false )
596+ .applyShortcutAndLocus(effectiveShortcutId)
596597 }
597598
598599 // Preserve existing bubble metadata
599600 val existingBubble = activeStatusBarNotification.notification.bubbleMetadata
600601 val compatBubble = NotificationCompat .BubbleMetadata .fromPlatform(existingBubble)
601602 if (compatBubble == null ) {
602603 Log .e(TAG , " NotificationCompact returns null bubble meta data from non-null active status bar notification" )
603- return null
604+ return this
604605 }
605606
606607 val preservedBubbleBuilder = when {
@@ -613,9 +614,10 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
613614 compatBubble.icon!!
614615 )
615616
616- else -> {
617- addBubbleMetadata(notificationBuilder, compatBubble.isNotificationSuppressed)
618- return effectiveShortcutId
617+ else -> { // edge case
618+ return this
619+ .addBubbleMetadata(compatBubble.isNotificationSuppressed)
620+ .applyShortcutAndLocus(effectiveShortcutId)
619621 }
620622 }
621623
@@ -634,14 +636,15 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
634636 .setSuppressNotification(false )
635637
636638 val preservedMetadata = preservedBubbleBuilder.build()
637- notificationBuilder.setBubbleMetadata(preservedMetadata)
638639
639- val existingShortcut = compatBubble.shortcutId
640- if (! existingShortcut.isNullOrEmpty()) {
641- effectiveShortcutId = existingShortcut
642- }
643-
644- return effectiveShortcutId
640+ return this
641+ .setBubbleMetadata(preservedMetadata)
642+ .apply {
643+ val existingShortcut = compatBubble.shortcutId
644+ if (! existingShortcut.isNullOrEmpty()) {
645+ applyShortcutAndLocus( existingShortcut)
646+ }
647+ }
645648 }
646649
647650 private fun createNotificationBuilder (
@@ -702,17 +705,12 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
702705 return notificationBuilder
703706 }
704707
705- private fun applyShortcutAndLocus (
706- notificationBuilder : NotificationCompat .Builder ,
707- shortcutId : String?
708- ) {
709- if (shortcutId.isNullOrEmpty()) {
710- return
708+ private fun NotificationCompat.Builder.applyShortcutAndLocus (shortcutId : String? ): NotificationCompat .Builder {
709+ return if (shortcutId.isNullOrEmpty()) this else {
710+ val locusId = androidx.core.content.LocusIdCompat (shortcutId)
711+ this .setShortcutId(shortcutId)
712+ .setLocusId(locusId)
711713 }
712- val ensuredShortcutId = shortcutId
713- val locusId = androidx.core.content.LocusIdCompat (ensuredShortcutId)
714- notificationBuilder.setShortcutId(ensuredShortcutId)
715- notificationBuilder.setLocusId(locusId)
716714 }
717715
718716 private fun getLargeIcon (): Bitmap {
@@ -746,11 +744,11 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
746744 }
747745 return largeIcon
748746 }
749- private fun prepareChatNotification (
750- notificationBuilder : NotificationCompat .Builder ,
747+
748+ private fun NotificationCompat.Builder. prepareChatNotification (
751749 activeStatusBarNotification : StatusBarNotification ?
752- ) {
753- val notificationUser = pushMessage.notificationUser ? : return
750+ ): NotificationCompat . Builder {
751+ val notificationUser = pushMessage.notificationUser ? : return this
754752
755753 val userType = notificationUser.type
756754 var style: NotificationCompat .MessagingStyle ? = null
@@ -759,7 +757,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
759757 activeStatusBarNotification.notification
760758 )
761759 }
762- val person = Person .Builder ()
760+ val personBuilder = Person .Builder ()
763761 .setKey(signatureVerification.user!! .id.toString() + " @" + notificationUser.id)
764762 .setName(EmojiCompat .get().process(notificationUser.name!! ))
765763 .setImportant(true )
@@ -776,32 +774,31 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
776774 } else {
777775 ApiUtils .getUrlForGuestAvatar(baseUrl!! , notificationUser.name, false )
778776 }
779- person .setIcon(loadAvatarSync(avatarUrl, context!! ))
777+ personBuilder .setIcon(loadAvatarSync(avatarUrl, context!! ))
780778 }
781779
782- val personBuilt = person.build()
783- notificationBuilder.setStyle(getStyle(personBuilt, style))
784- notificationBuilder.addPerson(personBuilt)
785- }
780+ val person = personBuilder.build()
786781
787- private fun addBubbleMetadata (notificationBuilder : NotificationCompat .Builder , suppressNotification : Boolean ) {
788- val roomToken = pushMessage.id
789- val shouldAbort = Build .VERSION .SDK_INT < Build .VERSION_CODES .R ||
790- roomToken.isNullOrEmpty() ||
791- roomToken?.let { ! shouldBubble(it) } == true
782+ return this
783+ .setStyle(getStyle(person, style))
784+ .addPerson(person)
785+ }
792786
793- if (shouldAbort) {
794- return
795- }
787+ private fun NotificationCompat.Builder.addBubbleMetadata (suppressNotification : Boolean ): NotificationCompat .Builder
788+ = runCatching {
789+ val roomToken = pushMessage.id
790+ val shouldAbort = Build .VERSION .SDK_INT < Build .VERSION_CODES .R ||
791+ roomToken.isNullOrEmpty() || roomToken.let { ! shouldBubble(it) }
796792
797- val ensuredRoomToken = roomToken!!
793+ if (shouldAbort) {
794+ return @runCatching this
795+ }
798796
799- try {
800- val conversationName = pushMessage.subject?.takeIf { it.isNotBlank() }
801- val shortcutId = " conversation_$ensuredRoomToken "
797+ val conversationName = pushMessage.subject.takeIf { it.isNotBlank() }
798+ val shortcutId = " conversation_$roomToken "
802799 val fallbackConversationLabel = conversationName ? : context!! .getString(R .string.nc_app_name)
803800
804- val bubbleIcon = resolveBubbleIcon(ensuredRoomToken ) ? : run {
801+ val bubbleIcon = resolveBubbleIcon(roomToken ) ? : run {
805802 val fallbackBitmap = getLargeIcon()
806803 androidx.core.graphics.drawable.IconCompat .createWithBitmap(fallbackBitmap)
807804 }
@@ -826,11 +823,11 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
826823
827824 androidx.core.content.pm.ShortcutManagerCompat .pushDynamicShortcut(context!! , shortcut)
828825
829- val bubbleRequestCode = NotificationUtils .calculateCRC32(" bubble_$ensuredRoomToken " ).toInt()
826+ val bubbleRequestCode = NotificationUtils .calculateCRC32(" bubble_$roomToken " ).toInt()
830827 val bubbleIntent = PendingIntent .getActivity(
831828 context,
832829 bubbleRequestCode,
833- com.nextcloud.talk.chat.BubbleActivity .newIntent(context!! , ensuredRoomToken , conversationName),
830+ com.nextcloud.talk.chat.BubbleActivity .newIntent(context!! , roomToken , conversationName),
834831 PendingIntent .FLAG_UPDATE_CURRENT or PendingIntent .FLAG_MUTABLE
835832 )
836833
@@ -843,15 +840,17 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
843840 .setSuppressNotification(suppressNotification)
844841 .build()
845842
846- notificationBuilder.setBubbleMetadata(bubbleData)
847- notificationBuilder.setShortcutId(shortcutId)
848- notificationBuilder.setLocusId(androidx.core.content.LocusIdCompat (shortcutId))
849- } catch (e: IllegalArgumentException ) {
850- Log .e(TAG , " Error adding bubble metadata: Invalid argument" , e)
851- } catch (e: IllegalStateException ) {
852- Log .e(TAG , " Error adding bubble metadata: Invalid state" , e)
843+ this .setBubbleMetadata(bubbleData)
844+ .setShortcutId(shortcutId)
845+ .setLocusId(androidx.core.content.LocusIdCompat (shortcutId))
846+ }.getOrElse { error ->
847+ when (error) {
848+ is IllegalArgumentException -> Log .e(TAG , " Error adding bubble metadata: Invalid argument" , error)
849+ is IllegalStateException -> Log .e(TAG , " Error adding bubble metadata: Invalid state" , error)
850+ }
851+
852+ this
853853 }
854- }
855854
856855 private fun shouldBubble (roomToken : String ): Boolean {
857856 val user = signatureVerification.user
@@ -931,20 +930,20 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
931930 return PendingIntent .getBroadcast(context, systemNotificationId, actualIntent, intentFlag)
932931 }
933932
934- private fun addMarkAsReadAction (notificationBuilder : NotificationCompat .Builder , systemNotificationId : Int ) {
935- if (pushMessage.objectId != null ) {
936- val messageId: Int = try {
937- parseMessageId(pushMessage.objectId!! )
938- } catch (nfe: NumberFormatException ) {
939- Log .e(TAG , " Failed to parse messageId from objectId, skip adding mark-as-read action." , nfe)
940- return
933+ private fun NotificationCompat.Builder.addMarkAsReadAction (systemNotificationId : Int ): NotificationCompat .Builder
934+ = runCatching {
935+ if (pushMessage.objectId == null ) {
936+ return @runCatching this
941937 }
942938
939+ val messageId: Int = parseMessageId(pushMessage.objectId!! )
940+
943941 val pendingIntent = buildIntentForAction(
944942 MarkAsReadReceiver ::class .java,
945943 systemNotificationId,
946944 messageId
947945 )
946+
948947 val markAsReadAction = NotificationCompat .Action .Builder (
949948 R .drawable.ic_mark_chat_read_24px,
950949 context!! .resources.getString(R .string.nc_mark_as_read),
@@ -953,11 +952,19 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
953952 .setSemanticAction(NotificationCompat .Action .SEMANTIC_ACTION_MARK_AS_READ )
954953 .setShowsUserInterface(false )
955954 .build()
956- notificationBuilder.addAction(markAsReadAction)
955+
956+ this .addAction(markAsReadAction)
957+ }.getOrElse { error ->
958+ when (error) {
959+ is NumberFormatException -> {
960+ Log .e(TAG , " Failed to parse messageId from objectId, skip adding mark-as-read action." , error)
961+ }
962+ }
963+
964+ this
957965 }
958- }
959966
960- private fun addReplyAction ( notificationBuilder : NotificationCompat .Builder , systemNotificationId : Int ) {
967+ private fun NotificationCompat.Builder. addReplyAction ( systemNotificationId : Int ): NotificationCompat . Builder {
961968 val replyLabel = context!! .resources.getString(R .string.nc_reply)
962969 val remoteInput = RemoteInput .Builder (NotificationUtils .KEY_DIRECT_REPLY )
963970 .setLabel(replyLabel)
@@ -974,7 +981,8 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor
974981 .setAllowGeneratedReplies(true )
975982 .addRemoteInput(remoteInput)
976983 .build()
977- notificationBuilder.addAction(replyAction)
984+
985+ return this .addAction(replyAction)
978986 }
979987
980988 private fun addDismissRecordingAvailableAction (
0 commit comments