Improve conversation query performance.

For the conversation query at least, we stopped joining on the
attachments tables, and instead get attachments on a page-by-page basis.
fork-5.53.8
Greyson Parrelli 2021-06-16 18:26:24 -04:00 zatwierdzone przez Cody Henthorne
rodzic 263ddb0d1e
commit fa26fb6b8b
6 zmienionych plików z 259 dodań i 107 usunięć

Wyświetl plik

@ -9,14 +9,17 @@ import com.annimon.stream.Stream;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.signal.paging.PagedDataSource; import org.signal.paging.PagedDataSource;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.conversation.ConversationData.MessageRequestData; import org.thoughtcrime.securesms.conversation.ConversationData.MessageRequestData;
import org.thoughtcrime.securesms.conversation.ConversationMessage.ConversationMessageFactory; import org.thoughtcrime.securesms.conversation.ConversationMessage.ConversationMessageFactory;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsSmsDatabase; import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord; import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.Mention; import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.util.Stopwatch; import org.thoughtcrime.securesms.util.Stopwatch;
import org.thoughtcrime.securesms.util.Util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -24,6 +27,7 @@ import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
/** /**
* Core data source for loading an individual conversation. * Core data source for loading an individual conversation.
@ -58,16 +62,18 @@ class ConversationDataSource implements PagedDataSource<ConversationMessage> {
@Override @Override
public @NonNull List<ConversationMessage> load(int start, int length, @NonNull CancellationSignal cancellationSignal) { public @NonNull List<ConversationMessage> load(int start, int length, @NonNull CancellationSignal cancellationSignal) {
Stopwatch stopwatch = new Stopwatch("load(" + start + ", " + length + "), thread " + threadId); Stopwatch stopwatch = new Stopwatch("load(" + start + ", " + length + "), thread " + threadId);
MmsSmsDatabase db = DatabaseFactory.getMmsSmsDatabase(context); MmsSmsDatabase db = DatabaseFactory.getMmsSmsDatabase(context);
List<MessageRecord> records = new ArrayList<>(length); List<MessageRecord> records = new ArrayList<>(length);
MentionHelper mentionHelper = new MentionHelper(); MentionHelper mentionHelper = new MentionHelper();
AttachmentHelper attachmentHelper = new AttachmentHelper();
try (MmsSmsDatabase.Reader reader = MmsSmsDatabase.readerFor(db.getConversation(threadId, start, length))) { try (MmsSmsDatabase.Reader reader = MmsSmsDatabase.readerFor(db.getConversation(threadId, start, length))) {
MessageRecord record; MessageRecord record;
while ((record = reader.getNext()) != null && !cancellationSignal.isCanceled()) { while ((record = reader.getNext()) != null && !cancellationSignal.isCanceled()) {
records.add(record); records.add(record);
mentionHelper.add(record); mentionHelper.add(record);
attachmentHelper.add(record);
} }
} }
@ -85,6 +91,12 @@ class ConversationDataSource implements PagedDataSource<ConversationMessage> {
stopwatch.split("mentions"); stopwatch.split("mentions");
attachmentHelper.fetchAttachments(context);
stopwatch.split("attachments");
records = attachmentHelper.buildUpdatedModels(context, records);
List<ConversationMessage> messages = Stream.of(records) List<ConversationMessage> messages = Stream.of(records)
.map(m -> ConversationMessageFactory.createWithUnresolvedData(context, m, mentionHelper.getMentions(m.getId()))) .map(m -> ConversationMessageFactory.createWithUnresolvedData(context, m, mentionHelper.getMentions(m.getId())))
.toList(); .toList();
@ -114,4 +126,37 @@ class ConversationDataSource implements PagedDataSource<ConversationMessage> {
return messageIdToMentions.get(id); return messageIdToMentions.get(id);
} }
} }
private static class AttachmentHelper {
private Collection<Long> messageIds = new LinkedList<>();
private Map<Long, List<DatabaseAttachment>> messageIdToAttachments = new HashMap<>();
void add(MessageRecord record) {
if (record.isMms()) {
messageIds.add(record.getId());
}
}
void fetchAttachments(Context context) {
messageIdToAttachments = DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessages(messageIds);
}
@NonNull List<MessageRecord> buildUpdatedModels(@NonNull Context context, @NonNull List<MessageRecord> records) {
return records.stream()
.map(record -> {
if (record instanceof MediaMmsMessageRecord) {
List<DatabaseAttachment> attachments = messageIdToAttachments.get(record.getId());
if (Util.hasItems(attachments)) {
return ((MediaMmsMessageRecord) record).withAttachments(context, attachments);
}
}
return record;
})
.collect(Collectors.toList());
}
}
} }

Wyświetl plik

@ -60,6 +60,7 @@ import org.thoughtcrime.securesms.util.FileUtils;
import org.thoughtcrime.securesms.util.JsonUtils; import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.SetUtil; import org.thoughtcrime.securesms.util.SetUtil;
import org.thoughtcrime.securesms.util.SqlUtil;
import org.thoughtcrime.securesms.util.StorageUtil; import org.thoughtcrime.securesms.util.StorageUtil;
import org.thoughtcrime.securesms.video.EncryptedMediaDataSource; import org.thoughtcrime.securesms.video.EncryptedMediaDataSource;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
@ -236,7 +237,7 @@ public class AttachmentDatabase extends Database {
cursor = database.query(TABLE_NAME, PROJECTION, PART_ID_WHERE, attachmentId.toStrings(), null, null, null); cursor = database.query(TABLE_NAME, PROJECTION, PART_ID_WHERE, attachmentId.toStrings(), null, null, null);
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
List<DatabaseAttachment> list = getAttachment(cursor); List<DatabaseAttachment> list = getAttachments(cursor);
if (list != null && list.size() > 0) { if (list != null && list.size() > 0) {
return list.get(0); return list.get(0);
@ -260,7 +261,7 @@ public class AttachmentDatabase extends Database {
null, null, UNIQUE_ID + " ASC, " + ROW_ID + " ASC"); null, null, UNIQUE_ID + " ASC, " + ROW_ID + " ASC");
while (cursor != null && cursor.moveToNext()) { while (cursor != null && cursor.moveToNext()) {
results.addAll(getAttachment(cursor)); results.addAll(getAttachments(cursor));
} }
return results; return results;
@ -270,6 +271,33 @@ public class AttachmentDatabase extends Database {
} }
} }
public @NonNull Map<Long, List<DatabaseAttachment>> getAttachmentsForMessages(@NonNull Collection<Long> mmsIds) {
if (mmsIds.isEmpty()) {
return Collections.emptyMap();
}
SQLiteDatabase database = databaseHelper.getReadableDatabase();
SqlUtil.Query query = SqlUtil.buildCollectionQuery(MMS_ID, mmsIds);
Map<Long, List<DatabaseAttachment>> output = new HashMap<>();
try (Cursor cursor = database.query(TABLE_NAME, PROJECTION, query.getWhere(), query.getWhereArgs(), null, null, UNIQUE_ID + " ASC, " + ROW_ID + " ASC")) {
while (cursor.moveToNext()) {
DatabaseAttachment attachment = getAttachment(cursor);
List<DatabaseAttachment> attachments = output.get(attachment.getMmsId());
if (attachments == null) {
attachments = new LinkedList<>();
output.put(attachment.getMmsId(), attachments);
}
attachments.add(attachment);
}
}
return output;
}
public boolean hasAttachment(@NonNull AttachmentId id) { public boolean hasAttachment(@NonNull AttachmentId id) {
SQLiteDatabase database = databaseHelper.getReadableDatabase(); SQLiteDatabase database = databaseHelper.getReadableDatabase();
@ -304,7 +332,7 @@ public class AttachmentDatabase extends Database {
try { try {
cursor = database.query(TABLE_NAME, PROJECTION, TRANSFER_STATE + " = ?", new String[] {String.valueOf(TRANSFER_PROGRESS_STARTED)}, null, null, null); cursor = database.query(TABLE_NAME, PROJECTION, TRANSFER_STATE + " = ?", new String[] {String.valueOf(TRANSFER_PROGRESS_STARTED)}, null, null, null);
while (cursor != null && cursor.moveToNext()) { while (cursor != null && cursor.moveToNext()) {
attachments.addAll(getAttachment(cursor)); attachments.addAll(getAttachments(cursor));
} }
} finally { } finally {
if (cursor != null) cursor.close(); if (cursor != null) cursor.close();
@ -1116,7 +1144,7 @@ public class AttachmentDatabase extends Database {
return Pair.create(selector, selection); return Pair.create(selector, selection);
} }
public List<DatabaseAttachment> getAttachment(@NonNull Cursor cursor) { public List<DatabaseAttachment> getAttachments(@NonNull Cursor cursor) {
try { try {
if (cursor.getColumnIndex(AttachmentDatabase.ATTACHMENT_JSON_ALIAS) != -1) { if (cursor.getColumnIndex(AttachmentDatabase.ATTACHMENT_JSON_ALIAS) != -1) {
if (cursor.isNull(cursor.getColumnIndexOrThrow(ATTACHMENT_JSON_ALIAS))) { if (cursor.isNull(cursor.getColumnIndexOrThrow(ATTACHMENT_JSON_ALIAS))) {
@ -1168,46 +1196,50 @@ public class AttachmentDatabase extends Database {
return result; return result;
} else { } else {
String contentType = cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_TYPE)); return Collections.singletonList(getAttachment(cursor));
return Collections.singletonList(new DatabaseAttachment(new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(ROW_ID)),
cursor.getLong(cursor.getColumnIndexOrThrow(UNIQUE_ID))),
cursor.getLong(cursor.getColumnIndexOrThrow(MMS_ID)),
!cursor.isNull(cursor.getColumnIndexOrThrow(DATA)),
MediaUtil.isImageType(contentType) || MediaUtil.isVideoType(contentType),
contentType,
cursor.getInt(cursor.getColumnIndexOrThrow(TRANSFER_STATE)),
cursor.getLong(cursor.getColumnIndexOrThrow(SIZE)),
cursor.getString(cursor.getColumnIndexOrThrow(FILE_NAME)),
cursor.getInt(cursor.getColumnIndexOrThrow(CDN_NUMBER)),
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_LOCATION)),
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_DISPOSITION)),
cursor.getString(cursor.getColumnIndexOrThrow(NAME)),
cursor.getBlob(cursor.getColumnIndexOrThrow(DIGEST)),
cursor.getString(cursor.getColumnIndexOrThrow(FAST_PREFLIGHT_ID)),
cursor.getInt(cursor.getColumnIndexOrThrow(VOICE_NOTE)) == 1,
cursor.getInt(cursor.getColumnIndexOrThrow(BORDERLESS)) == 1,
cursor.getInt(cursor.getColumnIndexOrThrow(VIDEO_GIF)) == 1,
cursor.getInt(cursor.getColumnIndexOrThrow(WIDTH)),
cursor.getInt(cursor.getColumnIndexOrThrow(HEIGHT)),
cursor.getInt(cursor.getColumnIndexOrThrow(QUOTE)) == 1,
cursor.getString(cursor.getColumnIndexOrThrow(CAPTION)),
cursor.getInt(cursor.getColumnIndexOrThrow(STICKER_ID)) >= 0
? new StickerLocator(CursorUtil.requireString(cursor, STICKER_PACK_ID),
CursorUtil.requireString(cursor, STICKER_PACK_KEY),
CursorUtil.requireInt(cursor, STICKER_ID),
CursorUtil.requireString(cursor, STICKER_EMOJI))
: null,
MediaUtil.isAudioType(contentType) ? null : BlurHash.parseOrNull(cursor.getString(cursor.getColumnIndexOrThrow(VISUAL_HASH))),
MediaUtil.isAudioType(contentType) ? AudioHash.parseOrNull(cursor.getString(cursor.getColumnIndexOrThrow(VISUAL_HASH))) : null,
TransformProperties.parse(cursor.getString(cursor.getColumnIndexOrThrow(TRANSFORM_PROPERTIES))),
cursor.getInt(cursor.getColumnIndexOrThrow(DISPLAY_ORDER)),
cursor.getLong(cursor.getColumnIndexOrThrow(UPLOAD_TIMESTAMP))));
} }
} catch (JSONException e) { } catch (JSONException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
} }
private @NonNull DatabaseAttachment getAttachment(@NonNull Cursor cursor) {
String contentType = cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_TYPE));
return new DatabaseAttachment(new AttachmentId(cursor.getLong(cursor.getColumnIndexOrThrow(ROW_ID)),
cursor.getLong(cursor.getColumnIndexOrThrow(UNIQUE_ID))),
cursor.getLong(cursor.getColumnIndexOrThrow(MMS_ID)),
!cursor.isNull(cursor.getColumnIndexOrThrow(DATA)),
MediaUtil.isImageType(contentType) || MediaUtil.isVideoType(contentType),
contentType,
cursor.getInt(cursor.getColumnIndexOrThrow(TRANSFER_STATE)),
cursor.getLong(cursor.getColumnIndexOrThrow(SIZE)),
cursor.getString(cursor.getColumnIndexOrThrow(FILE_NAME)),
cursor.getInt(cursor.getColumnIndexOrThrow(CDN_NUMBER)),
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_LOCATION)),
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_DISPOSITION)),
cursor.getString(cursor.getColumnIndexOrThrow(NAME)),
cursor.getBlob(cursor.getColumnIndexOrThrow(DIGEST)),
cursor.getString(cursor.getColumnIndexOrThrow(FAST_PREFLIGHT_ID)),
cursor.getInt(cursor.getColumnIndexOrThrow(VOICE_NOTE)) == 1,
cursor.getInt(cursor.getColumnIndexOrThrow(BORDERLESS)) == 1,
cursor.getInt(cursor.getColumnIndexOrThrow(VIDEO_GIF)) == 1,
cursor.getInt(cursor.getColumnIndexOrThrow(WIDTH)),
cursor.getInt(cursor.getColumnIndexOrThrow(HEIGHT)),
cursor.getInt(cursor.getColumnIndexOrThrow(QUOTE)) == 1,
cursor.getString(cursor.getColumnIndexOrThrow(CAPTION)),
cursor.getInt(cursor.getColumnIndexOrThrow(STICKER_ID)) >= 0
? new StickerLocator(CursorUtil.requireString(cursor, STICKER_PACK_ID),
CursorUtil.requireString(cursor, STICKER_PACK_KEY),
CursorUtil.requireInt(cursor, STICKER_ID),
CursorUtil.requireString(cursor, STICKER_EMOJI))
: null,
MediaUtil.isAudioType(contentType) ? null : BlurHash.parseOrNull(cursor.getString(cursor.getColumnIndexOrThrow(VISUAL_HASH))),
MediaUtil.isAudioType(contentType) ? AudioHash.parseOrNull(cursor.getString(cursor.getColumnIndexOrThrow(VISUAL_HASH))) : null,
TransformProperties.parse(cursor.getString(cursor.getColumnIndexOrThrow(TRANSFORM_PROPERTIES))),
cursor.getInt(cursor.getColumnIndexOrThrow(DISPLAY_ORDER)),
cursor.getLong(cursor.getColumnIndexOrThrow(UPLOAD_TIMESTAMP)));
}
private AttachmentId insertAttachment(long mmsId, Attachment attachment, boolean quote) private AttachmentId insertAttachment(long mmsId, Attachment attachment, boolean quote)
throws MmsException throws MmsException
{ {
@ -1309,7 +1341,7 @@ public class AttachmentDatabase extends Database {
try (Cursor cursor = databaseHelper.getWritableDatabase().query(TABLE_NAME, null, selection, args, null, null, null)) { try (Cursor cursor = databaseHelper.getWritableDatabase().query(TABLE_NAME, null, selection, args, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
return getAttachment(cursor).get(0); return getAttachments(cursor).get(0);
} }
} }

Wyświetl plik

@ -205,7 +205,7 @@ public class MediaDatabase extends Database {
public static MediaRecord from(@NonNull Context context, @NonNull Cursor cursor) { public static MediaRecord from(@NonNull Context context, @NonNull Cursor cursor) {
AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context); AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context);
List<DatabaseAttachment> attachments = attachmentDatabase.getAttachment(cursor); List<DatabaseAttachment> attachments = attachmentDatabase.getAttachments(cursor);
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.RECIPIENT_ID))); RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.RECIPIENT_ID)));
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID)); long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
boolean outgoing = MessageDatabase.Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX))); boolean outgoing = MessageDatabase.Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX)));

Wyświetl plik

@ -1252,6 +1252,7 @@ public class MmsDatabase extends MessageDatabase {
Avatar updatedAvatar = new Avatar(contact.getAvatar().getAttachmentId(), Avatar updatedAvatar = new Avatar(contact.getAvatar().getAttachmentId(),
attachment, attachment,
contact.getAvatar().isProfile()); contact.getAvatar().isProfile());
contacts.add(new Contact(contact, updatedAvatar)); contacts.add(new Contact(contact, updatedAvatar));
} else { } else {
contacts.add(contact); contacts.add(contact);
@ -1289,6 +1290,8 @@ public class MmsDatabase extends MessageDatabase {
DatabaseAttachment attachment = attachmentIdMap.get(preview.getAttachmentId()); DatabaseAttachment attachment = attachmentIdMap.get(preview.getAttachmentId());
if (attachment != null) { if (attachment != null) {
previews.add(new LinkPreview(preview.getUrl(), preview.getTitle(), preview.getDescription(), preview.getDate(), attachment)); previews.add(new LinkPreview(preview.getUrl(), preview.getTitle(), preview.getDescription(), preview.getDate(), attachment));
} else {
previews.add(preview);
} }
} else { } else {
previews.add(preview); previews.add(preview);
@ -2084,12 +2087,12 @@ public class MmsDatabase extends MessageDatabase {
Recipient recipient = Recipient.live(RecipientId.from(recipientId)).get(); Recipient recipient = Recipient.live(RecipientId.from(recipientId)).get();
List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument); List<IdentityKeyMismatch> mismatches = getMismatchedIdentities(mismatchDocument);
List<NetworkFailure> networkFailures = getFailures(networkDocument); List<NetworkFailure> networkFailures = getFailures(networkDocument);
List<DatabaseAttachment> attachments = DatabaseFactory.getAttachmentDatabase(context).getAttachment(cursor); List<DatabaseAttachment> attachments = DatabaseFactory.getAttachmentDatabase(context).getAttachments(cursor);
List<Contact> contacts = getSharedContacts(cursor, attachments); List<Contact> contacts = getSharedContacts(cursor, attachments);
Set<Attachment> contactAttachments = Stream.of(contacts).map(Contact::getAvatarAttachment).withoutNulls().collect(Collectors.toSet()); Set<Attachment> contactAttachments = Stream.of(contacts).map(Contact::getAvatarAttachment).withoutNulls().collect(Collectors.toSet());
List<LinkPreview> previews = getLinkPreviews(cursor, attachments); List<LinkPreview> previews = getLinkPreviews(cursor, attachments);
Set<Attachment> previewAttachments = Stream.of(previews).filter(lp -> lp.getThumbnail().isPresent()).map(lp -> lp.getThumbnail().get()).collect(Collectors.toSet()); Set<Attachment> previewAttachments = Stream.of(previews).filter(lp -> lp.getThumbnail().isPresent()).map(lp -> lp.getThumbnail().get()).collect(Collectors.toSet());
SlideDeck slideDeck = getSlideDeck(Stream.of(attachments).filterNot(contactAttachments::contains).filterNot(previewAttachments::contains).toList()); SlideDeck slideDeck = buildSlideDeck(context, Stream.of(attachments).filterNot(contactAttachments::contains).filterNot(previewAttachments::contains).toList());
Quote quote = getQuote(cursor); Quote quote = getQuote(cursor);
return new MediaMmsMessageRecord(id, recipient, recipient, return new MediaMmsMessageRecord(id, recipient, recipient,
@ -2124,7 +2127,7 @@ public class MmsDatabase extends MessageDatabase {
return new LinkedList<>(); return new LinkedList<>();
} }
private SlideDeck getSlideDeck(@NonNull List<DatabaseAttachment> attachments) { public static SlideDeck buildSlideDeck(@NonNull Context context, @NonNull List<DatabaseAttachment> attachments) {
List<DatabaseAttachment> messageAttachments = Stream.of(attachments) List<DatabaseAttachment> messageAttachments = Stream.of(attachments)
.filterNot(Attachment::isQuote) .filterNot(Attachment::isQuote)
.sorted(new DatabaseAttachment.DisplayOrderComparator()) .sorted(new DatabaseAttachment.DisplayOrderComparator())
@ -2138,7 +2141,7 @@ public class MmsDatabase extends MessageDatabase {
CharSequence quoteText = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.QUOTE_BODY)); CharSequence quoteText = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.QUOTE_BODY));
boolean quoteMissing = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.QUOTE_MISSING)) == 1; boolean quoteMissing = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.QUOTE_MISSING)) == 1;
List<Mention> quoteMentions = parseQuoteMentions(context, cursor); List<Mention> quoteMentions = parseQuoteMentions(context, cursor);
List<DatabaseAttachment> attachments = DatabaseFactory.getAttachmentDatabase(context).getAttachment(cursor); List<DatabaseAttachment> attachments = DatabaseFactory.getAttachmentDatabase(context).getAttachments(cursor);
List<? extends Attachment> quoteAttachments = Stream.of(attachments).filter(Attachment::isQuote).toList(); List<? extends Attachment> quoteAttachments = Stream.of(attachments).filter(Attachment::isQuote).toList();
SlideDeck quoteDeck = new SlideDeck(context, quoteAttachments); SlideDeck quoteDeck = new SlideDeck(context, quoteAttachments);

Wyświetl plik

@ -183,11 +183,13 @@ public class MmsSmsDatabase extends Database {
public Cursor getConversation(long threadId, long offset, long limit) { public Cursor getConversation(long threadId, long offset, long limit) {
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC"; SQLiteDatabase db = databaseHelper.getReadableDatabase();
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId; String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
String limitStr = limit > 0 || offset > 0 ? offset + ", " + limit : null; String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
String limitStr = limit > 0 || offset > 0 ? offset + ", " + limit : null;
String query = buildQuery(PROJECTION, selection, order, limitStr, false);
Cursor cursor = queryTables(PROJECTION, selection, order, limitStr); Cursor cursor = db.rawQuery(query, null);
setNotifyConversationListeners(cursor, threadId); setNotifyConversationListeners(cursor, threadId);
return cursor; return cursor;
@ -585,43 +587,46 @@ public class MmsSmsDatabase extends Database {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
private Cursor queryTables(String[] projection, String selection, String order, String limit) { private static @NonNull String buildQuery(String[] projection, String selection, String order, String limit, boolean includeAttachments) {
String attachmentJsonJoin;
if (includeAttachments) {
attachmentJsonJoin = "json_group_array(json_object(" + "'" + AttachmentDatabase.ROW_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + ", " +
"'" + AttachmentDatabase.UNIQUE_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UNIQUE_ID + ", " +
"'" + AttachmentDatabase.MMS_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + "," +
"'" + AttachmentDatabase.SIZE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.SIZE + ", " +
"'" + AttachmentDatabase.FILE_NAME + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.FILE_NAME + ", " +
"'" + AttachmentDatabase.DATA + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DATA + ", " +
"'" + AttachmentDatabase.CONTENT_TYPE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_TYPE + ", " +
"'" + AttachmentDatabase.CDN_NUMBER + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CDN_NUMBER + ", " +
"'" + AttachmentDatabase.CONTENT_LOCATION + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_LOCATION + ", " +
"'" + AttachmentDatabase.FAST_PREFLIGHT_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.FAST_PREFLIGHT_ID + ", " +
"'" + AttachmentDatabase.VOICE_NOTE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.VOICE_NOTE + ", " +
"'" + AttachmentDatabase.BORDERLESS + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.BORDERLESS + ", " +
"'" + AttachmentDatabase.VIDEO_GIF + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.VIDEO_GIF + ", " +
"'" + AttachmentDatabase.WIDTH + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.WIDTH + ", " +
"'" + AttachmentDatabase.HEIGHT + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.HEIGHT + ", " +
"'" + AttachmentDatabase.QUOTE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.QUOTE + ", " +
"'" + AttachmentDatabase.CONTENT_DISPOSITION + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_DISPOSITION + ", " +
"'" + AttachmentDatabase.NAME + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.NAME + ", " +
"'" + AttachmentDatabase.TRANSFER_STATE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFER_STATE + ", " +
"'" + AttachmentDatabase.CAPTION + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CAPTION + ", " +
"'" + AttachmentDatabase.STICKER_PACK_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_PACK_ID + ", " +
"'" + AttachmentDatabase.STICKER_PACK_KEY + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_PACK_KEY + ", " +
"'" + AttachmentDatabase.STICKER_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_ID + ", " +
"'" + AttachmentDatabase.STICKER_EMOJI + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_EMOJI + ", " +
"'" + AttachmentDatabase.VISUAL_HASH + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.VISUAL_HASH + ", " +
"'" + AttachmentDatabase.TRANSFORM_PROPERTIES + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFORM_PROPERTIES + ", " +
"'" + AttachmentDatabase.DISPLAY_ORDER + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DISPLAY_ORDER + ", " +
"'" + AttachmentDatabase.UPLOAD_TIMESTAMP + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UPLOAD_TIMESTAMP + "))";
} else {
attachmentJsonJoin = "NULL";
}
String[] mmsProjection = {MmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT, String[] mmsProjection = {MmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED, MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID + " AS " + MmsSmsColumns.ID, MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID + " AS " + MmsSmsColumns.ID,
"'MMS::' || " + MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID "'MMS::' || " + MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID + " || '::' || " + MmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.UNIQUE_ROW_ID,
+ " || '::' || " + MmsDatabase.DATE_SENT attachmentJsonJoin + " AS " + AttachmentDatabase.ATTACHMENT_JSON_ALIAS,
+ " AS " + MmsSmsColumns.UNIQUE_ROW_ID,
"json_group_array(json_object(" +
"'" + AttachmentDatabase.ROW_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.ROW_ID + ", " +
"'" + AttachmentDatabase.UNIQUE_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UNIQUE_ID + ", " +
"'" + AttachmentDatabase.MMS_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + "," +
"'" + AttachmentDatabase.SIZE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.SIZE + ", " +
"'" + AttachmentDatabase.FILE_NAME + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.FILE_NAME + ", " +
"'" + AttachmentDatabase.DATA + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DATA + ", " +
"'" + AttachmentDatabase.CONTENT_TYPE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_TYPE + ", " +
"'" + AttachmentDatabase.CDN_NUMBER + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CDN_NUMBER + ", " +
"'" + AttachmentDatabase.CONTENT_LOCATION + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_LOCATION + ", " +
"'" + AttachmentDatabase.FAST_PREFLIGHT_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.FAST_PREFLIGHT_ID + ", " +
"'" + AttachmentDatabase.VOICE_NOTE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.VOICE_NOTE + ", " +
"'" + AttachmentDatabase.BORDERLESS + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.BORDERLESS + ", " +
"'" + AttachmentDatabase.VIDEO_GIF + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.VIDEO_GIF + ", " +
"'" + AttachmentDatabase.WIDTH + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.WIDTH + ", " +
"'" + AttachmentDatabase.HEIGHT + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.HEIGHT + ", " +
"'" + AttachmentDatabase.QUOTE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.QUOTE + ", " +
"'" + AttachmentDatabase.CONTENT_DISPOSITION + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CONTENT_DISPOSITION + ", " +
"'" + AttachmentDatabase.NAME + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.NAME + ", " +
"'" + AttachmentDatabase.TRANSFER_STATE + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFER_STATE + ", " +
"'" + AttachmentDatabase.CAPTION + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.CAPTION + ", " +
"'" + AttachmentDatabase.STICKER_PACK_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_PACK_ID + ", " +
"'" + AttachmentDatabase.STICKER_PACK_KEY + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_PACK_KEY + ", " +
"'" + AttachmentDatabase.STICKER_ID + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_ID + ", " +
"'" + AttachmentDatabase.STICKER_EMOJI + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.STICKER_EMOJI + ", " +
"'" + AttachmentDatabase.VISUAL_HASH + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.VISUAL_HASH + ", " +
"'" + AttachmentDatabase.TRANSFORM_PROPERTIES + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFORM_PROPERTIES + ", " +
"'" + AttachmentDatabase.DISPLAY_ORDER + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DISPLAY_ORDER + ", " +
"'" + AttachmentDatabase.UPLOAD_TIMESTAMP + "', " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.UPLOAD_TIMESTAMP +
")) AS " + AttachmentDatabase.ATTACHMENT_JSON_ALIAS,
SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID, SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID,
SmsDatabase.TYPE, SmsDatabase.RECIPIENT_ID, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE, SmsDatabase.TYPE, SmsDatabase.RECIPIENT_ID, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT, MmsDatabase.MESSAGE_BOX, SmsDatabase.STATUS, MmsDatabase.PART_COUNT,
@ -653,10 +658,7 @@ public class MmsSmsDatabase extends Database {
String[] smsProjection = {SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT, String[] smsProjection = {SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED, SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
MmsSmsColumns.ID, MmsSmsColumns.ID, "'SMS::' || " + MmsSmsColumns.ID + " || '::' || " + SmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.UNIQUE_ROW_ID,
"'SMS::' || " + MmsSmsColumns.ID
+ " || '::' || " + SmsDatabase.DATE_SENT
+ " AS " + MmsSmsColumns.UNIQUE_ROW_ID,
"NULL AS " + AttachmentDatabase.ATTACHMENT_JSON_ALIAS, "NULL AS " + AttachmentDatabase.ATTACHMENT_JSON_ALIAS,
SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID, SmsDatabase.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID,
SmsDatabase.TYPE, SmsDatabase.RECIPIENT_ID, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE, SmsDatabase.TYPE, SmsDatabase.RECIPIENT_ID, SmsDatabase.ADDRESS_DEVICE_ID, SmsDatabase.SUBJECT, MmsDatabase.MESSAGE_TYPE,
@ -690,14 +692,19 @@ public class MmsSmsDatabase extends Database {
SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder(); SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder(); SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
mmsQueryBuilder.setDistinct(true); if (includeAttachments) {
smsQueryBuilder.setDistinct(true); mmsQueryBuilder.setDistinct(true);
smsQueryBuilder.setDistinct(true);
}
smsQueryBuilder.setTables(SmsDatabase.TABLE_NAME); smsQueryBuilder.setTables(SmsDatabase.TABLE_NAME);
mmsQueryBuilder.setTables(MmsDatabase.TABLE_NAME + " LEFT OUTER JOIN " +
AttachmentDatabase.TABLE_NAME +
" ON " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + " = " + MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID);
if (includeAttachments) {
mmsQueryBuilder.setTables(MmsDatabase.TABLE_NAME + " LEFT OUTER JOIN " + AttachmentDatabase.TABLE_NAME +
" ON " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.MMS_ID + " = " + MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID);
} else {
mmsQueryBuilder.setTables(MmsDatabase.TABLE_NAME);
}
Set<String> mmsColumnsPresent = new HashSet<>(); Set<String> mmsColumnsPresent = new HashSet<>();
mmsColumnsPresent.add(MmsSmsColumns.ID); mmsColumnsPresent.add(MmsSmsColumns.ID);
@ -770,22 +777,24 @@ public class MmsSmsDatabase extends Database {
smsColumnsPresent.add(MmsDatabase.REMOTE_DELETED); smsColumnsPresent.add(MmsDatabase.REMOTE_DELETED);
smsColumnsPresent.add(MmsSmsColumns.NOTIFIED_TIMESTAMP); smsColumnsPresent.add(MmsSmsColumns.NOTIFIED_TIMESTAMP);
@SuppressWarnings("deprecation") String mmsGroupBy = includeAttachments ? MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID : null;
String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(TRANSPORT, mmsProjection, mmsColumnsPresent, 4, MMS_TRANSPORT, selection, null, MmsDatabase.TABLE_NAME + "." + MmsDatabase.ID, null);
@SuppressWarnings("deprecation") String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery(TRANSPORT, mmsProjection, mmsColumnsPresent, 4, MMS_TRANSPORT, selection, null, mmsGroupBy, null);
String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(TRANSPORT, smsProjection, smsColumnsPresent, 4, SMS_TRANSPORT, selection, null, null, null); String smsSubQuery = smsQueryBuilder.buildUnionSubQuery(TRANSPORT, smsProjection, smsColumnsPresent, 4, SMS_TRANSPORT, selection, null, null, null);
SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder(); SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder();
String unionQuery = unionQueryBuilder.buildUnionQuery(new String[] {smsSubQuery, mmsSubQuery}, order, limit); String unionQuery = unionQueryBuilder.buildUnionQuery(new String[] { smsSubQuery, mmsSubQuery }, order, limit);
SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder(); SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder();
outerQueryBuilder.setTables("(" + unionQuery + ")"); outerQueryBuilder.setTables("(" + unionQuery + ")");
@SuppressWarnings("deprecation") return outerQueryBuilder.buildQuery(projection, null, null, null, null, null, null);
String query = outerQueryBuilder.buildQuery(projection, null, null, null, null, null, null); }
SQLiteDatabase db = databaseHelper.getReadableDatabase(); private Cursor queryTables(String[] projection, String selection, String order, String limit) {
return db.rawQuery(query, null); String query = buildQuery(projection, selection, order, limit, true);
return databaseHelper.getReadableDatabase().rawQuery(query, null);
} }
public static Reader readerFor(@NonNull Cursor cursor) { public static Reader readerFor(@NonNull Cursor cursor) {

Wyświetl plik

@ -24,6 +24,9 @@ import androidx.annotation.Nullable;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.AttachmentId;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.contactshare.Contact; import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase.Status; import org.thoughtcrime.securesms.database.SmsDatabase.Status;
@ -32,8 +35,14 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.linkpreview.LinkPreview; import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/** /**
* Represents the message record model for MMS messages that contain * Represents the message record model for MMS messages that contain
@ -87,10 +96,6 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
this.mentionsSelf = mentionsSelf; this.mentionsSelf = mentionsSelf;
} }
public int getPartCount() {
return partCount;
}
@Override @Override
public boolean hasSelfMention() { public boolean hasSelfMention() {
return mentionsSelf; return mentionsSelf;
@ -115,4 +120,62 @@ public class MediaMmsMessageRecord extends MmsMessageRecord {
return super.getDisplayBody(context); return super.getDisplayBody(context);
} }
public int getPartCount() {
return partCount;
}
public MediaMmsMessageRecord withAttachments(@NonNull Context context, @NonNull List<DatabaseAttachment> attachments) {
Map<AttachmentId, DatabaseAttachment> attachmentIdMap = new HashMap<>();
for (DatabaseAttachment attachment : attachments) {
attachmentIdMap.put(attachment.getAttachmentId(), attachment);
}
List<Contact> contacts = updateContacts(getSharedContacts(), attachmentIdMap);
Set<Attachment> contactAttachments = contacts.stream().map(Contact::getAvatarAttachment).filter(Objects::nonNull).collect(Collectors.toSet());
List<LinkPreview> linkPreviews = updateLinkPreviews(getLinkPreviews(), attachmentIdMap);
Set<Attachment> linkPreviewAttachments = linkPreviews.stream().map(LinkPreview::getThumbnail).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toSet());
List<DatabaseAttachment> slideAttachments = attachments.stream().filter(a -> !contactAttachments.contains(a)).filter(a -> !linkPreviewAttachments.contains(a)).collect(Collectors.toList());
SlideDeck slideDeck = MmsDatabase.Reader.buildSlideDeck(context, slideAttachments);
return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), slideDeck,
getPartCount(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(),
getReadReceiptCount(), getQuote(), contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
getNotifiedTimestamp(), getViewedReceiptCount());
}
private static @NonNull List<Contact> updateContacts(@NonNull List<Contact> contacts, @NonNull Map<AttachmentId, DatabaseAttachment> attachmentIdMap) {
return contacts.stream()
.map(contact -> {
if (contact.getAvatar() != null) {
DatabaseAttachment attachment = attachmentIdMap.get(contact.getAvatar().getAttachmentId());
Contact.Avatar updatedAvatar = new Contact.Avatar(contact.getAvatar().getAttachmentId(),
attachment,
contact.getAvatar().isProfile());
return new Contact(contact, updatedAvatar);
} else {
return contact;
}
})
.collect(Collectors.toList());
}
private static @NonNull List<LinkPreview> updateLinkPreviews(@NonNull List<LinkPreview> linkPreviews, @NonNull Map<AttachmentId, DatabaseAttachment> attachmentIdMap) {
return linkPreviews.stream()
.map(preview -> {
if (preview.getAttachmentId() != null) {
DatabaseAttachment attachment = attachmentIdMap.get(preview.getAttachmentId());
if (attachment != null) {
return new LinkPreview(preview.getUrl(), preview.getTitle(), preview.getDescription(), preview.getDate(), attachment);
} else {
return preview;
}
} else {
return preview;
}
})
.collect(Collectors.toList());
}
} }