From 7b26de5bd658e9b0fbb8908ff9557409c0844d91 Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 11 Jan 2024 12:34:41 +1030 Subject: [PATCH] Fix disappear after read --- .../v2/messages/ControlMessageView.kt | 4 ++ .../securesms/database/ExpirationInfo.kt | 11 ++- .../securesms/database/MmsDatabase.kt | 15 ++-- .../securesms/database/SmsDatabase.java | 5 +- .../securesms/database/Storage.kt | 5 ++ .../notifications/MarkReadReceiver.kt | 15 ++-- .../messages/visible/VisibleMessage.kt | 2 +- .../ReceivedMessageHandler.kt | 70 ++----------------- .../utilities/UpdateMessageBuilder.kt | 8 ++- 9 files changed, 55 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt index 97b1ef9a05..6dbe730ae3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.v2.messages import android.content.Context import android.util.AttributeSet +import android.util.Log import android.view.LayoutInflater import android.widget.LinearLayout import androidx.core.content.res.ResourcesCompat @@ -22,6 +23,8 @@ import javax.inject.Inject @AndroidEntryPoint class ControlMessageView : LinearLayout { + private val TAG = "ControlMessageView" + private lateinit var binding: ViewControlMessageBinding constructor(context: Context) : super(context) { initialize() } @@ -47,6 +50,7 @@ class ControlMessageView : LinearLayout { binding.apply { expirationTimerView.isVisible = true + Log.d(TAG, "bind() called, messageBody = $messageBody") expirationTimerView.setExpirationTime(message.expireStarted, message.expiresIn) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ExpirationInfo.kt b/app/src/main/java/org/thoughtcrime/securesms/database/ExpirationInfo.kt index f9adad8928..40d38e8b70 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ExpirationInfo.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ExpirationInfo.kt @@ -1,3 +1,12 @@ package org.thoughtcrime.securesms.database -data class ExpirationInfo(val id: Long, val expiresIn: Long, val expireStarted: Long, val isMms: Boolean) +data class ExpirationInfo( + val id: Long, + val timestamp: Long, + val expiresIn: Long, + val expireStarted: Long, + val isMms: Boolean +) { + private fun isDisappearAfterSend() = timestamp == expireStarted + fun isDisappearAfterRead() = expiresIn > 0 && !isDisappearAfterSend() +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt index 1ae98e6b3e..8b7cb22db5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.kt @@ -305,6 +305,8 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa } override fun markExpireStarted(messageId: Long, startedTimestamp: Long) { + Log.d(TAG, "markExpireStarted() called with: messageId = $messageId, startedTimestamp = $startedTimestamp") + val contentValues = ContentValues() contentValues.put(EXPIRE_STARTED, startedTimestamp) val db = databaseHelper.writableDatabase @@ -351,13 +353,14 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa ) while (cursor != null && cursor.moveToNext()) { if (MmsSmsColumns.Types.isSecureType(cursor.getLong(3))) { - val syncMessageId = - SyncMessageId(fromSerialized(cursor.getString(1)), cursor.getLong(2)) + val timestamp = cursor.getLong(2) + val syncMessageId = SyncMessageId(fromSerialized(cursor.getString(1)), timestamp) val expirationInfo = ExpirationInfo( - cursor.getLong(0), - cursor.getLong(4), - cursor.getLong(5), - true + id = cursor.getLong(0), + timestamp = timestamp, + expiresIn = cursor.getLong(4), + expireStarted = cursor.getLong(5), + isMms = true ) result.add(MarkedMessageInfo(syncMessageId, expirationInfo)) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 3a3a5f2857..cf2ca42297 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -363,8 +363,9 @@ public class SmsDatabase extends MessagingDatabase { cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESS, DATE_SENT, TYPE, EXPIRES_IN, EXPIRE_STARTED}, where, arguments, null, null, null); while (cursor != null && cursor.moveToNext()) { - SyncMessageId syncMessageId = new SyncMessageId(Address.fromSerialized(cursor.getString(1)), cursor.getLong(2)); - ExpirationInfo expirationInfo = new ExpirationInfo(cursor.getLong(0), cursor.getLong(4), cursor.getLong(5), false); + long timestamp = cursor.getLong(2); + SyncMessageId syncMessageId = new SyncMessageId(Address.fromSerialized(cursor.getString(1)), timestamp); + ExpirationInfo expirationInfo = new ExpirationInfo(cursor.getLong(0), timestamp, cursor.getLong(4), cursor.getLong(5), false); results.add(new MarkedMessageInfo(syncMessageId, expirationInfo)); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index cdca00b08c..7fee136003 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -94,6 +94,8 @@ import org.thoughtcrime.securesms.util.SessionMetaProtocol import java.security.MessageDigest import network.loki.messenger.libsession_util.util.Contact as LibSessionContact +private const val TAG = "Storage" + open class Storage( context: Context, helper: SQLCipherOpenHelper, @@ -240,6 +242,7 @@ open class Storage( } override fun markConversationAsRead(threadId: Long, lastSeenTime: Long, force: Boolean) { + Log.d(TAG, "markConversationAsRead() called with: threadId = $threadId, lastSeenTime = $lastSeenTime, force = $force") val threadDb = DatabaseComponent.get(context).threadDatabase() getRecipientForThread(threadId)?.let { recipient -> val currentLastRead = threadDb.getLastSeenAndHasSent(threadId).first() @@ -1722,6 +1725,8 @@ open class Storage( } override fun setExpirationConfiguration(config: ExpirationConfiguration) { + Log.d(TAG, "setExpirationConfiguration() called with: config = $config") + val recipient = getRecipientForThread(config.threadId) ?: return val expirationDb = DatabaseComponent.get(context).expirationConfigurationDatabase() diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/MarkReadReceiver.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/MarkReadReceiver.kt index 21cb6f334b..e5a7436de9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/MarkReadReceiver.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/MarkReadReceiver.kt @@ -58,7 +58,7 @@ class MarkReadReceiver : BroadcastReceiver() { ) { if (markedReadMessages.isEmpty()) return - Log.d(TAG, "process() called with: context = $context, markedReadMessages = $markedReadMessages") + Log.d(TAG, "process() called with: markedReadMessages = $markedReadMessages") sendReadReceipts(context, markedReadMessages) @@ -133,13 +133,16 @@ class MarkReadReceiver : BroadcastReceiver() { expirationInfo: ExpirationInfo, expiresIn: Long = expirationInfo.expiresIn ) { - Log.d(TAG, "scheduleDeletion() called with: context = $context, expirationInfo = $expirationInfo, expiresIn = $expiresIn") + Log.d(TAG, "MarkReadReceiver#scheduleDeletion() called with: expirationInfo = $expirationInfo, expiresIn = $expiresIn") - if (expiresIn <= 0 || expirationInfo.expireStarted > 0) return + val now = nowWithOffset - val now = SnodeAPI.nowWithOffset - val db = DatabaseComponent.get(context!!).run { if (expirationInfo.isMms) mmsDatabase() else smsDatabase() } - db.markExpireStarted(expirationInfo.id, now) + val expireStarted = expirationInfo.expireStarted + + if (expirationInfo.isDisappearAfterRead() && expireStarted == 0L || now < expireStarted) { + val db = DatabaseComponent.get(context!!).run { if (expirationInfo.isMms) mmsDatabase() else smsDatabase() } + db.markExpireStarted(expirationInfo.id, now) + } ApplicationContext.getInstance(context).expiringMessageManager.scheduleDeletion( expirationInfo.id, diff --git a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt index e9d8964271..a2c63cdce2 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/messages/visible/VisibleMessage.kt @@ -13,7 +13,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.Attachment * * **Note:** `nil` if this isn't a sync message. */ -class VisibleMessage( +data class VisibleMessage( var syncTarget: String? = null, var text: String? = null, val attachmentIDs: MutableList = mutableListOf(), diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt index e87546e42c..53ad3da19d 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/ReceivedMessageHandler.kt @@ -68,7 +68,6 @@ fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content, // Do nothing if the message was outdated if (MessageReceiver.messageIsOutdated(message, threadId, openGroupID)) { return } - MessageReceiver.updateExpiryIfNeeded(message, proto, openGroupID) when (message) { is ReadReceipt -> handleReadReceipt(message) is TypingIndicator -> handleTypingIndicator(message) @@ -154,7 +153,9 @@ fun MessageReceiver.cancelTypingIndicatorsIfNeeded(senderPublicKey: String) { } private fun MessageReceiver.handleExpirationTimerUpdate(message: ExpirationTimerUpdate) { - if (ExpirationConfiguration.isNewConfigEnabled) return + SSKEnvironment.shared.messageExpirationManager.setExpirationTimer(message) + + if (isNewConfigEnabled) return val module = MessagingModuleConfiguration.shared try { @@ -171,7 +172,6 @@ private fun MessageReceiver.handleExpirationTimerUpdate(message: ExpirationTimer } catch (e: Exception) { Log.e("Loki", "Failed to update expiration configuration.") } - SSKEnvironment.shared.messageExpirationManager.setExpirationTimer(message) } private fun MessageReceiver.handleDataExtractionNotification(message: DataExtractionNotification) { @@ -269,58 +269,6 @@ fun handleMessageRequestResponse(message: MessageRequestResponse) { } //endregion -fun MessageReceiver.updateExpiryIfNeeded( - message: Message, - proto: SignalServiceProtos.Content, - openGroupID: String? -) { - val storage = MessagingModuleConfiguration.shared.storage - - val sentTime = message.sentTimestamp ?: throw MessageReceiver.Error.InvalidMessage - - val threadID = - storage.getThreadIdFor(message.sender!!, message.groupPublicKey, openGroupID, false) - ?: throw MessageReceiver.Error.NoThread - val recipient = storage.getRecipientForThread(threadID) ?: throw MessageReceiver.Error.NoThread - - if (!recipient.isLocalNumber) { - val disappearingState = if (proto.hasExpirationType()) Recipient.DisappearingState.UPDATED else Recipient.DisappearingState.LEGACY - storage.updateDisappearingState(message.sender!!, threadID, disappearingState) - } - - if (!proto.hasLastDisappearingMessageChangeTimestamp() && !isNewConfigEnabled) return - - val localConfig = storage.getExpirationConfiguration(threadID) - - val durationSeconds = if (proto.hasExpirationTimer()) proto.expirationTimer else 0 - val type = if (proto.hasExpirationType()) proto.expirationType else null - - val expiryMode = type?.expiryMode(durationSeconds.toLong()) ?: ExpiryMode.NONE - - val lastDisappearingMessageChangeTimestamp = proto.lastDisappearingMessageChangeTimestamp - - // don't update any values for open groups - if (recipient.isOpenGroupRecipient && type != null) throw MessageReceiver.Error.InvalidMessage - - val incoming1on1 = recipient.isContactRecipient && !message.isSenderSelf - - val remoteConfig = ExpirationConfiguration( - threadID, - expiryMode, - lastDisappearingMessageChangeTimestamp - ) - - remoteConfig.takeUnless { incoming1on1 }?.takeIf { - localConfig == null - || it.updatedTimestampMs > localConfig.updatedTimestampMs - || !isNewConfigEnabled && !proto.hasLastDisappearingMessageChangeTimestamp() - }?.let(storage::setExpirationConfiguration) - - if (message is ExpirationTimerUpdate) { - SSKEnvironment.shared.messageExpirationManager.setExpirationTimer(message) - } -} - private fun SignalServiceProtos.Content.ExpirationType.expiryMode(durationSeconds: Long) = takeIf { durationSeconds > 0 }?.let { when (it) { SignalServiceProtos.Content.ExpirationType.DELETE_AFTER_READ -> ExpiryMode.AfterRead(durationSeconds) @@ -465,14 +413,10 @@ fun MessageReceiver.handleVisibleMessage( // Persist the message message.threadID = threadID - val messageID = - storage.persist(message, quoteModel, linkPreviews, message.groupPublicKey, openGroupID, - attachments, runThreadUpdate - ) ?: return null - val openGroupServerID = message.openGroupServerMessageID - if (openGroupServerID != null) { - val isSms = !(message.isMediaMessage() || attachments.isNotEmpty()) - storage.setOpenGroupServerMessageID(messageID, openGroupServerID, threadID, isSms) + val messageID = storage.persist(message, quoteModel, linkPreviews, message.groupPublicKey, openGroupID, attachments, runThreadUpdate) ?: return null + message.openGroupServerMessageID?.let { + val isSms = !message.isMediaMessage() && attachments.isEmpty() + storage.setOpenGroupServerMessageID(messageID, it, threadID, isSms) } return messageID } diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt index 82c0a0a1be..c46339b205 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -1,6 +1,7 @@ package org.session.libsession.messaging.utilities import android.content.Context +import android.util.Log import org.session.libsession.R import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.calls.CallMessageType @@ -17,6 +18,8 @@ import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.truncateIdForDisplay object UpdateMessageBuilder { + private val TAG = "UpdateMessageBuilder" + val storage = MessagingModuleConfiguration.shared.storage private fun getSenderName(senderId: String) = storage.getContactWithSessionID(senderId) @@ -85,6 +88,8 @@ object UpdateMessageBuilder { timestamp: Long, expireStarted: Long ): String { + Log.d(TAG, "buildExpirationTimerMessage() called with: duration = $duration, senderId = $senderId, isOutgoing = $isOutgoing, timestamp = $timestamp, expireStarted = $expireStarted") + if (!isOutgoing && senderId == null) return "" val senderName = if (isOutgoing) context.getString(R.string.MessageRecord_you) else getSenderName(senderId!!) return if (duration <= 0) { @@ -98,6 +103,7 @@ object UpdateMessageBuilder { } else { val time = ExpirationUtil.getExpirationDisplayValue(context, duration.toInt()) val action = context.getExpirationTypeDisplayValue(timestamp == expireStarted) + Log.d(TAG, "action = $action because timestamp = $timestamp and expireStarted = $expireStarted equal = ${timestamp == expireStarted}") if (isOutgoing) { if (!isNewConfigEnabled) context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time) else context.getString( @@ -114,7 +120,7 @@ object UpdateMessageBuilder { action ) } - } + }.also { Log.d(TAG, "display: $it") } } fun buildDataExtractionMessage(context: Context, kind: DataExtractionNotificationInfoMessage.Kind, senderId: String? = null): String {