Store receipt fields as booleans instead of counts.

This commit is contained in:
Greyson Parrelli
2023-11-14 09:16:56 -08:00
parent 5e70c06075
commit e80b7cf0a2
24 changed files with 275 additions and 213 deletions

View File

@@ -37,6 +37,7 @@ import org.signal.core.util.SqlUtil.buildCustomCollectionQuery
import org.signal.core.util.SqlUtil.buildSingleCollectionQuery
import org.signal.core.util.SqlUtil.buildTrueUpdateQuery
import org.signal.core.util.SqlUtil.getNextAutoIncrementId
import org.signal.core.util.Stopwatch
import org.signal.core.util.count
import org.signal.core.util.delete
import org.signal.core.util.exists
@@ -164,9 +165,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
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"
const val HAS_DELIVERY_RECEIPT = "has_delivery_receipt"
const val HAS_READ_RECEIPT = "has_read_receipt"
const val VIEWED_COLUMN = "viewed"
const val MISMATCHED_IDENTITIES = "mismatched_identities"
const val SMS_SUBSCRIPTION_ID = "subscription_id"
const val EXPIRES_IN = "expires_in"
@@ -227,9 +228,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
$MMS_TRANSACTION_ID TEXT,
$SMS_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,
$HAS_DELIVERY_RECEIPT INTEGER DEFAULT 0,
$HAS_READ_RECEIPT INTEGER DEFAULT 0,
$VIEWED_COLUMN INTEGER DEFAULT 0,
$MISMATCHED_IDENTITIES TEXT DEFAULT NULL,
$NETWORK_FAILURES TEXT DEFAULT NULL,
$EXPIRES_IN INTEGER DEFAULT 0,
@@ -307,8 +308,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
FROM_RECIPIENT_ID,
FROM_DEVICE_ID,
TO_RECIPIENT_ID,
DELIVERY_RECEIPT_COUNT,
READ_RECEIPT_COUNT,
HAS_DELIVERY_RECEIPT,
HAS_READ_RECEIPT,
MISMATCHED_IDENTITIES,
NETWORK_FAILURES,
SMS_SUBSCRIPTION_ID,
@@ -330,7 +331,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
REMOTE_DELETED,
MENTIONS_SELF,
NOTIFIED_TIMESTAMP,
VIEWED_RECEIPT_COUNT,
VIEWED_COLUMN,
RECEIPT_TIMESTAMP,
MESSAGE_RANGES,
STORY_TYPE,
@@ -665,7 +666,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
return readableDatabase
.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)
.where("$THREAD_ID = ? AND $VIEWED_COLUMN > 0 AND $TYPE & ${MessageTypes.BASE_INBOX_TYPE} = ${MessageTypes.BASE_INBOX_TYPE}", threadId)
.run()
.readToList { it.toMarkedMessageInfo(outgoing = false) }
}
@@ -687,7 +688,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val results: List<MarkedMessageInfo> = readableDatabase
.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")
.where("$ID IN (${Util.join(messageIds, ",")}) AND $VIEWED_COLUMN = 0")
.run()
.readToList { cursor ->
val type = cursor.requireLong(TYPE)
@@ -707,7 +708,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
writableDatabase
.update(TABLE_NAME)
.values(
VIEWED_RECEIPT_COUNT to 1,
VIEWED_COLUMN to 1,
RECEIPT_TIMESTAMP to currentTime
)
.where(query.where, query.whereArgs)
@@ -734,7 +735,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val results: List<MarkedMessageInfo> = readableDatabase
.select(ID, TO_RECIPIENT_ID, DATE_SENT, THREAD_ID, STORY_TYPE)
.from(TABLE_NAME)
.where("""$ID IN (${Util.join(messageIds, ",")}) AND ($outgoingTypeClause) AND ($TYPE & ${MessageTypes.SPECIAL_TYPES_MASK} = ${MessageTypes.SPECIAL_TYPE_GIFT_BADGE}) AND $VIEWED_RECEIPT_COUNT = 0""")
.where("""$ID IN (${Util.join(messageIds, ",")}) AND ($outgoingTypeClause) AND ($TYPE & ${MessageTypes.SPECIAL_TYPES_MASK} = ${MessageTypes.SPECIAL_TYPE_GIFT_BADGE}) AND $VIEWED_COLUMN = 0""")
.run()
.readToList { it.toMarkedMessageInfo(outgoing = true) }
@@ -745,7 +746,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
writableDatabase
.update(TABLE_NAME)
.values(
VIEWED_RECEIPT_COUNT to 1,
VIEWED_COLUMN to 1,
RECEIPT_TIMESTAMP to currentTime
)
.where(query.where, query.whereArgs)
@@ -1259,7 +1260,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
fun getUnreadStories(recipientId: RecipientId, limit: Int): Reader {
val threadId = threads.getThreadIdIfExistsFor(recipientId)
val query = "$IS_STORY_CLAUSE AND NOT ($outgoingTypeClause) AND $THREAD_ID = ? AND $VIEWED_RECEIPT_COUNT = ?"
val query = "$IS_STORY_CLAUSE AND NOT ($outgoingTypeClause) AND $THREAD_ID = ? AND $VIEWED_COLUMN = ?"
val args = buildArgs(threadId, 0)
return MmsReader(rawQueryWithAttachments(query, args, false, limit.toLong()))
}
@@ -1312,7 +1313,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
writableDatabase.withinTransaction { db ->
db.select(FROM_RECIPIENT_ID)
.from(TABLE_NAME)
.where("$IS_STORY_CLAUSE AND $DATE_SENT IN ($timestamps) AND NOT ($outgoingTypeClause) AND $VIEWED_RECEIPT_COUNT > 0")
.where("$IS_STORY_CLAUSE AND $DATE_SENT IN ($timestamps) AND NOT ($outgoingTypeClause) AND $VIEWED_COLUMN > 0")
.run()
.readToList { cursor -> RecipientId.from(cursor.requireLong(FROM_RECIPIENT_ID)) }
.forEach { id -> recipients.updateLastStoryViewTimestamp(id) }
@@ -1332,7 +1333,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val hasUnviewedStories = readableDatabase
.exists(TABLE_NAME)
.where("$IS_STORY_CLAUSE AND $THREAD_ID = ? AND $VIEWED_RECEIPT_COUNT = ? AND NOT ($outgoingTypeClause)", threadId, 0)
.where("$IS_STORY_CLAUSE AND $THREAD_ID = ? AND $VIEWED_COLUMN = ? AND NOT ($outgoingTypeClause)", threadId, 0)
.run()
return if (hasUnviewedStories) {
@@ -1369,7 +1370,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
WHERE
$IS_STORY_CLAUSE AND
($outgoingTypeClause) = 0 AND
$VIEWED_RECEIPT_COUNT = 0 AND
$VIEWED_COLUMN = 0 AND
$TABLE_NAME.$READ = 0
"""
@@ -1390,10 +1391,10 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
$TABLE_NAME.$ID AS mms_id,
${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID},
($outgoingTypeClause) AS is_outgoing,
$VIEWED_RECEIPT_COUNT,
$VIEWED_COLUMN,
$TABLE_NAME.$DATE_SENT,
$RECEIPT_TIMESTAMP,
($outgoingTypeClause) = 0 AND $VIEWED_RECEIPT_COUNT = 0 AS is_unread
($outgoingTypeClause) = 0 AND $VIEWED_COLUMN = 0 AS is_unread
FROM $TABLE_NAME
JOIN ${ThreadTable.TABLE_NAME} ON $TABLE_NAME.$THREAD_ID = ${ThreadTable.TABLE_NAME}.${ThreadTable.ID}
WHERE
@@ -1403,8 +1404,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
ORDER BY
is_unread DESC,
CASE
WHEN is_outgoing = 0 AND $VIEWED_RECEIPT_COUNT = 0 THEN $TABLE_NAME.$DATE_SENT
WHEN is_outgoing = 0 AND viewed_receipt_count > 0 THEN $RECEIPT_TIMESTAMP
WHEN is_outgoing = 0 AND $VIEWED_COLUMN = 0 THEN $TABLE_NAME.$DATE_SENT
WHEN is_outgoing = 0 AND $VIEWED_COLUMN > 0 THEN $RECEIPT_TIMESTAMP
WHEN is_outgoing = 1 THEN $TABLE_NAME.$DATE_SENT
END DESC
"""
@@ -1686,7 +1687,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val query = buildMeaningfulMessagesQuery(threadId)
return readableDatabase
.select(ID, DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, VIEWED_RECEIPT_COUNT, TYPE)
.select(ID, HAS_DELIVERY_RECEIPT, HAS_READ_RECEIPT, TYPE)
.from(TABLE_NAME)
.where(query.where, query.whereArgs)
.orderBy("$DATE_RECEIVED DESC")
@@ -1699,9 +1700,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
}
return MessageReceiptStatus(
deliveryCount = cursor.requireInt(DELIVERY_RECEIPT_COUNT),
readCount = cursor.requireInt(READ_RECEIPT_COUNT),
viewedCount = cursor.requireInt(VIEWED_RECEIPT_COUNT),
hasDeliveryReceipt = cursor.requireBoolean(HAS_DELIVERY_RECEIPT),
hasReadReceipt = cursor.requireBoolean(HAS_READ_RECEIPT),
type = cursor.requireLong(TYPE)
)
} else {
@@ -2817,7 +2817,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
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(HAS_DELIVERY_RECEIPT, 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)
@@ -2832,7 +2832,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
}
if (message.threadRecipient.isSelf && hasAudioAttachment(message.attachments)) {
contentValues.put(VIEWED_RECEIPT_COUNT, 1L)
contentValues.put(VIEWED_COLUMN, 1L)
}
val quoteAttachments: MutableList<Attachment> = mutableListOf()
@@ -4074,8 +4074,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
.run()
}
fun incrementDeliveryReceiptCounts(targetTimestamps: List<Long>, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Set<Long> {
return incrementReceiptCounts(targetTimestamps, receiptAuthor, receiptSentTimestamp, ReceiptType.DELIVERY)
fun incrementDeliveryReceiptCounts(targetTimestamps: List<Long>, receiptAuthor: RecipientId, receiptSentTimestamp: Long, stopwatch: Stopwatch? = null): Set<Long> {
return incrementReceiptCounts(targetTimestamps, receiptAuthor, receiptSentTimestamp, ReceiptType.DELIVERY, stopwatch = stopwatch)
}
fun incrementDeliveryReceiptCount(targetTimestamps: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long): Boolean {
@@ -4164,13 +4164,13 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
*
* @return All of the target timestamps that couldn't be found in the table.
*/
private fun incrementReceiptCounts(targetTimestamps: List<Long>, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier = MessageQualifier.ALL): Set<Long> {
private fun incrementReceiptCounts(targetTimestamps: List<Long>, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier = MessageQualifier.ALL, stopwatch: Stopwatch? = null): Set<Long> {
val messageUpdates: MutableSet<MessageReceiptUpdate> = HashSet()
val missingTargetTimestamps: MutableSet<Long> = HashSet()
writableDatabase.withinTransaction {
for (targetTimestamp in targetTimestamps) {
val updates: Set<MessageReceiptUpdate> = incrementReceiptCountInternal(targetTimestamp, receiptAuthor, receiptSentTimestamp, receiptType, messageQualifier)
val updates: Set<MessageReceiptUpdate> = incrementReceiptCountInternal(targetTimestamp, receiptAuthor, receiptSentTimestamp, receiptType, messageQualifier, stopwatch)
if (updates.isNotEmpty()) {
messageUpdates += updates
} else {
@@ -4180,7 +4180,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
for (update in messageUpdates) {
if (update.shouldUpdateSnippet) {
threads.updateReceiptStatus(update.messageId.id, update.threadId)
threads.updateReceiptStatus(update.messageId.id, update.threadId, stopwatch)
}
}
}
@@ -4198,71 +4198,94 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
notifyConversationListListeners()
}
stopwatch?.split("observers")
return missingTargetTimestamps
}
private fun incrementReceiptCountInternal(targetTimestamp: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier): Set<MessageReceiptUpdate> {
val messageUpdates: MutableSet<MessageReceiptUpdate> = HashSet()
private fun incrementReceiptCountInternal(targetTimestamp: Long, receiptAuthor: RecipientId, receiptSentTimestamp: Long, receiptType: ReceiptType, messageQualifier: MessageQualifier, stopwatch: Stopwatch? = null): Set<MessageReceiptUpdate> {
val qualifierWhere: String = when (messageQualifier) {
MessageQualifier.NORMAL -> " AND NOT ($IS_STORY_CLAUSE)"
MessageQualifier.STORY -> " AND $IS_STORY_CLAUSE"
MessageQualifier.ALL -> ""
}
var found = false
var hasStory = false
writableDatabase.rawQuery(
"""
// Note: While it is true that multiple messages can have the same (sent, author) pair, this should only happen for stories, which are handled below.
val receiptData: ReceiptData? = readableDatabase
.select(ID, THREAD_ID, STORY_TYPE, receiptType.columnName, TO_RECIPIENT_ID)
.from(TABLE_NAME)
.where(
"""
$DATE_SENT = $targetTimestamp AND
$FROM_RECIPIENT_ID = ? AND
(
$TO_RECIPIENT_ID = ? OR
EXISTS (
SELECT 1
FROM ${RecipientTable.TABLE_NAME}
WHERE
${RecipientTable.TABLE_NAME}.${RecipientTable.ID} = $TO_RECIPIENT_ID AND
${RecipientTable.TABLE_NAME}.${RecipientTable.TYPE} != ${RecipientTable.RecipientType.INDIVIDUAL.id}
)
)
$qualifierWhere
""",
Recipient.self().id,
receiptAuthor
)
.limit(1)
.run()
.readToSingleObject { cursor ->
ReceiptData(
messageId = cursor.requireLong(ID),
threadId = cursor.requireLong(THREAD_ID),
storyType = StoryType.fromCode(cursor.requireInt(STORY_TYPE)),
marked = cursor.requireBoolean(receiptType.columnName),
forIndividualChat = cursor.requireLong(TO_RECIPIENT_ID) == receiptAuthor.toLong()
)
}
stopwatch?.split("receipt-query")
if (receiptData == null) {
if (receiptType == ReceiptType.DELIVERY) {
earlyDeliveryReceiptCache.increment(targetTimestamp, receiptAuthor, receiptSentTimestamp)
}
return emptySet()
}
if (!receiptData.marked) {
// We set the receipt_timestamp to the max of the two values because that single column represents the timestamp of the last receipt of any type.
// That means we want to update it for each new receipt type, but we never want the time to go backwards.
writableDatabase.execSQL(
"""
UPDATE $TABLE_NAME
SET
${receiptType.columnName} = ${receiptType.columnName} + 1,
$RECEIPT_TIMESTAMP = CASE
WHEN ${receiptType.columnName} = 0 THEN MAX($RECEIPT_TIMESTAMP, $receiptSentTimestamp)
ELSE $RECEIPT_TIMESTAMP
END
${receiptType.columnName} = 1,
$RECEIPT_TIMESTAMP = MAX($RECEIPT_TIMESTAMP, $receiptSentTimestamp)
WHERE
$DATE_SENT = $targetTimestamp AND
$FROM_RECIPIENT_ID = ? AND
(
$TO_RECIPIENT_ID = ? OR
EXISTS (
SELECT 1
FROM ${RecipientTable.TABLE_NAME}
WHERE
${RecipientTable.TABLE_NAME}.${RecipientTable.ID} = $TO_RECIPIENT_ID AND
${RecipientTable.TABLE_NAME}.${RecipientTable.TYPE} != ${RecipientTable.RecipientType.INDIVIDUAL.id}
)
)
$qualifierWhere
RETURNING $ID, $THREAD_ID, $STORY_TYPE, ${receiptType.columnName}
""",
buildArgs(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))
val receiptCount = cursor.requireInt(receiptType.columnName)
$ID = ${receiptData.messageId}
"""
)
}
stopwatch?.split("receipt-update")
groupReceipts.update(receiptAuthor, messageId, receiptType.groupStatus, receiptSentTimestamp)
messageUpdates += MessageReceiptUpdate(threadId, MessageId(messageId), receiptType != ReceiptType.VIEWED && receiptCount == 1)
found = true
hasStory = storyType != StoryType.NONE
if (!receiptData.forIndividualChat) {
groupReceipts.update(receiptAuthor, receiptData.messageId, receiptType.groupStatus, receiptSentTimestamp)
}
if (!found && receiptType == ReceiptType.DELIVERY) {
earlyDeliveryReceiptCache.increment(targetTimestamp, receiptAuthor, receiptSentTimestamp)
}
stopwatch?.split("group-receipt")
if (hasStory) {
for (messageId in storySends.getStoryMessagesFor(receiptAuthor, targetTimestamp)) {
groupReceipts.update(receiptAuthor, messageId.id, receiptType.groupStatus, receiptSentTimestamp)
messageUpdates += MessageReceiptUpdate(-1, messageId, false)
}
return if (receiptData.storyType != StoryType.NONE) {
val storyMessageIds = storySends.getStoryMessagesFor(receiptAuthor, targetTimestamp)
storyMessageIds.forEach { messageId -> groupReceipts.update(receiptAuthor, messageId.id, receiptType.groupStatus, receiptSentTimestamp) }
storyMessageIds.map { messageId -> MessageReceiptUpdate(-1, messageId, false) }.toSet()
} else {
setOf(MessageReceiptUpdate(receiptData.threadId, MessageId(receiptData.messageId), shouldUpdateSnippet = receiptType != ReceiptType.VIEWED && !receiptData.marked))
}.also {
stopwatch?.split("stories")
}
return messageUpdates
}
/**
@@ -4736,15 +4759,22 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
}
protected enum class ReceiptType(val columnName: String, val groupStatus: Int) {
READ(READ_RECEIPT_COUNT, GroupReceiptTable.STATUS_READ),
DELIVERY(DELIVERY_RECEIPT_COUNT, GroupReceiptTable.STATUS_DELIVERED),
VIEWED(VIEWED_RECEIPT_COUNT, GroupReceiptTable.STATUS_VIEWED)
READ(HAS_READ_RECEIPT, GroupReceiptTable.STATUS_READ),
DELIVERY(HAS_DELIVERY_RECEIPT, GroupReceiptTable.STATUS_DELIVERED),
VIEWED(VIEWED_COLUMN, GroupReceiptTable.STATUS_VIEWED)
}
data class ReceiptData(
val messageId: Long,
val threadId: Long,
val storyType: StoryType,
val marked: Boolean,
val forIndividualChat: Boolean
)
data class MessageReceiptStatus(
val readCount: Int,
val deliveryCount: Int,
val viewedCount: Int,
val hasReadReceipt: Boolean,
val hasDeliveryReceipt: Boolean,
val type: Long
)
@@ -4942,8 +4972,8 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
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 hasDeliveryReceipt = cursor.requireBoolean(HAS_DELIVERY_RECEIPT)
var hasReadReceipt = cursor.requireBoolean(HAS_READ_RECEIPT)
val body = cursor.requireString(BODY)
val mismatchDocument = cursor.requireString(MISMATCHED_IDENTITIES)
val networkDocument = cursor.requireString(NETWORK_FAILURES)
@@ -4955,7 +4985,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val remoteDelete = cursor.requireBoolean(REMOTE_DELETED)
val mentionsSelf = cursor.requireBoolean(MENTIONS_SELF)
val notifiedTimestamp = cursor.requireLong(NOTIFIED_TIMESTAMP)
var viewedReceiptCount = cursor.requireInt(VIEWED_RECEIPT_COUNT)
var isViewed = cursor.requireBoolean(VIEWED_COLUMN)
val receiptTimestamp = cursor.requireLong(RECEIPT_TIMESTAMP)
val messageRangesData = cursor.requireBlob(MESSAGE_RANGES)
val storyType = StoryType.fromCode(cursor.requireInt(STORY_TYPE))
@@ -4966,9 +4996,9 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
val editCount = cursor.requireInt(REVISION_NUMBER)
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
readReceiptCount = 0
hasReadReceipt = false
if (MessageTypes.isOutgoingMessageType(box) && !storyType.isStory) {
viewedReceiptCount = 0
isViewed = false
}
}
@@ -5019,7 +5049,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
dateSent,
dateReceived,
dateServer,
deliveryReceiptCount,
hasDeliveryReceipt,
threadId,
body,
slideDeck,
@@ -5030,7 +5060,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
expiresIn,
expireStarted,
isViewOnce,
readReceiptCount,
hasReadReceipt,
quote,
contacts,
previews,
@@ -5039,7 +5069,7 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
remoteDelete,
mentionsSelf,
notifiedTimestamp,
viewedReceiptCount,
isViewed,
receiptTimestamp,
messageRanges,
storyType,

View File

@@ -92,7 +92,7 @@ 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.getToRecipient().getShortDisplayName(context));
} else if (messageRecord.getViewedReceiptCount() > 0) {
} else if (messageRecord.isViewed()) {
return context.getString(R.string.ThreadRecord__you_redeemed_a_badge);
} else {
return context.getString(R.string.ThreadRecord__s_donated_for_you, messageRecord.getFromRecipient().getShortDisplayName(context));

View File

@@ -13,6 +13,7 @@ import org.json.JSONObject
import org.jsoup.helper.StringUtil
import org.signal.core.util.CursorUtil
import org.signal.core.util.SqlUtil
import org.signal.core.util.Stopwatch
import org.signal.core.util.delete
import org.signal.core.util.exists
import org.signal.core.util.logging.Log
@@ -23,6 +24,7 @@ import org.signal.core.util.requireInt
import org.signal.core.util.requireLong
import org.signal.core.util.requireString
import org.signal.core.util.select
import org.signal.core.util.toInt
import org.signal.core.util.update
import org.signal.core.util.withinTransaction
import org.signal.libsignal.zkgroup.InvalidInputException
@@ -97,8 +99,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
const val SNIPPET_EXTRAS = "snippet_extras"
const val ARCHIVED = "archived"
const val STATUS = "status"
const val DELIVERY_RECEIPT_COUNT = "delivery_receipt_count"
const val READ_RECEIPT_COUNT = "read_receipt_count"
const val HAS_DELIVERY_RECEIPT = "has_delivery_receipt"
const val HAS_READ_RECEIPT = "has_read_receipt"
const val EXPIRES_IN = "expires_in"
const val LAST_SEEN = "last_seen"
const val HAS_SENT = "has_sent"
@@ -127,8 +129,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
$UNREAD_COUNT INTEGER DEFAULT 0,
$ARCHIVED INTEGER DEFAULT 0,
$STATUS INTEGER DEFAULT 0,
$DELIVERY_RECEIPT_COUNT INTEGER DEFAULT 0,
$READ_RECEIPT_COUNT INTEGER DEFAULT 0,
$HAS_DELIVERY_RECEIPT INTEGER DEFAULT 0,
$HAS_READ_RECEIPT INTEGER DEFAULT 0,
$EXPIRES_IN INTEGER DEFAULT 0,
$LAST_SEEN INTEGER DEFAULT 0,
$HAS_SENT INTEGER DEFAULT 0,
@@ -164,10 +166,10 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
SNIPPET_EXTRAS,
ARCHIVED,
STATUS,
DELIVERY_RECEIPT_COUNT,
HAS_DELIVERY_RECEIPT,
EXPIRES_IN,
LAST_SEEN,
READ_RECEIPT_COUNT,
HAS_READ_RECEIPT,
LAST_SCROLLED,
PINNED,
UNREAD_SELF_MENTION_COUNT
@@ -242,8 +244,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
SNIPPET_EXTRAS to extraSerialized,
MEANINGFUL_MESSAGES to if (meaningfulMessages) 1 else 0,
STATUS to status,
DELIVERY_RECEIPT_COUNT to deliveryReceiptCount,
READ_RECEIPT_COUNT to readReceiptCount,
HAS_DELIVERY_RECEIPT to deliveryReceiptCount,
HAS_READ_RECEIPT to readReceiptCount,
EXPIRES_IN to expiresIn,
ACTIVE to 1,
UNREAD_COUNT to unreadCount,
@@ -1406,16 +1408,17 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
* The idea here is that if it _is_ the most meaningful message, we can set the new status. If it's not, there's no need to update
* the thread at all.
*/
fun updateReceiptStatus(messageId: Long, threadId: Long) {
fun updateReceiptStatus(messageId: Long, threadId: Long, stopwatch: Stopwatch? = null) {
val status = messages.getReceiptStatusIfItsTheMostRecentMeaningfulMessage(messageId, threadId)
stopwatch?.split("thread-query")
if (status != null) {
Log.d(TAG, "Updating receipt status for thread $threadId")
writableDatabase
.update(TABLE_NAME)
.values(
DELIVERY_RECEIPT_COUNT to status.deliveryCount,
READ_RECEIPT_COUNT to status.readCount,
HAS_DELIVERY_RECEIPT to status.hasDeliveryReceipt.toInt(),
HAS_READ_RECEIPT to status.hasReadReceipt.toInt(),
STATUS to when {
MessageTypes.isFailedMessageType(status.type) -> MessageTable.Status.STATUS_FAILED
MessageTypes.isSentType(status.type) -> MessageTable.Status.STATUS_COMPLETE
@@ -1428,6 +1431,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
} else {
Log.d(TAG, "Receipt was for an old message, not updating thread.")
}
stopwatch?.split("thread-update")
}
private fun update(threadId: Long, unarchive: Boolean, allowDeletion: Boolean, notifyListeners: Boolean): Boolean {
@@ -1506,11 +1510,11 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
extra = getExtrasFor(record, threadBody),
date = record.timestamp,
status = record.deliveryStatus,
deliveryReceiptCount = record.deliveryReceiptCount,
deliveryReceiptCount = record.hasDeliveryReceipt().toInt(),
type = record.type,
unarchive = unarchive,
expiresIn = record.expiresIn,
readReceiptCount = record.readReceiptCount,
readReceiptCount = record.hasReadReceipt().toInt(),
unreadCount = unreadCount,
unreadMentionCount = unreadMentionCount
)
@@ -1675,8 +1679,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
UNREAD_COUNT to 0,
ARCHIVED to 0,
STATUS to 0,
DELIVERY_RECEIPT_COUNT to 0,
READ_RECEIPT_COUNT to 0,
HAS_DELIVERY_RECEIPT to 0,
HAS_READ_RECEIPT to 0,
EXPIRES_IN to 0,
LAST_SEEN to 0,
HAS_SENT to 0,
@@ -1890,7 +1894,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
Recipient(recipientId, details, true)
}
val readReceiptCount = if (TextSecurePreferences.isReadReceiptsEnabled(context)) cursor.requireInt(READ_RECEIPT_COUNT) else 0
val hasReadReceipt = TextSecurePreferences.isReadReceiptsEnabled(context) && cursor.requireBoolean(HAS_READ_RECEIPT)
val extraString = cursor.getString(cursor.getColumnIndexOrThrow(SNIPPET_EXTRAS))
val extra: Extra? = if (extraString != null) {
try {
@@ -1924,8 +1928,8 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa
.setDate(cursor.requireLong(DATE))
.setArchived(cursor.requireBoolean(ARCHIVED))
.setDeliveryStatus(cursor.requireInt(STATUS).toLong())
.setDeliveryReceiptCount(cursor.requireInt(DELIVERY_RECEIPT_COUNT))
.setReadReceiptCount(readReceiptCount)
.setHasDeliveryReceipt(cursor.requireBoolean(HAS_DELIVERY_RECEIPT))
.setHasReadReceipt(hasReadReceipt)
.setExpiresIn(cursor.requireLong(EXPIRES_IN))
.setLastSeen(cursor.requireLong(LAST_SEEN))
.setSnippetUri(getSnippetUri(cursor))

View File

@@ -65,6 +65,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V206_AddConversatio
import org.thoughtcrime.securesms.database.helpers.migration.V207_AddChunkSizeColumn
import org.thoughtcrime.securesms.database.helpers.migration.V209_ClearRecipientPniFromAciColumn
import org.thoughtcrime.securesms.database.helpers.migration.V210_FixPniPossibleColumns
import org.thoughtcrime.securesms.database.helpers.migration.V211_ReceiptColumnRenames
/**
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
@@ -73,7 +74,7 @@ object SignalDatabaseMigrations {
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
const val DATABASE_VERSION = 210
const val DATABASE_VERSION = 211
@JvmStatic
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
@@ -324,6 +325,10 @@ object SignalDatabaseMigrations {
if (oldVersion < 210) {
V210_FixPniPossibleColumns.migrate(context, db, oldVersion, newVersion)
}
if (oldVersion < 211) {
V211_ReceiptColumnRenames.migrate(context, db, oldVersion, newVersion)
}
}
@JvmStatic

View File

@@ -0,0 +1,23 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.database.helpers.migration
import android.app.Application
import net.zetetic.database.sqlcipher.SQLiteDatabase
/**
*/
@Suppress("ClassName")
object V211_ReceiptColumnRenames : SignalDatabaseMigration {
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("ALTER TABLE message RENAME COLUMN delivery_receipt_count TO has_delivery_receipt")
db.execSQL("ALTER TABLE message RENAME COLUMN read_receipt_count TO has_read_receipt")
db.execSQL("ALTER TABLE message RENAME COLUMN viewed_receipt_count TO viewed")
db.execSQL("ALTER TABLE thread RENAME COLUMN delivery_receipt_count TO has_delivery_receipt")
db.execSQL("ALTER TABLE thread RENAME COLUMN read_receipt_count TO has_read_receipt")
}
}

View File

@@ -46,13 +46,13 @@ public abstract class DisplayRecord {
private final long threadId;
private final String body;
private final int deliveryStatus;
private final int deliveryReceiptCount;
private final int readReceiptCount;
private final int viewReceiptCount;
private final boolean hasDeliveryReceipt;
private final boolean hasReadReceipt;
private final boolean viewed;
DisplayRecord(String body, Recipient fromRecipient, Recipient toRecipient, long dateSent,
long dateReceived, long threadId, int deliveryStatus, int deliveryReceiptCount,
long type, int readReceiptCount, int viewReceiptCount)
long dateReceived, long threadId, int deliveryStatus, boolean hasDeliveryReceipt,
long type, boolean hasReadReceipt, boolean viewed)
{
this.threadId = threadId;
this.fromRecipient = fromRecipient;
@@ -61,10 +61,10 @@ public abstract class DisplayRecord {
this.dateReceived = dateReceived;
this.type = type;
this.body = body;
this.deliveryReceiptCount = deliveryReceiptCount;
this.readReceiptCount = readReceiptCount;
this.hasDeliveryReceipt = hasDeliveryReceipt;
this.hasReadReceipt = hasReadReceipt;
this.viewed = viewed;
this.deliveryStatus = deliveryStatus;
this.viewReceiptCount = viewReceiptCount;
}
public @NonNull String getBody() {
@@ -203,36 +203,25 @@ public abstract class DisplayRecord {
return deliveryStatus;
}
public int getDeliveryReceiptCount() {
return deliveryReceiptCount;
public boolean hasDeliveryReceipt() {
return hasDeliveryReceipt;
}
public int getReadReceiptCount() {
return readReceiptCount;
}
/**
* For outgoing messages, this is incremented whenever a remote recipient has viewed our message
* and sends us a VIEWED receipt. For incoming messages, this is an indication of whether local
* user has viewed a piece of content.
*
* @return the number of times this has been viewed.
* Either the outgoing message has a viewed receipt, or an incoming message has been viewed by the local user.
*/
public int getViewedReceiptCount() {
return viewReceiptCount;
public boolean isViewed() {
return viewed;
}
public boolean isDelivered() {
return (deliveryStatus >= Status.STATUS_COMPLETE &&
deliveryStatus < Status.STATUS_PENDING) || deliveryReceiptCount > 0;
deliveryStatus < Status.STATUS_PENDING) || hasDeliveryReceipt;
}
public boolean isRemoteViewed() {
return viewReceiptCount > 0;
}
public boolean isRemoteRead() {
return readReceiptCount > 0;
public boolean hasReadReceipt() {
return hasReadReceipt;
}
public boolean isPendingInsecureSmsFallback() {

View File

@@ -41,19 +41,19 @@ public class InMemoryMessageRecord extends MessageRecord {
System.currentTimeMillis(),
threadId,
0,
0,
false,
type,
Collections.emptySet(),
Collections.emptySet(),
-1,
0,
System.currentTimeMillis(),
0,
false,
false,
Collections.emptyList(),
false,
0,
0,
false,
-1,
null,
0);

View File

@@ -109,25 +109,25 @@ public abstract class MessageRecord extends DisplayRecord {
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,
int deliveryStatus, boolean hasDeliveryReceipt, long type,
Set<IdentityKeyMismatch> mismatches,
Set<NetworkFailure> networkFailures,
int subscriptionId,
long expiresIn,
long expireStarted,
int readReceiptCount,
boolean hasReadReceipt,
boolean unidentified,
@NonNull List<ReactionRecord> reactions,
boolean remoteDelete,
long notifiedTimestamp,
int viewedReceiptCount,
boolean viewed,
long receiptTimestamp,
@Nullable MessageId originalMessageId,
int revisionNumber)
{
super(body, fromRecipient, toRecipient, dateSent, dateReceived,
threadId, deliveryStatus, deliveryReceiptCount, type,
readReceiptCount, viewedReceiptCount);
threadId, deliveryStatus, hasDeliveryReceipt, type,
hasReadReceipt, viewed);
this.id = id;
this.authorDeviceId = fromDeviceId;
this.mismatches = mismatches;

View File

@@ -78,7 +78,7 @@ public class MmsMessageRecord extends MessageRecord {
long dateSent,
long dateReceived,
long dateServer,
int deliveryReceiptCount,
boolean hasDeliveryReceipt,
long threadId,
String body,
@NonNull SlideDeck slideDeck,
@@ -89,7 +89,7 @@ public class MmsMessageRecord extends MessageRecord {
long expiresIn,
long expireStarted,
boolean viewOnce,
int readReceiptCount,
boolean hasReadReceipt,
@Nullable Quote quote,
@NonNull List<Contact> contacts,
@NonNull List<LinkPreview> linkPreviews,
@@ -98,7 +98,7 @@ public class MmsMessageRecord extends MessageRecord {
boolean remoteDelete,
boolean mentionsSelf,
long notifiedTimestamp,
int viewedReceiptCount,
boolean viewed,
long receiptTimestamp,
@Nullable BodyRangeList messageRanges,
@NonNull StoryType storyType,
@@ -112,9 +112,9 @@ public class MmsMessageRecord extends MessageRecord {
int revisionNumber)
{
super(id, body, fromRecipient, fromDeviceId, toRecipient,
dateSent, dateReceived, dateServer, threadId, Status.STATUS_NONE, deliveryReceiptCount,
mailbox, mismatches, failures, subscriptionId, expiresIn, expireStarted, readReceiptCount,
unidentified, reactions, remoteDelete, notifiedTimestamp, viewedReceiptCount, receiptTimestamp, originalMessageId, revisionNumber);
dateSent, dateReceived, dateServer, threadId, Status.STATUS_NONE, hasDeliveryReceipt,
mailbox, mismatches, failures, subscriptionId, expiresIn, expireStarted, hasReadReceipt,
unidentified, reactions, remoteDelete, notifiedTimestamp, viewed, receiptTimestamp, originalMessageId, revisionNumber);
this.slideDeck = slideDeck;
this.quote = quote;
@@ -276,18 +276,18 @@ public class MmsMessageRecord extends MessageRecord {
}
public @NonNull MmsMessageRecord withReactions(@NonNull List<ReactionRecord> reactions) {
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), hasDeliveryReceipt(), 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(), getLatestRevisionId(),
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), reactions, isRemoteDelete(), mentionsSelf,
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
getOriginalMessageId(), getRevisionNumber());
}
public @NonNull MmsMessageRecord withoutQuote() {
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), hasDeliveryReceipt(), 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(), getLatestRevisionId(),
hasReadReceipt(), null, getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
getOriginalMessageId(), getRevisionNumber());
}
@@ -306,27 +306,27 @@ public class MmsMessageRecord extends MessageRecord {
List<DatabaseAttachment> slideAttachments = attachments.stream().filter(a -> !contactAttachments.contains(a)).filter(a -> !linkPreviewAttachments.contains(a)).collect(Collectors.toList());
SlideDeck slideDeck = MessageTable.MmsReader.buildSlideDeck(slideAttachments);
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), slideDeck,
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), hasDeliveryReceipt(), 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(), getLatestRevisionId(),
hasReadReceipt(), quote, contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), getCall(), getScheduledDate(), getLatestRevisionId(),
getOriginalMessageId(), getRevisionNumber());
}
public @NonNull MmsMessageRecord withPayment(@NonNull Payment payment) {
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), hasDeliveryReceipt(), 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(), getLatestRevisionId(),
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), payment, getCall(), getScheduledDate(), getLatestRevisionId(),
getOriginalMessageId(), getRevisionNumber());
}
public @NonNull MmsMessageRecord withCall(@Nullable CallTable.Call call) {
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(),
return new MmsMessageRecord(getId(), getFromRecipient(), getFromDeviceId(), getToRecipient(), getDateSent(), getDateReceived(), getServerTimestamp(), hasDeliveryReceipt(), 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(), getLatestRevisionId(),
hasReadReceipt(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf,
getNotifiedTimestamp(), isViewed(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment(), call, getScheduledDate(), getLatestRevisionId(),
getOriginalMessageId(), getRevisionNumber());
}

View File

@@ -6,9 +6,9 @@ import org.thoughtcrime.securesms.database.MessageTypes;
final class StatusUtil {
private StatusUtil() {}
static boolean isDelivered(long deliveryStatus, int deliveryReceiptCount) {
static boolean isDelivered(long deliveryStatus, boolean hasDeliveryReceipt) {
return (deliveryStatus >= MessageTable.Status.STATUS_COMPLETE &&
deliveryStatus < MessageTable.Status.STATUS_PENDING) || deliveryReceiptCount > 0;
deliveryStatus < MessageTable.Status.STATUS_PENDING) || hasDeliveryReceipt;
}
static boolean isPending(long type) {

View File

@@ -43,8 +43,8 @@ public final class ThreadRecord {
private final long type;
private final long date;
private final long deliveryStatus;
private final int deliveryReceiptCount;
private final int readReceiptCount;
private final boolean hasDeliveryReceipt;
private final boolean hasReadReceipt;
private final Uri snippetUri;
private final String contentType;
private final Extra extra;
@@ -65,8 +65,8 @@ public final class ThreadRecord {
this.date = builder.date;
this.type = builder.type;
this.deliveryStatus = builder.deliveryStatus;
this.deliveryReceiptCount = builder.deliveryReceiptCount;
this.readReceiptCount = builder.readReceiptCount;
this.hasDeliveryReceipt = builder.hasDeliveryReceipt;
this.hasReadReceipt = builder.hasReadReceipt;
this.snippetUri = builder.snippetUri;
this.contentType = builder.contentType;
this.extra = builder.extra;
@@ -173,8 +173,8 @@ public final class ThreadRecord {
return StatusUtil.isFailed(type, deliveryStatus);
}
public boolean isRemoteRead() {
return readReceiptCount > 0;
public boolean hasReadReceipt() {
return hasReadReceipt;
}
public boolean isPendingInsecureSmsFallback() {
@@ -182,7 +182,7 @@ public final class ThreadRecord {
}
public boolean isDelivered() {
return StatusUtil.isDelivered(deliveryStatus, deliveryReceiptCount);
return StatusUtil.isDelivered(deliveryStatus, hasDeliveryReceipt);
}
public boolean isScheduledMessage() {
@@ -244,8 +244,8 @@ public final class ThreadRecord {
type == that.type &&
date == that.date &&
deliveryStatus == that.deliveryStatus &&
deliveryReceiptCount == that.deliveryReceiptCount &&
readReceiptCount == that.readReceiptCount &&
hasDeliveryReceipt == that.hasDeliveryReceipt &&
hasReadReceipt == that.hasReadReceipt &&
meaningfulMessages == that.meaningfulMessages &&
unreadCount == that.unreadCount &&
forcedUnread == that.forcedUnread &&
@@ -270,8 +270,8 @@ public final class ThreadRecord {
type,
date,
deliveryStatus,
deliveryReceiptCount,
readReceiptCount,
hasDeliveryReceipt,
hasReadReceipt,
snippetUri,
contentType,
extra,
@@ -293,8 +293,8 @@ public final class ThreadRecord {
private long type;
private long date;
private long deliveryStatus;
private int deliveryReceiptCount;
private int readReceiptCount;
private boolean hasDeliveryReceipt;
private boolean hasReadReceipt;
private Uri snippetUri;
private String contentType;
private Extra extra;
@@ -342,13 +342,13 @@ public final class ThreadRecord {
return this;
}
public Builder setDeliveryReceiptCount(int deliveryReceiptCount) {
this.deliveryReceiptCount = deliveryReceiptCount;
public Builder setHasDeliveryReceipt(boolean hasDeliveryReceipt) {
this.hasDeliveryReceipt = hasDeliveryReceipt;
return this;
}
public Builder setReadReceiptCount(int readReceiptCount) {
this.readReceiptCount = readReceiptCount;
public Builder setHasReadReceipt(boolean hasReadReceipt) {
this.hasReadReceipt = hasReadReceipt;
return this;
}