From cb882cabfd460b5c703e6c8f4533b8c3b4c99fcd Mon Sep 17 00:00:00 2001 From: Terrance Huang Date: Fri, 29 May 2026 23:30:38 -0400 Subject: [PATCH] Fix scheduled Note To Self messages delivering without notifications or preview update Fixes #13352 --- .../org/thoughtcrime/securesms/database/MessageTable.kt | 8 ++++++++ .../org/thoughtcrime/securesms/jobs/IndividualSendJob.kt | 5 +++-- .../thoughtcrime/securesms/jobs/IndividualSendJobV2.kt | 4 +++- .../securesms/notifications/v2/NotificationFactory.kt | 3 ++- .../notifications/v2/NotificationStateProvider.kt | 3 ++- .../securesms/service/ScheduledMessageManager.kt | 3 +++ 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt index a07458f785f..f651339527e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt @@ -2341,6 +2341,14 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat AppDependencies.databaseObserver.notifyConversationListListeners() } + fun markAsUnread(messageId: Long) { + writableDatabase + .update(TABLE_NAME) + .values(READ to 0) + .where("$ID = ?", messageId) + .run() + } + fun markAsRemoteDelete(targetMessage: MessageRecord, deletedBy: RecipientId) { writableDatabase.withinTransaction { db -> val hasRevision = (targetMessage as? MmsMessageRecord)?.latestRevisionId?.id != null diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.kt index 23f54f7c56e..09ee077606b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.kt @@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.jobs.RetrieveProfileJob.Companion.enqueue import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.mms.MmsException import org.thoughtcrime.securesms.mms.OutgoingMessage +import org.thoughtcrime.securesms.notifications.v2.ConversationId import org.thoughtcrime.securesms.ratelimit.ProofRequiredExceptionHandler import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientUtil @@ -169,13 +170,13 @@ class IndividualSendJob private constructor(parameters: Parameters, private val markAttachmentsUploaded(messageId, message) SignalDatabase.messages.markUnidentified(messageId, unidentified) - // For scheduled messages, which may not have updated the thread with its snippet yet - SignalDatabase.threads.updateSilently(threadId, false) + SignalDatabase.threads.update(threadId, false) if (recipient.isSelf) { SignalDatabase.messages.incrementDeliveryReceiptCount(message.sentTimeMillis, recipient.id, System.currentTimeMillis()) SignalDatabase.messages.incrementReadReceiptCount(message.sentTimeMillis, recipient.id, System.currentTimeMillis()) SignalDatabase.messages.incrementViewedReceiptCount(message.sentTimeMillis, recipient.id, System.currentTimeMillis()) + AppDependencies.messageNotifier.updateNotification(context, ConversationId.forConversation(threadId)) } if (unidentified && accessMode == SealedSenderAccessMode.UNKNOWN && profileKey == null) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2.kt index b2f5ce5cf6b..282eb3a99bd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJobV2.kt @@ -32,6 +32,7 @@ import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint import org.thoughtcrime.securesms.jobmanager.impl.SealedSenderConstraint import org.thoughtcrime.securesms.jobs.protos.IndividualSendJobV2Data import org.thoughtcrime.securesms.keyvalue.SignalStore +import org.thoughtcrime.securesms.notifications.v2.ConversationId import org.thoughtcrime.securesms.ratelimit.ProofRequiredExceptionHandler import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientUtil @@ -219,12 +220,13 @@ class IndividualSendJobV2 private constructor(parameters: Parameters, private va SignalDatabase.messages.markAsSent(messageId, success.sentUnidentified) PushSendJob.markAttachmentsUploaded(messageId, message) - SignalDatabase.threads.updateSilently(threadId, false) + SignalDatabase.threads.update(threadId, false) if (recipient.isSelf) { SignalDatabase.messages.incrementDeliveryReceiptCount(message.sentTimeMillis, recipient.id, System.currentTimeMillis()) SignalDatabase.messages.incrementReadReceiptCount(message.sentTimeMillis, recipient.id, System.currentTimeMillis()) SignalDatabase.messages.incrementViewedReceiptCount(message.sentTimeMillis, recipient.id, System.currentTimeMillis()) + AppDependencies.messageNotifier.updateNotification(context, ConversationId.forConversation(threadId)) } val accessMode = recipient.sealedSenderAccessMode diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationFactory.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationFactory.kt index 74efb9190e6..989f580d051 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationFactory.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationFactory.kt @@ -214,7 +214,8 @@ object NotificationFactory { } val canAlertBasedOnTime: Boolean = lastNotificationTimestamp < System.currentTimeMillis() - throttle.inWholeMilliseconds || lastNotificationTimestamp > System.currentTimeMillis() - return ((conversation.hasNewNotifications() && canAlertBasedOnTime) || alertOverride) && !conversation.mostRecentNotification.authorRecipient.isSelf + return ((conversation.hasNewNotifications() && canAlertBasedOnTime) || alertOverride) && + (!conversation.mostRecentNotification.authorRecipient.isSelf || conversation.recipient.isSelf) } @WorkerThread diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationStateProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationStateProvider.kt index 24c50d2a977..411e7d53ba4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationStateProvider.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationStateProvider.kt @@ -161,6 +161,7 @@ object NotificationStateProvider { ) { private val isGroupStoryReply: Boolean = thread.groupStoryId != null private val isUnreadIncoming: Boolean = isUnreadMessage && !messageRecord.isOutgoing && !isGroupStoryReply + private val isNoteToSelfScheduled: Boolean = isUnreadMessage && messageRecord.isOutgoing && threadRecipient.isSelf private val isIncomingMissedCall: Boolean = !messageRecord.isOutgoing && (messageRecord.isMissedAudioCall || messageRecord.isMissedVideoCall) private val isNotifiableGroupStoryMessage: Boolean = @@ -170,7 +171,7 @@ object NotificationStateProvider { (isParentStorySentBySelf || messageRecord.hasGroupQuoteOrSelfMention() || (hasSelfRepliedToStory && !messageRecord.isStoryReaction())) fun includeMessage(notificationProfile: NotificationProfile?): MessageInclusion { - return if (isUnreadIncoming || stickyThread || isNotifiableGroupStoryMessage || isIncomingMissedCall) { + return if (isUnreadIncoming || stickyThread || isNotifiableGroupStoryMessage || isIncomingMissedCall || isNoteToSelfScheduled) { if (threadRecipient.isMuted && !breaksThroughMute()) { MessageInclusion.MUTE_FILTERED } else if (notificationProfile != null && !notificationProfile.isRecipientAllowed(threadRecipient.id) && !(notificationProfile.allowAllMentions && messageRecord.hasGroupQuoteOrSelfMention())) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/ScheduledMessageManager.kt b/app/src/main/java/org/thoughtcrime/securesms/service/ScheduledMessageManager.kt index 82d99a61abd..90ca5ca0c7e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/ScheduledMessageManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/ScheduledMessageManager.kt @@ -56,6 +56,9 @@ class ScheduledMessageManager( for (record in scheduledMessagesToSend) { val expiresIn = SignalDatabase.recipients.getExpiresInSeconds(record.toRecipient.id) if (messagesTable.clearScheduledStatus(record.threadId, record.id, expiresIn.seconds.inWholeMilliseconds)) { + if (record.toRecipient.isSelf) { + messagesTable.markAsUnread(record.id) + } if (record.toRecipient.isPushGroup) { PushGroupSendJob.enqueue(application, AppDependencies.jobManager, record.id, record.toRecipient.id, emptySet(), true) } else {