From 279ad7945e9f75c14de973374a7d7a80aff395f8 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Fri, 14 Apr 2023 14:23:05 -0400 Subject: [PATCH] Move to defined from_recipient_id and to_recipient_id columns on message table. --- .../database/DatabaseConsistencyTest.kt | 2 +- .../RecipientTableTest_getAndPossiblyMerge.kt | 16 +- .../securesms/backup/FullBackupExporter.java | 2 +- .../securesms/badges/gifts/GiftMessageView.kt | 6 +- .../securesms/badges/gifts/Gifts.kt | 2 +- .../received/ViewReceivedGiftBottomSheet.kt | 2 +- .../viewgift/sent/ViewSentGiftBottomSheet.kt | 2 +- .../components/ConversationItemFooter.java | 6 +- .../voice/VoiceNoteMediaItemFactory.java | 2 +- .../conversation/ConversationFragment.java | 6 +- .../conversation/ConversationItem.java | 48 +- .../ConversationParentFragment.java | 8 +- .../conversation/ConversationUpdateItem.java | 18 +- .../securesms/conversation/MenuState.java | 16 +- .../error/SafetyNumberChangeRepository.java | 5 +- .../securesms/database/CallTable.kt | 2 +- ...he.java => EarlyDeliveryReceiptCache.java} | 25 +- .../securesms/database/GroupTable.kt | 2 +- .../securesms/database/MediaTable.kt | 6 +- .../securesms/database/MessageTable.kt | 467 +++++++++--------- .../securesms/database/SearchTable.kt | 4 +- .../securesms/database/StorySendTable.kt | 6 +- .../securesms/database/ThreadBodyUtil.java | 8 +- .../securesms/database/ThreadTable.kt | 33 +- .../helpers/SignalDatabaseMigrations.kt | 7 +- .../V185_MessageRecipientsMigration.kt | 285 +++++++++++ .../database/model/DisplayRecord.java | 16 +- .../database/model/InMemoryMessageRecord.java | 10 +- .../database/model/MediaMmsMessageRecord.java | 18 +- .../database/model/MessageRecord.java | 69 ++- .../database/model/MmsMessageRecord.java | 5 +- .../model/NotificationMmsMessageRecord.java | 5 +- .../exporter/SignalSmsExportReader.kt | 4 +- .../securesms/groups/GroupManagerV2.java | 2 +- .../securesms/jobs/IndividualSendJob.java | 20 +- .../securesms/jobs/MmsSendJob.java | 10 +- .../jobs/PushDistributionListSendJob.java | 6 +- .../securesms/jobs/PushGroupSendJob.java | 8 +- .../securesms/jobs/ReactionSendJob.java | 2 +- .../securesms/jobs/RemoteDeleteSendJob.java | 4 +- .../securesms/jobs/SmsReceiveJob.java | 8 +- .../securesms/jobs/SmsSendJob.java | 8 +- .../securesms/jobs/SmsSentJob.java | 6 +- .../longmessage/LongMessageFragment.java | 6 +- .../mediasend/v2/MediaSelectionRepository.kt | 6 +- .../messagedetails/MessageDetails.java | 2 +- .../MessageDetailsRepository.java | 16 +- .../MessageHeaderViewHolder.java | 2 +- .../messagedetails/RecipientViewHolder.java | 2 +- .../messages/DataMessageProcessor.kt | 2 +- .../messages/IncomingMessageObserver.kt | 3 +- .../messages/MessageContentProcessor.java | 81 ++- .../securesms/messages/MessageDecryptor.kt | 2 +- .../messages/ReceiptMessageProcessor.kt | 48 +- .../messages/SyncMessageProcessor.kt | 23 +- .../migrations/ApplicationMigrations.java | 7 +- .../securesms/mms/OutgoingMessage.kt | 54 +- .../notifications/v2/NotificationBuilder.kt | 4 +- .../v2/NotificationConversation.kt | 2 +- .../notifications/v2/NotificationFactory.kt | 4 +- .../notifications/v2/NotificationItem.kt | 24 +- .../notifications/v2/NotificationState.kt | 4 +- .../v2/NotificationStateProvider.kt | 4 +- .../profiles/spoofing/ReviewUtil.java | 4 +- .../safety/SafetyNumberBottomSheet.kt | 4 +- .../securesms/search/SearchRepository.java | 6 +- .../service/ScheduledMessageManager.kt | 10 +- .../securesms/sms/IncomingTextMessage.java | 28 +- .../securesms/sms/MessageSender.java | 48 +- .../securesms/stories/StoryTextPostModel.kt | 3 +- .../stories/landing/StoriesLandingItemData.kt | 2 +- .../securesms/stories/my/MyStoriesFragment.kt | 4 +- .../stories/my/MyStoriesRepository.kt | 4 +- .../viewer/page/StoryViewerPageRepository.kt | 6 +- .../direct/StoryDirectReplyDialogFragment.kt | 2 +- .../direct/StoryDirectReplyRepository.kt | 9 +- .../stories/viewer/reply/group/ReplyBody.kt | 2 +- .../reply/group/StoryGroupReplyRepository.kt | 2 +- .../reply/group/StoryGroupReplySender.kt | 2 +- .../viewer/views/StoryViewsRepository.kt | 8 +- .../securesms/util/AttachmentUtil.java | 10 +- .../securesms/util/RemoteDeleteUtil.java | 6 +- .../securesms/database/FakeMessageRecords.kt | 2 +- .../securesms/database/TestMms.kt | 5 +- .../securesms/database/TestSms.kt | 5 +- .../sms/UploadDependencyGraphTest.kt | 8 +- 86 files changed, 944 insertions(+), 719 deletions(-) rename app/src/main/java/org/thoughtcrime/securesms/database/{EarlyReceiptCache.java => EarlyDeliveryReceiptCache.java} (62%) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V185_MessageRecipientsMigration.kt diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/DatabaseConsistencyTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/DatabaseConsistencyTest.kt index 0912ec19cf..b996419796 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/DatabaseConsistencyTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/DatabaseConsistencyTest.kt @@ -84,7 +84,7 @@ class DatabaseConsistencyTest { .joinToString(separator = " ") .replace(Regex.fromLiteral("( "), "(") .replace(Regex.fromLiteral(" )"), ")") - .replace(Regex.fromLiteral("CREATE TABLE \"call\""), "CREATE TABLE call") // solves a specific weirdness with inconsequential quotes + .replace(Regex("CREATE TABLE \"([a-z]+)\""), "CREATE TABLE $1") // for some reason SQLite will wrap table names in quotes for upgraded tables. This unwraps them. } private class InMemoryTestHelper(private val application: Application) : SQLiteOpenHelper(application, null, null, 1) { diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt index a2384338f2..ac4dc97d14 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/RecipientTableTest_getAndPossiblyMerge.kt @@ -693,9 +693,9 @@ class RecipientTableTest_getAndPossiblyMerge { val sms2: MessageRecord = SignalDatabase.messages.getMessageRecord(smsId2)!! val sms3: MessageRecord = SignalDatabase.messages.getMessageRecord(smsId3)!! - assertEquals(retrievedId, sms1.recipient.id) - assertEquals(retrievedId, sms2.recipient.id) - assertEquals(retrievedId, sms3.recipient.id) + assertEquals(retrievedId, sms1.fromRecipient.id) + assertEquals(retrievedId, sms2.fromRecipient.id) + assertEquals(retrievedId, sms3.fromRecipient.id) assertEquals(retrievedThreadId, sms1.threadId) assertEquals(retrievedThreadId, sms2.threadId) @@ -706,9 +706,9 @@ class RecipientTableTest_getAndPossiblyMerge { val mms2: MessageRecord = SignalDatabase.messages.getMessageRecord(mmsId2)!! val mms3: MessageRecord = SignalDatabase.messages.getMessageRecord(mmsId3)!! - assertEquals(retrievedId, mms1.recipient.id) - assertEquals(retrievedId, mms2.recipient.id) - assertEquals(retrievedId, mms3.recipient.id) + assertEquals(retrievedId, mms1.fromRecipient.id) + assertEquals(retrievedId, mms2.fromRecipient.id) + assertEquals(retrievedId, mms3.fromRecipient.id) assertEquals(retrievedThreadId, mms1.threadId) assertEquals(retrievedThreadId, mms2.threadId) @@ -1035,7 +1035,7 @@ class RecipientTableTest_getAndPossiblyMerge { return SignalDatabase.rawDatabase .select(MessageTable.BODY) .from(MessageTable.TABLE_NAME) - .where("${MessageTable.RECIPIENT_ID} = ? AND ${MessageTable.TYPE} = ?", recipientId, MessageTypes.THREAD_MERGE_TYPE) + .where("${MessageTable.FROM_RECIPIENT_ID} = ? AND ${MessageTable.TYPE} = ?", recipientId, MessageTypes.THREAD_MERGE_TYPE) .orderBy("${MessageTable.DATE_RECEIVED} DESC") .limit(1) .run() @@ -1053,7 +1053,7 @@ class RecipientTableTest_getAndPossiblyMerge { return SignalDatabase.rawDatabase .select(MessageTable.BODY) .from(MessageTable.TABLE_NAME) - .where("${MessageTable.RECIPIENT_ID} = ? AND ${MessageTable.TYPE} = ?", recipientId, MessageTypes.SESSION_SWITCHOVER_TYPE) + .where("${MessageTable.FROM_RECIPIENT_ID} = ? AND ${MessageTable.TYPE} = ?", recipientId, MessageTypes.SESSION_SWITCHOVER_TYPE) .orderBy("${MessageTable.DATE_RECEIVED} DESC") .limit(1) .run() diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java index a1e0eb24ec..c70acead5e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/FullBackupExporter.java @@ -611,7 +611,7 @@ public class FullBackupExporter extends FullBackupBase { } private static boolean isForNonExpiringMmsMessage(@NonNull SQLiteDatabase db, long mmsId) { - String[] columns = new String[] { MessageTable.RECIPIENT_ID, MessageTable.EXPIRES_IN, MessageTable.VIEW_ONCE }; + String[] columns = new String[] { MessageTable.EXPIRES_IN, MessageTable.VIEW_ONCE }; String where = MessageTable.ID + " = ?"; String[] args = new String[] { String.valueOf(mmsId) }; diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/GiftMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/GiftMessageView.kt index b432eabaaa..bcdf62baaf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/GiftMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/GiftMessageView.kt @@ -50,7 +50,7 @@ class GiftMessageView @JvmOverloads constructor( } } - fun setGiftBadge(glideRequests: GlideRequests, giftBadge: GiftBadge, isOutgoing: Boolean, callback: Callback, recipient: Recipient) { + fun setGiftBadge(glideRequests: GlideRequests, giftBadge: GiftBadge, isOutgoing: Boolean, callback: Callback, fromRecipient: Recipient, toRecipient: Recipient) { descriptionView.text = giftBadge.formatExpiry(context) actionView.icon = null actionView.setOnClickListener { callback.onViewGiftBadgeClicked() } @@ -58,9 +58,9 @@ class GiftMessageView @JvmOverloads constructor( if (isOutgoing) { actionView.setText(R.string.GiftMessageView__view) - titleView.text = context.getString(R.string.GiftMessageView__donation_on_behalf_of_s, recipient.getDisplayName(context)) + titleView.text = context.getString(R.string.GiftMessageView__donation_on_behalf_of_s, toRecipient.getDisplayName(context)) } else { - titleView.text = context.getString(R.string.GiftMessageView__s_donated_to_signal_on, recipient.getShortDisplayName(context)) + titleView.text = context.getString(R.string.GiftMessageView__s_donated_to_signal_on, fromRecipient.getShortDisplayName(context)) when (giftBadge.redemptionState) { GiftBadge.RedemptionState.REDEEMED -> { stopAnimationIfNeeded() diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/Gifts.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/Gifts.kt index 6d300258fc..cd2d4d8cb1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/Gifts.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/Gifts.kt @@ -31,7 +31,7 @@ object Gifts { expiresIn: Long ): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = recipient, body = Base64.encodeBytes(giftBadge.toByteArray()), isSecure = true, sentTimeMillis = sentTimestamp, diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/received/ViewReceivedGiftBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/received/ViewReceivedGiftBottomSheet.kt index cd5aafe965..d260eb2972 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/received/ViewReceivedGiftBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/received/ViewReceivedGiftBottomSheet.kt @@ -62,7 +62,7 @@ class ViewReceivedGiftBottomSheet : DSLSettingsBottomSheetFragment() { fun show(fragmentManager: FragmentManager, messageRecord: MmsMessageRecord) { ViewReceivedGiftBottomSheet().apply { arguments = Bundle().apply { - putParcelable(ARG_SENT_FROM, messageRecord.recipient.id) + putParcelable(ARG_SENT_FROM, messageRecord.fromRecipient.id) putByteArray(ARG_GIFT_BADGE, messageRecord.giftBadge!!.toByteArray()) putLong(ARG_MESSAGE_ID, messageRecord.id) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/sent/ViewSentGiftBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/sent/ViewSentGiftBottomSheet.kt index da1cdf352e..dae757c06f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/sent/ViewSentGiftBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/viewgift/sent/ViewSentGiftBottomSheet.kt @@ -33,7 +33,7 @@ class ViewSentGiftBottomSheet : DSLSettingsBottomSheetFragment() { fun show(fragmentManager: FragmentManager, messageRecord: MmsMessageRecord) { ViewSentGiftBottomSheet().apply { arguments = Bundle().apply { - putParcelable(ARG_SENT_TO, messageRecord.recipient.id) + putParcelable(ARG_SENT_TO, messageRecord.toRecipient.id) putByteArray(ARG_GIFT_BADGE, messageRecord.giftBadge!!.toByteArray()) } show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java b/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java index d82e7b37b6..d9ab71908b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java @@ -306,7 +306,7 @@ public class ConversationItemFooter extends ConstraintLayout { int errorMsg; if (messageRecord.hasFailedWithNetworkFailures()) { errorMsg = R.string.ConversationItem_error_network_not_delivered; - } else if (messageRecord.getRecipient().isPushGroup() && messageRecord.isIdentityMismatchFailure()) { + } else if (messageRecord.getToRecipient().isPushGroup() && messageRecord.isIdentityMismatchFailure()) { errorMsg = R.string.ConversationItem_error_partially_not_delivered; } else { errorMsg = R.string.ConversationItem_error_not_sent_tap_for_details; @@ -386,7 +386,7 @@ public class ConversationItemFooter extends ConstraintLayout { long newMessageId = buildMessageId(messageRecord); if (previousMessageId == newMessageId && deliveryStatusView.isPending() && !messageRecord.isPending()) { - if (messageRecord.getRecipient().isGroup()) { + if (messageRecord.getToRecipient().isGroup()) { SignalLocalMetrics.GroupMessageSend.onUiUpdated(messageRecord.getId()); } else { SignalLocalMetrics.IndividualMessageSend.onUiUpdated(messageRecord.getId()); @@ -429,7 +429,7 @@ public class ConversationItemFooter extends ConstraintLayout { if (mmsMessageRecord.getSlideDeck().getAudioSlide() != null) { showAudioDurationViews(); - if (messageRecord.getViewedReceiptCount() > 0 || (messageRecord.isOutgoing() && Objects.equals(messageRecord.getRecipient(), Recipient.self()))) { + if (messageRecord.getViewedReceiptCount() > 0 || (messageRecord.isOutgoing() && Objects.equals(messageRecord.getToRecipient(), Recipient.self()))) { revealDot.setProgress(1f); } else { revealDot.setProgress(0f); diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaItemFactory.java b/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaItemFactory.java index c4554c29ac..deef397855 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaItemFactory.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaItemFactory.java @@ -86,7 +86,7 @@ class VoiceNoteMediaItemFactory { Recipient threadRecipient = Objects.requireNonNull(SignalDatabase.threads() .getRecipientForThreadId(messageRecord.getThreadId())); - Recipient sender = messageRecord.isOutgoing() ? Recipient.self() : messageRecord.getIndividualRecipient(); + Recipient sender = messageRecord.getFromRecipient(); Recipient avatarRecipient = threadRecipient.isGroup() ? threadRecipient : sender; AudioSlide audioSlide = ((MmsMessageRecord) messageRecord).getSlideDeck().getAudioSlide(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 38f01e8c69..b14a87754c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -1088,7 +1088,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect } private static boolean isNoteToSelfDelete(Set messageRecords) { - return messageRecords.stream().allMatch(messageRecord -> messageRecord.isOutgoing() && messageRecord.getRecipient().isSelf()); + return messageRecords.stream().allMatch(messageRecord -> messageRecord.isOutgoing() && messageRecord.getToRecipient().isSelf()); } private void handleDeleteForEveryone(Set messageRecords) { @@ -1436,7 +1436,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect SimpleTask.run(getLifecycle(), () -> { return SignalDatabase.messages().getMessagePositionInConversation(threadId, messageRecord.getDateReceived(), - messageRecord.isOutgoing() ? Recipient.self().getId() : messageRecord.getRecipient().getId()); + messageRecord.getFromRecipient().getId()); }, p -> moveToPosition(p + (isTypingIndicatorShowing() ? 1 : 0), () -> { Toast.makeText(getContext(), R.string.ConversationFragment_failed_to_open_message, Toast.LENGTH_SHORT).show(); })); @@ -1791,7 +1791,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect ApplicationDependencies.getViewOnceMessageManager().scheduleIfNecessary(); - ApplicationDependencies.getJobManager().add(new MultiDeviceViewOnceOpenJob(new MessageTable.SyncMessageId(messageRecord.getIndividualRecipient().getId(), messageRecord.getDateSent()))); + ApplicationDependencies.getJobManager().add(new MultiDeviceViewOnceOpenJob(new MessageTable.SyncMessageId(messageRecord.getToRecipient().getId(), messageRecord.getDateSent()))); return tempUri; } catch (IOException e) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index 8031987692..39f05474a9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -189,7 +189,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo private Optional nextMessageRecord; private Locale locale; private boolean groupThread; - private LiveRecipient recipient; + private LiveRecipient author; private GlideRequests glideRequests; private Optional previousMessage; private ConversationItemDisplayMode displayMode; @@ -363,7 +363,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo @NonNull Colorizer colorizer, @NonNull ConversationItemDisplayMode displayMode) { - if (this.recipient != null) this.recipient.removeForeverObserver(this); + if (this.author != null) this.author.removeForeverObserver(this); if (this.conversationRecipient != null) this.conversationRecipient.removeForeverObserver(this); lastYDownRelativeToThis = 0; @@ -378,28 +378,28 @@ public final class ConversationItem extends RelativeLayout implements BindableCo this.batchSelected = batchSelected; this.conversationRecipient = conversationRecipient.live(); this.groupThread = conversationRecipient.isGroup(); - this.recipient = messageRecord.getIndividualRecipient().live(); + this.author = messageRecord.getFromRecipient().live(); this.canPlayContent = false; this.mediaItem = null; this.colorizer = colorizer; this.displayMode = displayMode; this.previousMessage = previousMessageRecord; - this.recipient.observeForever(this); + this.author.observeForever(this); this.conversationRecipient.observeForever(this); setGutterSizes(messageRecord, groupThread); setMessageShape(messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setMediaAttributes(messageRecord, previousMessageRecord, nextMessageRecord, groupThread, hasWallpaper, isMessageRequestAccepted, allowedToPlayInline); setBodyText(messageRecord, searchQuery, isMessageRequestAccepted); - setBubbleState(messageRecord, messageRecord.getRecipient(), hasWallpaper, colorizer); + setBubbleState(messageRecord, messageRecord.getFromRecipient(), hasWallpaper, colorizer); setInteractionState(conversationMessage, pulse); setStatusIcons(messageRecord, hasWallpaper); - setContactPhoto(recipient.get()); - setGroupMessageStatus(messageRecord, recipient.get()); + setContactPhoto(author.get()); + setGroupMessageStatus(messageRecord, author.get()); setGroupAuthorColor(messageRecord, hasWallpaper, colorizer); setAuthor(messageRecord, previousMessageRecord, nextMessageRecord, groupThread, hasWallpaper); - setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread, messageRecord.getRecipient().getChatColors()); + setQuote(messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setMessageSpacing(context, messageRecord, previousMessageRecord, nextMessageRecord, groupThread); setReactions(messageRecord); setFooter(messageRecord, nextMessageRecord, locale, groupThread, hasWallpaper); @@ -627,7 +627,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } } - if (recipient.getId().equals(modified.getId())) { + if (author.getId().equals(modified.getId())) { setContactPhoto(modified); setGroupMessageStatus(messageRecord, modified); } @@ -669,8 +669,8 @@ public final class ConversationItem extends RelativeLayout implements BindableCo @Override public void unbind() { - if (recipient != null) { - recipient.removeForeverObserver(this); + if (author != null) { + author.removeForeverObserver(this); } if (conversationRecipient != null) { conversationRecipient.removeForeverObserver(this); @@ -1299,7 +1299,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo paymentViewStub.setVisibility(View.GONE); MmsMessageRecord mmsMessageRecord = (MmsMessageRecord) messageRecord; - giftViewStub.get().setGiftBadge(glideRequests, Objects.requireNonNull(mmsMessageRecord.getGiftBadge()), messageRecord.isOutgoing(), giftMessageViewCallback, messageRecord.getRecipient()); + giftViewStub.get().setGiftBadge(glideRequests, Objects.requireNonNull(mmsMessageRecord.getGiftBadge()), messageRecord.isOutgoing(), giftMessageViewCallback, messageRecord.getFromRecipient(), messageRecord.getToRecipient()); giftViewStub.get().setVisibility(VISIBLE); footer.setVisibility(VISIBLE); @@ -1316,7 +1316,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo MediaMmsMessageRecord mediaMmsMessageRecord = (MediaMmsMessageRecord) messageRecord; paymentViewStub.setVisibility(View.VISIBLE); - paymentViewStub.get().bindPayment(messageRecord.getIndividualRecipient(), Objects.requireNonNull(mediaMmsMessageRecord.getPayment()), colorizer); + paymentViewStub.get().bindPayment(messageRecord.getFromRecipient(), Objects.requireNonNull(mediaMmsMessageRecord.getPayment()), colorizer); footer.setVisibility(VISIBLE); } else { @@ -1538,7 +1538,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } } - private void setQuote(@NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread, @NonNull ChatColors chatColors) { + private void setQuote(@NonNull MessageRecord current, @NonNull Optional previous, @NonNull Optional next, boolean isGroupThread) { boolean startOfCluster = isStartOfMessageCluster(current, previous, isGroupThread); if (hasQuote(messageRecord)) { if (quoteView == null) { @@ -1773,7 +1773,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo private void setGroupAuthorColor(@NonNull MessageRecord messageRecord, boolean hasWallpaper, @NonNull Colorizer colorizer) { if (groupSender != null) { - groupSender.setTextColor(colorizer.getIncomingGroupSenderColor(getContext(), messageRecord.getIndividualRecipient())); + groupSender.setTextColor(colorizer.getIncomingGroupSenderColor(getContext(), messageRecord.getFromRecipient())); } } @@ -1782,7 +1782,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo if (isGroupThread && !current.isOutgoing()) { contactPhotoHolder.setVisibility(VISIBLE); - if (!previous.isPresent() || previous.get().isUpdate() || !current.getRecipient().equals(previous.get().getRecipient()) || + if (!previous.isPresent() || previous.get().isUpdate() || !current.getFromRecipient().equals(previous.get().getFromRecipient()) || !DateUtils.isSameDay(previous.get().getTimestamp(), current.getTimestamp()) || !isWithinClusteringTime(current, previous.get())) { groupSenderHolder.setVisibility(VISIBLE); @@ -1797,7 +1797,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo groupSenderHolder.setVisibility(GONE); } - if (!next.isPresent() || next.get().isUpdate() || !current.getRecipient().equals(next.get().getRecipient()) || !isWithinClusteringTime(current, next.get())) { + if (!next.isPresent() || next.get().isUpdate() || !current.getFromRecipient().equals(next.get().getFromRecipient()) || !isWithinClusteringTime(current, next.get())) { contactPhoto.setVisibility(VISIBLE); badgeImageView.setVisibility(VISIBLE); } else { @@ -1897,7 +1897,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo private boolean isStartOfMessageCluster(@NonNull MessageRecord current, @NonNull Optional previous, boolean isGroupThread) { if (isGroupThread) { return !previous.isPresent() || previous.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), previous.get().getTimestamp()) || - !current.getRecipient().equals(previous.get().getRecipient()) || !isWithinClusteringTime(current, previous.get()) || MessageRecordUtil.isScheduled(current); + !current.getFromRecipient().equals(previous.get().getFromRecipient()) || !isWithinClusteringTime(current, previous.get()) || MessageRecordUtil.isScheduled(current); } else { return !previous.isPresent() || previous.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), previous.get().getTimestamp()) || current.isOutgoing() != previous.get().isOutgoing() || previous.get().isSecure() != current.isSecure() || !isWithinClusteringTime(current, previous.get()) || @@ -1908,7 +1908,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo private boolean isEndOfMessageCluster(@NonNull MessageRecord current, @NonNull Optional next, boolean isGroupThread) { if (isGroupThread) { return !next.isPresent() || next.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), next.get().getTimestamp()) || - !current.getRecipient().equals(next.get().getRecipient()) || !current.getReactions().isEmpty() || !isWithinClusteringTime(current, next.get()) || + !current.getFromRecipient().equals(next.get().getFromRecipient()) || !current.getReactions().isEmpty() || !isWithinClusteringTime(current, next.get()) || MessageRecordUtil.isScheduled(current); } else { return !next.isPresent() || next.get().isUpdate() || !DateUtils.isSameDay(current.getTimestamp(), next.get().getTimestamp()) || @@ -2416,13 +2416,13 @@ public final class ConversationItem extends RelativeLayout implements BindableCo if (slide instanceof ImageSlide) { failedMessage = messageRecord.isOutgoing() ? context.getString(R.string.ConversationItem_cant_download_image_you_will_need_to_send_it_again) - : context.getString(R.string.ConversationItem_cant_download_image_s_will_need_to_send_it_again, messageRecord.getIndividualRecipient().getShortDisplayName(context)); + : context.getString(R.string.ConversationItem_cant_download_image_s_will_need_to_send_it_again, messageRecord.getFromRecipient().getShortDisplayName(context)); } else if (slide instanceof VideoSlide) { failedMessage = messageRecord.isOutgoing() ? context.getString(R.string.ConversationItem_cant_download_video_you_will_need_to_send_it_again) - : context.getString(R.string.ConversationItem_cant_download_video_s_will_need_to_send_it_again, messageRecord.getIndividualRecipient().getShortDisplayName(context)); + : context.getString(R.string.ConversationItem_cant_download_video_s_will_need_to_send_it_again, messageRecord.getFromRecipient().getShortDisplayName(context)); } else { failedMessage = messageRecord.isOutgoing() ? context.getString(R.string.ConversationItem_cant_download_message_you_will_need_to_send_it_again) - : context.getString(R.string.ConversationItem_cant_download_message_s_will_need_to_send_it_again, messageRecord.getIndividualRecipient().getShortDisplayName(context)); + : context.getString(R.string.ConversationItem_cant_download_message_s_will_need_to_send_it_again, messageRecord.getFromRecipient().getShortDisplayName(context)); } new MaterialAlertDialogBuilder(getContext()) @@ -2479,7 +2479,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo } } else if (!messageRecord.isOutgoing() && messageRecord.isIdentityMismatchFailure()) { if (eventListener != null) { - eventListener.onIncomingIdentityMismatchClicked(messageRecord.getIndividualRecipient().getId()); + eventListener.onIncomingIdentityMismatchClicked(messageRecord.getFromRecipient().getId()); } } else if (messageRecord.isPendingInsecureSmsFallback()) { handleMessageApproval(); @@ -2605,7 +2605,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo messageRecord.getId()); } else { ApplicationDependencies.getJobManager().add(new SmsSendJob(messageRecord.getId(), - messageRecord.getIndividualRecipient())); + messageRecord.getToRecipient())); } }); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java index 325355a7ef..3aeb541826 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java @@ -3997,13 +3997,7 @@ public class ConversationParentFragment extends Fragment MessageRecord messageRecord = conversationMessage.getMessageRecord(); - Recipient author; - - if (messageRecord.isOutgoing()) { - author = Recipient.self(); - } else { - author = messageRecord.getIndividualRecipient(); - } + Recipient author = messageRecord.getFromRecipient(); if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getSharedContacts().isEmpty()) { Contact contact = ((MmsMessageRecord) messageRecord).getSharedContacts().get(0); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java index fd9fd982fe..4bd808b8d7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationUpdateItem.java @@ -157,10 +157,10 @@ public final class ConversationUpdateItem extends FrameLayout this.conversationRecipient = conversationRecipient; this.isMessageRequestAccepted = isMessageRequestAccepted; - senderObserver.observe(lifecycleOwner, messageRecord.getIndividualRecipient()); + senderObserver.observe(lifecycleOwner, messageRecord.getFromRecipient()); if (conversationRecipient.isActiveGroup() && - (messageRecord.isGroupCall() || messageRecord.isCollapsedGroupV2JoinUpdate() || messageRecord.isGroupV2JoinRequest(messageRecord.getIndividualRecipient().getServiceId().orElse(null)))) { + (messageRecord.isGroupCall() || messageRecord.isCollapsedGroupV2JoinUpdate() || messageRecord.isGroupV2JoinRequest(messageRecord.getFromRecipient().getServiceId().orElse(null)))) { groupObserver.observe(lifecycleOwner, conversationRecipient); groupData.observe(lifecycleOwner, conversationRecipient); } else { @@ -437,7 +437,7 @@ public final class ConversationUpdateItem extends FrameLayout actionButton.setVisibility(VISIBLE); actionButton.setOnClickListener(v -> { if (batchSelected.isEmpty() && eventListener != null) { - eventListener.onSafetyNumberLearnMoreClicked(conversationMessage.getMessageRecord().getIndividualRecipient()); + eventListener.onSafetyNumberLearnMoreClicked(conversationMessage.getMessageRecord().getFromRecipient()); } }); } else if (conversationMessage.getMessageRecord().isGroupCall()) { @@ -507,15 +507,15 @@ public final class ConversationUpdateItem extends FrameLayout actionButton.setVisibility(VISIBLE); actionButton.setOnClickListener(v -> { if (batchSelected.isEmpty() && eventListener != null) { - eventListener.onBadDecryptLearnMoreClicked(conversationMessage.getMessageRecord().getRecipient().getId()); + eventListener.onBadDecryptLearnMoreClicked(conversationMessage.getMessageRecord().getFromRecipient().getId()); } }); - } else if (conversationMessage.getMessageRecord().isChangeNumber() && conversationMessage.getMessageRecord().getIndividualRecipient().isSystemContact()) { + } else if (conversationMessage.getMessageRecord().isChangeNumber() && conversationMessage.getMessageRecord().getFromRecipient().isSystemContact()) { actionButton.setText(R.string.ConversationUpdateItem_update_contact); actionButton.setVisibility(VISIBLE); actionButton.setOnClickListener(v -> { if (batchSelected.isEmpty() && eventListener != null) { - eventListener.onChangeNumberUpdateContact(conversationMessage.getMessageRecord().getIndividualRecipient()); + eventListener.onChangeNumberUpdateContact(conversationMessage.getMessageRecord().getFromRecipient()); } }); } else if (shouldShowBlockRequestAction(conversationMessage.getMessageRecord())) { @@ -523,7 +523,7 @@ public final class ConversationUpdateItem extends FrameLayout actionButton.setVisibility(VISIBLE); actionButton.setOnClickListener(v -> { if (batchSelected.isEmpty() && eventListener != null) { - eventListener.onBlockJoinRequest(conversationMessage.getMessageRecord().getIndividualRecipient()); + eventListener.onBlockJoinRequest(conversationMessage.getMessageRecord().getFromRecipient()); } }); } else if (conversationMessage.getMessageRecord().isBoostRequest()) { @@ -557,7 +557,7 @@ public final class ConversationUpdateItem extends FrameLayout actionButton.setVisibility(VISIBLE); actionButton.setOnClickListener(v -> { if (batchSelected.isEmpty() && eventListener != null) { - eventListener.onSendPaymentClicked(conversationMessage.getMessageRecord().getIndividualRecipient().getId()); + eventListener.onSendPaymentClicked(conversationMessage.getMessageRecord().getFromRecipient().getId()); } }); } else{ @@ -567,7 +567,7 @@ public final class ConversationUpdateItem extends FrameLayout } private boolean shouldShowBlockRequestAction(MessageRecord messageRecord) { - Recipient toBlock = messageRecord.getIndividualRecipient(); + Recipient toBlock = messageRecord.getFromRecipient(); if (!toBlock.hasServiceId() || !groupData.isSelfAdmin() || groupData.isBanned(toBlock) || groupData.isFullMember(toBlock)) { return false; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/MenuState.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/MenuState.java index 57f11a61dc..cf2ff82d9c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/MenuState.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/MenuState.java @@ -191,15 +191,15 @@ final class MenuState { boolean isDisplayingMessageRequest, boolean isNonAdminInAnnouncementGroup) { - return !actionMessage && - !isNonAdminInAnnouncementGroup && - !messageRecord.isRemoteDelete() && - !messageRecord.isPending() && - !messageRecord.isFailed() && - !isDisplayingMessageRequest && - messageRecord.isSecure() && + return !actionMessage && + !isNonAdminInAnnouncementGroup && + !messageRecord.isRemoteDelete() && + !messageRecord.isPending() && + !messageRecord.isFailed() && + !isDisplayingMessageRequest && + messageRecord.isSecure() && (!conversationRecipient.isGroup() || conversationRecipient.isActiveGroup()) && - !messageRecord.getRecipient().isBlocked() && + !messageRecord.getFromRecipient().isBlocked() && !conversationRecipient.isReleaseNotes(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java index 0fac917e9e..069b65358f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ui/error/SafetyNumberChangeRepository.java @@ -17,7 +17,6 @@ import org.signal.libsignal.protocol.SignalProtocolAddress; import org.thoughtcrime.securesms.crypto.ReentrantSessionLock; import org.thoughtcrime.securesms.crypto.storage.SignalIdentityKeyStore; import org.thoughtcrime.securesms.database.IdentityTable; -import org.thoughtcrime.securesms.database.MessageTable; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch; @@ -203,7 +202,7 @@ public final class SafetyNumberChangeRepository { if (messageRecord.isMms()) { SignalDatabase.messages().removeMismatchedIdentity(messageRecord.getId(), id, identityKey); - if (messageRecord.getRecipient().isDistributionList() || messageRecord.getRecipient().isPushGroup()) { + if (messageRecord.getToRecipient().isDistributionList() || messageRecord.getToRecipient().isPushGroup()) { resendIds.add(id); } else { MessageSender.resend(context, messageRecord); @@ -216,7 +215,7 @@ public final class SafetyNumberChangeRepository { } if (Util.hasItems(resendIds)) { - if (messageRecord.getRecipient().isPushGroup()) { + if (messageRecord.getToRecipient().isPushGroup()) { MessageSender.resendGroupMessage(context, messageRecord, resendIds); } else { MessageSender.resendDistributionList(context, messageRecord, resendIds); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt index f37874d42e..393f2faac3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/CallTable.kt @@ -88,7 +88,7 @@ class CallTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTabl val messageType: Long = Call.getMessageType(type, direction, event) writableDatabase.withinTransaction { - val result = SignalDatabase.messages.insertCallLog(peer, messageType, timestamp) + val result = SignalDatabase.messages.insertCallLog(peer, messageType, timestamp, direction == Direction.OUTGOING) val values = contentValuesOf( CALL_ID to callId, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/EarlyReceiptCache.java b/app/src/main/java/org/thoughtcrime/securesms/database/EarlyDeliveryReceiptCache.java similarity index 62% rename from app/src/main/java/org/thoughtcrime/securesms/database/EarlyReceiptCache.java rename to app/src/main/java/org/thoughtcrime/securesms/database/EarlyDeliveryReceiptCache.java index 15633dee2f..6e65b72452 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/EarlyReceiptCache.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/EarlyDeliveryReceiptCache.java @@ -9,35 +9,30 @@ import org.thoughtcrime.securesms.util.LRUCache; import java.util.HashMap; import java.util.Map; -public class EarlyReceiptCache { +public class EarlyDeliveryReceiptCache { - private static final String TAG = Log.tag(EarlyReceiptCache.class); + private static final String TAG = Log.tag(EarlyDeliveryReceiptCache.class); private final LRUCache> cache = new LRUCache<>(100); - private final String name; - public EarlyReceiptCache(@NonNull String name) { - this.name = name; - } - - public synchronized void increment(long timestamp, @NonNull RecipientId origin, long receiptTimestamp) { - Map receipts = cache.get(timestamp); + public synchronized void increment(long targetTimestamp, @NonNull RecipientId receiptAuthor, long receiptSentTimestamp) { + Map receipts = cache.get(targetTimestamp); if (receipts == null) { receipts = new HashMap<>(); } - Receipt receipt = receipts.get(origin); + Receipt receipt = receipts.get(receiptAuthor); if (receipt != null) { receipt.count++; - receipt.timestamp = receiptTimestamp; + receipt.timestamp = receiptSentTimestamp; } else { - receipt = new Receipt(1, receiptTimestamp); + receipt = new Receipt(1, receiptSentTimestamp); } - receipts.put(origin, receipt); + receipts.put(receiptAuthor, receipt); - cache.put(timestamp, receipts); + cache.put(targetTimestamp, receipts); } public synchronized Map remove(long timestamp) { @@ -45,7 +40,7 @@ public class EarlyReceiptCache { return receipts != null ? receipts : new HashMap<>(); } - public class Receipt { + public static class Receipt { private long count; private long timestamp; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt index 7be2edb605..f784c090db 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.kt @@ -1275,7 +1275,7 @@ class GroupTable(context: Context?, databaseHelper: SignalDatabase?) : DatabaseT SELECT ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED} FROM ${MessageTable.TABLE_NAME} WHERE - ${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} = ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AND + ${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID} = ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AND ${MessageTable.STORY_TYPE} > 1 ORDER BY ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED} DESC LIMIT 1 diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt index 79d5f27b81..687f9c4bcf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt @@ -54,7 +54,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED}, ${MessageTable.TABLE_NAME}.${MessageTable.DATE_SERVER}, ${MessageTable.TABLE_NAME}.${MessageTable.THREAD_ID}, - ${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID}, + ${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID}, ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} as $THREAD_RECIPIENT_ID FROM ${AttachmentTable.TABLE_NAME} @@ -78,7 +78,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD ) ) AND ${AttachmentTable.STICKER_PACK_ID} IS NULL AND - ${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} > 0 AND + ${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID} > 0 AND $THREAD_RECIPIENT_ID > 0 """.toSingleLine() @@ -204,7 +204,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD return MediaRecord( attachment = if (attachments.isNotEmpty()) attachments[0] else null, - recipientId = RecipientId.from(cursor.requireLong(MessageTable.RECIPIENT_ID)), + recipientId = RecipientId.from(cursor.requireLong(MessageTable.FROM_RECIPIENT_ID)), threadId = cursor.requireLong(MessageTable.THREAD_ID), threadRecipientId = RecipientId.from(cursor.requireLong(THREAD_RECIPIENT_ID)), date = if (MessageTypes.isPushType(cursor.requireLong(MessageTable.TYPE))) { 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 f3068f81c5..7d06528cdd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.kt @@ -67,7 +67,7 @@ import org.thoughtcrime.securesms.attachments.DatabaseAttachment.DisplayOrderCom import org.thoughtcrime.securesms.attachments.MmsNotificationAttachment import org.thoughtcrime.securesms.contactshare.Contact import org.thoughtcrime.securesms.conversation.MessageStyler -import org.thoughtcrime.securesms.database.EarlyReceiptCache.Receipt +import org.thoughtcrime.securesms.database.EarlyDeliveryReceiptCache.Receipt import org.thoughtcrime.securesms.database.MentionUtil.UpdatedBodyAndMentions import org.thoughtcrime.securesms.database.SignalDatabase.Companion.attachments import org.thoughtcrime.securesms.database.SignalDatabase.Companion.calls @@ -163,8 +163,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat const val THREAD_ID = "thread_id" const val READ = "read" const val BODY = "body" - const val RECIPIENT_ID = "recipient_id" - const val RECIPIENT_DEVICE_ID = "recipient_device_id" + const val FROM_RECIPIENT_ID = "from_recipient_id" + const val FROM_DEVICE_ID = "from_device_id" + const val TO_RECIPIENT_ID = "to_recipient_id" const val DELIVERY_RECEIPT_COUNT = "delivery_receipt_count" const val READ_RECEIPT_COUNT = "read_receipt_count" const val VIEWED_RECEIPT_COUNT = "viewed_receipt_count" @@ -211,8 +212,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat $DATE_RECEIVED INTEGER NOT NULL, $DATE_SERVER INTEGER DEFAULT -1, $THREAD_ID INTEGER NOT NULL REFERENCES ${ThreadTable.TABLE_NAME} (${ThreadTable.ID}) ON DELETE CASCADE, - $RECIPIENT_ID INTEGER NOT NULL REFERENCES ${RecipientTable.TABLE_NAME} (${RecipientTable.ID}) ON DELETE CASCADE, - $RECIPIENT_DEVICE_ID INTEGER, + $FROM_RECIPIENT_ID INTEGER NOT NULL REFERENCES ${RecipientTable.TABLE_NAME} (${RecipientTable.ID}) ON DELETE CASCADE, + $FROM_DEVICE_ID INTEGER, + $TO_RECIPIENT_ID INTEGER NOT NULL REFERENCES ${RecipientTable.TABLE_NAME} (${RecipientTable.ID}) ON DELETE CASCADE, $TYPE INTEGER NOT NULL, $BODY TEXT, $READ INTEGER DEFAULT 0, @@ -257,23 +259,23 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat ) """ - private const val INDEX_THREAD_DATE = "mms_thread_date_index" - private const val INDEX_THREAD_STORY_SCHEDULED_DATE = "mms_thread_story_parent_story_scheduled_date_index" + private const val INDEX_THREAD_DATE = "message_thread_date_index" + private const val INDEX_THREAD_STORY_SCHEDULED_DATE = "message_thread_story_parent_story_scheduled_date_index" @JvmField val CREATE_INDEXS = arrayOf( - "CREATE INDEX IF NOT EXISTS mms_read_and_notified_and_thread_id_index ON $TABLE_NAME ($READ, $NOTIFIED, $THREAD_ID)", - "CREATE INDEX IF NOT EXISTS mms_type_index ON $TABLE_NAME ($TYPE)", - "CREATE INDEX IF NOT EXISTS mms_date_sent_index ON $TABLE_NAME ($DATE_SENT, $RECIPIENT_ID, $THREAD_ID)", - "CREATE INDEX IF NOT EXISTS mms_date_server_index ON $TABLE_NAME ($DATE_SERVER)", + "CREATE INDEX IF NOT EXISTS message_read_and_notified_and_thread_id_index ON $TABLE_NAME ($READ, $NOTIFIED, $THREAD_ID)", + "CREATE INDEX IF NOT EXISTS message_type_index ON $TABLE_NAME ($TYPE)", + "CREATE INDEX IF NOT EXISTS message_date_sent_from_to_thread_index ON $TABLE_NAME ($DATE_SENT, $FROM_RECIPIENT_ID, $TO_RECIPIENT_ID, $THREAD_ID)", + "CREATE INDEX IF NOT EXISTS message_date_server_index ON $TABLE_NAME ($DATE_SERVER)", "CREATE INDEX IF NOT EXISTS $INDEX_THREAD_DATE ON $TABLE_NAME ($THREAD_ID, $DATE_RECEIVED);", - "CREATE INDEX IF NOT EXISTS mms_reactions_unread_index ON $TABLE_NAME ($REACTIONS_UNREAD);", - "CREATE INDEX IF NOT EXISTS mms_story_type_index ON $TABLE_NAME ($STORY_TYPE);", - "CREATE INDEX IF NOT EXISTS mms_parent_story_id_index ON $TABLE_NAME ($PARENT_STORY_ID);", + "CREATE INDEX IF NOT EXISTS message_reactions_unread_index ON $TABLE_NAME ($REACTIONS_UNREAD);", + "CREATE INDEX IF NOT EXISTS message_story_type_index ON $TABLE_NAME ($STORY_TYPE);", + "CREATE INDEX IF NOT EXISTS message_parent_story_id_index ON $TABLE_NAME ($PARENT_STORY_ID);", "CREATE INDEX IF NOT EXISTS $INDEX_THREAD_STORY_SCHEDULED_DATE ON $TABLE_NAME ($THREAD_ID, $DATE_RECEIVED, $STORY_TYPE, $PARENT_STORY_ID, $SCHEDULED_DATE);", "CREATE INDEX IF NOT EXISTS message_quote_id_quote_author_scheduled_date_index ON $TABLE_NAME ($QUOTE_ID, $QUOTE_AUTHOR, $SCHEDULED_DATE);", - "CREATE INDEX IF NOT EXISTS mms_exported_index ON $TABLE_NAME ($EXPORTED);", - "CREATE INDEX IF NOT EXISTS mms_id_type_payment_transactions_index ON $TABLE_NAME ($ID,$TYPE) WHERE $TYPE & ${MessageTypes.SPECIAL_TYPE_PAYMENTS_NOTIFICATION} != 0;" + "CREATE INDEX IF NOT EXISTS message_exported_index ON $TABLE_NAME ($EXPORTED);", + "CREATE INDEX IF NOT EXISTS message_id_type_payment_transactions_index ON $TABLE_NAME ($ID,$TYPE) WHERE $TYPE & ${MessageTypes.SPECIAL_TYPE_PAYMENTS_NOTIFICATION} != 0;" ) private val MMS_PROJECTION_BASE = arrayOf( @@ -291,8 +293,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat MMS_STATUS, MMS_TRANSACTION_ID, BODY, - RECIPIENT_ID, - RECIPIENT_DEVICE_ID, + FROM_RECIPIENT_ID, + FROM_DEVICE_ID, + TO_RECIPIENT_ID, DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, MISMATCHED_IDENTITIES, @@ -526,18 +529,18 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } } - private val earlyDeliveryReceiptCache = EarlyReceiptCache("MmsDelivery") + private val earlyDeliveryReceiptCache = EarlyDeliveryReceiptCache() private fun getOldestGroupUpdateSender(threadId: Long, minimumDateReceived: Long): RecipientId? { val type = MessageTypes.SECURE_MESSAGE_BIT or MessageTypes.PUSH_MESSAGE_BIT or MessageTypes.GROUP_UPDATE_BIT or MessageTypes.BASE_INBOX_TYPE return readableDatabase - .select(RECIPIENT_ID) + .select(FROM_RECIPIENT_ID) .from(TABLE_NAME) .where("$THREAD_ID = ? AND $TYPE & ? AND $DATE_RECEIVED >= ?", threadId.toString(), type.toString(), minimumDateReceived.toString()) .limit(1) .run() - .readToSingleObject { RecipientId.from(it.requireLong(RECIPIENT_ID)) } + .readToSingleObject { RecipientId.from(it.requireLong(FROM_RECIPIENT_ID)) } } fun getExpirationStartedMessages(): Cursor { @@ -655,11 +658,11 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat fun getViewedIncomingMessages(threadId: Long): List { return readableDatabase - .select(ID, RECIPIENT_ID, DATE_SENT, TYPE, THREAD_ID, STORY_TYPE) + .select(ID, FROM_RECIPIENT_ID, DATE_SENT, TYPE, THREAD_ID, STORY_TYPE) .from(TABLE_NAME) .where("$THREAD_ID = ? AND $VIEWED_RECEIPT_COUNT > 0 AND $TYPE & ${MessageTypes.BASE_INBOX_TYPE} = ${MessageTypes.BASE_INBOX_TYPE}", threadId) .run() - .readToList { it.toMarkedMessageInfo() } + .readToList { it.toMarkedMessageInfo(outgoing = false) } } fun setIncomingMessageViewed(messageId: Long): MarkedMessageInfo? { @@ -677,7 +680,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } val results: List = readableDatabase - .select(ID, RECIPIENT_ID, DATE_SENT, TYPE, THREAD_ID, STORY_TYPE) + .select(ID, FROM_RECIPIENT_ID, DATE_SENT, TYPE, THREAD_ID, STORY_TYPE) .from(TABLE_NAME) .where("$ID IN (${Util.join(messageIds, ",")}) AND $VIEWED_RECEIPT_COUNT = 0") .run() @@ -685,7 +688,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val type = cursor.requireLong(TYPE) if (MessageTypes.isSecureType(type) && MessageTypes.isInboxType(type)) { - cursor.toMarkedMessageInfo() + cursor.toMarkedMessageInfo(outgoing = false) } else { null } @@ -724,11 +727,11 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat fun setOutgoingGiftsRevealed(messageIds: List): List { val results: List = readableDatabase - .select(ID, RECIPIENT_ID, DATE_SENT, THREAD_ID, STORY_TYPE) + .select(ID, TO_RECIPIENT_ID, DATE_SENT, THREAD_ID, STORY_TYPE) .from(TABLE_NAME) .where("""$ID IN (${Util.join(messageIds, ",")}) AND (${getOutgoingTypeClause()}) AND ($TYPE & ${MessageTypes.SPECIAL_TYPES_MASK} = ${MessageTypes.SPECIAL_TYPE_GIFT_BADGE}) AND $VIEWED_RECEIPT_COUNT = 0""") .run() - .readToList { it.toMarkedMessageInfo() } + .readToList { it.toMarkedMessageInfo(outgoing = true) } val currentTime = System.currentTimeMillis() SqlUtil @@ -752,14 +755,15 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return results } - fun insertCallLog(recipientId: RecipientId, type: Long, timestamp: Long): InsertResult { + fun insertCallLog(recipientId: RecipientId, type: Long, timestamp: Long, outgoing: Boolean): InsertResult { val unread = MessageTypes.isMissedAudioCall(type) || MessageTypes.isMissedVideoCall(type) val recipient = Recipient.resolved(recipientId) val threadId = threads.getOrCreateThreadIdFor(recipient) val values = contentValuesOf( - RECIPIENT_ID to recipientId.serialize(), - RECIPIENT_DEVICE_ID to 1, + FROM_RECIPIENT_ID to if (outgoing) Recipient.self().id.serialize() else recipientId.serialize(), + FROM_DEVICE_ID to 1, + TO_RECIPIENT_ID to if (outgoing) recipientId.serialize() else Recipient.self().id.serialize(), DATE_RECEIVED to System.currentTimeMillis(), DATE_SENT to timestamp, READ to if (unread) 0 else 1, @@ -828,8 +832,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat .toByteArray() val values = contentValuesOf( - RECIPIENT_ID to sender.serialize(), - RECIPIENT_DEVICE_ID to 1, + FROM_RECIPIENT_ID to sender.serialize(), + FROM_DEVICE_ID to 1, + TO_RECIPIENT_ID to groupRecipientId.serialize(), DATE_RECEIVED to timestamp, DATE_SENT to timestamp, READ to if (markRead) 1 else 0, @@ -1003,7 +1008,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat type = type or MessageTypes.KEY_EXCHANGE_IDENTITY_DEFAULT_BIT } - val recipient = Recipient.resolved(message.sender) + val recipient = Recipient.resolved(message.authorId) val groupRecipient: Recipient? = if (message.groupId == null) { null @@ -1034,8 +1039,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } val values = ContentValues() - values.put(RECIPIENT_ID, message.sender.serialize()) - values.put(RECIPIENT_DEVICE_ID, message.senderDeviceId) + values.put(FROM_RECIPIENT_ID, message.authorId.serialize()) + values.put(FROM_DEVICE_ID, message.authorDeviceId) + values.put(TO_RECIPIENT_ID, Recipient.self().id.serialize()) values.put(DATE_RECEIVED, message.receivedTimestampMillis) values.put(DATE_SENT, message.sentTimestampMillis) values.put(DATE_SERVER, message.serverTimestampMillis) @@ -1098,8 +1104,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat .filterNotNull() .forEach { threadId -> val values = contentValuesOf( - RECIPIENT_ID to recipient.id.serialize(), - RECIPIENT_DEVICE_ID to 1, + FROM_RECIPIENT_ID to recipient.id.serialize(), + FROM_DEVICE_ID to 1, + TO_RECIPIENT_ID to Recipient.self().id.serialize(), DATE_RECEIVED to System.currentTimeMillis(), DATE_SENT to System.currentTimeMillis(), READ to 1, @@ -1129,8 +1136,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat private fun insertGroupV1MigrationMembershipChanges(recipientId: RecipientId, threadId: Long, membershipChange: GroupMigrationMembershipChange) { val values = contentValuesOf( - RECIPIENT_ID to recipientId.serialize(), - RECIPIENT_DEVICE_ID to 1, + FROM_RECIPIENT_ID to recipientId.serialize(), + FROM_DEVICE_ID to 1, + TO_RECIPIENT_ID to Recipient.self().id.serialize(), DATE_RECEIVED to System.currentTimeMillis(), DATE_SENT to System.currentTimeMillis(), READ to 1, @@ -1162,8 +1170,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat .filterNotNull() .forEach { threadId: Long -> val values = contentValuesOf( - RECIPIENT_ID to recipientId.serialize(), - RECIPIENT_DEVICE_ID to 1, + FROM_RECIPIENT_ID to recipientId.serialize(), + FROM_DEVICE_ID to 1, + TO_RECIPIENT_ID to Recipient.self().id.serialize(), DATE_RECEIVED to System.currentTimeMillis(), DATE_SENT to System.currentTimeMillis(), READ to 1, @@ -1185,8 +1194,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat writableDatabase .insertInto(TABLE_NAME) .values( - RECIPIENT_ID to recipientId.serialize(), - RECIPIENT_DEVICE_ID to 1, + FROM_RECIPIENT_ID to recipientId.serialize(), + FROM_DEVICE_ID to 1, + TO_RECIPIENT_ID to Recipient.self().id.serialize(), DATE_RECEIVED to System.currentTimeMillis(), DATE_SENT to System.currentTimeMillis(), READ to 1, @@ -1201,8 +1211,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat writableDatabase .insertInto(TABLE_NAME) .values( - RECIPIENT_ID to recipientId.serialize(), - RECIPIENT_DEVICE_ID to 1, + FROM_RECIPIENT_ID to recipientId.serialize(), + FROM_DEVICE_ID to 1, + TO_RECIPIENT_ID to Recipient.self().id.serialize(), DATE_RECEIVED to System.currentTimeMillis(), DATE_SENT to System.currentTimeMillis(), READ to 1, @@ -1219,8 +1230,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat writableDatabase .insertInto(TABLE_NAME) .values( - RECIPIENT_ID to recipientId.serialize(), - RECIPIENT_DEVICE_ID to 1, + FROM_RECIPIENT_ID to recipientId.serialize(), + FROM_DEVICE_ID to 1, + TO_RECIPIENT_ID to Recipient.self().id.serialize(), DATE_RECEIVED to System.currentTimeMillis(), DATE_SENT to System.currentTimeMillis(), READ to 1, @@ -1239,8 +1251,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } else { db.insertInto(TABLE_NAME) .values( - RECIPIENT_ID to recipientId.serialize(), - RECIPIENT_DEVICE_ID to 1, + FROM_RECIPIENT_ID to recipientId.serialize(), + FROM_DEVICE_ID to 1, + TO_RECIPIENT_ID to Recipient.self().id.serialize(), DATE_RECEIVED to System.currentTimeMillis(), DATE_SENT to System.currentTimeMillis(), READ to 1, @@ -1285,7 +1298,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val whereArgs: Array if (threadId == null) { - where += " AND $RECIPIENT_ID = ?" + where += " AND $FROM_RECIPIENT_ID = ?" whereArgs = buildArgs(recipientId) } else { where += " AND $THREAD_ID = ?" @@ -1327,7 +1340,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat fun markOnboardingStoryRead() { val recipientId = SignalStore.releaseChannelValues().releaseChannelRecipientId ?: return - val where = "$IS_STORY_CLAUSE AND NOT (${getOutgoingTypeClause()}) AND $READ = 0 AND $RECIPIENT_ID = ?" + val where = "$IS_STORY_CLAUSE AND NOT (${getOutgoingTypeClause()}) AND $READ = 0 AND $FROM_RECIPIENT_ID = ?" val markedMessageInfos = setMessagesRead(where, buildArgs(recipientId)) if (markedMessageInfos.isNotEmpty()) { @@ -1391,17 +1404,16 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat /** * Synchronizes whether we've viewed a recipient's story based on incoming sync messages. */ - fun updateViewedStories(syncMessageIds: Set) { - val timestamps: String = syncMessageIds - .map { it.timetamp } + fun updateViewedStories(targetTimestamps: Set) { + val timestamps: String = targetTimestamps .joinToString(",") writableDatabase.withinTransaction { db -> - db.select(RECIPIENT_ID) + db.select(FROM_RECIPIENT_ID) .from(TABLE_NAME) .where("$IS_STORY_CLAUSE AND $DATE_SENT IN ($timestamps) AND NOT (${getOutgoingTypeClause()}) AND $VIEWED_RECEIPT_COUNT > 0") .run() - .readToList { cursor -> RecipientId.from(cursor.requireLong(RECIPIENT_ID)) } + .readToList { cursor -> RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)) } .forEach { id -> recipients.updateLastStoryViewTimestamp(id) } } } @@ -1432,24 +1444,19 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat fun isOutgoingStoryAlreadyInDatabase(recipientId: RecipientId, sentTimestamp: Long): Boolean { return readableDatabase .exists(TABLE_NAME) - .where("$RECIPIENT_ID = ? AND $STORY_TYPE > 0 AND $DATE_SENT = ? AND (${getOutgoingTypeClause()})", recipientId, sentTimestamp) + .where("$TO_RECIPIENT_ID = ? AND $STORY_TYPE > 0 AND $DATE_SENT = ? AND (${getOutgoingTypeClause()})", recipientId, sentTimestamp) .run() } @Throws(NoSuchMessageException::class) fun getStoryId(authorId: RecipientId, sentTimestamp: Long): MessageId { return readableDatabase - .select(ID, RECIPIENT_ID) + .select(ID) .from(TABLE_NAME) - .where("$IS_STORY_CLAUSE AND $DATE_SENT = ?", sentTimestamp) + .where("$IS_STORY_CLAUSE AND $DATE_SENT = ? AND $FROM_RECIPIENT_ID = ?", sentTimestamp, authorId) .run() .readToSingleObject { cursor -> - val rowRecipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))) - if (Recipient.self().id == authorId || rowRecipientId == authorId) { - MessageId(CursorUtil.requireLong(cursor, ID)) - } else { - null - } + MessageId(CursorUtil.requireLong(cursor, ID)) } ?: throw NoSuchMessageException("No story sent at $sentTimestamp") } @@ -1601,11 +1608,11 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat db.execSQL(deleteStoryRepliesQuery, sharedArgs) db.execSQL(disassociateQuoteQuery, sharedArgs) - db.select(RECIPIENT_ID) + db.select(FROM_RECIPIENT_ID) .from(TABLE_NAME) .where(storiesBeforeTimestampWhere, sharedArgs) .run() - .readToList { RecipientId.from(it.requireLong(RECIPIENT_ID)) } + .readToList { RecipientId.from(it.requireLong(FROM_RECIPIENT_ID)) } .forEach { id -> ApplicationDependencies.getDatabaseObserver().notifyStoryObservers(id) } val deletedStoryCount = db.select(ID) @@ -2133,13 +2140,13 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val releaseChannelId = SignalStore.releaseChannelValues().releaseChannelRecipientId return writableDatabase.withinTransaction { db -> val infos = db - .select(ID, RECIPIENT_ID, DATE_SENT, TYPE, EXPIRES_IN, EXPIRE_STARTED, THREAD_ID, STORY_TYPE) + .select(ID, FROM_RECIPIENT_ID, DATE_SENT, TYPE, EXPIRES_IN, EXPIRE_STARTED, THREAD_ID, STORY_TYPE) .from("$TABLE_NAME INDEXED BY $INDEX_THREAD_DATE") .where(where, arguments ?: emptyArray()) .run() .readToList { cursor -> val threadId = cursor.requireLong(THREAD_ID) - val recipientId = RecipientId.from(cursor.requireLong(RECIPIENT_ID)) + val recipientId = RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)) val dateSent = cursor.requireLong(DATE_SENT) val messageId = cursor.requireLong(ID) val expiresIn = cursor.requireLong(EXPIRES_IN) @@ -2171,7 +2178,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat fun getOldestUnreadMentionDetails(threadId: Long): Pair? { return readableDatabase - .select(RECIPIENT_ID, DATE_RECEIVED) + .select(FROM_RECIPIENT_ID, DATE_RECEIVED) .from(TABLE_NAME) .where("$THREAD_ID = ? AND $READ = 0 AND $MENTIONS_SELF = 1", threadId) .orderBy("$DATE_RECEIVED ASC") @@ -2179,7 +2186,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat .run() .readToSingleObject { cursor -> Pair( - RecipientId.from(cursor.requireLong(RECIPIENT_ID)), + RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)), cursor.requireLong(DATE_RECEIVED) ) } @@ -2228,13 +2235,13 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat fun getNotification(messageId: Long): Optional { return readableDatabase - .select(RECIPIENT_ID, MMS_CONTENT_LOCATION, MMS_TRANSACTION_ID, SMS_SUBSCRIPTION_ID) + .select(FROM_RECIPIENT_ID, MMS_CONTENT_LOCATION, MMS_TRANSACTION_ID, SMS_SUBSCRIPTION_ID) .from(TABLE_NAME) .where("$ID = ?", messageId) .run() .readToSingleObject { cursor -> MmsNotificationInfo( - from = RecipientId.from(cursor.requireLong(RECIPIENT_ID)), + from = RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)), contentLocation = cursor.requireNonNullString(MMS_CONTENT_LOCATION), transactionId = cursor.requireNonNullString(MMS_TRANSACTION_ID), subscriptionId = cursor.requireInt(SMS_SUBSCRIPTION_ID) @@ -2254,8 +2261,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val subscriptionId = cursor.requireInt(SMS_SUBSCRIPTION_ID) val expiresIn = cursor.requireLong(EXPIRES_IN) val viewOnce = cursor.requireLong(VIEW_ONCE) == 1L - val recipient = Recipient.resolved(RecipientId.from(cursor.requireLong(RECIPIENT_ID))) val threadId = cursor.requireLong(THREAD_ID) + val threadRecipient = Recipient.resolved(threads.getRecipientIdForThreadId(threadId)!!) val distributionType = threads.getDistributionType(threadId) val storyType = StoryType.fromCode(cursor.requireInt(STORY_TYPE)) val parentStoryId = ParentStoryId.deserialize(cursor.requireLong(PARENT_STORY_ID)) @@ -2312,7 +2319,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat if (body != null && (MessageTypes.isGroupQuit(outboxType) || MessageTypes.isGroupUpdate(outboxType))) { OutgoingMessage.groupUpdateMessage( - recipient = recipient, + threadRecipient = threadRecipient, groupContext = MessageGroupContext(body, MessageTypes.isGroupV2(outboxType)), avatar = attachments, sentTimeMillis = timestamp, @@ -2325,26 +2332,26 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat ) } else if (MessageTypes.isExpirationTimerUpdate(outboxType)) { OutgoingMessage.expirationUpdateMessage( - recipient = recipient, + threadRecipient = threadRecipient, sentTimeMillis = timestamp, expiresIn = expiresIn ) } else if (MessageTypes.isPaymentsNotification(outboxType)) { OutgoingMessage.paymentNotificationMessage( - recipient = recipient, + threadRecipient = threadRecipient, paymentUuid = body!!, sentTimeMillis = timestamp, expiresIn = expiresIn ) } else if (MessageTypes.isPaymentsRequestToActivate(outboxType)) { OutgoingMessage.requestToActivatePaymentsMessage( - recipient = recipient, + threadRecipient = threadRecipient, sentTimeMillis = timestamp, expiresIn = expiresIn ) } else if (MessageTypes.isPaymentsActivated(outboxType)) { OutgoingMessage.paymentsActivatedMessage( - recipient = recipient, + threadRecipient = threadRecipient, sentTimeMillis = timestamp, expiresIn = expiresIn ) @@ -2367,7 +2374,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } OutgoingMessage( - recipient = recipient, + recipient = threadRecipient, body = body, attachments = attachments, timestamp = timestamp, @@ -2416,7 +2423,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val contentValues = contentValuesOf( DATE_SENT to retrieved.sentTimeMillis, DATE_SERVER to retrieved.serverTimeMillis, - RECIPIENT_ID to retrieved.from!!.serialize(), + FROM_RECIPIENT_ID to retrieved.from!!.serialize(), + TO_RECIPIENT_ID to Recipient.self().id.serialize(), TYPE to mailbox, MMS_MESSAGE_TYPE to PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF, THREAD_ID to threadId, @@ -2576,7 +2584,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val threadId = getThreadIdFor(notification) - val recipientId: String = if (notification.from != null) { + val authorId: String = if (notification.from != null) { Recipient.external(context, Util.toIsoString(notification.from.textString)).id.serialize() } else { RecipientId.UNKNOWN.serialize() @@ -2591,7 +2599,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat MMS_MESSAGE_SIZE to if (notification.messageSize != -1L) notification.messageSize else null, MMS_TRANSACTION_ID to notification.transactionId.toIsoString(), MMS_MESSAGE_TYPE to if (notification.messageType != 0) notification.messageType else null, - RECIPIENT_ID to recipientId, + FROM_RECIPIENT_ID to authorId, TYPE to MessageTypes.BASE_INBOX_TYPE, THREAD_ID to threadId, MMS_STATUS to MmsStatus.DOWNLOAD_INITIALIZED, @@ -2612,8 +2620,10 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val messageId = writableDatabase .insertInto(TABLE_NAME) .values( - RECIPIENT_ID to recipientId.serialize(), - RECIPIENT_DEVICE_ID to senderDeviceId, + FROM_RECIPIENT_ID to recipientId.serialize(), + FROM_DEVICE_ID to senderDeviceId, + TO_RECIPIENT_ID to Recipient.self().id.serialize(), + TO_RECIPIENT_ID to Recipient.self().id.serialize(), DATE_RECEIVED to System.currentTimeMillis(), DATE_SENT to sentTimestamp, DATE_SERVER to -1, @@ -2636,8 +2646,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat writableDatabase .insertInto(TABLE_NAME) .values( - RECIPIENT_ID to recipientId.serialize(), - RECIPIENT_DEVICE_ID to senderDevice, + FROM_RECIPIENT_ID to recipientId.serialize(), + FROM_DEVICE_ID to senderDevice, + TO_RECIPIENT_ID to Recipient.self().id.serialize(), DATE_SENT to sentTimestamp, DATE_RECEIVED to receivedTimestamp, DATE_SERVER to -1, @@ -2830,14 +2841,16 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat contentValues.put(SMS_SUBSCRIPTION_ID, message.subscriptionId) contentValues.put(EXPIRES_IN, message.expiresIn) contentValues.put(VIEW_ONCE, message.isViewOnce) - contentValues.put(RECIPIENT_ID, message.recipient.id.serialize()) + contentValues.put(FROM_RECIPIENT_ID, Recipient.self().id.serialize()) + contentValues.put(FROM_DEVICE_ID, SignalStore.account().deviceId) + contentValues.put(TO_RECIPIENT_ID, message.threadRecipient.id.serialize()) contentValues.put(DELIVERY_RECEIPT_COUNT, earlyDeliveryReceipts.values.sumOf { it.count }) contentValues.put(RECEIPT_TIMESTAMP, earlyDeliveryReceipts.values.map { it.timestamp }.maxOrNull() ?: -1L) contentValues.put(STORY_TYPE, message.storyType.code) contentValues.put(PARENT_STORY_ID, if (message.parentStoryId != null) message.parentStoryId.serialize() else 0) contentValues.put(SCHEDULED_DATE, message.scheduledDate) - if (message.recipient.isSelf && hasAudioAttachment(message.attachments)) { + if (message.threadRecipient.isSelf && hasAudioAttachment(message.attachments)) { contentValues.put(VIEWED_RECEIPT_COUNT, 1L) } @@ -2888,7 +2901,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat unarchive = false ) - if (message.recipient.isGroup) { + if (message.threadRecipient.isGroup) { val members: MutableSet = mutableSetOf() if (message.isGroupUpdate && message.isV2Group) { @@ -2899,7 +2912,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat members -= Recipient.self().id } else { - members += groups.getGroupMembers(message.recipient.requireGroupId(), GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF).map { it.id } + members += groups.getGroupMembers(message.threadRecipient.requireGroupId(), GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF).map { it.id } } groupReceipts.insert(members, messageId, defaultReceiptStatus, message.sentTimeMillis) @@ -2907,8 +2920,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat for (recipientId in earlyDeliveryReceipts.keys) { groupReceipts.update(recipientId, messageId, GroupReceiptTable.STATUS_DELIVERED, -1) } - } else if (message.recipient.isDistributionList) { - val members = distributionLists.getMembers(message.recipient.requireDistributionListId()) + } else if (message.threadRecipient.isDistributionList) { + val members = distributionLists.getMembers(message.threadRecipient.requireDistributionListId()) groupReceipts.insert(members, messageId, defaultReceiptStatus, message.sentTimeMillis) @@ -2930,7 +2943,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat ApplicationDependencies.getDatabaseObserver().notifyScheduledMessageObservers(threadId) } } else { - ApplicationDependencies.getDatabaseObserver().notifyStoryObservers(message.recipient.id) + ApplicationDependencies.getDatabaseObserver().notifyStoryObservers(message.threadRecipient.id) } notifyConversationListListeners() @@ -3221,14 +3234,14 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat private fun isDuplicate(message: IncomingMediaMessage, threadId: Long): Boolean { return readableDatabase .exists(TABLE_NAME) - .where("$DATE_SENT = ? AND $RECIPIENT_ID = ? AND $THREAD_ID = ?", message.sentTimeMillis, message.from!!.serialize(), threadId) + .where("$DATE_SENT = ? AND $FROM_RECIPIENT_ID = ? AND $THREAD_ID = ?", message.sentTimeMillis, message.from!!.serialize(), threadId) .run() } private fun isDuplicate(message: IncomingTextMessage, threadId: Long): Boolean { return readableDatabase .exists(TABLE_NAME) - .where("$DATE_SENT = ? AND $RECIPIENT_ID = ? AND $THREAD_ID = ?", message.sentTimestampMillis, message.sender.serialize(), threadId) + .where("$DATE_SENT = ? AND $FROM_RECIPIENT_ID = ? AND $THREAD_ID = ?", message.sentTimestampMillis, message.authorId.serialize(), threadId) .run() } @@ -3432,7 +3445,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return readableDatabase .select("COUNT(*)") .from(TABLE_NAME) - .where("$RECIPIENT_ID = ? AND $TYPE = ?", recipientId, MessageTypes.CHANGE_NUMBER_TYPE) + .where("$FROM_RECIPIENT_ID = ? AND $TYPE = ?", recipientId, MessageTypes.CHANGE_NUMBER_TYPE) .run() .readToSingleInt() } @@ -3707,7 +3720,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val data: MutableList = ArrayList() readableDatabase - .select(RECIPIENT_ID, SERVER_GUID, DATE_RECEIVED) + .select(FROM_RECIPIENT_ID, SERVER_GUID, DATE_RECEIVED) .from(TABLE_NAME) .where("$THREAD_ID = ? AND $DATE_RECEIVED <= ?", threadId, timestamp) .orderBy("$DATE_RECEIVED DESC") @@ -3718,7 +3731,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat if (serverGuid != null && serverGuid.isNotEmpty()) { data += ReportSpamData( - recipientId = RecipientId.from(cursor.requireLong(RECIPIENT_ID)), + recipientId = RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)), serverGuid = serverGuid, dateReceived = cursor.requireLong(DATE_RECEIVED) ) @@ -3782,11 +3795,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat * Whether or not the message has been quoted by another message. */ fun isQuoted(messageRecord: MessageRecord): Boolean { - val author = if (messageRecord.isOutgoing) Recipient.self().id else messageRecord.recipient.id - return readableDatabase .exists(TABLE_NAME) - .where("$QUOTE_ID = ? AND $QUOTE_AUTHOR = ? AND $SCHEDULED_DATE = ?", messageRecord.dateSent, author, -1) + .where("$QUOTE_ID = ? AND $QUOTE_AUTHOR = ? AND $SCHEDULED_DATE = ?", messageRecord.dateSent, messageRecord.fromRecipient.id, -1) .run() } @@ -3804,10 +3815,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat for (record in records) { val timestamp = record.dateSent - val author = if (record.isOutgoing) Recipient.self().id else record.recipient.id - byQuoteDescriptor[QuoteDescriptor(timestamp, author)] = record - args.add(buildArgs(timestamp, author, -1)) + byQuoteDescriptor[QuoteDescriptor(timestamp, record.fromRecipient.id)] = record + args.add(buildArgs(timestamp, record.fromRecipient.id, -1)) } val quotedIds: MutableSet = mutableSetOf() @@ -3838,11 +3848,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return id } - val query: String = if (targetMessage.quote!!.author == Recipient.self().id) { - "$DATE_SENT = ${targetMessage.quote!!.id} AND ($TYPE & ${MessageTypes.BASE_TYPE_MASK}) = ${MessageTypes.BASE_SENT_TYPE}" - } else { - "$DATE_SENT = ${targetMessage.quote!!.id} AND $RECIPIENT_ID = '${targetMessage.quote!!.author.serialize()}'" - } + val query = "$DATE_SENT = ${targetMessage.quote!!.id} AND $FROM_RECIPIENT_ID = '${targetMessage.quote!!.author.serialize()}'" MmsReader(readableDatabase.query(TABLE_NAME, MMS_PROJECTION, query, null, null, null, "1")).use { reader -> val record: MessageRecord? = reader.firstOrNull() @@ -3856,9 +3862,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat fun getAllMessagesThatQuote(id: MessageId): List { val targetMessage: MessageRecord = getMessageRecord(id.id) - val author = if (targetMessage.isOutgoing) Recipient.self().id else targetMessage.recipient.id - val query = "$QUOTE_ID = ${targetMessage.dateSent} AND $QUOTE_AUTHOR = ${author.serialize()} AND $SCHEDULED_DATE = -1" + val query = "$QUOTE_ID = ${targetMessage.dateSent} AND $QUOTE_AUTHOR = ${targetMessage.fromRecipient.id.serialize()} AND $SCHEDULED_DATE = -1" val order = "$DATE_RECEIVED DESC" val records: MutableList = ArrayList() @@ -3872,20 +3877,18 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return records.sortedByDescending { it.dateReceived } } - fun getQuotedMessagePosition(threadId: Long, quoteId: Long, recipientId: RecipientId): Int { - val isOwnNumber = Recipient.resolved(recipientId).isSelf - + fun getQuotedMessagePosition(threadId: Long, quoteId: Long, authorId: RecipientId): Int { readableDatabase - .select(DATE_SENT, RECIPIENT_ID, REMOTE_DELETED) + .select(DATE_SENT, FROM_RECIPIENT_ID, REMOTE_DELETED) .from(TABLE_NAME) .where("$THREAD_ID = $threadId AND $STORY_TYPE = 0 AND $PARENT_STORY_ID <= 0 AND $SCHEDULED_DATE = -1") .orderBy("$DATE_RECEIVED DESC") .run() .forEach { cursor -> val quoteIdMatches = cursor.requireLong(DATE_SENT) == quoteId - val recipientIdMatches = recipientId == RecipientId.from(cursor.requireLong(RECIPIENT_ID)) + val recipientIdMatches = authorId == RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)) - if (quoteIdMatches && (recipientIdMatches || isOwnNumber)) { + if (quoteIdMatches && recipientIdMatches) { return if (cursor.requireBoolean(REMOTE_DELETED)) { -1 } else { @@ -3897,20 +3900,18 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return -1 } - fun getMessagePositionInConversation(threadId: Long, receivedTimestamp: Long, recipientId: RecipientId): Int { - val isOwnNumber = Recipient.resolved(recipientId).isSelf - + fun getMessagePositionInConversation(threadId: Long, receivedTimestamp: Long, authorId: RecipientId): Int { readableDatabase - .select(DATE_RECEIVED, RECIPIENT_ID, REMOTE_DELETED) + .select(DATE_RECEIVED, FROM_RECIPIENT_ID, REMOTE_DELETED) .from(TABLE_NAME) .where("$THREAD_ID = $threadId AND $STORY_TYPE = 0 AND $PARENT_STORY_ID <= 0 AND $SCHEDULED_DATE = -1") .orderBy("$DATE_RECEIVED DESC") .run() .forEach { cursor -> val timestampMatches = cursor.requireLong(DATE_RECEIVED) == receivedTimestamp - val recipientIdMatches = recipientId == RecipientId.from(cursor.requireLong(RECIPIENT_ID)) + val authorIdMatches = authorId == RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)) - if (timestampMatches && (recipientIdMatches || isOwnNumber)) { + if (timestampMatches && authorIdMatches) { return if (cursor.requireBoolean(REMOTE_DELETED)) { -1 } else { @@ -4094,52 +4095,52 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat .run() } - fun incrementDeliveryReceiptCounts(syncMessageIds: List, timestamp: Long): Collection { - return incrementReceiptCounts(syncMessageIds, timestamp, ReceiptType.DELIVERY) + fun incrementDeliveryReceiptCounts(targetTimestamps: List, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Set { + return incrementReceiptCounts(targetTimestamps, receiptAuthor, receiptSentTimestamp, ReceiptType.DELIVERY) } - fun incrementDeliveryReceiptCount(syncMessageId: SyncMessageId, timestamp: Long): Boolean { - return incrementReceiptCount(syncMessageId, timestamp, ReceiptType.DELIVERY) + fun incrementDeliveryReceiptCount(targetTimestamps: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Boolean { + return incrementReceiptCount(targetTimestamps, receiptAuthor, receiptSentTimestamp, ReceiptType.DELIVERY) } /** * @return A list of ID's that were not updated. */ - fun incrementReadReceiptCounts(syncMessageIds: List, timestamp: Long): Collection { - return incrementReceiptCounts(syncMessageIds, timestamp, ReceiptType.READ) + fun incrementReadReceiptCounts(targetTimestamps: List, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Set { + return incrementReceiptCounts(targetTimestamps, receiptAuthor, receiptSentTimestamp, ReceiptType.READ) } - fun incrementReadReceiptCount(syncMessageId: SyncMessageId, timestamp: Long): Boolean { - return incrementReceiptCount(syncMessageId, timestamp, ReceiptType.READ) + fun incrementReadReceiptCount(targetTimestamps: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Boolean { + return incrementReceiptCount(targetTimestamps, receiptAuthor, receiptSentTimestamp, ReceiptType.READ) } /** * @return A list of ID's that were not updated. */ - fun incrementViewedReceiptCounts(syncMessageIds: List, timestamp: Long): Collection { - return incrementReceiptCounts(syncMessageIds, timestamp, ReceiptType.VIEWED) + fun incrementViewedReceiptCounts(targetTimestamps: List, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Set { + return incrementReceiptCounts(targetTimestamps, receiptAuthor, receiptSentTimestamp, ReceiptType.VIEWED) } - fun incrementViewedNonStoryReceiptCounts(syncMessageIds: List, timestamp: Long): Collection { - return incrementReceiptCounts(syncMessageIds, timestamp, ReceiptType.VIEWED, MessageQualifier.NORMAL) + fun incrementViewedNonStoryReceiptCounts(targetTimestamps: List, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Set { + return incrementReceiptCounts(targetTimestamps, receiptAuthor, receiptSentTimestamp, ReceiptType.VIEWED, MessageQualifier.NORMAL) } - fun incrementViewedReceiptCount(syncMessageId: SyncMessageId, timestamp: Long): Boolean { - return incrementReceiptCount(syncMessageId, timestamp, ReceiptType.VIEWED) + fun incrementViewedReceiptCount(targetTimestamp: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Boolean { + return incrementReceiptCount(targetTimestamp, receiptAuthor, receiptSentTimestamp, ReceiptType.VIEWED) } - fun incrementViewedStoryReceiptCounts(syncMessageIds: List, timestamp: Long): Collection { + fun incrementViewedStoryReceiptCounts(targetTimestamps: List, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Set { val messageUpdates: MutableSet = HashSet() - val unhandled: MutableSet = HashSet() + val unhandled: MutableSet = HashSet() writableDatabase.withinTransaction { - for (id in syncMessageIds) { - val updates = incrementReceiptCountInternal(id, timestamp, ReceiptType.VIEWED, MessageQualifier.STORY) + for (targetTimestamp in targetTimestamps) { + val updates = incrementReceiptCountInternal(targetTimestamp, receiptAuthor, receiptSentTimestamp, ReceiptType.VIEWED, MessageQualifier.STORY) if (updates.isNotEmpty()) { messageUpdates += updates } else { - unhandled += id + unhandled += targetTimestamp } } } @@ -4161,11 +4162,11 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat * * @return Whether or not some thread was updated. */ - private fun incrementReceiptCount(syncMessageId: SyncMessageId, timestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier = MessageQualifier.ALL): Boolean { + private fun incrementReceiptCount(targetTimestamp: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier = MessageQualifier.ALL): Boolean { var messageUpdates: Set = HashSet() writableDatabase.withinTransaction { - messageUpdates = incrementReceiptCountInternal(syncMessageId, timestamp, receiptType, messageQualifier) + messageUpdates = incrementReceiptCountInternal(targetTimestamp, receiptAuthor, receiptSentTimestamp, receiptType, messageQualifier) for (messageUpdate in messageUpdates) { threads.update(messageUpdate.threadId, false) @@ -4182,20 +4183,20 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat /** * Wraps multiple receipt updates in a transaction and triggers the proper updates. * - * @return All of the messages that didn't result in updates. + * @return All of the target timestamps that couldn't be found in the table. */ - private fun incrementReceiptCounts(syncMessageIds: List, timestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier = MessageQualifier.ALL): Collection { + private fun incrementReceiptCounts(targetTimestamps: List, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier = MessageQualifier.ALL): Set { val messageUpdates: MutableSet = HashSet() - val unhandled: MutableSet = HashSet() + val missingTargetTimestamps: MutableSet = HashSet() writableDatabase.withinTransaction { - for (id in syncMessageIds) { - val updates = incrementReceiptCountInternal(id, timestamp, receiptType, messageQualifier) + for (targetTimestamp in targetTimestamps) { + val updates: Set = incrementReceiptCountInternal(targetTimestamp, receiptAuthor, receiptSentTimestamp, receiptType, messageQualifier) if (updates.isNotEmpty()) { messageUpdates += updates } else { - unhandled += id + missingTargetTimestamps += targetTimestamp } } @@ -4217,10 +4218,10 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat notifyConversationListListeners() } - return unhandled + return missingTargetTimestamps } - private fun incrementReceiptCountInternal(messageId: SyncMessageId, timestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier): Set { + private fun incrementReceiptCountInternal(targetTimestamp: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier): Set { val messageUpdates: MutableSet = HashSet() val qualifierWhere: String = when (messageQualifier) { @@ -4229,74 +4230,46 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat MessageQualifier.ALL -> "" } - readableDatabase - .select(ID, THREAD_ID, TYPE, RECIPIENT_ID, receiptType.columnName, RECEIPT_TIMESTAMP) - .from(TABLE_NAME) - .where("$DATE_SENT = ? $qualifierWhere", messageId.timetamp) - .run() - .forEach { cursor -> - if (MessageTypes.isOutgoingMessageType(cursor.requireLong(TYPE))) { - val theirRecipientId = RecipientId.from(cursor.requireLong(RECIPIENT_ID)) - val ourRecipientId = messageId.recipientId - val columnName = receiptType.columnName + var found = false + var hasStory = false + writableDatabase.rawQuery( + """ + UPDATE $TABLE_NAME + SET + ${receiptType.columnName} = ${receiptType.columnName} + 1, + $RECEIPT_TIMESTAMP = CASE + WHEN ${receiptType.columnName} = 0 THEN MAX($RECEIPT_TIMESTAMP, ?) + ELSE $RECEIPT_TIMESTAMP + END + WHERE + $DATE_SENT = ? AND + $FROM_RECIPIENT_ID = ? AND + ($TO_RECIPIENT_ID = ? OR EXISTS (SELECT 1 FROM ${GroupTable.TABLE_NAME} WHERE ${GroupTable.TABLE_NAME}.${GroupTable.RECIPIENT_ID} = $TO_RECIPIENT_ID)) + $qualifierWhere + RETURNING $ID, $THREAD_ID, $STORY_TYPE + """.toSingleLine(), + buildArgs(receiptSentTimestamp, targetTimestamp, Recipient.self().id, receiptAuthor) + ).forEach { cursor -> + val messageId = cursor.requireLong(ID) + val threadId = cursor.requireLong(THREAD_ID) + val storyType = StoryType.fromCode(cursor.requireInt(STORY_TYPE)) - if (ourRecipientId == theirRecipientId || Recipient.resolved(theirRecipientId).isGroup) { - val id = cursor.requireLong(ID) - val threadId = cursor.requireLong(THREAD_ID) - val status = receiptType.groupStatus - val isFirstIncrement = cursor.requireLong(columnName) == 0L - val savedTimestamp = cursor.requireLong(RECEIPT_TIMESTAMP) - val updatedTimestamp = if (isFirstIncrement) max(savedTimestamp, timestamp) else savedTimestamp + groupReceipts.update(receiptAuthor, messageId, receiptType.groupStatus, receiptSentTimestamp) + messageUpdates += MessageUpdate(threadId, MessageId(messageId)) - writableDatabase.execSQL( - """ - UPDATE $TABLE_NAME - SET - $columnName = $columnName + 1, - $RECEIPT_TIMESTAMP = ? - WHERE $ID = ? - """.toSingleLine(), - buildArgs(updatedTimestamp, id) - ) + found = true + hasStory = storyType != StoryType.NONE + } - groupReceipts.update(ourRecipientId, id, status, timestamp) + if (!found && receiptType == ReceiptType.DELIVERY) { + earlyDeliveryReceiptCache.increment(targetTimestamp, receiptAuthor, receiptSentTimestamp) + } - messageUpdates += MessageUpdate(threadId, MessageId(id)) - } - } - - if (messageUpdates.isNotEmpty() && receiptType == ReceiptType.DELIVERY) { - earlyDeliveryReceiptCache.increment(messageId.timetamp, messageId.recipientId, timestamp) - } + if (hasStory) { + for (messageId in storySends.getStoryMessagesFor(receiptAuthor, targetTimestamp)) { + groupReceipts.update(receiptAuthor, messageId.id, receiptType.groupStatus, receiptSentTimestamp) + messageUpdates += MessageUpdate(-1, messageId) } - - messageUpdates += incrementStoryReceiptCount(messageId, timestamp, receiptType) - - return messageUpdates - } - - private fun incrementStoryReceiptCount(messageId: SyncMessageId, timestamp: Long, receiptType: ReceiptType): Set { - val messageUpdates: MutableSet = HashSet() - val columnName = receiptType.columnName - - for (storyMessageId in storySends.getStoryMessagesFor(messageId)) { - writableDatabase.execSQL( - """ - UPDATE $TABLE_NAME - SET - $columnName = $columnName + 1, - $RECEIPT_TIMESTAMP = CASE - WHEN $columnName = 0 THEN MAX($RECEIPT_TIMESTAMP, ?) - ELSE $RECEIPT_TIMESTAMP - END - WHERE $ID = ? - """.toSingleLine(), - buildArgs(timestamp, storyMessageId.id) - ) - - groupReceipts.update(messageId.recipientId, storyMessageId.id, receiptType.groupStatus, timestamp) - - messageUpdates += MessageUpdate(-1, storyMessageId) } return messageUpdates @@ -4358,15 +4331,12 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat */ private fun setTimestampReadFromSyncMessageInternal(messageId: SyncMessageId, proposedExpireStarted: Long, threadToLatestRead: MutableMap): TimestampReadResult { val expiring: MutableList> = LinkedList() - val projection = arrayOf(ID, THREAD_ID, EXPIRES_IN, EXPIRE_STARTED) - val query = "$DATE_SENT = ? AND ($RECIPIENT_ID = ? OR ($RECIPIENT_ID = ? AND ${getOutgoingTypeClause()}))" - val args = buildArgs(messageId.timetamp, messageId.recipientId, Recipient.self().id) val threads: MutableList = LinkedList() readableDatabase .select(ID, THREAD_ID, EXPIRES_IN, EXPIRE_STARTED) .from(TABLE_NAME) - .where("$DATE_SENT = ? AND ($RECIPIENT_ID = ? OR ($RECIPIENT_ID = ? AND ${getOutgoingTypeClause()}))", messageId.timetamp, messageId.recipientId, Recipient.self().id) + .where("$DATE_SENT = ? AND ($FROM_RECIPIENT_ID = ? OR ($FROM_RECIPIENT_ID = ? AND ${getOutgoingTypeClause()}))", messageId.timetamp, messageId.recipientId, Recipient.self().id) .run() .forEach { cursor -> val id = cursor.requireLong(ID) @@ -4416,23 +4386,15 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat * Does *not* include attachments. */ fun getMessageFor(timestamp: Long, authorId: RecipientId): MessageRecord? { - val isSelf = authorId == Recipient.self().id - val cursor = readableDatabase .select(*MMS_PROJECTION) .from(TABLE_NAME) - .where("$DATE_SENT = ?", timestamp) + .where("$DATE_SENT = ? AND $FROM_RECIPIENT_ID = ?", timestamp, authorId) .run() - mmsReaderFor(cursor).use { reader -> - for (record in reader) { - if ((isSelf && record.isOutgoing) || (!isSelf && record.individualRecipient.id == authorId)) { - return record - } - } + return mmsReaderFor(cursor).use { reader -> + reader.firstOrNull() } - - return null } /** @@ -4543,8 +4505,14 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat override fun remapRecipient(fromId: RecipientId, toId: RecipientId) { writableDatabase .update(TABLE_NAME) - .values(RECIPIENT_ID to toId.serialize()) - .where("$RECIPIENT_ID = ?", fromId) + .values(FROM_RECIPIENT_ID to toId.serialize()) + .where("$FROM_RECIPIENT_ID = ?", fromId) + .run() + + writableDatabase + .update(TABLE_NAME) + .values(TO_RECIPIENT_ID to toId.serialize()) + .where("$TO_RECIPIENT_ID = ?", fromId) .run() } @@ -4705,12 +4673,13 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return threads.getThreadIdFor(releaseChannelRecipientId) ?: return -1L } - private fun Cursor.toMarkedMessageInfo(): MarkedMessageInfo { + private fun Cursor.toMarkedMessageInfo(outgoing: Boolean): MarkedMessageInfo { + val recipientColumn = if (outgoing) TO_RECIPIENT_ID else FROM_RECIPIENT_ID return MarkedMessageInfo( messageId = MessageId(this.requireLong(ID)), threadId = this.requireLong(THREAD_ID), syncMessageId = SyncMessageId( - recipientId = RecipientId.from(this.requireLong(RECIPIENT_ID)), + recipientId = RecipientId.from(this.requireLong(recipientColumn)), timetamp = this.requireLong(DATE_SENT) ), expirationInfo = null, @@ -4920,9 +4889,11 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val dateReceived = cursor.requireLong(DATE_RECEIVED) val threadId = cursor.requireLong(THREAD_ID) val mailbox = cursor.requireLong(TYPE) - val recipientId = cursor.requireLong(RECIPIENT_ID) - val addressDeviceId = cursor.requireInt(RECIPIENT_DEVICE_ID) - val recipient = Recipient.live(RecipientId.from(recipientId)).get() + val fromRecipientId = cursor.requireLong(FROM_RECIPIENT_ID) + val fromDeviceId = cursor.requireInt(FROM_DEVICE_ID) + val toRecipientId = cursor.requireLong(TO_RECIPIENT_ID) + val fromRecipient = Recipient.live(RecipientId.from(fromRecipientId)).get() + val toRecipient = Recipient.live(RecipientId.from(toRecipientId)).get() val contentLocation = cursor.requireString(MMS_CONTENT_LOCATION).toIsoBytes() val transactionId = cursor.requireString(MMS_TRANSACTION_ID).toIsoBytes() val messageSize = cursor.requireLong(MMS_MESSAGE_SIZE) @@ -4955,9 +4926,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return NotificationMmsMessageRecord( id, - recipient, - recipient, - addressDeviceId, + fromRecipient, + fromDeviceId, + toRecipient, dateSent, dateReceived, deliveryReceiptCount, @@ -4986,8 +4957,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat val dateServer = cursor.requireLong(DATE_SERVER) val box = cursor.requireLong(TYPE) val threadId = cursor.requireLong(THREAD_ID) - val recipientId = cursor.requireLong(RECIPIENT_ID) - val addressDeviceId = cursor.requireInt(RECIPIENT_DEVICE_ID) + val fromRecipientId = cursor.requireLong(FROM_RECIPIENT_ID) + val fromDeviceId = cursor.requireInt(FROM_DEVICE_ID) + val toRecipientId = cursor.requireLong(TO_RECIPIENT_ID) val deliveryReceiptCount = cursor.requireInt(DELIVERY_RECEIPT_COUNT) var readReceiptCount = cursor.requireInt(READ_RECEIPT_COUNT) val body = cursor.requireString(BODY) @@ -5015,7 +4987,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat } } - val recipient = Recipient.live(RecipientId.from(recipientId)).get() + val fromRecipient = Recipient.live(RecipientId.from(fromRecipientId)).get() + val toRecipient = Recipient.live(RecipientId.from(toRecipientId)).get() val mismatches = getMismatchedIdentities(mismatchDocument) val networkFailures = getFailures(networkDocument) @@ -5055,9 +5028,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat return MediaMmsMessageRecord( id, - recipient, - recipient, - addressDeviceId, + fromRecipient, + fromDeviceId, + toRecipient, dateSent, dateReceived, dateServer, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt index 7a8a5ed1cf..4eb68124f8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.kt @@ -63,7 +63,7 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa private const val MESSAGES_QUERY = """ SELECT ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AS $CONVERSATION_RECIPIENT, - ${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} AS $MESSAGE_RECIPIENT, + ${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID} AS $MESSAGE_RECIPIENT, snippet($FTS_TABLE_NAME, -1, '', '', '$SNIPPET_WRAP', 7) AS $SNIPPET, ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED}, $FTS_TABLE_NAME.$THREAD_ID, @@ -86,7 +86,7 @@ class SearchTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa private const val MESSAGES_FOR_THREAD_QUERY = """ SELECT ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID} AS $CONVERSATION_RECIPIENT, - ${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} AS $MESSAGE_RECIPIENT, + ${MessageTable.TABLE_NAME}.${MessageTable.FROM_RECIPIENT_ID} AS $MESSAGE_RECIPIENT, snippet($FTS_TABLE_NAME, -1, '', '', '$SNIPPET_WRAP', 7) AS $SNIPPET, ${MessageTable.TABLE_NAME}.${MessageTable.DATE_RECEIVED}, $FTS_TABLE_NAME.$THREAD_ID, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/StorySendTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/StorySendTable.kt index cd71b212e3..b15f6450f3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/StorySendTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/StorySendTable.kt @@ -171,14 +171,14 @@ class StorySendTable(context: Context, databaseHelper: SignalDatabase) : Databas } } - fun getStoryMessagesFor(syncMessageId: MessageTable.SyncMessageId): Set { + fun getStoryMessagesFor(recipientId: RecipientId, sentTimestamp: Long): Set { val messageIds = mutableSetOf() readableDatabase.query( TABLE_NAME, arrayOf(MESSAGE_ID), "$RECIPIENT_ID = ? AND $SENT_TIMESTAMP = ?", - SqlUtil.buildArgs(syncMessageId.recipientId, syncMessageId.timetamp), + SqlUtil.buildArgs(recipientId, sentTimestamp), null, null, null @@ -270,7 +270,7 @@ class StorySendTable(context: Context, databaseHelper: SignalDatabase) : Databas val query = """ SELECT ${MessageTable.TABLE_NAME}.${MessageTable.ID} as $MESSAGE_ID, ${DistributionListTables.DISTRIBUTION_ID} FROM ${MessageTable.TABLE_NAME} - INNER JOIN ${DistributionListTables.LIST_TABLE_NAME} ON ${DistributionListTables.LIST_TABLE_NAME}.${DistributionListTables.RECIPIENT_ID} = ${MessageTable.TABLE_NAME}.${MessageTable.RECIPIENT_ID} + INNER JOIN ${DistributionListTables.LIST_TABLE_NAME} ON ${DistributionListTables.LIST_TABLE_NAME}.${DistributionListTables.RECIPIENT_ID} = ${MessageTable.TABLE_NAME}.${MessageTable.TO_RECIPIENT_ID} WHERE ${MessageTable.DATE_SENT} = $sentTimestamp AND ${DistributionListTables.DISTRIBUTION_ID} IS NOT NULL """.trimIndent() diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadBodyUtil.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadBodyUtil.java index a661937d28..b1c07c05fc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadBodyUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadBodyUtil.java @@ -91,11 +91,11 @@ public final class ThreadBodyUtil { private static @NonNull String getGiftSummary(@NonNull Context context, @NonNull MessageRecord messageRecord) { if (messageRecord.isOutgoing()) { - return context.getString(R.string.ThreadRecord__you_donated_for_s, messageRecord.getRecipient().getShortDisplayName(context)); + return context.getString(R.string.ThreadRecord__you_donated_for_s, messageRecord.getToRecipient().getShortDisplayName(context)); } else if (messageRecord.getViewedReceiptCount() > 0) { return context.getString(R.string.ThreadRecord__you_redeemed_a_badge); } else { - return context.getString(R.string.ThreadRecord__s_donated_for_you, messageRecord.getRecipient().getShortDisplayName(context)); + return context.getString(R.string.ThreadRecord__s_donated_for_you, messageRecord.getFromRecipient().getShortDisplayName(context)); } } @@ -111,7 +111,7 @@ public final class ThreadBodyUtil { if (messageRecord.isOutgoing()) { return context.getString(R.string.ThreadRecord_you_sent_request); } else { - return context.getString(R.string.ThreadRecord_wants_you_to_activate_payments, messageRecord.getRecipient().getShortDisplayName(context)); + return context.getString(R.string.ThreadRecord_wants_you_to_activate_payments, messageRecord.getFromRecipient().getShortDisplayName(context)); } } @@ -119,7 +119,7 @@ public final class ThreadBodyUtil { if (messageRecord.isOutgoing()) { return context.getString(R.string.ThreadRecord_you_activated_payments); } else { - return context.getString(R.string.ThreadRecord_can_accept_payments, messageRecord.getRecipient().getShortDisplayName(context)); + return context.getString(R.string.ThreadRecord_can_accept_payments, messageRecord.getFromRecipient().getShortDisplayName(context)); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt index 1fe3b68ff9..3c3a75abe9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt @@ -1359,6 +1359,11 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa } private fun update(threadId: Long, unarchive: Boolean, allowDeletion: Boolean, notifyListeners: Boolean): Boolean { + if (threadId == -1L) { + Log.d(TAG, "Skipping update for threadId -1") + return false + } + val meaningfulMessages = messages.hasMeaningfulMessage(threadId) val isPinned = getPinnedThreadIds().contains(threadId) @@ -1581,10 +1586,10 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa } private fun getExtrasFor(record: MessageRecord, body: ThreadBody): Extra? { - val threadRecipient = if (record.isOutgoing) record.recipient else getRecipientForThreadId(record.threadId) + val threadRecipient = getRecipientForThreadId(record.threadId) val messageRequestAccepted = RecipientUtil.isMessageRequestAccepted(record.threadId, threadRecipient) val isHidden = threadRecipient?.isHidden ?: false - val individualRecipientId = record.individualRecipient.id + val authorId = record.fromRecipient.id if (!messageRequestAccepted && threadRecipient != null) { if (threadRecipient.isPushGroup) { @@ -1594,46 +1599,46 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa val from = RecipientId.from(ServiceId.from(inviteAddState.addedOrInvitedBy)) return if (inviteAddState.isInvited) { Log.i(TAG, "GV2 invite message request from $from") - Extra.forGroupV2invite(from, individualRecipientId) + Extra.forGroupV2invite(from, authorId) } else { Log.i(TAG, "GV2 message request from $from") - Extra.forGroupMessageRequest(from, individualRecipientId) + Extra.forGroupMessageRequest(from, authorId) } } Log.w(TAG, "Falling back to unknown message request state for GV2 message") - return Extra.forMessageRequest(individualRecipientId) + return Extra.forMessageRequest(authorId) } else { val recipientId = messages.getGroupAddedBy(record.threadId) if (recipientId != null) { - return Extra.forGroupMessageRequest(recipientId, individualRecipientId) + return Extra.forGroupMessageRequest(recipientId, authorId) } } } else { - return Extra.forMessageRequest(individualRecipientId, isHidden) + return Extra.forMessageRequest(authorId, isHidden) } } val extras: Extra? = if (record.isScheduled()) { - Extra.forScheduledMessage(individualRecipientId) + Extra.forScheduledMessage(authorId) } else if (record.isRemoteDelete) { - Extra.forRemoteDelete(individualRecipientId) + Extra.forRemoteDelete(authorId) } else if (record.isViewOnce) { - Extra.forViewOnce(individualRecipientId) + Extra.forViewOnce(authorId) } else if (record.isMms && (record as MmsMessageRecord).slideDeck.stickerSlide != null) { val slide: StickerSlide = record.slideDeck.stickerSlide!! - Extra.forSticker(slide.emoji, individualRecipientId) + Extra.forSticker(slide.emoji, authorId) } else if (record.isMms && (record as MmsMessageRecord).slideDeck.slides.size > 1) { - Extra.forAlbum(individualRecipientId) + Extra.forAlbum(authorId) } else if (threadRecipient != null && threadRecipient.isGroup) { - Extra.forDefault(individualRecipientId) + Extra.forDefault(authorId) } else { null } return if (record.messageRanges != null) { val bodyRanges = record.requireMessageRanges().adjustBodyRanges(body.bodyAdjustments)!! - extras?.copy(bodyRanges = bodyRanges.serialize()) ?: Extra.forBodyRanges(bodyRanges, individualRecipientId) + extras?.copy(bodyRanges = bodyRanges.serialize()) ?: Extra.forBodyRanges(bodyRanges, authorId) } else { extras } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index f97dd35ff7..92caa2edca 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -40,6 +40,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V181_ThreadTableFor import org.thoughtcrime.securesms.database.helpers.migration.V182_CallTableMigration import org.thoughtcrime.securesms.database.helpers.migration.V183_CallLinkTableMigration import org.thoughtcrime.securesms.database.helpers.migration.V184_CallLinkReplaceIndexMigration +import org.thoughtcrime.securesms.database.helpers.migration.V185_MessageRecipientsMigration /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -48,7 +49,7 @@ object SignalDatabaseMigrations { val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass) - const val DATABASE_VERSION = 184 + const val DATABASE_VERSION = 185 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { @@ -195,6 +196,10 @@ object SignalDatabaseMigrations { if (oldVersion < 184) { V184_CallLinkReplaceIndexMigration.migrate(context, db, oldVersion, newVersion) } + + if (oldVersion < 185) { + V185_MessageRecipientsMigration.migrate(context, db, oldVersion, newVersion) + } } @JvmStatic diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V185_MessageRecipientsMigration.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V185_MessageRecipientsMigration.kt new file mode 100644 index 0000000000..981a573419 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V185_MessageRecipientsMigration.kt @@ -0,0 +1,285 @@ +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import android.preference.PreferenceManager +import net.zetetic.database.sqlcipher.SQLiteDatabase +import org.signal.core.util.SqlUtil +import org.signal.core.util.Stopwatch +import org.signal.core.util.logging.Log +import org.signal.core.util.readToList +import org.signal.core.util.readToSingleInt +import org.signal.core.util.readToSingleObject +import org.signal.core.util.requireLong +import org.signal.core.util.requireNonNullString +import org.signal.core.util.requireString +import org.signal.core.util.toSingleLine +import org.thoughtcrime.securesms.database.KeyValueDatabase +import org.thoughtcrime.securesms.dependencies.ApplicationDependencies +import org.thoughtcrime.securesms.recipients.RecipientId +import org.whispersystems.signalservice.api.push.ACI + +/** + * Our current column setup for knowing is the the sender/receiver of a message is both confusing and non-optimal from a performance perspective. + * This moves to a world where instead of tracking a single recipient, we track two: a sender and receiver. + */ +object V185_MessageRecipientsMigration : SignalDatabaseMigration { + + private val TAG = Log.tag(V185_MessageRecipientsMigration::class.java) + + private val outgoingClause = "(" + listOf(21, 23, 22, 24, 25, 26, 2, 11) + .map { "type & ${0x1F} = $it" } + .joinToString(separator = " OR ") + ")" + + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + val stopwatch = Stopwatch("migration") + + val selfId: RecipientId? = getSelfId(db) + + if (selfId == null) { + val messageCount = db.rawQuery("SELECT COUNT(*) FROM message").readToSingleInt() + if (messageCount == 0) { + Log.i(TAG, "Could not find ourselves in the DB! Assuming this is an install that hasn't been registered yet.") + } else { + throw IllegalStateException("Could not find ourselves in the recipient table, but messages exist in the message table!") + } + } + + stopwatch.split("get-self") + + val dependentItems: List = getAllDependentItems(db, "message") + + dependentItems.forEach { item -> + val sql = "DROP ${item.type} IF EXISTS ${item.name}" + Log.d(TAG, "Executing: $sql") + db.execSQL(sql) + } + + stopwatch.split("drop-dependents") + + db.execSQL( + """ + CREATE TABLE message_tmp ( + _id INTEGER PRIMARY KEY AUTOINCREMENT, + date_sent INTEGER NOT NULL, + date_received INTEGER NOT NULL, + date_server INTEGER DEFAULT -1, + thread_id INTEGER NOT NULL REFERENCES thread (_id) ON DELETE CASCADE, + from_recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE, + from_device_id INTEGER, + to_recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE, + type INTEGER NOT NULL, + body TEXT, + read INTEGER DEFAULT 0, + ct_l TEXT, + exp INTEGER, + m_type INTEGER, + m_size INTEGER, + st INTEGER, + tr_id TEXT, + subscription_id INTEGER DEFAULT -1, + receipt_timestamp INTEGER DEFAULT -1, + delivery_receipt_count INTEGER DEFAULT 0, + read_receipt_count INTEGER DEFAULT 0, + viewed_receipt_count INTEGER DEFAULT 0, + mismatched_identities TEXT DEFAULT NULL, + network_failures TEXT DEFAULT NULL, + expires_in INTEGER DEFAULT 0, + expire_started INTEGER DEFAULT 0, + notified INTEGER DEFAULT 0, + quote_id INTEGER DEFAULT 0, + quote_author INTEGER DEFAULT 0, + quote_body TEXT DEFAULT NULL, + quote_missing INTEGER DEFAULT 0, + quote_mentions BLOB DEFAULT NULL, + quote_type INTEGER DEFAULT 0, + shared_contacts TEXT DEFAULT NULL, + unidentified INTEGER DEFAULT 0, + link_previews TEXT DEFAULT NULL, + view_once INTEGER DEFAULT 0, + reactions_unread INTEGER DEFAULT 0, + reactions_last_seen INTEGER DEFAULT -1, + remote_deleted INTEGER DEFAULT 0, + mentions_self INTEGER DEFAULT 0, + notified_timestamp INTEGER DEFAULT 0, + server_guid TEXT DEFAULT NULL, + message_ranges BLOB DEFAULT NULL, + story_type INTEGER DEFAULT 0, + parent_story_id INTEGER DEFAULT 0, + export_state BLOB DEFAULT NULL, + exported INTEGER DEFAULT 0, + scheduled_date INTEGER DEFAULT -1 + ) + """ + ) + stopwatch.split("create-table") + + db.execSQL( + """ + INSERT INTO message_tmp + SELECT + _id, + date_sent, + date_received, + date_server, + thread_id, + recipient_id, + recipient_device_id, + recipient_id, + type, + body, + read, + ct_l, + exp, + m_type, + m_size, + st, + tr_id, + subscription_id, + receipt_timestamp, + delivery_receipt_count, + read_receipt_count, + viewed_receipt_count, + mismatched_identities, + network_failures, + expires_in, + expire_started, + notified, + quote_id, + quote_author, + quote_body, + quote_missing, + quote_mentions, + quote_type, + shared_contacts, + unidentified, + link_previews, + view_once, + reactions_unread, + reactions_last_seen, + remote_deleted, + mentions_self, + notified_timestamp, + server_guid, + message_ranges, + story_type, + parent_story_id, + export_state, + exported, + scheduled_date + FROM message + """ + ) + stopwatch.split("copy-data") + + // Previously, the recipient_id on an outgoing message represented who it was going to (an individual or group). + // So if a message is outgoing, we'll set to = from, then from = self + if (selfId != null) { + db.execSQL( + """ + UPDATE message_tmp + SET + to_recipient_id = from_recipient_id, + from_recipient_id = ${selfId.toLong()}, + from_device_id = 1 + WHERE $outgoingClause + """.toSingleLine() + ) + } + stopwatch.split("update-data") + + db.execSQL("DROP TABLE message") + stopwatch.split("drop-old-table") + + db.execSQL("ALTER TABLE message_tmp RENAME TO message") + stopwatch.split("rename-table") + + dependentItems.forEach { item -> + val sql = when (item.name) { + "mms_date_sent_index" -> "CREATE INDEX message_date_sent_from_to_thread_index ON message (date_sent, from_recipient_id, to_recipient_id, thread_id)" + else -> item.createStatement.replace(Regex.fromLiteral("CREATE INDEX mms_"), "CREATE INDEX message_") + } + Log.d(TAG, "Executing: $sql") + db.execSQL(sql) + } + stopwatch.split("recreate-dependents") + + db.execSQL("PRAGMA foreign_key_check") + stopwatch.split("fk-check") + + stopwatch.stop(TAG) + } + + private fun getSelfId(db: SQLiteDatabase): RecipientId? { + val idByAci: RecipientId? = getLocalAci(ApplicationDependencies.getApplication())?.let { aci -> + db.rawQuery("SELECT _id FROM recipient WHERE uuid = ?", SqlUtil.buildArgs(aci)) + .readToSingleObject { RecipientId.from(it.requireLong("_id")) } + } + + if (idByAci != null) { + return idByAci + } + + Log.w(TAG, "Failed to find by ACI! Will try by E164.") + + val idByE164: RecipientId? = getLocalE164(ApplicationDependencies.getApplication())?.let { e164 -> + db.rawQuery("SELECT _id FROM recipient WHERE phone = ?", SqlUtil.buildArgs(e164)) + .readToSingleObject { RecipientId.from(it.requireLong("_id")) } + } + + if (idByE164 == null) { + Log.w(TAG, "Also failed to find by E164!") + } + + return idByE164 + } + + private fun getLocalAci(context: Application): ACI? { + if (KeyValueDatabase.exists(context)) { + val keyValueDatabase = KeyValueDatabase.getInstance(context).readableDatabase + keyValueDatabase.query("key_value", arrayOf("value"), "key = ?", SqlUtil.buildArgs("account.aci"), null, null, null).use { cursor -> + return if (cursor.moveToFirst()) { + ACI.parseOrNull(cursor.requireString("value")) + } else { + Log.w(TAG, "ACI not present in KV database!") + null + } + } + } else { + Log.w(TAG, "Pre-KV database -- searching for ACI in shared prefs.") + return ACI.parseOrNull(PreferenceManager.getDefaultSharedPreferences(context).getString("pref_local_uuid", null)) + } + } + + private fun getLocalE164(context: Application): String? { + if (KeyValueDatabase.exists(context)) { + val keyValueDatabase = KeyValueDatabase.getInstance(context).readableDatabase + keyValueDatabase.query("key_value", arrayOf("value"), "key = ?", SqlUtil.buildArgs("account.e164"), null, null, null).use { cursor -> + return if (cursor.moveToFirst()) { + cursor.requireString("value") + } else { + Log.w(TAG, "E164 not present in KV database!") + null + } + } + } else { + Log.w(TAG, "Pre-KV database -- searching for E164 in shared prefs.") + return PreferenceManager.getDefaultSharedPreferences(context).getString("pref_local_number", null) + } + } + + private fun getAllDependentItems(db: SQLiteDatabase, tableName: String): List { + return db.rawQuery("SELECT type, name, sql FROM sqlite_schema WHERE tbl_name='$tableName' AND type != 'table'").readToList { cursor -> + SqlItem( + type = cursor.requireNonNullString("type"), + name = cursor.requireNonNullString("name"), + createStatement = cursor.requireNonNullString("sql") + ) + } + } + + data class SqlItem( + val type: String, + val name: String, + val createStatement: String + ) +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java index f3766b0dfe..7837619cbe 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java @@ -39,7 +39,8 @@ public abstract class DisplayRecord { protected final long type; - private final Recipient recipient; + private final Recipient fromRecipient; + private final Recipient toRecipient; private final long dateSent; private final long dateReceived; private final long threadId; @@ -49,12 +50,13 @@ public abstract class DisplayRecord { private final int readReceiptCount; private final int viewReceiptCount; - DisplayRecord(String body, Recipient recipient, long dateSent, + DisplayRecord(String body, Recipient fromRecipient, Recipient toRecipient, long dateSent, long dateReceived, long threadId, int deliveryStatus, int deliveryReceiptCount, long type, int readReceiptCount, int viewReceiptCount) { this.threadId = threadId; - this.recipient = recipient; + this.fromRecipient = fromRecipient; + this.toRecipient = toRecipient; this.dateSent = dateSent; this.dateReceived = dateReceived; this.type = type; @@ -97,8 +99,12 @@ public abstract class DisplayRecord { public abstract SpannableString getDisplayBody(@NonNull Context context); - public Recipient getRecipient() { - return recipient.live().get(); + public Recipient getFromRecipient() { + return fromRecipient.live().get(); + } + + public Recipient getToRecipient() { + return toRecipient.live().get(); } public long getDateSent() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/InMemoryMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/InMemoryMessageRecord.java index b036f2ff0e..21898f782d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/InMemoryMessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/InMemoryMessageRecord.java @@ -27,15 +27,15 @@ public class InMemoryMessageRecord extends MessageRecord { private InMemoryMessageRecord(long id, String body, - Recipient conversationRecipient, + Recipient author, long threadId, long type) { super(id, body, - conversationRecipient, - conversationRecipient, + author, 1, + author, System.currentTimeMillis(), System.currentTimeMillis(), System.currentTimeMillis(), @@ -170,8 +170,8 @@ public class InMemoryMessageRecord extends MessageRecord { * Useful for create an empty message record when one is needed. */ public static final class ForceConversationBubble extends InMemoryMessageRecord { - public ForceConversationBubble(Recipient conversationRecipient, long threadId) { - super(FORCE_BUBBLE_ID, "", conversationRecipient, threadId, 0); + public ForceConversationBubble(Recipient author, long threadId) { + super(FORCE_BUBBLE_ID, "", author, threadId, 0); } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java index 5b0b1156f0..653201db94 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java @@ -72,9 +72,9 @@ public class MediaMmsMessageRecord extends MmsMessageRecord { private final long scheduledDate; public MediaMmsMessageRecord(long id, - Recipient conversationRecipient, - Recipient individualRecipient, - int recipientDeviceId, + Recipient fromRecipient, + int fromDeviceId, + Recipient toRecipient, long dateSent, long dateReceived, long dateServer, @@ -108,7 +108,7 @@ public class MediaMmsMessageRecord extends MmsMessageRecord { @Nullable CallTable.Call call, long scheduledDate) { - super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, dateSent, + super(id, body, fromRecipient, fromDeviceId, toRecipient, dateSent, dateReceived, dateServer, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, mismatches, failures, subscriptionId, expiresIn, expireStarted, viewOnce, slideDeck, readReceiptCount, quote, contacts, linkPreviews, unidentified, reactions, remoteDelete, notifiedTimestamp, viewedReceiptCount, receiptTimestamp, @@ -205,14 +205,14 @@ public class MediaMmsMessageRecord extends MmsMessageRecord { } public @NonNull MediaMmsMessageRecord withReactions(@NonNull List reactions) { - return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(), + return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), reactions, isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate()); } public @NonNull MediaMmsMessageRecord withoutQuote() { - return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(), + return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), getReadReceiptCount(), null, getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate()); @@ -233,14 +233,14 @@ public class MediaMmsMessageRecord extends MmsMessageRecord { List slideAttachments = attachments.stream().filter(a -> !contactAttachments.contains(a)).filter(a -> !linkPreviewAttachments.contains(a)).collect(Collectors.toList()); SlideDeck slideDeck = MessageTable.MmsReader.buildSlideDeck(context, slideAttachments); - return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), slideDeck, + return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), slideDeck, getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), getReadReceiptCount(), quote, contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate()); } public @NonNull MediaMmsMessageRecord withPayment(@NonNull Payment payment) { - return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(), + return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), payment, getCall(), getScheduledDate()); @@ -248,7 +248,7 @@ public class MediaMmsMessageRecord extends MmsMessageRecord { public @NonNull MediaMmsMessageRecord withCall(@Nullable CallTable.Call call) { - return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(), + return new MediaMmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), call, getScheduledDate()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index cf69cc720f..4cec607d43 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -89,9 +89,8 @@ public abstract class MessageRecord extends DisplayRecord { private static final String TAG = Log.tag(MessageRecord.class); - private final Recipient individualRecipient; - private final int recipientDeviceId; private final long id; + private final int authorDeviceId; private final Set mismatches; private final Set networkFailures; private final int subscriptionId; @@ -106,8 +105,7 @@ public abstract class MessageRecord extends DisplayRecord { protected Boolean isJumboji = null; - MessageRecord(long id, String body, Recipient conversationRecipient, - Recipient individualRecipient, int recipientDeviceId, + MessageRecord(long id, String body, Recipient fromRecipient, int fromDeviceId, Recipient toRecipient, long dateSent, long dateReceived, long dateServer, long threadId, int deliveryStatus, int deliveryReceiptCount, long type, Set mismatches, @@ -117,12 +115,11 @@ public abstract class MessageRecord extends DisplayRecord { @NonNull List reactions, boolean remoteDelete, long notifiedTimestamp, int viewedReceiptCount, long receiptTimestamp) { - super(body, conversationRecipient, dateSent, dateReceived, + super(body, fromRecipient, toRecipient, dateSent, dateReceived, threadId, deliveryStatus, deliveryReceiptCount, type, readReceiptCount, viewedReceiptCount); this.id = id; - this.individualRecipient = individualRecipient; - this.recipientDeviceId = recipientDeviceId; + this.authorDeviceId = fromDeviceId; this.mismatches = mismatches; this.networkFailures = networkFailures; this.subscriptionId = subscriptionId; @@ -171,11 +168,11 @@ public abstract class MessageRecord extends DisplayRecord { } else if (isGroupUpdate() && isOutgoing()) { return staticUpdateDescription(context.getString(R.string.MessageRecord_you_updated_group), R.drawable.ic_update_group_16); } else if (isGroupUpdate()) { - return fromRecipient(getIndividualRecipient(), r -> GroupUtil.getNonV2GroupDescription(context, getBody()).toString(r), R.drawable.ic_update_group_16); + return fromRecipient(getFromRecipient(), r -> GroupUtil.getNonV2GroupDescription(context, getBody()).toString(r), R.drawable.ic_update_group_16); } else if (isGroupQuit() && isOutgoing()) { return staticUpdateDescription(context.getString(R.string.MessageRecord_left_group), R.drawable.ic_update_group_leave_16); } else if (isGroupQuit()) { - return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.ConversationItem_group_action_left, r.getDisplayName(context)), R.drawable.ic_update_group_leave_16); + return fromRecipient(getFromRecipient(), r -> context.getString(R.string.ConversationItem_group_action_left, r.getDisplayName(context)), R.drawable.ic_update_group_leave_16); } else if (isIncomingAudioCall()) { return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_incoming_voice_call), getCallDateString(context)), R.drawable.ic_update_audio_call_incoming_16); } else if (isIncomingVideoCall()) { @@ -191,47 +188,47 @@ public abstract class MessageRecord extends DisplayRecord { } else if (isGroupCall()) { return getGroupCallUpdateDescription(context, getBody(), true); } else if (isJoined()) { - return staticUpdateDescription(context.getString(R.string.MessageRecord_s_joined_signal, getIndividualRecipient().getDisplayName(context)), R.drawable.ic_update_group_add_16); + return staticUpdateDescription(context.getString(R.string.MessageRecord_s_joined_signal, getFromRecipient().getDisplayName(context)), R.drawable.ic_update_group_add_16); } else if (isExpirationTimerUpdate()) { int seconds = (int)(getExpiresIn() / 1000); if (seconds <= 0) { return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_disabled_disappearing_messages), R.drawable.ic_update_timer_disabled_16) - : fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_s_disabled_disappearing_messages, r.getDisplayName(context)), R.drawable.ic_update_timer_disabled_16); + : fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_disabled_disappearing_messages, r.getDisplayName(context)), R.drawable.ic_update_timer_disabled_16); } String time = ExpirationUtil.getExpirationDisplayValue(context, seconds); return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time), R.drawable.ic_update_timer_16) - : fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, r.getDisplayName(context), time), R.drawable.ic_update_timer_16); + : fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, r.getDisplayName(context), time), R.drawable.ic_update_timer_16); } else if (isIdentityUpdate()) { - return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), R.drawable.ic_update_safety_number_16); + return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), R.drawable.ic_update_safety_number_16); } else if (isIdentityVerified()) { - if (isOutgoing()) return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified, r.getDisplayName(context)), R.drawable.ic_update_verified_16); - else return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified_from_another_device, r.getDisplayName(context)), R.drawable.ic_update_verified_16); + if (isOutgoing()) return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified, r.getDisplayName(context)), R.drawable.ic_update_verified_16); + else return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified_from_another_device, r.getDisplayName(context)), R.drawable.ic_update_verified_16); } else if (isIdentityDefault()) { - if (isOutgoing()) return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified, r.getDisplayName(context)), R.drawable.ic_update_info_16); - else return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified_from_another_device, r.getDisplayName(context)), R.drawable.ic_update_info_16); + if (isOutgoing()) return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified, r.getDisplayName(context)), R.drawable.ic_update_info_16); + else return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified_from_another_device, r.getDisplayName(context)), R.drawable.ic_update_info_16); } else if (isProfileChange()) { return staticUpdateDescription(getProfileChangeDescription(context), R.drawable.ic_update_profile_16); } else if (isChangeNumber()) { - return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_s_changed_their_phone_number, r.getDisplayName(context)), R.drawable.ic_phone_16); + return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_changed_their_phone_number, r.getDisplayName(context)), R.drawable.ic_phone_16); } else if (isBoostRequest()) { return staticUpdateDescription(context.getString(R.string.MessageRecord_like_this_new_feature_help_support_signal_with_a_one_time_donation), 0); } else if (isEndSession()) { if (isOutgoing()) return staticUpdateDescription(context.getString(R.string.SmsMessageRecord_secure_session_reset), R.drawable.ic_update_info_16); - else return fromRecipient(getIndividualRecipient(), r-> context.getString(R.string.SmsMessageRecord_secure_session_reset_s, r.getDisplayName(context)), R.drawable.ic_update_info_16); + else return fromRecipient(getFromRecipient(), r-> context.getString(R.string.SmsMessageRecord_secure_session_reset_s, r.getDisplayName(context)), R.drawable.ic_update_info_16); } else if (isGroupV1MigrationEvent()) { return getGroupMigrationEventDescription(context); } else if (isChatSessionRefresh()) { return staticUpdateDescription(context.getString(R.string.MessageRecord_chat_session_refreshed), R.drawable.ic_refresh_16); } else if (isBadDecryptType()) { - return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_a_message_from_s_couldnt_be_delivered, r.getDisplayName(context)), R.drawable.ic_error_outline_14); + return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_a_message_from_s_couldnt_be_delivered, r.getDisplayName(context)), R.drawable.ic_error_outline_14); } else if (isThreadMergeEventType()) { try { ThreadMergeEvent event = ThreadMergeEvent.parseFrom(Base64.decodeOrThrow(getBody())); if (event.getPreviousE164().isEmpty()) { - return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_another_chat_has_been_merged, r.getDisplayName(context)), R.drawable.ic_thread_merge_16); + return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_another_chat_has_been_merged, r.getDisplayName(context)), R.drawable.ic_thread_merge_16); } else { - return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_their_number_s_has_been_merged, r.getDisplayName(context), PhoneNumberFormatter.prettyPrint(event.getPreviousE164())), R.drawable.ic_thread_merge_16); + return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_their_number_s_has_been_merged, r.getDisplayName(context), PhoneNumberFormatter.prettyPrint(event.getPreviousE164())), R.drawable.ic_thread_merge_16); } } catch (InvalidProtocolBufferException e) { throw new AssertionError(e); @@ -241,9 +238,9 @@ public abstract class MessageRecord extends DisplayRecord { SessionSwitchoverEvent event = SessionSwitchoverEvent.parseFrom(Base64.decodeOrThrow(getBody())); if (event.getE164().isEmpty()) { - return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), R.drawable.ic_update_safety_number_16); + return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), R.drawable.ic_update_safety_number_16); } else { - return fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_s_belongs_to_s, PhoneNumberFormatter.prettyPrint(r.requireE164()), r.getDisplayName(context)), R.drawable.ic_update_info_16); + return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_belongs_to_s, PhoneNumberFormatter.prettyPrint(r.requireE164()), r.getDisplayName(context)), R.drawable.ic_update_info_16); } } catch (InvalidProtocolBufferException e) { throw new AssertionError(e); @@ -251,13 +248,13 @@ public abstract class MessageRecord extends DisplayRecord { } else if (isSmsExportType()) { int messageResource = SignalStore.misc().getSmsExportPhase().isSmsSupported() ? R.string.MessageRecord__you_will_no_longer_be_able_to_send_sms_messages_from_signal_soon : R.string.MessageRecord__you_can_no_longer_send_sms_messages_in_signal; - return fromRecipient(getIndividualRecipient(), r -> context.getString(messageResource, r.getDisplayName(context)), R.drawable.ic_update_info_16); + return fromRecipient(getFromRecipient(), r -> context.getString(messageResource, r.getDisplayName(context)), R.drawable.ic_update_info_16); } else if (isPaymentsRequestToActivate()) { - return isOutgoing() ? fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_you_sent_request, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments) - : fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_wants_you_to_activate_payments, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments); + return isOutgoing() ? fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_sent_request, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments) + : fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_wants_you_to_activate_payments, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments); } else if (isPaymentsActivated()) { return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_activated_payments), R.drawable.ic_card_activate_payments) - : fromRecipient(getIndividualRecipient(), r -> context.getString(R.string.MessageRecord_can_accept_payments, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments); + : fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_can_accept_payments, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments); } return null; @@ -383,11 +380,11 @@ public abstract class MessageRecord extends DisplayRecord { ProfileChangeDetails profileChangeDetails = ProfileChangeDetails.parseFrom(decoded); if (profileChangeDetails.hasProfileNameChange()) { - String displayName = getIndividualRecipient().getDisplayName(context); + String displayName = getFromRecipient().getDisplayName(context); String newName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.getProfileNameChange().getNew()).toString()); String previousName = StringUtil.isolateBidi(ProfileName.fromSerialized(profileChangeDetails.getProfileNameChange().getPrevious()).toString()); - if (getIndividualRecipient().isSystemContact()) { + if (getFromRecipient().isSystemContact()) { return context.getString(R.string.MessageRecord_changed_their_profile_name_from_to, displayName, previousName, newName); } else { return context.getString(R.string.MessageRecord_changed_their_profile_name_to, previousName, newName); @@ -397,7 +394,7 @@ public abstract class MessageRecord extends DisplayRecord { Log.w(TAG, "Profile name change details could not be read", e); } - return context.getString(R.string.MessageRecord_changed_their_profile, getIndividualRecipient().getDisplayName(context)); + return context.getString(R.string.MessageRecord_changed_their_profile, getFromRecipient().getDisplayName(context)); } private UpdateDescription getGroupMigrationEventDescription(@NonNull Context context) { @@ -600,12 +597,8 @@ public abstract class MessageRecord extends DisplayRecord { return false; } - public Recipient getIndividualRecipient() { - return individualRecipient.live().get(); - } - - public int getRecipientDeviceId() { - return recipientDeviceId; + public int getFromDeviceId() { + return authorDeviceId; } public long getType() { @@ -625,7 +618,7 @@ public abstract class MessageRecord extends DisplayRecord { } public boolean hasFailedWithNetworkFailures() { - return isFailed() && ((getRecipient().isPushGroup() && hasNetworkFailures()) || !isIdentityMismatchFailure()); + return isFailed() && ((getToRecipient().isPushGroup() && hasNetworkFailures()) || !isIdentityMismatchFailure()); } public boolean isChatSessionRefresh() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java index c68b851721..921e31216c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MmsMessageRecord.java @@ -29,8 +29,7 @@ public abstract class MmsMessageRecord extends MessageRecord { private final boolean viewOnce; - MmsMessageRecord(long id, String body, Recipient conversationRecipient, - Recipient individualRecipient, int recipientDeviceId, long dateSent, + MmsMessageRecord(long id, String body, Recipient fromRecipient, int fromDeviceId, Recipient toRecipient, long dateSent, long dateReceived, long dateServer, long threadId, int deliveryStatus, int deliveryReceiptCount, long type, Set mismatches, Set networkFailures, int subscriptionId, long expiresIn, @@ -42,7 +41,7 @@ public abstract class MmsMessageRecord extends MessageRecord { int viewedReceiptCount, long receiptTimestamp, @NonNull StoryType storyType, @Nullable ParentStoryId parentStoryId, @Nullable GiftBadge giftBadge) { - super(id, body, conversationRecipient, individualRecipient, recipientDeviceId, + super(id, body, fromRecipient, fromDeviceId, toRecipient, dateSent, dateReceived, dateServer, threadId, deliveryStatus, deliveryReceiptCount, type, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, readReceiptCount, unidentified, reactions, remoteDelete, notifiedTimestamp, viewedReceiptCount, receiptTimestamp); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java index f30a7f1bb3..533e2d9bb6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/NotificationMmsMessageRecord.java @@ -48,8 +48,7 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord { private final int status; private final byte[] transactionId; - public NotificationMmsMessageRecord(long id, Recipient conversationRecipient, - Recipient individualRecipient, int recipientDeviceId, + public NotificationMmsMessageRecord(long id, Recipient fromRecipient, int fromDeviceId, Recipient toRecipient, long dateSent, long dateReceived, int deliveryReceiptCount, long threadId, byte[] contentLocation, long messageSize, long expiry, int status, byte[] transactionId, long mailbox, @@ -57,7 +56,7 @@ public class NotificationMmsMessageRecord extends MmsMessageRecord { int viewedReceiptCount, long receiptTimestamp, @NonNull StoryType storyType, @Nullable ParentStoryId parentStoryId, @Nullable GiftBadge giftBadge) { - super(id, "", conversationRecipient, individualRecipient, recipientDeviceId, + super(id, "", fromRecipient, fromDeviceId, toRecipient, dateSent, dateReceived, -1, threadId, Status.STATUS_NONE, deliveryReceiptCount, mailbox, new HashSet<>(), new HashSet<>(), subscriptionId, 0, 0, false, slideDeck, readReceiptCount, null, Collections.emptyList(), Collections.emptyList(), false, diff --git a/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportReader.kt b/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportReader.kt index 7887ebcaf3..b0b66176ee 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportReader.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/exporter/SignalSmsExportReader.kt @@ -115,7 +115,7 @@ class SignalSmsExportReader( } else if (threadRecipient != null) { setOf(threadRecipient.smsExportAddress()) } else { - setOf(record.individualRecipient.smsExportAddress()) + setOf(record.toRecipient.smsExportAddress()) } val parts: MutableList = mutableListOf() @@ -138,7 +138,7 @@ class SignalSmsExportReader( } } - val sender: String = if (record.isOutgoing) Recipient.self().smsExportAddress() else record.individualRecipient.smsExportAddress() + val sender: String = if (record.isOutgoing) Recipient.self().smsExportAddress() else record.fromRecipient.smsExportAddress() return ExportableMessage.Mms( id = MessageId(record.id), diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java index cbc2191227..e81014d011 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/GroupManagerV2.java @@ -1290,7 +1290,7 @@ final class GroupManagerV2 { long threadId = MessageSender.send(context, outgoingMessage, -1, MessageSender.SendType.SIGNAL, null, null); return new RecipientAndThread(groupRecipient, threadId); } else { - long threadId = SignalDatabase.threads().getOrCreateValidThreadId(outgoingMessage.getRecipient(), -1, outgoingMessage.getDistributionType()); + long threadId = SignalDatabase.threads().getOrCreateValidThreadId(outgoingMessage.getThreadRecipient(), -1, outgoingMessage.getDistributionType()); try { long messageId = SignalDatabase.messages().insertMessageOutbox(outgoingMessage, threadId, false, null); SignalDatabase.messages().markAsSent(messageId, true); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.java index c3319c3a41..5f2aca9237 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/IndividualSendJob.java @@ -12,7 +12,6 @@ import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; import org.thoughtcrime.securesms.database.MessageTable; -import org.thoughtcrime.securesms.database.MessageTable.SyncMessageId; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.PaymentTable; import org.thoughtcrime.securesms.database.RecipientTable.UnidentifiedAccessMode; @@ -151,11 +150,11 @@ public class IndividualSendJob extends PushSendJob { } try { - log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getRecipient().getId() + ", Thread: " + threadId + ", Attachments: " + buildAttachmentString(message.getAttachments())); + log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getThreadRecipient().getId() + ", Thread: " + threadId + ", Attachments: " + buildAttachmentString(message.getAttachments())); - RecipientUtil.shareProfileIfFirstSecureMessage(message.getRecipient()); + RecipientUtil.shareProfileIfFirstSecureMessage(message.getThreadRecipient()); - Recipient recipient = message.getRecipient().fresh(); + Recipient recipient = message.getThreadRecipient().fresh(); byte[] profileKey = recipient.getProfileKey(); UnidentifiedAccessMode accessMode = recipient.getUnidentifiedAccessMode(); @@ -166,10 +165,9 @@ public class IndividualSendJob extends PushSendJob { database.markUnidentified(messageId, unidentified); if (recipient.isSelf()) { - SyncMessageId id = new SyncMessageId(recipient.getId(), message.getSentTimeMillis()); - SignalDatabase.messages().incrementDeliveryReceiptCount(id, System.currentTimeMillis()); - SignalDatabase.messages().incrementReadReceiptCount(id, System.currentTimeMillis()); - SignalDatabase.messages().incrementViewedReceiptCount(id, System.currentTimeMillis()); + SignalDatabase.messages().incrementDeliveryReceiptCount(message.getSentTimeMillis(), recipient.getId(), System.currentTimeMillis()); + SignalDatabase.messages().incrementReadReceiptCount(message.getSentTimeMillis(), recipient.getId(), System.currentTimeMillis()); + SignalDatabase.messages().incrementViewedReceiptCount(message.getSentTimeMillis(), recipient.getId(), System.currentTimeMillis()); } if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN && profileKey == null) { @@ -219,14 +217,14 @@ public class IndividualSendJob extends PushSendJob { private boolean deliver(OutgoingMessage message) throws IOException, InsecureFallbackApprovalException, UntrustedIdentityException, UndeliverableMessageException { - if (message.getRecipient() == null) { + if (message.getThreadRecipient() == null) { throw new UndeliverableMessageException("No destination address."); } try { rotateSenderCertificateIfNecessary(); - Recipient messageRecipient = message.getRecipient().fresh(); + Recipient messageRecipient = message.getThreadRecipient().fresh(); if (messageRecipient.isUnregistered()) { throw new UndeliverableMessageException(messageRecipient.getId() + " not registered!"); @@ -262,7 +260,7 @@ public class IndividualSendJob extends PushSendJob { if (message.getParentStoryId() != null) { try { MessageRecord storyRecord = SignalDatabase.messages().getMessageRecord(message.getParentStoryId().asMessageId().getId()); - Recipient storyRecipient = storyRecord.isOutgoing() ? Recipient.self() : storyRecord.getRecipient(); + Recipient storyRecipient = storyRecord.getFromRecipient(); SignalServiceDataMessage.StoryContext storyContext = new SignalServiceDataMessage.StoryContext(storyRecipient.requireServiceId(), storyRecord.getDateSent()); mediaMessageBuilder.withStoryContext(storyContext); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/MmsSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/MmsSendJob.java index 92602e87cc..20c482f62f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/MmsSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/MmsSendJob.java @@ -240,8 +240,8 @@ public final class MmsSendJob extends SendJob { req.setFrom(new EncodedStringValue(SignalStore.account().getE164())); } - if (message.getRecipient().isMmsGroup()) { - List members = SignalDatabase.groups().getGroupMembers(message.getRecipient().requireGroupId(), GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF); + if (message.getThreadRecipient().isMmsGroup()) { + List members = SignalDatabase.groups().getGroupMembers(message.getThreadRecipient().requireGroupId(), GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF); for (Recipient member : members) { if (!member.hasSmsAddress()) { @@ -255,11 +255,11 @@ public final class MmsSendJob extends SendJob { } } } else { - if (!message.getRecipient().hasSmsAddress()) { - throw new UndeliverableMessageException("Recipient did not have an SMS address! " + message.getRecipient().getId()); + if (!message.getThreadRecipient().hasSmsAddress()) { + throw new UndeliverableMessageException("Recipient did not have an SMS address! " + message.getThreadRecipient().getId()); } - req.addTo(new EncodedStringValue(message.getRecipient().requireSmsAddress())); + req.addTo(new EncodedStringValue(message.getThreadRecipient().requireSmsAddress())); } req.setDate(System.currentTimeMillis() / 1000); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java index f589157ea2..6bbcf29006 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java @@ -154,14 +154,14 @@ public final class PushDistributionListSendJob extends PushSendJob { return; } - Recipient listRecipient = message.getRecipient().resolve(); + Recipient listRecipient = message.getThreadRecipient().resolve(); if (!listRecipient.isDistributionList()) { throw new MmsException("Message recipient isn't a distribution list!"); } try { - log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getRecipient().getId() + ", Attachments: " + buildAttachmentString(message.getAttachments())); + log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getThreadRecipient().getId() + ", Attachments: " + buildAttachmentString(message.getAttachments())); List targets; List skipped = Collections.emptyList(); @@ -221,7 +221,7 @@ public final class PushDistributionListSendJob extends PushSendJob { Log.d(TAG, "[" + messageId + "] Sending a story message with a manifest of size " + manifestCollection.size()); - return GroupSendUtil.sendStoryMessage(context, message.getRecipient().requireDistributionListId(), destinations, isRecipientUpdate, new MessageId(messageId), message.getSentTimeMillis(), storyMessage, manifestCollection); + return GroupSendUtil.sendStoryMessage(context, message.getThreadRecipient().requireDistributionListId(), destinations, isRecipientUpdate, new MessageId(messageId), message.getSentTimeMillis(), storyMessage, manifestCollection); } catch (ServerRejectedException e) { throw new UndeliverableMessageException(e); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index 285f30c78a..edf17acd4d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -190,7 +190,7 @@ public final class PushGroupSendJob extends PushSendJob { return; } - Recipient groupRecipient = message.getRecipient().resolve(); + Recipient groupRecipient = message.getThreadRecipient().resolve(); if (!groupRecipient.isPushGroup()) { throw new MmsException("Message recipient isn't a group!"); @@ -205,7 +205,7 @@ public final class PushGroupSendJob extends PushSendJob { } try { - log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getRecipient().getId() + ", Thread: " + threadId + ", Attachments: " + buildAttachmentString(message.getAttachments())); + log(TAG, String.valueOf(message.getSentTimeMillis()), "Sending message: " + messageId + ", Recipient: " + message.getThreadRecipient().getId() + ", Thread: " + threadId + ", Attachments: " + buildAttachmentString(message.getAttachments())); if (!groupRecipient.resolve().isProfileSharing() && !database.isGroupQuitMessage(messageId)) { RecipientUtil.shareProfileIfFirstSecureMessage(groupRecipient); @@ -348,13 +348,13 @@ public final class PushGroupSendJob extends PushSendJob { if (message.getParentStoryId() != null) { try { MessageRecord storyRecord = SignalDatabase.messages().getMessageRecord(message.getParentStoryId().asMessageId().getId()); - Recipient recipient = storyRecord.isOutgoing() ? Recipient.self() : storyRecord.getIndividualRecipient(); + Recipient storyAuthor = storyRecord.getFromRecipient(); destinations = destinations.stream() .filter(r -> r.getStoriesCapability() == Recipient.Capability.SUPPORTED) .collect(java.util.stream.Collectors.toList()); - SignalServiceDataMessage.StoryContext storyContext = new SignalServiceDataMessage.StoryContext(recipient.requireServiceId(), storyRecord.getDateSent()); + SignalServiceDataMessage.StoryContext storyContext = new SignalServiceDataMessage.StoryContext(storyAuthor.requireServiceId(), storyRecord.getDateSent()); groupMessageBuilder.withStoryContext(storyContext); Optional reaction = getStoryReactionFor(message, storyContext); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java index 4436121495..474e7eb9df 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ReactionSendJob.java @@ -139,7 +139,7 @@ public class ReactionSendJob extends BaseJob { ReactionTable reactionTable = SignalDatabase.reactions(); MessageRecord message = SignalDatabase.messages().getMessageRecord(messageId.getId()); - Recipient targetAuthor = message.isOutgoing() ? Recipient.self() : message.getIndividualRecipient(); + Recipient targetAuthor = message.getFromRecipient(); long targetSentTimestamp = message.getDateSent(); if (targetAuthor.getId().equals(SignalStore.releaseChannelValues().getReleaseChannelRecipientId())) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java index b649cf6dbb..6f81b7e10b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java @@ -151,7 +151,7 @@ public class RemoteDeleteSendJob extends BaseJob { List skipped = Stream.of(SetUtil.difference(possible, eligible)).map(Recipient::getId).toList(); boolean isForStory = message.isMms() && (((MmsMessageRecord) message).getStoryType().isStory() || ((MmsMessageRecord) message).getParentStoryId() != null); - DistributionListId distributionListId = isForStory ? message.getRecipient().getDistributionListId().orElse(null) : null; + DistributionListId distributionListId = isForStory ? message.getToRecipient().getDistributionListId().orElse(null) : null; GroupSendJobHelper.SendResult sendResult = deliver(conversationRecipient, eligible, targetSentTimestamp, isForStory, distributionListId); @@ -167,7 +167,7 @@ public class RemoteDeleteSendJob extends BaseJob { Log.i(TAG, "Completed now: " + sendResult.completed.size() + ", Skipped: " + totalSkips.size() + ", Remaining: " + recipients.size()); - if (totalSkips.size() > 0 && message.getRecipient().isGroup()) { + if (totalSkips.size() > 0 && message.getToRecipient().isGroup()) { SignalDatabase.groupReceipts().setSkipped(totalSkips, messageId); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java index da37ebf933..ac5dc2c73a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsReceiveJob.java @@ -118,7 +118,7 @@ public class SmsReceiveJob extends BaseJob { } } - if (message.isPresent() && SignalStore.account().getE164() != null && message.get().getSender().equals(Recipient.self().getId())) { + if (message.isPresent() && SignalStore.account().getE164() != null && message.get().getAuthorId().equals(Recipient.self().getId())) { Log.w(TAG, "Received an SMS from ourselves! Ignoring."); } else if (message.isPresent() && !isBlocked(message.get())) { Optional insertResult = storeMessage(message.get()); @@ -145,8 +145,8 @@ public class SmsReceiveJob extends BaseJob { } private boolean isBlocked(IncomingTextMessage message) { - if (message.getSender() != null) { - Recipient recipient = Recipient.resolved(message.getSender()); + if (message.getAuthorId() != null) { + Recipient recipient = Recipient.resolved(message.getAuthorId()); return recipient.isBlocked(); } @@ -193,7 +193,7 @@ public class SmsReceiveJob extends BaseJob { } private static Notification buildPreRegistrationNotification(@NonNull Context context, @NonNull IncomingTextMessage message) { - Recipient sender = Recipient.resolved(message.getSender()); + Recipient sender = Recipient.resolved(message.getAuthorId()); return new NotificationCompat.Builder(context, NotificationChannels.getInstance().getMessagesChannel()) .setStyle(new NotificationCompat.MessagingStyle(new Person.Builder() diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsSendJob.java index a1b261b485..d032d33694 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsSendJob.java @@ -89,8 +89,8 @@ public class SmsSendJob extends SendJob { return; } - if (!record.getRecipient().hasSmsAddress()) { - throw new UndeliverableMessageException("Recipient didn't have an SMS address! " + record.getRecipient().getId()); + if (!record.getToRecipient().hasSmsAddress()) { + throw new UndeliverableMessageException("Recipient didn't have an SMS address! " + record.getToRecipient().getId()); } try { @@ -100,7 +100,7 @@ public class SmsSendJob extends SendJob { } catch (UndeliverableMessageException ude) { warn(TAG, ude); SignalDatabase.messages().markAsSentFailed(record.getId()); - ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, record.getRecipient(), ConversationId.fromMessageRecord(record)); + ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, record.getToRecipient(), ConversationId.fromMessageRecord(record)); } } @@ -131,7 +131,7 @@ public class SmsSendJob extends SendJob { throw new UndeliverableMessageException("Trying to send a secure SMS?"); } - String recipient = message.getIndividualRecipient().requireSmsAddress(); + String recipient = message.getToRecipient().requireSmsAddress(); // See issue #1516 for bug report, and discussion on commits related to #4833 for problems // related to the original fix to #1516. This still may not be a correct fix if networks allow diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsSentJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsSentJob.java index 10ad0b0609..c620eea74a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsSentJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/SmsSentJob.java @@ -110,15 +110,15 @@ public class SmsSentJob extends BaseJob { if (isMultipart) { Log.w(TAG, "Service connectivity problem, but not retrying due to multipart"); database.markAsSentFailed(messageId); - ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, record.getRecipient(), ConversationId.forConversation(record.getThreadId())); + ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, record.getToRecipient(), ConversationId.forConversation(record.getThreadId())); } else { Log.w(TAG, "Service connectivity problem, requeuing..."); - ApplicationDependencies.getJobManager().add(new SmsSendJob(messageId, record.getIndividualRecipient(), runAttempt + 1)); + ApplicationDependencies.getJobManager().add(new SmsSendJob(messageId, record.getToRecipient(), runAttempt + 1)); } break; default: database.markAsSentFailed(messageId); - ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, record.getRecipient(), ConversationId.forConversation(record.getThreadId())); + ApplicationDependencies.getMessageNotifier().notifyMessageDeliveryFailed(context, record.getToRecipient(), ConversationId.forConversation(record.getThreadId())); } } catch (NoSuchMessageException e) { Log.w(TAG, e); diff --git a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageFragment.java b/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageFragment.java index f693270423..80186ad006 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageFragment.java @@ -102,7 +102,7 @@ public class LongMessageFragment extends FullScreenDialogFragment { if (message.get().getMessageRecord().isOutgoing()) { toolbar.setTitle(getString(R.string.LongMessageActivity_your_message)); } else { - Recipient recipient = message.get().getMessageRecord().getRecipient(); + Recipient recipient = message.get().getMessageRecord().getFromRecipient(); String name = recipient.getDisplayName(requireContext()); toolbar.setTitle(getString(R.string.LongMessageActivity_message_from_s, name)); @@ -113,8 +113,8 @@ public class LongMessageFragment extends FullScreenDialogFragment { if (message.get().getMessageRecord().isOutgoing()) { bubble = sentBubble.get(); colorizerView.setVisibility(View.VISIBLE); - colorizerView.setBackground(message.get().getMessageRecord().getRecipient().getChatColors().getChatBubbleMask()); - bubble.getBackground().setColorFilter(message.get().getMessageRecord().getRecipient().getChatColors().getChatBubbleColorFilter()); + colorizerView.setBackground(message.get().getMessageRecord().getToRecipient().getChatColors().getChatBubbleMask()); + bubble.getBackground().setColorFilter(message.get().getMessageRecord().getToRecipient().getChatColors().getChatBubbleColorFilter()); bubble.addOnLayoutChangeListener(bubbleLayoutListener); bubbleLayoutListener.onLayoutChange(bubble, 0, 0, 0, 0, 0, 0, 0, 0); } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt index b913c11c95..4fde5ae4d0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt @@ -324,7 +324,7 @@ class MediaSelectionRepository(context: Context) { val thread = SignalDatabase.threads.getOrCreateThreadIdFor(recipient) val outgoingMessage = OutgoingMessage( - recipient = recipient, + threadRecipient = recipient, body = splitBody, attachments = slideDeck.asAttachments(), sentTimeMillis = System.currentTimeMillis(), @@ -370,7 +370,7 @@ class MediaSelectionRepository(context: Context) { } val message = OutgoingMessage( - recipient = recipient, + threadRecipient = recipient, body = body, sentTimeMillis = if (recipient.isDistributionList) distributionListPreUploadSentTimestamps.getOrPut(preUploadResults.first()) { System.currentTimeMillis() } else System.currentTimeMillis(), expiresIn = if (isStory) 0 else TimeUnit.SECONDS.toMillis(recipient.expiresInSeconds.toLong()), @@ -401,7 +401,7 @@ class MediaSelectionRepository(context: Context) { storyClips.forEach { storyClipMessages.add( OutgoingMessage( - recipient = recipient, + threadRecipient = recipient, body = body, attachments = listOf(MediaUploadRepository.asAttachment(context, it)), sentTimeMillis = if (recipient.isDistributionList) distributionListStoryClipsSentTimestamps.getOrPut(it.asKey()) { System.currentTimeMillis() } else System.currentTimeMillis(), diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetails.java b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetails.java index 03d141fac2..cc1299c3ab 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetails.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetails.java @@ -38,7 +38,7 @@ public final class MessageDetails { viewed = new TreeSet<>(RECIPIENT_COMPARATOR); skipped = new TreeSet<>(RECIPIENT_COMPARATOR); - if (conversationMessage.getMessageRecord().getRecipient().isSelf()) { + if (conversationMessage.getMessageRecord().getToRecipient().isSelf()) { read.addAll(recipients); } else if (conversationMessage.getMessageRecord().isOutgoing()) { for (RecipientDeliveryStatus status : recipients) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsRepository.java b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsRepository.java index 0687d9f2e1..5dcf4dce0c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageDetailsRepository.java @@ -76,19 +76,19 @@ public final class MessageDetailsRepository { private @NonNull MessageDetails getRecipientDeliveryStatusesInternal(@NonNull MessageRecord messageRecord) { List recipients = new LinkedList<>(); - if (!messageRecord.getRecipient().isGroup() && !messageRecord.getRecipient().isDistributionList()) { + if (!messageRecord.getToRecipient().isGroup() && !messageRecord.getToRecipient().isDistributionList()) { recipients.add(new RecipientDeliveryStatus(messageRecord, - messageRecord.getRecipient(), + messageRecord.getToRecipient(), getStatusFor(messageRecord), messageRecord.isUnidentified(), messageRecord.getReceiptTimestamp(), - getNetworkFailure(messageRecord, messageRecord.getRecipient()), - getKeyMismatchFailure(messageRecord, messageRecord.getRecipient()))); + getNetworkFailure(messageRecord, messageRecord.getToRecipient()), + getKeyMismatchFailure(messageRecord, messageRecord.getToRecipient()))); } else { List receiptInfoList = SignalDatabase.groupReceipts().getGroupReceiptInfo(messageRecord.getId()); - if (receiptInfoList.isEmpty() && messageRecord.getRecipient().isGroup()) { - List group = SignalDatabase.groups().getGroupMembers(messageRecord.getRecipient().requireGroupId(), GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF); + if (receiptInfoList.isEmpty() && messageRecord.getToRecipient().isGroup()) { + List group = SignalDatabase.groups().getGroupMembers(messageRecord.getToRecipient().requireGroupId(), GroupTable.MemberSet.FULL_MEMBERS_EXCLUDING_SELF); for (Recipient recipient : group) { recipients.add(new RecipientDeliveryStatus(messageRecord, @@ -99,8 +99,8 @@ public final class MessageDetailsRepository { getNetworkFailure(messageRecord, recipient), getKeyMismatchFailure(messageRecord, recipient))); } - } else if (receiptInfoList.isEmpty() && messageRecord.getRecipient().isDistributionList()) { - DistributionId distributionId = SignalDatabase.distributionLists().getDistributionId(messageRecord.getRecipient().requireDistributionListId()); + } else if (receiptInfoList.isEmpty() && messageRecord.getToRecipient().isDistributionList()) { + DistributionId distributionId = SignalDatabase.distributionLists().getDistributionId(messageRecord.getToRecipient().requireDistributionListId()); Set recipientIds = SignalDatabase.storySends().getRecipientsForDistributionId(messageRecord.getId(), Objects.requireNonNull(distributionId)); List resolved = Recipient.resolvedList(recipientIds); diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageHeaderViewHolder.java b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageHeaderViewHolder.java index b3ebd8f0fa..6f1b37b25f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageHeaderViewHolder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageHeaderViewHolder.java @@ -104,7 +104,7 @@ final class MessageHeaderViewHolder extends RecyclerView.ViewHolder implements G glideRequests, Locale.getDefault(), new HashSet<>(), - conversationMessage.getMessageRecord().getRecipient(), + conversationMessage.getMessageRecord().getToRecipient(), null, false, false, diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/RecipientViewHolder.java b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/RecipientViewHolder.java index 1279e11e29..347a09f52b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/RecipientViewHolder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/RecipientViewHolder.java @@ -51,7 +51,7 @@ final class RecipientViewHolder extends RecyclerView.ViewHolder { conflictButton.setVisibility(View.VISIBLE); error.setText(itemView.getContext().getString(R.string.message_details_recipient__new_safety_number)); conflictButton.setOnClickListener(unused -> callbacks.onErrorClicked(data.getMessageRecord())); - } else if ((data.getNetworkFailure() != null && !data.getMessageRecord().isPending()) || (!data.getMessageRecord().getRecipient().isPushGroup() && data.getMessageRecord().isFailed())) { + } else if ((data.getNetworkFailure() != null && !data.getMessageRecord().isPending()) || (!data.getMessageRecord().getToRecipient().isPushGroup() && data.getMessageRecord().isFailed())) { timestamp.setVisibility(View.GONE); error.setVisibility(View.VISIBLE); conflictButton.setVisibility(View.GONE); diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt index 8bac0e4b69..626fb46bf3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/DataMessageProcessor.kt @@ -520,7 +520,7 @@ object DataMessageProcessor { null } else { - warn(envelope.timestamp, "[handleRemoteDelete] Invalid remote delete! deleteTime: ${envelope.serverTimestamp}, targetTime: ${targetMessage.serverTimestamp}, deleteAuthor: $senderRecipientId, targetAuthor: ${targetMessage.recipient.id}") + warn(envelope.timestamp, "[handleRemoteDelete] Invalid remote delete! deleteTime: ${envelope.serverTimestamp}, targetTime: ${targetMessage.serverTimestamp}, deleteAuthor: $senderRecipientId, targetAuthor: ${targetMessage.fromRecipient.id}") null } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt index 4a3c9e6ab4..d81a41ac8c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/IncomingMessageObserver.kt @@ -18,7 +18,6 @@ import org.signal.core.util.logging.Log import org.signal.core.util.withinTransaction import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.crypto.ReentrantSessionLock -import org.thoughtcrime.securesms.database.MessageTable import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.jobmanager.Job @@ -318,7 +317,7 @@ class IncomingMessageObserver(private val context: Application) { val senderId = RecipientId.from(ServiceId.parseOrThrow(envelope.sourceUuid)) Log.i(TAG, "Received server receipt. Sender: $senderId, Device: ${envelope.sourceDevice}, Timestamp: ${envelope.timestamp}") - SignalDatabase.messages.incrementDeliveryReceiptCount(MessageTable.SyncMessageId(senderId, envelope.timestamp), System.currentTimeMillis()) + SignalDatabase.messages.incrementDeliveryReceiptCount(envelope.timestamp, senderId, System.currentTimeMillis()) SignalDatabase.messageLog.deleteEntryForRecipient(envelope.timestamp, senderId, envelope.sourceDevice) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java index a5cb62f34e..d9cf9589f5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java @@ -1081,7 +1081,7 @@ public class MessageContentProcessor { return null; } else { warn(String.valueOf(content.getTimestamp()), String.format(Locale.ENGLISH, "[handleRemoteDelete] Invalid remote delete! deleteTime: %d, targetTime: %d, deleteAuthor: %s, targetAuthor: %s", - content.getServerReceivedTimestamp(), targetMessage.getServerTimestamp(), senderRecipient.getId(), targetMessage.getRecipient().getId())); + content.getServerReceivedTimestamp(), targetMessage.getServerTimestamp(), senderRecipient.getId(), targetMessage.getFromRecipient().getId())); return null; } } @@ -2251,9 +2251,8 @@ public class MessageContentProcessor { } if (recipient.isSelf()) { - SyncMessageId id = new SyncMessageId(recipient.getId(), message.getTimestamp()); - SignalDatabase.messages().incrementDeliveryReceiptCount(id, System.currentTimeMillis()); - SignalDatabase.messages().incrementReadReceiptCount(id, System.currentTimeMillis()); + SignalDatabase.messages().incrementDeliveryReceiptCount(message.getTimestamp(), recipient.getId(), System.currentTimeMillis()); + SignalDatabase.messages().incrementReadReceiptCount(message.getTimestamp(), recipient.getId(), System.currentTimeMillis()); } database.setTransactionSuccessful(); @@ -2370,9 +2369,8 @@ public class MessageContentProcessor { attachments = Stream.of(allAttachments).filterNot(Attachment::isSticker).toList(); if (recipient.isSelf()) { - SyncMessageId id = new SyncMessageId(recipient.getId(), message.getTimestamp()); - SignalDatabase.messages().incrementDeliveryReceiptCount(id, System.currentTimeMillis()); - SignalDatabase.messages().incrementReadReceiptCount(id, System.currentTimeMillis()); + SignalDatabase.messages().incrementDeliveryReceiptCount(message.getTimestamp(), recipient.getId(), System.currentTimeMillis()); + SignalDatabase.messages().incrementReadReceiptCount(message.getTimestamp(), recipient.getId(), System.currentTimeMillis()); } messageTable.setTransactionSuccessful(); @@ -2407,7 +2405,7 @@ public class MessageContentProcessor { log(envelopeTimestamp, "Synchronize sent media message for " + message.getTimestamp()); MessageTable database = SignalDatabase.messages(); - Recipient recipients = getSyncMessageDestination(message); + Recipient recipient = getSyncMessageDestination(message); Optional quote = getValidatedQuote(message.getDataMessage().get().getQuote()); Optional sticker = getStickerAttachment(message.getDataMessage().get().getSticker()); Optional> sharedContacts = getContacts(message.getDataMessage().get().getSharedContacts()); @@ -2423,7 +2421,7 @@ public class MessageContentProcessor { syncAttachments.add(sticker.get()); } - OutgoingMessage mediaMessage = new OutgoingMessage(recipients, + OutgoingMessage mediaMessage = new OutgoingMessage(recipient, message.getDataMessage().get().getBody().orElse(null), syncAttachments, message.getTimestamp(), @@ -2445,11 +2443,11 @@ public class MessageContentProcessor { bodyRanges, -1); - if (recipients.getExpiresInSeconds() != message.getDataMessage().get().getExpiresInSeconds()) { + if (recipient.getExpiresInSeconds() != message.getDataMessage().get().getExpiresInSeconds()) { handleSynchronizeSentExpirationUpdate(message); } - long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipients); + long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient); long messageId; List attachments; @@ -2459,10 +2457,10 @@ public class MessageContentProcessor { try { messageId = database.insertMessageOutbox(mediaMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null); - if (recipients.isGroup()) { - updateGroupReceiptStatus(message, messageId, recipients.requireGroupId()); + if (recipient.isGroup()) { + updateGroupReceiptStatus(message, messageId, recipient.requireGroupId()); } else { - database.markUnidentified(messageId, isUnidentified(message, recipients)); + database.markUnidentified(messageId, isUnidentified(message, recipient)); } database.markAsSent(messageId, true); @@ -2481,10 +2479,10 @@ public class MessageContentProcessor { TimeUnit.SECONDS.toMillis(message.getDataMessage().get().getExpiresInSeconds())); } - if (recipients.isSelf()) { - SyncMessageId id = new SyncMessageId(recipients.getId(), message.getTimestamp()); - SignalDatabase.messages().incrementDeliveryReceiptCount(id, System.currentTimeMillis()); - SignalDatabase.messages().incrementReadReceiptCount(id, System.currentTimeMillis()); + if (recipient.isSelf()) { + SyncMessageId id = new SyncMessageId(recipient.getId(), message.getTimestamp()); + SignalDatabase.messages().incrementDeliveryReceiptCount(message.getTimestamp(), recipient.getId(), System.currentTimeMillis()); + SignalDatabase.messages().incrementReadReceiptCount(message.getTimestamp(), recipient.getId(), System.currentTimeMillis()); } database.setTransactionSuccessful(); @@ -2672,9 +2670,8 @@ public class MessageContentProcessor { } if (recipient.isSelf()) { - SyncMessageId id = new SyncMessageId(recipient.getId(), message.getTimestamp()); - SignalDatabase.messages().incrementDeliveryReceiptCount(id, System.currentTimeMillis()); - SignalDatabase.messages().incrementReadReceiptCount(id, System.currentTimeMillis()); + SignalDatabase.messages().incrementDeliveryReceiptCount(message.getTimestamp(), recipient.getId(), System.currentTimeMillis()); + SignalDatabase.messages().incrementReadReceiptCount(message.getTimestamp(), recipient.getId(), System.currentTimeMillis()); } return threadId; @@ -2825,20 +2822,16 @@ public class MessageContentProcessor { log(TAG, "Processing viewed receipts. Sender: " + senderRecipient.getId() + ", Device: " + content.getSenderDevice() + ", Only Stories: " + (!readReceipts && storyViewedReceipts) + ", Timestamps: " + Util.join(message.getTimestamps(), ", ")); - List ids = Stream.of(message.getTimestamps()) - .map(t -> new SyncMessageId(senderRecipient.getId(), t)) - .toList(); - - final Collection unhandled; + final Set unhandled; if (readReceipts && storyViewedReceipts) { - unhandled = SignalDatabase.messages().incrementViewedReceiptCounts(ids, content.getTimestamp()); + unhandled = SignalDatabase.messages().incrementViewedReceiptCounts(message.getTimestamps(), senderRecipient.getId(), content.getTimestamp()); } else if (readReceipts) { - unhandled = SignalDatabase.messages().incrementViewedNonStoryReceiptCounts(ids, content.getTimestamp()); + unhandled = SignalDatabase.messages().incrementViewedNonStoryReceiptCounts(message.getTimestamps(), senderRecipient.getId(), content.getTimestamp()); } else { - unhandled = SignalDatabase.messages().incrementViewedStoryReceiptCounts(ids, content.getTimestamp()); + unhandled = SignalDatabase.messages().incrementViewedStoryReceiptCounts(message.getTimestamps(), senderRecipient.getId(), content.getTimestamp()); } - Set handled = new HashSet<>(ids); + Set handled = new HashSet<>(unhandled); handled.removeAll(unhandled); SignalDatabase.messages().updateViewedStories(handled); @@ -2846,10 +2839,10 @@ public class MessageContentProcessor { if (unhandled.size() > 0) { RecipientId selfId = Recipient.self().getId(); - for (SyncMessageId id : unhandled) { - warn(String.valueOf(content.getTimestamp()), "[handleViewedReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + ", author: " + id.getRecipientId() + " | Receipt so associating with message from self (" + selfId + ")"); + for (long timestamp : unhandled) { + warn(String.valueOf(content.getTimestamp()), "[handleViewedReceipt] Could not find matching message! timestamp: " + timestamp + ", author: " + senderRecipient.getId() + " | Receipt so associating with message from self (" + selfId + ")"); if (!processingEarlyContent) { - ApplicationDependencies.getEarlyMessageCache().store(selfId, id.getTimetamp(), content); + ApplicationDependencies.getEarlyMessageCache().store(selfId, timestamp, content); } } } @@ -2866,14 +2859,10 @@ public class MessageContentProcessor { { log(content.getTimestamp(), "Processing delivery receipts. Sender: " + senderRecipient.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", ")); - List ids = Stream.of(message.getTimestamps()) - .map(t -> new SyncMessageId(senderRecipient.getId(), t)) - .toList(); + Set unhandled = SignalDatabase.messages().incrementDeliveryReceiptCounts(message.getTimestamps(), senderRecipient.getId(), content.getTimestamp()); - Collection unhandled = SignalDatabase.messages().incrementDeliveryReceiptCounts(ids, content.getTimestamp()); - - for (SyncMessageId id : unhandled) { - warn(String.valueOf(content.getTimestamp()), "[handleDeliveryReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + " author: " + id.getRecipientId()); + for (long timestamp : unhandled) { + warn(String.valueOf(content.getTimestamp()), "[handleDeliveryReceipt] Could not find matching message! timestamp: " + timestamp + " author: " + senderRecipient.getId()); // Early delivery receipts are special-cased in the database methods } @@ -2898,19 +2887,15 @@ public class MessageContentProcessor { log(TAG, "Processing read receipts. Sender: " + senderRecipient.getId() + ", Device: " + content.getSenderDevice() + ", Timestamps: " + Util.join(message.getTimestamps(), ", ")); - List ids = Stream.of(message.getTimestamps()) - .map(t -> new SyncMessageId(senderRecipient.getId(), t)) - .toList(); - - Collection unhandled = SignalDatabase.messages().incrementReadReceiptCounts(ids, content.getTimestamp()); + Set unhandled = SignalDatabase.messages().incrementReadReceiptCounts(message.getTimestamps(), senderRecipient.getId(), content.getTimestamp()); if (unhandled.size() > 0) { RecipientId selfId = Recipient.self().getId(); - for (SyncMessageId id : unhandled) { - warn(String.valueOf(content.getTimestamp()), "[handleReadReceipt] Could not find matching message! timestamp: " + id.getTimetamp() + ", author: " + id.getRecipientId() + " | Receipt, so associating with message from self (" + selfId + ")"); + for (long timestamp : unhandled) { + warn(String.valueOf(content.getTimestamp()), "[handleReadReceipt] Could not find matching message! timestamp: " + timestamp + ", author: " + senderRecipient.getId() + " | Receipt, so associating with message from self (" + selfId + ")"); if (!processingEarlyContent) { - ApplicationDependencies.getEarlyMessageCache().store(selfId, id.getTimetamp(), content); + ApplicationDependencies.getEarlyMessageCache().store(selfId, timestamp, content); } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt index 1f938616ad..42a1bff159 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageDecryptor.kt @@ -127,7 +127,7 @@ object MessageDecryptor { return Result.Ignore(envelope, serverDeliveredTimestamp, followUpOperations.toUnmodifiableList()) } - Log.d(TAG, "${logPrefix(envelope, cipherResult)} Successfully decrypted the envelope.") + Log.d(TAG, "${logPrefix(envelope, cipherResult)} Successfully decrypted the envelope (GUID ${envelope.serverGuid}).") val validationResult: EnvelopeContentValidator.Result = EnvelopeContentValidator.validate(envelope, cipherResult.content) diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt index c6cad12dbc..2f90034796 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/ReceiptMessageProcessor.kt @@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.messages import android.annotation.SuppressLint import android.content.Context -import org.thoughtcrime.securesms.database.MessageTable.SyncMessageId import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.jobs.PushProcessEarlyMessagesJob @@ -39,15 +38,14 @@ object ReceiptMessageProcessor { ) { log(envelope.timestamp, "Processing delivery receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Timestamps: ${deliveryReceipt.timestampList.joinToString(", ")}") - val ids = deliveryReceipt.timestampList.map { SyncMessageId(senderRecipientId, it) } - val unhandled = SignalDatabase.messages.incrementDeliveryReceiptCounts(ids, envelope.timestamp) + val missingTargetTimestamps: Set = SignalDatabase.messages.incrementDeliveryReceiptCounts(deliveryReceipt.timestampList, senderRecipientId, envelope.timestamp) - for (id in unhandled) { - warn(envelope.timestamp, "[handleDeliveryReceipt] Could not find matching message! timestamp: ${id.timetamp} author: ${id.recipientId}") + for (targetTimestamp in missingTargetTimestamps) { + warn(envelope.timestamp, "[handleDeliveryReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId") // Early delivery receipts are special-cased in the database methods } - if (unhandled.isNotEmpty()) { + if (missingTargetTimestamps.isNotEmpty()) { PushProcessEarlyMessagesJob.enqueue() } @@ -71,21 +69,20 @@ object ReceiptMessageProcessor { log(envelope.timestamp, "Processing read receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Timestamps: ${readReceipt.timestampList.joinToString(", ")}") - val ids = readReceipt.timestampList.map { SyncMessageId(senderRecipientId, it) } - val unhandled = SignalDatabase.messages.incrementReadReceiptCounts(ids, envelope.timestamp) + val missingTargetTimestamps: Set = SignalDatabase.messages.incrementReadReceiptCounts(readReceipt.timestampList, senderRecipientId, envelope.timestamp) - if (unhandled.isNotEmpty()) { + if (missingTargetTimestamps.isNotEmpty()) { val selfId = Recipient.self().id - for (id in unhandled) { - warn(envelope.timestamp, "[handleReadReceipt] Could not find matching message! timestamp: ${id.timetamp}, author: ${id.recipientId} | Receipt, so associating with message from self ($selfId)") + for (targetTimestamp in missingTargetTimestamps) { + warn(envelope.timestamp, "[handleReadReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId | Receipt, so associating with message from self ($selfId)") if (earlyMessageCacheEntry != null) { - ApplicationDependencies.getEarlyMessageCache().store(selfId, id.timetamp, earlyMessageCacheEntry) + ApplicationDependencies.getEarlyMessageCache().store(selfId, targetTimestamp, earlyMessageCacheEntry) } } } - if (unhandled.isNotEmpty() && earlyMessageCacheEntry != null) { + if (missingTargetTimestamps.isNotEmpty() && earlyMessageCacheEntry != null) { PushProcessEarlyMessagesJob.enqueue() } } @@ -108,30 +105,29 @@ object ReceiptMessageProcessor { log(envelope.timestamp, "Processing viewed receipts. Sender: $senderRecipientId, Device: ${metadata.sourceDeviceId}, Only Stories: ${!readReceipts}, Timestamps: ${viewedReceipt.timestampList.joinToString(", ")}") - val ids = viewedReceipt.timestampList.map { SyncMessageId(senderRecipientId, it) } - - val unhandled: Collection = if (readReceipts && storyViewedReceipts) { - SignalDatabase.messages.incrementViewedReceiptCounts(ids, envelope.timestamp) + val missingTargetTimestamps: Set = if (readReceipts && storyViewedReceipts) { + SignalDatabase.messages.incrementViewedReceiptCounts(viewedReceipt.timestampList, senderRecipientId, envelope.timestamp) } else if (readReceipts) { - SignalDatabase.messages.incrementViewedNonStoryReceiptCounts(ids, envelope.timestamp) + SignalDatabase.messages.incrementViewedNonStoryReceiptCounts(viewedReceipt.timestampList, senderRecipientId, envelope.timestamp) } else { - SignalDatabase.messages.incrementViewedStoryReceiptCounts(ids, envelope.timestamp) + SignalDatabase.messages.incrementViewedStoryReceiptCounts(viewedReceipt.timestampList, senderRecipientId, envelope.timestamp) } - val handled: Set = ids.toSet() - unhandled.toSet() - SignalDatabase.messages.updateViewedStories(handled) + val foundTargetTimestamps: Set = viewedReceipt.timestampList.toSet() - missingTargetTimestamps.toSet() + SignalDatabase.messages.updateViewedStories(foundTargetTimestamps) - if (unhandled.isNotEmpty()) { + if (missingTargetTimestamps.isNotEmpty()) { val selfId = Recipient.self().id - for (id in unhandled) { - warn(envelope.timestamp, "[handleViewedReceipt] Could not find matching message! timestamp: ${id.timetamp}, author: ${id.recipientId} | Receipt so associating with message from self ($selfId)") + + for (targetTimestamp in missingTargetTimestamps) { + warn(envelope.timestamp, "[handleViewedReceipt] Could not find matching message! targetTimestamp: $targetTimestamp, receiptAuthor: $senderRecipientId | Receipt so associating with message from self ($selfId)") if (earlyMessageCacheEntry != null) { - ApplicationDependencies.getEarlyMessageCache().store(selfId, id.timetamp, earlyMessageCacheEntry) + ApplicationDependencies.getEarlyMessageCache().store(selfId, targetTimestamp, earlyMessageCacheEntry) } } } - if (unhandled.isNotEmpty() && earlyMessageCacheEntry != null) { + if (missingTargetTimestamps.isNotEmpty() && earlyMessageCacheEntry != null) { PushProcessEarlyMessagesJob.enqueue() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt index 756c035679..cec359315a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/SyncMessageProcessor.kt @@ -16,7 +16,6 @@ import org.thoughtcrime.securesms.database.CallTable import org.thoughtcrime.securesms.database.GroupReceiptTable import org.thoughtcrime.securesms.database.GroupTable import org.thoughtcrime.securesms.database.MessageTable.MarkedMessageInfo -import org.thoughtcrime.securesms.database.MessageTable.SyncMessageId import org.thoughtcrime.securesms.database.NoSuchMessageException import org.thoughtcrime.securesms.database.PaymentMetaDataUtil import org.thoughtcrime.securesms.database.SentStorySyncManifest @@ -323,9 +322,8 @@ object SyncMessageProcessor { attachments = allAttachments.filterNot { it.isSticker } if (recipient.isSelf) { - val id = SyncMessageId(recipient.id, sent.timestamp) - SignalDatabase.messages.incrementDeliveryReceiptCount(id, System.currentTimeMillis()) - SignalDatabase.messages.incrementReadReceiptCount(id, System.currentTimeMillis()) + SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) } SignalDatabase.messages.setTransactionSuccessful() @@ -536,9 +534,8 @@ object SyncMessageProcessor { .scheduleDeletion(messageId, true, sent.expirationStartTimestamp, sent.message.expireTimer.seconds.inWholeMilliseconds) } if (recipient.isSelf) { - val id = SyncMessageId(recipient.id, sent.timestamp) - SignalDatabase.messages.incrementDeliveryReceiptCount(id, System.currentTimeMillis()) - SignalDatabase.messages.incrementReadReceiptCount(id, System.currentTimeMillis()) + SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) } SignalDatabase.messages.setTransactionSuccessful() } finally { @@ -614,9 +611,8 @@ object SyncMessageProcessor { ApplicationDependencies.getExpiringMessageManager().scheduleDeletion(messageId, true, sent.expirationStartTimestamp, sent.message.expireTimer.seconds.inWholeMilliseconds) } if (recipient.isSelf) { - val id = SyncMessageId(recipient.id, sent.timestamp) - SignalDatabase.messages.incrementDeliveryReceiptCount(id, System.currentTimeMillis()) - SignalDatabase.messages.incrementReadReceiptCount(id, System.currentTimeMillis()) + SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) } SignalDatabase.messages.setTransactionSuccessful() } finally { @@ -662,7 +658,7 @@ object SyncMessageProcessor { messageId = SignalDatabase.messages.insertMessageOutbox(outgoingMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null) updateGroupReceiptStatus(sent, messageId, recipient.requireGroupId()) } else { - val outgoingTextMessage = text(recipient = recipient, body = body, expiresIn = expiresInMillis, sentTimeMillis = sent.timestamp, bodyRanges = bodyRanges) + val outgoingTextMessage = text(threadRecipient = recipient, body = body, expiresIn = expiresInMillis, sentTimeMillis = sent.timestamp, bodyRanges = bodyRanges) messageId = SignalDatabase.messages.insertMessageOutbox(outgoingTextMessage, threadId, false, null) SignalDatabase.messages.markUnidentified(messageId, sent.isUnidentified(recipient.serviceId.orNull())) } @@ -674,9 +670,8 @@ object SyncMessageProcessor { } if (recipient.isSelf) { - val id = SyncMessageId(recipient.id, sent.timestamp) - SignalDatabase.messages.incrementDeliveryReceiptCount(id, System.currentTimeMillis()) - SignalDatabase.messages.incrementReadReceiptCount(id, System.currentTimeMillis()) + SignalDatabase.messages.incrementDeliveryReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) + SignalDatabase.messages.incrementReadReceiptCount(sent.timestamp, recipient.id, System.currentTimeMillis()) } return threadId diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java index 45a3cf0dae..35a5d176ec 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java @@ -124,9 +124,10 @@ public class ApplicationMigrations { static final int RECOVERY_PASSWORD_SYNC = 79; static final int DECRYPTIONS_DRAINED = 80; static final int REBUILD_MESSAGE_FTS_INDEX_3 = 81; + static final int TO_FROM_RECIPIENTS = 82; } - public static final int CURRENT_VERSION = 81; + public static final int CURRENT_VERSION = 82; /** * This *must* be called after the {@link JobManager} has been instantiated, but *before* the call @@ -552,6 +553,10 @@ public class ApplicationMigrations { jobs.put(Version.REBUILD_MESSAGE_FTS_INDEX_3, new RebuildMessageSearchIndexMigrationJob()); } + if (lastSeenVersion < Version.TO_FROM_RECIPIENTS) { + jobs.put(Version.TO_FROM_RECIPIENTS, new DatabaseMigrationJob()); + } + return jobs; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMessage.kt b/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMessage.kt index 51b1797ef6..114e49098a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMessage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMessage.kt @@ -19,7 +19,7 @@ import org.thoughtcrime.securesms.sms.GroupV2UpdateMessageUtil * Represents all the data needed for an outgoing message. */ data class OutgoingMessage( - val recipient: Recipient, + val threadRecipient: Recipient, val sentTimeMillis: Long, val body: String = "", val distributionType: Int = ThreadTable.DistributionTypes.DEFAULT, @@ -82,7 +82,7 @@ data class OutgoingMessage( bodyRanges: BodyRangeList? = null, scheduledDate: Long = -1 ) : this( - recipient = recipient, + threadRecipient = recipient, body = body ?: "", attachments = attachments, sentTimeMillis = timestamp, @@ -123,7 +123,7 @@ data class OutgoingMessage( bodyRanges: BodyRangeList? = null, contacts: List = emptyList() ) : this( - recipient = recipient, + threadRecipient = recipient, body = buildMessage(slideDeck, body ?: ""), attachments = slideDeck.asAttachments(), sentTimeMillis = timestamp, @@ -168,9 +168,9 @@ data class OutgoingMessage( * A literal, insecure SMS message. */ @JvmStatic - fun sms(recipient: Recipient, body: String, subscriptionId: Int): OutgoingMessage { + fun sms(threadRecipient: Recipient, body: String, subscriptionId: Int): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, sentTimeMillis = System.currentTimeMillis(), body = body, subscriptionId = subscriptionId, @@ -183,14 +183,14 @@ data class OutgoingMessage( */ @JvmStatic fun text( - recipient: Recipient, + threadRecipient: Recipient, body: String, expiresIn: Long, sentTimeMillis: Long = System.currentTimeMillis(), bodyRanges: BodyRangeList? = null ): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, sentTimeMillis = sentTimeMillis, body = body, expiresIn = expiresIn, @@ -204,11 +204,11 @@ data class OutgoingMessage( * Helper for creating a group update message when a state change occurs and needs to be sent to others. */ @JvmStatic - fun groupUpdateMessage(recipient: Recipient, group: DecryptedGroupV2Context, sentTimeMillis: Long): OutgoingMessage { + fun groupUpdateMessage(threadRecipient: Recipient, group: DecryptedGroupV2Context, sentTimeMillis: Long): OutgoingMessage { val groupContext = MessageGroupContext(group) return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, body = groupContext.encodedGroupContext, sentTimeMillis = sentTimeMillis, messageGroupContext = groupContext, @@ -223,7 +223,7 @@ data class OutgoingMessage( */ @JvmStatic fun groupUpdateMessage( - recipient: Recipient, + threadRecipient: Recipient, groupContext: MessageGroupContext, avatar: List = emptyList(), sentTimeMillis: Long, @@ -235,7 +235,7 @@ data class OutgoingMessage( mentions: List = emptyList() ): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, body = groupContext.encodedGroupContext, isGroup = true, isGroupUpdate = true, @@ -257,7 +257,7 @@ data class OutgoingMessage( */ @JvmStatic fun textStoryMessage( - recipient: Recipient, + threadRecipient: Recipient, body: String, sentTimeMillis: Long, storyType: StoryType, @@ -265,7 +265,7 @@ data class OutgoingMessage( bodyRanges: BodyRangeList? ): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, body = body, sentTimeMillis = sentTimeMillis, storyType = storyType, @@ -279,9 +279,9 @@ data class OutgoingMessage( * Specialized message sent to request someone activate payments. */ @JvmStatic - fun requestToActivatePaymentsMessage(recipient: Recipient, sentTimeMillis: Long, expiresIn: Long): OutgoingMessage { + fun requestToActivatePaymentsMessage(threadRecipient: Recipient, sentTimeMillis: Long, expiresIn: Long): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, sentTimeMillis = sentTimeMillis, expiresIn = expiresIn, isRequestToActivatePayments = true, @@ -295,9 +295,9 @@ data class OutgoingMessage( * be sent to those that sent requests prior to activation. */ @JvmStatic - fun paymentsActivatedMessage(recipient: Recipient, sentTimeMillis: Long, expiresIn: Long): OutgoingMessage { + fun paymentsActivatedMessage(threadRecipient: Recipient, sentTimeMillis: Long, expiresIn: Long): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, sentTimeMillis = sentTimeMillis, expiresIn = expiresIn, isPaymentsActivated = true, @@ -310,9 +310,9 @@ data class OutgoingMessage( * Type of message sent when sending a payment to another Signal contact. */ @JvmStatic - fun paymentNotificationMessage(recipient: Recipient, paymentUuid: String, sentTimeMillis: Long, expiresIn: Long): OutgoingMessage { + fun paymentNotificationMessage(threadRecipient: Recipient, paymentUuid: String, sentTimeMillis: Long, expiresIn: Long): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, body = paymentUuid, sentTimeMillis = sentTimeMillis, expiresIn = expiresIn, @@ -325,9 +325,9 @@ data class OutgoingMessage( * Helper for creating expiration update messages. */ @JvmStatic - fun expirationUpdateMessage(recipient: Recipient, sentTimeMillis: Long, expiresIn: Long): OutgoingMessage { + fun expirationUpdateMessage(threadRecipient: Recipient, sentTimeMillis: Long, expiresIn: Long): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, sentTimeMillis = sentTimeMillis, expiresIn = expiresIn, isExpirationUpdate = true, @@ -340,9 +340,9 @@ data class OutgoingMessage( * Message for when you have verified the identity of a contact. */ @JvmStatic - fun identityVerifiedMessage(recipient: Recipient, sentTimeMillis: Long): OutgoingMessage { + fun identityVerifiedMessage(threadRecipient: Recipient, sentTimeMillis: Long): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, sentTimeMillis = sentTimeMillis, isIdentityVerified = true, isUrgent = false, @@ -354,9 +354,9 @@ data class OutgoingMessage( * Message for when the verification status of an identity is getting set to the default. */ @JvmStatic - fun identityDefaultMessage(recipient: Recipient, sentTimeMillis: Long): OutgoingMessage { + fun identityDefaultMessage(threadRecipient: Recipient, sentTimeMillis: Long): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, sentTimeMillis = sentTimeMillis, isIdentityDefault = true, isUrgent = false, @@ -369,9 +369,9 @@ data class OutgoingMessage( * but it doesn't hurt to support receiving them in sync messages. */ @JvmStatic - fun endSessionMessage(recipient: Recipient, sentTimeMillis: Long): OutgoingMessage { + fun endSessionMessage(threadRecipient: Recipient, sentTimeMillis: Long): OutgoingMessage { return OutgoingMessage( - recipient = recipient, + threadRecipient = threadRecipient, sentTimeMillis = sentTimeMillis, isEndSession = true, isUrgent = false, diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationBuilder.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationBuilder.kt index c83a3a571f..552342e3d2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationBuilder.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationBuilder.kt @@ -293,7 +293,7 @@ sealed class NotificationBuilder(protected val context: Context) { .setIcon(notificationItem.getPersonIcon(context).toIconCompat()) if (includeShortcut) { - personBuilder.setKey(ConversationUtil.getShortcutId(notificationItem.individualRecipient)) + personBuilder.setKey(ConversationUtil.getShortcutId(notificationItem.authorRecipient)) } person = personBuilder.build() @@ -319,7 +319,7 @@ sealed class NotificationBuilder(protected val context: Context) { if (line != null) { style.addLine(line) } - addPerson(notificationItem.individualRecipient) + addPerson(notificationItem.authorRecipient) } builder.setStyle(style) diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationConversation.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationConversation.kt index 2312f4591e..70ab472732 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationConversation.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationConversation.kt @@ -74,7 +74,7 @@ data class NotificationConversation( val stringBuilder = SpannableStringBuilder() if (privacy.isDisplayContact && recipient.isGroup) { - stringBuilder.append(Util.getBoldedString(mostRecentNotification.individualRecipient.getDisplayName(context) + ": ")) + stringBuilder.append(Util.getBoldedString(mostRecentNotification.authorRecipient.getDisplayName(context) + ": ")) } return if (privacy.isDisplayMessage) { 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 38ec67a6a1..892b12ae7c 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 @@ -112,7 +112,7 @@ object NotificationFactory { conversation = conversation, targetThread = targetThread, defaultBubbleState = defaultBubbleState, - shouldAlert = (conversation.hasNewNotifications() || alertOverrides.contains(conversation.thread)) && !conversation.mostRecentNotification.individualRecipient.isSelf + shouldAlert = (conversation.hasNewNotifications() || alertOverrides.contains(conversation.thread)) && !conversation.mostRecentNotification.authorRecipient.isSelf ) if (conversation.hasNewNotifications()) { threadsThatNewlyAlerted += conversation.thread @@ -157,7 +157,7 @@ object NotificationFactory { conversation = conversation, targetThread = targetThread, defaultBubbleState = defaultBubbleState, - shouldAlert = (conversation.hasNewNotifications() || alertOverrides.contains(conversation.thread)) && !conversation.mostRecentNotification.individualRecipient.isSelf + shouldAlert = (conversation.hasNewNotifications() || alertOverrides.contains(conversation.thread)) && !conversation.mostRecentNotification.authorRecipient.isSelf ) } catch (e: SecurityException) { Log.w(TAG, "Too many pending intents device quirk", e) diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationItem.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationItem.kt index b004db8bfc..daaa84c425 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationItem.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationItem.kt @@ -49,12 +49,12 @@ sealed class NotificationItem(val threadRecipient: Recipient, protected val reco val slideDeck: SlideDeck? = if (record.isViewOnce) null else (record as? MmsMessageRecord)?.slideDeck val isJoined: Boolean = record.isJoined val isPersonSelf: Boolean - get() = individualRecipient.isSelf + get() = authorRecipient.isSelf protected val notifiedTimestamp: Long = record.notifiedTimestamp abstract val timestamp: Long - abstract val individualRecipient: Recipient + abstract val authorRecipient: Recipient abstract val isNewNotification: Boolean protected abstract fun getPrimaryTextActual(context: Context): CharSequence @@ -92,8 +92,8 @@ sealed class NotificationItem(val threadRecipient: Recipient, protected val reco context.getString(R.string.SingleRecipientNotificationBuilder_new_message) } else { SpannableStringBuilder().apply { - append(Util.getBoldedString(individualRecipient.getShortDisplayNameIncludingUsername(context))) - if (threadRecipient != individualRecipient) { + append(Util.getBoldedString(authorRecipient.getShortDisplayNameIncludingUsername(context))) + if (threadRecipient != authorRecipient) { append(Util.getBoldedString("@${threadRecipient.getDisplayName(context)}")) } append(": ") @@ -104,7 +104,7 @@ sealed class NotificationItem(val threadRecipient: Recipient, protected val reco fun getPersonName(context: Context): CharSequence { return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) { - individualRecipient.getDisplayName(context) + authorRecipient.getDisplayName(context) } else { context.getString(R.string.SingleRecipientNotificationBuilder_signal) } @@ -115,8 +115,8 @@ sealed class NotificationItem(val threadRecipient: Recipient, protected val reco } fun getPersonUri(): String? { - return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact && individualRecipient.isSystemContact) { - individualRecipient.contactUri.toString() + return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact && authorRecipient.isSystemContact) { + authorRecipient.contactUri.toString() } else { null } @@ -124,7 +124,7 @@ sealed class NotificationItem(val threadRecipient: Recipient, protected val reco fun getPersonIcon(context: Context): Bitmap? { return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) { - individualRecipient.getContactDrawable(context).toLargeBitmap(context) + authorRecipient.getContactDrawable(context).toLargeBitmap(context) } else { null } @@ -153,8 +153,8 @@ sealed class NotificationItem(val threadRecipient: Recipient, protected val reco return timestamp == other.timestamp && id == other.id && isMms == other.isMms && - individualRecipient == other.individualRecipient && - individualRecipient.hasSameContent(other.individualRecipient) && + authorRecipient == other.authorRecipient && + authorRecipient.hasSameContent(other.authorRecipient) && slideDeck?.thumbnailSlide?.isInProgress == other.slideDeck?.thumbnailSlide?.isInProgress && record.isRemoteDelete == other.record.isRemoteDelete } @@ -203,7 +203,7 @@ sealed class NotificationItem(val threadRecipient: Recipient, protected val reco */ class MessageNotification(threadRecipient: Recipient, record: MessageRecord) : NotificationItem(threadRecipient, record) { override val timestamp: Long = record.timestamp - override val individualRecipient: Recipient = if (record.isOutgoing) Recipient.self() else record.individualRecipient.resolve() + override val authorRecipient: Recipient = record.fromRecipient.resolve() override val isNewNotification: Boolean = notifiedTimestamp == 0L private var thumbnailInfo: ThumbnailInfo? = null @@ -302,7 +302,7 @@ class MessageNotification(threadRecipient: Recipient, record: MessageRecord) : N */ class ReactionNotification(threadRecipient: Recipient, record: MessageRecord, val reaction: ReactionRecord) : NotificationItem(threadRecipient, record) { override val timestamp: Long = reaction.dateReceived - override val individualRecipient: Recipient = Recipient.resolved(reaction.author) + override val authorRecipient: Recipient = Recipient.resolved(reaction.author) override val isNewNotification: Boolean = timestamp > notifiedTimestamp override fun getPrimaryTextActual(context: Context): CharSequence { diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationState.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationState.kt index 1e05c54135..0d6fec86b6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/v2/NotificationState.kt @@ -38,7 +38,7 @@ data class NotificationState(val conversations: List, get() = notificationItems.lastOrNull() val mostRecentSender: Recipient? - get() = mostRecentNotification?.individualRecipient + get() = mostRecentNotification?.authorRecipient fun getNonVisibleConversation(visibleThread: ConversationId?): List { return conversations.filterNot { it.thread == visibleThread } @@ -81,7 +81,7 @@ data class NotificationState(val conversations: List, } fun getThreadsWithMostRecentNotificationFromSelf(): Set { - return conversations.filter { it.mostRecentNotification.individualRecipient.isSelf } + return conversations.filter { it.mostRecentNotification.authorRecipient.isSelf } .map { it.thread } .toSet() } 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 9c29b7e2c9..8cb6ee003a 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 @@ -112,8 +112,8 @@ object NotificationStateProvider { } notificationItems.sort() - if (notificationItems.isNotEmpty() && stickyThreads.containsKey(thread) && !notificationItems.last().individualRecipient.isSelf) { - val indexOfOldestNonSelfMessage: Int = notificationItems.indexOfLast { it.individualRecipient.isSelf } + 1 + if (notificationItems.isNotEmpty() && stickyThreads.containsKey(thread) && !notificationItems.last().authorRecipient.isSelf) { + val indexOfOldestNonSelfMessage: Int = notificationItems.indexOfLast { it.authorRecipient.isSelf } + 1 notificationItems = notificationItems.slice(indexOfOldestNonSelfMessage..notificationItems.lastIndex).toMutableList() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewUtil.java b/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewUtil.java index 22ab639b20..0e977ad1a6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/spoofing/ReviewUtil.java @@ -64,8 +64,8 @@ public final class ReviewUtil { .getGroupMembers(groupId, GroupTable.MemberSet.FULL_MEMBERS_INCLUDING_SELF); List changed = Stream.of(profileChangeRecords) - .distinctBy(record -> record.getRecipient().getId()) - .map(record -> new ReviewRecipient(record.getRecipient().resolve(), getProfileChangeDetails(record))) + .distinctBy(record -> record.getFromRecipient().getId()) + .map(record -> new ReviewRecipient(record.getFromRecipient().resolve(), getProfileChangeDetails(record))) .filter(recipient -> !recipient.getRecipient().isSystemContact()) .toList(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheet.kt index ef48643057..ff388953cf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/safety/SafetyNumberBottomSheet.kt @@ -134,9 +134,9 @@ object SafetyNumberBottomSheet { private fun getDestinationFromRecord(messageRecord: MessageRecord): List { val key = if ((messageRecord as? MmsMessageRecord)?.storyType?.isStory == true) { - ContactSearchKey.RecipientSearchKey(messageRecord.recipient.id, true) + ContactSearchKey.RecipientSearchKey(messageRecord.toRecipient.id, true) } else { - ContactSearchKey.RecipientSearchKey(messageRecord.recipient.id, false) + ContactSearchKey.RecipientSearchKey(messageRecord.toRecipient.id, false) } return listOf(key) diff --git a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java index f0ef177d97..e2c771b8c0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java @@ -367,8 +367,7 @@ public class SearchRepository { CharSequence updatedBody = MentionUtil.updateBodyAndMentionsWithDisplayNames(context, body, mentions).getBody(); CharSequence updatedSnippet = makeSnippet(cleanQueries, Objects.requireNonNull(updatedBody)); - //noinspection ConstantConditions - results.add(new MessageResult(threadTable.getRecipientForThreadId(record.getThreadId()), record.getRecipient(), updatedBody, updatedSnippet, record.getThreadId(), record.getId(), record.getDateReceived(), true)); + results.add(new MessageResult(record.getToRecipient(), record.getFromRecipient(), updatedBody, updatedSnippet, record.getThreadId(), record.getId(), record.getDateReceived(), true)); } } } @@ -394,8 +393,7 @@ public class SearchRepository { try (MessageTable.Reader reader = messageTable.getMessages(mentionQueryResults.keySet())) { for (MessageRecord record : reader) { - //noinspection ConstantConditions - results.add(new MessageResult(threadTable.getRecipientForThreadId(record.getThreadId()), record.getRecipient(), record.getBody(), record.getBody(), record.getThreadId(), record.getId(), record.getDateReceived(), true)); + results.add(new MessageResult(record.getToRecipient(), record.getFromRecipient(), record.getBody(), record.getBody(), record.getThreadId(), record.getId(), record.getDateReceived(), true)); } } 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 c2c91b143e..5b291f1942 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/ScheduledMessageManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/ScheduledMessageManager.kt @@ -47,19 +47,19 @@ class ScheduledMessageManager( val delay = (oldestMessage.scheduledDate - System.currentTimeMillis()).coerceAtLeast(0) Log.i(TAG, "The next scheduled message needs to be sent in $delay ms.") - return Event(delay, oldestMessage.recipient.id, oldestMessage.threadId) + return Event(delay, oldestMessage.toRecipient.id, oldestMessage.threadId) } @WorkerThread override fun executeEvent(event: Event) { val scheduledMessagesToSend = messagesTable.getScheduledMessagesBefore(System.currentTimeMillis()) for (record in scheduledMessagesToSend) { - val expiresIn = SignalDatabase.recipients.getExpiresInSeconds(record.recipient.id) + val expiresIn = SignalDatabase.recipients.getExpiresInSeconds(record.toRecipient.id) if (messagesTable.clearScheduledStatus(record.threadId, record.id, expiresIn.seconds.inWholeMilliseconds)) { - if (record.recipient.isPushGroup) { - PushGroupSendJob.enqueue(application, ApplicationDependencies.getJobManager(), record.id, record.recipient.id, emptySet(), true) + if (record.toRecipient.isPushGroup) { + PushGroupSendJob.enqueue(application, ApplicationDependencies.getJobManager(), record.id, record.toRecipient.id, emptySet(), true) } else { - IndividualSendJob.enqueue(application, ApplicationDependencies.getJobManager(), record.id, record.recipient, true) + IndividualSendJob.enqueue(application, ApplicationDependencies.getJobManager(), record.id, record.toRecipient, true) } } else { Log.i(TAG, "messageId=${record.id} was not a scheduled message, ignoring") diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java b/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java index 3853e4169b..ee24084145 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/IncomingTextMessage.java @@ -31,7 +31,7 @@ public class IncomingTextMessage implements Parcelable { private static final String TAG = Log.tag(IncomingTextMessage.class); private final String message; - private final RecipientId sender; + private final RecipientId authorId; private final int senderDeviceId; private final int protocol; private final String serviceCenterAddress; @@ -47,9 +47,9 @@ public class IncomingTextMessage implements Parcelable { private final boolean unidentified; @Nullable private final String serverGuid; - public IncomingTextMessage(@NonNull RecipientId sender, @NonNull SmsMessage message, int subscriptionId) { + public IncomingTextMessage(@NonNull RecipientId authorId, @NonNull SmsMessage message, int subscriptionId) { this.message = message.getDisplayMessageBody(); - this.sender = sender; + this.authorId = authorId; this.senderDeviceId = SignalServiceAddress.DEFAULT_DEVICE_ID; this.protocol = message.getProtocolIdentifier(); this.serviceCenterAddress = message.getServiceCenterAddress(); @@ -66,7 +66,7 @@ public class IncomingTextMessage implements Parcelable { this.serverGuid = null; } - public IncomingTextMessage(@NonNull RecipientId sender, + public IncomingTextMessage(@NonNull RecipientId authorId, int senderDeviceId, long sentTimestampMillis, long serverTimestampMillis, @@ -78,7 +78,7 @@ public class IncomingTextMessage implements Parcelable { String serverGuid) { this.message = encodedBody; - this.sender = sender; + this.authorId = authorId; this.senderDeviceId = senderDeviceId; this.protocol = 31337; this.serviceCenterAddress = "GCM"; @@ -97,7 +97,7 @@ public class IncomingTextMessage implements Parcelable { public IncomingTextMessage(Parcel in) { this.message = in.readString(); - this.sender = in.readParcelable(IncomingTextMessage.class.getClassLoader()); + this.authorId = in.readParcelable(IncomingTextMessage.class.getClassLoader()); this.senderDeviceId = in.readInt(); this.protocol = in.readInt(); this.serviceCenterAddress = in.readString(); @@ -116,8 +116,8 @@ public class IncomingTextMessage implements Parcelable { public IncomingTextMessage(IncomingTextMessage base, String newBody) { this.message = newBody; - this.sender = base.getSender(); - this.senderDeviceId = base.getSenderDeviceId(); + this.authorId = base.getAuthorId(); + this.senderDeviceId = base.getAuthorDeviceId(); this.protocol = base.getProtocol(); this.serviceCenterAddress = base.getServiceCenterAddress(); this.replyPathPresent = base.isReplyPathPresent(); @@ -141,8 +141,8 @@ public class IncomingTextMessage implements Parcelable { } this.message = body.toString(); - this.sender = fragments.get(0).getSender(); - this.senderDeviceId = fragments.get(0).getSenderDeviceId(); + this.authorId = fragments.get(0).getAuthorId(); + this.senderDeviceId = fragments.get(0).getAuthorDeviceId(); this.protocol = fragments.get(0).getProtocol(); this.serviceCenterAddress = fragments.get(0).getServiceCenterAddress(); this.replyPathPresent = fragments.get(0).isReplyPathPresent(); @@ -186,11 +186,11 @@ public class IncomingTextMessage implements Parcelable { return message; } - public RecipientId getSender() { - return sender; + public RecipientId getAuthorId() { + return authorId; } - public int getSenderDeviceId() { + public int getAuthorDeviceId() { return senderDeviceId; } @@ -277,7 +277,7 @@ public class IncomingTextMessage implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { out.writeString(message); - out.writeParcelable(sender, flags); + out.writeParcelable(authorId, flags); out.writeInt(senderDeviceId); out.writeInt(protocol); out.writeString(serviceCenterAddress); diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java b/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java index aa94dbad3f..4e51e50247 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java @@ -120,13 +120,13 @@ public class MessageSender { database.beginTransaction(); for (OutgoingMessage message : messages) { - long allocatedThreadId = threadTable.getOrCreateValidThreadId(message.getRecipient(), -1L, message.getDistributionType()); + long allocatedThreadId = threadTable.getOrCreateValidThreadId(message.getThreadRecipient(), -1L, message.getDistributionType()); long messageId = database.insertMessageOutbox(message.stripAttachments(), allocatedThreadId, false, insertListener); messageIds.add(messageId); threads.add(allocatedThreadId); - if (message.getRecipient().isGroup() && message.getAttachments().isEmpty() && message.getLinkPreviews().isEmpty() && message.getSharedContacts().isEmpty()) { + if (message.getThreadRecipient().isGroup() && message.getAttachments().isEmpty() && message.getLinkPreviews().isEmpty() && message.getSharedContacts().isEmpty()) { SignalLocalMetrics.GroupMessageSend.onInsertedIntoDatabase(messageId, metricId); } else { SignalLocalMetrics.GroupMessageSend.cancel(metricId); @@ -136,7 +136,7 @@ public class MessageSender { for (int i = 0; i < messageIds.size(); i++) { long messageId = messageIds.get(i); OutgoingMessage message = messages.get(i); - Recipient recipient = message.getRecipient(); + Recipient recipient = message.getThreadRecipient(); if (recipient.isDistributionList()) { DistributionId distributionId = Objects.requireNonNull(SignalDatabase.distributionLists().getDistributionId(recipient.requireDistributionListId())); @@ -196,7 +196,7 @@ public class MessageSender { for (int i = 0; i < messageIds.size(); i++) { long messageId = messageIds.get(i); OutgoingMessage message = messages.get(i); - Recipient recipient = message.getRecipient(); + Recipient recipient = message.getThreadRecipient(); List dependencies = dependencyGraph.getDependencyMap().get(message); List jobDependencyIds = (dependencies != null) ? dependencies.stream().map(UploadDependencyGraph.Node::getJobId).collect(Collectors.toList()) @@ -224,16 +224,16 @@ public class MessageSender { @Nullable final String metricId, @Nullable final MessageTable.InsertListener insertListener) { - Log.i(TAG, "Sending media message to " + message.getRecipient().getId() + ", thread: " + threadId); + Log.i(TAG, "Sending media message to " + message.getThreadRecipient().getId() + ", thread: " + threadId); try { ThreadTable threadTable = SignalDatabase.threads(); MessageTable database = SignalDatabase.messages(); - long allocatedThreadId = threadTable.getOrCreateValidThreadId(message.getRecipient(), threadId, message.getDistributionType()); - Recipient recipient = message.getRecipient(); + long allocatedThreadId = threadTable.getOrCreateValidThreadId(message.getThreadRecipient(), threadId, message.getDistributionType()); + Recipient recipient = message.getThreadRecipient(); long messageId = database.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, recipient, message, allocatedThreadId), allocatedThreadId, sendType != SendType.SIGNAL, insertListener); - if (message.getRecipient().isGroup() && message.getAttachments().isEmpty() && message.getLinkPreviews().isEmpty() && message.getSharedContacts().isEmpty()) { + if (message.getThreadRecipient().isGroup() && message.getAttachments().isEmpty() && message.getLinkPreviews().isEmpty() && message.getSharedContacts().isEmpty()) { SignalLocalMetrics.GroupMessageSend.onInsertedIntoDatabase(messageId, metricId); } else { SignalLocalMetrics.GroupMessageSend.cancel(metricId); @@ -256,7 +256,7 @@ public class MessageSender { final long threadId, final MessageTable.InsertListener insertListener) { - Log.i(TAG, "Sending media message with pre-uploads to " + message.getRecipient().getId() + ", thread: " + threadId + ", pre-uploads: " + preUploadResults); + Log.i(TAG, "Sending media message with pre-uploads to " + message.getThreadRecipient().getId() + ", thread: " + threadId + ", pre-uploads: " + preUploadResults); Preconditions.checkArgument(message.getAttachments().isEmpty(), "If the media is pre-uploaded, there should be no attachments on the message."); try { @@ -264,8 +264,8 @@ public class MessageSender { MessageTable mmsDatabase = SignalDatabase.messages(); AttachmentTable attachmentDatabase = SignalDatabase.attachments(); - Recipient recipient = message.getRecipient(); - long allocatedThreadId = threadTable.getOrCreateValidThreadId(message.getRecipient(), threadId); + Recipient recipient = message.getThreadRecipient(); + long allocatedThreadId = threadTable.getOrCreateValidThreadId(message.getThreadRecipient(), threadId); long messageId = mmsDatabase.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, recipient, message, allocatedThreadId), allocatedThreadId, false, @@ -292,7 +292,7 @@ public class MessageSender { @NonNull Collection preUploadResults, boolean overwritePreUploadMessageIds) { - Log.i(TAG, "Sending media broadcast (overwrite: " + overwritePreUploadMessageIds + ") to " + Stream.of(messages).map(m -> m.getRecipient().getId()).toList()); + Log.i(TAG, "Sending media broadcast (overwrite: " + overwritePreUploadMessageIds + ") to " + Stream.of(messages).map(m -> m.getThreadRecipient().getId()).toList()); Preconditions.checkArgument(messages.size() > 0, "No messages!"); Preconditions.checkArgument(Stream.of(messages).allMatch(m -> m.getAttachments().isEmpty()), "Messages can't have attachments! They should be pre-uploaded."); @@ -309,8 +309,8 @@ public class MessageSender { mmsDatabase.beginTransaction(); try { if (overwritePreUploadMessageIds) { - long primaryThreadId = threadTable.getOrCreateThreadIdFor(primaryMessage.getRecipient(), primaryMessage.getDistributionType()); - long primaryMessageId = mmsDatabase.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, primaryMessage.getRecipient(), primaryMessage, primaryThreadId), + long primaryThreadId = threadTable.getOrCreateThreadIdFor(primaryMessage.getThreadRecipient(), primaryMessage.getDistributionType()); + long primaryMessageId = mmsDatabase.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, primaryMessage.getThreadRecipient(), primaryMessage, primaryThreadId), primaryThreadId, false, null); @@ -337,8 +337,8 @@ public class MessageSender { } for (OutgoingMessage secondaryMessage : secondaryMessages) { - long allocatedThreadId = threadTable.getOrCreateThreadIdFor(secondaryMessage.getRecipient(), secondaryMessage.getDistributionType()); - long messageId = mmsDatabase.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, secondaryMessage.getRecipient(), secondaryMessage, allocatedThreadId), + long allocatedThreadId = threadTable.getOrCreateThreadIdFor(secondaryMessage.getThreadRecipient(), secondaryMessage.getDistributionType()); + long messageId = mmsDatabase.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, secondaryMessage.getThreadRecipient(), secondaryMessage, allocatedThreadId), allocatedThreadId, false, null); @@ -370,7 +370,7 @@ public class MessageSender { for (int i = 0; i < messageIds.size(); i++) { long messageId = messageIds.get(i); OutgoingMessage message = messages.get(i); - Recipient recipient = message.getRecipient(); + Recipient recipient = message.getThreadRecipient(); if (recipient.isDistributionList()) { List members = SignalDatabase.distributionLists().getMembers(recipient.requireDistributionListId()); @@ -390,7 +390,7 @@ public class MessageSender { for (int i = 0; i < messageIds.size(); i++) { long messageId = messageIds.get(i); - Recipient recipient = messages.get(i).getRecipient(); + Recipient recipient = messages.get(i).getThreadRecipient(); if (isLocalSelfSend(context, recipient, SendType.SIGNAL)) { sendLocalMediaSelf(context, messageId); @@ -473,7 +473,7 @@ public class MessageSender { public static void resendGroupMessage(@NonNull Context context, @NonNull MessageRecord messageRecord, @NonNull Set filterRecipientIds) { if (!messageRecord.isMms()) throw new AssertionError("Not Group"); - sendGroupPush(context, messageRecord.getRecipient(), messageRecord.getId(), filterRecipientIds, Collections.emptyList()); + sendGroupPush(context, messageRecord.getToRecipient(), messageRecord.getId(), filterRecipientIds, Collections.emptyList()); onMessageSent(); } @@ -481,14 +481,14 @@ public class MessageSender { if (!messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getStoryType().isStory()) { throw new AssertionError("Not a story"); } - sendDistributionList(context, messageRecord.getRecipient(), messageRecord.getId(), filterRecipientIds, Collections.emptyList()); + sendDistributionList(context, messageRecord.getToRecipient(), messageRecord.getId(), filterRecipientIds, Collections.emptyList()); onMessageSent(); } public static void resend(Context context, MessageRecord messageRecord) { long messageId = messageRecord.getId(); boolean forceSms = messageRecord.isForcedSms(); - Recipient recipient = messageRecord.getRecipient(); + Recipient recipient = messageRecord.getToRecipient(); SendType sendType; @@ -658,9 +658,9 @@ public class MessageSender { mmsDatabase.markAsSent(messageId, true); mmsDatabase.markUnidentified(messageId, true); - mmsDatabase.incrementDeliveryReceiptCount(syncId, System.currentTimeMillis()); - mmsDatabase.incrementReadReceiptCount(syncId, System.currentTimeMillis()); - mmsDatabase.incrementViewedReceiptCount(syncId, System.currentTimeMillis()); + mmsDatabase.incrementDeliveryReceiptCount(message.getSentTimeMillis(), Recipient.self().getId(), System.currentTimeMillis()); + mmsDatabase.incrementReadReceiptCount(message.getSentTimeMillis(), Recipient.self().getId(), System.currentTimeMillis()); + mmsDatabase.incrementViewedReceiptCount(message.getSentTimeMillis(), Recipient.self().getId(), System.currentTimeMillis()); if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) { mmsDatabase.markExpireStarted(messageId); diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostModel.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostModel.kt index eb570126f8..2981dd827b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostModel.kt @@ -31,7 +31,6 @@ import org.thoughtcrime.securesms.fonts.TextToScript import org.thoughtcrime.securesms.fonts.TypefaceCache import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader import org.thoughtcrime.securesms.mms.GlideApp -import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.ParcelUtil @@ -94,7 +93,7 @@ data class StoryTextPostModel( return parseFrom( body = messageRecord.body, storySentAtMillis = messageRecord.timestamp, - storyAuthor = if (messageRecord.isOutgoing) Recipient.self().id else messageRecord.individualRecipient.id, + storyAuthor = messageRecord.fromRecipient.id, bodyRanges = messageRecord.messageRanges ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingItemData.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingItemData.kt index cb628974ee..5c5b0170f9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingItemData.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingItemData.kt @@ -15,7 +15,7 @@ data class StoriesLandingItemData( val primaryStory: ConversationMessage, val secondaryStory: ConversationMessage?, val storyRecipient: Recipient, - val individualRecipient: Recipient = primaryStory.messageRecord.individualRecipient, + val individualRecipient: Recipient = primaryStory.messageRecord.fromRecipient, val dateInMilliseconds: Long = primaryStory.messageRecord.dateSent, val sendingCount: Long = 0, val failureCount: Long = 0 diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesFragment.kt index 94649bb89e..019d674269 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesFragment.kt @@ -119,8 +119,8 @@ class MyStoriesFragment : DSLSettingsFragment( } } } else { - val recipient = if (it.distributionStory.messageRecord.recipient.isGroup) { - it.distributionStory.messageRecord.recipient + val recipient = if (it.distributionStory.messageRecord.toRecipient.isGroup) { + it.distributionStory.messageRecord.toRecipient } else { Recipient.self() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesRepository.kt index 1e0b9f5de1..283c3efb9d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesRepository.kt @@ -28,8 +28,8 @@ class MyStoriesRepository(context: Context) { val storiesMap = mutableMapOf>() SignalDatabase.messages.getAllOutgoingStories(true, -1).use { for (messageRecord in it) { - val currentList = storiesMap[messageRecord.recipient] ?: emptyList() - storiesMap[messageRecord.recipient] = (currentList + messageRecord) + val currentList = storiesMap[messageRecord.toRecipient] ?: emptyList() + storiesMap[messageRecord.toRecipient] = (currentList + messageRecord) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt index c4fca53f0c..b3a43873e5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt @@ -54,7 +54,7 @@ open class StoryViewerPageRepository(context: Context, private val storyViewStat } val results = stories.filterNot { - recipient.isMyStory && it.recipient.isGroup + recipient.isMyStory && it.toRecipient.isGroup } emitter.onNext(results) @@ -79,9 +79,9 @@ open class StoryViewerPageRepository(context: Context, private val storyViewStat val recipient = Recipient.resolved(recipientId) val story = StoryPost( id = record.id, - sender = if (record.isOutgoing) Recipient.self() else record.individualRecipient, + sender = record.fromRecipient, group = if (recipient.isGroup) recipient else null, - distributionList = if (record.recipient.isDistributionList) record.recipient else null, + distributionList = if (record.toRecipient.isDistributionList) record.toRecipient else null, viewCount = record.viewedReceiptCount, replyCount = SignalDatabase.messages.getNumberOfStoryReplies(record.id), dateInMilliseconds = record.dateSent, diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/direct/StoryDirectReplyDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/direct/StoryDirectReplyDialogFragment.kt index 8aecb59548..8de00a3e85 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/direct/StoryDirectReplyDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/direct/StoryDirectReplyDialogFragment.kt @@ -110,7 +110,7 @@ class StoryDirectReplyDialogFragment : if (state.groupDirectReplyRecipient != null) { composer.displayReplyHint(state.groupDirectReplyRecipient) } else if (state.storyRecord != null) { - composer.displayReplyHint(state.storyRecord.recipient) + composer.displayReplyHint(state.storyRecord.fromRecipient) } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/direct/StoryDirectReplyRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/direct/StoryDirectReplyRepository.kt index c940706dc4..55c1ddb31b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/direct/StoryDirectReplyRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/direct/StoryDirectReplyRepository.kt @@ -30,21 +30,18 @@ class StoryDirectReplyRepository(context: Context) { return Completable.create { emitter -> val message = SignalDatabase.messages.getMessageRecord(storyId) as MediaMmsMessageRecord val (recipient, threadId) = if (groupDirectReplyRecipientId == null) { - message.recipient to message.threadId + message.fromRecipient to message.threadId } else { val resolved = Recipient.resolved(groupDirectReplyRecipientId) resolved to SignalDatabase.threads.getOrCreateThreadIdFor(resolved) } - val quoteAuthor: Recipient = when { - message.isOutgoing -> Recipient.self() - else -> message.individualRecipient - } + val quoteAuthor: Recipient = message.fromRecipient MessageSender.send( context, OutgoingMessage( - recipient = recipient, + threadRecipient = recipient, body = body.toString(), sentTimeMillis = System.currentTimeMillis(), expiresIn = TimeUnit.SECONDS.toMillis(recipient.expiresInSeconds.toLong()), diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/ReplyBody.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/ReplyBody.kt index 10ca4b50cb..752035fed8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/ReplyBody.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/ReplyBody.kt @@ -8,7 +8,7 @@ import org.thoughtcrime.securesms.recipients.Recipient sealed class ReplyBody(val messageRecord: MessageRecord) { val key: MessageId = MessageId(messageRecord.id) - val sender: Recipient = if (messageRecord.isOutgoing) Recipient.self() else messageRecord.individualRecipient.resolve() + val sender: Recipient = messageRecord.fromRecipient.resolve() val sentAtMillis: Long = messageRecord.dateSent open fun hasSameContent(other: ReplyBody): Boolean { diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyRepository.kt index 57cf94d688..cb548fcd9d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyRepository.kt @@ -56,7 +56,7 @@ class StoryGroupReplyRepository { } fun getNameColorsMap(storyId: Long, sessionMemberCache: MutableMap>): Observable> { - return Single.fromCallable { SignalDatabase.messages.getMessageRecord(storyId).individualRecipient.id } + return Single.fromCallable { SignalDatabase.messages.getMessageRecord(storyId).fromRecipient.id } .subscribeOn(Schedulers.io()) .flatMapObservable { recipientId -> Observable.create?> { emitter -> diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt index bba4c9fdf8..7337a1ff78 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt @@ -56,7 +56,7 @@ object StoryGroupReplySender { MessageSender.send( context, OutgoingMessage( - recipient = recipient, + threadRecipient = recipient, body = body.toString(), sentTimeMillis = System.currentTimeMillis(), parentStoryId = ParentStoryId.GroupReply(message.id), diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/views/StoryViewsRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/views/StoryViewsRepository.kt index bc75b07df8..cfa7b83e41 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/views/StoryViewsRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/views/StoryViewsRepository.kt @@ -25,17 +25,15 @@ class StoryViewsRepository { fun getStoryRecipient(storyId: Long): Single { return Single.fromCallable { - val record = SignalDatabase.messages.getMessageRecord(storyId) - - record.recipient + SignalDatabase.messages.getMessageRecord(storyId).toRecipient }.subscribeOn(Schedulers.io()) } fun getViews(storyId: Long): Observable> { return Observable.create> { emitter -> val record: MessageRecord = SignalDatabase.messages.getMessageRecord(storyId) - val filterIds: Set = if (record.recipient.isDistributionList) { - val distributionId: DistributionId = SignalDatabase.distributionLists.getDistributionId(record.recipient.requireDistributionListId())!! + val filterIds: Set = if (record.toRecipient.isDistributionList) { + val distributionId: DistributionId = SignalDatabase.distributionLists.getDistributionId(record.toRecipient.requireDistributionListId())!! SignalDatabase.storySends.getRecipientsForDistributionId(storyId, distributionId) } else { emptySet() diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/AttachmentUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/AttachmentUtil.java index a99544bc31..a52359cd98 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/AttachmentUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/AttachmentUtil.java @@ -93,13 +93,13 @@ public class AttachmentUtil { try { MessageRecord message = SignalDatabase.messages().getMessageRecord(attachment.getMmsId()); - Recipient individualRecipient = message.getRecipient(); - Recipient threadRecipient = SignalDatabase.threads().getRecipientForThreadId(message.getThreadId()); + Recipient fromRecipient = message.getFromRecipient(); + Recipient toRecipient = message.getToRecipient(); - if (threadRecipient != null && threadRecipient.isGroup()) { - return threadRecipient.isProfileSharing() || isTrustedIndividual(individualRecipient, message); + if (toRecipient != null && toRecipient.isGroup()) { + return toRecipient.isProfileSharing() || isTrustedIndividual(fromRecipient, message); } else { - return isTrustedIndividual(individualRecipient, message); + return isTrustedIndividual(fromRecipient, message); } } catch (NoSuchMessageException e) { Log.w(TAG, "Message could not be found! Assuming not a trusted contact."); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/RemoteDeleteUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/RemoteDeleteUtil.java index 62e66653e4..f006fc3466 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/RemoteDeleteUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/RemoteDeleteUtil.java @@ -28,7 +28,7 @@ public final class RemoteDeleteUtil { boolean isValidIncomingOutgoing = (selfIsDeleteSender && targetMessage.isOutgoing()) || (!selfIsDeleteSender && !targetMessage.isOutgoing()); - boolean isValidSender = targetMessage.getIndividualRecipient().getId().equals(deleteSenderId) || selfIsDeleteSender && targetMessage.isOutgoing(); + boolean isValidSender = targetMessage.getFromRecipient().getId().equals(deleteSenderId) || selfIsDeleteSender && targetMessage.isOutgoing(); long messageTimestamp = selfIsDeleteSender && targetMessage.isOutgoing() ? targetMessage.getDateSent() : targetMessage.getServerTimestamp(); @@ -47,11 +47,11 @@ public final class RemoteDeleteUtil { return !message.isUpdate() && message.isOutgoing() && message.isPush() && - (!message.getRecipient().isGroup() || message.getRecipient().isActiveGroup()) && + (!message.getToRecipient().isGroup() || message.getToRecipient().isActiveGroup()) && !message.isRemoteDelete() && !MessageRecordUtil.hasGiftBadge(message) && !message.isPaymentNotification() && - (((currentTime - message.getDateSent()) < SEND_THRESHOLD) || message.getRecipient().isSelf()); + (((currentTime - message.getDateSent()) < SEND_THRESHOLD) || message.getToRecipient().isSelf()); } private static boolean isSelf(@NonNull RecipientId recipientId) { diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/FakeMessageRecords.kt b/app/src/test/java/org/thoughtcrime/securesms/database/FakeMessageRecords.kt index 0d7d76bb97..255a77dec2 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/FakeMessageRecords.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/FakeMessageRecords.kt @@ -143,8 +143,8 @@ object FakeMessageRecords { return MediaMmsMessageRecord( id, conversationRecipient, - individualRecipient, recipientDeviceId, + individualRecipient, dateSent, dateReceived, dateServer, diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/TestMms.kt b/app/src/test/java/org/thoughtcrime/securesms/database/TestMms.kt index e57f4aa735..684fc944f1 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/TestMms.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/TestMms.kt @@ -67,7 +67,7 @@ object TestMms { fun insert( db: SQLiteDatabase, message: OutgoingMessage, - recipientId: RecipientId = message.recipient.id, + recipientId: RecipientId = message.threadRecipient.id, body: String = message.body, type: Long = MessageTypes.BASE_INBOX_TYPE, unread: Boolean = false, @@ -86,7 +86,8 @@ object TestMms { put(MessageTable.SMS_SUBSCRIPTION_ID, message.subscriptionId) put(MessageTable.EXPIRES_IN, message.expiresIn) put(MessageTable.VIEW_ONCE, message.isViewOnce) - put(MessageTable.RECIPIENT_ID, recipientId.serialize()) + put(MessageTable.FROM_RECIPIENT_ID, recipientId.serialize()) + put(MessageTable.TO_RECIPIENT_ID, recipientId.serialize()) put(MessageTable.DELIVERY_RECEIPT_COUNT, 0) put(MessageTable.RECEIPT_TIMESTAMP, 0) put(MessageTable.VIEWED_RECEIPT_COUNT, if (viewed) 1 else 0) diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/TestSms.kt b/app/src/test/java/org/thoughtcrime/securesms/database/TestSms.kt index 1b6f3d4a93..1e9e301eb3 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/TestSms.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/TestSms.kt @@ -59,8 +59,9 @@ object TestSms { threadId: Long = 1 ): Long { val values = ContentValues().apply { - put(MessageTable.RECIPIENT_ID, message.sender.serialize()) - put(MessageTable.RECIPIENT_DEVICE_ID, message.senderDeviceId) + put(MessageTable.FROM_RECIPIENT_ID, message.authorId.serialize()) + put(MessageTable.FROM_DEVICE_ID, message.authorDeviceId) + put(MessageTable.TO_RECIPIENT_ID, message.authorId.serialize()) put(MessageTable.DATE_RECEIVED, message.receivedTimestampMillis) put(MessageTable.DATE_SENT, message.sentTimestampMillis) put(MessageTable.DATE_SERVER, message.serverTimestampMillis) diff --git a/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt b/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt index efb28314c6..e98da4a115 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt @@ -167,8 +167,8 @@ class UploadDependencyGraphTest { // GIVEN val attachment1 = UriAttachmentBuilder.build(uniqueLong.getAndIncrement(), contentType = MediaUtil.IMAGE_JPEG) val attachment2 = UriAttachmentBuilder.build(uniqueLong.getAndIncrement(), contentType = MediaUtil.IMAGE_JPEG) - val message1 = OutgoingMessage(recipient = Recipient.UNKNOWN, sentTimeMillis = System.currentTimeMillis(), attachments = listOf(attachment1)) - val message2 = OutgoingMessage(recipient = Recipient.UNKNOWN, sentTimeMillis = System.currentTimeMillis() + 1, attachments = listOf(attachment2)) + val message1 = OutgoingMessage(threadRecipient = Recipient.UNKNOWN, sentTimeMillis = System.currentTimeMillis(), attachments = listOf(attachment1)) + val message2 = OutgoingMessage(threadRecipient = Recipient.UNKNOWN, sentTimeMillis = System.currentTimeMillis() + 1, attachments = listOf(attachment2)) val testSubject = UploadDependencyGraph.create(listOf(message1, message2), jobManager) { getAttachmentForPreUpload(uniqueLong.getAndIncrement(), it) } // WHEN @@ -191,7 +191,7 @@ class UploadDependencyGraphTest { ) } - val message = OutgoingMessage(recipient = Recipient.UNKNOWN, sentTimeMillis = System.currentTimeMillis(), attachments = uriAttachments) + val message = OutgoingMessage(threadRecipient = Recipient.UNKNOWN, sentTimeMillis = System.currentTimeMillis(), attachments = uriAttachments) val testSubject = UploadDependencyGraph.create(listOf(message), jobManager) { getAttachmentForPreUpload(uniqueLong.getAndIncrement(), it) } val result = testSubject.consumeDeferredQueue() @@ -262,7 +262,7 @@ class UploadDependencyGraphTest { private fun Iterable.createMessages(uriAttachments: List): List { return mapIndexed { index, _ -> OutgoingMessage( - recipient = Recipient.UNKNOWN, + threadRecipient = Recipient.UNKNOWN, sentTimeMillis = System.currentTimeMillis() + index, attachments = uriAttachments, isSecure = true