Convert OutgoingMediaMessage and it's couterparts to kotlin.

This commit is contained in:
Cody Henthorne 2022-12-09 09:48:16 -05:00
parent 8cd9a3cabe
commit c56e63d62f
33 changed files with 544 additions and 1029 deletions

View file

@ -9,11 +9,8 @@ import org.junit.runner.RunWith
import org.signal.core.util.ThreadUtil
import org.thoughtcrime.securesms.attachments.PointerAttachment
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.ThreadTable
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.mms.IncomingMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
import org.thoughtcrime.securesms.profiles.ProfileName
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.releasechannel.ReleaseChannel
@ -113,28 +110,15 @@ class ConversationItemPreviewer {
}
val message = OutgoingMediaMessage(
other,
body,
PointerAttachment.forPointers(Optional.of(attachments)),
System.currentTimeMillis(),
-1,
0,
false,
ThreadTable.DistributionTypes.DEFAULT,
StoryType.NONE,
null,
false,
null,
emptyList(),
emptyList(),
emptyList(),
emptySet(),
emptySet(),
null
recipient = other,
body = body,
attachments = PointerAttachment.forPointers(Optional.of(attachments)),
timestamp = System.currentTimeMillis(),
isSecure = true
)
val insert = SignalDatabase.mms.insertMessageOutbox(
OutgoingSecureMediaMessage(message),
message,
SignalDatabase.threads.getOrCreateThreadIdFor(other),
false,
null

View file

@ -5,7 +5,6 @@ import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
import org.thoughtcrime.securesms.mms.IncomingMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
import org.thoughtcrime.securesms.recipients.Recipient
import java.util.Optional
@ -30,27 +29,19 @@ object MmsHelper {
secure: Boolean = true
): Long {
val message = OutgoingMediaMessage(
recipient,
body,
emptyList(),
sentTimeMillis,
subscriptionId,
expiresIn,
viewOnce,
distributionType,
storyType,
parentStoryId,
isStoryReaction,
null,
emptyList(),
emptyList(),
emptyList(),
emptySet(),
emptySet(),
giftBadge
).let {
if (secure) OutgoingSecureMediaMessage(it) else it
}
recipient = recipient,
body = body,
timestamp = sentTimeMillis,
subscriptionId = subscriptionId,
expiresIn = expiresIn,
viewOnce = viewOnce,
distributionType = distributionType,
storyType = storyType,
parentStoryId = parentStoryId,
isStoryReaction = isStoryReaction,
giftBadge = giftBadge,
isSecure = secure
)
return insert(
message = message,

View file

@ -4,11 +4,8 @@ import android.content.Context
import org.signal.libsignal.zkgroup.InvalidInputException
import org.signal.libsignal.zkgroup.receipts.ReceiptCredentialPresentation
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.database.ThreadTable
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.Base64
import java.lang.Integer.min
@ -33,22 +30,13 @@ object Gifts {
sentTimestamp: Long,
expiresIn: Long
): OutgoingMediaMessage {
return OutgoingSecureMediaMessage(
recipient,
Base64.encodeBytes(giftBadge.toByteArray()),
listOf(),
sentTimestamp,
ThreadTable.DistributionTypes.CONVERSATION,
expiresIn,
false,
StoryType.NONE,
null,
false,
null,
listOf(),
listOf(),
listOf(),
giftBadge
return OutgoingMediaMessage(
recipient = recipient,
body = Base64.encodeBytes(giftBadge.toByteArray()),
isSecure = true,
sentTimeMillis = sentTimestamp,
expiresIn = expiresIn,
giftBadge = giftBadge
)
}

View file

@ -9,7 +9,7 @@ import org.thoughtcrime.securesms.database.ThreadTable
import org.thoughtcrime.securesms.groups.GroupChangeException
import org.thoughtcrime.securesms.groups.GroupManager
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.sms.MessageSender
@ -39,7 +39,7 @@ class ExpireTimerSettingsRepository(val context: Context) {
}
} else {
SignalDatabase.recipients.setExpireMessages(recipientId, newExpirationTime)
val outgoingMessage = OutgoingExpirationUpdateMessage(Recipient.resolved(recipientId), System.currentTimeMillis(), newExpirationTime * 1000L)
val outgoingMessage = OutgoingMediaMessage.expirationUpdateMessage(Recipient.resolved(recipientId), System.currentTimeMillis(), newExpirationTime * 1000L)
MessageSender.send(context, outgoingMessage, getThreadId(recipientId), false, null, null)
consumer.invoke(Result.success(newExpirationTime))
}

View file

@ -238,7 +238,6 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.ImageSlide;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.mms.QuoteId;
import org.thoughtcrime.securesms.mms.QuoteModel;
import org.thoughtcrime.securesms.mms.Slide;
@ -2970,12 +2969,29 @@ public class ConversationParentFragment extends Fragment
}
private void sendMediaMessage(@NonNull MediaSendActivityResult result) {
long thread = this.threadId;
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.get().getExpiresInSeconds());
QuoteModel quote = result.isViewOnce() ? null : inputPanel.getQuote().orElse(null);
List<Mention> mentions = new ArrayList<>(result.getMentions());
OutgoingMediaMessage message = new OutgoingMediaMessage(recipient.get(), new SlideDeck(), result.getBody(), System.currentTimeMillis(), -1, expiresIn, result.isViewOnce(), distributionType, result.getStoryType(), null, false, quote, Collections.emptyList(), Collections.emptyList(), mentions, null);
OutgoingMediaMessage secureMessage = new OutgoingSecureMediaMessage(message);
long thread = this.threadId;
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.get().getExpiresInSeconds());
QuoteModel quote = result.isViewOnce() ? null : inputPanel.getQuote().orElse(null);
List<Mention> mentions = new ArrayList<>(result.getMentions());
OutgoingMediaMessage message = new OutgoingMediaMessage(recipient.get(),
result.getBody(),
Collections.emptyList(),
System.currentTimeMillis(),
-1,
expiresIn,
result.isViewOnce(),
distributionType,
result.getStoryType(),
null,
false,
quote,
Collections.emptyList(),
Collections.emptyList(),
mentions,
Collections.emptySet(),
Collections.emptySet(),
null,
true);
final Context context = requireContext().getApplicationContext();
@ -2985,10 +3001,10 @@ public class ConversationParentFragment extends Fragment
attachmentManager.clear(glideRequests, false);
silentlySetComposeText("");
long id = fragment.stageOutgoingMessage(secureMessage);
long id = fragment.stageOutgoingMessage(message);
SimpleTask.run(() -> {
long resultId = MessageSender.sendPushWithPreUploadedMedia(context, secureMessage, result.getPreUploadResults(), thread, null);
long resultId = MessageSender.sendPushWithPreUploadedMedia(context, message, result.getPreUploadResults(), thread, null);
int deleted = SignalDatabase.attachments().deleteAbandonedPreuploadedAttachments();
Log.i(TAG, "Deleted " + deleted + " abandoned attachments.");
@ -3048,7 +3064,25 @@ public class ConversationParentFragment extends Fragment
}
}
OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(Recipient.resolved(recipientId), slideDeck, body, System.currentTimeMillis(), sendType.getSimSubscriptionIdOr(-1), expiresIn, viewOnce, distributionType, StoryType.NONE, null, false, quote, contacts, previews, mentions, null);
OutgoingMediaMessage outgoingMessageCandidate = new OutgoingMediaMessage(Recipient.resolved(recipientId),
OutgoingMediaMessage.buildMessage(slideDeck, body),
slideDeck.asAttachments(),
System.currentTimeMillis(),
sendType.getSimSubscriptionIdOr(-1),
expiresIn,
viewOnce,
distributionType,
StoryType.NONE,
null,
false,
quote,
contacts,
previews,
mentions,
Collections.emptySet(),
Collections.emptySet(),
null,
false);
final SettableFuture<Void> future = new SettableFuture<>();
final Context context = requireContext().getApplicationContext();
@ -3056,7 +3090,7 @@ public class ConversationParentFragment extends Fragment
final OutgoingMediaMessage outgoingMessage;
if (sendPush) {
outgoingMessage = new OutgoingSecureMediaMessage(outgoingMessageCandidate);
outgoingMessage = outgoingMessageCandidate.makeSecure();
ApplicationDependencies.getTypingStatusSender().onTypingStopped(thread);
} else {
outgoingMessage = outgoingMessageCandidate.withExpiry(0);

View file

@ -73,13 +73,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
import org.thoughtcrime.securesms.mms.MessageGroupContext;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingPaymentsActivatedMessages;
import org.thoughtcrime.securesms.mms.OutgoingPaymentsNotificationMessage;
import org.thoughtcrime.securesms.mms.OutgoingRequestToActivatePaymentMessages;
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.mms.QuoteModel;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -1808,15 +1802,15 @@ public class MmsTable extends MessageTable {
}
if (body != null && (Types.isGroupQuit(outboxType) || Types.isGroupUpdate(outboxType))) {
return new OutgoingGroupUpdateMessage(recipient, new MessageGroupContext(body, Types.isGroupV2(outboxType)), attachments, timestamp, 0, false, quote, contacts, previews, mentions);
return OutgoingMediaMessage.groupUpdateMessage(recipient, new MessageGroupContext(body, Types.isGroupV2(outboxType)), attachments, timestamp, 0, false, quote, contacts, previews, mentions);
} else if (Types.isExpirationTimerUpdate(outboxType)) {
return new OutgoingExpirationUpdateMessage(recipient, timestamp, expiresIn);
return OutgoingMediaMessage.expirationUpdateMessage(recipient, timestamp, expiresIn);
} else if (Types.isPaymentsNotification(outboxType)) {
return new OutgoingPaymentsNotificationMessage(recipient, Objects.requireNonNull(body), timestamp, expiresIn);
return OutgoingMediaMessage.paymentNotificationMessage(recipient, Objects.requireNonNull(body), timestamp, expiresIn);
} else if (Types.isPaymentsRequestToActivate(outboxType)) {
return new OutgoingRequestToActivatePaymentMessages(recipient, timestamp, expiresIn);
return OutgoingMediaMessage.requestToActivatePaymentsMessage(recipient, timestamp, expiresIn);
} else if (Types.isPaymentsActivated(outboxType)) {
return new OutgoingPaymentsActivatedMessages(recipient, timestamp, expiresIn);
return OutgoingMediaMessage.paymentsActivatedMessage(recipient, timestamp, expiresIn);
}
GiftBadge giftBadge = null;
@ -1841,11 +1835,8 @@ public class MmsTable extends MessageTable {
mentions,
networkFailures,
mismatches,
giftBadge);
if (Types.isSecureType(outboxType)) {
return new OutgoingSecureMediaMessage(message);
}
giftBadge,
Types.isSecureType(outboxType));
return message;
}
@ -2237,14 +2228,13 @@ public class MmsTable extends MessageTable {
if (forceSms) type |= Types.MESSAGE_FORCE_SMS_BIT;
if (message.isGroup()) {
OutgoingGroupUpdateMessage outgoingGroupUpdateMessage = (OutgoingGroupUpdateMessage) message;
if (outgoingGroupUpdateMessage.isV2Group()) {
if (message.isV2Group()) {
type |= Types.GROUP_V2_BIT | Types.GROUP_UPDATE_BIT;
if (outgoingGroupUpdateMessage.isJustAGroupLeave()) {
if (message.isJustAGroupLeave()) {
type |= Types.GROUP_LEAVE_BIT;
}
} else {
MessageGroupContext.GroupV1Properties properties = outgoingGroupUpdateMessage.requireGroupV1Properties();
MessageGroupContext.GroupV1Properties properties = message.requireGroupV1Properties();
if (properties.isUpdate()) type |= Types.GROUP_UPDATE_BIT;
else if (properties.isQuit()) type |= Types.GROUP_LEAVE_BIT;
}
@ -2336,13 +2326,11 @@ public class MmsTable extends MessageTable {
long messageId = insertMediaMessage(threadId, updatedBodyAndMentions.getBodyAsString(), message.getAttachments(), quoteAttachments, message.getSharedContacts(), message.getLinkPreviews(), updatedBodyAndMentions.getMentions(), null, contentValues, insertListener, false, false);
if (message.getRecipient().isGroup()) {
OutgoingGroupUpdateMessage outgoingGroupUpdateMessage = (message instanceof OutgoingGroupUpdateMessage) ? (OutgoingGroupUpdateMessage) message : null;
GroupReceiptTable receiptDatabase = SignalDatabase.groupReceipts();
Set<RecipientId> members = new HashSet<>();
if (outgoingGroupUpdateMessage != null && outgoingGroupUpdateMessage.isV2Group()) {
MessageGroupContext.GroupV2Properties groupV2Properties = outgoingGroupUpdateMessage.requireGroupV2Properties();
if (message.isGroupUpdate() && message.isV2Group()) {
MessageGroupContext.GroupV2Properties groupV2Properties = message.requireGroupV2Properties();
members.addAll(Stream.of(groupV2Properties.getAllActivePendingAndRemovedMembers())
.distinct()
.map(uuid -> RecipientId.from(ServiceId.from(uuid)))

View file

@ -18,8 +18,8 @@ import org.thoughtcrime.securesms.database.RecipientTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.ThreadTable;
import org.thoughtcrime.securesms.groups.GroupManager.GroupActionResult;
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage;
import org.thoughtcrime.securesms.mms.MessageGroupContext;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -174,7 +174,17 @@ final class GroupManagerV1 {
avatarAttachment = new UriAttachment(avatarUri, MediaUtil.IMAGE_PNG, AttachmentTable.TRANSFER_PROGRESS_DONE, avatar.length, null, false, false, false, false, null, null, null, null, null);
}
OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0, false, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
OutgoingMediaMessage outgoingMessage = OutgoingMediaMessage.groupUpdateMessage(groupRecipient,
new MessageGroupContext(groupContext),
Collections.singletonList(avatarAttachment),
System.currentTimeMillis(),
0,
false,
null,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList());
long threadId = MessageSender.send(context, outgoingMessage, -1, false, null, null);
return new GroupActionResult(groupRecipient, threadId, newMemberCount, Collections.emptyList());
@ -198,14 +208,14 @@ final class GroupManagerV1 {
long threadId = threadTable.getOrCreateThreadIdFor(recipient);
recipientTable.setExpireMessages(recipient.getId(), expirationTime);
OutgoingExpirationUpdateMessage outgoingMessage = new OutgoingExpirationUpdateMessage(recipient, System.currentTimeMillis(), expirationTime * 1000L);
OutgoingMediaMessage outgoingMessage = OutgoingMediaMessage.expirationUpdateMessage(recipient, System.currentTimeMillis(), expirationTime * 1000L);
MessageSender.send(context, outgoingMessage, threadId, false, null, null);
}
@WorkerThread
private static Optional<OutgoingGroupUpdateMessage> createGroupLeaveMessage(@NonNull Context context,
@NonNull GroupId.V1 groupId,
@NonNull Recipient groupRecipient)
private static Optional<OutgoingMediaMessage> createGroupLeaveMessage(@NonNull Context context,
@NonNull GroupId.V1 groupId,
@NonNull Recipient groupRecipient)
{
GroupTable groupDatabase = SignalDatabase.groups();

View file

@ -46,7 +46,7 @@ import org.thoughtcrime.securesms.jobs.PushGroupSilentUpdateSendJob;
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
@ -1264,7 +1264,7 @@ final class GroupManagerV2 {
GroupId.V2 groupId = GroupId.v2(masterKey);
Recipient groupRecipient = Recipient.externalGroupExact(groupId);
DecryptedGroupV2Context decryptedGroupV2Context = GroupProtoUtil.createDecryptedGroupV2Context(masterKey, groupMutation, signedGroupChange);
OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(groupRecipient, decryptedGroupV2Context, System.currentTimeMillis());
OutgoingMediaMessage outgoingMessage = OutgoingMediaMessage.groupUpdateMessage(groupRecipient, decryptedGroupV2Context, System.currentTimeMillis());
DecryptedGroupChange plainGroupChange = groupMutation.getGroupChange();

View file

@ -41,7 +41,7 @@ import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob;
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.sms.IncomingGroupUpdateMessage;
@ -511,8 +511,8 @@ public class GroupsV2StateProcessor {
.addDeleteMembers(UuidUtil.toByteString(selfUuid))
.build();
DecryptedGroupV2Context decryptedGroupV2Context = GroupProtoUtil.createDecryptedGroupV2Context(masterKey, new GroupMutation(decryptedGroup, simulatedGroupChange, simulatedGroupState), null);
OutgoingGroupUpdateMessage leaveMessage = new OutgoingGroupUpdateMessage(groupRecipient, decryptedGroupV2Context, System.currentTimeMillis());
DecryptedGroupV2Context decryptedGroupV2Context = GroupProtoUtil.createDecryptedGroupV2Context(masterKey, new GroupMutation(decryptedGroup, simulatedGroupChange, simulatedGroupState), null);
OutgoingMediaMessage leaveMessage = OutgoingMediaMessage.groupUpdateMessage(groupRecipient, decryptedGroupV2Context, System.currentTimeMillis());
try {
MessageTable mmsDatabase = SignalDatabase.mms();
@ -738,13 +738,13 @@ public class GroupsV2StateProcessor {
if (outgoing) {
try {
MessageTable mmsDatabase = SignalDatabase.mms();
ThreadTable threadTable = SignalDatabase.threads();
RecipientId recipientId = recipientTable.getOrInsertFromGroupId(groupId);
Recipient recipient = Recipient.resolved(recipientId);
OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(recipient, decryptedGroupV2Context, timestamp);
long threadId = threadTable.getOrCreateThreadIdFor(recipient);
long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
MessageTable mmsDatabase = SignalDatabase.mms();
ThreadTable threadTable = SignalDatabase.threads();
RecipientId recipientId = recipientTable.getOrInsertFromGroupId(groupId);
Recipient recipient = Recipient.resolved(recipientId);
OutgoingMediaMessage outgoingMessage = OutgoingMediaMessage.groupUpdateMessage(recipient, decryptedGroupV2Context, timestamp);
long threadId = threadTable.getOrCreateThreadIdFor(recipient);
long messageId = mmsDatabase.insertMessageOutbox(outgoingMessage, threadId, false, null);
mmsDatabase.markAsSent(messageId, true);
threadTable.update(threadId, false, false);

View file

@ -4,7 +4,7 @@ import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.jobmanager.Data
import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.mms.OutgoingPaymentsNotificationMessage
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.net.NotPushRegisteredException
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
@ -63,7 +63,7 @@ class PaymentNotificationSendJobV2 private constructor(
MessageSender.send(
context,
OutgoingPaymentsNotificationMessage(
OutgoingMediaMessage.paymentNotificationMessage(
recipient,
uuid.toString(),
System.currentTimeMillis(),

View file

@ -140,8 +140,8 @@ public final class PushDistributionListSendJob extends PushSendJob {
{
MessageTable database = SignalDatabase.mms();
OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
Set<NetworkFailure> existingNetworkFailures = message.getNetworkFailures();
Set<IdentityKeyMismatch> existingIdentityMismatches = message.getIdentityKeyMismatches();
Set<NetworkFailure> existingNetworkFailures = new HashSet<>(message.getNetworkFailures());
Set<IdentityKeyMismatch> existingIdentityMismatches = new HashSet<>(message.getIdentityKeyMismatches());
if (!message.getStoryType().isStory()) {
throw new MmsException("Only story sends are currently supported!");

View file

@ -37,7 +37,6 @@ import org.thoughtcrime.securesms.messages.GroupSendUtil;
import org.thoughtcrime.securesms.messages.StorySendUtil;
import org.thoughtcrime.securesms.mms.MessageGroupContext;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
@ -143,7 +142,7 @@ public final class PushGroupSendJob extends PushSendJob {
}
private static boolean isGv2UpdateMessage(@NonNull OutgoingMediaMessage message) {
return (message instanceof OutgoingGroupUpdateMessage && ((OutgoingGroupUpdateMessage) message).isV2Group());
return message.isGroupUpdate() && message.isV2Group();
}
@Override
@ -165,8 +164,8 @@ public final class PushGroupSendJob extends PushSendJob {
MessageTable database = SignalDatabase.mms();
OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
long threadId = database.getMessageRecord(messageId).getThreadId();
Set<NetworkFailure> existingNetworkFailures = message.getNetworkFailures();
Set<IdentityKeyMismatch> existingIdentityMismatches = message.getIdentityKeyMismatches();
Set<NetworkFailure> existingNetworkFailures = new HashSet<>(message.getNetworkFailures());
Set<IdentityKeyMismatch> existingIdentityMismatches = new HashSet<>(message.getIdentityKeyMismatches());
ApplicationDependencies.getJobManager().cancelAllInQueue(TypingSendJob.getQueue(threadId));
@ -280,14 +279,12 @@ public final class PushGroupSendJob extends PushSendJob {
} else {
throw new UndeliverableMessageException("No group found! " + groupId);
}
} else if (message.isGroup()) {
OutgoingGroupUpdateMessage groupMessage = (OutgoingGroupUpdateMessage) message;
if (groupMessage.isV2Group()) {
MessageGroupContext.GroupV2Properties properties = groupMessage.requireGroupV2Properties();
} else if (message.isGroup() && message.isGroupUpdate()) {
if (message.isV2Group()) {
MessageGroupContext.GroupV2Properties properties = message.requireGroupV2Properties();
GroupContextV2 groupContext = properties.getGroupContext();
SignalServiceGroupV2.Builder builder = SignalServiceGroupV2.newBuilder(properties.getGroupMasterKey())
.withRevision(groupContext.getRevision());
SignalServiceGroupV2.Builder builder = SignalServiceGroupV2.newBuilder(properties.getGroupMasterKey())
.withRevision(groupContext.getRevision());
ByteString groupChange = groupContext.getGroupChange();
if (groupChange != null) {

View file

@ -18,7 +18,7 @@ import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.messages.GroupSendUtil;
import org.thoughtcrime.securesms.mms.MessageGroupContext;
import org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.net.NotPushRegisteredException;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
@ -68,7 +68,7 @@ public final class PushGroupSilentUpdateSendJob extends BaseJob {
public static @NonNull Job create(@NonNull Context context,
@NonNull GroupId.V2 groupId,
@NonNull DecryptedGroup decryptedGroup,
@NonNull OutgoingGroupUpdateMessage groupMessage)
@NonNull OutgoingMediaMessage groupMessage)
{
List<UUID> memberUuids = DecryptedGroupUtil.toUuidList(decryptedGroup.getMembersList());
List<UUID> pendingUuids = DecryptedGroupUtil.pendingToUuidList(decryptedGroup.getPendingMembersList());

View file

@ -5,7 +5,7 @@ import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.jobmanager.Data
import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.mms.OutgoingPaymentsActivatedMessages
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.net.NotPushRegisteredException
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.sms.MessageSender
@ -45,7 +45,7 @@ class SendPaymentsActivatedJob(parameters: Parameters) : BaseJob(parameters) {
if (recipient != null) {
MessageSender.send(
context,
OutgoingPaymentsActivatedMessages(recipient, System.currentTimeMillis(), 0),
OutgoingMediaMessage.paymentsActivatedMessage(recipient, System.currentTimeMillis(), 0),
threadId,
false,
null,

View file

@ -15,7 +15,6 @@ import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.conversation.MessageSendType
import org.thoughtcrime.securesms.database.AttachmentTable.TransformProperties
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.ThreadTable
import org.thoughtcrime.securesms.database.model.Mention
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.keyvalue.SignalStore
@ -32,7 +31,6 @@ import org.thoughtcrime.securesms.mediasend.VideoEditorFragment
import org.thoughtcrime.securesms.mediasend.VideoTrimTransform
import org.thoughtcrime.securesms.mms.MediaConstraints
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
import org.thoughtcrime.securesms.mms.SentMediaQuality
import org.thoughtcrime.securesms.mms.Slide
import org.thoughtcrime.securesms.providers.BlobProvider
@ -231,9 +229,9 @@ class MediaSelectionRepository(context: Context) {
isViewOnce: Boolean,
storyClips: List<Media>
) {
val nonStoryMessages: MutableList<OutgoingSecureMediaMessage> = ArrayList(contacts.size)
val storyPreUploadMessages: MutableMap<PreUploadResult, MutableList<OutgoingSecureMediaMessage>> = mutableMapOf()
val storyClipMessages: MutableList<OutgoingSecureMediaMessage> = ArrayList()
val nonStoryMessages: MutableList<OutgoingMediaMessage> = ArrayList(contacts.size)
val storyPreUploadMessages: MutableMap<PreUploadResult, MutableList<OutgoingMediaMessage>> = mutableMapOf()
val storyClipMessages: MutableList<OutgoingMediaMessage> = ArrayList()
val distributionListPreUploadSentTimestamps: MutableMap<PreUploadResult, Long> = mutableMapOf()
val distributionListStoryClipsSentTimestamps: MutableMap<MediaKey, Long> = mutableMapOf()
@ -252,38 +250,26 @@ class MediaSelectionRepository(context: Context) {
}
val message = OutgoingMediaMessage(
recipient,
body,
emptyList(),
if (recipient.isDistributionList) distributionListPreUploadSentTimestamps.getOrPut(preUploadResults.first()) { System.currentTimeMillis() } else System.currentTimeMillis(),
-1,
if (isStory) 0 else TimeUnit.SECONDS.toMillis(recipient.expiresInSeconds.toLong()),
isViewOnce,
ThreadTable.DistributionTypes.DEFAULT,
storyType,
null,
false,
null,
emptyList(),
emptyList(),
mentions,
mutableSetOf(),
mutableSetOf(),
null
recipient = recipient,
body = body,
sentTimeMillis = if (recipient.isDistributionList) distributionListPreUploadSentTimestamps.getOrPut(preUploadResults.first()) { System.currentTimeMillis() } else System.currentTimeMillis(),
expiresIn = if (isStory) 0 else TimeUnit.SECONDS.toMillis(recipient.expiresInSeconds.toLong()),
isViewOnce = isViewOnce,
storyType = storyType,
mentions = mentions,
isSecure = true
)
if (isStory) {
preUploadResults.filterNot { result -> storyClips.any { it.uri == result.media.uri } }.forEach {
val list = storyPreUploadMessages[it] ?: mutableListOf()
list.add(
OutgoingSecureMediaMessage(message).withSentTimestamp(
if (recipient.isDistributionList) {
distributionListPreUploadSentTimestamps.getOrPut(it) { System.currentTimeMillis() }
} else {
System.currentTimeMillis()
}
)
)
val timestamp = if (recipient.isDistributionList) {
distributionListPreUploadSentTimestamps.getOrPut(it) { System.currentTimeMillis() }
} else {
System.currentTimeMillis()
}
list.add(message.copy(sentTimeMillis = timestamp))
storyPreUploadMessages[it] = list
// XXX We must do this to avoid sending out messages to the same recipient with the same
@ -293,27 +279,15 @@ class MediaSelectionRepository(context: Context) {
storyClips.forEach {
storyClipMessages.add(
OutgoingSecureMediaMessage(
OutgoingMediaMessage(
recipient,
body,
listOf(MediaUploadRepository.asAttachment(context, it)),
if (recipient.isDistributionList) distributionListStoryClipsSentTimestamps.getOrPut(it.asKey()) { System.currentTimeMillis() } else System.currentTimeMillis(),
-1,
0,
isViewOnce,
ThreadTable.DistributionTypes.DEFAULT,
storyType,
null,
false,
null,
emptyList(),
emptyList(),
mentions,
mutableSetOf(),
mutableSetOf(),
null
)
OutgoingMediaMessage(
recipient = recipient,
body = body,
attachments = listOf(MediaUploadRepository.asAttachment(context, it)),
sentTimeMillis = if (recipient.isDistributionList) distributionListStoryClipsSentTimestamps.getOrPut(it.asKey()) { System.currentTimeMillis() } else System.currentTimeMillis(),
isViewOnce = isViewOnce,
storyType = storyType,
mentions = mentions,
isSecure = true
)
)
@ -322,7 +296,7 @@ class MediaSelectionRepository(context: Context) {
ThreadUtil.sleep(5)
}
} else {
nonStoryMessages.add(OutgoingSecureMediaMessage(message))
nonStoryMessages.add(message)
// XXX We must do this to avoid sending out messages to the same recipient with the same
// sentTimestamp. If we do this, they'll be considered dupes by the receiver.

View file

@ -8,7 +8,6 @@ import org.signal.core.util.ThreadUtil
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.ThreadTable
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost
import org.thoughtcrime.securesms.fonts.TextFont
@ -18,7 +17,6 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview
import org.thoughtcrime.securesms.mediasend.v2.UntrustedRecords
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationState
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
import org.thoughtcrime.securesms.providers.BlobProvider
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.stories.Stories
@ -61,7 +59,7 @@ class TextStoryPostSendRepository {
private fun performSend(contactSearchKey: Set<ContactSearchKey>, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?): Single<TextStoryPostSendResult> {
return Single.fromCallable {
val messages: MutableList<OutgoingSecureMediaMessage> = mutableListOf()
val messages: MutableList<OutgoingMediaMessage> = mutableListOf()
val distributionListSentTimestamp = System.currentTimeMillis()
for (contact in contactSearchKey) {
@ -79,27 +77,15 @@ class TextStoryPostSendRepository {
}
val message = OutgoingMediaMessage(
recipient,
serializeTextStoryState(textStoryPostCreationState),
emptyList(),
if (recipient.isDistributionList) distributionListSentTimestamp else System.currentTimeMillis(),
-1,
0,
false,
ThreadTable.DistributionTypes.DEFAULT,
storyType.toTextStoryType(),
null,
false,
null,
emptyList(),
listOfNotNull(linkPreview),
emptyList(),
mutableSetOf(),
mutableSetOf(),
null
recipient = recipient,
body = serializeTextStoryState(textStoryPostCreationState),
timestamp = if (recipient.isDistributionList) distributionListSentTimestamp else System.currentTimeMillis(),
storyType = storyType.toTextStoryType(),
previews = listOfNotNull(linkPreview),
isSecure = true
)
messages.add(OutgoingSecureMediaMessage(message))
messages.add(message)
ThreadUtil.sleep(5)
}

View file

@ -104,9 +104,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.mms.QuoteModel;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.mms.StickerSlide;
@ -1967,9 +1965,9 @@ public final class MessageContentProcessor {
MessageTable database = SignalDatabase.mms();
Recipient recipient = getSyncMessageDestination(message);
OutgoingExpirationUpdateMessage expirationUpdateMessage = new OutgoingExpirationUpdateMessage(recipient,
message.getTimestamp(),
TimeUnit.SECONDS.toMillis(message.getDataMessage().get().getExpiresInSeconds()));
OutgoingMediaMessage expirationUpdateMessage = OutgoingMediaMessage.expirationUpdateMessage(recipient,
message.getTimestamp(),
TimeUnit.SECONDS.toMillis(message.getDataMessage().get().getExpiresInSeconds()));
long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient);
long messageId = database.insertMessageOutbox(expirationUpdateMessage, threadId, false, null);
@ -2044,9 +2042,8 @@ public final class MessageContentProcessor {
getMentions(message.getDataMessage().get().getMentions()).orElse(Collections.emptyList()),
Collections.emptySet(),
Collections.emptySet(),
null);
mediaMessage = new OutgoingSecureMediaMessage(mediaMessage);
null,
true);
if (recipient.getExpiresInSeconds() != message.getDataMessage().get().getExpiresInSeconds()) {
handleSynchronizeSentExpirationUpdate(message);
@ -2164,9 +2161,8 @@ public final class MessageContentProcessor {
Collections.emptyList(),
Collections.emptySet(),
Collections.emptySet(),
null);
mediaMessage = new OutgoingSecureMediaMessage(mediaMessage);
null,
true);
MmsTable database = SignalDatabase.mms();
long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient);
@ -2260,9 +2256,8 @@ public final class MessageContentProcessor {
mentions.orElse(Collections.emptyList()),
Collections.emptySet(),
Collections.emptySet(),
giftBadge.orElse(null));
mediaMessage = new OutgoingSecureMediaMessage(mediaMessage);
giftBadge.orElse(null),
true);
if (recipients.getExpiresInSeconds() != message.getDataMessage().get().getExpiresInSeconds()) {
handleSynchronizeSentExpirationUpdate(message);
@ -2444,16 +2439,10 @@ public final class MessageContentProcessor {
-1,
expiresInMillis,
false,
ThreadTable.DistributionTypes.DEFAULT,
StoryType.NONE,
null,
false,
null,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
null);
outgoingMediaMessage = new OutgoingSecureMediaMessage(outgoingMediaMessage);
true);
messageId = SignalDatabase.mms().insertMessageOutbox(outgoingMediaMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null);
database = SignalDatabase.mms();

View file

@ -463,7 +463,7 @@ public class AttachmentManager {
.setTitle(context.getString(R.string.AttachmentManager__not_activated_payments, recipient.getShortDisplayName(context)))
.setMessage(context.getString(R.string.AttachmentManager__request_to_activate_payments))
.setPositiveButton(context.getString(R.string.AttachmentManager__send_request), (dialog, which) -> {
OutgoingRequestToActivatePaymentMessages outgoingMessage = new OutgoingRequestToActivatePaymentMessages(recipient, System.currentTimeMillis(), 0);
OutgoingMediaMessage outgoingMessage = OutgoingMediaMessage.requestToActivatePaymentsMessage(recipient, System.currentTimeMillis(), 0);
MessageSender.send(context, outgoingMessage, SignalDatabase.threads().getOrCreateThreadIdFor(recipient), false, null, null);
})
.setNegativeButton(context.getString(R.string.AttachmentManager__cancel), null)

View file

@ -1,39 +0,0 @@
package org.thoughtcrime.securesms.mms;
import org.thoughtcrime.securesms.database.ThreadTable;
import org.thoughtcrime.securesms.database.model.StoryType;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.Collections;
import java.util.LinkedList;
public class OutgoingExpirationUpdateMessage extends OutgoingSecureMediaMessage {
public OutgoingExpirationUpdateMessage(Recipient recipient, long sentTimeMillis, long expiresIn) {
super(recipient,
"",
new LinkedList<>(),
sentTimeMillis,
ThreadTable.DistributionTypes.CONVERSATION,
expiresIn,
false,
StoryType.NONE,
null,
false,
null,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
null);
}
@Override
public boolean isExpirationUpdate() {
return true;
}
@Override
public boolean isUrgent() {
return false;
}
}

View file

@ -1,104 +0,0 @@
package org.thoughtcrime.securesms.mms;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.ThreadTable;
import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.database.model.StoryType;
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.GroupV2UpdateMessageUtil;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
import java.util.Collections;
import java.util.List;
public final class OutgoingGroupUpdateMessage extends OutgoingSecureMediaMessage {
private final MessageGroupContext messageGroupContext;
public OutgoingGroupUpdateMessage(@NonNull Recipient recipient,
@NonNull MessageGroupContext groupContext,
@NonNull List<Attachment> avatar,
long sentTimeMillis,
long expiresIn,
boolean viewOnce,
@Nullable QuoteModel quote,
@NonNull List<Contact> contacts,
@NonNull List<LinkPreview> previews,
@NonNull List<Mention> mentions)
{
super(recipient,
groupContext.getEncodedGroupContext(),
avatar,
sentTimeMillis,
ThreadTable.DistributionTypes.CONVERSATION,
expiresIn,
viewOnce,
StoryType.NONE,
null,
false,
quote,
contacts,
previews,
mentions,
null);
this.messageGroupContext = groupContext;
}
public OutgoingGroupUpdateMessage(@NonNull Recipient recipient,
@NonNull GroupContext group,
@Nullable final Attachment avatar,
long sentTimeMillis,
long expireIn,
boolean viewOnce,
@Nullable QuoteModel quote,
@NonNull List<Contact> contacts,
@NonNull List<LinkPreview> previews,
@NonNull List<Mention> mentions)
{
this(recipient, new MessageGroupContext(group), getAttachments(avatar), sentTimeMillis, expireIn, viewOnce, quote, contacts, previews, mentions);
}
public OutgoingGroupUpdateMessage(@NonNull Recipient recipient,
@NonNull DecryptedGroupV2Context group,
long sentTimeMillis)
{
this(recipient, new MessageGroupContext(group), Collections.emptyList(), sentTimeMillis, 0, false, null, Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
}
@Override
public boolean isGroup() {
return true;
}
public boolean isV2Group() {
return GroupV2UpdateMessageUtil.isGroupV2(messageGroupContext);
}
public boolean isJustAGroupLeave() {
return GroupV2UpdateMessageUtil.isJustAGroupLeave(messageGroupContext);
}
public @NonNull MessageGroupContext.GroupV1Properties requireGroupV1Properties() {
return messageGroupContext.requireGroupV1Properties();
}
public @NonNull MessageGroupContext.GroupV2Properties requireGroupV2Properties() {
return messageGroupContext.requireGroupV2Properties();
}
@Override
public boolean isUrgent() {
return false;
}
private static List<Attachment> getAttachments(@Nullable Attachment avatar) {
return avatar == null ? Collections.emptyList() : Collections.singletonList(avatar);
}
}

View file

@ -1,277 +0,0 @@
package org.thoughtcrime.securesms.mms;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.database.model.ParentStoryId;
import org.thoughtcrime.securesms.database.model.StoryType;
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class OutgoingMediaMessage {
private final Recipient recipient;
protected final String body;
protected final List<Attachment> attachments;
private final long sentTimeMillis;
private final int distributionType;
private final int subscriptionId;
private final long expiresIn;
private final boolean viewOnce;
private final QuoteModel outgoingQuote;
private final StoryType storyType;
private final ParentStoryId parentStoryId;
private final boolean isStoryReaction;
private final GiftBadge giftBadge;
private final Set<NetworkFailure> networkFailures = new HashSet<>();
private final Set<IdentityKeyMismatch> identityKeyMismatches = new HashSet<>();
private final List<Contact> contacts = new LinkedList<>();
private final List<LinkPreview> linkPreviews = new LinkedList<>();
private final List<Mention> mentions = new LinkedList<>();
public OutgoingMediaMessage(Recipient recipient,
String message,
List<Attachment> attachments,
long sentTimeMillis,
int subscriptionId,
long expiresIn,
boolean viewOnce,
int distributionType,
@NonNull StoryType storyType,
@Nullable ParentStoryId parentStoryId,
boolean isStoryReaction,
@Nullable QuoteModel outgoingQuote,
@NonNull List<Contact> contacts,
@NonNull List<LinkPreview> linkPreviews,
@NonNull List<Mention> mentions,
@NonNull Set<NetworkFailure> networkFailures,
@NonNull Set<IdentityKeyMismatch> identityKeyMismatches,
@Nullable GiftBadge giftBadge)
{
this.recipient = recipient;
this.body = message;
this.sentTimeMillis = sentTimeMillis;
this.distributionType = distributionType;
this.attachments = attachments;
this.subscriptionId = subscriptionId;
this.expiresIn = expiresIn;
this.viewOnce = viewOnce;
this.outgoingQuote = outgoingQuote;
this.storyType = storyType;
this.parentStoryId = parentStoryId;
this.isStoryReaction = isStoryReaction;
this.giftBadge = giftBadge;
this.contacts.addAll(contacts);
this.linkPreviews.addAll(linkPreviews);
this.mentions.addAll(mentions);
this.networkFailures.addAll(networkFailures);
this.identityKeyMismatches.addAll(identityKeyMismatches);
}
public OutgoingMediaMessage(Recipient recipient,
SlideDeck slideDeck,
String message,
long sentTimeMillis,
int subscriptionId,
long expiresIn,
boolean viewOnce,
int distributionType,
@NonNull StoryType storyType,
@Nullable ParentStoryId parentStoryId,
boolean isStoryReaction,
@Nullable QuoteModel outgoingQuote,
@NonNull List<Contact> contacts,
@NonNull List<LinkPreview> linkPreviews,
@NonNull List<Mention> mentions,
@Nullable GiftBadge giftBadge)
{
this(recipient,
buildMessage(slideDeck, message),
slideDeck.asAttachments(),
sentTimeMillis,
subscriptionId,
expiresIn,
viewOnce,
distributionType,
storyType,
parentStoryId,
isStoryReaction,
outgoingQuote,
contacts,
linkPreviews,
mentions,
new HashSet<>(),
new HashSet<>(),
giftBadge);
}
public OutgoingMediaMessage(OutgoingMediaMessage that) {
this.recipient = that.getRecipient();
this.body = that.body;
this.distributionType = that.distributionType;
this.attachments = that.attachments;
this.sentTimeMillis = that.sentTimeMillis;
this.subscriptionId = that.subscriptionId;
this.expiresIn = that.expiresIn;
this.viewOnce = that.viewOnce;
this.outgoingQuote = that.outgoingQuote;
this.storyType = that.storyType;
this.parentStoryId = that.parentStoryId;
this.isStoryReaction = that.isStoryReaction;
this.giftBadge = that.giftBadge;
this.identityKeyMismatches.addAll(that.identityKeyMismatches);
this.networkFailures.addAll(that.networkFailures);
this.contacts.addAll(that.contacts);
this.linkPreviews.addAll(that.linkPreviews);
this.mentions.addAll(that.mentions);
}
public @NonNull OutgoingMediaMessage withExpiry(long expiresIn) {
return new OutgoingMediaMessage(
getRecipient(),
body,
attachments,
sentTimeMillis,
subscriptionId,
expiresIn,
viewOnce,
distributionType,
storyType,
parentStoryId,
isStoryReaction,
outgoingQuote,
contacts,
linkPreviews,
mentions,
networkFailures,
identityKeyMismatches,
giftBadge
);
}
public Recipient getRecipient() {
return recipient;
}
public String getBody() {
return body;
}
public List<Attachment> getAttachments() {
return attachments;
}
public int getDistributionType() {
return distributionType;
}
public boolean isSecure() {
return false;
}
public boolean isGroup() {
return false;
}
public boolean isExpirationUpdate() {
return false;
}
public boolean isPaymentsNotification() {
return false;
}
public boolean isRequestToActivatePayments() {
return false;
}
public boolean isPaymentsActivated() {
return false;
}
public long getSentTimeMillis() {
return sentTimeMillis;
}
public int getSubscriptionId() {
return subscriptionId;
}
public long getExpiresIn() {
return expiresIn;
}
public boolean isViewOnce() {
return viewOnce;
}
public @NonNull StoryType getStoryType() {
return storyType;
}
public @Nullable ParentStoryId getParentStoryId() {
return parentStoryId;
}
public boolean isStoryReaction() {
return isStoryReaction;
}
public @Nullable QuoteModel getOutgoingQuote() {
return outgoingQuote;
}
public @NonNull List<Contact> getSharedContacts() {
return contacts;
}
public @NonNull List<LinkPreview> getLinkPreviews() {
return linkPreviews;
}
public @NonNull List<Mention> getMentions() {
return mentions;
}
public @NonNull Set<NetworkFailure> getNetworkFailures() {
return networkFailures;
}
public @NonNull Set<IdentityKeyMismatch> getIdentityKeyMismatches() {
return identityKeyMismatches;
}
public @Nullable GiftBadge getGiftBadge() {
return giftBadge;
}
public boolean isUrgent() {
return true;
}
private static String buildMessage(SlideDeck slideDeck, String message) {
if (!TextUtils.isEmpty(message) && !TextUtils.isEmpty(slideDeck.getBody())) {
return slideDeck.getBody() + "\n\n" + message;
} else if (!TextUtils.isEmpty(message)) {
return message;
} else {
return slideDeck.getBody();
}
}
}

View file

@ -0,0 +1,293 @@
package org.thoughtcrime.securesms.mms
import org.thoughtcrime.securesms.attachments.Attachment
import org.thoughtcrime.securesms.contactshare.Contact
import org.thoughtcrime.securesms.database.ThreadTable
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch
import org.thoughtcrime.securesms.database.documents.NetworkFailure
import org.thoughtcrime.securesms.database.model.Mention
import org.thoughtcrime.securesms.database.model.ParentStoryId
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.database.model.databaseprotos.DecryptedGroupV2Context
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
import org.thoughtcrime.securesms.linkpreview.LinkPreview
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.sms.GroupV2UpdateMessageUtil
/**
* Outgoing media message for all outgoing media messages (push/mms, group updates, expiration updates, payments, etc.)
*/
data class OutgoingMediaMessage(
val recipient: Recipient,
val sentTimeMillis: Long,
val body: String = "",
val distributionType: Int = ThreadTable.DistributionTypes.DEFAULT,
val subscriptionId: Int = -1,
val expiresIn: Long = 0L,
val isViewOnce: Boolean = false,
val outgoingQuote: QuoteModel? = null,
val storyType: StoryType = StoryType.NONE,
val parentStoryId: ParentStoryId? = null,
val isStoryReaction: Boolean = false,
val giftBadge: GiftBadge? = null,
val isSecure: Boolean = false,
val attachments: List<Attachment> = emptyList(),
val sharedContacts: List<Contact> = emptyList(),
val linkPreviews: List<LinkPreview> = emptyList(),
val mentions: List<Mention> = emptyList(),
val isGroup: Boolean = false,
val isGroupUpdate: Boolean = false,
val messageGroupContext: MessageGroupContext? = null,
val isExpirationUpdate: Boolean = false,
val isPaymentsNotification: Boolean = false,
val isRequestToActivatePayments: Boolean = false,
val isPaymentsActivated: Boolean = false,
val isUrgent: Boolean = true,
val networkFailures: Set<NetworkFailure> = emptySet(),
val identityKeyMismatches: Set<IdentityKeyMismatch> = emptySet(),
) {
val isV2Group: Boolean = messageGroupContext != null && GroupV2UpdateMessageUtil.isGroupV2(messageGroupContext)
val isJustAGroupLeave: Boolean = messageGroupContext != null && GroupV2UpdateMessageUtil.isJustAGroupLeave(messageGroupContext)
/**
* Smaller constructor for calling from Java and legacy code using the original interface.
*/
constructor(
recipient: Recipient,
body: String? = "",
attachments: List<Attachment> = emptyList(),
timestamp: Long,
subscriptionId: Int = -1,
expiresIn: Long = 0L,
viewOnce: Boolean = false,
distributionType: Int = ThreadTable.DistributionTypes.DEFAULT,
storyType: StoryType = StoryType.NONE,
parentStoryId: ParentStoryId? = null,
isStoryReaction: Boolean = false,
quote: QuoteModel? = null,
contacts: List<Contact> = emptyList(),
previews: List<LinkPreview> = emptyList(),
mentions: List<Mention> = emptyList(),
networkFailures: Set<NetworkFailure> = emptySet(),
mismatches: Set<IdentityKeyMismatch> = emptySet(),
giftBadge: GiftBadge? = null,
isSecure: Boolean = false
) : this(
recipient = recipient,
body = body ?: "",
attachments = attachments,
sentTimeMillis = timestamp,
subscriptionId = subscriptionId,
expiresIn = expiresIn,
isViewOnce = viewOnce,
distributionType = distributionType,
storyType = storyType,
parentStoryId = parentStoryId,
isStoryReaction = isStoryReaction,
outgoingQuote = quote,
sharedContacts = contacts,
linkPreviews = previews,
mentions = mentions,
networkFailures = networkFailures,
identityKeyMismatches = mismatches,
giftBadge = giftBadge,
isSecure = isSecure
)
/**
* Allow construction of attachments/body via a [SlideDeck] instead of passing in attachments list.
*/
constructor(
recipient: Recipient,
slideDeck: SlideDeck,
body: String? = "",
timestamp: Long,
subscriptionId: Int = -1,
expiresIn: Long = 0L,
viewOnce: Boolean = false,
storyType: StoryType = StoryType.NONE,
linkPreviews: List<LinkPreview> = emptyList(),
mentions: List<Mention> = emptyList(),
isSecure: Boolean = false
) : this(
recipient = recipient,
body = buildMessage(slideDeck, body ?: ""),
attachments = slideDeck.asAttachments(),
sentTimeMillis = timestamp,
subscriptionId = subscriptionId,
expiresIn = expiresIn,
isViewOnce = viewOnce,
storyType = storyType,
linkPreviews = linkPreviews,
mentions = mentions,
isSecure = isSecure
)
fun withExpiry(expiresIn: Long): OutgoingMediaMessage {
return copy(expiresIn = expiresIn)
}
fun stripAttachments(): OutgoingMediaMessage {
return copy(attachments = emptyList())
}
fun makeSecure(): OutgoingMediaMessage {
return copy(isSecure = true)
}
fun requireGroupV1Properties(): MessageGroupContext.GroupV1Properties {
return messageGroupContext!!.requireGroupV1Properties()
}
fun requireGroupV2Properties(): MessageGroupContext.GroupV2Properties {
return messageGroupContext!!.requireGroupV2Properties()
}
companion object {
/**
* Helper for creating a group update message when a state change occurs and needs to be sent to others.
*/
@JvmStatic
fun groupUpdateMessage(recipient: Recipient, group: DecryptedGroupV2Context, sentTimeMillis: Long): OutgoingMediaMessage {
val groupContext = MessageGroupContext(group)
return OutgoingMediaMessage(
recipient = recipient,
body = groupContext.encodedGroupContext,
sentTimeMillis = sentTimeMillis,
messageGroupContext = groupContext,
isGroup = true,
isGroupUpdate = true,
isSecure = true
)
}
/**
* Helper for creating a group update message when a state change occurs and needs to be sent to others.
*/
@JvmStatic
fun groupUpdateMessage(
recipient: Recipient,
groupContext: MessageGroupContext,
avatar: List<Attachment> = emptyList(),
sentTimeMillis: Long,
expiresIn: Long = 0L,
viewOnce: Boolean = false,
quote: QuoteModel? = null,
contacts: List<Contact> = emptyList(),
previews: List<LinkPreview> = emptyList(),
mentions: List<Mention> = emptyList()
): OutgoingMediaMessage {
return OutgoingMediaMessage(
recipient = recipient,
body = groupContext.encodedGroupContext,
isGroup = true,
isGroupUpdate = true,
messageGroupContext = groupContext,
attachments = avatar,
sentTimeMillis = sentTimeMillis,
expiresIn = expiresIn,
isViewOnce = viewOnce,
outgoingQuote = quote,
sharedContacts = contacts,
linkPreviews = previews,
mentions = mentions,
isSecure = true
)
}
/**
* Helper for creating a text story message.
*/
@JvmStatic
fun textStoryMessage(
recipient: Recipient,
body: String,
sentTimeMillis: Long,
storyType: StoryType,
linkPreviews: List<LinkPreview>
): OutgoingMediaMessage {
return OutgoingMediaMessage(
recipient = recipient,
body = body,
sentTimeMillis = sentTimeMillis,
storyType = storyType,
linkPreviews = linkPreviews,
isSecure = true
)
}
/**
* Specialized message sent to request someone activate payments.
*/
@JvmStatic
fun requestToActivatePaymentsMessage(recipient: Recipient, sentTimeMillis: Long, expiresIn: Long): OutgoingMediaMessage {
return OutgoingMediaMessage(
recipient = recipient,
sentTimeMillis = sentTimeMillis,
expiresIn = expiresIn,
isRequestToActivatePayments = true,
isUrgent = false,
isSecure = true
)
}
/**
* Specialized message sent to indicate you activated payments. Intended to only
* be sent to those that sent requests prior to activation.
*/
@JvmStatic
fun paymentsActivatedMessage(recipient: Recipient, sentTimeMillis: Long, expiresIn: Long): OutgoingMediaMessage {
return OutgoingMediaMessage(
recipient = recipient,
sentTimeMillis = sentTimeMillis,
expiresIn = expiresIn,
isPaymentsActivated = true,
isUrgent = false,
isSecure = true
)
}
/**
* Type of message sent when sending a payment to another Signal contact.
*/
@JvmStatic
fun paymentNotificationMessage(recipient: Recipient, paymentUuid: String, sentTimeMillis: Long, expiresIn: Long): OutgoingMediaMessage {
return OutgoingMediaMessage(
recipient = recipient,
body = paymentUuid,
sentTimeMillis = sentTimeMillis,
expiresIn = expiresIn,
isPaymentsNotification = true,
isSecure = true
)
}
/**
* Helper for creating expiration update messages.
*/
@JvmStatic
fun expirationUpdateMessage(recipient: Recipient, sentTimeMillis: Long, expiresIn: Long): OutgoingMediaMessage {
return OutgoingMediaMessage(
recipient = recipient,
sentTimeMillis = sentTimeMillis,
expiresIn = expiresIn,
isExpirationUpdate = true,
isUrgent = false,
isSecure = true
)
}
@JvmStatic
fun buildMessage(slideDeck: SlideDeck, message: String): String {
return if (message.isNotEmpty() && slideDeck.body.isNotEmpty()) {
"${slideDeck.body}\n\n$message"
} else if (message.isNotEmpty()) {
message
} else {
slideDeck.body
}
}
}
}

View file

@ -1,88 +0,0 @@
package org.thoughtcrime.securesms.mms
import org.thoughtcrime.securesms.database.ThreadTable
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.recipients.Recipient
import java.util.LinkedList
/**
* Specialized message sent to request someone activate payments.
*/
class OutgoingRequestToActivatePaymentMessages(
recipient: Recipient,
sentTimeMillis: Long,
expiresIn: Long
) : OutgoingSecureMediaMessage(
recipient,
"",
LinkedList(),
sentTimeMillis,
ThreadTable.DistributionTypes.CONVERSATION,
expiresIn,
false,
StoryType.NONE,
null,
false,
null,
emptyList(),
emptyList(),
emptyList(),
null
) {
override fun isRequestToActivatePayments(): Boolean = true
override fun isUrgent(): Boolean = false
}
/**
* Specialized message sent to indicate you activated payments. Intended to only
* be sent to those that sent requests prior to activation.
*/
class OutgoingPaymentsActivatedMessages(
recipient: Recipient,
sentTimeMillis: Long,
expiresIn: Long
) : OutgoingSecureMediaMessage(
recipient,
"",
LinkedList(),
sentTimeMillis,
ThreadTable.DistributionTypes.CONVERSATION,
expiresIn,
false,
StoryType.NONE,
null,
false,
null,
emptyList(),
emptyList(),
emptyList(),
null
) {
override fun isPaymentsActivated(): Boolean = true
override fun isUrgent(): Boolean = false
}
class OutgoingPaymentsNotificationMessage(
recipient: Recipient,
paymentUuid: String,
sentTimeMillis: Long,
expiresIn: Long
) : OutgoingSecureMediaMessage(
recipient,
paymentUuid,
LinkedList(),
sentTimeMillis,
ThreadTable.DistributionTypes.CONVERSATION,
expiresIn,
false,
StoryType.NONE,
null,
false,
null,
emptyList(),
emptyList(),
emptyList(),
null
) {
override fun isPaymentsNotification(): Boolean = true
}

View file

@ -1,102 +0,0 @@
package org.thoughtcrime.securesms.mms;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.database.model.ParentStoryId;
import org.thoughtcrime.securesms.database.model.StoryType;
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.Collections;
import java.util.List;
public class OutgoingSecureMediaMessage extends OutgoingMediaMessage {
public OutgoingSecureMediaMessage(Recipient recipient,
String body,
List<Attachment> attachments,
long sentTimeMillis,
int distributionType,
long expiresIn,
boolean viewOnce,
@NonNull StoryType storyType,
@Nullable ParentStoryId parentStoryId,
boolean isStoryReaction,
@Nullable QuoteModel quote,
@NonNull List<Contact> contacts,
@NonNull List<LinkPreview> previews,
@NonNull List<Mention> mentions,
@Nullable GiftBadge giftBadge)
{
super(recipient, body, attachments, sentTimeMillis, -1, expiresIn, viewOnce, distributionType, storyType, parentStoryId, isStoryReaction, quote, contacts, previews, mentions, Collections.emptySet(), Collections.emptySet(), giftBadge);
}
public OutgoingSecureMediaMessage(OutgoingMediaMessage base) {
super(base);
}
@Override
public boolean isSecure() {
return true;
}
@Override
public @NonNull OutgoingMediaMessage withExpiry(long expiresIn) {
return new OutgoingSecureMediaMessage(getRecipient(),
getBody(),
getAttachments(),
getSentTimeMillis(),
getDistributionType(),
expiresIn,
isViewOnce(),
getStoryType(),
getParentStoryId(),
isStoryReaction(),
getOutgoingQuote(),
getSharedContacts(),
getLinkPreviews(),
getMentions(),
getGiftBadge());
}
public @NonNull OutgoingSecureMediaMessage withSentTimestamp(long sentTimestamp) {
return new OutgoingSecureMediaMessage(getRecipient(),
getBody(),
getAttachments(),
sentTimestamp,
getDistributionType(),
getExpiresIn(),
isViewOnce(),
getStoryType(),
getParentStoryId(),
isStoryReaction(),
getOutgoingQuote(),
getSharedContacts(),
getLinkPreviews(),
getMentions(),
getGiftBadge());
}
public @NonNull OutgoingSecureMediaMessage stripAttachments() {
return new OutgoingSecureMediaMessage(getRecipient(),
getBody(),
Collections.emptyList(),
getSentTimeMillis(),
getDistributionType(),
getExpiresIn(),
isViewOnce(),
getStoryType(),
getParentStoryId(),
isStoryReaction(),
getOutgoingQuote(),
Collections.emptyList(),
getLinkPreviews(),
getMentions(),
getGiftBadge());
}
}

View file

@ -101,7 +101,8 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
Collections.emptyList(),
Collections.emptySet(),
Collections.emptySet(),
null);
null,
recipient.isPushGroup());
threadId = MessageSender.send(context, reply, -1, false, null, null);
break;
}

View file

@ -24,7 +24,7 @@ import org.thoughtcrime.securesms.jobs.MultiDeviceMessageRequestResponseJob;
import org.thoughtcrime.securesms.jobs.RefreshOwnProfileJob;
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
import org.whispersystems.signalservice.api.push.ServiceId;
@ -319,7 +319,7 @@ public class RecipientUtil {
if (threadId == -1 || !SignalDatabase.mmsSms().hasMeaningfulMessage(threadId)) {
SignalDatabase.recipients().setExpireMessages(recipient.getId(), defaultTimer);
OutgoingExpirationUpdateMessage outgoingMessage = new OutgoingExpirationUpdateMessage(recipient, System.currentTimeMillis(), defaultTimer * 1000L);
OutgoingMediaMessage outgoingMessage = OutgoingMediaMessage.expirationUpdateMessage(recipient, System.currentTimeMillis(), defaultTimer * 1000L);
MessageSender.send(context, outgoingMessage, SignalDatabase.threads().getOrCreateThreadIdFor(recipient), false, null, null);
return true;
}

View file

@ -23,7 +23,6 @@ import org.thoughtcrime.securesms.conversation.MessageSendType;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.database.AttachmentTable;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.ThreadTable;
import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.database.model.StoryType;
import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost;
@ -35,7 +34,6 @@ import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryBackgroundColors;
import org.thoughtcrime.securesms.mms.ImageSlide;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.mms.SentMediaQuality;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
@ -168,7 +166,7 @@ public final class MultiShareSender {
if (!storiesBatch.isEmpty()) {
MessageSender.sendStories(context,
storiesBatch.stream()
.map(OutgoingSecureMediaMessage::new)
.map(OutgoingMediaMessage::makeSecure)
.collect(Collectors.toList()),
null,
null);
@ -249,15 +247,10 @@ public final class MultiShareSender {
subscriptionId,
0L,
false,
ThreadTable.DistributionTypes.DEFAULT,
storyType.toTextStoryType(),
null,
false,
null,
Collections.emptyList(),
buildLinkPreviews(context, multiShareArgs.getLinkPreview()),
Collections.emptyList(),
null);
false);
outgoingMessages.add(outgoingMediaMessage);
} else if (canSendAsTextStory) {
@ -288,15 +281,10 @@ public final class MultiShareSender {
subscriptionId,
0L,
false,
ThreadTable.DistributionTypes.DEFAULT,
storyType,
null,
false,
null,
Collections.emptyList(),
Collections.emptyList(),
validatedMentions,
null);
false);
outgoingMessages.add(outgoingMediaMessage);
}
@ -309,15 +297,10 @@ public final class MultiShareSender {
subscriptionId,
expiresIn,
isViewOnce,
ThreadTable.DistributionTypes.DEFAULT,
StoryType.NONE,
null,
false,
null,
Collections.emptyList(),
buildLinkPreviews(context, multiShareArgs.getLinkPreview()),
validatedMentions,
null);
false);
outgoingMessages.add(outgoingMediaMessage);
}
@ -326,7 +309,7 @@ public final class MultiShareSender {
storiesToBatchSend.addAll(outgoingMessages);
} else if (shouldSendAsPush(recipient, forceSms)) {
for (final OutgoingMediaMessage outgoingMessage : outgoingMessages) {
MessageSender.send(context, new OutgoingSecureMediaMessage(outgoingMessage), threadId, false, null, null);
MessageSender.send(context, outgoingMessage.makeSecure(), threadId, false, null, null);
}
} else {
for (final OutgoingMediaMessage outgoingMessage : outgoingMessages) {
@ -421,7 +404,7 @@ public final class MultiShareSender {
@NonNull StoryType storyType,
@NonNull ChatColors background)
{
return new OutgoingMediaMessage(
return OutgoingMediaMessage.textStoryMessage(
recipient,
Base64.encodeBytes(StoryTextPost.newBuilder()
.setBody(getBodyForTextStory(multiShareArgs.getDraftText(), multiShareArgs.getLinkPreview()))
@ -431,22 +414,9 @@ public final class MultiShareSender {
.setTextForegroundColor(Color.WHITE)
.build()
.toByteArray()),
Collections.emptyList(),
sentTimestamp,
-1,
0,
false,
ThreadTable.DistributionTypes.DEFAULT,
storyType.toTextStoryType(),
null,
false,
null,
Collections.emptyList(),
buildLinkPreviews(context, multiShareArgs.getLinkPreview()),
Collections.emptyList(),
Collections.emptySet(),
Collections.emptySet(),
null);
buildLinkPreviews(context, multiShareArgs.getLinkPreview()));
}
private static @NonNull String getBodyForTextStory(@Nullable String draftText, @Nullable LinkPreview linkPreview) {

View file

@ -70,7 +70,6 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mms.MmsException;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
@ -138,7 +137,7 @@ public class MessageSender {
}
public static void sendStories(@NonNull final Context context,
@NonNull final List<OutgoingSecureMediaMessage> messages,
@NonNull final List<OutgoingMediaMessage> messages,
@Nullable final String metricId,
@Nullable final SmsTable.InsertListener insertListener)
{
@ -152,7 +151,7 @@ public class MessageSender {
try {
database.beginTransaction();
for (OutgoingSecureMediaMessage message : messages) {
for (OutgoingMediaMessage message : messages) {
long allocatedThreadId = threadTable.getOrCreateValidThreadId(message.getRecipient(), -1L, message.getDistributionType());
long messageId = database.insertMessageOutbox(message.stripAttachments(), allocatedThreadId, false, insertListener);
@ -167,9 +166,9 @@ public class MessageSender {
}
for (int i = 0; i < messageIds.size(); i++) {
long messageId = messageIds.get(i);
OutgoingSecureMediaMessage message = messages.get(i);
Recipient recipient = message.getRecipient();
long messageId = messageIds.get(i);
OutgoingMediaMessage message = messages.get(i);
Recipient recipient = message.getRecipient();
if (recipient.isDistributionList()) {
DistributionId distributionId = Objects.requireNonNull(SignalDatabase.distributionLists().getDistributionId(recipient.requireDistributionListId()));
@ -193,7 +192,7 @@ public class MessageSender {
for (int i = 0; i < messageIds.size(); i++) {
long messageId = messageIds.get(i);
OutgoingSecureMediaMessage message = messages.get(i);
OutgoingMediaMessage message = messages.get(i);
List<UploadDependencyGraph.Node> nodes = dependencyGraph.getDependencyMap().get(message);
if (nodes == null || nodes.isEmpty()) {
@ -228,7 +227,7 @@ public class MessageSender {
for (int i = 0; i < messageIds.size(); i++) {
long messageId = messageIds.get(i);
OutgoingSecureMediaMessage message = messages.get(i);
OutgoingMediaMessage message = messages.get(i);
Recipient recipient = message.getRecipient();
List<UploadDependencyGraph.Node> dependencies = dependencyGraph.getDependencyMap().get(message);
@ -327,7 +326,7 @@ public class MessageSender {
}
public static void sendMediaBroadcast(@NonNull Context context,
@NonNull List<OutgoingSecureMediaMessage> messages,
@NonNull List<OutgoingMediaMessage> messages,
@NonNull Collection<PreUploadResult> preUploadResults,
boolean overwritePreUploadMessageIds)
{
@ -335,15 +334,15 @@ public class MessageSender {
Preconditions.checkArgument(messages.size() > 0, "No messages!");
Preconditions.checkArgument(Stream.of(messages).allMatch(m -> m.getAttachments().isEmpty()), "Messages can't have attachments! They should be pre-uploaded.");
JobManager jobManager = ApplicationDependencies.getJobManager();
AttachmentTable attachmentDatabase = SignalDatabase.attachments();
MessageTable mmsDatabase = SignalDatabase.mms();
ThreadTable threadTable = SignalDatabase.threads();
List<AttachmentId> preUploadAttachmentIds = Stream.of(preUploadResults).map(PreUploadResult::getAttachmentId).toList();
List<String> preUploadJobIds = Stream.of(preUploadResults).map(PreUploadResult::getJobIds).flatMap(Stream::of).toList();
List<Long> messageIds = new ArrayList<>(messages.size());
List<String> messageDependsOnIds = new ArrayList<>(preUploadJobIds);
OutgoingSecureMediaMessage primaryMessage = messages.get(0);
JobManager jobManager = ApplicationDependencies.getJobManager();
AttachmentTable attachmentDatabase = SignalDatabase.attachments();
MessageTable mmsDatabase = SignalDatabase.mms();
ThreadTable threadTable = SignalDatabase.threads();
List<AttachmentId> preUploadAttachmentIds = Stream.of(preUploadResults).map(PreUploadResult::getAttachmentId).toList();
List<String> preUploadJobIds = Stream.of(preUploadResults).map(PreUploadResult::getJobIds).flatMap(Stream::of).toList();
List<Long> messageIds = new ArrayList<>(messages.size());
List<String> messageDependsOnIds = new ArrayList<>(preUploadJobIds);
OutgoingMediaMessage primaryMessage = messages.get(0);
mmsDatabase.beginTransaction();
try {
@ -368,14 +367,14 @@ public class MessageSender {
.toList();
if (messages.size() > 0) {
List<OutgoingSecureMediaMessage> secondaryMessages = overwritePreUploadMessageIds ? messages.subList(1, messages.size()) : messages;
List<List<AttachmentId>> attachmentCopies = new ArrayList<>();
List<OutgoingMediaMessage> secondaryMessages = overwritePreUploadMessageIds ? messages.subList(1, messages.size()) : messages;
List<List<AttachmentId>> attachmentCopies = new ArrayList<>();
for (int i = 0; i < preUploadAttachmentIds.size(); i++) {
attachmentCopies.add(new ArrayList<>(messages.size()));
}
for (OutgoingSecureMediaMessage secondaryMessage : secondaryMessages) {
for (OutgoingMediaMessage secondaryMessage : secondaryMessages) {
long allocatedThreadId = threadTable.getOrCreateThreadIdFor(secondaryMessage.getRecipient(), secondaryMessage.getDistributionType());
long messageId = mmsDatabase.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, secondaryMessage.getRecipient(), secondaryMessage, allocatedThreadId),
allocatedThreadId,
@ -407,9 +406,9 @@ public class MessageSender {
}
for (int i = 0; i < messageIds.size(); i++) {
long messageId = messageIds.get(i);
OutgoingSecureMediaMessage message = messages.get(i);
Recipient recipient = message.getRecipient();
long messageId = messageIds.get(i);
OutgoingMediaMessage message = messages.get(i);
Recipient recipient = message.getRecipient();
if (recipient.isDistributionList()) {
List<RecipientId> members = SignalDatabase.distributionLists().getMembers(recipient.requireDistributionListId());

View file

@ -25,7 +25,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseStoryTypeBottomSheet
import org.thoughtcrime.securesms.mms.MediaConstraints
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.SentMediaQuality
import org.thoughtcrime.securesms.mms.VideoSlide
import org.thoughtcrime.securesms.recipients.Recipient
@ -81,7 +81,7 @@ object Stories {
}
}
fun sendTextStories(messages: List<OutgoingSecureMediaMessage>): Completable {
fun sendTextStories(messages: List<OutgoingMediaMessage>): Completable {
return Completable.create { emitter ->
MessageSender.sendStories(ApplicationDependencies.getApplication(), messages, null, null)
emitter.onComplete()

View file

@ -16,13 +16,10 @@ import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.ThreadTable
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
import org.thoughtcrime.securesms.mms.SlideDeck
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.sharing.MultiShareArgs
@ -105,25 +102,12 @@ class AddToGroupStoryDelegate(
Log.d(TAG, "Sending preupload media.")
val recipient = Recipient.resolved(result.recipientId)
val secureMessage = OutgoingSecureMediaMessage(
OutgoingMediaMessage(
Recipient.resolved(result.recipientId),
SlideDeck(),
"",
System.currentTimeMillis(),
-1,
0,
false,
ThreadTable.DistributionTypes.DEFAULT,
result.storyType,
null,
false,
null,
emptyList(),
emptyList(),
result.mentions.toList(),
null
)
val secureMessage = OutgoingMediaMessage(
recipient = recipient,
timestamp = System.currentTimeMillis(),
storyType = result.storyType,
mentions = result.mentions.toList(),
isSecure = true
)
val threadId = SignalDatabase.threads.getOrCreateThreadIdFor(recipient)

View file

@ -12,7 +12,6 @@ import org.thoughtcrime.securesms.database.model.ParentStoryId
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.mediasend.v2.UntrustedRecords
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
import org.thoughtcrime.securesms.sms.MessageSender
/**
@ -42,27 +41,16 @@ object StoryGroupReplySender {
Completable.create {
MessageSender.send(
context,
OutgoingSecureMediaMessage(
OutgoingMediaMessage(
recipient,
body.toString(),
emptyList(),
System.currentTimeMillis(),
0,
0L,
false,
0,
StoryType.NONE,
ParentStoryId.GroupReply(message.id),
isReaction,
null,
emptyList(),
emptyList(),
mentions,
emptySet(),
emptySet(),
null
)
OutgoingMediaMessage(
recipient = recipient,
body = body.toString(),
timestamp = System.currentTimeMillis(),
distributionType = 0,
storyType = StoryType.NONE,
parentStoryId = ParentStoryId.GroupReply(message.id),
isStoryReaction = isReaction,
mentions = mentions,
isSecure = true
),
message.threadId,
false,

View file

@ -21,9 +21,9 @@ import org.thoughtcrime.securesms.jobs.AttachmentCompressionJob
import org.thoughtcrime.securesms.jobs.AttachmentCopyJob
import org.thoughtcrime.securesms.jobs.AttachmentUploadJob
import org.thoughtcrime.securesms.jobs.ResumableUploadSpecJob
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.SentMediaQuality
import org.thoughtcrime.securesms.testutil.OutgoingMediaMessageBuilder
import org.thoughtcrime.securesms.testutil.OutgoingMediaMessageBuilder.secure
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.testutil.UriAttachmentBuilder
import org.thoughtcrime.securesms.util.JsonUtils
import org.thoughtcrime.securesms.util.MediaUtil
@ -51,7 +51,7 @@ class UploadDependencyGraphTest {
fun `Given a list of Uri attachments and a list of Messages, when I get the dependencyMap, then I expect a times m results`() {
// GIVEN
val uriAttachments = (1..5).map { UriAttachmentBuilder.build(id = uniqueLong.getAndIncrement(), contentType = MediaUtil.IMAGE_JPEG) }
val messages = (1..5).map { OutgoingMediaMessageBuilder.create(attachments = uriAttachments).secure() }
val messages = (1..5).createMessages(uriAttachments)
val testSubject = UploadDependencyGraph.create(messages, jobManager) { getAttachmentForPreUpload(uniqueLong.getAndIncrement(), it) }
// WHEN
@ -66,7 +66,7 @@ class UploadDependencyGraphTest {
fun `Given a list of Uri attachments and a list of Messages, when I consumeDeferredQueue, then I expect one upload chain and one copy job for each attachment`() {
// GIVEN
val uriAttachments = (1..5).map { UriAttachmentBuilder.build(id = uniqueLong.getAndIncrement(), contentType = MediaUtil.IMAGE_JPEG) }
val messages = (1..5).map { OutgoingMediaMessageBuilder.create(attachments = uriAttachments).secure() }
val messages = (1..5).createMessages(uriAttachments)
val testSubject = UploadDependencyGraph.create(messages, jobManager) { getAttachmentForPreUpload(uniqueLong.getAndIncrement(), it) }
// WHEN
@ -88,7 +88,7 @@ class UploadDependencyGraphTest {
)
}
val messages = (1..5).map { OutgoingMediaMessageBuilder.create(attachments = uriAttachments).secure() }
val messages = (1..5).createMessages(uriAttachments)
val testSubject = UploadDependencyGraph.create(messages, jobManager) { getAttachmentForPreUpload(uniqueLong.getAndIncrement(), it) }
// WHEN
@ -108,7 +108,7 @@ class UploadDependencyGraphTest {
)
}
val messages = (1..5).map { OutgoingMediaMessageBuilder.create(attachments = uriAttachments).secure() }
val messages = (1..5).createMessages(uriAttachments)
val testSubject = UploadDependencyGraph.create(messages, jobManager) { getAttachmentForPreUpload(uniqueLong.getAndIncrement(), it) }
// WHEN
@ -130,7 +130,7 @@ class UploadDependencyGraphTest {
)
}
val messages = (1..8).map { OutgoingMediaMessageBuilder.create(attachments = uriAttachments).secure() }
val messages = (1..8).createMessages(uriAttachments)
val testSubject = UploadDependencyGraph.create(messages, jobManager) { getAttachmentForPreUpload(uniqueLong.getAndIncrement(), it) }
// WHEN
@ -150,7 +150,7 @@ class UploadDependencyGraphTest {
getAttachmentForPreUpload(id, uriAttachment)
}
val messages = (1..5).map { OutgoingMediaMessageBuilder.create(attachments = databaseAttachments).secure() }
val messages = (1..5).createMessages(databaseAttachments)
val testSubject = UploadDependencyGraph.create(messages, jobManager) { getAttachmentForPreUpload(uniqueLong.getAndIncrement(), it) }
// WHEN
@ -166,8 +166,8 @@ class UploadDependencyGraphTest {
// GIVEN
val attachment1 = UriAttachmentBuilder.build(uniqueLong.getAndIncrement(), contentType = MediaUtil.IMAGE_JPEG)
val attachment2 = UriAttachmentBuilder.build(uniqueLong.getAndIncrement(), contentType = MediaUtil.IMAGE_JPEG)
val message1 = OutgoingMediaMessageBuilder.create(attachments = listOf(attachment1))
val message2 = OutgoingMediaMessageBuilder.create(attachments = listOf(attachment2))
val message1 = OutgoingMediaMessage(recipient = Recipient.UNKNOWN, sentTimeMillis = System.currentTimeMillis(), attachments = listOf(attachment1))
val message2 = OutgoingMediaMessage(recipient = Recipient.UNKNOWN, sentTimeMillis = System.currentTimeMillis() + 1, attachments = listOf(attachment2))
val testSubject = UploadDependencyGraph.create(listOf(message1, message2), jobManager) { getAttachmentForPreUpload(uniqueLong.getAndIncrement(), it) }
// WHEN
@ -190,7 +190,7 @@ class UploadDependencyGraphTest {
)
}
val message = OutgoingMediaMessageBuilder.create(attachments = uriAttachments)
val message = OutgoingMediaMessage(recipient = Recipient.UNKNOWN, sentTimeMillis = System.currentTimeMillis(), attachments = uriAttachments)
val testSubject = UploadDependencyGraph.create(listOf(message), jobManager) { getAttachmentForPreUpload(uniqueLong.getAndIncrement(), it) }
val result = testSubject.consumeDeferredQueue()
@ -257,4 +257,15 @@ class UploadDependencyGraphTest {
attachment.uploadTimestamp
)
}
private fun Iterable<Int>.createMessages(uriAttachments: List<Attachment>): List<OutgoingMediaMessage> {
return mapIndexed { index, _ ->
OutgoingMediaMessage(
recipient = Recipient.UNKNOWN,
sentTimeMillis = System.currentTimeMillis() + index,
attachments = uriAttachments,
isSecure = true
)
}
}
}

View file

@ -1,62 +0,0 @@
package org.thoughtcrime.securesms.testutil
import org.thoughtcrime.securesms.attachments.Attachment
import org.thoughtcrime.securesms.contactshare.Contact
import org.thoughtcrime.securesms.database.ThreadTable
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch
import org.thoughtcrime.securesms.database.documents.NetworkFailure
import org.thoughtcrime.securesms.database.model.Mention
import org.thoughtcrime.securesms.database.model.ParentStoryId
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
import org.thoughtcrime.securesms.linkpreview.LinkPreview
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
import org.thoughtcrime.securesms.mms.QuoteModel
import org.thoughtcrime.securesms.recipients.Recipient
object OutgoingMediaMessageBuilder {
fun create(
recipient: Recipient = Recipient.UNKNOWN,
message: String = "",
attachments: List<Attachment> = emptyList(),
sentTimeMillis: Long = System.currentTimeMillis(),
subscriptionId: Int = -1,
expiresIn: Long = -1,
viewOnce: Boolean = false,
distributionType: Int = ThreadTable.DistributionTypes.DEFAULT,
storyType: StoryType = StoryType.NONE,
parentStoryId: ParentStoryId? = null,
isStoryReaction: Boolean = false,
quoteModel: QuoteModel? = null,
contacts: List<Contact> = emptyList(),
linkPreviews: List<LinkPreview> = emptyList(),
mentions: List<Mention> = emptyList(),
networkFailures: Set<NetworkFailure> = emptySet(),
identityKeyMismatches: Set<IdentityKeyMismatch> = emptySet(),
giftBadge: GiftBadge? = null
): OutgoingMediaMessage {
return OutgoingMediaMessage(
recipient,
message,
attachments,
sentTimeMillis,
subscriptionId,
expiresIn,
viewOnce,
distributionType,
storyType,
parentStoryId,
isStoryReaction,
quoteModel,
contacts,
linkPreviews,
mentions,
networkFailures,
identityKeyMismatches,
giftBadge
)
}
fun OutgoingMediaMessage.secure(): OutgoingSecureMediaMessage = OutgoingSecureMediaMessage(this)
}