mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 11:49:04 +01:00
Compare commits
4 Commits
debugging-
...
attachment
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6b15fe657 | ||
|
|
f3bbc7179e | ||
|
|
9abe32ab4b | ||
|
|
d07b98eae1 |
@@ -54,8 +54,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testSmallJpegImage() throws Exception {
|
public void testSmallJpegImage() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
||||||
InputStream is = getUrlInputStream(smallKitten);
|
InputStream is = getUrlInputStream(smallKitten);
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(msgId, item.getMessageId());
|
assertEquals(msgId, item.getMessageId());
|
||||||
assertEquals(160, item.getWidth());
|
assertEquals(160, item.getWidth());
|
||||||
assertEquals(240, item.getHeight());
|
assertEquals(240, item.getHeight());
|
||||||
@@ -70,8 +70,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testBigJpegImage() throws Exception {
|
public void testBigJpegImage() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
||||||
InputStream is = getUrlInputStream(originalKitten);
|
InputStream is = getUrlInputStream(originalKitten);
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(msgId, item.getMessageId());
|
assertEquals(msgId, item.getMessageId());
|
||||||
assertEquals(1728, item.getWidth());
|
assertEquals(1728, item.getWidth());
|
||||||
assertEquals(2592, item.getHeight());
|
assertEquals(2592, item.getHeight());
|
||||||
@@ -86,8 +86,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testSmallPngImage() throws Exception {
|
public void testSmallPngImage() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/png");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/png");
|
||||||
InputStream is = getUrlInputStream(pngKitten);
|
InputStream is = getUrlInputStream(pngKitten);
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(msgId, item.getMessageId());
|
assertEquals(msgId, item.getMessageId());
|
||||||
assertEquals(737, item.getWidth());
|
assertEquals(737, item.getWidth());
|
||||||
assertEquals(510, item.getHeight());
|
assertEquals(510, item.getHeight());
|
||||||
@@ -102,8 +102,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testUberGif() throws Exception {
|
public void testUberGif() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
||||||
InputStream is = getUrlInputStream(uberGif);
|
InputStream is = getUrlInputStream(uberGif);
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(1, item.getWidth());
|
assertEquals(1, item.getWidth());
|
||||||
assertEquals(1, item.getHeight());
|
assertEquals(1, item.getHeight());
|
||||||
assertEquals(dimensions.minHeight, item.getThumbnailWidth());
|
assertEquals(dimensions.minHeight, item.getThumbnailWidth());
|
||||||
@@ -117,8 +117,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testLottaPixels() throws Exception {
|
public void testLottaPixels() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
||||||
InputStream is = getUrlInputStream(lottaPixel);
|
InputStream is = getUrlInputStream(lottaPixel);
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(64250, item.getWidth());
|
assertEquals(64250, item.getWidth());
|
||||||
assertEquals(64250, item.getHeight());
|
assertEquals(64250, item.getHeight());
|
||||||
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
||||||
@@ -132,8 +132,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testImageIoCrash() throws Exception {
|
public void testImageIoCrash() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
||||||
InputStream is = getUrlInputStream(imageIoCrash);
|
InputStream is = getUrlInputStream(imageIoCrash);
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(1184, item.getWidth());
|
assertEquals(1184, item.getWidth());
|
||||||
assertEquals(448, item.getHeight());
|
assertEquals(448, item.getHeight());
|
||||||
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
||||||
@@ -147,8 +147,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testGimpCrash() throws Exception {
|
public void testGimpCrash() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
||||||
InputStream is = getUrlInputStream(gimpCrash);
|
InputStream is = getUrlInputStream(gimpCrash);
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(1, item.getWidth());
|
assertEquals(1, item.getWidth());
|
||||||
assertEquals(1, item.getHeight());
|
assertEquals(1, item.getHeight());
|
||||||
assertEquals(dimensions.minHeight, item.getThumbnailWidth());
|
assertEquals(dimensions.minHeight, item.getThumbnailWidth());
|
||||||
@@ -162,8 +162,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testOptiPngAfl() throws Exception {
|
public void testOptiPngAfl() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
||||||
InputStream is = getUrlInputStream(optiPngAfl);
|
InputStream is = getUrlInputStream(optiPngAfl);
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(32, item.getWidth());
|
assertEquals(32, item.getWidth());
|
||||||
assertEquals(32, item.getHeight());
|
assertEquals(32, item.getHeight());
|
||||||
assertEquals(dimensions.minHeight, item.getThumbnailWidth());
|
assertEquals(dimensions.minHeight, item.getThumbnailWidth());
|
||||||
@@ -177,8 +177,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testLibrawError() throws Exception {
|
public void testLibrawError() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
||||||
InputStream is = getUrlInputStream(librawError);
|
InputStream is = getUrlInputStream(librawError);
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertTrue(item.hasError());
|
assertTrue(item.hasError());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,8 +186,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testSmallAnimatedGifMaxDimensions() throws Exception {
|
public void testSmallAnimatedGifMaxDimensions() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/gif");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/gif");
|
||||||
InputStream is = getAssetInputStream("animated.gif");
|
InputStream is = getAssetInputStream("animated.gif");
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(65535, item.getWidth());
|
assertEquals(65535, item.getWidth());
|
||||||
assertEquals(65535, item.getHeight());
|
assertEquals(65535, item.getHeight());
|
||||||
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
||||||
@@ -201,8 +201,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testSmallAnimatedGifHugeDimensions() throws Exception {
|
public void testSmallAnimatedGifHugeDimensions() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/gif");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/gif");
|
||||||
InputStream is = getAssetInputStream("animated2.gif");
|
InputStream is = getAssetInputStream("animated2.gif");
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(10000, item.getWidth());
|
assertEquals(10000, item.getWidth());
|
||||||
assertEquals(10000, item.getHeight());
|
assertEquals(10000, item.getHeight());
|
||||||
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
||||||
@@ -216,8 +216,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testSmallGifLargeDimensions() throws Exception {
|
public void testSmallGifLargeDimensions() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/gif");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/gif");
|
||||||
InputStream is = getAssetInputStream("error_large.gif");
|
InputStream is = getAssetInputStream("error_large.gif");
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(16384, item.getWidth());
|
assertEquals(16384, item.getWidth());
|
||||||
assertEquals(16384, item.getHeight());
|
assertEquals(16384, item.getHeight());
|
||||||
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
||||||
@@ -231,8 +231,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testHighError() throws Exception {
|
public void testHighError() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
||||||
InputStream is = getAssetInputStream("error_high.jpg");
|
InputStream is = getAssetInputStream("error_high.jpg");
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(1, item.getWidth());
|
assertEquals(1, item.getWidth());
|
||||||
assertEquals(10000, item.getHeight());
|
assertEquals(10000, item.getHeight());
|
||||||
assertEquals(dimensions.minWidth, item.getThumbnailWidth());
|
assertEquals(dimensions.minWidth, item.getThumbnailWidth());
|
||||||
@@ -246,8 +246,8 @@ public class AttachmentRetrieverIntegrationTest {
|
|||||||
public void testWideError() throws Exception {
|
public void testWideError() throws Exception {
|
||||||
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
AttachmentHeader h = new AttachmentHeader(msgId, "image/jpeg");
|
||||||
InputStream is = getAssetInputStream("error_wide.jpg");
|
InputStream is = getAssetInputStream("error_wide.jpg");
|
||||||
Attachment a = new Attachment(h, is);
|
Attachment a = new Attachment(is);
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, true);
|
AttachmentItem item = retriever.getAttachmentItem(h, a, true);
|
||||||
assertEquals(1920, item.getWidth());
|
assertEquals(1920, item.getWidth());
|
||||||
assertEquals(1, item.getHeight());
|
assertEquals(1, item.getHeight());
|
||||||
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
||||||
|
|||||||
@@ -1,22 +1,33 @@
|
|||||||
package org.briarproject.briar.android.attachment;
|
package org.briarproject.briar.android.attachment;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.MutableLiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
|
import org.briarproject.briar.api.messaging.Attachment;
|
||||||
import org.briarproject.briar.api.messaging.AttachmentHeader;
|
import org.briarproject.briar.api.messaging.AttachmentHeader;
|
||||||
import org.briarproject.briar.api.messaging.MessagingManager;
|
import org.briarproject.briar.api.messaging.MessagingManager;
|
||||||
import org.jsoup.UnsupportedMimeTypeException;
|
import org.jsoup.UnsupportedMimeTypeException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.concurrent.ThreadSafe;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
||||||
@@ -25,64 +36,97 @@ import static org.briarproject.bramble.util.LogUtils.logException;
|
|||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
import static org.briarproject.briar.api.messaging.MessagingConstants.IMAGE_MIME_TYPES;
|
import static org.briarproject.briar.api.messaging.MessagingConstants.IMAGE_MIME_TYPES;
|
||||||
|
|
||||||
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class AttachmentCreationTask {
|
class AttachmentCreationTask {
|
||||||
|
|
||||||
private static Logger LOG =
|
private static Logger LOG =
|
||||||
getLogger(AttachmentCreationTask.class.getName());
|
getLogger(AttachmentCreationTask.class.getName());
|
||||||
|
|
||||||
|
private final Executor ioExecutor;
|
||||||
private final MessagingManager messagingManager;
|
private final MessagingManager messagingManager;
|
||||||
private final ContentResolver contentResolver;
|
private final ContentResolver contentResolver;
|
||||||
|
private final AttachmentRetriever retriever;
|
||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
private final Collection<Uri> uris;
|
private final Collection<Uri> uris;
|
||||||
private final boolean needsSize;
|
private final boolean needsSize;
|
||||||
@Nullable
|
private final MutableLiveData<AttachmentResult> result;
|
||||||
private volatile AttachmentCreator attachmentCreator;
|
|
||||||
|
|
||||||
private volatile boolean canceled = false;
|
private volatile boolean canceled = false;
|
||||||
|
|
||||||
AttachmentCreationTask(MessagingManager messagingManager,
|
AttachmentCreationTask(Executor ioExecutor,
|
||||||
ContentResolver contentResolver,
|
MessagingManager messagingManager, ContentResolver contentResolver,
|
||||||
AttachmentCreator attachmentCreator, GroupId groupId,
|
AttachmentRetriever retriever, GroupId groupId,
|
||||||
Collection<Uri> uris, boolean needsSize) {
|
Collection<Uri> uris, boolean needsSize) {
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
this.messagingManager = messagingManager;
|
this.messagingManager = messagingManager;
|
||||||
this.contentResolver = contentResolver;
|
this.contentResolver = contentResolver;
|
||||||
|
this.retriever = retriever;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.uris = uris;
|
this.uris = uris;
|
||||||
this.needsSize = needsSize;
|
this.needsSize = needsSize;
|
||||||
this.attachmentCreator = attachmentCreator;
|
result = new MutableLiveData<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancel() {
|
LiveData<AttachmentResult> getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the task, asynchronously waits for it to finish, and deletes any
|
||||||
|
* created attachments.
|
||||||
|
*/
|
||||||
|
void cancel() {
|
||||||
canceled = true;
|
canceled = true;
|
||||||
attachmentCreator = null;
|
// Observe the task until it finishes (which may already have happened)
|
||||||
}
|
result.observeForever(new Observer<AttachmentResult>() {
|
||||||
|
@Override
|
||||||
@IoExecutor
|
public void onChanged(@Nullable AttachmentResult attachmentResult) {
|
||||||
public void storeAttachments() {
|
requireNonNull(attachmentResult);
|
||||||
for (Uri uri: uris) processUri(uri);
|
if (attachmentResult.isFinished()) {
|
||||||
AttachmentCreator attachmentCreator = this.attachmentCreator;
|
deleteUnsentAttachments(attachmentResult.getItemResults());
|
||||||
if (!canceled && attachmentCreator != null)
|
result.removeObserver(this);
|
||||||
attachmentCreator.onAttachmentCreationFinished();
|
}
|
||||||
this.attachmentCreator = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@IoExecutor
|
|
||||||
private void processUri(Uri uri) {
|
|
||||||
if (canceled) return;
|
|
||||||
try {
|
|
||||||
AttachmentHeader h = storeAttachment(uri);
|
|
||||||
AttachmentCreator attachmentCreator = this.attachmentCreator;
|
|
||||||
if (attachmentCreator != null) {
|
|
||||||
attachmentCreator.onAttachmentHeaderReceived(uri, h, needsSize);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously creates and stores the attachments.
|
||||||
|
*/
|
||||||
|
void storeAttachments() {
|
||||||
|
ioExecutor.execute(() -> {
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Storing " + uris.size() + " attachments");
|
||||||
|
List<AttachmentItemResult> results = new ArrayList<>();
|
||||||
|
for (Uri uri : uris) {
|
||||||
|
if (canceled) break;
|
||||||
|
results.add(processUri(uri));
|
||||||
|
result.postValue(new AttachmentResult(new ArrayList<>(results),
|
||||||
|
false, false));
|
||||||
|
}
|
||||||
|
result.postValue(new AttachmentResult(new ArrayList<>(results),
|
||||||
|
true, !canceled));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@IoExecutor
|
||||||
|
private AttachmentItemResult processUri(Uri uri) {
|
||||||
|
AttachmentHeader header = null;
|
||||||
|
try {
|
||||||
|
header = storeAttachment(uri);
|
||||||
|
Attachment a = retriever.getMessageAttachment(header);
|
||||||
|
AttachmentItem item =
|
||||||
|
retriever.getAttachmentItem(header, a, needsSize);
|
||||||
|
if (item.hasError()) throw new IOException();
|
||||||
|
if (needsSize) retriever.cachePut(item);
|
||||||
|
return new AttachmentItemResult(uri, item);
|
||||||
} catch (DbException | IOException e) {
|
} catch (DbException | IOException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
AttachmentCreator attachmentCreator = this.attachmentCreator;
|
// If the attachment was already stored, delete it
|
||||||
if (attachmentCreator != null) {
|
tryToRemove(header);
|
||||||
attachmentCreator.onAttachmentError(uri, e);
|
|
||||||
}
|
|
||||||
canceled = true;
|
canceled = true;
|
||||||
|
return new AttachmentItemResult(uri, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,4 +157,31 @@ class AttachmentCreationTask {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tryToRemove(@Nullable AttachmentHeader h) {
|
||||||
|
try {
|
||||||
|
if (h != null) messagingManager.removeAttachment(h);
|
||||||
|
} catch (DbException e1) {
|
||||||
|
logException(LOG, WARNING, e1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteUnsentAttachments(
|
||||||
|
Collection<AttachmentItemResult> itemResults) {
|
||||||
|
List<AttachmentHeader> headers = new ArrayList<>(itemResults.size());
|
||||||
|
for (AttachmentItemResult itemResult : itemResults) {
|
||||||
|
AttachmentItem item = itemResult.getItem();
|
||||||
|
if (item != null) headers.add(item.getHeader());
|
||||||
|
}
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Deleting " + headers.size() + " unsent attachments");
|
||||||
|
ioExecutor.execute(() -> {
|
||||||
|
for (AttachmentHeader header : headers) {
|
||||||
|
try {
|
||||||
|
messagingManager.removeAttachment(header);
|
||||||
|
} catch (DbException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,33 @@
|
|||||||
package org.briarproject.briar.android.attachment;
|
package org.briarproject.briar.android.attachment;
|
||||||
|
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.arch.lifecycle.LiveData;
|
import android.arch.lifecycle.LiveData;
|
||||||
import android.arch.lifecycle.MutableLiveData;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.UiThread;
|
import android.support.annotation.UiThread;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
|
||||||
import org.briarproject.briar.R;
|
|
||||||
import org.briarproject.briar.api.messaging.Attachment;
|
|
||||||
import org.briarproject.briar.api.messaging.AttachmentHeader;
|
import org.briarproject.briar.api.messaging.AttachmentHeader;
|
||||||
import org.briarproject.briar.api.messaging.FileTooBigException;
|
|
||||||
import org.briarproject.briar.api.messaging.MessagingManager;
|
import org.briarproject.briar.api.messaging.MessagingManager;
|
||||||
import org.jsoup.UnsupportedMimeTypeException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.logging.Logger.getLogger;
|
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
|
||||||
import static org.briarproject.briar.android.util.UiUtils.observeForeverOnce;
|
|
||||||
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_IMAGE_SIZE;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class AttachmentCreator {
|
public class AttachmentCreator {
|
||||||
|
|
||||||
private static Logger LOG = getLogger(AttachmentCreator.class.getName());
|
|
||||||
|
|
||||||
private final Application app;
|
private final Application app;
|
||||||
@IoExecutor
|
@IoExecutor
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final MessagingManager messagingManager;
|
private final MessagingManager messagingManager;
|
||||||
private final AttachmentRetriever retriever;
|
private final AttachmentRetriever retriever;
|
||||||
|
|
||||||
private final CopyOnWriteArrayList<Uri> uris = new CopyOnWriteArrayList<>();
|
|
||||||
private final CopyOnWriteArrayList<AttachmentItemResult> itemResults =
|
|
||||||
new CopyOnWriteArrayList<>();
|
|
||||||
|
|
||||||
private final MutableLiveData<AttachmentResult> result =
|
|
||||||
new MutableLiveData<>();
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private AttachmentCreationTask task;
|
private AttachmentCreationTask task;
|
||||||
|
|
||||||
@@ -62,20 +39,19 @@ public class AttachmentCreator {
|
|||||||
this.retriever = retriever;
|
this.retriever = retriever;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a background task to create attachments from the given URIs and
|
||||||
|
* returns a LiveData to monitor the progress of the task.
|
||||||
|
*/
|
||||||
@UiThread
|
@UiThread
|
||||||
public LiveData<AttachmentResult> storeAttachments(
|
public LiveData<AttachmentResult> storeAttachments(GroupId groupId,
|
||||||
LiveData<GroupId> groupId, Collection<Uri> newUris) {
|
Collection<Uri> uris) {
|
||||||
if (task != null || !uris.isEmpty())
|
if (task != null) throw new IllegalStateException();
|
||||||
throw new IllegalStateException();
|
boolean needsSize = uris.size() == 1;
|
||||||
uris.addAll(newUris);
|
task = new AttachmentCreationTask(ioExecutor, messagingManager,
|
||||||
observeForeverOnce(groupId, id -> {
|
app.getContentResolver(), retriever, groupId, uris, needsSize);
|
||||||
if (id == null) throw new IllegalStateException();
|
task.storeAttachments();
|
||||||
boolean needsSize = uris.size() == 1;
|
return task.getResult();
|
||||||
task = new AttachmentCreationTask(messagingManager,
|
|
||||||
app.getContentResolver(), this, id, uris, needsSize);
|
|
||||||
ioExecutor.execute(() -> task.storeAttachments());
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,134 +61,49 @@ public class AttachmentCreator {
|
|||||||
*/
|
*/
|
||||||
@UiThread
|
@UiThread
|
||||||
public LiveData<AttachmentResult> getLiveAttachments() {
|
public LiveData<AttachmentResult> getLiveAttachments() {
|
||||||
if (task == null || uris.isEmpty())
|
if (task == null) throw new IllegalStateException();
|
||||||
throw new IllegalStateException();
|
|
||||||
// A task is already running. It will update the result LiveData.
|
// A task is already running. It will update the result LiveData.
|
||||||
// So nothing more to do here.
|
// So nothing more to do here.
|
||||||
return result;
|
return task.getResult();
|
||||||
}
|
|
||||||
|
|
||||||
@IoExecutor
|
|
||||||
void onAttachmentHeaderReceived(Uri uri, AttachmentHeader h,
|
|
||||||
boolean needsSize) {
|
|
||||||
// get and cache AttachmentItem for ImagePreview
|
|
||||||
try {
|
|
||||||
Attachment a = retriever.getMessageAttachment(h);
|
|
||||||
AttachmentItem item = retriever.getAttachmentItem(a, needsSize);
|
|
||||||
if (item.hasError()) throw new IOException();
|
|
||||||
AttachmentItemResult itemResult =
|
|
||||||
new AttachmentItemResult(uri, item);
|
|
||||||
itemResults.add(itemResult);
|
|
||||||
result.postValue(getResult(false));
|
|
||||||
} catch (IOException | DbException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
onAttachmentError(uri, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@IoExecutor
|
|
||||||
void onAttachmentError(Uri uri, Throwable t) {
|
|
||||||
// get error message
|
|
||||||
String errorMsg;
|
|
||||||
if (t instanceof UnsupportedMimeTypeException) {
|
|
||||||
String mimeType = ((UnsupportedMimeTypeException) t).getMimeType();
|
|
||||||
errorMsg = app.getString(
|
|
||||||
R.string.image_attach_error_invalid_mime_type, mimeType);
|
|
||||||
} else if (t instanceof FileTooBigException) {
|
|
||||||
int mb = MAX_IMAGE_SIZE / 1024 / 1024;
|
|
||||||
errorMsg = app.getString(R.string.image_attach_error_too_big, mb);
|
|
||||||
} else {
|
|
||||||
errorMsg = null; // generic error
|
|
||||||
}
|
|
||||||
AttachmentItemResult itemResult =
|
|
||||||
new AttachmentItemResult(uri, errorMsg);
|
|
||||||
itemResults.add(itemResult);
|
|
||||||
result.postValue(getResult(false));
|
|
||||||
// expect to receive a cancel from the UI
|
|
||||||
}
|
|
||||||
|
|
||||||
@IoExecutor
|
|
||||||
void onAttachmentCreationFinished() {
|
|
||||||
result.postValue(getResult(true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the headers of any attachments created by
|
||||||
|
* {@link #storeAttachments(GroupId, Collection)}, unless
|
||||||
|
* {@link #onAttachmentsSent()} or {@link #cancel()} has been called.
|
||||||
|
*/
|
||||||
@UiThread
|
@UiThread
|
||||||
public List<AttachmentHeader> getAttachmentHeadersForSending() {
|
public List<AttachmentHeader> getAttachmentHeadersForSending() {
|
||||||
List<AttachmentHeader> headers = new ArrayList<>(itemResults.size());
|
if (task == null) return emptyList();
|
||||||
for (AttachmentItemResult itemResult : itemResults) {
|
AttachmentResult result = task.getResult().getValue();
|
||||||
// check if we are trying to send attachment items with errors
|
if (result == null) return emptyList();
|
||||||
if (itemResult.getItem() == null) throw new IllegalStateException();
|
List<AttachmentHeader> headers = new ArrayList<>();
|
||||||
headers.add(itemResult.getItem().getHeader());
|
for (AttachmentItemResult itemResult : result.getItemResults()) {
|
||||||
|
AttachmentItem item = itemResult.getItem();
|
||||||
|
if (item != null) headers.add(item.getHeader());
|
||||||
}
|
}
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the attachments as sent and adds the items to the cache for display
|
* Informs the AttachmentCreator that the attachments created by
|
||||||
*
|
* {@link #storeAttachments(GroupId, Collection)} will be sent.
|
||||||
* @param id The MessageId of the sent message.
|
|
||||||
*/
|
*/
|
||||||
@UiThread
|
@UiThread
|
||||||
public void onAttachmentsSent(MessageId id) {
|
public void onAttachmentsSent() {
|
||||||
List<AttachmentItem> items = new ArrayList<>(itemResults.size());
|
task = null; // Prevent cancel() from cancelling the task
|
||||||
for (AttachmentItemResult itemResult : itemResults) {
|
|
||||||
// check if we are trying to send attachment items with errors
|
|
||||||
if (itemResult.getItem() == null) throw new IllegalStateException();
|
|
||||||
items.add(itemResult.getItem());
|
|
||||||
}
|
|
||||||
retriever.cachePut(id, items);
|
|
||||||
resetState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Needs to be called when created attachments will not be sent anymore.
|
* Cancels the task started by
|
||||||
|
* {@link #storeAttachments(GroupId, Collection)}, if any, unless
|
||||||
|
* {@link #onAttachmentsSent()} has been called.
|
||||||
*/
|
*/
|
||||||
@UiThread
|
@UiThread
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
if (task == null) throw new AssertionError();
|
if (task != null) {
|
||||||
task.cancel();
|
task.cancel();
|
||||||
deleteUnsentAttachments();
|
task = null;
|
||||||
resetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@UiThread
|
|
||||||
private void resetState() {
|
|
||||||
task = null;
|
|
||||||
uris.clear();
|
|
||||||
itemResults.clear();
|
|
||||||
result.setValue(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@UiThread
|
|
||||||
public void deleteUnsentAttachments() {
|
|
||||||
// Make a copy for the IoExecutor as we clear the itemResults soon
|
|
||||||
List<AttachmentHeader> headers = new ArrayList<>(itemResults.size());
|
|
||||||
for (AttachmentItemResult itemResult : itemResults) {
|
|
||||||
// check if we are trying to send attachment items with errors
|
|
||||||
if (itemResult.getItem() != null)
|
|
||||||
headers.add(itemResult.getItem().getHeader());
|
|
||||||
}
|
}
|
||||||
ioExecutor.execute(() -> {
|
|
||||||
for (AttachmentHeader header : headers) {
|
|
||||||
try {
|
|
||||||
messagingManager.removeAttachment(header);
|
|
||||||
} catch (DbException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private AttachmentResult getResult(boolean finished) {
|
|
||||||
// Make a copy of the list,
|
|
||||||
// because our copy will continue to change in the background.
|
|
||||||
// (As it's a CopyOnWriteArrayList,
|
|
||||||
// the code that receives the result can safely do simple things
|
|
||||||
// like iterating over the list,
|
|
||||||
// but anything that involves calling more than one list method
|
|
||||||
// is still unsafe.)
|
|
||||||
Collection<AttachmentItemResult> items = new ArrayList<>(itemResults);
|
|
||||||
return new AttachmentResult(items, finished);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public class AttachmentItem implements Parcelable {
|
|||||||
header = new AttachmentHeader(messageId, mimeType);
|
header = new AttachmentHeader(messageId, mimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AttachmentHeader getHeader() {
|
AttachmentHeader getHeader() {
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,18 +15,18 @@ public class AttachmentItemResult {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private final AttachmentItem item;
|
private final AttachmentItem item;
|
||||||
@Nullable
|
@Nullable
|
||||||
private final String errorMsg;
|
private final Exception exception;
|
||||||
|
|
||||||
AttachmentItemResult(Uri uri, AttachmentItem item) {
|
AttachmentItemResult(Uri uri, AttachmentItem item) {
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.item = item;
|
this.item = item;
|
||||||
this.errorMsg = null;
|
this.exception = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachmentItemResult(Uri uri, @Nullable String errorMsg) {
|
AttachmentItemResult(Uri uri, Exception exception) {
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.item = null;
|
this.item = null;
|
||||||
this.errorMsg = errorMsg;
|
this.exception = exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri getUri() {
|
public Uri getUri() {
|
||||||
@@ -43,8 +43,8 @@ public class AttachmentItemResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getErrorMsg() {
|
public Exception getException() {
|
||||||
return errorMsg;
|
return exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ public class AttachmentResult {
|
|||||||
|
|
||||||
private final Collection<AttachmentItemResult> itemResults;
|
private final Collection<AttachmentItemResult> itemResults;
|
||||||
private final boolean finished;
|
private final boolean finished;
|
||||||
|
private final boolean success;
|
||||||
|
|
||||||
public AttachmentResult(Collection<AttachmentItemResult> itemResults,
|
AttachmentResult(Collection<AttachmentItemResult> itemResults,
|
||||||
boolean finished) {
|
boolean finished, boolean success) {
|
||||||
this.itemResults = itemResults;
|
this.itemResults = itemResults;
|
||||||
this.finished = finished;
|
this.finished = finished;
|
||||||
|
this.success = success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<AttachmentItemResult> getItemResults() {
|
public Collection<AttachmentItemResult> getItemResults() {
|
||||||
@@ -27,4 +29,7 @@ public class AttachmentResult {
|
|||||||
return finished;
|
return finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import android.webkit.MimeTypeMap;
|
|||||||
|
|
||||||
import com.bumptech.glide.util.MarkEnforcingInputStream;
|
import com.bumptech.glide.util.MarkEnforcingInputStream;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Pair;
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
@@ -20,6 +22,7 @@ import org.briarproject.briar.api.messaging.MessagingManager;
|
|||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@@ -35,13 +38,16 @@ import static android.support.media.ExifInterface.TAG_ORIENTATION;
|
|||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
import static java.util.logging.Logger.getLogger;
|
||||||
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
import static org.briarproject.bramble.util.IoUtils.tryToClose;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class AttachmentRetriever {
|
public class AttachmentRetriever {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
getLogger(AttachmentRetriever.class.getName());
|
getLogger(AttachmentRetriever.class.getName());
|
||||||
|
|
||||||
private static final int READ_LIMIT = 1024 * 8192;
|
private static final int READ_LIMIT = 1024 * 8192;
|
||||||
|
|
||||||
private final MessagingManager messagingManager;
|
private final MessagingManager messagingManager;
|
||||||
@@ -50,7 +56,7 @@ public class AttachmentRetriever {
|
|||||||
private final int minWidth, maxWidth;
|
private final int minWidth, maxWidth;
|
||||||
private final int minHeight, maxHeight;
|
private final int minHeight, maxHeight;
|
||||||
|
|
||||||
private final Map<MessageId, List<AttachmentItem>> attachmentCache =
|
private final Map<MessageId, AttachmentItem> attachmentCache =
|
||||||
new ConcurrentHashMap<>();
|
new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -88,27 +94,56 @@ public class AttachmentRetriever {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cachePut(MessageId messageId,
|
public void cachePut(AttachmentItem item) {
|
||||||
List<AttachmentItem> attachments) {
|
attachmentCache.put(item.getMessageId(), item);
|
||||||
attachmentCache.put(messageId, attachments);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public List<AttachmentItem> cacheGet(MessageId messageId) {
|
public AttachmentItem cacheGet(MessageId attachmentId) {
|
||||||
return attachmentCache.get(messageId);
|
return attachmentCache.get(attachmentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Attachment getMessageAttachment(AttachmentHeader h)
|
@DatabaseExecutor
|
||||||
throws DbException {
|
public List<Pair<AttachmentHeader, Attachment>> getMessageAttachments(
|
||||||
return messagingManager.getAttachment(h);
|
List<AttachmentHeader> headers) throws DbException {
|
||||||
|
long start = now();
|
||||||
|
List<Pair<AttachmentHeader, Attachment>> attachments =
|
||||||
|
new ArrayList<>(headers.size());
|
||||||
|
for (AttachmentHeader h : headers) {
|
||||||
|
Attachment a = messagingManager.getAttachment(h.getMessageId());
|
||||||
|
attachments.add(new Pair<>(h, a));
|
||||||
|
}
|
||||||
|
logDuration(LOG, "Loading attachments", start);
|
||||||
|
return attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
Attachment getMessageAttachment(AttachmentHeader h) throws DbException {
|
||||||
|
return messagingManager.getAttachment(h.getMessageId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates {@link AttachmentItem}s from the passed headers and Attachments.
|
||||||
|
* <p>
|
||||||
|
* Note: This closes the {@link Attachment}'s {@link InputStream}.
|
||||||
|
*/
|
||||||
|
public List<AttachmentItem> getAttachmentItems(
|
||||||
|
List<Pair<AttachmentHeader, Attachment>> attachments) {
|
||||||
|
boolean needsSize = attachments.size() == 1;
|
||||||
|
List<AttachmentItem> items = new ArrayList<>(attachments.size());
|
||||||
|
for (Pair<AttachmentHeader, Attachment> a : attachments) {
|
||||||
|
AttachmentItem item =
|
||||||
|
getAttachmentItem(a.getFirst(), a.getSecond(), needsSize);
|
||||||
|
items.add(item);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an {@link AttachmentItem} from the {@link Attachment}'s
|
* Creates an {@link AttachmentItem} from the {@link Attachment}'s
|
||||||
* {@link InputStream} which will be closed when this method returns.
|
* {@link InputStream} which will be closed when this method returns.
|
||||||
*/
|
*/
|
||||||
public AttachmentItem getAttachmentItem(Attachment a, boolean needsSize) {
|
AttachmentItem getAttachmentItem(AttachmentHeader h, Attachment a,
|
||||||
AttachmentHeader h = a.getHeader();
|
boolean needsSize) {
|
||||||
if (!needsSize) {
|
if (!needsSize) {
|
||||||
String extension =
|
String extension =
|
||||||
imageHelper.getExtensionFromMimeType(h.getContentType());
|
imageHelper.getExtensionFromMimeType(h.getContentType());
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
|||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||||
import org.briarproject.bramble.api.db.NoSuchMessageException;
|
|
||||||
import org.briarproject.bramble.api.event.Event;
|
import org.briarproject.bramble.api.event.Event;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.event.EventListener;
|
import org.briarproject.bramble.api.event.EventListener;
|
||||||
@@ -82,7 +81,6 @@ import org.briarproject.briar.api.messaging.Attachment;
|
|||||||
import org.briarproject.briar.api.messaging.AttachmentHeader;
|
import org.briarproject.briar.api.messaging.AttachmentHeader;
|
||||||
import org.briarproject.briar.api.messaging.MessagingManager;
|
import org.briarproject.briar.api.messaging.MessagingManager;
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||||
import org.briarproject.briar.api.messaging.event.AttachmentReceivedEvent;
|
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -109,12 +107,10 @@ import static android.support.v7.util.SortedList.INVALID_POSITION;
|
|||||||
import static android.view.Gravity.RIGHT;
|
import static android.view.Gravity.RIGHT;
|
||||||
import static android.widget.Toast.LENGTH_SHORT;
|
import static android.widget.Toast.LENGTH_SHORT;
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.singletonList;
|
|
||||||
import static java.util.Collections.sort;
|
import static java.util.Collections.sort;
|
||||||
import static java.util.Objects.requireNonNull;
|
import static java.util.Objects.requireNonNull;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static java.util.logging.Logger.getLogger;
|
|
||||||
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
import static org.briarproject.bramble.util.LogUtils.logDuration;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
import static org.briarproject.bramble.util.LogUtils.now;
|
import static org.briarproject.bramble.util.LogUtils.now;
|
||||||
@@ -142,7 +138,7 @@ public class ConversationActivity extends BriarActivity
|
|||||||
public static final String CONTACT_ID = "briar.CONTACT_ID";
|
public static final String CONTACT_ID = "briar.CONTACT_ID";
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
getLogger(ConversationActivity.class.getName());
|
Logger.getLogger(ConversationActivity.class.getName());
|
||||||
|
|
||||||
private static final int TRANSITION_DURATION_MS = 500;
|
private static final int TRANSITION_DURATION_MS = 500;
|
||||||
private static final int ONBOARDING_DELAY_MS = 250;
|
private static final int ONBOARDING_DELAY_MS = 250;
|
||||||
@@ -175,8 +171,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
volatile GroupInvitationManager groupInvitationManager;
|
volatile GroupInvitationManager groupInvitationManager;
|
||||||
|
|
||||||
private final Map<MessageId, String> textCache = new ConcurrentHashMap<>();
|
private final Map<MessageId, String> textCache = new ConcurrentHashMap<>();
|
||||||
private final Map<MessageId, PrivateMessageHeader> missingAttachments =
|
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
private final Observer<String> contactNameObserver = name -> {
|
private final Observer<String> contactNameObserver = name -> {
|
||||||
requireNonNull(name);
|
requireNonNull(name);
|
||||||
loadMessages();
|
loadMessages();
|
||||||
@@ -440,40 +434,31 @@ public class ConversationActivity extends BriarActivity
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void eagerlyLoadMessageSize(PrivateMessageHeader h) {
|
private void eagerlyLoadMessageSize(PrivateMessageHeader h)
|
||||||
try {
|
throws DbException {
|
||||||
MessageId id = h.getId();
|
MessageId id = h.getId();
|
||||||
// If the message has text, load it
|
// If the message has text, load it
|
||||||
if (h.hasText()) {
|
if (h.hasText()) {
|
||||||
String text = textCache.get(id);
|
String text = textCache.get(id);
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
LOG.info("Eagerly loading text for latest message");
|
LOG.info("Eagerly loading text for latest message");
|
||||||
text = messagingManager.getMessageText(id);
|
text = messagingManager.getMessageText(id);
|
||||||
textCache.put(id, requireNonNull(text));
|
textCache.put(id, requireNonNull(text));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// If the message has a single image, load its size - for multiple
|
}
|
||||||
// images we use a grid so the size is fixed
|
// If the message has a single image, load its size - for multiple
|
||||||
List<AttachmentHeader> headers = h.getAttachmentHeaders();
|
// images we use a grid so the size is fixed
|
||||||
if (headers.size() == 1) {
|
List<AttachmentHeader> headers = h.getAttachmentHeaders();
|
||||||
List<AttachmentItem> items = attachmentRetriever.cacheGet(id);
|
if (headers.size() == 1) {
|
||||||
if (items == null) {
|
MessageId attachmentId = headers.get(0).getMessageId();
|
||||||
LOG.info("Eagerly loading image size for latest message");
|
AttachmentItem item = attachmentRetriever.cacheGet(attachmentId);
|
||||||
AttachmentHeader header = headers.get(0);
|
if (item == null) {
|
||||||
try {
|
LOG.info("Eagerly loading image size for latest message");
|
||||||
Attachment a = attachmentRetriever
|
item = attachmentRetriever.getAttachmentItems(
|
||||||
.getMessageAttachment(header);
|
attachmentRetriever.getMessageAttachments(headers))
|
||||||
AttachmentItem item =
|
.get(0);
|
||||||
attachmentRetriever.getAttachmentItem(a, true);
|
attachmentRetriever.cachePut(item);
|
||||||
attachmentRetriever.cachePut(id, singletonList(item));
|
|
||||||
} catch (NoSuchMessageException e) {
|
|
||||||
LOG.info("Attachment not received yet");
|
|
||||||
missingAttachments.put(header.getMessageId(), h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (DbException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,30 +536,18 @@ public class ConversationActivity extends BriarActivity
|
|||||||
&& adapter.isScrolledToBottom(layoutManager);
|
&& adapter.isScrolledToBottom(layoutManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadMessageAttachments(PrivateMessageHeader h) {
|
private void loadMessageAttachments(MessageId messageId,
|
||||||
// TODO: Use placeholders for missing/invalid attachments
|
List<AttachmentHeader> headers) {
|
||||||
runOnDbThread(() -> {
|
runOnDbThread(() -> {
|
||||||
try {
|
try {
|
||||||
|
List<Pair<AttachmentHeader, Attachment>> attachments =
|
||||||
|
attachmentRetriever.getMessageAttachments(headers);
|
||||||
// TODO move getting the items off to IoExecutor, if size == 1
|
// TODO move getting the items off to IoExecutor, if size == 1
|
||||||
List<AttachmentHeader> headers = h.getAttachmentHeaders();
|
List<AttachmentItem> items =
|
||||||
boolean needsSize = headers.size() == 1;
|
attachmentRetriever.getAttachmentItems(attachments);
|
||||||
List<AttachmentItem> items = new ArrayList<>(headers.size());
|
if (items.size() == 1)
|
||||||
for (AttachmentHeader header : headers) {
|
attachmentRetriever.cachePut(items.get(0));
|
||||||
try {
|
displayMessageAttachments(messageId, items);
|
||||||
Attachment a = attachmentRetriever
|
|
||||||
.getMessageAttachment(header);
|
|
||||||
AttachmentItem item = attachmentRetriever
|
|
||||||
.getAttachmentItem(a, needsSize);
|
|
||||||
items.add(item);
|
|
||||||
} catch (NoSuchMessageException e) {
|
|
||||||
LOG.info("Attachment not received yet");
|
|
||||||
missingAttachments.put(header.getMessageId(), h);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Don't cache items unless all are present and valid
|
|
||||||
attachmentRetriever.cachePut(h.getId(), items);
|
|
||||||
displayMessageAttachments(h.getId(), items);
|
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
@@ -597,13 +570,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof AttachmentReceivedEvent) {
|
|
||||||
AttachmentReceivedEvent a = (AttachmentReceivedEvent) e;
|
|
||||||
if (a.getContactId().equals(contactId)) {
|
|
||||||
LOG.info("Attachment received");
|
|
||||||
onAttachmentReceived(a.getMessageId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e instanceof ContactRemovedEvent) {
|
if (e instanceof ContactRemovedEvent) {
|
||||||
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
ContactRemovedEvent c = (ContactRemovedEvent) e;
|
||||||
if (c.getContactId().equals(contactId)) {
|
if (c.getContactId().equals(contactId)) {
|
||||||
@@ -654,15 +620,6 @@ public class ConversationActivity extends BriarActivity
|
|||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
|
||||||
private void onAttachmentReceived(MessageId attachmentId) {
|
|
||||||
PrivateMessageHeader h = missingAttachments.remove(attachmentId);
|
|
||||||
if (h != null) {
|
|
||||||
LOG.info("Missing attachment received");
|
|
||||||
loadMessageAttachments(h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void onNewConversationMessage(ConversationMessageHeader h) {
|
private void onNewConversationMessage(ConversationMessageHeader h) {
|
||||||
if (h instanceof ConversationRequest ||
|
if (h instanceof ConversationRequest ||
|
||||||
@@ -949,14 +906,19 @@ public class ConversationActivity extends BriarActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<AttachmentItem> getAttachmentItems(PrivateMessageHeader h) {
|
public List<AttachmentItem> getAttachmentItems(MessageId m,
|
||||||
List<AttachmentItem> attachments =
|
List<AttachmentHeader> headers) {
|
||||||
attachmentRetriever.cacheGet(h.getId());
|
List<AttachmentItem> items = new ArrayList<>(headers.size());
|
||||||
if (attachments == null) {
|
for (AttachmentHeader header : headers) {
|
||||||
loadMessageAttachments(h);
|
AttachmentItem item =
|
||||||
return emptyList();
|
attachmentRetriever.cacheGet(header.getMessageId());
|
||||||
|
if (item == null) {
|
||||||
|
loadMessageAttachments(m, headers);
|
||||||
|
return emptyList();
|
||||||
|
}
|
||||||
|
items.add(item);
|
||||||
}
|
}
|
||||||
return attachments;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Application;
|
|||||||
import android.arch.lifecycle.AndroidViewModel;
|
import android.arch.lifecycle.AndroidViewModel;
|
||||||
import android.arch.lifecycle.LiveData;
|
import android.arch.lifecycle.LiveData;
|
||||||
import android.arch.lifecycle.MutableLiveData;
|
import android.arch.lifecycle.MutableLiveData;
|
||||||
|
import android.arch.lifecycle.Observer;
|
||||||
import android.arch.lifecycle.Transformations;
|
import android.arch.lifecycle.Transformations;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
@@ -124,7 +125,7 @@ public class ConversationViewModel extends AndroidViewModel
|
|||||||
@Override
|
@Override
|
||||||
protected void onCleared() {
|
protected void onCleared() {
|
||||||
super.onCleared();
|
super.onCleared();
|
||||||
attachmentCreator.deleteUnsentAttachments();
|
attachmentCreator.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -200,12 +201,23 @@ public class ConversationViewModel extends AndroidViewModel
|
|||||||
@UiThread
|
@UiThread
|
||||||
public LiveData<AttachmentResult> storeAttachments(Collection<Uri> uris,
|
public LiveData<AttachmentResult> storeAttachments(Collection<Uri> uris,
|
||||||
boolean restart) {
|
boolean restart) {
|
||||||
if (restart) {
|
MutableLiveData<AttachmentResult> delegate = new MutableLiveData<>();
|
||||||
return attachmentCreator.getLiveAttachments();
|
// messagingGroupId is loaded with the contact
|
||||||
} else {
|
observeForeverOnce(messagingGroupId, groupId -> {
|
||||||
// messagingGroupId is loaded with the contact
|
requireNonNull(groupId);
|
||||||
return attachmentCreator.storeAttachments(messagingGroupId, uris);
|
LiveData<AttachmentResult> result;
|
||||||
}
|
if (restart) result = attachmentCreator.getLiveAttachments();
|
||||||
|
else result = attachmentCreator.storeAttachments(groupId, uris);
|
||||||
|
result.observeForever(new Observer<AttachmentResult>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(@Nullable AttachmentResult value) {
|
||||||
|
requireNonNull(value);
|
||||||
|
if (value.isFinished()) result.removeObserver(this);
|
||||||
|
delegate.setValue(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -294,7 +306,7 @@ public class ConversationViewModel extends AndroidViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void storeMessage(PrivateMessage m) {
|
private void storeMessage(PrivateMessage m) {
|
||||||
attachmentCreator.onAttachmentsSent(m.getMessage().getId());
|
attachmentCreator.onAttachmentsSent();
|
||||||
dbExecutor.execute(() -> {
|
dbExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
long start = now();
|
long start = now();
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.briarproject.briar.api.forum.ForumInvitationRequest;
|
|||||||
import org.briarproject.briar.api.forum.ForumInvitationResponse;
|
import org.briarproject.briar.api.forum.ForumInvitationResponse;
|
||||||
import org.briarproject.briar.api.introduction.IntroductionRequest;
|
import org.briarproject.briar.api.introduction.IntroductionRequest;
|
||||||
import org.briarproject.briar.api.introduction.IntroductionResponse;
|
import org.briarproject.briar.api.introduction.IntroductionResponse;
|
||||||
|
import org.briarproject.briar.api.messaging.AttachmentHeader;
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationRequest;
|
||||||
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
|
import org.briarproject.briar.api.privategroup.invitation.GroupInvitationResponse;
|
||||||
@@ -55,7 +56,8 @@ class ConversationVisitor implements
|
|||||||
if (h.getAttachmentHeaders().isEmpty()) {
|
if (h.getAttachmentHeaders().isEmpty()) {
|
||||||
attachments = emptyList();
|
attachments = emptyList();
|
||||||
} else {
|
} else {
|
||||||
attachments = attachmentCache.getAttachmentItems(h);
|
attachments = attachmentCache
|
||||||
|
.getAttachmentItems(h.getId(), h.getAttachmentHeaders());
|
||||||
}
|
}
|
||||||
if (h.isLocal()) {
|
if (h.isLocal()) {
|
||||||
item = new ConversationMessageItem(
|
item = new ConversationMessageItem(
|
||||||
@@ -293,6 +295,7 @@ class ConversationVisitor implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface AttachmentCache {
|
interface AttachmentCache {
|
||||||
List<AttachmentItem> getAttachmentItems(PrivateMessageHeader h);
|
List<AttachmentItem> getAttachmentItems(MessageId m,
|
||||||
|
List<AttachmentHeader> headers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import org.briarproject.bramble.api.db.DatabaseExecutor;
|
|||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.briar.android.attachment.AttachmentItem;
|
import org.briarproject.briar.android.attachment.AttachmentItem;
|
||||||
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
import org.briarproject.briar.android.viewmodel.LiveEvent;
|
||||||
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
import org.briarproject.briar.android.viewmodel.MutableLiveEvent;
|
||||||
@@ -134,10 +135,10 @@ public class ImageViewModel extends AndroidViewModel {
|
|||||||
|
|
||||||
private void saveImage(AttachmentItem attachment, OutputStreamProvider osp,
|
private void saveImage(AttachmentItem attachment, OutputStreamProvider osp,
|
||||||
@Nullable Runnable afterCopy) {
|
@Nullable Runnable afterCopy) {
|
||||||
|
MessageId messageId = attachment.getMessageId();
|
||||||
dbExecutor.execute(() -> {
|
dbExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
Attachment a =
|
Attachment a = messagingManager.getAttachment(messageId);
|
||||||
messagingManager.getAttachment(attachment.getHeader());
|
|
||||||
copyImageFromDb(a, osp, afterCopy);
|
copyImageFromDb(a, osp, afterCopy);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import com.bumptech.glide.load.data.DataFetcher;
|
|||||||
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
import org.briarproject.bramble.api.db.DatabaseExecutor;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.briar.android.attachment.AttachmentItem;
|
import org.briarproject.briar.android.attachment.AttachmentItem;
|
||||||
import org.briarproject.briar.api.messaging.Attachment;
|
|
||||||
import org.briarproject.briar.api.messaging.MessagingManager;
|
import org.briarproject.briar.api.messaging.MessagingManager;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -50,12 +50,11 @@ class BriarDataFetcher implements DataFetcher<InputStream> {
|
|||||||
@Override
|
@Override
|
||||||
public void loadData(Priority priority,
|
public void loadData(Priority priority,
|
||||||
DataCallback<? super InputStream> callback) {
|
DataCallback<? super InputStream> callback) {
|
||||||
|
MessageId id = attachment.getMessageId();
|
||||||
dbExecutor.execute(() -> {
|
dbExecutor.execute(() -> {
|
||||||
if (cancel) return;
|
if (cancel) return;
|
||||||
try {
|
try {
|
||||||
Attachment a =
|
inputStream = messagingManager.getAttachment(id).getStream();
|
||||||
messagingManager.getAttachment(attachment.getHeader());
|
|
||||||
inputStream = a.getStream();
|
|
||||||
callback.onDataReady(inputStream);
|
callback.onDataReady(inputStream);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
callback.onLoadFailed(e);
|
callback.onLoadFailed(e);
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import org.briarproject.briar.android.attachment.AttachmentItemResult;
|
|||||||
import org.briarproject.briar.android.attachment.AttachmentManager;
|
import org.briarproject.briar.android.attachment.AttachmentManager;
|
||||||
import org.briarproject.briar.android.attachment.AttachmentResult;
|
import org.briarproject.briar.android.attachment.AttachmentResult;
|
||||||
import org.briarproject.briar.android.view.ImagePreview.ImagePreviewListener;
|
import org.briarproject.briar.android.view.ImagePreview.ImagePreviewListener;
|
||||||
|
import org.briarproject.briar.api.messaging.FileTooBigException;
|
||||||
|
import org.jsoup.UnsupportedMimeTypeException;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -41,9 +43,11 @@ import static android.support.v4.content.ContextCompat.getColor;
|
|||||||
import static android.support.v4.view.AbsSavedState.EMPTY_STATE;
|
import static android.support.v4.view.AbsSavedState.EMPTY_STATE;
|
||||||
import static android.view.View.GONE;
|
import static android.view.View.GONE;
|
||||||
import static android.widget.Toast.LENGTH_LONG;
|
import static android.widget.Toast.LENGTH_LONG;
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
import static org.briarproject.briar.android.util.UiUtils.resolveColorAttribute;
|
import static org.briarproject.briar.android.util.UiUtils.resolveColorAttribute;
|
||||||
import static org.briarproject.briar.api.messaging.MessagingConstants.IMAGE_MIME_TYPES;
|
import static org.briarproject.briar.api.messaging.MessagingConstants.IMAGE_MIME_TYPES;
|
||||||
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE;
|
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_ATTACHMENTS_PER_MESSAGE;
|
||||||
|
import static org.briarproject.briar.api.messaging.MessagingConstants.MAX_IMAGE_SIZE;
|
||||||
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_DISMISSED;
|
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_DISMISSED;
|
||||||
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_FINISHED;
|
import static uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt.STATE_FINISHED;
|
||||||
|
|
||||||
@@ -186,18 +190,16 @@ public class TextAttachmentController extends TextSendController
|
|||||||
result.observe(attachmentListener, new Observer<AttachmentResult>() {
|
result.observe(attachmentListener, new Observer<AttachmentResult>() {
|
||||||
@Override
|
@Override
|
||||||
public void onChanged(@Nullable AttachmentResult attachmentResult) {
|
public void onChanged(@Nullable AttachmentResult attachmentResult) {
|
||||||
if (attachmentResult == null) {
|
requireNonNull(attachmentResult);
|
||||||
// The fresh LiveData was deliberately set to null.
|
boolean finished = attachmentResult.isFinished();
|
||||||
// This means that we can stop observing it.
|
boolean success = attachmentResult.isSuccess();
|
||||||
|
if (finished) {
|
||||||
result.removeObserver(this);
|
result.removeObserver(this);
|
||||||
} else {
|
if (!success) return;
|
||||||
boolean noError = onNewAttachmentItemResults(
|
|
||||||
attachmentResult.getItemResults());
|
|
||||||
if (noError && attachmentResult.isFinished()) {
|
|
||||||
onAllAttachmentsCreated();
|
|
||||||
result.removeObserver(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
boolean noError = onNewAttachmentItemResults(
|
||||||
|
attachmentResult.getItemResults());
|
||||||
|
if (noError && success) onAllAttachmentsCreated();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -207,7 +209,7 @@ public class TextAttachmentController extends TextSendController
|
|||||||
if (!loadingUris) throw new AssertionError();
|
if (!loadingUris) throw new AssertionError();
|
||||||
for (AttachmentItemResult result : itemResults) {
|
for (AttachmentItemResult result : itemResults) {
|
||||||
if (result.hasError()) {
|
if (result.hasError()) {
|
||||||
onError(result.getErrorMsg());
|
onError(requireNonNull(result.getException()));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
imagePreview.loadPreviewImage(result);
|
imagePreview.loadPreviewImage(result);
|
||||||
@@ -253,12 +255,20 @@ public class TextAttachmentController extends TextSendController
|
|||||||
}
|
}
|
||||||
|
|
||||||
@UiThread
|
@UiThread
|
||||||
private void onError(@Nullable String errorMsg) {
|
private void onError(Exception e) {
|
||||||
if (errorMsg == null) {
|
String errorMsg;
|
||||||
errorMsg = imagePreview.getContext()
|
Context ctx = imagePreview.getContext();
|
||||||
.getString(R.string.image_attach_error);
|
if (e instanceof UnsupportedMimeTypeException) {
|
||||||
|
String mimeType = ((UnsupportedMimeTypeException) e).getMimeType();
|
||||||
|
errorMsg = ctx.getString(
|
||||||
|
R.string.image_attach_error_invalid_mime_type, mimeType);
|
||||||
|
} else if (e instanceof FileTooBigException) {
|
||||||
|
int mb = MAX_IMAGE_SIZE / 1024 / 1024;
|
||||||
|
errorMsg = ctx.getString(R.string.image_attach_error_too_big, mb);
|
||||||
|
} else {
|
||||||
|
errorMsg = ctx.getString(R.string.image_attach_error);
|
||||||
}
|
}
|
||||||
Toast.makeText(textInput.getContext(), errorMsg, LENGTH_LONG).show();
|
Toast.makeText(ctx, errorMsg, LENGTH_LONG).show();
|
||||||
onCancel();
|
onCancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.briarproject.briar.api.messaging.MessagingManager;
|
|||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
@@ -24,26 +25,32 @@ public class AttachmentRetrieverTest extends BrambleMockTestCase {
|
|||||||
100, 50, 200, 75, 300
|
100, 50, 200, 75, 300
|
||||||
);
|
);
|
||||||
private final MessageId msgId = new MessageId(getRandomId());
|
private final MessageId msgId = new MessageId(getRandomId());
|
||||||
|
private final Attachment attachment = new Attachment(
|
||||||
|
new BufferedInputStream(
|
||||||
|
new ByteArrayInputStream(getRandomBytes(42))));
|
||||||
|
|
||||||
private final MessagingManager messagingManager =
|
private final MessagingManager messagingManager =
|
||||||
context.mock(MessagingManager.class);
|
context.mock(MessagingManager.class);
|
||||||
private final ImageHelper imageHelper = context.mock(ImageHelper.class);
|
private final ImageHelper imageHelper = context.mock(ImageHelper.class);
|
||||||
private final AttachmentRetriever retriever = new AttachmentRetriever(
|
private final AttachmentRetriever controller =
|
||||||
messagingManager,
|
new AttachmentRetriever(
|
||||||
dimensions,
|
messagingManager,
|
||||||
imageHelper
|
dimensions,
|
||||||
);
|
imageHelper
|
||||||
|
);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoSize() {
|
public void testNoSize() {
|
||||||
String mimeType = "image/jpeg";
|
String mimeType = "image/jpeg";
|
||||||
Attachment attachment = getAttachment(mimeType);
|
AttachmentHeader h = getAttachmentHeader(mimeType);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(imageHelper).getExtensionFromMimeType(mimeType);
|
oneOf(imageHelper).getExtensionFromMimeType(mimeType);
|
||||||
will(returnValue("jpg"));
|
will(returnValue("jpg"));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
AttachmentItem item = retriever.getAttachmentItem(attachment, false);
|
AttachmentItem item =
|
||||||
|
controller.getAttachmentItem(h, attachment, false);
|
||||||
assertEquals(mimeType, item.getMimeType());
|
assertEquals(mimeType, item.getMimeType());
|
||||||
assertEquals("jpg", item.getExtension());
|
assertEquals("jpg", item.getExtension());
|
||||||
assertFalse(item.hasError());
|
assertFalse(item.hasError());
|
||||||
@@ -52,21 +59,22 @@ public class AttachmentRetrieverTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testNoSizeWrongMimeTypeProducesError() {
|
public void testNoSizeWrongMimeTypeProducesError() {
|
||||||
String mimeType = "application/octet-stream";
|
String mimeType = "application/octet-stream";
|
||||||
Attachment attachment = getAttachment(mimeType);
|
AttachmentHeader h = getAttachmentHeader(mimeType);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(imageHelper).getExtensionFromMimeType(mimeType);
|
oneOf(imageHelper).getExtensionFromMimeType(mimeType);
|
||||||
will(returnValue(null));
|
will(returnValue(null));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
AttachmentItem item = retriever.getAttachmentItem(attachment, false);
|
AttachmentItem item =
|
||||||
|
controller.getAttachmentItem(h, attachment, false);
|
||||||
assertTrue(item.hasError());
|
assertTrue(item.hasError());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSmallJpegImage() {
|
public void testSmallJpegImage() {
|
||||||
String mimeType = "image/jpeg";
|
String mimeType = "image/jpeg";
|
||||||
Attachment attachment = getAttachment(mimeType);
|
AttachmentHeader h = getAttachmentHeader(mimeType);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(imageHelper).decodeStream(with(any(InputStream.class)));
|
oneOf(imageHelper).decodeStream(with(any(InputStream.class)));
|
||||||
@@ -75,7 +83,7 @@ public class AttachmentRetrieverTest extends BrambleMockTestCase {
|
|||||||
will(returnValue("jpg"));
|
will(returnValue("jpg"));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
AttachmentItem item = retriever.getAttachmentItem(attachment, true);
|
AttachmentItem item = controller.getAttachmentItem(h, attachment, true);
|
||||||
assertEquals(msgId, item.getMessageId());
|
assertEquals(msgId, item.getMessageId());
|
||||||
assertEquals(160, item.getWidth());
|
assertEquals(160, item.getWidth());
|
||||||
assertEquals(240, item.getHeight());
|
assertEquals(240, item.getHeight());
|
||||||
@@ -89,7 +97,7 @@ public class AttachmentRetrieverTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testBigJpegImage() {
|
public void testBigJpegImage() {
|
||||||
String mimeType = "image/jpeg";
|
String mimeType = "image/jpeg";
|
||||||
Attachment attachment = getAttachment(mimeType);
|
AttachmentHeader h = getAttachmentHeader(mimeType);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(imageHelper).decodeStream(with(any(InputStream.class)));
|
oneOf(imageHelper).decodeStream(with(any(InputStream.class)));
|
||||||
@@ -98,7 +106,7 @@ public class AttachmentRetrieverTest extends BrambleMockTestCase {
|
|||||||
will(returnValue("jpg"));
|
will(returnValue("jpg"));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
AttachmentItem item = retriever.getAttachmentItem(attachment, true);
|
AttachmentItem item = controller.getAttachmentItem(h, attachment, true);
|
||||||
assertEquals(1728, item.getWidth());
|
assertEquals(1728, item.getWidth());
|
||||||
assertEquals(2592, item.getHeight());
|
assertEquals(2592, item.getHeight());
|
||||||
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
assertEquals(dimensions.maxWidth, item.getThumbnailWidth());
|
||||||
@@ -108,7 +116,7 @@ public class AttachmentRetrieverTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMalformedError() {
|
public void testMalformedError() {
|
||||||
Attachment attachment = getAttachment("image/jpeg");
|
AttachmentHeader h = getAttachmentHeader("image/jpeg");
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(imageHelper).decodeStream(with(any(InputStream.class)));
|
oneOf(imageHelper).decodeStream(with(any(InputStream.class)));
|
||||||
@@ -117,13 +125,12 @@ public class AttachmentRetrieverTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(null));
|
will(returnValue(null));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
AttachmentItem item = retriever.getAttachmentItem(attachment, true);
|
AttachmentItem item = controller.getAttachmentItem(h, attachment, true);
|
||||||
assertTrue(item.hasError());
|
assertTrue(item.hasError());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Attachment getAttachment(String contentType) {
|
private AttachmentHeader getAttachmentHeader(String contentType) {
|
||||||
AttachmentHeader header = new AttachmentHeader(msgId, contentType);
|
return new AttachmentHeader(msgId, contentType);
|
||||||
InputStream in = new ByteArrayInputStream(getRandomBytes(42));
|
|
||||||
return new Attachment(header, in);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,15 @@
|
|||||||
package org.briarproject.briar.api.messaging;
|
package org.briarproject.briar.api.messaging;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
|
|
||||||
@Immutable
|
|
||||||
@NotNullByDefault
|
|
||||||
public class Attachment {
|
public class Attachment {
|
||||||
|
|
||||||
private final AttachmentHeader header;
|
|
||||||
private final InputStream stream;
|
private final InputStream stream;
|
||||||
|
|
||||||
public Attachment(AttachmentHeader header, InputStream stream) {
|
public Attachment(InputStream stream) {
|
||||||
this.header = header;
|
|
||||||
this.stream = stream;
|
this.stream = stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AttachmentHeader getHeader() {
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream getStream() {
|
public InputStream getStream() {
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,5 +2,8 @@ package org.briarproject.briar.api.messaging;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception that is thrown when a file is too big to attach to a message.
|
||||||
|
*/
|
||||||
public class FileTooBigException extends IOException {
|
public class FileTooBigException extends IOException {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
package org.briarproject.briar.api.messaging;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An exception that is thrown when an {@link AttachmentHeader} is used to
|
|
||||||
* load an {@link Attachment}, and the header refers to a message that is not
|
|
||||||
* an attachment, or to an attachment that does not have the expected content
|
|
||||||
* type.
|
|
||||||
*/
|
|
||||||
@NotNullByDefault
|
|
||||||
public class InvalidAttachmentException extends DbException {
|
|
||||||
}
|
|
||||||
@@ -40,7 +40,7 @@ public interface MessagingManager extends ConversationClient {
|
|||||||
/**
|
/**
|
||||||
* Stores a local attachment message.
|
* Stores a local attachment message.
|
||||||
*
|
*
|
||||||
* @throws FileTooBigException If the attachment is too big
|
* @throws FileTooBigException
|
||||||
*/
|
*/
|
||||||
AttachmentHeader addLocalAttachment(GroupId groupId, long timestamp,
|
AttachmentHeader addLocalAttachment(GroupId groupId, long timestamp,
|
||||||
String contentType, InputStream is) throws DbException, IOException;
|
String contentType, InputStream is) throws DbException, IOException;
|
||||||
@@ -68,13 +68,9 @@ public interface MessagingManager extends ConversationClient {
|
|||||||
String getMessageText(MessageId m) throws DbException;
|
String getMessageText(MessageId m) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the attachment with the given message ID and content type.
|
* Returns the attachment with the given ID.
|
||||||
*
|
|
||||||
* @throws InvalidAttachmentException If the header refers to a message
|
|
||||||
* that is not an attachment, or to an attachment that does not have the
|
|
||||||
* expected content type
|
|
||||||
*/
|
*/
|
||||||
Attachment getAttachment(AttachmentHeader h) throws DbException;
|
Attachment getAttachment(MessageId m) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the contact with the given {@link ContactId} does support
|
* Returns true if the contact with the given {@link ContactId} does support
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import org.briarproject.bramble.api.sync.Message;
|
|||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.MessageStatus;
|
import org.briarproject.bramble.api.sync.MessageStatus;
|
||||||
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
|
import org.briarproject.bramble.api.sync.validation.IncomingMessageHook;
|
||||||
import org.briarproject.bramble.api.system.Scheduler;
|
|
||||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
import org.briarproject.bramble.api.versioning.ClientVersioningManager;
|
||||||
import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
|
import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
|
||||||
import org.briarproject.briar.api.client.MessageTracker;
|
import org.briarproject.briar.api.client.MessageTracker;
|
||||||
@@ -33,7 +32,6 @@ import org.briarproject.briar.api.conversation.ConversationMessageHeader;
|
|||||||
import org.briarproject.briar.api.messaging.Attachment;
|
import org.briarproject.briar.api.messaging.Attachment;
|
||||||
import org.briarproject.briar.api.messaging.AttachmentHeader;
|
import org.briarproject.briar.api.messaging.AttachmentHeader;
|
||||||
import org.briarproject.briar.api.messaging.FileTooBigException;
|
import org.briarproject.briar.api.messaging.FileTooBigException;
|
||||||
import org.briarproject.briar.api.messaging.InvalidAttachmentException;
|
|
||||||
import org.briarproject.briar.api.messaging.MessagingManager;
|
import org.briarproject.briar.api.messaging.MessagingManager;
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessage;
|
import org.briarproject.briar.api.messaging.PrivateMessage;
|
||||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||||
@@ -48,19 +46,13 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static java.util.logging.Logger.getLogger;
|
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
|
||||||
import static org.briarproject.bramble.util.IoUtils.copyAndClose;
|
import static org.briarproject.bramble.util.IoUtils.copyAndClose;
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
|
||||||
import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
|
import static org.briarproject.briar.client.MessageTrackerConstants.MSG_KEY_READ;
|
||||||
import static org.briarproject.briar.messaging.MessageTypes.ATTACHMENT;
|
import static org.briarproject.briar.messaging.MessageTypes.ATTACHMENT;
|
||||||
import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE;
|
import static org.briarproject.briar.messaging.MessageTypes.PRIVATE_MESSAGE;
|
||||||
@@ -79,10 +71,6 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
|
|||||||
ConversationClient, OpenDatabaseHook, ContactHook,
|
ConversationClient, OpenDatabaseHook, ContactHook,
|
||||||
ClientVersioningHook {
|
ClientVersioningHook {
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
getLogger(MessagingManagerImpl.class.getName());
|
|
||||||
|
|
||||||
private final ScheduledExecutorService scheduler;
|
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
private final ClientHelper clientHelper;
|
private final ClientHelper clientHelper;
|
||||||
private final MetadataParser metadataParser;
|
private final MetadataParser metadataParser;
|
||||||
@@ -91,12 +79,10 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
|
|||||||
private final ContactGroupFactory contactGroupFactory;
|
private final ContactGroupFactory contactGroupFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
MessagingManagerImpl(@Scheduler ScheduledExecutorService scheduler,
|
MessagingManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
|
||||||
DatabaseComponent db, ClientHelper clientHelper,
|
|
||||||
ClientVersioningManager clientVersioningManager,
|
ClientVersioningManager clientVersioningManager,
|
||||||
MetadataParser metadataParser, MessageTracker messageTracker,
|
MetadataParser metadataParser, MessageTracker messageTracker,
|
||||||
ContactGroupFactory contactGroupFactory) {
|
ContactGroupFactory contactGroupFactory) {
|
||||||
this.scheduler = scheduler;
|
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.clientHelper = clientHelper;
|
this.clientHelper = clientHelper;
|
||||||
this.metadataParser = metadataParser;
|
this.metadataParser = metadataParser;
|
||||||
@@ -252,20 +238,9 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
|
|||||||
meta.put(MSG_KEY_ATTACHMENT_HEADERS, headers);
|
meta.put(MSG_KEY_ATTACHMENT_HEADERS, headers);
|
||||||
}
|
}
|
||||||
// Mark attachments as shared and permanent now we're ready to send
|
// Mark attachments as shared and permanent now we're ready to send
|
||||||
// FIXME: Revert
|
|
||||||
int i = 15;
|
|
||||||
for (AttachmentHeader a : m.getAttachmentHeaders()) {
|
for (AttachmentHeader a : m.getAttachmentHeaders()) {
|
||||||
scheduler.schedule(() -> {
|
db.setMessageShared(txn, a.getMessageId());
|
||||||
try {
|
db.setMessagePermanent(txn, a.getMessageId());
|
||||||
db.transaction(false, txn1 -> {
|
|
||||||
db.setMessageShared(txn1, a.getMessageId());
|
|
||||||
db.setMessagePermanent(txn1, a.getMessageId());
|
|
||||||
});
|
|
||||||
} catch (DbException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
}
|
|
||||||
}, i, SECONDS);
|
|
||||||
i *= 2;
|
|
||||||
}
|
}
|
||||||
clientHelper.addLocalMessage(txn, m.getMessage(), meta, true,
|
clientHelper.addLocalMessage(txn, m.getMessage(), meta, true,
|
||||||
false);
|
false);
|
||||||
@@ -399,20 +374,13 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Attachment getAttachment(AttachmentHeader h) throws DbException {
|
public Attachment getAttachment(MessageId m) throws DbException {
|
||||||
// TODO: Support large messages
|
// TODO: Support large messages
|
||||||
MessageId m = h.getMessageId();
|
|
||||||
byte[] body = clientHelper.getMessage(m).getBody();
|
byte[] body = clientHelper.getMessage(m).getBody();
|
||||||
try {
|
try {
|
||||||
BdfDictionary meta = clientHelper.getMessageMetadataAsDictionary(m);
|
BdfDictionary meta = clientHelper.getMessageMetadataAsDictionary(m);
|
||||||
Long messageType = meta.getOptionalLong(MSG_KEY_MSG_TYPE);
|
|
||||||
if (messageType == null || messageType != ATTACHMENT)
|
|
||||||
throw new InvalidAttachmentException();
|
|
||||||
String contentType = meta.getString(MSG_KEY_CONTENT_TYPE);
|
|
||||||
if (!contentType.equals(h.getContentType()))
|
|
||||||
throw new InvalidAttachmentException();
|
|
||||||
int offset = meta.getLong(MSG_KEY_DESCRIPTOR_LENGTH).intValue();
|
int offset = meta.getLong(MSG_KEY_DESCRIPTOR_LENGTH).intValue();
|
||||||
return new Attachment(h, new ByteArrayInputStream(body, offset,
|
return new Attachment(new ByteArrayInputStream(body, offset,
|
||||||
body.length - offset));
|
body.length - offset));
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
|
|||||||
Reference in New Issue
Block a user