Added support for link previews.

This commit is contained in:
Greyson Parrelli
2019-01-15 00:41:05 -08:00
parent bef9beff16
commit c76081d99c
88 changed files with 2687 additions and 678 deletions

View File

@@ -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());

View File

@@ -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));
}

View File

@@ -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));
}

View File

@@ -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),

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);