mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 09:20:19 +01:00
Implement Stories feature behind flag.
Co-Authored-By: Greyson Parrelli <37311915+greyson-signal@users.noreply.github.com> Co-Authored-By: Rashad Sookram <95182499+rashad-signal@users.noreply.github.com>
This commit is contained in:
@@ -12,6 +12,7 @@ import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||
import org.thoughtcrime.securesms.database.MessageSendLogDatabase;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.database.model.DistributionListId;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
@@ -37,6 +38,7 @@ import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
|
||||
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
|
||||
import org.whispersystems.signalservice.api.push.DistributionId;
|
||||
@@ -76,6 +78,7 @@ public final class GroupSendUtil {
|
||||
* @param groupId The groupId of the group you're sending to, or null if you're sending to a collection of recipients not joined by a group.
|
||||
* @param isRecipientUpdate True if you've already sent this message to some recipients in the past, otherwise false.
|
||||
*/
|
||||
@WorkerThread
|
||||
public static List<SendMessageResult> sendResendableDataMessage(@NonNull Context context,
|
||||
@Nullable GroupId.V2 groupId,
|
||||
@NonNull List<Recipient> allTargets,
|
||||
@@ -85,7 +88,7 @@ public final class GroupSendUtil {
|
||||
@NonNull SignalServiceDataMessage message)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return sendMessage(context, groupId, messageId, allTargets, isRecipientUpdate, DataSendOperation.resendable(message, contentHint, messageId), null);
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), messageId, allTargets, isRecipientUpdate, DataSendOperation.resendable(message, contentHint, messageId), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,7 +109,7 @@ public final class GroupSendUtil {
|
||||
@NonNull SignalServiceDataMessage message)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return sendMessage(context, groupId, null, allTargets, isRecipientUpdate, DataSendOperation.unresendable(message, contentHint), null);
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, isRecipientUpdate, DataSendOperation.unresendable(message, contentHint), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,7 +126,7 @@ public final class GroupSendUtil {
|
||||
@Nullable CancelationSignal cancelationSignal)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return sendMessage(context, groupId, null, allTargets, false, new TypingSendOperation(message), cancelationSignal);
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, false, new TypingSendOperation(message), cancelationSignal);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,7 +142,43 @@ public final class GroupSendUtil {
|
||||
@NonNull SignalServiceCallMessage message)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return sendMessage(context, groupId, null, allTargets, false, new CallSendOperation(message), null);
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), null, allTargets, false, new CallSendOperation(message), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles all of the logic of sending a story to a group. Will do sender key sends and legacy 1:1 sends as-needed, and give you back a list of
|
||||
* {@link SendMessageResult}s just like we're used to.
|
||||
*
|
||||
* @param isRecipientUpdate True if you've already sent this message to some recipients in the past, otherwise false.
|
||||
*/
|
||||
public static List<SendMessageResult> sendStoryMessage(@NonNull Context context,
|
||||
@NonNull DistributionListId distributionListId,
|
||||
@NonNull List<Recipient> allTargets,
|
||||
boolean isRecipientUpdate,
|
||||
@NonNull MessageId messageId,
|
||||
long sentTimestamp,
|
||||
@NonNull SignalServiceStoryMessage message)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return sendMessage(context, null, getDistributionId(distributionListId), messageId, allTargets, isRecipientUpdate, new StorySendOperation(messageId, null, sentTimestamp, message), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles all of the logic of sending a story to a group. Will do sender key sends and legacy 1:1 sends as-needed, and give you back a list of
|
||||
* {@link SendMessageResult}s just like we're used to.
|
||||
*
|
||||
* @param isRecipientUpdate True if you've already sent this message to some recipients in the past, otherwise false.
|
||||
*/
|
||||
public static List<SendMessageResult> sendGroupStoryMessage(@NonNull Context context,
|
||||
@NonNull GroupId.V2 groupId,
|
||||
@NonNull List<Recipient> allTargets,
|
||||
boolean isRecipientUpdate,
|
||||
@NonNull MessageId messageId,
|
||||
long sentTimestamp,
|
||||
@NonNull SignalServiceStoryMessage message)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return sendMessage(context, groupId, getDistributionId(groupId), messageId, allTargets, isRecipientUpdate, new StorySendOperation(messageId, groupId, sentTimestamp, message), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,6 +191,7 @@ public final class GroupSendUtil {
|
||||
@WorkerThread
|
||||
private static List<SendMessageResult> sendMessage(@NonNull Context context,
|
||||
@Nullable GroupId.V2 groupId,
|
||||
@Nullable DistributionId distributionId,
|
||||
@Nullable MessageId relatedMessageId,
|
||||
@NonNull List<Recipient> allTargets,
|
||||
boolean isRecipientUpdate,
|
||||
@@ -159,7 +199,7 @@ public final class GroupSendUtil {
|
||||
@Nullable CancelationSignal cancelationSignal)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
Log.i(TAG, "Starting group send. GroupId: " + (groupId != null ? groupId.toString() : "none") + ", RelatedMessageId: " + (relatedMessageId != null ? relatedMessageId.toString() : "none") + ", Targets: " + allTargets.size() + ", RecipientUpdate: " + isRecipientUpdate + ", Operation: " + sendOperation.getClass().getSimpleName());
|
||||
Log.i(TAG, "Starting group send. GroupId: " + (groupId != null ? groupId.toString() : "none") + ", DistributionListId: " + (distributionId != null ? distributionId.toString() : "none") + " RelatedMessageId: " + (relatedMessageId != null ? relatedMessageId.toString() : "none") + ", Targets: " + allTargets.size() + ", RecipientUpdate: " + isRecipientUpdate + ", Operation: " + sendOperation.getClass().getSimpleName());
|
||||
|
||||
Set<Recipient> unregisteredTargets = allTargets.stream().filter(Recipient::isUnregistered).collect(Collectors.toSet());
|
||||
List<Recipient> registeredTargets = allTargets.stream().filter(r -> !unregisteredTargets.contains(r)).collect(Collectors.toList());
|
||||
@@ -172,7 +212,11 @@ public final class GroupSendUtil {
|
||||
|
||||
for (Recipient recipient : registeredTargets) {
|
||||
Optional<UnidentifiedAccessPair> access = recipients.getAccessPair(recipient.getId());
|
||||
boolean validMembership = groupRecord.isPresent() && groupRecord.get().getMembers().contains(recipient.getId());
|
||||
boolean validMembership = true;
|
||||
|
||||
if (groupId != null && (!groupRecord.isPresent() || !groupRecord.get().getMembers().contains(recipient.getId()))) {
|
||||
validMembership = false;
|
||||
}
|
||||
|
||||
if (recipient.getSenderKeyCapability() == Recipient.Capability.SUPPORTED &&
|
||||
recipient.hasServiceId() &&
|
||||
@@ -186,8 +230,8 @@ public final class GroupSendUtil {
|
||||
}
|
||||
}
|
||||
|
||||
if (groupId == null) {
|
||||
Log.i(TAG, "Recipients not in a group. Using legacy.");
|
||||
if (distributionId == null) {
|
||||
Log.i(TAG, "No DistributionId. Using legacy.");
|
||||
legacyTargets.addAll(senderKeyTargets);
|
||||
senderKeyTargets.clear();
|
||||
} else if (Recipient.self().getSenderKeyCapability() != Recipient.Capability.SUPPORTED) {
|
||||
@@ -204,21 +248,20 @@ public final class GroupSendUtil {
|
||||
Log.i(TAG, "Can use sender key for " + senderKeyTargets.size() + "/" + allTargets.size() + " recipients.");
|
||||
}
|
||||
|
||||
if (relatedMessageId != null) {
|
||||
if (relatedMessageId != null && groupId != null) {
|
||||
SignalLocalMetrics.GroupMessageSend.onSenderKeyStarted(relatedMessageId.getId());
|
||||
}
|
||||
|
||||
List<SendMessageResult> allResults = new ArrayList<>(allTargets.size());
|
||||
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
|
||||
SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
|
||||
|
||||
if (senderKeyTargets.size() > 0 && groupId != null) {
|
||||
DistributionId distributionId = SignalDatabase.groups().getOrCreateDistributionId(groupId);
|
||||
long keyCreateTime = SenderKeyUtil.getCreateTimeForOurKey(context, distributionId);
|
||||
if (senderKeyTargets.size() > 0 && distributionId != null) {
|
||||
long keyCreateTime = SenderKeyUtil.getCreateTimeForOurKey(distributionId);
|
||||
long keyAge = System.currentTimeMillis() - keyCreateTime;
|
||||
|
||||
if (keyCreateTime != -1 && keyAge > FeatureFlags.senderKeyMaxAge()) {
|
||||
Log.w(TAG, "DistributionId " + distributionId + " was created at " + keyCreateTime + " and is " + (keyAge) + " ms old (~" + TimeUnit.MILLISECONDS.toDays(keyAge) + " days). Rotating.");
|
||||
SenderKeyUtil.rotateOurKey(context, distributionId);
|
||||
SenderKeyUtil.rotateOurKey(distributionId);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -324,6 +367,22 @@ public final class GroupSendUtil {
|
||||
return allResults;
|
||||
}
|
||||
|
||||
private static @Nullable DistributionId getDistributionId(@Nullable GroupId.V2 groupId) {
|
||||
if (groupId != null) {
|
||||
return SignalDatabase.groups().getOrCreateDistributionId(groupId);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable DistributionId getDistributionId(@Nullable DistributionListId distributionListId) {
|
||||
if (distributionListId != null) {
|
||||
return Optional.fromNullable(SignalDatabase.distributionLists().getDistributionId(distributionListId)).orNull();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Abstraction layer to handle the different types of message send operations we can do */
|
||||
private interface SendOperation {
|
||||
@NonNull List<SendMessageResult> sendWithSenderKey(@NonNull SignalServiceMessageSender messageSender,
|
||||
@@ -528,6 +587,64 @@ public final class GroupSendUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static class StorySendOperation implements SendOperation {
|
||||
|
||||
private final MessageId relatedMessageId;
|
||||
private final GroupId groupId;
|
||||
private final long sentTimestamp;
|
||||
private final SignalServiceStoryMessage message;
|
||||
|
||||
public StorySendOperation(@NonNull MessageId relatedMessageId, @Nullable GroupId groupId, long sentTimestamp, @NonNull SignalServiceStoryMessage message) {
|
||||
this.relatedMessageId = relatedMessageId;
|
||||
this.groupId = groupId;
|
||||
this.sentTimestamp = sentTimestamp;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull List<SendMessageResult> sendWithSenderKey(@NonNull SignalServiceMessageSender messageSender,
|
||||
@NonNull DistributionId distributionId,
|
||||
@NonNull List<SignalServiceAddress> targets,
|
||||
@NonNull List<UnidentifiedAccess> access,
|
||||
boolean isRecipientUpdate)
|
||||
throws NoSessionException, UntrustedIdentityException, InvalidKeyException, IOException, InvalidRegistrationIdException
|
||||
{
|
||||
return messageSender.sendGroupStory(distributionId, Optional.fromNullable(groupId).transform(GroupId::getDecodedId), targets, access, message, getSentTimestamp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull List<SendMessageResult> sendLegacy(@NonNull SignalServiceMessageSender messageSender,
|
||||
@NonNull List<SignalServiceAddress> targets,
|
||||
@NonNull List<Optional<UnidentifiedAccessPair>> access,
|
||||
boolean isRecipientUpdate,
|
||||
@Nullable PartialSendCompleteListener partialListener,
|
||||
@Nullable CancelationSignal cancelationSignal)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
return messageSender.sendStory(targets, access, message, getSentTimestamp());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ContentHint getContentHint() {
|
||||
return ContentHint.RESENDABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSentTimestamp() {
|
||||
return sentTimestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldIncludeInMessageLog() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MessageId getRelatedMessageId() {
|
||||
return relatedMessageId;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SenderKeyMetricEventListener implements SenderKeyGroupEvents {
|
||||
|
||||
private final long messageId;
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase.InsertResult;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase.SyncMessageId;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||
import org.thoughtcrime.securesms.database.PaymentDatabase;
|
||||
import org.thoughtcrime.securesms.database.PaymentMetaDataUtil;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
@@ -132,7 +133,9 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroupContext;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroupV2;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServicePreview;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceStoryMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
|
||||
import org.whispersystems.signalservice.api.messages.calls.AnswerMessage;
|
||||
import org.whispersystems.signalservice.api.messages.calls.BusyMessage;
|
||||
@@ -266,7 +269,7 @@ public final class MessageContentProcessor {
|
||||
else if (message.getReaction().isPresent()) messageId = handleReaction(content, message, senderRecipient);
|
||||
else if (message.getRemoteDelete().isPresent()) messageId = handleRemoteDelete(content, message, senderRecipient);
|
||||
else if (message.getPayment().isPresent()) handlePayment(content, message, senderRecipient);
|
||||
else if (message.getStoryContext().isPresent()) handleStoryMessage(content);
|
||||
else if (message.getStoryContext().isPresent()) handleStoryReply(content, message, senderRecipient);
|
||||
else if (isMediaMessage) messageId = handleMediaMessage(content, message, smsMessageId, senderRecipient, threadRecipient, receivedTime);
|
||||
else if (message.getBody().isPresent()) messageId = handleTextMessage(content, message, smsMessageId, groupId, senderRecipient, threadRecipient, receivedTime);
|
||||
else if (Build.VERSION.SDK_INT > 19 && message.getGroupCallUpdate().isPresent()) handleGroupCallUpdateMessage(content, message, groupId, senderRecipient);
|
||||
@@ -344,6 +347,8 @@ public final class MessageContentProcessor {
|
||||
else if (message.isViewedReceipt()) handleViewedReceipt(content, message, senderRecipient);
|
||||
} else if (content.getTypingMessage().isPresent()) {
|
||||
handleTypingMessage(content, content.getTypingMessage().get(), senderRecipient);
|
||||
} else if (content.getStoryMessage().isPresent()) {
|
||||
handleStoryMessage(content, content.getStoryMessage().get(), senderRecipient);
|
||||
} else if (content.getDecryptionErrorMessage().isPresent()) {
|
||||
handleRetryReceipt(content, content.getDecryptionErrorMessage().get(), senderRecipient);
|
||||
} else if (content.getSenderKeyDistributionMessage().isPresent()) {
|
||||
@@ -824,6 +829,8 @@ public final class MessageContentProcessor {
|
||||
content.getTimestamp(),
|
||||
content.getServerReceivedTimestamp(),
|
||||
receivedTime,
|
||||
false,
|
||||
null,
|
||||
-1,
|
||||
expiresInSeconds * 1000L,
|
||||
true,
|
||||
@@ -1161,6 +1168,8 @@ public final class MessageContentProcessor {
|
||||
handleRemoteDelete(content, message.getMessage(), senderRecipient);
|
||||
} else if (message.getMessage().getAttachments().isPresent() || message.getMessage().getQuote().isPresent() || message.getMessage().getPreviews().isPresent() || message.getMessage().getSticker().isPresent() || message.getMessage().isViewOnce() || message.getMessage().getMentions().isPresent()) {
|
||||
threadId = handleSynchronizeSentMediaMessage(message, content.getTimestamp());
|
||||
} else if (message.getMessage().getStoryContext().isPresent()) {
|
||||
handleStoryReply(content, message.getMessage(), senderRecipient);
|
||||
} else {
|
||||
threadId = handleSynchronizeSentTextMessage(message, content.getTimestamp());
|
||||
}
|
||||
@@ -1305,8 +1314,109 @@ public final class MessageContentProcessor {
|
||||
messageNotifier.updateNotification(context);
|
||||
}
|
||||
|
||||
private void handleStoryMessage(SignalServiceContent content) {
|
||||
warn(content.getTimestamp(), "Detected a story reply. We do not support this yet. Dropping.");
|
||||
private void handleStoryMessage(@NonNull SignalServiceContent content, @NonNull SignalServiceStoryMessage message, @NonNull Recipient senderRecipient) throws StorageFailedException {
|
||||
log(content.getTimestamp(), "Story message.");
|
||||
|
||||
Optional<InsertResult> insertResult;
|
||||
|
||||
MessageDatabase database = SignalDatabase.mms();
|
||||
database.beginTransaction();
|
||||
|
||||
try {
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(senderRecipient.getId(),
|
||||
content.getTimestamp(),
|
||||
content.getServerReceivedTimestamp(),
|
||||
System.currentTimeMillis(),
|
||||
true,
|
||||
null,
|
||||
-1,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
content.isNeedsReceipt(),
|
||||
Optional.absent(),
|
||||
Optional.fromNullable(GroupUtil.getGroupContextIfPresent(content)),
|
||||
message.getFileAttachment().transform(Collections::singletonList),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
content.getServerUuid());
|
||||
|
||||
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
database.setTransactionSuccessful();
|
||||
}
|
||||
} catch (MmsException e) {
|
||||
throw new StorageFailedException(e, content.getSender().getIdentifier(), content.getSenderDevice());
|
||||
} finally {
|
||||
database.endTransaction();
|
||||
}
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
List<DatabaseAttachment> allAttachments = SignalDatabase.attachments().getAttachmentsForMessage(insertResult.get().getMessageId());
|
||||
List<DatabaseAttachment> attachments = Stream.of(allAttachments).filterNot(Attachment::isSticker).toList();
|
||||
|
||||
for (DatabaseAttachment attachment : attachments) {
|
||||
ApplicationDependencies.getJobManager().add(new AttachmentDownloadJob(insertResult.get().getMessageId(), attachment.getAttachmentId(), false));
|
||||
}
|
||||
|
||||
ApplicationDependencies.getExpireStoriesManager().scheduleIfNecessary();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStoryReply(@NonNull SignalServiceContent content, @NonNull SignalServiceDataMessage message, @NonNull Recipient senderRecipient) throws StorageFailedException {
|
||||
log(content.getTimestamp(), "Story reply.");
|
||||
|
||||
SignalServiceDataMessage.StoryContext storyContext = message.getStoryContext().get();
|
||||
|
||||
MessageDatabase database = SignalDatabase.mms();
|
||||
database.beginTransaction();
|
||||
|
||||
try {
|
||||
// TODO [stories] check if this works for group stories
|
||||
RecipientId storyAuthorRecipient = RecipientId.from(storyContext.getAuthorServiceId(), null);
|
||||
MessageId storyId;
|
||||
try {
|
||||
storyId = database.getStoryId(storyAuthorRecipient, storyContext.getSentTimestamp());
|
||||
} catch (NoSuchMessageException e) {
|
||||
warn(content.getTimestamp(), "Couldn't find story for reply.", e);
|
||||
return;
|
||||
}
|
||||
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(senderRecipient.getId(),
|
||||
content.getTimestamp(),
|
||||
content.getServerReceivedTimestamp(),
|
||||
System.currentTimeMillis(),
|
||||
false,
|
||||
storyId,
|
||||
-1,
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
content.isNeedsReceipt(),
|
||||
message.getBody(),
|
||||
Optional.fromNullable(GroupUtil.getGroupContextIfPresent(content)),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
content.getServerUuid());
|
||||
|
||||
Optional<InsertResult> insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
database.setTransactionSuccessful();
|
||||
}
|
||||
} catch (MmsException e) {
|
||||
throw new StorageFailedException(e, content.getSender().getIdentifier(), content.getSenderDevice());
|
||||
} finally {
|
||||
database.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable MessageId handleMediaMessage(@NonNull SignalServiceContent content,
|
||||
@@ -1337,6 +1447,8 @@ public final class MessageContentProcessor {
|
||||
message.getTimestamp(),
|
||||
content.getServerReceivedTimestamp(),
|
||||
receivedTime,
|
||||
false,
|
||||
null,
|
||||
-1,
|
||||
TimeUnit.SECONDS.toMillis(message.getExpiresInSeconds()),
|
||||
false,
|
||||
@@ -1433,16 +1545,22 @@ public final class MessageContentProcessor {
|
||||
syncAttachments.add(sticker.get());
|
||||
}
|
||||
|
||||
OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipients, message.getMessage().getBody().orNull(),
|
||||
syncAttachments,
|
||||
message.getTimestamp(), -1,
|
||||
TimeUnit.SECONDS.toMillis(message.getMessage().getExpiresInSeconds()),
|
||||
viewOnce,
|
||||
ThreadDatabase.DistributionTypes.DEFAULT, quote.orNull(),
|
||||
sharedContacts.or(Collections.emptyList()),
|
||||
previews.or(Collections.emptyList()),
|
||||
mentions.or(Collections.emptyList()),
|
||||
Collections.emptySet(), Collections.emptySet());
|
||||
OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipients,
|
||||
message.getMessage().getBody().orNull(),
|
||||
syncAttachments,
|
||||
message.getTimestamp(),
|
||||
-1,
|
||||
TimeUnit.SECONDS.toMillis(message.getMessage().getExpiresInSeconds()),
|
||||
viewOnce,
|
||||
ThreadDatabase.DistributionTypes.DEFAULT,
|
||||
false,
|
||||
null,
|
||||
quote.orNull(),
|
||||
sharedContacts.or(Collections.emptyList()),
|
||||
previews.or(Collections.emptyList()),
|
||||
mentions.or(Collections.emptyList()),
|
||||
Collections.emptySet(),
|
||||
Collections.emptySet());
|
||||
|
||||
mediaMessage = new OutgoingSecureMediaMessage(mediaMessage);
|
||||
|
||||
@@ -1622,17 +1740,19 @@ public final class MessageContentProcessor {
|
||||
|
||||
if (isGroup) {
|
||||
OutgoingMediaMessage outgoingMediaMessage = new OutgoingMediaMessage(recipient,
|
||||
new SlideDeck(),
|
||||
body,
|
||||
message.getTimestamp(),
|
||||
-1,
|
||||
expiresInMillis,
|
||||
false,
|
||||
ThreadDatabase.DistributionTypes.DEFAULT,
|
||||
null,
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList());
|
||||
new SlideDeck(),
|
||||
body,
|
||||
message.getTimestamp(),
|
||||
-1,
|
||||
expiresInMillis,
|
||||
false,
|
||||
ThreadDatabase.DistributionTypes.DEFAULT,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList(),
|
||||
Collections.emptyList());
|
||||
outgoingMediaMessage = new OutgoingSecureMediaMessage(outgoingMediaMessage);
|
||||
|
||||
messageId = SignalDatabase.mms().insertMessageOutbox(outgoingMediaMessage, threadId, false, GroupReceiptDatabase.STATUS_UNKNOWN, null);
|
||||
@@ -2160,13 +2280,13 @@ public final class MessageContentProcessor {
|
||||
return Optional.of(contacts);
|
||||
}
|
||||
|
||||
private Optional<List<LinkPreview>> getLinkPreviews(Optional<List<SignalServiceDataMessage.Preview>> previews, @NonNull String message) {
|
||||
private Optional<List<LinkPreview>> getLinkPreviews(Optional<List<SignalServicePreview>> previews, @NonNull String message) {
|
||||
if (!previews.isPresent() || previews.get().isEmpty()) return Optional.absent();
|
||||
|
||||
List<LinkPreview> linkPreviews = new ArrayList<>(previews.get().size());
|
||||
LinkPreviewUtil.Links urlsInMessage = LinkPreviewUtil.findValidPreviewUrls(message);
|
||||
|
||||
for (SignalServiceDataMessage.Preview preview : previews.get()) {
|
||||
for (SignalServicePreview preview : previews.get()) {
|
||||
Optional<Attachment> thumbnail = PointerAttachment.forPointer(preview.getImage());
|
||||
Optional<String> url = Optional.fromNullable(preview.getUrl());
|
||||
Optional<String> title = Optional.fromNullable(preview.getTitle());
|
||||
|
||||
Reference in New Issue
Block a user