mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-22 07:57:30 +00:00
Upload attachments in a separate job.
This commit is contained in:
parent
96c641c2a0
commit
19d5ba5c0e
@ -82,7 +82,7 @@ dependencies {
|
|||||||
compile 'com.google.android.exoplayer:exoplayer-core:2.9.1'
|
compile 'com.google.android.exoplayer:exoplayer-core:2.9.1'
|
||||||
compile 'com.google.android.exoplayer:exoplayer-ui: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 'org.whispersystems:webrtc-android:M69'
|
||||||
|
|
||||||
compile "me.leolin:ShortcutBadger:1.1.16"
|
compile "me.leolin:ShortcutBadger:1.1.16"
|
||||||
@ -177,7 +177,7 @@ dependencyVerification {
|
|||||||
'com.google.android.gms:play-services-maps:45e8021e7ddac4a44a82a0e9698991389ded3023d35c58f38dbd86d54211ec0e',
|
'com.google.android.gms:play-services-maps:45e8021e7ddac4a44a82a0e9698991389ded3023d35c58f38dbd86d54211ec0e',
|
||||||
'com.google.android.exoplayer:exoplayer-ui:7a942afcc402ff01e9bf48e8d3942850986710f06562d50a1408aaf04a683151',
|
'com.google.android.exoplayer:exoplayer-ui:7a942afcc402ff01e9bf48e8d3942850986710f06562d50a1408aaf04a683151',
|
||||||
'com.google.android.exoplayer:exoplayer-core:b6ab34abac36bc2bc6934b7a50008162feca2c0fde91aaf1e8c1c22f2c16e2c0',
|
'com.google.android.exoplayer:exoplayer-core:b6ab34abac36bc2bc6934b7a50008162feca2c0fde91aaf1e8c1c22f2c16e2c0',
|
||||||
'org.whispersystems:signal-service-android:26639df2a9c31b6f31f82034091a4ea3002ca6b1088e7fe6d30428a8290dcf2a',
|
'org.whispersystems:signal-service-android:b02896703fb826792056ad872b812107ec2e80ea18dbeb43b97327d82faa3947',
|
||||||
'org.whispersystems:webrtc-android:5493c92141ce884fc5ce8240d783232f4fe14bd17a8d0d7d1bd4944d0bd1682f',
|
'org.whispersystems:webrtc-android:5493c92141ce884fc5ce8240d783232f4fe14bd17a8d0d7d1bd4944d0bd1682f',
|
||||||
'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774',
|
'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774',
|
||||||
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
||||||
@ -244,7 +244,7 @@ dependencyVerification {
|
|||||||
'com.android.support:support-annotations:5d5b9414f02d3fa0ee7526b8d5ddae0da67c8ecc8c4d63ffa6cf91488a93b927',
|
'com.android.support:support-annotations:5d5b9414f02d3fa0ee7526b8d5ddae0da67c8ecc8c4d63ffa6cf91488a93b927',
|
||||||
'com.google.guava:listenablefuture:e4ad7607e5c0477c6f890ef26a49cb8d1bb4dffb650bab4502afee64644e3069',
|
'com.google.guava:listenablefuture:e4ad7607e5c0477c6f890ef26a49cb8d1bb4dffb650bab4502afee64644e3069',
|
||||||
'org.signal:signal-metadata-android:d9d798aab7ee7200373ecff8718baf8aaeb632c123604e8a41b7b4c0c97eeee1',
|
'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:disklrucache:c1b1b6f5bbd01e2fcdc9d7f60913c8d338bdb65ed4a93bfa02b56f19daaade4b',
|
||||||
'com.github.bumptech.glide:annotations:bede99ef9f71517a4274bac18fd3e483e9f2b6108d7d6fe8f4949be4aa4d9512',
|
'com.github.bumptech.glide:annotations:bede99ef9f71517a4274bac18fd3e483e9f2b6108d7d6fe8f4949be4aa4d9512',
|
||||||
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
||||||
|
@ -678,7 +678,7 @@ public class RegistrationActivity extends BaseActionBarActivity implements Verif
|
|||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Void doInBackground(Void... voids) {
|
||||||
try {
|
try {
|
||||||
accountManager.requestVoiceVerificationCode();
|
accountManager.requestVoiceVerificationCode(Locale.getDefault());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
}
|
}
|
||||||
|
@ -358,6 +358,21 @@ public class AttachmentDatabase extends Database {
|
|||||||
thumbnailExecutor.submit(new ThumbnailFetchCallable(attachmentId));
|
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<Attachment, AttachmentId> insertAttachmentsForMessage(long mmsId, @NonNull List<Attachment> attachments, @NonNull List<Attachment> quoteAttachment)
|
@NonNull Map<Attachment, AttachmentId> insertAttachmentsForMessage(long mmsId, @NonNull List<Attachment> attachments, @NonNull List<Attachment> quoteAttachment)
|
||||||
throws MmsException
|
throws MmsException
|
||||||
{
|
{
|
||||||
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.dependencies;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.gcm.GcmBroadcastReceiver;
|
import org.thoughtcrime.securesms.gcm.GcmBroadcastReceiver;
|
||||||
|
import org.thoughtcrime.securesms.jobs.AttachmentUploadJob;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
|
||||||
import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob;
|
import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob;
|
||||||
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
|
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
|
||||||
@ -95,7 +96,8 @@ import dagger.Provides;
|
|||||||
RotateProfileKeyJob.class,
|
RotateProfileKeyJob.class,
|
||||||
MultiDeviceConfigurationUpdateJob.class,
|
MultiDeviceConfigurationUpdateJob.class,
|
||||||
RefreshUnidentifiedDeliveryAbilityJob.class,
|
RefreshUnidentifiedDeliveryAbilityJob.class,
|
||||||
TypingSendJob.class})
|
TypingSendJob.class,
|
||||||
|
AttachmentUploadJob.class})
|
||||||
public class SignalCommunicationModule {
|
public class SignalCommunicationModule {
|
||||||
|
|
||||||
private static final String TAG = SignalCommunicationModule.class.getSimpleName();
|
private static final String TAG = SignalCommunicationModule.class.getSimpleName();
|
||||||
|
@ -56,19 +56,14 @@ public class GcmBroadcastReceiver extends WakefulBroadcastReceiver implements In
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String receiptData = intent.getStringExtra("receipt");
|
if (intent.hasExtra("notification")) {
|
||||||
|
handleReceivedNotification(context);
|
||||||
if (!TextUtils.isEmpty(receiptData)) handleReceivedMessage(context, receiptData);
|
} else {
|
||||||
else if (intent.hasExtra("notification")) handleReceivedNotification(context);
|
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) {
|
private void handleReceivedNotification(Context context) {
|
||||||
if (!incrementActiveGcmCount()) {
|
if (!incrementActiveGcmCount()) {
|
||||||
Log.i(TAG, "Skipping GCM processing -- there's already one enqueued.");
|
Log.i(TAG, "Skipping GCM processing -- there's already one enqueued.");
|
||||||
|
@ -70,7 +70,10 @@ public class JobManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<List<Job>> jobListChain = chain.getJobListChain();
|
List<List<Job>> jobListChain = chain.getJobListChain();
|
||||||
List<List<OneTimeWorkRequest>> requestListChain = Stream.of(jobListChain).map(jl -> Stream.of(jl).map(this::toWorkRequest).toList()).toList();
|
List<List<OneTimeWorkRequest>> requestListChain = Stream.of(jobListChain)
|
||||||
|
.filter(jobList -> !jobList.isEmpty())
|
||||||
|
.map(jobList -> Stream.of(jobList).map(this::toWorkRequest).toList())
|
||||||
|
.toList();
|
||||||
|
|
||||||
if (jobListChain.isEmpty()) {
|
if (jobListChain.isEmpty()) {
|
||||||
throw new IllegalStateException("Enqueued an empty chain.");
|
throw new IllegalStateException("Enqueued an empty chain.");
|
||||||
|
144
src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java
Normal file
144
src/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.java
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -19,11 +19,6 @@ import androidx.work.WorkerParameters;
|
|||||||
public class PushContentReceiveJob extends PushReceivedJob {
|
public class PushContentReceiveJob extends PushReceivedJob {
|
||||||
|
|
||||||
private static final long serialVersionUID = 5685475456901715638L;
|
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) {
|
public PushContentReceiveJob(@NonNull Context context, @NonNull WorkerParameters workerParameters) {
|
||||||
super(context, workerParameters);
|
super(context, workerParameters);
|
||||||
@ -31,40 +26,21 @@ public class PushContentReceiveJob extends PushReceivedJob {
|
|||||||
|
|
||||||
public PushContentReceiveJob(Context context) {
|
public PushContentReceiveJob(Context context) {
|
||||||
super(context, JobParameters.newBuilder().create());
|
super(context, JobParameters.newBuilder().create());
|
||||||
this.data = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PushContentReceiveJob(Context context, String data) {
|
|
||||||
super(context, JobParameters.newBuilder().create());
|
|
||||||
this.data = data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initialize(@NonNull SafeData data) {
|
protected void initialize(@NonNull SafeData data) { }
|
||||||
this.data = data.getString(KEY_DATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) {
|
protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) {
|
||||||
return dataBuilder.putString(KEY_DATA, data).build();
|
return dataBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRun() {
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCanceled() {
|
public void onCanceled() { }
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onShouldRetry(Exception exception) {
|
public boolean onShouldRetry(Exception exception) {
|
||||||
|
@ -2,9 +2,12 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.WorkerThread;
|
||||||
|
|
||||||
|
import com.annimon.stream.Stream;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext;
|
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.crypto.UnidentifiedAccessUtil;
|
||||||
import org.thoughtcrime.securesms.database.Address;
|
import org.thoughtcrime.securesms.database.Address;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
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.NoSuchMessageException;
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
||||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
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.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.MmsException;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
@ -61,6 +66,29 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
this.messageId = messageId;
|
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<AttachmentUploadJob> 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
|
@Override
|
||||||
protected void initialize(@NonNull SafeData data) {
|
protected void initialize(@NonNull SafeData data) {
|
||||||
messageId = data.getLong(KEY_MESSAGE_ID);
|
messageId = data.getLong(KEY_MESSAGE_ID);
|
||||||
@ -158,23 +186,21 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
try {
|
try {
|
||||||
rotateSenderCertificateIfNecessary();
|
rotateSenderCertificateIfNecessary();
|
||||||
|
|
||||||
SignalServiceAddress address = getPushAddress(message.getRecipient().getAddress());
|
SignalServiceAddress address = getPushAddress(message.getRecipient().getAddress());
|
||||||
MediaConstraints mediaConstraints = MediaConstraints.getPushMediaConstraints();
|
List<SignalServiceAttachment> serviceAttachments = getAttachmentPointersFor(message.getAttachments());
|
||||||
List<Attachment> scaledAttachments = scaleAndStripExifFromAttachments(mediaConstraints, message.getAttachments());
|
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
||||||
List<SignalServiceAttachment> attachmentStreams = getAttachmentsFor(scaledAttachments);
|
Optional<SignalServiceDataMessage.Quote> quote = getQuoteFor(message);
|
||||||
Optional<byte[]> profileKey = getProfileKey(message.getRecipient());
|
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
||||||
Optional<SignalServiceDataMessage.Quote> quote = getQuoteFor(message);
|
SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder()
|
||||||
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
.withBody(message.getBody())
|
||||||
SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder()
|
.withAttachments(serviceAttachments)
|
||||||
.withBody(message.getBody())
|
.withTimestamp(message.getSentTimeMillis())
|
||||||
.withAttachments(attachmentStreams)
|
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||||
.withTimestamp(message.getSentTimeMillis())
|
.withProfileKey(profileKey.orNull())
|
||||||
.withExpiration((int)(message.getExpiresIn() / 1000))
|
.withQuote(quote.orNull())
|
||||||
.withProfileKey(profileKey.orNull())
|
.withSharedContacts(sharedContacts)
|
||||||
.withQuote(quote.orNull())
|
.asExpirationUpdate(message.isExpirationUpdate())
|
||||||
.withSharedContacts(sharedContacts)
|
.build();
|
||||||
.asExpirationUpdate(message.isExpirationUpdate())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
return messageSender.sendMessage(address, UnidentifiedAccessUtil.getAccessFor(context, message.getRecipient()), mediaMessage).getSuccess().isUnidentified();
|
return messageSender.sendMessage(address, UnidentifiedAccessUtil.getAccessFor(context, message.getRecipient()), mediaMessage).getSuccess().isUnidentified();
|
||||||
} catch (UnregisteredUserException e) {
|
} catch (UnregisteredUserException e) {
|
||||||
@ -188,5 +214,4 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||||||
throw new RetryLaterException(e);
|
throw new RetryLaterException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,10 @@ package org.thoughtcrime.securesms.jobs;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
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.greenrobot.eventbus.EventBus;
|
||||||
import org.signal.libsignal.metadata.certificate.InvalidCertificateException;
|
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.mms.PartAuthority;
|
||||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
import org.thoughtcrime.securesms.util.BitmapDecodingException;
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
|
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;
|
||||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
@ -37,7 +44,6 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import androidx.work.WorkerParameters;
|
import androidx.work.WorkerParameters;
|
||||||
@ -136,7 +142,43 @@ public abstract class PushSendJob extends SendJob {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void notifyMediaMessageDeliveryFailed(Context context, long messageId) {
|
protected @Nullable List<SignalServiceAttachment> getAttachmentPointersFor(List<Attachment> 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);
|
long threadId = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId);
|
||||||
Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
|
Recipient recipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ public class MessageSender {
|
|||||||
|
|
||||||
private static void sendMediaPush(Context context, Recipient recipient, long messageId) {
|
private static void sendMediaPush(Context context, Recipient recipient, long messageId) {
|
||||||
JobManager jobManager = ApplicationContext.getInstance(context).getJobManager();
|
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) {
|
private static void sendGroupPush(Context context, Recipient recipient, long messageId, Address filterAddress) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user