diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessages.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessages.kt index a64e718808..6fa9a2e278 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessages.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessages.kt @@ -37,7 +37,7 @@ class DisappearingMessages @Inject constructor( sentTimestamp = expiryChangeTimestampMs } - messageExpirationManager.setExpirationTimer(message) + messageExpirationManager.insertExpirationTimerMessage(message) MessageSender.send(message, address) ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(context) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModel.kt index f3ed76f06b..79ede208ad 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/disappearingmessages/DisappearingMessagesViewModel.kt @@ -19,9 +19,6 @@ import kotlinx.coroutines.launch import network.loki.messenger.BuildConfig import network.loki.messenger.libsession_util.util.ExpiryMode import org.session.libsession.messaging.messages.ExpirationConfiguration -import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate -import org.session.libsession.messaging.sending_receiving.MessageSender -import org.session.libsession.snode.SnodeAPI import org.session.libsession.utilities.SSKEnvironment.MessageExpirationManagerProtocol import org.session.libsession.utilities.TextSecurePreferences import org.thoughtcrime.securesms.conversation.disappearingmessages.ui.ExpiryCallbacks @@ -30,13 +27,13 @@ import org.thoughtcrime.securesms.conversation.disappearingmessages.ui.toUiState import org.thoughtcrime.securesms.database.GroupDatabase import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.database.ThreadDatabase -import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities class DisappearingMessagesViewModel( private val threadId: Long, private val application: Application, private val textSecurePreferences: TextSecurePreferences, private val messageExpirationManager: MessageExpirationManagerProtocol, + private val disappearingMessages: DisappearingMessages, private val threadDb: ThreadDatabase, private val groupDb: GroupDatabase, private val storage: Storage, @@ -90,20 +87,7 @@ class DisappearingMessagesViewModel( return@launch } - val expiryChangeTimestampMs = SnodeAPI.nowWithOffset - storage.setExpirationConfiguration(ExpirationConfiguration(threadId, mode, expiryChangeTimestampMs)) - - val message = ExpirationTimerUpdate().apply { - expiryMode = mode - sender = textSecurePreferences.getLocalNumber() - isSenderSelf = true - recipient = address.serialize() - sentTimestamp = expiryChangeTimestampMs - } - messageExpirationManager.setExpirationTimer(message) - MessageSender.send(message, address) - - ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(application) + disappearingMessages.set(threadId, address, mode) _event.send(Event.SUCCESS) } @@ -121,6 +105,7 @@ class DisappearingMessagesViewModel( private val application: Application, private val textSecurePreferences: TextSecurePreferences, private val messageExpirationManager: MessageExpirationManagerProtocol, + private val disappearingMessages: DisappearingMessages, private val threadDb: ThreadDatabase, private val groupDb: GroupDatabase, private val storage: Storage @@ -131,6 +116,7 @@ class DisappearingMessagesViewModel( application, textSecurePreferences, messageExpirationManager, + disappearingMessages, threadDb, groupDb, storage, 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 cf2ca42297..6a96b14d3d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -253,6 +253,8 @@ public class SmsDatabase extends MessagingDatabase { @Override public void markExpireStarted(long id, long startedAtTimestamp) { + Log.d(TAG, "markExpireStarted() called with: id = [" + id + "], startedAtTimestamp = [" + startedAtTimestamp + "]"); + ContentValues contentValues = new ContentValues(); contentValues.put(EXPIRE_STARTED, startedAtTimestamp); 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 d4b086c37d..b79fd14486 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/MarkReadReceiver.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/MarkReadReceiver.kt @@ -56,10 +56,10 @@ class MarkReadReceiver : BroadcastReceiver() { context: Context, markedReadMessages: List ) { - if (markedReadMessages.isEmpty()) return - Log.d(TAG, "process() called with: markedReadMessages = $markedReadMessages") + if (markedReadMessages.isEmpty()) return + sendReadReceipts(context, markedReadMessages) markedReadMessages.forEach { scheduleDeletion(context, it.expirationInfo) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.kt b/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.kt index 38b77c4801..a22470e482 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/service/ExpiringMessageManager.kt @@ -8,7 +8,6 @@ import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsession.messaging.messages.signal.IncomingMediaMessage import org.session.libsession.messaging.messages.signal.OutgoingExpirationUpdateMessage import org.session.libsession.snode.SnodeAPI.nowWithOffset -import org.session.libsession.utilities.Address import org.session.libsession.utilities.Address.Companion.fromSerialized import org.session.libsession.utilities.GroupUtil.doubleEncodeGroupID import org.session.libsession.utilities.GroupUtil.getDecodedGroupIDAsData @@ -21,7 +20,6 @@ import org.session.libsignal.utilities.guava.Optional import org.thoughtcrime.securesms.database.MmsDatabase import org.thoughtcrime.securesms.database.MmsSmsDatabase import org.thoughtcrime.securesms.database.SmsDatabase -import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.dependencies.DatabaseComponent.Companion.get import org.thoughtcrime.securesms.mms.MmsException import java.io.IOException @@ -149,15 +147,14 @@ class ExpiringMessageManager(context: Context) : MessageExpirationManagerProtoco } } - override fun setExpirationTimer(message: ExpirationTimerUpdate) { + override fun insertExpirationTimerMessage(message: ExpirationTimerUpdate) { val expiryMode: ExpiryMode = message.expiryMode Log.d(TAG, "setExpirationTimer() called with: message = $message, expiryMode = $expiryMode") val userPublicKey = getLocalNumber(context) val senderPublicKey = message.sender val sentTimestamp = if (message.sentTimestamp == null) 0 else message.sentTimestamp!! - val expireStartedAt = - if (expiryMode is AfterSend || message.isSenderSelf) sentTimestamp else 0 + val expireStartedAt = if (expiryMode is AfterSend || message.isSenderSelf) sentTimestamp else 0 // Notify the user if (senderPublicKey == null || userPublicKey == senderPublicKey) { @@ -167,14 +164,13 @@ class ExpiringMessageManager(context: Context) : MessageExpirationManagerProtoco insertIncomingExpirationTimerMessage(message, expireStartedAt) } - if (expiryMode is AfterSend && expiryMode.expirySeconds > 0 && message.sentTimestamp != null && senderPublicKey != null) { - startAnyExpiration(message.sentTimestamp!!, senderPublicKey, expireStartedAt) - } + startAnyExpiration(message) } override fun startAnyExpiration(timestamp: Long, author: String, expireStartedAt: Long) { Log.d(TAG, "startAnyExpiration() called with: timestamp = $timestamp, author = $author, expireStartedAt = $expireStartedAt") - val messageRecord = mmsSmsDatabase.getMessageFor(timestamp, author) ?: return + val messageRecord = mmsSmsDatabase.getMessageFor(timestamp, author) ?: throw Exception("no message record!!!") + Log.d(TAG, "startAnyExpiration() $messageRecord") val mms = messageRecord.isMms() getDatabase(mms).markExpireStarted(messageRecord.getId(), expireStartedAt) scheduleDeletion(messageRecord.getId(), mms, expireStartedAt, messageRecord.expiresIn) diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt index eb8679de3b..424f52c2d7 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/MessageSender.kt @@ -421,9 +421,10 @@ object MessageSender { storage.markUnidentified(timestamp, userPublicKey) // Start the disappearing messages timer if needed Log.d("MessageSender", "Start the disappearing messages timer if needed message.recipient = ${message.recipient}, userPublicKey = $userPublicKey, isSyncMessage = $isSyncMessage") - message.threadID?.let(storage::getExpirationConfiguration)?.takeIf { it.expiryMode.expirySeconds > 0 }?.let { config -> + message.threadID?.let(storage::getExpirationConfiguration)?.expiryMode?.takeIf { it.expirySeconds > 0 }?.let { mode -> if (message.recipient == userPublicKey || !isSyncMessage) { - SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(timestamp, userPublicKey, timestamp) + val expireStartedAt = if (mode is ExpiryMode.AfterRead) timestamp + 1 else timestamp + SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(timestamp, userPublicKey, expireStartedAt) } } } ?: run { 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 0d856c06fe..2ca3be8b51 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 @@ -65,6 +65,8 @@ internal fun MessageReceiver.isBlocked(publicKey: String): Boolean { } fun MessageReceiver.handle(message: Message, proto: SignalServiceProtos.Content, threadId: Long, openGroupID: String?) { + Log.d("MessageReceiver", "handle() called with: message = $message, proto = $proto, threadId = $threadId, openGroupID = $openGroupID") + // Do nothing if the message was outdated if (MessageReceiver.messageIsOutdated(message, threadId, openGroupID)) { return } @@ -122,6 +124,7 @@ private fun MessageReceiver.handleReadReceipt(message: ReadReceipt) { private fun MessageReceiver.handleCallMessage(message: CallMessage) { // TODO: refactor this out to persistence, just to help debug the flow and send/receive in synchronous testing WebRtcUtils.SIGNAL_QUEUE.trySend(message) + SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message, coerceToDisappearAfterRead = true) } private fun MessageReceiver.handleTypingIndicator(message: TypingIndicator) { @@ -153,7 +156,7 @@ fun MessageReceiver.cancelTypingIndicatorsIfNeeded(senderPublicKey: String) { } private fun MessageReceiver.handleExpirationTimerUpdate(message: ExpirationTimerUpdate) { - SSKEnvironment.shared.messageExpirationManager.setExpirationTimer(message) + SSKEnvironment.shared.messageExpirationManager.insertExpirationTimerMessage(message) if (isNewConfigEnabled) return @@ -186,6 +189,7 @@ private fun MessageReceiver.handleDataExtractionNotification(message: DataExtrac else -> return } storage.insertDataExtractionNotificationMessage(senderPublicKey, notification, message.sentTimestamp!!) + SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message, coerceToDisappearAfterRead = true) } private fun handleConfigurationMessage(message: ConfigurationMessage) { @@ -285,6 +289,8 @@ fun MessageReceiver.handleVisibleMessage( runThreadUpdate: Boolean, runProfileUpdate: Boolean ): Long? { + Log.d("ReceivedMessageHandler", "handleVisibleMessage() called with: message = $message, proto = $proto, openGroupID = $openGroupID, threadId = $threadId, runThreadUpdate = $runThreadUpdate, runProfileUpdate = $runProfileUpdate") + val storage = MessagingModuleConfiguration.shared.storage val context = MessagingModuleConfiguration.shared.context val userPublicKey = storage.getUserPublicKey() @@ -386,14 +392,7 @@ fun MessageReceiver.handleVisibleMessage( } } // Parse attachments if needed - val attachments = proto.dataMessage.attachmentsList.mapNotNull { attachmentProto -> - val attachment = Attachment.fromProto(attachmentProto) - if (!attachment.isValid()) { - return@mapNotNull null - } else { - return@mapNotNull attachment - } - } + val attachments = proto.dataMessage.attachmentsList.map(Attachment::fromProto).filter { it.isValid() } // Cancel any typing indicators if needed cancelTypingIndicatorsIfNeeded(message.sender!!) // Parse reaction if needed @@ -429,6 +428,7 @@ fun MessageReceiver.handleVisibleMessage( val isSms = !message.isMediaMessage() && attachments.isEmpty() storage.setOpenGroupServerMessageID(messageID, it, threadID, isSms) } + SSKEnvironment.shared.messageExpirationManager.startAnyExpiration(message) return messageID } return null diff --git a/libsession/src/main/java/org/session/libsession/utilities/SSKEnvironment.kt b/libsession/src/main/java/org/session/libsession/utilities/SSKEnvironment.kt index 378413b6b1..3bba820fc0 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/SSKEnvironment.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/SSKEnvironment.kt @@ -1,10 +1,13 @@ package org.session.libsession.utilities import android.content.Context +import android.util.Log import network.loki.messenger.libsession_util.util.ExpiryMode import org.session.libsession.messaging.contacts.Contact +import org.session.libsession.messaging.messages.Message import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsession.messaging.sending_receiving.notifications.MessageNotifier +import org.session.libsession.snode.SnodeAPI import org.session.libsession.utilities.recipients.Recipient class SSKEnvironment( @@ -38,8 +41,20 @@ class SSKEnvironment( } interface MessageExpirationManagerProtocol { - fun setExpirationTimer(message: ExpirationTimerUpdate) + fun insertExpirationTimerMessage(message: ExpirationTimerUpdate) fun startAnyExpiration(timestamp: Long, author: String, expireStartedAt: Long) + fun startAnyExpiration(message: Message, coerceToDisappearAfterRead: Boolean = false) { + Log.d("MessageExpirationManagerProtocol", "startAnyExpiration() called with: message = $message, coerceToDisappearAfterRead = $coerceToDisappearAfterRead") + + val timestamp = message.sentTimestamp ?: return + startAnyExpiration( + timestamp = timestamp, + author = message.sender ?: return, + expireStartedAt = if (message.expiryMode is ExpiryMode.AfterRead || coerceToDisappearAfterRead && message.expiryMode.expiryMillis > 0) SnodeAPI.nowWithOffset.coerceAtLeast(timestamp + 1) + else if (message.expiryMode is ExpiryMode.AfterSend) timestamp + else return + ) + } } companion object {