From 19d5ba5c0e5297ee4c7b824f42e6f9a6ba1fdd90 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Fri, 7 Dec 2018 18:31:39 -0800 Subject: [PATCH] Upload attachments in a separate job. --- build.gradle | 6 +- .../securesms/RegistrationActivity.java | 2 +- .../database/AttachmentDatabase.java | 15 ++ .../SignalCommunicationModule.java | 4 +- .../securesms/gcm/GcmBroadcastReceiver.java | 15 +- .../securesms/jobmanager/JobManager.java | 5 +- .../securesms/jobs/AttachmentUploadJob.java | 144 ++++++++++++++++++ .../securesms/jobs/PushContentReceiveJob.java | 32 +--- .../securesms/jobs/PushMediaSendJob.java | 65 +++++--- .../securesms/jobs/PushSendJob.java | 46 +++++- .../securesms/sms/MessageSender.java | 2 +- 11 files changed, 269 insertions(+), 67 deletions(-) create mode 100644 src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java diff --git a/build.gradle b/build.gradle index d9f28f25b5..e87729c9ba 100644 --- a/build.gradle +++ b/build.gradle @@ -82,7 +82,7 @@ dependencies { compile 'com.google.android.exoplayer:exoplayer-core:2.9.1' compile 'com.google.android.exoplayer:exoplayer-ui:2.9.1' - compile 'org.whispersystems:signal-service-android:2.12.2' + compile 'org.whispersystems:signal-service-android:2.12.3' compile 'org.whispersystems:webrtc-android:M69' compile "me.leolin:ShortcutBadger:1.1.16" @@ -177,7 +177,7 @@ dependencyVerification { 'com.google.android.gms:play-services-maps:45e8021e7ddac4a44a82a0e9698991389ded3023d35c58f38dbd86d54211ec0e', 'com.google.android.exoplayer:exoplayer-ui:7a942afcc402ff01e9bf48e8d3942850986710f06562d50a1408aaf04a683151', 'com.google.android.exoplayer:exoplayer-core:b6ab34abac36bc2bc6934b7a50008162feca2c0fde91aaf1e8c1c22f2c16e2c0', - 'org.whispersystems:signal-service-android:26639df2a9c31b6f31f82034091a4ea3002ca6b1088e7fe6d30428a8290dcf2a', + 'org.whispersystems:signal-service-android:b02896703fb826792056ad872b812107ec2e80ea18dbeb43b97327d82faa3947', 'org.whispersystems:webrtc-android:5493c92141ce884fc5ce8240d783232f4fe14bd17a8d0d7d1bd4944d0bd1682f', 'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774', 'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb', @@ -244,7 +244,7 @@ dependencyVerification { 'com.android.support:support-annotations:5d5b9414f02d3fa0ee7526b8d5ddae0da67c8ecc8c4d63ffa6cf91488a93b927', 'com.google.guava:listenablefuture:e4ad7607e5c0477c6f890ef26a49cb8d1bb4dffb650bab4502afee64644e3069', 'org.signal:signal-metadata-android:d9d798aab7ee7200373ecff8718baf8aaeb632c123604e8a41b7b4c0c97eeee1', - 'org.whispersystems:signal-service-java:a156f4025ce59abb1b48c089719323cd0e82d6ab4bdd345c408a5e44121499b1', + 'org.whispersystems:signal-service-java:81fcda4be6e0dfc1f3e990b8bf5d2731a2bb6798b67748981e2a0ceba33d5e7a', 'com.github.bumptech.glide:disklrucache:c1b1b6f5bbd01e2fcdc9d7f60913c8d338bdb65ed4a93bfa02b56f19daaade4b', 'com.github.bumptech.glide:annotations:bede99ef9f71517a4274bac18fd3e483e9f2b6108d7d6fe8f4949be4aa4d9512', 'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a', diff --git a/src/org/thoughtcrime/securesms/RegistrationActivity.java b/src/org/thoughtcrime/securesms/RegistrationActivity.java index 85d8395974..42da574a96 100644 --- a/src/org/thoughtcrime/securesms/RegistrationActivity.java +++ b/src/org/thoughtcrime/securesms/RegistrationActivity.java @@ -678,7 +678,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif @Override protected Void doInBackground(Void... voids) { try { - accountManager.requestVoiceVerificationCode(); + accountManager.requestVoiceVerificationCode(Locale.getDefault()); } catch (IOException e) { Log.w(TAG, e); } diff --git a/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java b/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java index 7fe79dc8f9..e5b6308918 100644 --- a/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java +++ b/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java @@ -358,6 +358,21 @@ public class AttachmentDatabase extends Database { thumbnailExecutor.submit(new ThumbnailFetchCallable(attachmentId)); } + public void updateAttachmentAfterUpload(@NonNull AttachmentId id, @NonNull Attachment attachment) { + SQLiteDatabase database = databaseHelper.getWritableDatabase(); + ContentValues values = new ContentValues(); + + values.put(TRANSFER_STATE, TRANSFER_PROGRESS_DONE); + values.put(CONTENT_LOCATION, attachment.getLocation()); + values.put(DIGEST, attachment.getDigest()); + values.put(CONTENT_DISPOSITION, attachment.getKey()); + values.put(NAME, attachment.getRelay()); + values.put(SIZE, attachment.getSize()); + values.put(FAST_PREFLIGHT_ID, attachment.getFastPreflightId()); + + database.update(TABLE_NAME, values, PART_ID_WHERE, id.toStrings()); + } + @NonNull Map insertAttachmentsForMessage(long mmsId, @NonNull List attachments, @NonNull List quoteAttachment) throws MmsException { diff --git a/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java b/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java index 4e8ce7f737..37d10f5524 100644 --- a/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java +++ b/src/org/thoughtcrime/securesms/dependencies/SignalCommunicationModule.java @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.dependencies; import android.content.Context; import org.thoughtcrime.securesms.gcm.GcmBroadcastReceiver; +import org.thoughtcrime.securesms.jobs.AttachmentUploadJob; import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob; import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob; import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob; @@ -95,7 +96,8 @@ import dagger.Provides; RotateProfileKeyJob.class, MultiDeviceConfigurationUpdateJob.class, RefreshUnidentifiedDeliveryAbilityJob.class, - TypingSendJob.class}) + TypingSendJob.class, + AttachmentUploadJob.class}) public class SignalCommunicationModule { private static final String TAG = SignalCommunicationModule.class.getSimpleName(); diff --git a/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java b/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java index 717ab6a768..e20d87ded1 100644 --- a/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java +++ b/src/org/thoughtcrime/securesms/gcm/GcmBroadcastReceiver.java @@ -56,19 +56,14 @@ public class GcmBroadcastReceiver extends WakefulBroadcastReceiver implements In return; } - String receiptData = intent.getStringExtra("receipt"); - - if (!TextUtils.isEmpty(receiptData)) handleReceivedMessage(context, receiptData); - else if (intent.hasExtra("notification")) handleReceivedNotification(context); + if (intent.hasExtra("notification")) { + handleReceivedNotification(context); + } else { + Log.w(TAG, "Received an unexpected intent."); + } } } - private void handleReceivedMessage(Context context, String data) { - ApplicationContext.getInstance(context) - .getJobManager() - .add(new PushContentReceiveJob(context, data)); - } - private void handleReceivedNotification(Context context) { if (!incrementActiveGcmCount()) { Log.i(TAG, "Skipping GCM processing -- there's already one enqueued."); diff --git a/src/org/thoughtcrime/securesms/jobmanager/JobManager.java b/src/org/thoughtcrime/securesms/jobmanager/JobManager.java index 20f962bfb4..fee7565647 100644 --- a/src/org/thoughtcrime/securesms/jobmanager/JobManager.java +++ b/src/org/thoughtcrime/securesms/jobmanager/JobManager.java @@ -70,7 +70,10 @@ public class JobManager { } List> jobListChain = chain.getJobListChain(); - List> requestListChain = Stream.of(jobListChain).map(jl -> Stream.of(jl).map(this::toWorkRequest).toList()).toList(); + List> requestListChain = Stream.of(jobListChain) + .filter(jobList -> !jobList.isEmpty()) + .map(jobList -> Stream.of(jobList).map(this::toWorkRequest).toList()) + .toList(); if (jobListChain.isEmpty()) { throw new IllegalStateException("Enqueued an empty chain."); diff --git a/src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java b/src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java new file mode 100644 index 0000000000..0247f7c226 --- /dev/null +++ b/src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java @@ -0,0 +1,144 @@ +package org.thoughtcrime.securesms.jobs; + +import android.content.Context; +import android.support.annotation.NonNull; + +import org.greenrobot.eventbus.EventBus; +import org.thoughtcrime.securesms.attachments.Attachment; +import org.thoughtcrime.securesms.attachments.AttachmentId; +import org.thoughtcrime.securesms.attachments.DatabaseAttachment; +import org.thoughtcrime.securesms.attachments.PointerAttachment; +import org.thoughtcrime.securesms.database.AttachmentDatabase; +import org.thoughtcrime.securesms.database.DatabaseFactory; +import org.thoughtcrime.securesms.dependencies.InjectableType; +import org.thoughtcrime.securesms.events.PartProgressEvent; +import org.thoughtcrime.securesms.jobmanager.JobParameters; +import org.thoughtcrime.securesms.jobmanager.SafeData; +import org.thoughtcrime.securesms.logging.Log; +import org.thoughtcrime.securesms.mms.MediaConstraints; +import org.thoughtcrime.securesms.mms.MediaStream; +import org.thoughtcrime.securesms.mms.MmsException; +import org.thoughtcrime.securesms.mms.PartAuthority; +import org.thoughtcrime.securesms.transport.UndeliverableMessageException; +import org.thoughtcrime.securesms.util.MediaUtil; +import org.whispersystems.libsignal.util.guava.Optional; +import org.whispersystems.signalservice.api.SignalServiceMessageSender; +import org.whispersystems.signalservice.api.messages.SignalServiceAttachment; +import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer; +import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; + +import androidx.work.Data; +import androidx.work.WorkerParameters; + +public class AttachmentUploadJob extends ContextJob implements InjectableType { + + private static final String TAG = AttachmentUploadJob.class.getSimpleName(); + + private static final String KEY_ROW_ID = "row_id"; + private static final String KEY_UNIQUE_ID = "unique_id"; + + private AttachmentId attachmentId; + @Inject SignalServiceMessageSender messageSender; + + protected AttachmentUploadJob(@NonNull Context context, @NonNull WorkerParameters workerParameters) { + super(context, workerParameters); + } + + protected AttachmentUploadJob(@NonNull Context context, AttachmentId attachmentId) { + super(context, new JobParameters.Builder() + .withNetworkRequirement() + .withRetryDuration(TimeUnit.DAYS.toMillis(1)) + .create()); + + this.attachmentId = attachmentId; + } + + @Override + protected void initialize(@NonNull SafeData data) { + this.attachmentId = new AttachmentId(data.getLong(KEY_ROW_ID), data.getLong(KEY_UNIQUE_ID)); + } + + @Override + protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { + return dataBuilder.putLong(KEY_ROW_ID, attachmentId.getRowId()) + .putLong(KEY_UNIQUE_ID, attachmentId.getUniqueId()) + .build(); + } + + @Override + public void onRun() throws Exception { + AttachmentDatabase database = DatabaseFactory.getAttachmentDatabase(context); + DatabaseAttachment databaseAttachment = database.getAttachment(attachmentId); + + if (databaseAttachment == null) { + throw new IllegalStateException("Cannot find the specified attachment."); + } + + MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints(); + Attachment scaledAttachment = scaleAndStripExif(database, mediaConstraints, databaseAttachment); + SignalServiceAttachment localAttachment = getAttachmentFor(scaledAttachment); + SignalServiceAttachmentPointer remoteAttachment = messageSender.uploadAttachment(localAttachment.asStream()); + Attachment attachment = PointerAttachment.forPointer(Optional.of(remoteAttachment)).get(); + + database.updateAttachmentAfterUpload(databaseAttachment.getAttachmentId(), attachment); + } + + @Override + protected void onCanceled() { } + + @Override + protected boolean onShouldRetry(Exception exception) { + return exception instanceof PushNetworkException; + } + + protected 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()); + return SignalServiceAttachment.newStreamBuilder() + .withStream(is) + .withContentType(attachment.getContentType()) + .withLength(attachment.getSize()) + .withFileName(attachment.getFileName()) + .withVoiceNote(attachment.isVoiceNote()) + .withWidth(attachment.getWidth()) + .withHeight(attachment.getHeight()) + .withCaption(attachment.getCaption()) + .withListener((total, progress) -> EventBus.getDefault().postSticky(new PartProgressEvent(attachment, total, progress))) + .build(); + } catch (IOException ioe) { + Log.w(TAG, "Couldn't open attachment", ioe); + } + return null; + } + + private Attachment scaleAndStripExif(@NonNull AttachmentDatabase attachmentDatabase, + @NonNull MediaConstraints constraints, + @NonNull Attachment attachment) + throws UndeliverableMessageException + { + try { + if (constraints.isSatisfied(context, attachment)) { + if (MediaUtil.isJpeg(attachment)) { + MediaStream stripped = constraints.getResizedMedia(context, attachment); + return attachmentDatabase.updateAttachmentData(attachment, stripped); + } else { + return attachment; + } + } else if (constraints.canResize(attachment)) { + MediaStream resized = constraints.getResizedMedia(context, attachment); + return attachmentDatabase.updateAttachmentData(attachment, resized); + } else { + throw new UndeliverableMessageException("Size constraints could not be met!"); + } + } catch (IOException | MmsException e) { + throw new UndeliverableMessageException(e); + } + } +} diff --git a/src/org/thoughtcrime/securesms/jobs/PushContentReceiveJob.java b/src/org/thoughtcrime/securesms/jobs/PushContentReceiveJob.java index 319c23fe1b..55b7afac4f 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushContentReceiveJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushContentReceiveJob.java @@ -19,11 +19,6 @@ import androidx.work.WorkerParameters; public class PushContentReceiveJob extends PushReceivedJob { private static final long serialVersionUID = 5685475456901715638L; - private static final String TAG = PushContentReceiveJob.class.getSimpleName(); - - private static final String KEY_DATA = "data"; - - private String data; public PushContentReceiveJob(@NonNull Context context, @NonNull WorkerParameters workerParameters) { super(context, workerParameters); @@ -31,40 +26,21 @@ public class PushContentReceiveJob extends PushReceivedJob { public PushContentReceiveJob(Context context) { super(context, JobParameters.newBuilder().create()); - this.data = null; - } - - public PushContentReceiveJob(Context context, String data) { - super(context, JobParameters.newBuilder().create()); - this.data = data; } @Override - protected void initialize(@NonNull SafeData data) { - this.data = data.getString(KEY_DATA); - } + protected void initialize(@NonNull SafeData data) { } @Override protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) { - return dataBuilder.putString(KEY_DATA, data).build(); + return dataBuilder.build(); } @Override - public void onRun() { - try { - String sessionKey = TextSecurePreferences.getSignalingKey(context); - SignalServiceEnvelope envelope = new SignalServiceEnvelope(data, sessionKey); - - processEnvelope(envelope); - } catch (IOException | InvalidVersionException e) { - Log.w(TAG, e); - } - } + public void onRun() { } @Override - public void onCanceled() { - - } + public void onCanceled() { } @Override public boolean onShouldRetry(Exception exception) { diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index b6dbda6c75..e264626b0d 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -2,9 +2,12 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; import android.support.annotation.NonNull; +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.DatabaseFactory; @@ -12,8 +15,10 @@ import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode; 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.mms.MediaConstraints; +import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.recipients.Recipient; @@ -61,6 +66,29 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { this.messageId = messageId; } + @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 attachmentJobs = Stream.of(message.getAttachments()).map(a -> new AttachmentUploadJob(context, ((DatabaseAttachment) a).getAttachmentId())).toList(); + ChainParameters chainParams = new ChainParameters.Builder().setGroupId(destination.serialize()).build(); + + if (attachmentJobs.isEmpty()) { + jobManager.add(new PushMediaSendJob(context, messageId, destination)); + } else { + jobManager.startChain(attachmentJobs) + .then(new PushMediaSendJob(context, messageId, destination)) + .enqueue(chainParams); + } + + } catch (NoSuchMessageException | MmsException e) { + Log.w(TAG, "Failed to enqueue message.", e); + DatabaseFactory.getMmsDatabase(context).markAsSentFailed(messageId); + notifyMediaMessageDeliveryFailed(context, messageId); + } + } + @Override protected void initialize(@NonNull SafeData data) { messageId = data.getLong(KEY_MESSAGE_ID); @@ -158,23 +186,21 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { try { rotateSenderCertificateIfNecessary(); - SignalServiceAddress address = getPushAddress(message.getRecipient().getAddress()); - MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints(); - List scaledAttachments = scaleAndStripExifFromAttachments(mediaConstraints, message.getAttachments()); - List attachmentStreams = getAttachmentsFor(scaledAttachments); - Optional profileKey = getProfileKey(message.getRecipient()); - Optional quote = getQuoteFor(message); - List sharedContacts = getSharedContactsFor(message); - SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder() - .withBody(message.getBody()) - .withAttachments(attachmentStreams) - .withTimestamp(message.getSentTimeMillis()) - .withExpiration((int)(message.getExpiresIn() / 1000)) - .withProfileKey(profileKey.orNull()) - .withQuote(quote.orNull()) - .withSharedContacts(sharedContacts) - .asExpirationUpdate(message.isExpirationUpdate()) - .build(); + SignalServiceAddress address = getPushAddress(message.getRecipient().getAddress()); + List serviceAttachments = getAttachmentPointersFor(message.getAttachments()); + Optional profileKey = getProfileKey(message.getRecipient()); + Optional quote = getQuoteFor(message); + List sharedContacts = getSharedContactsFor(message); + SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder() + .withBody(message.getBody()) + .withAttachments(serviceAttachments) + .withTimestamp(message.getSentTimeMillis()) + .withExpiration((int)(message.getExpiresIn() / 1000)) + .withProfileKey(profileKey.orNull()) + .withQuote(quote.orNull()) + .withSharedContacts(sharedContacts) + .asExpirationUpdate(message.isExpirationUpdate()) + .build(); return messageSender.sendMessage(address, UnidentifiedAccessUtil.getAccessFor(context, message.getRecipient()), mediaMessage).getSuccess().isUnidentified(); } catch (UnregisteredUserException e) { @@ -188,5 +214,4 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { throw new RetryLaterException(e); } } - } diff --git a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java index 9bc4b0a3f5..39ee53c4bf 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java @@ -2,6 +2,10 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import com.annimon.stream.Stream; import org.greenrobot.eventbus.EventBus; import org.signal.libsignal.metadata.certificate.InvalidCertificateException; @@ -22,12 +26,15 @@ import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.BitmapDecodingException; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.thoughtcrime.securesms.util.Util; 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.shared.SharedContact; import org.whispersystems.signalservice.api.push.SignalServiceAddress; @@ -37,7 +44,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.LinkedList; import java.util.List; -import java.util.UUID; import java.util.concurrent.TimeUnit; import androidx.work.WorkerParameters; @@ -136,7 +142,43 @@ public abstract class PushSendJob extends SendJob { return null; } - protected void notifyMediaMessageDeliveryFailed(Context context, long messageId) { + protected @Nullable List getAttachmentPointersFor(List attachments) { + return Stream.of(attachments).map(this::getAttachmentPointerFor).filter(a -> a != null).toList(); + } + + protected @Nullable SignalServiceAttachment getAttachmentPointerFor(Attachment attachment) { + if (TextUtils.isEmpty(attachment.getLocation())) { + Log.w(TAG, "empty content id"); + return null; + } + + if (TextUtils.isEmpty(attachment.getKey())) { + Log.w(TAG, "empty encrypted key"); + return null; + } + + try { + long id = Long.parseLong(attachment.getLocation()); + byte[] key = Base64.decode(attachment.getKey()); + + return new SignalServiceAttachmentPointer(id, + attachment.getContentType(), + key, + Optional.of(Util.toIntExact(attachment.getSize())), + Optional.absent(), + attachment.getWidth(), + attachment.getHeight(), + Optional.fromNullable(attachment.getDigest()), + Optional.fromNullable(attachment.getFileName()), + attachment.isVoiceNote(), + Optional.fromNullable(attachment.getCaption())); + } catch (IOException | ArithmeticException e) { + Log.w(TAG, e); + return null; + } + } + + protected static void notifyMediaMessageDeliveryFailed(Context context, long messageId) { long threadId = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId); Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId); diff --git a/src/org/thoughtcrime/securesms/sms/MessageSender.java b/src/org/thoughtcrime/securesms/sms/MessageSender.java index 349717481d..bf16b1121c 100644 --- a/src/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/src/org/thoughtcrime/securesms/sms/MessageSender.java @@ -199,7 +199,7 @@ public class MessageSender { private static void sendMediaPush(Context context, Recipient recipient, long messageId) { JobManager jobManager = ApplicationContext.getInstance(context).getJobManager(); - jobManager.add(new PushMediaSendJob(context, messageId, recipient.getAddress())); + PushMediaSendJob.enqueue(context, jobManager, messageId, recipient.getAddress()); } private static void sendGroupPush(Context context, Recipient recipient, long messageId, Address filterAddress) {