diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java index 866d355038..7f95a8ad78 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java @@ -6,6 +6,7 @@ public interface MmsSmsColumns { public static final String ID = "_id"; public static final String NORMALIZED_DATE_SENT = "date_sent"; public static final String NORMALIZED_DATE_RECEIVED = "date_received"; + public static final String NORMALIZED_TYPE = "type"; public static final String DATE_SERVER = "date_server"; public static final String THREAD_ID = "thread_id"; public static final String READ = "read"; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java index d149feed7e..c7806df89f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java @@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.notifications.v2.MessageNotifierV2; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.util.CursorUtil; +import org.thoughtcrime.securesms.util.SqlUtil; import org.whispersystems.libsignal.util.Pair; import java.io.Closeable; @@ -105,6 +106,14 @@ public class MmsSmsDatabase extends Database { MmsSmsColumns.NOTIFIED_TIMESTAMP, MmsSmsColumns.VIEWED_RECEIPT_COUNT}; + private static final String SNIPPET_QUERY = "SELECT " + MmsSmsColumns.ID + ", 0 AS " + TRANSPORT + ", " + SmsDatabase.TYPE + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + SmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + SmsDatabase.TABLE_NAME + " " + + "WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + SmsDatabase.TYPE + " NOT IN (" + SmsDatabase.Types.PROFILE_CHANGE_TYPE + ", " + SmsDatabase.Types.GV1_MIGRATION_TYPE + ") " + + "UNION ALL " + + "SELECT " + MmsSmsColumns.ID + ", 1 AS " + TRANSPORT + ", " + MmsDatabase.MESSAGE_BOX + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + MmsDatabase.TABLE_NAME + " " + + "WHERE " + MmsSmsColumns.THREAD_ID + " = ? " + + "ORDER BY " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC " + + "LIMIT 1"; + public MmsSmsDatabase(Context context, SQLCipherOpenHelper databaseHelper) { super(context, databaseHelper); } @@ -209,11 +218,33 @@ public class MmsSmsDatabase extends Database { return cursor; } - public Cursor getConversationSnippet(long threadId) { - String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC"; - String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND (" + SmsDatabase.TYPE + " IS NULL OR " + SmsDatabase.TYPE + " NOT IN (" + SmsDatabase.Types.PROFILE_CHANGE_TYPE + ", " + SmsDatabase.Types.GV1_MIGRATION_TYPE + "))"; + public @NonNull MessageRecord getConversationSnippet(long threadId) throws NoSuchMessageException { + SQLiteDatabase db = databaseHelper.getReadableDatabase(); + try (Cursor cursor = db.rawQuery(SNIPPET_QUERY, SqlUtil.buildArgs(threadId, threadId))) { + if (cursor.moveToFirst()) { + boolean isMms = CursorUtil.requireBoolean(cursor, TRANSPORT); + long id = CursorUtil.requireLong(cursor, MmsSmsColumns.ID); - return queryTables(PROJECTION, selection, order, "1"); + if (isMms) { + return DatabaseFactory.getMmsDatabase(context).getMessageRecord(id); + } else { + return DatabaseFactory.getSmsDatabase(context).getMessageRecord(id); + } + } else { + throw new NoSuchMessageException("no message"); + } + } + } + + public long getConversationSnippetType(long threadId) throws NoSuchMessageException { + SQLiteDatabase db = databaseHelper.getReadableDatabase(); + try (Cursor cursor = db.rawQuery(SNIPPET_QUERY, SqlUtil.buildArgs(threadId, threadId))) { + if (cursor.moveToFirst()) { + return CursorUtil.requireLong(cursor, MmsSmsColumns.NORMALIZED_TYPE); + } else { + throw new NoSuchMessageException("no message"); + } + } } public Cursor getUnread() { @@ -791,18 +822,6 @@ public class MmsSmsDatabase extends Database { return databaseHelper.getReadableDatabase().rawQuery(query, null); } - public static long getType(@NonNull Cursor cursor) { - String transportType = CursorUtil.requireString(cursor, TRANSPORT); - - if (MmsSmsDatabase.MMS_TRANSPORT.equals(transportType)) { - return CursorUtil.requireLong(cursor, MmsDatabase.MESSAGE_BOX); - } else if (MmsSmsDatabase.SMS_TRANSPORT.equals(transportType)) { - return CursorUtil.requireLong(cursor, SmsDatabase.TYPE); - } else { - throw new AssertionError("Bad transport type: " + transportType); - } - } - public static Reader readerFor(@NonNull Cursor cursor) { return new Reader(cursor); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java index 6d839a36c0..3cc72ffae4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -1226,8 +1226,8 @@ public class ThreadDatabase extends Database { } private boolean update(long threadId, boolean unarchive, boolean allowDeletion, boolean notifyListeners) { - MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context); - boolean meaningfulMessages = mmsSmsDatabase.hasMeaningfulMessage(threadId); + MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context); + boolean meaningfulMessages = mmsSmsDatabase.hasMeaningfulMessage(threadId); if (!meaningfulMessages) { if (allowDeletion) { @@ -1236,43 +1236,49 @@ public class ThreadDatabase extends Database { return true; } - try (MmsSmsDatabase.Reader reader = MmsSmsDatabase.readerFor(mmsSmsDatabase.getConversationSnippet(threadId))) { - MessageRecord record = reader.getNext(); - - if (record != null) { - updateThread(threadId, - meaningfulMessages, - ThreadBodyUtil.getFormattedBodyFor(context, record), - getAttachmentUriFor(record), - getContentTypeFor(record), - getExtrasFor(record), - record.getTimestamp(), - record.getDeliveryStatus(), - record.getDeliveryReceiptCount(), - record.getType(), - unarchive, - record.getExpiresIn(), - record.getReadReceiptCount()); - if (notifyListeners) { - notifyConversationListListeners(); - } - return false; - } else { + MessageRecord record; + try { + record = mmsSmsDatabase.getConversationSnippet(threadId); + } catch (NoSuchMessageException e) { + if (allowDeletion) { deleteConversation(threadId); - return true; } + return true; } + + updateThread(threadId, + meaningfulMessages, + ThreadBodyUtil.getFormattedBodyFor(context, record), + getAttachmentUriFor(record), + getContentTypeFor(record), + getExtrasFor(record), + record.getTimestamp(), + record.getDeliveryStatus(), + record.getDeliveryReceiptCount(), + record.getType(), + unarchive, + record.getExpiresIn(), + record.getReadReceiptCount()); + + if (notifyListeners) { + notifyConversationListListeners(); + } + + return false; } public void updateSnippetTypeSilently(long threadId) { - try (Cursor cursor = DatabaseFactory.getMmsSmsDatabase(context).getConversationSnippet(threadId)) { - if (cursor.moveToFirst()) { - ContentValues contentValues = new ContentValues(1); - contentValues.put(SNIPPET_TYPE, MmsSmsDatabase.getType(cursor)); - - databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, ID_WHERE, SqlUtil.buildArgs(threadId)); - } + long type; + try { + type = DatabaseFactory.getMmsSmsDatabase(context).getConversationSnippetType(threadId); + } catch (NoSuchMessageException e) { + throw new AssertionError(e); } + + ContentValues contentValues = new ContentValues(1); + contentValues.put(SNIPPET_TYPE, type); + + databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, ID_WHERE, SqlUtil.buildArgs(threadId)); } public @NonNull ThreadRecord getThreadRecordFor(@NonNull Recipient recipient) {