mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-24 05:21:34 +00:00
Added support for link previews.
This commit is contained in:
@@ -101,7 +101,7 @@ public class AttachmentUploadJob extends ContextJob implements InjectableType {
|
||||
exception instanceof ConnectException;
|
||||
}
|
||||
|
||||
protected SignalServiceAttachment getAttachmentFor(Attachment attachment) {
|
||||
private SignalServiceAttachment getAttachmentFor(Attachment attachment) {
|
||||
try {
|
||||
if (attachment.getDataUri() == null || attachment.getSize() == 0) throw new IOException("Assertion failed, outgoing attachment has no data!");
|
||||
InputStream is = PartAuthority.getAttachmentStream(context, attachment.getDataUri());
|
||||
|
||||
@@ -33,18 +33,25 @@ public class MultiDeviceConfigurationUpdateJob extends ContextJob implements Inj
|
||||
private static final String KEY_READ_RECEIPTS_ENABLED = "read_receipts_enabled";
|
||||
private static final String KEY_TYPING_INDICATORS_ENABLED = "typing_indicators_enabled";
|
||||
private static final String KEY_UNIDENTIFIED_DELIVERY_INDICATORS_ENABLED = "unidentified_delivery_indicators_enabled";
|
||||
private static final String KEY_LINK_PREVIEWS_ENABLED = "link_previews_enabled";
|
||||
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private boolean readReceiptsEnabled;
|
||||
private boolean typingIndicatorsEnabled;
|
||||
private boolean unidentifiedDeliveryIndicatorsEnabled;
|
||||
private boolean linkPreviewsEnabled;
|
||||
|
||||
public MultiDeviceConfigurationUpdateJob(@NonNull Context context, @NonNull WorkerParameters workerParameters) {
|
||||
super(context, workerParameters);
|
||||
}
|
||||
|
||||
public MultiDeviceConfigurationUpdateJob(Context context, boolean readReceiptsEnabled, boolean typingIndicatorsEnabled, boolean unidentifiedDeliveryIndicatorsEnabled) {
|
||||
public MultiDeviceConfigurationUpdateJob(Context context,
|
||||
boolean readReceiptsEnabled,
|
||||
boolean typingIndicatorsEnabled,
|
||||
boolean unidentifiedDeliveryIndicatorsEnabled,
|
||||
boolean linkPreviewsEnabled)
|
||||
{
|
||||
super(context, JobParameters.newBuilder()
|
||||
.withGroupId("__MULTI_DEVICE_CONFIGURATION_UPDATE_JOB__")
|
||||
.withNetworkRequirement()
|
||||
@@ -53,6 +60,7 @@ public class MultiDeviceConfigurationUpdateJob extends ContextJob implements Inj
|
||||
this.readReceiptsEnabled = readReceiptsEnabled;
|
||||
this.typingIndicatorsEnabled = typingIndicatorsEnabled;
|
||||
this.unidentifiedDeliveryIndicatorsEnabled = unidentifiedDeliveryIndicatorsEnabled;
|
||||
this.linkPreviewsEnabled = linkPreviewsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,6 +68,7 @@ public class MultiDeviceConfigurationUpdateJob extends ContextJob implements Inj
|
||||
readReceiptsEnabled = data.getBoolean(KEY_READ_RECEIPTS_ENABLED);
|
||||
typingIndicatorsEnabled = data.getBoolean(KEY_TYPING_INDICATORS_ENABLED);
|
||||
unidentifiedDeliveryIndicatorsEnabled = data.getBoolean(KEY_UNIDENTIFIED_DELIVERY_INDICATORS_ENABLED);
|
||||
linkPreviewsEnabled = data.getBoolean(KEY_LINK_PREVIEWS_ENABLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,6 +76,7 @@ public class MultiDeviceConfigurationUpdateJob extends ContextJob implements Inj
|
||||
return dataBuilder.putBoolean(KEY_READ_RECEIPTS_ENABLED, readReceiptsEnabled)
|
||||
.putBoolean(KEY_TYPING_INDICATORS_ENABLED, typingIndicatorsEnabled)
|
||||
.putBoolean(KEY_UNIDENTIFIED_DELIVERY_INDICATORS_ENABLED, unidentifiedDeliveryIndicatorsEnabled)
|
||||
.putBoolean(KEY_LINK_PREVIEWS_ENABLED, linkPreviewsEnabled)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -79,7 +89,8 @@ public class MultiDeviceConfigurationUpdateJob extends ContextJob implements Inj
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(readReceiptsEnabled),
|
||||
Optional.of(unidentifiedDeliveryIndicatorsEnabled),
|
||||
Optional.of(typingIndicatorsEnabled))),
|
||||
Optional.of(typingIndicatorsEnabled),
|
||||
Optional.of(linkPreviewsEnabled))),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ public class MultiDeviceReadReceiptUpdateJob extends ContextJob implements Injec
|
||||
return;
|
||||
}
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(enabled), Optional.absent(), Optional.absent())),
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(enabled), Optional.absent(), Optional.absent(), Optional.absent())),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,11 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.app.NotificationManagerCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.signal.libsignal.metadata.InvalidMetadataMessageException;
|
||||
import org.signal.libsignal.metadata.InvalidMetadataVersionException;
|
||||
import org.signal.libsignal.metadata.ProtocolDuplicateMessageException;
|
||||
@@ -53,6 +56,8 @@ import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.groups.GroupMessageProcessor;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
@@ -80,6 +85,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.crypto.SignalServiceCipher;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
|
||||
@@ -227,7 +233,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
|
||||
if (content.getDataMessage().isPresent()) {
|
||||
SignalServiceDataMessage message = content.getDataMessage().get();
|
||||
boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent();
|
||||
boolean isMediaMessage = message.getAttachments().isPresent() || message.getQuote().isPresent() || message.getSharedContacts().isPresent() || message.getPreviews().isPresent();
|
||||
|
||||
if (message.isEndSession()) handleEndSessionMessage(content, smsMessageId);
|
||||
else if (message.isGroupUpdate()) handleGroupMessage(content, message, smsMessageId);
|
||||
@@ -484,6 +490,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
message.getGroupInfo(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent(),
|
||||
Optional.absent());
|
||||
|
||||
database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||
@@ -518,7 +525,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
threadId = GroupMessageProcessor.process(context, content, message.getMessage(), true);
|
||||
} else if (message.getMessage().isExpirationUpdate()) {
|
||||
threadId = handleSynchronizeSentExpirationUpdate(message);
|
||||
} else if (message.getMessage().getAttachments().isPresent() || message.getMessage().getQuote().isPresent()) {
|
||||
} else if (message.getMessage().getAttachments().isPresent() || message.getMessage().getQuote().isPresent() || message.getMessage().getPreviews().isPresent()) {
|
||||
threadId = handleSynchronizeSentMediaMessage(message);
|
||||
} else {
|
||||
threadId = handleSynchronizeSentTextMessage(message);
|
||||
@@ -581,7 +588,8 @@ public class PushDecryptJob extends ContextJob {
|
||||
.add(new MultiDeviceConfigurationUpdateJob(getContext(),
|
||||
TextSecurePreferences.isReadReceiptsEnabled(getContext()),
|
||||
TextSecurePreferences.isTypingIndicatorsEnabled(getContext()),
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext())));
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()),
|
||||
TextSecurePreferences.isLinkPreviewsEnabled(getContext())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -617,18 +625,20 @@ public class PushDecryptJob extends ContextJob {
|
||||
notifyTypingStoppedFromIncomingMessage(getMessageDestination(content, message), content.getSender(), content.getSenderDevice());
|
||||
|
||||
try {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Optional<QuoteModel> quote = getValidatedQuote(message.getQuote());
|
||||
Optional<List<Contact>> sharedContacts = getContacts(message.getSharedContacts());
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
|
||||
message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, false,
|
||||
content.isNeedsReceipt(),
|
||||
message.getBody(),
|
||||
message.getGroupInfo(),
|
||||
message.getAttachments(),
|
||||
quote,
|
||||
sharedContacts);
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Optional<QuoteModel> quote = getValidatedQuote(message.getQuote());
|
||||
Optional<List<Contact>> sharedContacts = getContacts(message.getSharedContacts());
|
||||
Optional<List<LinkPreview>> linkPreviews = getLinkPreviews(message.getPreviews(), message.getBody().or(""));
|
||||
IncomingMediaMessage mediaMessage = new IncomingMediaMessage(Address.fromExternal(context, content.getSender()),
|
||||
message.getTimestamp(), -1,
|
||||
message.getExpiresInSeconds() * 1000L, false,
|
||||
content.isNeedsReceipt(),
|
||||
message.getBody(),
|
||||
message.getGroupInfo(),
|
||||
message.getAttachments(),
|
||||
quote,
|
||||
sharedContacts,
|
||||
linkPreviews);
|
||||
|
||||
Optional<InsertResult> insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||
|
||||
@@ -673,17 +683,19 @@ public class PushDecryptJob extends ContextJob {
|
||||
private long handleSynchronizeSentMediaMessage(@NonNull SentTranscriptMessage message)
|
||||
throws MmsException
|
||||
{
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipients = getSyncMessageDestination(message);
|
||||
Optional<QuoteModel> quote = getValidatedQuote(message.getMessage().getQuote());
|
||||
Optional<List<Contact>> sharedContacts = getContacts(message.getMessage().getSharedContacts());
|
||||
OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipients, message.getMessage().getBody().orNull(),
|
||||
PointerAttachment.forPointers(message.getMessage().getAttachments()),
|
||||
message.getTimestamp(), -1,
|
||||
message.getMessage().getExpiresInSeconds() * 1000,
|
||||
ThreadDatabase.DistributionTypes.DEFAULT, quote.orNull(),
|
||||
sharedContacts.or(Collections.emptyList()),
|
||||
Collections.emptyList(), Collections.emptyList());
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
Recipient recipients = getSyncMessageDestination(message);
|
||||
Optional<QuoteModel> quote = getValidatedQuote(message.getMessage().getQuote());
|
||||
Optional<List<Contact>> sharedContacts = getContacts(message.getMessage().getSharedContacts());
|
||||
Optional<List<LinkPreview>> previews = getLinkPreviews(message.getMessage().getPreviews(), message.getMessage().getBody().or(""));
|
||||
OutgoingMediaMessage mediaMessage = new OutgoingMediaMessage(recipients, message.getMessage().getBody().orNull(),
|
||||
PointerAttachment.forPointers(message.getMessage().getAttachments()),
|
||||
message.getTimestamp(), -1,
|
||||
message.getMessage().getExpiresInSeconds() * 1000,
|
||||
ThreadDatabase.DistributionTypes.DEFAULT, quote.orNull(),
|
||||
sharedContacts.or(Collections.emptyList()),
|
||||
previews.or(Collections.emptyList()),
|
||||
Collections.emptyList(), Collections.emptyList());
|
||||
|
||||
mediaMessage = new OutgoingSecureMediaMessage(mediaMessage);
|
||||
|
||||
@@ -784,7 +796,7 @@ public class PushDecryptJob extends ContextJob {
|
||||
long messageId;
|
||||
|
||||
if (isGroup) {
|
||||
OutgoingMediaMessage outgoingMediaMessage = new OutgoingMediaMessage(recipient, new SlideDeck(), body, message.getTimestamp(), -1, expiresInMillis, ThreadDatabase.DistributionTypes.DEFAULT, null, Collections.emptyList());
|
||||
OutgoingMediaMessage outgoingMediaMessage = new OutgoingMediaMessage(recipient, new SlideDeck(), body, message.getTimestamp(), -1, expiresInMillis, ThreadDatabase.DistributionTypes.DEFAULT, null, Collections.emptyList(), Collections.emptyList());
|
||||
outgoingMediaMessage = new OutgoingSecureMediaMessage(outgoingMediaMessage);
|
||||
|
||||
messageId = DatabaseFactory.getMmsDatabase(context).insertMessageOutbox(outgoingMediaMessage, threadId, false, null);
|
||||
@@ -1003,7 +1015,14 @@ public class PushDecryptJob extends ContextJob {
|
||||
List<Attachment> attachments = new LinkedList<>();
|
||||
|
||||
if (message.isMms()) {
|
||||
attachments = ((MmsMessageRecord) message).getSlideDeck().asAttachments();
|
||||
MmsMessageRecord mmsMessage = (MmsMessageRecord) message;
|
||||
attachments = mmsMessage.getSlideDeck().asAttachments();
|
||||
if (attachments.isEmpty()) {
|
||||
attachments.addAll(Stream.of(mmsMessage.getLinkPreviews())
|
||||
.filter(lp -> lp.getThumbnail().isPresent())
|
||||
.map(lp -> lp.getThumbnail().get())
|
||||
.toList());
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.of(new QuoteModel(quote.get().getId(), author, message.getBody(), false, attachments));
|
||||
@@ -1029,6 +1048,30 @@ public class PushDecryptJob extends ContextJob {
|
||||
return Optional.of(contacts);
|
||||
}
|
||||
|
||||
private Optional<List<LinkPreview>> getLinkPreviews(Optional<List<Preview>> previews, @NonNull String message) {
|
||||
if (!previews.isPresent()) return Optional.absent();
|
||||
|
||||
List<LinkPreview> linkPreviews = new ArrayList<>(previews.get().size());
|
||||
|
||||
for (Preview preview : previews.get()) {
|
||||
Optional<Attachment> thumbnail = PointerAttachment.forPointer(preview.getImage());
|
||||
Optional<String> url = Optional.fromNullable(preview.getUrl());
|
||||
Optional<String> title = Optional.fromNullable(preview.getTitle());
|
||||
boolean hasContent = !TextUtils.isEmpty(title.or("")) || thumbnail.isPresent();
|
||||
boolean presentInBody = url.isPresent() && LinkPreviewUtil.findWhitelistedUrls(message).contains(url.get());
|
||||
boolean validDomain = url.isPresent() && LinkPreviewUtil.isWhitelistedLinkUrl(url.get());
|
||||
|
||||
if (hasContent && presentInBody && validDomain) {
|
||||
LinkPreview linkPreview = new LinkPreview(url.get(), title.or(""), thumbnail);
|
||||
linkPreviews.add(linkPreview);
|
||||
} else {
|
||||
Log.w(TAG, String.format("Discarding an invalid link preview. hasContent: %b presentInBody: %b validDomain: %b", hasContent, presentInBody, validDomain));
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.of(linkPreviews);
|
||||
}
|
||||
|
||||
private Optional<InsertResult> insertPlaceholder(@NonNull String sender, int senderDevice, long timestamp) {
|
||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||
IncomingTextMessage textMessage = new IncomingTextMessage(Address.fromExternal(context, sender),
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Quote;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
|
||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||
@@ -50,6 +51,7 @@ import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupC
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -93,16 +95,15 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
@WorkerThread
|
||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId, @NonNull Address destination, @Nullable Address filterAddress) {
|
||||
try {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
|
||||
List<Attachment> attachments = new LinkedList<>();
|
||||
|
||||
if (message.isGroup()) {
|
||||
Log.i(TAG, "Group update message. Using legacy attachment upload path.");
|
||||
jobManager.add(new PushGroupSendJob(context, messageId, destination, filterAddress));
|
||||
return;
|
||||
}
|
||||
attachments.addAll(message.getAttachments());
|
||||
attachments.addAll(Stream.of(message.getLinkPreviews()).filter(p -> p.getThumbnail().isPresent()).map(p -> p.getThumbnail().get()).toList());
|
||||
attachments.addAll(Stream.of(message.getSharedContacts()).filter(c -> c.getAvatar() != null).map(c -> c.getAvatar().getAttachment()).withoutNulls().toList());
|
||||
|
||||
List<AttachmentUploadJob> attachmentJobs = Stream.of(message.getAttachments()).map(a -> new AttachmentUploadJob(context, ((DatabaseAttachment) a).getAttachmentId())).toList();
|
||||
List<AttachmentUploadJob> attachmentJobs = Stream.of(attachments).map(a -> new AttachmentUploadJob(context, ((DatabaseAttachment) a).getAttachmentId())).toList();
|
||||
ChainParameters chainParams = new ChainParameters.Builder().setGroupId(destination.serialize()).build();
|
||||
|
||||
if (attachmentJobs.isEmpty()) {
|
||||
@@ -237,7 +238,9 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
||||
Optional<Quote> quote = getQuoteFor(message);
|
||||
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
||||
List<Preview> previews = getPreviewsFor(message);
|
||||
List<SignalServiceAddress> addresses = Stream.of(destinations).map(this::getPushAddress).toList();
|
||||
List<SignalServiceAttachment> attachmentPointers = getAttachmentPointersFor(message.getAttachments());
|
||||
|
||||
List<Optional<UnidentifiedAccessPair>> unidentifiedAccess = Stream.of(addresses)
|
||||
.map(address -> Address.fromSerialized(address.getNumber()))
|
||||
@@ -246,13 +249,9 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
.toList();
|
||||
|
||||
if (message.isGroup()) {
|
||||
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
|
||||
List<Attachment> scaledAttachments = scaleAndStripExifFromAttachments(mediaConstraints, message.getAttachments());
|
||||
List<SignalServiceAttachment> attachmentStreams = getAttachmentsFor(scaledAttachments);
|
||||
|
||||
OutgoingGroupMediaMessage groupMessage = (OutgoingGroupMediaMessage) message;
|
||||
GroupContext groupContext = groupMessage.getGroupContext();
|
||||
SignalServiceAttachment avatar = attachmentStreams.isEmpty() ? null : attachmentStreams.get(0);
|
||||
SignalServiceAttachment avatar = attachmentPointers.isEmpty() ? null : attachmentPointers.get(0);
|
||||
SignalServiceGroup.Type type = groupMessage.isGroupQuit() ? SignalServiceGroup.Type.QUIT : SignalServiceGroup.Type.UPDATE;
|
||||
SignalServiceGroup group = new SignalServiceGroup(type, GroupUtil.getDecodedId(groupId), groupContext.getName(), groupContext.getMembersList(), avatar);
|
||||
SignalServiceDataMessage groupDataMessage = SignalServiceDataMessage.newBuilder()
|
||||
@@ -263,8 +262,6 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
|
||||
return messageSender.sendMessage(addresses, unidentifiedAccess, groupDataMessage);
|
||||
} else {
|
||||
List<SignalServiceAttachment> attachmentPointers = getAttachmentPointersFor(message.getAttachments());
|
||||
|
||||
SignalServiceGroup group = new SignalServiceGroup(GroupUtil.getDecodedId(groupId));
|
||||
SignalServiceDataMessage groupMessage = SignalServiceDataMessage.newBuilder()
|
||||
.withTimestamp(message.getSentTimeMillis())
|
||||
@@ -276,6 +273,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
||||
.withProfileKey(profileKey.orNull())
|
||||
.withQuote(quote.orNull())
|
||||
.withSharedContacts(sharedContacts)
|
||||
.withPreviews(previews)
|
||||
.build();
|
||||
|
||||
return messageSender.sendMessage(addresses, unidentifiedAccess, groupMessage);
|
||||
|
||||
@@ -7,9 +7,11 @@ import android.support.annotation.WorkerThread;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||
@@ -18,6 +20,7 @@ import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.ChainParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
@@ -32,12 +35,14 @@ import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview;
|
||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -69,9 +74,15 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
@WorkerThread
|
||||
public static void enqueue(@NonNull Context context, @NonNull JobManager jobManager, long messageId, @NonNull Address destination) {
|
||||
try {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
|
||||
List<AttachmentUploadJob> attachmentJobs = Stream.of(message.getAttachments()).map(a -> new AttachmentUploadJob(context, ((DatabaseAttachment) a).getAttachmentId())).toList();
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
OutgoingMediaMessage message = database.getOutgoingMessage(messageId);
|
||||
List<Attachment> attachments = new LinkedList<>();
|
||||
|
||||
attachments.addAll(message.getAttachments());
|
||||
attachments.addAll(Stream.of(message.getLinkPreviews()).filter(p -> p.getThumbnail().isPresent()).map(p -> p.getThumbnail().get()).toList());
|
||||
attachments.addAll(Stream.of(message.getSharedContacts()).filter(c -> c.getAvatar() != null).map(c -> c.getAvatar().getAttachment()).withoutNulls().toList());
|
||||
|
||||
List<AttachmentUploadJob> attachmentJobs = Stream.of(attachments).map(a -> new AttachmentUploadJob(context, ((DatabaseAttachment) a).getAttachmentId())).toList();
|
||||
ChainParameters chainParams = new ChainParameters.Builder().setGroupId(destination.serialize()).build();
|
||||
|
||||
if (attachmentJobs.isEmpty()) {
|
||||
@@ -191,6 +202,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
||||
Optional<SignalServiceDataMessage.Quote> quote = getQuoteFor(message);
|
||||
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
||||
List<Preview> previews = getPreviewsFor(message);
|
||||
SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder()
|
||||
.withBody(message.getBody())
|
||||
.withAttachments(serviceAttachments)
|
||||
@@ -199,6 +211,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
||||
.withProfileKey(profileKey.orNull())
|
||||
.withQuote(quote.orNull())
|
||||
.withSharedContacts(sharedContacts)
|
||||
.withPreviews(previews)
|
||||
.asExpirationUpdate(message.isExpirationUpdate())
|
||||
.build();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.events.PartProgressEvent;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
@@ -36,6 +37,7 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage.Preview;
|
||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
@@ -54,7 +56,7 @@ public abstract class PushSendJob extends SendJob {
|
||||
private static final String TAG = PushSendJob.class.getSimpleName();
|
||||
private static final long CERTIFICATE_EXPIRATION_BUFFER = TimeUnit.DAYS.toMillis(1);
|
||||
|
||||
protected PushSendJob(@NonNull Context context, @NonNull WorkerParameters workerParameters) {
|
||||
public PushSendJob(@NonNull Context context, @NonNull WorkerParameters workerParameters) {
|
||||
super(context, workerParameters);
|
||||
}
|
||||
|
||||
@@ -247,6 +249,13 @@ public abstract class PushSendJob extends SendJob {
|
||||
return sharedContacts;
|
||||
}
|
||||
|
||||
List<Preview> getPreviewsFor(OutgoingMediaMessage mediaMessage) {
|
||||
return Stream.of(mediaMessage.getLinkPreviews()).map(lp -> {
|
||||
SignalServiceAttachment attachment = lp.getThumbnail().isPresent() ? getAttachmentPointerFor(lp.getThumbnail().get()) : null;
|
||||
return new Preview(lp.getUrl(), lp.getTitle(), Optional.fromNullable(attachment));
|
||||
}).toList();
|
||||
}
|
||||
|
||||
protected void rotateSenderCertificateIfNecessary() throws IOException {
|
||||
try {
|
||||
byte[] certificateBytes = TextSecurePreferences.getUnidentifiedAccessCertificate(context);
|
||||
|
||||
Reference in New Issue
Block a user