Download missing parts before viewing or saving

This commit is contained in:
cketti 2015-01-18 03:35:28 +01:00
parent 585d9cbe7f
commit 9363c5b276
9 changed files with 161 additions and 69 deletions

View File

@ -3144,40 +3144,8 @@ public class MessagingController implements Runnable {
}
}
/**
* Attempts to load the attachment specified by part from the given account and message.
* @param account
* @param message
* @param part
* @param listener
*/
public void loadAttachment(
final Account account,
final Message message,
final Part part,
final Object tag,
final MessagingListener listener) {
/*
* Check if the attachment has already been downloaded. If it has there's no reason to
* download it, so we just tell the listener that it's ready to go.
*/
if (part.getBody() != null) {
for (MessagingListener l : getListeners(listener)) {
l.loadAttachmentStarted(account, message, part, tag, false);
}
for (MessagingListener l : getListeners(listener)) {
l.loadAttachmentFinished(account, message, part, tag);
}
return;
}
for (MessagingListener l : getListeners(listener)) {
l.loadAttachmentStarted(account, message, part, tag, true);
}
public void loadAttachment(final Account account, final LocalMessage message, final Part part,
final MessagingListener listener) {
put("loadAttachment", listener, new Runnable() {
@Override
@ -3185,32 +3153,29 @@ public class MessagingController implements Runnable {
Folder remoteFolder = null;
LocalFolder localFolder = null;
try {
LocalStore localStore = account.getLocalStore();
String folderName = message.getFolder().getName();
LocalStore localStore = account.getLocalStore();
localFolder = localStore.getFolder(folderName);
List<Part> attachments = MessageExtractor.collectAttachments(message);
for (Part attachment : attachments) {
attachment.setBody(null);
}
Store remoteStore = account.getRemoteStore();
localFolder = localStore.getFolder(message.getFolder().getName());
remoteFolder = remoteStore.getFolder(message.getFolder().getName());
remoteFolder = remoteStore.getFolder(folderName);
remoteFolder.open(Folder.OPEN_MODE_RW);
//FIXME: This is an ugly hack that won't be needed once the Message objects have been united.
Message remoteMessage = remoteFolder.getMessage(message.getUid());
MimeMessageHelper.setBody(remoteMessage, message.getBody());
remoteFolder.fetchPart(remoteMessage, part, null);
localFolder.addPartToMessage((LocalMessage) message, part);
localFolder.addPartToMessage(message, part);
for (MessagingListener l : getListeners(listener)) {
l.loadAttachmentFinished(account, message, part, tag);
l.loadAttachmentFinished(account, message, part);
}
} catch (MessagingException me) {
if (K9.DEBUG)
Log.v(K9.LOG_TAG, "Exception loading attachment", me);
for (MessagingListener l : getListeners(listener)) {
l.loadAttachmentFailed(account, message, part, tag, me.getMessage());
l.loadAttachmentFailed(account, message, part, me.getMessage());
}
notifyUserIfCertificateProblem(context, me, account, true);
addErrorMessage(account, null, me);

View File

@ -133,13 +133,9 @@ public class MessagingListener {
public void setPushActive(Account account, String folderName, boolean enabled) {}
public void loadAttachmentStarted(Account account, Message message, Part part, Object tag,
boolean requiresDownload) {}
public void loadAttachmentFinished(Account account, Message message, Part part) {}
public void loadAttachmentFinished(Account account, Message message, Part part, Object tag) {}
public void loadAttachmentFailed(Account account, Message message, Part part, Object tag,
String reason) {}
public void loadAttachmentFailed(Account account, Message message, Part part, String reason) {}

View File

@ -7,15 +7,17 @@ import com.fsck.k9.mail.internet.MimeBodyPart;
public class LocalBodyPart extends MimeBodyPart implements LocalPart {
private final String accountUuid;
private final LocalMessage message;
private final long messagePartId;
private final String displayName;
private final long size;
private final boolean firstClassAttachment;
public LocalBodyPart(String accountUuid, long messagePartId, String displayName, long size,
public LocalBodyPart(String accountUuid, LocalMessage message, long messagePartId, String displayName, long size,
boolean firstClassAttachment) throws MessagingException {
super();
this.accountUuid = accountUuid;
this.message = message;
this.messagePartId = messagePartId;
this.displayName = displayName;
this.size = size;
@ -46,4 +48,9 @@ public class LocalBodyPart extends MimeBodyPart implements LocalPart {
public boolean isFirstClassAttachment() {
return firstClassAttachment;
}
@Override
public LocalMessage getMessage() {
return message;
}
}

View File

@ -689,7 +689,8 @@ public class LocalFolder extends Folder<LocalMessage> implements Serializable {
String parentMimeType = parentPart.getMimeType();
if (parentMimeType.startsWith("multipart/")) {
BodyPart bodyPart = new LocalBodyPart(getAccountUuid(), id, displayName, size, firstClassAttachment);
BodyPart bodyPart = new LocalBodyPart(getAccountUuid(), message, id, displayName, size,
firstClassAttachment);
((Multipart) parentPart.getBody()).addBodyPart(bodyPart);
part = bodyPart;
} else if (parentMimeType.startsWith("message/")) {

View File

@ -7,4 +7,5 @@ public interface LocalPart {
String getDisplayName();
long getSize();
boolean isFirstClassAttachment();
LocalMessage getMessage();
}

View File

@ -19,29 +19,44 @@ import android.os.Environment;
import android.util.Log;
import android.widget.Toast;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.Preferences;
import com.fsck.k9.R;
import com.fsck.k9.cache.TemporaryAttachmentStore;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.helper.FileHelper;
import com.fsck.k9.helper.MediaScannerNotifier;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.Part;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mailstore.AttachmentViewInfo;
import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.mailstore.LocalPart;
import org.apache.commons.io.IOUtils;
public class AttachmentController {
private final Context context;
private final SingleMessageView messageView;
private final MessagingController controller;
private final MessageViewFragment messageViewFragment;
private final AttachmentViewInfo attachment;
AttachmentController(SingleMessageView messageView, AttachmentViewInfo attachment) {
this.context = messageView.getContext();
this.messageView = messageView;
AttachmentController(MessagingController controller, MessageViewFragment messageViewFragment,
AttachmentViewInfo attachment) {
this.context = messageViewFragment.getContext();
this.controller = controller;
this.messageViewFragment = messageViewFragment;
this.attachment = attachment;
}
public void viewAttachment() {
new ViewAttachmentAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
if (needsDownloading()) {
downloadAndViewAttachment((LocalPart) attachment.part);
} else {
viewLocalAttachment();
}
}
public void saveAttachment() {
@ -52,6 +67,60 @@ public class AttachmentController {
saveAttachmentTo(new File(directory));
}
private boolean needsDownloading() {
return isPartMissing() && isLocalPart();
}
private boolean isPartMissing() {
return attachment.part.getBody() == null;
}
private boolean isLocalPart() {
return attachment.part instanceof LocalPart;
}
private void downloadAndViewAttachment(LocalPart localPart) {
downloadAttachment(localPart, new Runnable() {
@Override
public void run() {
viewLocalAttachment();
}
});
}
private void downloadAndSaveAttachmentTo(LocalPart localPart, final File directory) {
downloadAttachment(localPart, new Runnable() {
@Override
public void run() {
saveAttachmentTo(directory);
}
});
}
private void downloadAttachment(LocalPart localPart, final Runnable attachmentDownloadedCallback) {
String accountUuid = localPart.getAccountUuid();
Account account = Preferences.getPreferences(context).getAccount(accountUuid);
LocalMessage message = localPart.getMessage();
messageViewFragment.showAttachmentLoadingDialog();
controller.loadAttachment(account, message, attachment.part, new MessagingListener() {
@Override
public void loadAttachmentFinished(Account account, Message message, Part part) {
messageViewFragment.hideAttachmentLoadingDialogOnMainThread();
messageViewFragment.runOnMainThread(attachmentDownloadedCallback);
}
@Override
public void loadAttachmentFailed(Account account, Message message, Part part, String reason) {
messageViewFragment.hideAttachmentLoadingDialogOnMainThread();
}
});
}
private void viewLocalAttachment() {
new ViewAttachmentAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void saveAttachmentTo(File directory) {
boolean isExternalStorageMounted = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
if (!isExternalStorageMounted) {
@ -60,6 +129,14 @@ public class AttachmentController {
return;
}
if (needsDownloading()) {
downloadAndSaveAttachmentTo((LocalPart) attachment.part, directory);
} else {
saveLocalAttachmentTo(directory);
}
}
private void saveLocalAttachmentTo(File directory) {
//FIXME: write file in background thread
try {
File file = saveAttachmentWithUniqueFileName(directory);
@ -187,7 +264,7 @@ public class AttachmentController {
}
private void addUiIntentFlags(Intent intent) {
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
}
private int getResolvedIntentActivitiesCount(Intent intent) {
@ -243,7 +320,7 @@ public class AttachmentController {
@Override
protected void onPreExecute() {
messageView.disableAttachmentViewButton(attachment);
messageViewFragment.disableAttachmentButtons(attachment);
}
@Override
@ -254,7 +331,7 @@ public class AttachmentController {
@Override
protected void onPostExecute(Intent intent) {
viewAttachment(intent);
messageView.enableAttachmentViewButton(attachment);
messageViewFragment.enableAttachmentButtons(attachment);
}
private void viewAttachment(Intent intent) {

View File

@ -43,12 +43,14 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
return attachment;
}
public void enableViewButton() {
public void enableButtons() {
viewButton.setEnabled(true);
downloadButton.setEnabled(true);
}
public void disableViewButton() {
public void disableButtons() {
viewButton.setEnabled(false);
downloadButton.setEnabled(false);
}
public void setAttachment(AttachmentViewInfo attachment) throws MessagingException {

View File

@ -663,6 +663,37 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
}
}
public Context getContext() {
return mContext;
}
public void disableAttachmentButtons(AttachmentViewInfo attachment) {
mMessageView.disableAttachmentButtons(attachment);
}
public void enableAttachmentButtons(AttachmentViewInfo attachment) {
mMessageView.enableAttachmentButtons(attachment);
}
public void runOnMainThread(Runnable runnable) {
handler.post(runnable);
}
public void showAttachmentLoadingDialog() {
mMessageView.disableAttachmentButtons();
showDialog(R.id.dialog_attachment_progress);
}
public void hideAttachmentLoadingDialogOnMainThread() {
handler.post(new Runnable() {
@Override
public void run() {
removeDialog(R.id.dialog_attachment_progress);
mMessageView.enableAttachmentButtons();
}
});
}
public interface MessageViewFragmentListener {
public void onForward(LocalMessage mMessage, PgpData mPgpData);
public void disableDeleteAction();
@ -760,7 +791,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
}
private AttachmentController getAttachmentController(AttachmentViewInfo attachment) {
return new AttachmentController(mMessageView, attachment);
return new AttachmentController(mController, this, attachment);
}
private class DownloadMessageListener extends MessagingListener {

View File

@ -500,6 +500,18 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
}
}
public void enableAttachmentButtons() {
for (AttachmentView attachmentView : attachments.values()) {
attachmentView.enableButtons();
}
}
public void disableAttachmentButtons() {
for (AttachmentView attachmentView : attachments.values()) {
attachmentView.disableButtons();
}
}
public void showAllHeaders() {
mHeaderContainer.onShowAdditionalHeaders();
}
@ -701,12 +713,12 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
}
}
public void enableAttachmentViewButton(AttachmentViewInfo attachment) {
getAttachmentView(attachment).enableViewButton();
public void enableAttachmentButtons(AttachmentViewInfo attachment) {
getAttachmentView(attachment).enableButtons();
}
public void disableAttachmentViewButton(AttachmentViewInfo attachment) {
getAttachmentView(attachment).disableViewButton();
public void disableAttachmentButtons(AttachmentViewInfo attachment) {
getAttachmentView(attachment).disableButtons();
}
private AttachmentView getAttachmentView(AttachmentViewInfo attachment) {