mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 21:29:54 +01:00
[android] move unsent attachment cache logic into AttachmentController
This commit is contained in:
@@ -29,7 +29,6 @@ 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;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import static android.support.media.ExifInterface.ORIENTATION_ROTATE_270;
|
import static android.support.media.ExifInterface.ORIENTATION_ROTATE_270;
|
||||||
@@ -59,7 +58,8 @@ class AttachmentController {
|
|||||||
private final int minWidth, maxWidth;
|
private final int minWidth, maxWidth;
|
||||||
private final int minHeight, maxHeight;
|
private final int minHeight, maxHeight;
|
||||||
|
|
||||||
private final List<AttachmentHeader> unsent = new CopyOnWriteArrayList<>();
|
private final Map<Uri, AttachmentItem> unsentItems =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
private final Map<MessageId, List<AttachmentItem>> attachmentCache =
|
private final Map<MessageId, List<AttachmentItem>> attachmentCache =
|
||||||
new ConcurrentHashMap<>();
|
new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@@ -121,9 +121,15 @@ class AttachmentController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
AttachmentHeader createAttachmentHeader(ContentResolver contentResolver,
|
void createAttachmentHeader(ContentResolver contentResolver,
|
||||||
GroupId groupId, Uri uri)
|
GroupId groupId, Uri uri, boolean needsSize)
|
||||||
throws IOException, DbException {
|
throws IOException, DbException {
|
||||||
|
if (unsentItems.containsKey(uri)) {
|
||||||
|
// This can happen due to configuration (screen orientation) change.
|
||||||
|
// So don't create a new attachment, if we have one already.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long start = now();
|
||||||
InputStream is = contentResolver.openInputStream(uri);
|
InputStream is = contentResolver.openInputStream(uri);
|
||||||
if (is == null) throw new IOException();
|
if (is == null) throw new IOException();
|
||||||
String contentType = contentResolver.getType(uri);
|
String contentType = contentResolver.getType(uri);
|
||||||
@@ -132,32 +138,47 @@ class AttachmentController {
|
|||||||
AttachmentHeader h = messagingManager
|
AttachmentHeader h = messagingManager
|
||||||
.addLocalAttachment(groupId, timestamp, contentType, is);
|
.addLocalAttachment(groupId, timestamp, contentType, is);
|
||||||
tryToClose(is, LOG, WARNING);
|
tryToClose(is, LOG, WARNING);
|
||||||
unsent.add(h);
|
logDuration(LOG, "Storing attachment", start);
|
||||||
return h;
|
// get and store AttachmentItem for ImagePreview
|
||||||
|
AttachmentItem item =
|
||||||
|
getAttachmentItem(contentResolver, uri, h, needsSize);
|
||||||
|
if (item.hasError()) throw new IOException();
|
||||||
|
unsentItems.put(uri, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
void deleteUnsentAttachments() {
|
void deleteUnsentAttachments() {
|
||||||
for (AttachmentHeader h : unsent) {
|
for (AttachmentItem item : unsentItems.values()) {
|
||||||
try {
|
try {
|
||||||
messagingManager.removeAttachment(h);
|
messagingManager.removeAttachment(item.getHeader());
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unsentItems.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AttachmentHeader> getUnsentAttachments() {
|
List<AttachmentHeader> getUnsentAttachmentHeaders() {
|
||||||
return new ArrayList<>(unsent);
|
List<AttachmentHeader> headers =
|
||||||
|
new ArrayList<>(unsentItems.values().size());
|
||||||
|
for (AttachmentItem item : unsentItems.values()) {
|
||||||
|
headers.add(item.getHeader());
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
void markAttachmentsSent() {
|
/**
|
||||||
unsent.clear();
|
* Marks the attachments as sent and adds the items to the cache for display
|
||||||
|
* @param id The MessageId of the sent message.
|
||||||
|
*/
|
||||||
|
void onAttachmentsSent(MessageId id) {
|
||||||
|
attachmentCache.put(id, new ArrayList<>(unsentItems.values()));
|
||||||
|
unsentItems.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@DatabaseExecutor
|
@DatabaseExecutor
|
||||||
AttachmentItem getAttachmentItem(ContentResolver contentResolver, Uri uri,
|
private AttachmentItem getAttachmentItem(ContentResolver contentResolver,
|
||||||
AttachmentHeader h, boolean needsSize) throws IOException {
|
Uri uri, AttachmentHeader h, boolean needsSize) throws IOException {
|
||||||
InputStream is = null;
|
InputStream is = null;
|
||||||
try {
|
try {
|
||||||
is = contentResolver.openInputStream(uri);
|
is = contentResolver.openInputStream(uri);
|
||||||
@@ -192,17 +213,15 @@ class AttachmentController {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
AttachmentItem getAttachmentItem(AttachmentHeader h, Attachment a,
|
AttachmentItem getAttachmentItem(AttachmentHeader h, Attachment a,
|
||||||
boolean needsSize) {
|
boolean needsSize) {
|
||||||
MessageId messageId = h.getMessageId();
|
|
||||||
if (!needsSize) {
|
if (!needsSize) {
|
||||||
String mimeType = h.getContentType();
|
String extension =
|
||||||
String extension = imageHelper.getExtensionFromMimeType(mimeType);
|
imageHelper.getExtensionFromMimeType(h.getContentType());
|
||||||
boolean hasError = false;
|
boolean hasError = false;
|
||||||
if (extension == null) {
|
if (extension == null) {
|
||||||
extension = "";
|
extension = "";
|
||||||
hasError = true;
|
hasError = true;
|
||||||
}
|
}
|
||||||
return new AttachmentItem(messageId, 0, 0, mimeType, extension, 0,
|
return new AttachmentItem(h, 0, 0, extension, 0, 0, hasError);
|
||||||
0, hasError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Size size = new Size();
|
Size size = new Size();
|
||||||
@@ -240,10 +259,17 @@ class AttachmentController {
|
|||||||
// get file extension
|
// get file extension
|
||||||
String extension = imageHelper.getExtensionFromMimeType(size.mimeType);
|
String extension = imageHelper.getExtensionFromMimeType(size.mimeType);
|
||||||
boolean hasError = extension == null || size.error;
|
boolean hasError = extension == null || size.error;
|
||||||
|
if (!h.getContentType().equals(size.mimeType)) {
|
||||||
|
if (LOG.isLoggable(WARNING)) {
|
||||||
|
LOG.warning("Header has different mime type (" +
|
||||||
|
h.getContentType() + ") than image (" + size.mimeType +
|
||||||
|
").");
|
||||||
|
}
|
||||||
|
hasError = true;
|
||||||
|
}
|
||||||
if (extension == null) extension = "";
|
if (extension == null) extension = "";
|
||||||
return new AttachmentItem(messageId, size.width, size.height,
|
return new AttachmentItem(h, size.width, size.height, extension,
|
||||||
size.mimeType, extension, thumbnailSize.width,
|
thumbnailSize.width, thumbnailSize.height, hasError);
|
||||||
thumbnailSize.height, hasError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.support.annotation.Nullable;
|
|||||||
|
|
||||||
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;
|
||||||
|
import org.briarproject.briar.api.messaging.AttachmentHeader;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
@@ -15,9 +16,9 @@ import javax.annotation.concurrent.Immutable;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class AttachmentItem implements Parcelable {
|
public class AttachmentItem implements Parcelable {
|
||||||
|
|
||||||
private final MessageId messageId;
|
private final AttachmentHeader header;
|
||||||
private final int width, height;
|
private final int width, height;
|
||||||
private final String mimeType, extension;
|
private final String extension;
|
||||||
private final int thumbnailWidth, thumbnailHeight;
|
private final int thumbnailWidth, thumbnailHeight;
|
||||||
private final boolean hasError;
|
private final boolean hasError;
|
||||||
private final long instanceId;
|
private final long instanceId;
|
||||||
@@ -37,13 +38,12 @@ public class AttachmentItem implements Parcelable {
|
|||||||
|
|
||||||
private static final AtomicLong NEXT_INSTANCE_ID = new AtomicLong(0);
|
private static final AtomicLong NEXT_INSTANCE_ID = new AtomicLong(0);
|
||||||
|
|
||||||
AttachmentItem(MessageId messageId, int width, int height, String mimeType,
|
AttachmentItem(AttachmentHeader header, int width, int height,
|
||||||
String extension, int thumbnailWidth, int thumbnailHeight,
|
String extension, int thumbnailWidth, int thumbnailHeight,
|
||||||
boolean hasError) {
|
boolean hasError) {
|
||||||
this.messageId = messageId;
|
this.header = header;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.mimeType = mimeType;
|
|
||||||
this.extension = extension;
|
this.extension = extension;
|
||||||
this.thumbnailWidth = thumbnailWidth;
|
this.thumbnailWidth = thumbnailWidth;
|
||||||
this.thumbnailHeight = thumbnailHeight;
|
this.thumbnailHeight = thumbnailHeight;
|
||||||
@@ -54,19 +54,24 @@ public class AttachmentItem implements Parcelable {
|
|||||||
protected AttachmentItem(Parcel in) {
|
protected AttachmentItem(Parcel in) {
|
||||||
byte[] messageIdByte = new byte[MessageId.LENGTH];
|
byte[] messageIdByte = new byte[MessageId.LENGTH];
|
||||||
in.readByteArray(messageIdByte);
|
in.readByteArray(messageIdByte);
|
||||||
messageId = new MessageId(messageIdByte);
|
MessageId messageId = new MessageId(messageIdByte);
|
||||||
width = in.readInt();
|
width = in.readInt();
|
||||||
height = in.readInt();
|
height = in.readInt();
|
||||||
mimeType = in.readString();
|
String mimeType = in.readString();
|
||||||
extension = in.readString();
|
extension = in.readString();
|
||||||
thumbnailWidth = in.readInt();
|
thumbnailWidth = in.readInt();
|
||||||
thumbnailHeight = in.readInt();
|
thumbnailHeight = in.readInt();
|
||||||
hasError = in.readByte() != 0;
|
hasError = in.readByte() != 0;
|
||||||
instanceId = in.readLong();
|
instanceId = in.readLong();
|
||||||
|
header = new AttachmentHeader(messageId, mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachmentHeader getHeader() {
|
||||||
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessageId getMessageId() {
|
public MessageId getMessageId() {
|
||||||
return messageId;
|
return header.getMessageId();
|
||||||
}
|
}
|
||||||
|
|
||||||
int getWidth() {
|
int getWidth() {
|
||||||
@@ -78,7 +83,7 @@ public class AttachmentItem implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String getMimeType() {
|
String getMimeType() {
|
||||||
return mimeType;
|
return header.getContentType();
|
||||||
}
|
}
|
||||||
|
|
||||||
String getExtension() {
|
String getExtension() {
|
||||||
@@ -108,10 +113,10 @@ public class AttachmentItem implements Parcelable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
dest.writeByteArray(messageId.getBytes());
|
dest.writeByteArray(header.getMessageId().getBytes());
|
||||||
dest.writeInt(width);
|
dest.writeInt(width);
|
||||||
dest.writeInt(height);
|
dest.writeInt(height);
|
||||||
dest.writeString(mimeType);
|
dest.writeString(header.getContentType());
|
||||||
dest.writeString(extension);
|
dest.writeString(extension);
|
||||||
dest.writeInt(thumbnailWidth);
|
dest.writeInt(thumbnailWidth);
|
||||||
dest.writeInt(thumbnailHeight);
|
dest.writeInt(thumbnailHeight);
|
||||||
|
|||||||
@@ -38,11 +38,8 @@ import org.briarproject.briar.api.messaging.PrivateMessageFactory;
|
|||||||
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
import org.briarproject.briar.api.messaging.PrivateMessageHeader;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -102,8 +99,6 @@ public class ConversationViewModel extends AndroidViewModel implements
|
|||||||
new MutableLiveData<>();
|
new MutableLiveData<>();
|
||||||
private final MutableLiveData<PrivateMessageHeader> addedHeader =
|
private final MutableLiveData<PrivateMessageHeader> addedHeader =
|
||||||
new MutableLiveData<>();
|
new MutableLiveData<>();
|
||||||
// TODO move to AttachmentController
|
|
||||||
private final Map<Uri, AttachmentItem> unsentItems = new HashMap<>();
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ConversationViewModel(Application application,
|
ConversationViewModel(Application application,
|
||||||
@@ -199,12 +194,6 @@ public class ConversationViewModel extends AndroidViewModel implements
|
|||||||
@Override
|
@Override
|
||||||
public void storeAttachment(Uri uri, boolean needsSize, Runnable onSuccess,
|
public void storeAttachment(Uri uri, boolean needsSize, Runnable onSuccess,
|
||||||
Runnable onError) {
|
Runnable onError) {
|
||||||
if (unsentItems.containsKey(uri)) {
|
|
||||||
// This can happen due to configuration (screen orientation) change.
|
|
||||||
// So don't create a new attachment, if we have one already.
|
|
||||||
androidExecutor.runOnUiThread(onSuccess);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (messagingGroupId.getValue() == null) loadGroupId();
|
if (messagingGroupId.getValue() == null) loadGroupId();
|
||||||
observeForeverOnce(messagingGroupId, groupId -> dbExecutor.execute(()
|
observeForeverOnce(messagingGroupId, groupId -> dbExecutor.execute(()
|
||||||
-> {
|
-> {
|
||||||
@@ -213,10 +202,8 @@ public class ConversationViewModel extends AndroidViewModel implements
|
|||||||
try {
|
try {
|
||||||
ContentResolver contentResolver =
|
ContentResolver contentResolver =
|
||||||
getApplication().getContentResolver();
|
getApplication().getContentResolver();
|
||||||
AttachmentHeader h = attachmentController
|
attachmentController.createAttachmentHeader(contentResolver,
|
||||||
.createAttachmentHeader(contentResolver, groupId, uri);
|
groupId, uri, needsSize);
|
||||||
unsentItems.put(uri, attachmentController
|
|
||||||
.getAttachmentItem(contentResolver, uri, h, needsSize));
|
|
||||||
androidExecutor.runOnUiThread(onSuccess);
|
androidExecutor.runOnUiThread(onSuccess);
|
||||||
} catch (DbException | IOException e) {
|
} catch (DbException | IOException e) {
|
||||||
logException(LOG, WARNING, e);
|
logException(LOG, WARNING, e);
|
||||||
@@ -227,13 +214,12 @@ public class ConversationViewModel extends AndroidViewModel implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<AttachmentHeader> getAttachments() {
|
public List<AttachmentHeader> getAttachmentHeaders() {
|
||||||
return attachmentController.getUnsentAttachments();
|
return attachmentController.getUnsentAttachmentHeaders();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeAttachments() {
|
public void removeAttachments() {
|
||||||
unsentItems.clear();
|
|
||||||
dbExecutor.execute(attachmentController::deleteUnsentAttachments);
|
dbExecutor.execute(attachmentController::deleteUnsentAttachments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,10 +318,7 @@ public class ConversationViewModel extends AndroidViewModel implements
|
|||||||
message.getId(), message.getGroupId(),
|
message.getId(), message.getGroupId(),
|
||||||
message.getTimestamp(), true, true, false, false,
|
message.getTimestamp(), true, true, false, false,
|
||||||
text != null, attachments);
|
text != null, attachments);
|
||||||
attachmentController.put(m.getMessage().getId(),
|
attachmentController.onAttachmentsSent(m.getMessage().getId());
|
||||||
new ArrayList<>(unsentItems.values()));
|
|
||||||
unsentItems.clear();
|
|
||||||
attachmentController.markAttachmentsSent();
|
|
||||||
// TODO add text to cache when available here
|
// TODO add text to cache when available here
|
||||||
addedHeader.postValue(h);
|
addedHeader.postValue(h);
|
||||||
} catch (DbException e) {
|
} catch (DbException e) {
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ public class TextAttachmentController extends TextSendController
|
|||||||
public void onSendEvent() {
|
public void onSendEvent() {
|
||||||
if (canSend()) {
|
if (canSend()) {
|
||||||
listener.onSendClick(textInput.getText(),
|
listener.onSendClick(textInput.getText(),
|
||||||
attachmentManager.getAttachments());
|
attachmentManager.getAttachmentHeaders());
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,7 +283,7 @@ public class TextAttachmentController extends TextSendController
|
|||||||
void storeAttachment(Uri uri, boolean needsSize, Runnable onSuccess,
|
void storeAttachment(Uri uri, boolean needsSize, Runnable onSuccess,
|
||||||
Runnable onError);
|
Runnable onError);
|
||||||
|
|
||||||
List<AttachmentHeader> getAttachments();
|
List<AttachmentHeader> getAttachmentHeaders();
|
||||||
|
|
||||||
void removeAttachments();
|
void removeAttachments();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ class MessagingManagerImpl extends ConversationClientImpl
|
|||||||
if (is.available() == 0) throw new IOException();
|
if (is.available() == 0) throw new IOException();
|
||||||
byte[] b = new byte[MessageId.LENGTH];
|
byte[] b = new byte[MessageId.LENGTH];
|
||||||
new Random().nextBytes(b);
|
new Random().nextBytes(b);
|
||||||
return new AttachmentHeader(new MessageId(b), "image/png");
|
return new AttachmentHeader(new MessageId(b), contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user