Skip to content

Commit 56dcd8e

Browse files
committed
- Refactoring NotificationWorker functions related to bubbling to now properly follow the builder pattern
Signed-off-by: rapterjet2004 <juliuslinus1@gmail.com>
1 parent 8f46d7b commit 56dcd8e

1 file changed

Lines changed: 97 additions & 89 deletions

File tree

app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt

Lines changed: 97 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)