Add support for separate story view receipt control.

This reverts commit 1046265d23.
This commit is contained in:
Alex Hart
2022-10-13 12:46:13 -03:00
committed by Cody Henthorne
parent 2f2711c9a3
commit ca36eaacce
23 changed files with 332 additions and 48 deletions

View File

@@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.ParentStoryId;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.database.model.StoryResult;
import org.thoughtcrime.securesms.database.model.StoryType;
import org.thoughtcrime.securesms.database.model.StoryViewState;
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExportState;
import org.thoughtcrime.securesms.database.model.databaseprotos.ThreadMergeEvent;
@@ -135,7 +136,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns,
public abstract void markGiftRedemptionStarted(long messageId);
public abstract void markGiftRedemptionFailed(long messageId);
public abstract Set<MessageUpdate> incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType, boolean storiesOnly);
public abstract Set<MessageUpdate> incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType, @NonNull MessageQualifier messageType);
public abstract List<MarkedMessageInfo> setEntireThreadRead(long threadId);
public abstract List<MarkedMessageInfo> setMessagesReadSince(long threadId, long timestamp);
@@ -218,6 +219,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns,
public abstract void deleteGroupStoryReplies(long parentStoryId);
public abstract boolean isOutgoingStoryAlreadyInDatabase(@NonNull RecipientId recipientId, long sentTimestamp);
public abstract @NonNull List<MarkedMessageInfo> setGroupStoryMessagesReadSince(long threadId, long groupStoryId, long sinceTimestamp);
public abstract @NonNull List<StoryType> getStoryTypes(@NonNull List<MessageId> messageIds);
public abstract @NonNull StoryViewState getStoryViewState(@NonNull RecipientId recipientId);
public abstract void updateViewedStories(@NonNull Set<SyncMessageId> syncMessageIds);
@@ -920,4 +922,23 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns,
return dateReceived;
}
}
/**
* Describes which messages to act on. This is used when incrementing receipts.
* Specifically, this was added to support stories having separate viewed receipt settings.
*/
public enum MessageQualifier {
/**
* A normal database message (i.e. not a story)
*/
NORMAL,
/**
* A story message
*/
STORY,
/**
* Both normal and story message
*/
ALL
}
}

View File

@@ -379,7 +379,7 @@ public class MmsDatabase extends MessageDatabase {
@Override
public @NonNull List<MarkedMessageInfo> getViewedIncomingMessages(long threadId) {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
String[] columns = new String[]{ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, THREAD_ID};
String[] columns = new String[]{ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, THREAD_ID, STORY_TYPE};
String where = THREAD_ID + " = ? AND " + VIEWED_RECEIPT_COUNT + " > 0 AND " + MESSAGE_BOX + " & " + Types.BASE_INBOX_TYPE + " = " + Types.BASE_INBOX_TYPE;
String[] args = SqlUtil.buildArgs(threadId);
@@ -395,6 +395,7 @@ public class MmsDatabase extends MessageDatabase {
RecipientId recipientId = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID));
long dateSent = CursorUtil.requireLong(cursor, DATE_SENT);
SyncMessageId syncMessageId = new SyncMessageId(recipientId, dateSent);
StoryType storyType = StoryType.fromCode(CursorUtil.requireInt(cursor, STORY_TYPE));
results.add(new MarkedMessageInfo(threadId, syncMessageId, new MessageId(messageId, true), null));
}
@@ -421,7 +422,7 @@ public class MmsDatabase extends MessageDatabase {
}
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
String[] columns = new String[]{ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, THREAD_ID};
String[] columns = new String[]{ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, THREAD_ID, STORY_TYPE};
String where = ID + " IN (" + Util.join(messageIds, ",") + ") AND " + VIEWED_RECEIPT_COUNT + " = 0";
List<MarkedMessageInfo> results = new LinkedList<>();
@@ -435,6 +436,7 @@ public class MmsDatabase extends MessageDatabase {
RecipientId recipientId = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID));
long dateSent = CursorUtil.requireLong(cursor, DATE_SENT);
SyncMessageId syncMessageId = new SyncMessageId(recipientId, dateSent);
StoryType storyType = StoryType.fromCode(CursorUtil.requireInt(cursor, STORY_TYPE));
results.add(new MarkedMessageInfo(threadId, syncMessageId, new MessageId(messageId, true), null));
@@ -463,7 +465,7 @@ public class MmsDatabase extends MessageDatabase {
@Override
public @NonNull List<MarkedMessageInfo>
setOutgoingGiftsRevealed(@NonNull List<Long> messageIds) {
String[] projection = SqlUtil.buildArgs(ID, RECIPIENT_ID, DATE_SENT, THREAD_ID);
String[] projection = SqlUtil.buildArgs(ID, RECIPIENT_ID, DATE_SENT, THREAD_ID, STORY_TYPE);
String where = ID + " IN (" + Util.join(messageIds, ",") + ") AND (" + getOutgoingTypeClause() + ") AND (" + getTypeField() + " & " + Types.SPECIAL_TYPES_MASK + " = " + Types.SPECIAL_TYPE_GIFT_BADGE + ") AND " + VIEWED_RECEIPT_COUNT + " = 0";
List<MarkedMessageInfo> results = new LinkedList<>();
@@ -475,6 +477,7 @@ public class MmsDatabase extends MessageDatabase {
RecipientId recipientId = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID));
long dateSent = CursorUtil.requireLong(cursor, DATE_SENT);
SyncMessageId syncMessageId = new SyncMessageId(recipientId, dateSent);
StoryType storyType = StoryType.fromCode(CursorUtil.requireInt(cursor, STORY_TYPE));
results.add(new MarkedMessageInfo(threadId, syncMessageId, new MessageId(messageId, true), null));
@@ -1122,13 +1125,28 @@ public class MmsDatabase extends MessageDatabase {
}
@Override
public Set<MessageUpdate> incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType, boolean storiesOnly) {
public Set<MessageUpdate> incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType, MessageQualifier messageQualifier) {
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
Set<MessageUpdate> messageUpdates = new HashSet<>();
final String qualifierWhere;
switch (messageQualifier) {
case NORMAL:
qualifierWhere = " AND NOT (" + IS_STORY_CLAUSE + ")";
break;
case STORY:
qualifierWhere = " AND " + IS_STORY_CLAUSE;
break;
case ALL:
qualifierWhere = "";
break;
default:
throw new IllegalArgumentException("Unsupported qualifier: " + messageQualifier);
}
try (Cursor cursor = SQLiteDatabaseExtensionsKt.select(database, ID, THREAD_ID, MESSAGE_BOX, RECIPIENT_ID, receiptType.getColumnName(), RECEIPT_TIMESTAMP)
.from(TABLE_NAME)
.where(DATE_SENT + " = ?" + (storiesOnly ? " AND " + IS_STORY_CLAUSE : ""), messageId.getTimetamp())
.where(DATE_SENT + " = ?" + qualifierWhere, messageId.getTimetamp())
.run())
{
while (cursor.moveToNext()) {
@@ -1509,6 +1527,38 @@ public class MmsDatabase extends MessageDatabase {
}
}
@Override
public @NonNull List<StoryType> getStoryTypes(@NonNull List<MessageId> messageIds) {
List<Long> mmsMessages = messageIds.stream()
.filter(MessageId::isMms)
.map(MessageId::getId)
.collect(java.util.stream.Collectors.toList());
if (mmsMessages.isEmpty()) {
return Collections.emptyList();
}
String[] projection = SqlUtil.buildArgs(ID, STORY_TYPE);
List<SqlUtil.Query> queries = SqlUtil.buildCollectionQuery(ID, mmsMessages);
HashMap<Long, StoryType> storyTypes = new HashMap<>();
for (final SqlUtil.Query query : queries) {
try (Cursor cursor = getWritableDatabase().query(TABLE_NAME, projection, query.getWhere(), query.getWhereArgs(), null, null, null)) {
while (cursor != null && cursor.moveToNext()) {
storyTypes.put(CursorUtil.requireLong(cursor, ID), StoryType.fromCode(CursorUtil.requireInt(cursor, STORY_TYPE)));
}
}
}
return messageIds.stream().map(id -> {
if (id.isMms() && storyTypes.containsKey(id.getId())) {
return storyTypes.get(id.getId());
} else {
return StoryType.NONE;
}
}).collect(java.util.stream.Collectors.toList());
}
@Override
public List<MarkedMessageInfo> setEntireThreadRead(long threadId) {
return setMessagesRead(THREAD_ID + " = ? AND " + STORY_TYPE + " = 0 AND " + PARENT_STORY_ID + " <= 0", new String[] { String.valueOf(threadId)});
@@ -1528,7 +1578,7 @@ public class MmsDatabase extends MessageDatabase {
database.beginTransaction();
try {
cursor = database.query(TABLE_NAME, new String[] {ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED, THREAD_ID }, where, arguments, null, null, null);
cursor = database.query(TABLE_NAME, new String[] {ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED, THREAD_ID, STORY_TYPE }, where, arguments, null, null, null);
while(cursor != null && cursor.moveToNext()) {
if (Types.isSecureType(CursorUtil.requireLong(cursor, MESSAGE_BOX))) {
@@ -1540,6 +1590,7 @@ public class MmsDatabase extends MessageDatabase {
long expireStarted = CursorUtil.requireLong(cursor, EXPIRE_STARTED);
SyncMessageId syncMessageId = new SyncMessageId(recipientId, dateSent);
ExpirationInfo expirationInfo = new ExpirationInfo(messageId, expiresIn, expireStarted, true);
StoryType storyType = StoryType.fromCode(CursorUtil.requireInt(cursor, STORY_TYPE));
if (!recipientId.equals(releaseChannelId)) {
result.add(new MarkedMessageInfo(threadId, syncMessageId, new MessageId(messageId, true), expirationInfo));

View File

@@ -493,6 +493,10 @@ public class MmsSmsDatabase extends Database {
return incrementReceiptCounts(syncMessageIds, timestamp, MessageDatabase.ReceiptType.VIEWED);
}
public @NonNull Collection<SyncMessageId> incrementViewedNonStoryReceiptCounts(@NonNull List<SyncMessageId> syncMessageIds, long timestamp) {
return incrementReceiptCounts(syncMessageIds, timestamp, MessageDatabase.ReceiptType.VIEWED, MessageDatabase.MessageQualifier.NORMAL);
}
public boolean incrementViewedReceiptCount(SyncMessageId syncMessageId, long timestamp) {
return incrementReceiptCount(syncMessageId, timestamp, MessageDatabase.ReceiptType.VIEWED);
}
@@ -505,7 +509,7 @@ public class MmsSmsDatabase extends Database {
db.beginTransaction();
try {
for (SyncMessageId id : syncMessageIds) {
Set<MessageUpdate> updates = incrementStoryReceiptCountInternal(id, timestamp, MessageDatabase.ReceiptType.VIEWED);
Set<MessageUpdate> updates = incrementReceiptCountInternal(id, timestamp, MessageDatabase.ReceiptType.VIEWED, MessageDatabase.MessageQualifier.STORY);
if (updates.size() > 0) {
messageUpdates.addAll(updates);
@@ -537,13 +541,17 @@ public class MmsSmsDatabase extends Database {
* @return Whether or not some thread was updated.
*/
private boolean incrementReceiptCount(SyncMessageId syncMessageId, long timestamp, @NonNull MessageDatabase.ReceiptType receiptType) {
return incrementReceiptCount(syncMessageId, timestamp, receiptType, MessageDatabase.MessageQualifier.ALL);
}
private boolean incrementReceiptCount(SyncMessageId syncMessageId, long timestamp, @NonNull MessageDatabase.ReceiptType receiptType, @NonNull MessageDatabase.MessageQualifier messageQualifier) {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
ThreadDatabase threadDatabase = SignalDatabase.threads();
Set<MessageUpdate> messageUpdates = new HashSet<>();
db.beginTransaction();
try {
messageUpdates = incrementReceiptCountInternal(syncMessageId, timestamp, receiptType);
messageUpdates = incrementReceiptCountInternal(syncMessageId, timestamp, receiptType, messageQualifier);
for (MessageUpdate messageUpdate : messageUpdates) {
threadDatabase.update(messageUpdate.getThreadId(), false);
@@ -567,6 +575,10 @@ public class MmsSmsDatabase extends Database {
* @return All of the messages that didn't result in updates.
*/
private @NonNull Collection<SyncMessageId> incrementReceiptCounts(@NonNull List<SyncMessageId> syncMessageIds, long timestamp, @NonNull MessageDatabase.ReceiptType receiptType) {
return incrementReceiptCounts(syncMessageIds, timestamp, receiptType, MessageDatabase.MessageQualifier.ALL);
}
private @NonNull Collection<SyncMessageId> incrementReceiptCounts(@NonNull List<SyncMessageId> syncMessageIds, long timestamp, @NonNull MessageDatabase.ReceiptType receiptType, @NonNull MessageDatabase.MessageQualifier messageQualifier) {
SQLiteDatabase db = databaseHelper.getSignalWritableDatabase();
ThreadDatabase threadDatabase = SignalDatabase.threads();
Set<MessageUpdate> messageUpdates = new HashSet<>();
@@ -575,7 +587,7 @@ public class MmsSmsDatabase extends Database {
db.beginTransaction();
try {
for (SyncMessageId id : syncMessageIds) {
Set<MessageUpdate> updates = incrementReceiptCountInternal(id, timestamp, receiptType);
Set<MessageUpdate> updates = incrementReceiptCountInternal(id, timestamp, receiptType, messageQualifier);
if (updates.size() > 0) {
messageUpdates.addAll(updates);
@@ -609,22 +621,15 @@ public class MmsSmsDatabase extends Database {
/**
* Doesn't do any transactions or updates, so we can re-use the method safely.
*/
private @NonNull Set<MessageUpdate> incrementReceiptCountInternal(SyncMessageId syncMessageId, long timestamp, MessageDatabase.ReceiptType receiptType) {
private @NonNull Set<MessageUpdate> incrementReceiptCountInternal(SyncMessageId syncMessageId, long timestamp, MessageDatabase.ReceiptType receiptType, @NonNull MessageDatabase.MessageQualifier messageQualifier) {
Set<MessageUpdate> messageUpdates = new HashSet<>();
messageUpdates.addAll(SignalDatabase.sms().incrementReceiptCount(syncMessageId, timestamp, receiptType, false));
messageUpdates.addAll(SignalDatabase.mms().incrementReceiptCount(syncMessageId, timestamp, receiptType, false));
messageUpdates.addAll(SignalDatabase.sms().incrementReceiptCount(syncMessageId, timestamp, receiptType, messageQualifier));
messageUpdates.addAll(SignalDatabase.mms().incrementReceiptCount(syncMessageId, timestamp, receiptType, messageQualifier));
return messageUpdates;
}
/**
* Doesn't do any transactions or updates, so we can re-use the method safely.
*/
private @NonNull Set<MessageUpdate> incrementStoryReceiptCountInternal(@NonNull SyncMessageId syncMessageId, long timestamp, @NonNull MessageDatabase.ReceiptType receiptType) {
return SignalDatabase.mms().incrementReceiptCount(syncMessageId, timestamp, receiptType, true);
}
public void updateViewedStories(@NonNull Set<SyncMessageId> syncMessageIds) {
SignalDatabase.mms().updateViewedStories(syncMessageIds);
}

View File

@@ -50,6 +50,7 @@ import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.ParentStoryId;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.database.model.StoryResult;
import org.thoughtcrime.securesms.database.model.StoryType;
import org.thoughtcrime.securesms.database.model.StoryViewState;
import org.thoughtcrime.securesms.database.model.databaseprotos.GroupCallUpdateDetails;
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExportState;
@@ -515,7 +516,11 @@ public class SmsDatabase extends MessageDatabase {
}
@Override
public @NonNull Set<MessageUpdate> incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType, boolean storiesOnly) {
public @NonNull Set<MessageUpdate> incrementReceiptCount(SyncMessageId messageId, long timestamp, @NonNull ReceiptType receiptType, @NonNull MessageQualifier messageQualifier) {
if (messageQualifier == MessageQualifier.STORY) {
return Collections.emptySet();
}
if (receiptType == ReceiptType.VIEWED) {
return Collections.emptySet();
}
@@ -1567,6 +1572,11 @@ public class SmsDatabase extends MessageDatabase {
throw new UnsupportedOperationException();
}
@Override
public @NonNull List<StoryType> getStoryTypes(@NonNull List<MessageId> messageIds) {
throw new UnsupportedOperationException();
}
@Override
public void deleteGroupStoryReplies(long parentStoryId) {
throw new UnsupportedOperationException();