Fix message disappearance after send

This commit is contained in:
charles 2022-12-20 13:14:36 +11:00
parent 3c6b93b2f8
commit 42923b5c2b
16 changed files with 92 additions and 41 deletions

View File

@ -108,10 +108,14 @@ class ExpirationSettingsActivity: PassphraseRequiredActionBarActivity() {
lifecycleScope.launchWhenStarted { lifecycleScope.launchWhenStarted {
launch { launch {
viewModel.uiState.collect { uiState -> viewModel.uiState.collect { uiState ->
if (uiState.settingsSaved == true) { when (uiState.settingsSaved) {
Toast.makeText(this@ExpirationSettingsActivity, getString(R.string.ExpirationSettingsActivity_settings_saved), Toast.LENGTH_SHORT).show() true -> {
showToast(getString(R.string.ExpirationSettingsActivity_settings_updated))
finish() finish()
} }
false -> showToast(getString(R.string.ExpirationSettingsActivity_settings_not_updated))
else -> {}
}
} }
} }
launch { launch {
@ -145,6 +149,10 @@ class ExpirationSettingsActivity: PassphraseRequiredActionBarActivity() {
} }
private fun showToast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
private fun getDeleteOptions(): List<RadioOption> { private fun getDeleteOptions(): List<RadioOption> {
if (!viewModel.uiState.value.showExpirationTypeSelector) return emptyList() if (!viewModel.uiState.value.showExpirationTypeSelector) return emptyList()

View File

@ -88,6 +88,7 @@ class ExpirationSettingsViewModel(
fun onExpirationTypeSelected(option: RadioOption) { fun onExpirationTypeSelected(option: RadioOption) {
_selectedExpirationType.value = option.value.toIntOrNull() ?: -1 _selectedExpirationType.value = option.value.toIntOrNull() ?: -1
_selectedExpirationTimer.value = _expirationTimerOptions.value.firstOrNull()
} }
fun onExpirationTimerSelected(option: RadioOption) { fun onExpirationTimerSelected(option: RadioOption) {
@ -96,16 +97,22 @@ class ExpirationSettingsViewModel(
fun onSetClick() = viewModelScope.launch { fun onSetClick() = viewModelScope.launch {
val expiryType = _selectedExpirationType.value val expiryType = _selectedExpirationType.value
val firstOption = _expirationTimerOptions.value.firstOrNull()?.value?.toIntOrNull() ?: 0 val expirationTimer = _selectedExpirationTimer.value?.value?.toIntOrNull() ?: 0
val expiresIn = _selectedExpirationTimer.value?.value?.toIntOrNull() ?: if (expiryType >= 0) firstOption else 0 val address = recipient.value?.address
val expiryChangeTimestampMs = System.currentTimeMillis() if (address == null || (expirationConfig?.expirationTypeValue == expiryType && expirationConfig?.durationSeconds == expirationTimer)) {
storage.setExpirationConfiguration(ExpirationConfiguration(threadId, expiresIn, expiryType, expiryChangeTimestampMs)) _uiState.update {
it.copy(settingsSaved = false)
}
return@launch
}
val message = ExpirationTimerUpdate(expiresIn) val expiryChangeTimestampMs = System.currentTimeMillis()
val address = recipient.value?.address ?: return@launch storage.setExpirationConfiguration(ExpirationConfiguration(threadId, expirationTimer, expiryType, expiryChangeTimestampMs))
val message = ExpirationTimerUpdate(expirationTimer)
message.recipient = address.serialize() message.recipient = address.serialize()
message.sentTimestamp = System.currentTimeMillis() message.sentTimestamp = expiryChangeTimestampMs
messageExpirationManager.setExpirationTimer(message) messageExpirationManager.setExpirationTimer(message, expiryType)
MessageSender.send(message, address) MessageSender.send(message, address)
_uiState.update { _uiState.update {

View File

@ -65,6 +65,7 @@ import org.session.libsession.utilities.recipients.Recipient
import org.session.libsession.utilities.recipients.Recipient.DisappearingState import org.session.libsession.utilities.recipients.Recipient.DisappearingState
import org.session.libsession.utilities.recipients.RecipientModifiedListener import org.session.libsession.utilities.recipients.RecipientModifiedListener
import org.session.libsignal.crypto.MnemonicCodec import org.session.libsignal.crypto.MnemonicCodec
import org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType
import org.session.libsignal.utilities.IdPrefix import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.ListenableFuture import org.session.libsignal.utilities.ListenableFuture
import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.Log
@ -1356,8 +1357,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
val recipient = viewModel.recipient ?: return val recipient = viewModel.recipient ?: return
processMessageRequestApproval() processMessageRequestApproval()
// Create the message // Create the message
val sentTimestampMs = System.currentTimeMillis()
val message = VisibleMessage() val message = VisibleMessage()
message.sentTimestamp = System.currentTimeMillis() message.sentTimestamp = sentTimestampMs
message.text = body message.text = body
val quote = quotedMessage?.let { val quote = quotedMessage?.let {
val quotedAttachments = (it as? MmsMessageRecord)?.slideDeck?.asAttachments() ?: listOf() val quotedAttachments = (it as? MmsMessageRecord)?.slideDeck?.asAttachments() ?: listOf()
@ -1372,8 +1374,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
else it.individualRecipient.address else it.individualRecipient.address
quote?.copy(author = sender) quote?.copy(author = sender)
} }
val expiresInMillis = (viewModel.expirationConfiguration?.durationSeconds ?: 0) * 1000L val expiresInMs = (viewModel.expirationConfiguration?.durationSeconds ?: 0) * 1000L
val outgoingTextMessage = OutgoingMediaMessage.from(message, recipient, attachments, localQuote, linkPreview, expiresInMillis) val expireStartedAtMs = if (viewModel.expirationConfiguration?.expirationType == ExpirationType.DELETE_AFTER_SEND) {
sentTimestampMs + expiresInMs
} else 0
val outgoingTextMessage = OutgoingMediaMessage.from(message, recipient, attachments, localQuote, linkPreview, expiresInMs, expireStartedAtMs)
// Clear the input bar // Clear the input bar
binding?.inputBar?.text = "" binding?.inputBar?.text = ""
binding?.inputBar?.cancelQuoteDraft() binding?.inputBar?.cancelQuoteDraft()

View File

@ -467,6 +467,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
val timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT)) val timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT))
val subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID)) val subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID))
val expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN)) val expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN))
val expireStartedAt = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED))
val address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)) val address = cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS))
val threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID)) val threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID))
val distributionType = get(context).threadDatabase().getDistributionType(threadId) val distributionType = get(context).threadDatabase().getDistributionType(threadId)
@ -535,6 +536,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
timestamp, timestamp,
subscriptionId, subscriptionId,
expiresIn, expiresIn,
expireStartedAt,
distributionType, distributionType,
quote, quote,
contacts, contacts,
@ -663,6 +665,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
contentValues.put(PART_COUNT, retrieved.attachments.size) contentValues.put(PART_COUNT, retrieved.attachments.size)
contentValues.put(SUBSCRIPTION_ID, retrieved.subscriptionId) contentValues.put(SUBSCRIPTION_ID, retrieved.subscriptionId)
contentValues.put(EXPIRES_IN, retrieved.expiresIn) contentValues.put(EXPIRES_IN, retrieved.expiresIn)
contentValues.put(EXPIRE_STARTED, retrieved.expireStartedAt)
contentValues.put(READ, if (retrieved.isExpirationUpdate) 1 else 0) contentValues.put(READ, if (retrieved.isExpirationUpdate) 1 else 0)
contentValues.put(UNIDENTIFIED, retrieved.isUnidentified) contentValues.put(UNIDENTIFIED, retrieved.isUnidentified)
contentValues.put(MESSAGE_REQUEST_RESPONSE, retrieved.isMessageRequestResponse) contentValues.put(MESSAGE_REQUEST_RESPONSE, retrieved.isMessageRequestResponse)
@ -805,6 +808,7 @@ class MmsDatabase(context: Context, databaseHelper: SQLCipherOpenHelper) : Messa
contentValues.put(DATE_RECEIVED, receivedTimestamp) contentValues.put(DATE_RECEIVED, receivedTimestamp)
contentValues.put(SUBSCRIPTION_ID, message.subscriptionId) contentValues.put(SUBSCRIPTION_ID, message.subscriptionId)
contentValues.put(EXPIRES_IN, message.expiresIn) contentValues.put(EXPIRES_IN, message.expiresIn)
contentValues.put(EXPIRE_STARTED, message.expireStartedAt)
contentValues.put(ADDRESS, message.recipient.address.serialize()) contentValues.put(ADDRESS, message.recipient.address.serialize())
contentValues.put( contentValues.put(
DELIVERY_RECEIPT_COUNT, DELIVERY_RECEIPT_COUNT,

View File

@ -158,7 +158,11 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
recipientDb.setApprovedMe(targetRecipient, true) recipientDb.setApprovedMe(targetRecipient, true)
} }
} }
val expiresIn = getExpirationConfiguration(message.threadID ?: -1)?.durationSeconds ?: 0 val expirationConfig = getExpirationConfiguration(message.threadID ?: -1)
val expiresIn = expirationConfig?.durationSeconds ?: 0
val expireStartedAt = if (expirationConfig?.expirationType == ExpirationType.DELETE_AFTER_SEND) {
message.sentTimestamp!! + (expirationConfig.durationSeconds * 1000L)
} else 0
if (message.isMediaMessage() || attachments.isNotEmpty()) { if (message.isMediaMessage() || attachments.isNotEmpty()) {
val quote: Optional<QuoteModel> = if (quotes != null) Optional.of(quotes) else Optional.absent() val quote: Optional<QuoteModel> = if (quotes != null) Optional.of(quotes) else Optional.absent()
val linkPreviews: Optional<List<LinkPreview>> = if (linkPreview.isEmpty()) Optional.absent() else Optional.of(linkPreview.mapNotNull { it!! }) val linkPreviews: Optional<List<LinkPreview>> = if (linkPreview.isEmpty()) Optional.absent() else Optional.of(linkPreview.mapNotNull { it!! })
@ -170,7 +174,8 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
pointers, pointers,
quote.orNull(), quote.orNull(),
linkPreviews.orNull()?.firstOrNull(), linkPreviews.orNull()?.firstOrNull(),
expiresIn * 1000L expiresIn * 1000L,
expireStartedAt
) )
mmsDatabase.insertSecureDecryptedMessageOutbox(mediaMessage, message.threadID ?: -1, message.sentTimestamp!!, runThreadUpdate) mmsDatabase.insertSecureDecryptedMessageOutbox(mediaMessage, message.threadID ?: -1, message.sentTimestamp!!, runThreadUpdate)
} else { } else {
@ -178,7 +183,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
val signalServiceAttachments = attachments.mapNotNull { val signalServiceAttachments = attachments.mapNotNull {
it.toSignalPointer() it.toSignalPointer()
} }
val mediaMessage = IncomingMediaMessage.from(message, senderAddress, expiresIn * 1000L, group, signalServiceAttachments, quote, linkPreviews) val mediaMessage = IncomingMediaMessage.from(message, senderAddress, expiresIn * 1000L, expireStartedAt, group, signalServiceAttachments, quote, linkPreviews)
mmsDatabase.insertSecureDecryptedMessageInbox(mediaMessage, message.threadID ?: -1, message.receivedTimestamp ?: 0, runIncrement, runThreadUpdate) mmsDatabase.insertSecureDecryptedMessageInbox(mediaMessage, message.threadID ?: -1, message.receivedTimestamp ?: 0, runIncrement, runThreadUpdate)
} }
if (insertResult.isPresent) { if (insertResult.isPresent) {
@ -485,7 +490,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
val recipient = Recipient.from(context, fromSerialized(groupID), false) val recipient = Recipient.from(context, fromSerialized(groupID), false)
val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() ?: "" val updateData = UpdateMessageData.buildGroupUpdate(type, name, members)?.toJSON() ?: ""
val infoMessage = OutgoingGroupMediaMessage(recipient, updateData, groupID, null, sentTimestamp, 0, true, null, listOf(), listOf()) val infoMessage = OutgoingGroupMediaMessage(recipient, updateData, groupID, null, sentTimestamp, 0, 0, true, null, listOf(), listOf())
val mmsDB = DatabaseComponent.get(context).mmsDatabase() val mmsDB = DatabaseComponent.get(context).mmsDatabase()
val mmsSmsDB = DatabaseComponent.get(context).mmsSmsDatabase() val mmsSmsDB = DatabaseComponent.get(context).mmsSmsDatabase()
if (mmsSmsDB.getMessageFor(sentTimestamp, userPublicKey) != null) return if (mmsSmsDB.getMessageFor(sentTimestamp, userPublicKey) != null) return
@ -736,6 +741,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
sentTimestamp, sentTimestamp,
-1, -1,
0, 0,
0,
false, false,
false, false,
false, false,
@ -810,6 +816,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context,
response.sentTimestamp!!, response.sentTimestamp!!,
-1, -1,
0, 0,
0,
false, false,
false, false,
true, true,

View File

@ -90,7 +90,7 @@ public class AndroidAutoReplyReceiver extends BroadcastReceiver {
if (recipient.isGroupRecipient()) { if (recipient.isGroupRecipient()) {
Log.w("AndroidAutoReplyReceiver", "GroupRecipient, Sending media message"); Log.w("AndroidAutoReplyReceiver", "GroupRecipient, Sending media message");
OutgoingMediaMessage reply = OutgoingMediaMessage.from(message, recipient, Collections.emptyList(), null, null, expiresInMillis); OutgoingMediaMessage reply = OutgoingMediaMessage.from(message, recipient, Collections.emptyList(), null, null, expiresInMillis, 0);
try { try {
DatabaseComponent.get(context).mmsDatabase().insertMessageOutbox(reply, replyThreadId, false, null, true); DatabaseComponent.get(context).mmsDatabase().insertMessageOutbox(reply, replyThreadId, false, null, true);
} catch (MmsException e) { } catch (MmsException e) {

View File

@ -83,7 +83,7 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
long expiresInMillis = config == null ? 0 : config.getDurationSeconds() * 1000L; long expiresInMillis = config == null ? 0 : config.getDurationSeconds() * 1000L;
switch (replyMethod) { switch (replyMethod) {
case GroupMessage: { case GroupMessage: {
OutgoingMediaMessage reply = OutgoingMediaMessage.from(message, recipient, Collections.emptyList(), null, null, expiresInMillis); OutgoingMediaMessage reply = OutgoingMediaMessage.from(message, recipient, Collections.emptyList(), null, null, expiresInMillis, 0);
try { try {
DatabaseComponent.get(context).mmsDatabase().insertMessageOutbox(reply, threadId, false, null, true); DatabaseComponent.get(context).mmsDatabase().insertMessageOutbox(reply, threadId, false, null, true);
MessageSender.send(message, address); MessageSender.send(message, address);

View File

@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.service;
import android.content.Context; import android.content.Context;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.session.libsession.messaging.messages.ExpirationConfiguration; import org.session.libsession.messaging.messages.ExpirationConfiguration;
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate; import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate;
import org.session.libsession.messaging.messages.signal.IncomingMediaMessage; import org.session.libsession.messaging.messages.signal.IncomingMediaMessage;
@ -14,11 +13,11 @@ import org.session.libsession.utilities.SSKEnvironment;
import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsession.utilities.recipients.Recipient; import org.session.libsession.utilities.recipients.Recipient;
import org.session.libsignal.messages.SignalServiceGroup; import org.session.libsignal.messages.SignalServiceGroup;
import org.session.libsignal.protos.SignalServiceProtos.Content.ExpirationType;
import org.session.libsignal.utilities.Log; import org.session.libsignal.utilities.Log;
import org.session.libsignal.utilities.guava.Optional; import org.session.libsignal.utilities.guava.Optional;
import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase; import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.dependencies.DatabaseComponent; import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.MmsException;
@ -69,16 +68,18 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
} }
@Override @Override
public void setExpirationTimer(@NotNull ExpirationTimerUpdate message) { public void setExpirationTimer(@NotNull ExpirationTimerUpdate message, int expiryType) {
String userPublicKey = TextSecurePreferences.getLocalNumber(context); String userPublicKey = TextSecurePreferences.getLocalNumber(context);
String senderPublicKey = message.getSender(); String senderPublicKey = message.getSender();
long expireStartedAt = ExpirationType.DELETE_AFTER_SEND_VALUE != expiryType
? 0 : message.getSentTimestamp() + (message.getDuration() * 1000L);
// Notify the user // Notify the user
if (senderPublicKey == null || userPublicKey.equals(senderPublicKey)) { if (senderPublicKey == null || userPublicKey.equals(senderPublicKey)) {
// sender is self or a linked device // sender is self or a linked device
insertOutgoingExpirationTimerMessage(message); insertOutgoingExpirationTimerMessage(message, expireStartedAt);
} else { } else {
insertIncomingExpirationTimerMessage(message); insertIncomingExpirationTimerMessage(message, expireStartedAt);
} }
if (message.getId() != null) { if (message.getId() != null) {
@ -86,7 +87,7 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
} }
} }
private void insertIncomingExpirationTimerMessage(ExpirationTimerUpdate message) { private void insertIncomingExpirationTimerMessage(ExpirationTimerUpdate message, long expireStartedAt) {
MmsDatabase database = DatabaseComponent.get(context).mmsDatabase(); MmsDatabase database = DatabaseComponent.get(context).mmsDatabase();
String senderPublicKey = message.getSender(); String senderPublicKey = message.getSender();
@ -111,7 +112,7 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
} }
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(address, sentTimestamp, -1, IncomingMediaMessage mediaMessage = new IncomingMediaMessage(address, sentTimestamp, -1,
duration * 1000L, true, duration * 1000L, expireStartedAt, true,
false, false,
false, false,
Optional.absent(), Optional.absent(),
@ -128,7 +129,7 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
} }
} }
private void insertOutgoingExpirationTimerMessage(ExpirationTimerUpdate message) { private void insertOutgoingExpirationTimerMessage(ExpirationTimerUpdate message, long expireStartedAt) {
MmsDatabase database = DatabaseComponent.get(context).mmsDatabase(); MmsDatabase database = DatabaseComponent.get(context).mmsDatabase();
Long sentTimestamp = message.getSentTimestamp(); Long sentTimestamp = message.getSentTimestamp();
@ -139,7 +140,7 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
Recipient recipient = Recipient.from(context, address, false); Recipient recipient = Recipient.from(context, address, false);
try { try {
OutgoingExpirationUpdateMessage timerUpdateMessage = new OutgoingExpirationUpdateMessage(recipient, sentTimestamp, duration * 1000L, groupId); OutgoingExpirationUpdateMessage timerUpdateMessage = new OutgoingExpirationUpdateMessage(recipient, sentTimestamp, duration * 1000L, expireStartedAt, groupId);
database.insertSecureDecryptedMessageOutbox(timerUpdateMessage, -1, sentTimestamp, true); database.insertSecureDecryptedMessageOutbox(timerUpdateMessage, -1, sentTimestamp, true);
} catch (MmsException e) { } catch (MmsException e) {
Log.e("Loki", "Failed to insert expiration update message."); Log.e("Loki", "Failed to insert expiration update message.");

View File

@ -885,5 +885,6 @@
<string name="activity_expiration_settings_timer">Timer</string> <string name="activity_expiration_settings_timer">Timer</string>
<string name="activity_expiration_settings_group_footer"><![CDATA[This setting applies to everyone in this conversation.<br/>Only group admins can change this setting.]]></string> <string name="activity_expiration_settings_group_footer"><![CDATA[This setting applies to everyone in this conversation.<br/>Only group admins can change this setting.]]></string>
<string name="activity_conversation_outdated_client_banner_text">%s is using an outdated client. Disappearing messages may not work as expected.</string> <string name="activity_conversation_outdated_client_banner_text">%s is using an outdated client. Disappearing messages may not work as expected.</string>
<string name="ExpirationSettingsActivity_settings_saved">Settings saved</string> <string name="ExpirationSettingsActivity_settings_updated">Settings updated</string>
<string name="ExpirationSettingsActivity_settings_not_updated">Settings not updated and please try again</string>
</resources> </resources>

View File

@ -26,6 +26,7 @@ public class IncomingMediaMessage {
private final long sentTimeMillis; private final long sentTimeMillis;
private final int subscriptionId; private final int subscriptionId;
private final long expiresIn; private final long expiresIn;
private final long expireStartedAt;
private final boolean expirationUpdate; private final boolean expirationUpdate;
private final boolean unidentified; private final boolean unidentified;
private final boolean messageRequestResponse; private final boolean messageRequestResponse;
@ -41,6 +42,7 @@ public class IncomingMediaMessage {
long sentTimeMillis, long sentTimeMillis,
int subscriptionId, int subscriptionId,
long expiresIn, long expiresIn,
long expireStartedAt,
boolean expirationUpdate, boolean expirationUpdate,
boolean unidentified, boolean unidentified,
boolean messageRequestResponse, boolean messageRequestResponse,
@ -58,6 +60,7 @@ public class IncomingMediaMessage {
this.body = body.orNull(); this.body = body.orNull();
this.subscriptionId = subscriptionId; this.subscriptionId = subscriptionId;
this.expiresIn = expiresIn; this.expiresIn = expiresIn;
this.expireStartedAt = expireStartedAt;
this.expirationUpdate = expirationUpdate; this.expirationUpdate = expirationUpdate;
this.dataExtractionNotification = dataExtractionNotification.orNull(); this.dataExtractionNotification = dataExtractionNotification.orNull();
this.quote = quote.orNull(); this.quote = quote.orNull();
@ -75,12 +78,13 @@ public class IncomingMediaMessage {
public static IncomingMediaMessage from(VisibleMessage message, public static IncomingMediaMessage from(VisibleMessage message,
Address from, Address from,
long expiresIn, long expiresIn,
long expireStartedAt,
Optional<SignalServiceGroup> group, Optional<SignalServiceGroup> group,
List<SignalServiceAttachment> attachments, List<SignalServiceAttachment> attachments,
Optional<QuoteModel> quote, Optional<QuoteModel> quote,
Optional<List<LinkPreview>> linkPreviews) Optional<List<LinkPreview>> linkPreviews)
{ {
return new IncomingMediaMessage(from, message.getSentTimestamp(), -1, expiresIn, false, return new IncomingMediaMessage(from, message.getSentTimestamp(), -1, expiresIn, expireStartedAt, false,
false, false, Optional.fromNullable(message.getText()), group, Optional.fromNullable(attachments), quote, Optional.absent(), linkPreviews, Optional.absent()); false, false, Optional.fromNullable(message.getText()), group, Optional.fromNullable(attachments), quote, Optional.absent(), linkPreviews, Optional.absent());
} }
@ -120,6 +124,10 @@ public class IncomingMediaMessage {
return expiresIn; return expiresIn;
} }
public long getExpireStartedAt() {
return expireStartedAt;
}
public boolean isGroupMessage() { public boolean isGroupMessage() {
return groupId != null; return groupId != null;
} }

View File

@ -11,9 +11,9 @@ public class OutgoingExpirationUpdateMessage extends OutgoingSecureMediaMessage
private final String groupId; private final String groupId;
public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn, String groupId) { public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn, long expireStartedAt, String groupId) {
super(recipient, "", new LinkedList<Attachment>(), sentTimeMillis, super(recipient, "", new LinkedList<Attachment>(), sentTimeMillis,
DistributionTypes.CONVERSATION, expiresIn, null, Collections.emptyList(), DistributionTypes.CONVERSATION, expiresIn, expireStartedAt, null, Collections.emptyList(),
Collections.emptyList()); Collections.emptyList());
this.groupId = groupId; this.groupId = groupId;
} }

View File

@ -24,6 +24,7 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
@Nullable final Attachment avatar, @Nullable final Attachment avatar,
long sentTime, long sentTime,
long expireIn, long expireIn,
long expireStartedAt,
boolean updateMessage, boolean updateMessage,
@Nullable QuoteModel quote, @Nullable QuoteModel quote,
@NonNull List<Contact> contacts, @NonNull List<Contact> contacts,
@ -32,7 +33,7 @@ public class OutgoingGroupMediaMessage extends OutgoingSecureMediaMessage {
super(recipient, body, super(recipient, body,
new LinkedList<Attachment>() {{if (avatar != null) add(avatar);}}, new LinkedList<Attachment>() {{if (avatar != null) add(avatar);}},
sentTime, sentTime,
DistributionTypes.CONVERSATION, expireIn, quote, contacts, previews); DistributionTypes.CONVERSATION, expireIn, expireStartedAt, quote, contacts, previews);
this.groupID = groupId; this.groupID = groupId;
this.isUpdateMessage = updateMessage; this.isUpdateMessage = updateMessage;

View File

@ -26,6 +26,7 @@ public class OutgoingMediaMessage {
private final int distributionType; private final int distributionType;
private final int subscriptionId; private final int subscriptionId;
private final long expiresIn; private final long expiresIn;
private final long expireStartedAt;
private final QuoteModel outgoingQuote; private final QuoteModel outgoingQuote;
private final List<NetworkFailure> networkFailures = new LinkedList<>(); private final List<NetworkFailure> networkFailures = new LinkedList<>();
@ -35,7 +36,7 @@ public class OutgoingMediaMessage {
public OutgoingMediaMessage(Recipient recipient, String message, public OutgoingMediaMessage(Recipient recipient, String message,
List<Attachment> attachments, long sentTimeMillis, List<Attachment> attachments, long sentTimeMillis,
int subscriptionId, long expiresIn, int subscriptionId, long expiresIn, long expireStartedAt,
int distributionType, int distributionType,
@Nullable QuoteModel outgoingQuote, @Nullable QuoteModel outgoingQuote,
@NonNull List<Contact> contacts, @NonNull List<Contact> contacts,
@ -50,6 +51,7 @@ public class OutgoingMediaMessage {
this.attachments = attachments; this.attachments = attachments;
this.subscriptionId = subscriptionId; this.subscriptionId = subscriptionId;
this.expiresIn = expiresIn; this.expiresIn = expiresIn;
this.expireStartedAt = expireStartedAt;
this.outgoingQuote = outgoingQuote; this.outgoingQuote = outgoingQuote;
this.contacts.addAll(contacts); this.contacts.addAll(contacts);
@ -66,6 +68,7 @@ public class OutgoingMediaMessage {
this.sentTimeMillis = that.sentTimeMillis; this.sentTimeMillis = that.sentTimeMillis;
this.subscriptionId = that.subscriptionId; this.subscriptionId = that.subscriptionId;
this.expiresIn = that.expiresIn; this.expiresIn = that.expiresIn;
this.expireStartedAt = that.expireStartedAt;
this.outgoingQuote = that.outgoingQuote; this.outgoingQuote = that.outgoingQuote;
this.identityKeyMismatches.addAll(that.identityKeyMismatches); this.identityKeyMismatches.addAll(that.identityKeyMismatches);
@ -79,14 +82,15 @@ public class OutgoingMediaMessage {
List<Attachment> attachments, List<Attachment> attachments,
@Nullable QuoteModel outgoingQuote, @Nullable QuoteModel outgoingQuote,
@Nullable LinkPreview linkPreview, @Nullable LinkPreview linkPreview,
long expiresInMillis) long expiresInMillis,
long expireStartedAt)
{ {
List<LinkPreview> previews = Collections.emptyList(); List<LinkPreview> previews = Collections.emptyList();
if (linkPreview != null) { if (linkPreview != null) {
previews = Collections.singletonList(linkPreview); previews = Collections.singletonList(linkPreview);
} }
return new OutgoingMediaMessage(recipient, message.getText(), attachments, message.getSentTimestamp(), -1, return new OutgoingMediaMessage(recipient, message.getText(), attachments, message.getSentTimestamp(), -1,
expiresInMillis, DistributionTypes.DEFAULT, outgoingQuote, Collections.emptyList(), expiresInMillis, expireStartedAt, DistributionTypes.DEFAULT, outgoingQuote, Collections.emptyList(),
previews, Collections.emptyList(), Collections.emptyList()); previews, Collections.emptyList(), Collections.emptyList());
} }
@ -124,6 +128,10 @@ public class OutgoingMediaMessage {
return expiresIn; return expiresIn;
} }
public long getExpireStartedAt() {
return expireStartedAt;
}
public @Nullable QuoteModel getOutgoingQuote() { public @Nullable QuoteModel getOutgoingQuote() {
return outgoingQuote; return outgoingQuote;
} }

View File

@ -19,11 +19,12 @@ public class OutgoingSecureMediaMessage extends OutgoingMediaMessage {
long sentTimeMillis, long sentTimeMillis,
int distributionType, int distributionType,
long expiresIn, long expiresIn,
long expireStartedAt,
@Nullable QuoteModel quote, @Nullable QuoteModel quote,
@NonNull List<Contact> contacts, @NonNull List<Contact> contacts,
@NonNull List<LinkPreview> previews) @NonNull List<LinkPreview> previews)
{ {
super(recipient, body, attachments, sentTimeMillis, -1, expiresIn, distributionType, quote, contacts, previews, Collections.emptyList(), Collections.emptyList()); super(recipient, body, attachments, sentTimeMillis, -1, expiresIn, expireStartedAt, distributionType, quote, contacts, previews, Collections.emptyList(), Collections.emptyList());
} }
public OutgoingSecureMediaMessage(OutgoingMediaMessage base) { public OutgoingSecureMediaMessage(OutgoingMediaMessage base) {

View File

@ -105,7 +105,7 @@ fun updateExpirationConfigurationIfNeeded(message: Message, proto: SignalService
) )
storage.setExpirationConfiguration(remoteConfig) storage.setExpirationConfiguration(remoteConfig)
if (message is ExpirationTimerUpdate) { if (message is ExpirationTimerUpdate) {
SSKEnvironment.shared.messageExpirationManager.setExpirationTimer(message) SSKEnvironment.shared.messageExpirationManager.setExpirationTimer(message, type?.number ?: -1)
} }
} }
@ -181,7 +181,7 @@ private fun MessageReceiver.handleExpirationTimerUpdate(message: ExpirationTimer
} catch (e: Exception) { } catch (e: Exception) {
Log.e("Loki", "Failed to update expiration configuration.") Log.e("Loki", "Failed to update expiration configuration.")
} }
SSKEnvironment.shared.messageExpirationManager.setExpirationTimer(message) SSKEnvironment.shared.messageExpirationManager.setExpirationTimer(message, type?.number ?: -1)
} }
private fun MessageReceiver.handleDataExtractionNotification(message: DataExtractionNotification) { private fun MessageReceiver.handleDataExtractionNotification(message: DataExtractionNotification) {

View File

@ -36,7 +36,7 @@ class SSKEnvironment(
} }
interface MessageExpirationManagerProtocol { interface MessageExpirationManagerProtocol {
fun setExpirationTimer(message: ExpirationTimerUpdate) fun setExpirationTimer(message: ExpirationTimerUpdate, expiryType: Int)
fun startAnyExpiration(timestamp: Long, author: String) fun startAnyExpiration(timestamp: Long, author: String)
} }