Merge pull request #2500 from k9mail/GH-999_attachment_download_progress

Show progress for attachment downloads
This commit is contained in:
cketti 2017-04-28 23:29:21 +02:00 committed by GitHub
commit 0627ff5f87
19 changed files with 268 additions and 73 deletions

View file

@ -0,0 +1,10 @@
package com.fsck.k9.mail;
import java.io.IOException;
import java.io.InputStream;
public interface BodyFactory {
Body createBody(String contentTransferEncoding, String contentType, InputStream inputStream) throws IOException;
}

View file

@ -0,0 +1,43 @@
package com.fsck.k9.mail;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import com.fsck.k9.mail.internet.BinaryTempFileBody;
import com.fsck.k9.mail.internet.BinaryTempFileMessageBody;
import com.fsck.k9.mail.internet.MimeUtility;
import org.apache.commons.io.IOUtils;
import org.apache.james.mime4j.util.MimeUtil;
public class DefaultBodyFactory implements BodyFactory {
public Body createBody(String contentTransferEncoding, String contentType, InputStream inputStream)
throws IOException {
if (contentTransferEncoding != null) {
contentTransferEncoding = MimeUtility.getHeaderParameter(contentTransferEncoding, null);
}
final BinaryTempFileBody tempBody;
if (MimeUtil.isMessage(contentType)) {
tempBody = new BinaryTempFileMessageBody(contentTransferEncoding);
} else {
tempBody = new BinaryTempFileBody(contentTransferEncoding);
}
OutputStream outputStream = tempBody.getOutputStream();
try {
copyData(inputStream, outputStream);
} finally {
outputStream.close();
}
return tempBody;
}
protected void copyData(InputStream inputStream, OutputStream outputStream) throws IOException {
IOUtils.copy(inputStream, outputStream);
}
}

View file

@ -127,8 +127,8 @@ public abstract class Folder<T extends Message> {
public abstract void fetch(List<T> messages, FetchProfile fp, public abstract void fetch(List<T> messages, FetchProfile fp,
MessageRetrievalListener<T> listener) throws MessagingException; MessageRetrievalListener<T> listener) throws MessagingException;
public void fetchPart(Message message, Part part, public void fetchPart(Message message, Part part, MessageRetrievalListener<Message> listener,
MessageRetrievalListener<Message> listener) throws MessagingException { BodyFactory bodyFactory) throws MessagingException {
// This is causing trouble. Disabled for now. See issue 1733 // This is causing trouble. Disabled for now. See issue 1733
//throw new RuntimeException("fetchPart() not implemented."); //throw new RuntimeException("fetchPart() not implemented.");

View file

@ -19,7 +19,9 @@ import android.support.annotation.NonNull;
import com.fsck.k9.mail.Address; import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Body; import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.BodyFactory;
import com.fsck.k9.mail.BodyPart; import com.fsck.k9.mail.BodyPart;
import com.fsck.k9.mail.DefaultBodyFactory;
import com.fsck.k9.mail.Message; import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Multipart; import com.fsck.k9.mail.Multipart;
@ -106,7 +108,7 @@ public class MimeMessage extends Message {
// REALLY long References: headers // REALLY long References: headers
parserConfig.setMaxHeaderCount(-1); // Disable the check for header count. parserConfig.setMaxHeaderCount(-1); // Disable the check for header count.
MimeStreamParser parser = new MimeStreamParser(parserConfig); MimeStreamParser parser = new MimeStreamParser(parserConfig);
parser.setContentHandler(new MimeMessageBuilder()); parser.setContentHandler(new MimeMessageBuilder(new DefaultBodyFactory()));
if (recurse) { if (recurse) {
parser.setRecurse(); parser.setRecurse();
} }
@ -520,8 +522,10 @@ public class MimeMessage extends Message {
private class MimeMessageBuilder implements ContentHandler { private class MimeMessageBuilder implements ContentHandler {
private final LinkedList<Object> stack = new LinkedList<>(); private final LinkedList<Object> stack = new LinkedList<>();
private final BodyFactory bodyFactory;
public MimeMessageBuilder() { public MimeMessageBuilder(BodyFactory bodyFactory) {
this.bodyFactory = bodyFactory;
} }
private void expect(Class<?> c) { private void expect(Class<?> c) {
@ -576,7 +580,7 @@ public class MimeMessage extends Message {
@Override @Override
public void body(BodyDescriptor bd, InputStream in) throws IOException, MimeException { public void body(BodyDescriptor bd, InputStream in) throws IOException, MimeException {
expect(Part.class); expect(Part.class);
Body body = MimeUtility.createBody(in, bd.getTransferEncoding(), bd.getMimeType()); Body body = bodyFactory.createBody(bd.getTransferEncoding(), bd.getMimeType(), in);
((Part)stack.peek()).setBody(body); ((Part)stack.peek()).setBody(body);
} }

View file

@ -4,7 +4,6 @@ package com.fsck.k9.mail.internet;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -16,7 +15,7 @@ import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Multipart; import com.fsck.k9.mail.Multipart;
import com.fsck.k9.mail.Part; import com.fsck.k9.mail.Part;
import org.apache.commons.io.IOUtils;
import org.apache.james.mime4j.codec.Base64InputStream; import org.apache.james.mime4j.codec.Base64InputStream;
import org.apache.james.mime4j.codec.QuotedPrintableInputStream; import org.apache.james.mime4j.codec.QuotedPrintableInputStream;
import org.apache.james.mime4j.util.MimeUtil; import org.apache.james.mime4j.util.MimeUtil;
@ -985,30 +984,6 @@ public class MimeUtility {
return isSameMimeType(mimeType, DEFAULT_ATTACHMENT_MIME_TYPE); return isSameMimeType(mimeType, DEFAULT_ATTACHMENT_MIME_TYPE);
} }
public static Body createBody(InputStream in, String contentTransferEncoding, String contentType)
throws IOException {
if (contentTransferEncoding != null) {
contentTransferEncoding = MimeUtility.getHeaderParameter(contentTransferEncoding, null);
}
BinaryTempFileBody tempBody;
if (MimeUtil.isMessage(contentType)) {
tempBody = new BinaryTempFileMessageBody(contentTransferEncoding);
} else {
tempBody = new BinaryTempFileBody(contentTransferEncoding);
}
OutputStream out = tempBody.getOutputStream();
try {
IOUtils.copy(in, out);
} finally {
out.close();
}
return tempBody;
}
/** /**
* Get decoded contents of a body. * Get decoded contents of a body.
* <p/> * <p/>

View file

@ -3,31 +3,31 @@ package com.fsck.k9.mail.store.imap;
import java.io.IOException; import java.io.IOException;
import com.fsck.k9.mail.BodyFactory;
import com.fsck.k9.mail.Part; import com.fsck.k9.mail.Part;
import com.fsck.k9.mail.filter.FixedLengthInputStream; import com.fsck.k9.mail.filter.FixedLengthInputStream;
import com.fsck.k9.mail.internet.MimeHeader; import com.fsck.k9.mail.internet.MimeHeader;
import com.fsck.k9.mail.internet.MimeUtility;
class FetchPartCallback implements ImapResponseCallback { class FetchPartCallback implements ImapResponseCallback {
private Part mPart; private final Part part;
private final BodyFactory bodyFactory;
FetchPartCallback(Part part) {
mPart = part; FetchPartCallback(Part part, BodyFactory bodyFactory) {
this.part = part;
this.bodyFactory = bodyFactory;
} }
@Override @Override
public Object foundLiteral(ImapResponse response, FixedLengthInputStream literal) throws IOException { public Object foundLiteral(ImapResponse response, FixedLengthInputStream literal) throws IOException {
if (response.getTag() == null && if (response.getTag() == null && ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) {
ImapResponseParser.equalsIgnoreCase(response.get(1), "FETCH")) {
//TODO: check for correct UID //TODO: check for correct UID
String contentTransferEncoding = mPart String contentTransferEncoding = part.getHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING)[0];
.getHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING)[0]; String contentType = part.getHeader(MimeHeader.HEADER_CONTENT_TYPE)[0];
String contentType = mPart
.getHeader(MimeHeader.HEADER_CONTENT_TYPE)[0];
return MimeUtility.createBody(literal, contentTransferEncoding, contentType); return bodyFactory.createBody(contentTransferEncoding, contentType, literal);
} }
return null; return null;
} }

View file

@ -19,6 +19,7 @@ import java.util.concurrent.ConcurrentHashMap;
import android.text.TextUtils; import android.text.TextUtils;
import com.fsck.k9.mail.Body; import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.BodyFactory;
import com.fsck.k9.mail.FetchProfile; import com.fsck.k9.mail.FetchProfile;
import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.Folder;
@ -779,8 +780,8 @@ class ImapFolder extends Folder<ImapMessage> {
} }
@Override @Override
public void fetchPart(Message message, Part part, MessageRetrievalListener<Message> listener) public void fetchPart(Message message, Part part, MessageRetrievalListener<Message> listener,
throws MessagingException { BodyFactory bodyFactory) throws MessagingException {
checkOpen(); checkOpen();
String partId = part.getServerExtra(); String partId = part.getServerExtra();
@ -800,7 +801,7 @@ class ImapFolder extends Folder<ImapMessage> {
ImapResponse response; ImapResponse response;
int messageNumber = 0; int messageNumber = 0;
ImapResponseCallback callback = new FetchPartCallback(part); ImapResponseCallback callback = new FetchPartCallback(part, bodyFactory);
do { do {
response = connection.readResponse(callback); response = connection.readResponse(callback);
@ -828,7 +829,7 @@ class ImapFolder extends Folder<ImapMessage> {
if (literal != null) { if (literal != null) {
if (literal instanceof Body) { if (literal instanceof Body) {
// Most of the work was done in FetchAttchmentCallback.foundLiteral() // Most of the work was done in FetchAttachmentCallback.foundLiteral()
MimeMessageHelper.setBody(part, (Body) literal); MimeMessageHelper.setBody(part, (Body) literal);
} else if (literal instanceof String) { } else if (literal instanceof String) {
String bodyString = (String) literal; String bodyString = (String) literal;
@ -837,8 +838,8 @@ class ImapFolder extends Folder<ImapMessage> {
String contentTransferEncoding = String contentTransferEncoding =
part.getHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING)[0]; part.getHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING)[0];
String contentType = part.getHeader(MimeHeader.HEADER_CONTENT_TYPE)[0]; String contentType = part.getHeader(MimeHeader.HEADER_CONTENT_TYPE)[0];
MimeMessageHelper.setBody(part, MimeUtility.createBody(bodyStream, contentTransferEncoding, Body body = bodyFactory.createBody(contentTransferEncoding, contentType, bodyStream);
contentType)); MimeMessageHelper.setBody(part, body);
} else { } else {
// This shouldn't happen // This shouldn't happen
throw new MessagingException("Got FETCH response with bogus parameters"); throw new MessagingException("Got FETCH response with bogus parameters");

View file

@ -12,6 +12,7 @@ import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import com.fsck.k9.mail.Body; import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.DefaultBodyFactory;
import com.fsck.k9.mail.FetchProfile; import com.fsck.k9.mail.FetchProfile;
import com.fsck.k9.mail.FetchProfile.Item; import com.fsck.k9.mail.FetchProfile.Item;
import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Flag;
@ -934,7 +935,7 @@ public class ImapFolderTest {
Part part = createPart("TEXT"); Part part = createPart("TEXT");
when(imapConnection.readResponse(any(ImapResponseCallback.class))).thenReturn(createImapResponse("x OK")); when(imapConnection.readResponse(any(ImapResponseCallback.class))).thenReturn(createImapResponse("x OK"));
folder.fetchPart(message, part, null); folder.fetchPart(message, part, null, null);
verify(imapConnection).sendCommand("UID FETCH 1 (UID BODY.PEEK[TEXT]<0.4096>)", false); verify(imapConnection).sendCommand("UID FETCH 1 (UID BODY.PEEK[TEXT]<0.4096>)", false);
} }
@ -948,7 +949,7 @@ public class ImapFolderTest {
Part part = createPart("1.1"); Part part = createPart("1.1");
when(imapConnection.readResponse(any(ImapResponseCallback.class))).thenReturn(createImapResponse("x OK")); when(imapConnection.readResponse(any(ImapResponseCallback.class))).thenReturn(createImapResponse("x OK"));
folder.fetchPart(message, part, null); folder.fetchPart(message, part, null, null);
verify(imapConnection).sendCommand("UID FETCH 1 (UID BODY.PEEK[1.1])", false); verify(imapConnection).sendCommand("UID FETCH 1 (UID BODY.PEEK[1.1])", false);
} }
@ -962,7 +963,7 @@ public class ImapFolderTest {
Part part = createPlainTextPart("1.1"); Part part = createPlainTextPart("1.1");
setupSingleFetchResponseToCallback(); setupSingleFetchResponseToCallback();
folder.fetchPart(message, part, null); folder.fetchPart(message, part, null, new DefaultBodyFactory());
ArgumentCaptor<Body> bodyArgumentCaptor = ArgumentCaptor.forClass(Body.class); ArgumentCaptor<Body> bodyArgumentCaptor = ArgumentCaptor.forClass(Body.class);
verify(part).setBody(bodyArgumentCaptor.capture()); verify(part).setBody(bodyArgumentCaptor.capture());

View file

@ -69,8 +69,11 @@ import com.fsck.k9.activity.misc.Attachment;
import com.fsck.k9.controller.MessagingController; import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener; import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.controller.SimpleMessagingListener; import com.fsck.k9.controller.SimpleMessagingListener;
import com.fsck.k9.fragment.AttachmentDownloadDialogFragment;
import com.fsck.k9.fragment.ProgressDialogFragment; import com.fsck.k9.fragment.ProgressDialogFragment;
import com.fsck.k9.fragment.ProgressDialogFragment.CancelListener; import com.fsck.k9.fragment.ProgressDialogFragment.CancelListener;
import com.fsck.k9.fragment.AttachmentDownloadDialogFragment;
import com.fsck.k9.fragment.AttachmentDownloadDialogFragment.AttachmentDownloadCancelListener;
import com.fsck.k9.helper.Contacts; import com.fsck.k9.helper.Contacts;
import com.fsck.k9.helper.IdentityHelper; import com.fsck.k9.helper.IdentityHelper;
import com.fsck.k9.helper.MailTo; import com.fsck.k9.helper.MailTo;
@ -101,7 +104,7 @@ import com.fsck.k9.ui.compose.QuotedMessagePresenter;
@SuppressWarnings("deprecation") // TODO get rid of activity dialogs and indeterminate progress bars @SuppressWarnings("deprecation") // TODO get rid of activity dialogs and indeterminate progress bars
public class MessageCompose extends K9Activity implements OnClickListener, public class MessageCompose extends K9Activity implements OnClickListener,
CancelListener, OnFocusChangeListener, OnCryptoModeChangedListener, CancelListener, AttachmentDownloadCancelListener, OnFocusChangeListener, OnCryptoModeChangedListener,
OnOpenPgpInlineChangeListener, OnOpenPgpSignOnlyChangeListener, MessageBuilder.Callback, OnOpenPgpInlineChangeListener, OnOpenPgpSignOnlyChangeListener, MessageBuilder.Callback,
AttachmentPresenter.AttachmentsChangedListener, RecipientPresenter.RecipientsChangedListener { AttachmentPresenter.AttachmentsChangedListener, RecipientPresenter.RecipientsChangedListener {
@ -1053,6 +1056,10 @@ public class MessageCompose extends K9Activity implements OnClickListener,
return false; return false;
} }
@Override
public void onProgressCancel(AttachmentDownloadDialogFragment fragment) {
attachmentPresenter.attachmentProgressDialogCancelled();
}
public void onProgressCancel(ProgressDialogFragment fragment) { public void onProgressCancel(ProgressDialogFragment fragment) {
attachmentPresenter.attachmentProgressDialogCancelled(); attachmentPresenter.attachmentProgressDialogCancelled();

View file

@ -162,7 +162,7 @@ public class AttachmentPresenter {
if (attachmentViewInfo.inlineAttachment) { if (attachmentViewInfo.inlineAttachment) {
continue; continue;
} }
if (!attachmentViewInfo.isContentAvailable) { if (!attachmentViewInfo.isContentAvailable()) {
allPartsAvailable = false; allPartsAvailable = false;
continue; continue;
} }

View file

@ -63,10 +63,13 @@ import com.fsck.k9.controller.MessagingControllerCommands.PendingExpunge;
import com.fsck.k9.controller.MessagingControllerCommands.PendingMarkAllAsRead; import com.fsck.k9.controller.MessagingControllerCommands.PendingMarkAllAsRead;
import com.fsck.k9.controller.MessagingControllerCommands.PendingMoveOrCopy; import com.fsck.k9.controller.MessagingControllerCommands.PendingMoveOrCopy;
import com.fsck.k9.controller.MessagingControllerCommands.PendingSetFlag; import com.fsck.k9.controller.MessagingControllerCommands.PendingSetFlag;
import com.fsck.k9.controller.ProgressBodyFactory.ProgressListener;
import com.fsck.k9.helper.Contacts; import com.fsck.k9.helper.Contacts;
import com.fsck.k9.mail.Address; import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.AuthenticationFailedException; import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.BodyFactory;
import com.fsck.k9.mail.CertificateValidationException; import com.fsck.k9.mail.CertificateValidationException;
import com.fsck.k9.mail.DefaultBodyFactory;
import com.fsck.k9.mail.FetchProfile; import com.fsck.k9.mail.FetchProfile;
import com.fsck.k9.mail.FetchProfile.Item; import com.fsck.k9.mail.FetchProfile.Item;
import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Flag;
@ -1482,8 +1485,9 @@ public class MessagingController {
/* /*
* Now download the parts we're interested in storing. * Now download the parts we're interested in storing.
*/ */
BodyFactory bodyFactory = new DefaultBodyFactory();
for (Part part : viewables) { for (Part part : viewables) {
remoteFolder.fetchPart(message, part, null); remoteFolder.fetchPart(message, part, null, bodyFactory);
} }
// Store the updated message locally // Store the updated message locally
localFolder.appendMessages(Collections.singletonList(message)); localFolder.appendMessages(Collections.singletonList(message));
@ -2551,8 +2555,17 @@ public class MessagingController {
remoteFolder = remoteStore.getFolder(folderName); remoteFolder = remoteStore.getFolder(folderName);
remoteFolder.open(Folder.OPEN_MODE_RW); remoteFolder.open(Folder.OPEN_MODE_RW);
ProgressBodyFactory bodyFactory = new ProgressBodyFactory(new ProgressListener() {
@Override
public void updateProgress(int progress) {
for (MessagingListener listener : getListeners()) {
listener.updateProgress(progress);
}
}
});
Message remoteMessage = remoteFolder.getMessage(message.getUid()); Message remoteMessage = remoteFolder.getMessage(message.getUid());
remoteFolder.fetchPart(remoteMessage, part, null); remoteFolder.fetchPart(remoteMessage, part, null, bodyFactory);
localFolder.addPartToMessage(message, part); localFolder.addPartToMessage(message, part);

View file

@ -73,4 +73,6 @@ public interface MessagingListener {
void remoteSearchFailed(String folder, String err); void remoteSearchFailed(String folder, String err);
void enableProgressIndicator(boolean enable); void enableProgressIndicator(boolean enable);
void updateProgress(int progress);
} }

View file

@ -0,0 +1,44 @@
package com.fsck.k9.controller;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Timer;
import java.util.TimerTask;
import com.fsck.k9.mail.DefaultBodyFactory;
import org.apache.commons.io.output.CountingOutputStream;
class ProgressBodyFactory extends DefaultBodyFactory {
private final ProgressListener progressListener;
ProgressBodyFactory(ProgressListener progressListener) {
this.progressListener = progressListener;
}
@Override
protected void copyData(InputStream inputStream, OutputStream outputStream) throws IOException {
final CountingOutputStream countingOutputStream = new CountingOutputStream(outputStream);
Timer timer = new Timer();
try {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
progressListener.updateProgress(countingOutputStream.getCount());
}
}, 0, 50);
super.copyData(inputStream, countingOutputStream);
} finally {
timer.cancel();
}
}
interface ProgressListener {
void updateProgress(int progress);
}
}

View file

@ -181,4 +181,9 @@ public abstract class SimpleMessagingListener implements MessagingListener {
@Override @Override
public void enableProgressIndicator(boolean enable) { public void enableProgressIndicator(boolean enable) {
} }
@Override
public void updateProgress(int progress) {
}
} }

View file

@ -0,0 +1,84 @@
package com.fsck.k9.fragment;
import android.app.Activity;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.controller.SimpleMessagingListener;
public class AttachmentDownloadDialogFragment extends DialogFragment {
private static final String ARG_SIZE = "size";
private static final String ARG_MESSAGE = "message";
private ProgressDialog dialog;
private MessagingListener messagingListener;
private MessagingController messagingController;
public static AttachmentDownloadDialogFragment newInstance(int size, String message) {
AttachmentDownloadDialogFragment fragment = new AttachmentDownloadDialogFragment();
Bundle args = new Bundle();
args.putInt(ARG_SIZE, size);
args.putString(ARG_MESSAGE, message);
fragment.setArguments(args);
return fragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Bundle args = getArguments();
int size = args.getInt(ARG_SIZE);
String message = args.getString(ARG_MESSAGE);
messagingListener = new SimpleMessagingListener() {
@Override
public void updateProgress(int progress) {
dialog.setProgress(progress);
}
};
messagingController = MessagingController.getInstance(getActivity());
messagingController.addListener(messagingListener);
dialog = new ProgressDialog(getActivity());
dialog.setMessage(message);
dialog.setMax(size);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setProgress(0);
dialog.show();
return dialog;
}
@Override
public void onDestroyView() {
messagingController.removeListener(messagingListener);
super.onDestroyView();
}
@Override
public void onCancel(DialogInterface dialog) {
Activity activity = getActivity();
if (activity != null && activity instanceof AttachmentDownloadCancelListener) {
AttachmentDownloadCancelListener listener = (AttachmentDownloadCancelListener) activity;
listener.onProgressCancel(this);
}
super.onCancel(dialog);
}
public interface AttachmentDownloadCancelListener {
void onProgressCancel(AttachmentDownloadDialogFragment fragment);
}
}

View file

@ -21,16 +21,24 @@ public class AttachmentViewInfo {
public final Uri internalUri; public final Uri internalUri;
public final boolean inlineAttachment; public final boolean inlineAttachment;
public final Part part; public final Part part;
public final boolean isContentAvailable; private boolean contentAvailable;
public AttachmentViewInfo(String mimeType, String displayName, long size, Uri internalUri, boolean inlineAttachment, public AttachmentViewInfo(String mimeType, String displayName, long size, Uri internalUri, boolean inlineAttachment,
Part part, boolean isContentAvailable) { Part part, boolean contentAvailable) {
this.mimeType = mimeType; this.mimeType = mimeType;
this.displayName = displayName; this.displayName = displayName;
this.size = size; this.size = size;
this.internalUri = internalUri; this.internalUri = internalUri;
this.inlineAttachment = inlineAttachment; this.inlineAttachment = inlineAttachment;
this.part = part; this.part = part;
this.isContentAvailable = isContentAvailable; this.contentAvailable = contentAvailable;
}
public boolean isContentAvailable() {
return contentAvailable;
}
public void setContentAvailable() {
this.contentAvailable = true;
} }
} }

View file

@ -57,7 +57,7 @@ public class AttachmentController {
} }
public void viewAttachment() { public void viewAttachment() {
if (!attachment.isContentAvailable) { if (!attachment.isContentAvailable()) {
downloadAndViewAttachment((LocalPart) attachment.part); downloadAndViewAttachment((LocalPart) attachment.part);
} else { } else {
viewLocalAttachment(); viewLocalAttachment();
@ -100,6 +100,7 @@ public class AttachmentController {
controller.loadAttachment(account, message, attachment.part, new SimpleMessagingListener() { controller.loadAttachment(account, message, attachment.part, new SimpleMessagingListener() {
@Override @Override
public void loadAttachmentFinished(Account account, Message message, Part part) { public void loadAttachmentFinished(Account account, Message message, Part part) {
attachment.setContentAvailable();
messageViewFragment.hideAttachmentLoadingDialogOnMainThread(); messageViewFragment.hideAttachmentLoadingDialogOnMainThread();
messageViewFragment.runOnMainThread(attachmentDownloadedCallback); messageViewFragment.runOnMainThread(attachmentDownloadedCallback);
} }
@ -129,7 +130,7 @@ public class AttachmentController {
return; return;
} }
if (!attachment.isContentAvailable) { if (!attachment.isContentAvailable()) {
downloadAndSaveAttachmentTo((LocalPart) attachment.part, directory); downloadAndSaveAttachmentTo((LocalPart) attachment.part, directory);
} else { } else {
saveLocalAttachmentTo(directory); saveLocalAttachmentTo(directory);

View file

@ -18,7 +18,6 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Parcelable; import android.os.Parcelable;
import android.text.TextUtils; import android.text.TextUtils;
import timber.log.Timber;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -36,21 +35,22 @@ import com.fsck.k9.activity.ChooseFolder;
import com.fsck.k9.activity.MessageLoaderHelper; import com.fsck.k9.activity.MessageLoaderHelper;
import com.fsck.k9.activity.MessageLoaderHelper.MessageLoaderCallbacks; import com.fsck.k9.activity.MessageLoaderHelper.MessageLoaderCallbacks;
import com.fsck.k9.activity.MessageReference; import com.fsck.k9.activity.MessageReference;
import com.fsck.k9.activity.setup.OpenPgpAppSelectDialog;
import com.fsck.k9.controller.MessagingController; import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.fragment.AttachmentDownloadDialogFragment;
import com.fsck.k9.fragment.ConfirmationDialogFragment; import com.fsck.k9.fragment.ConfirmationDialogFragment;
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener; import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
import com.fsck.k9.fragment.ProgressDialogFragment;
import com.fsck.k9.helper.FileBrowserHelper; import com.fsck.k9.helper.FileBrowserHelper;
import com.fsck.k9.helper.FileBrowserHelper.FileBrowserFailOverCallback; import com.fsck.k9.helper.FileBrowserHelper.FileBrowserFailOverCallback;
import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Flag;
import com.fsck.k9.mailstore.AttachmentViewInfo; import com.fsck.k9.mailstore.AttachmentViewInfo;
import com.fsck.k9.mailstore.LocalMessage; import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.mailstore.MessageViewInfo; import com.fsck.k9.mailstore.MessageViewInfo;
import com.fsck.k9.activity.setup.OpenPgpAppSelectDialog;
import com.fsck.k9.ui.messageview.CryptoInfoDialog.OnClickShowCryptoKeyListener; import com.fsck.k9.ui.messageview.CryptoInfoDialog.OnClickShowCryptoKeyListener;
import com.fsck.k9.ui.messageview.MessageCryptoPresenter.MessageCryptoMvpView; import com.fsck.k9.ui.messageview.MessageCryptoPresenter.MessageCryptoMvpView;
import com.fsck.k9.view.MessageCryptoDisplayStatus; import com.fsck.k9.view.MessageCryptoDisplayStatus;
import com.fsck.k9.view.MessageHeader; import com.fsck.k9.view.MessageHeader;
import timber.log.Timber;
public class MessageViewFragment extends Fragment implements ConfirmationDialogFragmentListener, public class MessageViewFragment extends Fragment implements ConfirmationDialogFragmentListener,
@ -534,7 +534,8 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
} }
case R.id.dialog_attachment_progress: { case R.id.dialog_attachment_progress: {
String message = getString(R.string.dialog_attachment_progress_title); String message = getString(R.string.dialog_attachment_progress_title);
fragment = ProgressDialogFragment.newInstance(null, message); int size = (int) currentAttachmentViewInfo.size;
fragment = AttachmentDownloadDialogFragment.newInstance(size, message);
break; break;
} }
default: { default: {
@ -795,22 +796,18 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
@Override @Override
public void onViewAttachment(AttachmentViewInfo attachment) { public void onViewAttachment(AttachmentViewInfo attachment) {
//TODO: check if we have to download the attachment first currentAttachmentViewInfo = attachment;
getAttachmentController(attachment).viewAttachment(); getAttachmentController(attachment).viewAttachment();
} }
@Override @Override
public void onSaveAttachment(AttachmentViewInfo attachment) { public void onSaveAttachment(AttachmentViewInfo attachment) {
//TODO: check if we have to download the attachment first currentAttachmentViewInfo = attachment;
getAttachmentController(attachment).saveAttachment(); getAttachmentController(attachment).saveAttachment();
} }
@Override @Override
public void onSaveAttachmentToUserProvidedDirectory(final AttachmentViewInfo attachment) { public void onSaveAttachmentToUserProvidedDirectory(final AttachmentViewInfo attachment) {
//TODO: check if we have to download the attachment first
currentAttachmentViewInfo = attachment; currentAttachmentViewInfo = attachment;
FileBrowserHelper.getInstance().showFileBrowserActivity(MessageViewFragment.this, null, FileBrowserHelper.getInstance().showFileBrowserActivity(MessageViewFragment.this, null,
ACTIVITY_CHOOSE_DIRECTORY, new FileBrowserFailOverCallback() { ACTIVITY_CHOOSE_DIRECTORY, new FileBrowserFailOverCallback() {

View file

@ -168,7 +168,7 @@ public class AttachmentInfoExtractorTest {
AttachmentViewInfo attachmentViewInfo = attachmentInfoExtractor.extractAttachmentInfoForDatabase(part); AttachmentViewInfo attachmentViewInfo = attachmentInfoExtractor.extractAttachmentInfoForDatabase(part);
assertFalse(attachmentViewInfo.isContentAvailable); assertFalse(attachmentViewInfo.isContentAvailable());
} }
@Test @Test
@ -178,7 +178,7 @@ public class AttachmentInfoExtractorTest {
AttachmentViewInfo attachmentViewInfo = attachmentInfoExtractor.extractAttachmentInfoForDatabase(part); AttachmentViewInfo attachmentViewInfo = attachmentInfoExtractor.extractAttachmentInfoForDatabase(part);
assertTrue(attachmentViewInfo.isContentAvailable); assertTrue(attachmentViewInfo.isContentAvailable());
} }
@Test @Test
@ -206,6 +206,6 @@ public class AttachmentInfoExtractorTest {
assertEquals(TEST_SIZE, attachmentViewInfo.size); assertEquals(TEST_SIZE, attachmentViewInfo.size);
assertEquals(TEST_MIME_TYPE, attachmentViewInfo.mimeType); assertEquals(TEST_MIME_TYPE, attachmentViewInfo.mimeType);
assertFalse(attachmentViewInfo.inlineAttachment); assertFalse(attachmentViewInfo.inlineAttachment);
assertTrue(attachmentViewInfo.isContentAvailable); assertTrue(attachmentViewInfo.isContentAvailable());
} }
} }