mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-27 11:42:16 -05:00
Use a Loader to extract text of a message in a background thread
This commit is contained in:
parent
78ed2a23b1
commit
2e05127c97
@ -467,4 +467,10 @@ public class LocalMessageExtractor {
|
||||
}
|
||||
return new ViewableContainer(text, html, attachments);
|
||||
}
|
||||
|
||||
public static MessageViewInfo decodeMessageForView(Context context, Message message) throws MessagingException {
|
||||
//TODO: Modify extractTextAndAttachments() to only extract the text type (plain vs. HTML) we currently need.
|
||||
ViewableContainer viewable = LocalMessageExtractor.extractTextAndAttachments(context, message);
|
||||
return new MessageViewInfo(viewable.html, viewable.attachments, message);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package com.fsck.k9.mailstore;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.Part;
|
||||
|
||||
|
||||
public class MessageViewInfo {
|
||||
public final String text;
|
||||
public final List<Part> attachments;
|
||||
public final Message message;
|
||||
|
||||
public MessageViewInfo(String text, List<Part> attachments, Message message) {
|
||||
this.text = text;
|
||||
this.attachments = Collections.unmodifiableList(attachments);
|
||||
this.message = message;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.fsck.k9.ui.message;
|
||||
|
||||
|
||||
import android.content.AsyncTaskLoader;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mailstore.LocalMessageExtractor;
|
||||
import com.fsck.k9.mailstore.MessageViewInfo;
|
||||
|
||||
|
||||
public class DecodeMessageLoader extends AsyncTaskLoader<MessageViewInfo> {
|
||||
private final Message message;
|
||||
private MessageViewInfo messageViewInfo;
|
||||
|
||||
public DecodeMessageLoader(Context context, Message message) {
|
||||
super(context);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
if (messageViewInfo != null) {
|
||||
super.deliverResult(messageViewInfo);
|
||||
}
|
||||
|
||||
if (takeContentChanged() || messageViewInfo == null) {
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(MessageViewInfo messageViewInfo) {
|
||||
this.messageViewInfo = messageViewInfo;
|
||||
super.deliverResult(messageViewInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageViewInfo loadInBackground() {
|
||||
try {
|
||||
return LocalMessageExtractor.decodeMessageForView(getContext(), message);
|
||||
} catch (Exception e) {
|
||||
Log.e(K9.LOG_TAG, "Error while decoding message", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -44,6 +44,8 @@ import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.Part;
|
||||
import com.fsck.k9.mailstore.LocalMessage;
|
||||
import com.fsck.k9.mailstore.MessageViewInfo;
|
||||
import com.fsck.k9.ui.message.DecodeMessageLoader;
|
||||
import com.fsck.k9.ui.message.LocalMessageLoader;
|
||||
import com.fsck.k9.view.AttachmentView;
|
||||
import com.fsck.k9.view.AttachmentView.AttachmentFileDownloadCallback;
|
||||
@ -65,6 +67,7 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
private static final int ACTIVITY_CHOOSE_DIRECTORY = 3;
|
||||
|
||||
private static final int LOCAL_MESSAGE_LOADER_ID = 1;
|
||||
private static final int DECODE_MESSAGE_LOADER_ID = 2;
|
||||
|
||||
|
||||
public static MessageViewFragment newInstance(MessageReference reference) {
|
||||
@ -112,6 +115,8 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
private Context mContext;
|
||||
|
||||
private LoaderCallbacks<LocalMessage> localMessageLoaderCallback = new LocalMessageLoaderCallback();
|
||||
private LoaderCallbacks<MessageViewInfo> decodeMessageLoaderCallback = new DecodeMessageLoaderCallback();
|
||||
private MessageViewInfo messageViewInfo;
|
||||
|
||||
|
||||
class MessageViewHandler extends Handler {
|
||||
@ -301,11 +306,19 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
}
|
||||
|
||||
private void startExtractingTextAndAttachments(LocalMessage message) {
|
||||
//TODO: extract in background thread
|
||||
getLoaderManager().initLoader(DECODE_MESSAGE_LOADER_ID, null, decodeMessageLoaderCallback);
|
||||
}
|
||||
|
||||
private void onDecodeMessageFinished(MessageViewInfo messageContainer) {
|
||||
//TODO: handle decryption and signature verification
|
||||
this.messageViewInfo = messageContainer;
|
||||
showMessage(messageContainer);
|
||||
}
|
||||
|
||||
private void showMessage(MessageViewInfo messageContainer) {
|
||||
try {
|
||||
mMessageView.setMessage(mAccount, message, mPgpData, mController, mListener);
|
||||
mMessageView.setShowDownloadButton(message);
|
||||
mMessageView.setMessage(mAccount, messageContainer, mPgpData, mController, mListener);
|
||||
mMessageView.setShowDownloadButton(mMessage);
|
||||
} catch (MessagingException e) {
|
||||
Log.e(K9.LOG_TAG, "Error while trying to display message", e);
|
||||
}
|
||||
@ -656,7 +669,7 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
PgpData data = new PgpData();
|
||||
data.setDecryptedData(decryptedData);
|
||||
data.setSignatureResult(signatureResult);
|
||||
mMessageView.setMessage(mAccount, (LocalMessage) mMessage, data, mController, mListener);
|
||||
mMessageView.setMessage(mAccount, messageViewInfo, data, mController, mListener);
|
||||
} catch (MessagingException e) {
|
||||
Log.e(K9.LOG_TAG, "displayMessageBody failed", e);
|
||||
}
|
||||
@ -809,11 +822,13 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
class LocalMessageLoaderCallback implements LoaderCallbacks<LocalMessage> {
|
||||
@Override
|
||||
public Loader<LocalMessage> onCreateLoader(int id, Bundle args) {
|
||||
setProgress(true);
|
||||
return new LocalMessageLoader(mContext, mController, mAccount, mMessageReference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<LocalMessage> loader, LocalMessage message) {
|
||||
setProgress(false);
|
||||
mMessage = message;
|
||||
if (message == null) {
|
||||
onLoadMessageFromDatabaseFailed();
|
||||
@ -827,4 +842,23 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
class DecodeMessageLoaderCallback implements LoaderCallbacks<MessageViewInfo> {
|
||||
@Override
|
||||
public Loader<MessageViewInfo> onCreateLoader(int id, Bundle args) {
|
||||
setProgress(true);
|
||||
return new DecodeMessageLoader(mContext, mMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<MessageViewInfo> loader, MessageViewInfo messageContainer) {
|
||||
setProgress(false);
|
||||
onDecodeMessageFinished(messageContainer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<MessageViewInfo> loader) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -52,13 +52,9 @@ import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Flag;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.Multipart;
|
||||
import com.fsck.k9.mail.Part;
|
||||
import com.fsck.k9.mail.internet.MimeUtility;
|
||||
import com.fsck.k9.mailstore.LocalAttachmentBodyPart;
|
||||
import com.fsck.k9.mailstore.LocalMessage;
|
||||
import com.fsck.k9.mailstore.LocalMessageExtractor;
|
||||
import com.fsck.k9.mailstore.ViewableContainer;
|
||||
import com.fsck.k9.mailstore.MessageViewInfo;
|
||||
import com.fsck.k9.provider.AttachmentProvider.AttachmentProviderColumns;
|
||||
|
||||
import com.fsck.k9.view.AttachmentView;
|
||||
@ -502,7 +498,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
|
||||
return mHeaderContainer.additionalHeadersVisible();
|
||||
}
|
||||
|
||||
public void setMessage(Account account, LocalMessage message, PgpData pgpData,
|
||||
public void setMessage(Account account, MessageViewInfo messageViewInfo, PgpData pgpData,
|
||||
MessagingController controller, MessagingListener listener) throws MessagingException {
|
||||
resetView();
|
||||
|
||||
@ -515,18 +511,16 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
|
||||
}
|
||||
|
||||
if (text == null) {
|
||||
//FIXME: Run the text extraction in a background thread because it might involve disk I/O
|
||||
ViewableContainer viewables = LocalMessageExtractor.extractTextAndAttachments(getContext(), message);
|
||||
text = viewables.html;
|
||||
text = messageViewInfo.text;
|
||||
}
|
||||
|
||||
// Save the text so we can reset the WebView when the user clicks the "Show pictures" button
|
||||
mText = text;
|
||||
|
||||
mHasAttachments = message.hasAttachments();
|
||||
mHasAttachments = !messageViewInfo.attachments.isEmpty();
|
||||
|
||||
if (mHasAttachments) {
|
||||
renderAttachments(message, 0, message, account, controller, listener);
|
||||
renderAttachments(messageViewInfo, account, controller, listener);
|
||||
}
|
||||
|
||||
mHiddenAttachments.setVisibility(View.GONE);
|
||||
@ -558,7 +552,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
|
||||
// button wasn't already pressed, see if the user's preferences has us
|
||||
// showing them anyway.
|
||||
if (Utility.hasExternalImages(text) && !showPictures()) {
|
||||
Address[] from = message.getFrom();
|
||||
Address[] from = messageViewInfo.message.getFrom();
|
||||
if ((account.getShowPictures() == Account.ShowPictures.ALWAYS) ||
|
||||
((account.getShowPictures() == Account.ShowPictures.ONLY_FROM_CONTACTS) &&
|
||||
// Make sure we have at least one from address
|
||||
@ -574,7 +568,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
|
||||
if (text != null) {
|
||||
loadBodyFromText(text);
|
||||
mOpenPgpView.updateLayout(account, pgpData.getDecryptedData(),
|
||||
pgpData.getSignatureResult(), message);
|
||||
pgpData.getSignatureResult(), messageViewInfo.message);
|
||||
} else {
|
||||
showStatusMessage(getContext().getString(R.string.webview_empty_message));
|
||||
}
|
||||
@ -613,26 +607,20 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
|
||||
}
|
||||
}
|
||||
|
||||
public void renderAttachments(Part part, int depth, Message message, Account account,
|
||||
MessagingController controller, MessagingListener listener) throws MessagingException {
|
||||
public void renderAttachments(MessageViewInfo messageContainer, Account account, MessagingController controller,
|
||||
MessagingListener listener) throws MessagingException {
|
||||
|
||||
if (part.getBody() instanceof Multipart) {
|
||||
Multipart mp = (Multipart) part.getBody();
|
||||
for (int i = 0; i < mp.getCount(); i++) {
|
||||
renderAttachments(mp.getBodyPart(i), depth + 1, message, account, controller, listener);
|
||||
}
|
||||
} else if (part instanceof LocalAttachmentBodyPart) {
|
||||
AttachmentView view = (AttachmentView)mInflater.inflate(R.layout.message_view_attachment, null);
|
||||
for (Part attachment : messageContainer.attachments) {
|
||||
AttachmentView view = (AttachmentView) mInflater.inflate(R.layout.message_view_attachment, null);
|
||||
view.setCallback(attachmentCallback);
|
||||
|
||||
try {
|
||||
if (view.populateFromPart(part, message, account, controller, listener)) {
|
||||
addAttachment(view);
|
||||
} else {
|
||||
addHiddenAttachment(view);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(K9.LOG_TAG, "Error adding attachment view", e);
|
||||
boolean isFirstClassAttachment = view.populateFromPart(attachment, messageContainer.message, account,
|
||||
controller, listener);
|
||||
|
||||
if (isFirstClassAttachment) {
|
||||
addAttachment(view);
|
||||
} else {
|
||||
addHiddenAttachment(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,7 @@ package com.fsck.k9.view;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
@ -14,7 +11,6 @@ import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Environment;
|
||||
@ -43,15 +39,12 @@ import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mail.Part;
|
||||
import com.fsck.k9.mail.internet.MimeHeader;
|
||||
import com.fsck.k9.mail.internet.MimeUtility;
|
||||
import com.fsck.k9.mailstore.LocalAttachmentBodyPart;
|
||||
import com.fsck.k9.provider.AttachmentProvider;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
|
||||
public class AttachmentView extends FrameLayout implements OnClickListener, OnLongClickListener {
|
||||
private Context context;
|
||||
private Message message;
|
||||
private LocalAttachmentBodyPart part;
|
||||
private Part part;
|
||||
private Account account;
|
||||
private MessagingController controller;
|
||||
private MessagingListener listener;
|
||||
@ -96,10 +89,10 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
|
||||
*
|
||||
* @return {@code true} for a regular attachment. {@code false} for attachments that should be initially hidden.
|
||||
*/
|
||||
public boolean populateFromPart(Part inputPart, Message message, Account account,
|
||||
public boolean populateFromPart(Part part, Message message, Account account,
|
||||
MessagingController controller, MessagingListener listener) throws MessagingException {
|
||||
|
||||
part = (LocalAttachmentBodyPart) inputPart;
|
||||
this.part = part;
|
||||
this.message = message;
|
||||
this.account = account;
|
||||
this.controller = controller;
|
||||
@ -247,19 +240,21 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
|
||||
}
|
||||
|
||||
private void writeAttachmentToStorage(File file) throws IOException {
|
||||
Uri uri = AttachmentProvider.getAttachmentUri(account, part.getAttachmentId());
|
||||
InputStream in = context.getContentResolver().openInputStream(uri);
|
||||
try {
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
try {
|
||||
IOUtils.copy(in, out);
|
||||
out.flush();
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
//FIXME
|
||||
throw new RuntimeException("temporarily disabled");
|
||||
// Uri uri = AttachmentProvider.getAttachmentUri(account, part.getAttachmentId());
|
||||
// InputStream in = context.getContentResolver().openInputStream(uri);
|
||||
// try {
|
||||
// OutputStream out = new FileOutputStream(file);
|
||||
// try {
|
||||
// IOUtils.copy(in, out);
|
||||
// out.flush();
|
||||
// } finally {
|
||||
// out.close();
|
||||
// }
|
||||
// } finally {
|
||||
// in.close();
|
||||
// }
|
||||
}
|
||||
|
||||
public void showFile() {
|
||||
@ -323,14 +318,16 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
|
||||
}
|
||||
|
||||
private Intent createViewIntentForAttachmentProviderUri(String mimeType) {
|
||||
Uri uri = AttachmentProvider.getAttachmentUriForViewing(account, part.getAttachmentId(), mimeType, name);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(uri, mimeType);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
addUiIntentFlags(intent);
|
||||
|
||||
return intent;
|
||||
//FIXME
|
||||
throw new RuntimeException("temporarily disabled");
|
||||
// Uri uri = AttachmentProvider.getAttachmentUriForViewing(account, part.getAttachmentId(), mimeType, name);
|
||||
//
|
||||
// Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
// intent.setDataAndType(uri, mimeType);
|
||||
// intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
// addUiIntentFlags(intent);
|
||||
//
|
||||
// return intent;
|
||||
}
|
||||
|
||||
private Intent createViewIntentForFileUri(String mimeType, Uri uri) {
|
||||
@ -422,20 +419,22 @@ public class AttachmentView extends FrameLayout implements OnClickListener, OnLo
|
||||
}
|
||||
|
||||
private Bitmap getPreviewIcon() {
|
||||
Bitmap icon = null;
|
||||
try {
|
||||
InputStream input = context.getContentResolver().openInputStream(
|
||||
AttachmentProvider.getAttachmentThumbnailUri(account,
|
||||
part.getAttachmentId(),
|
||||
62,
|
||||
62));
|
||||
icon = BitmapFactory.decodeStream(input);
|
||||
input.close();
|
||||
} catch (Exception e) {
|
||||
// We don't care what happened, we just return null for the preview icon.
|
||||
}
|
||||
|
||||
return icon;
|
||||
//FIXME - temporarily disabled
|
||||
return null;
|
||||
// Bitmap icon = null;
|
||||
// try {
|
||||
// InputStream input = context.getContentResolver().openInputStream(
|
||||
// AttachmentProvider.getAttachmentThumbnailUri(account,
|
||||
// part.getAttachmentId(),
|
||||
// 62,
|
||||
// 62));
|
||||
// icon = BitmapFactory.decodeStream(input);
|
||||
// input.close();
|
||||
// } catch (Exception e) {
|
||||
// // We don't care what happened, we just return null for the preview icon.
|
||||
// }
|
||||
//
|
||||
// return icon;
|
||||
}
|
||||
|
||||
protected void onPostExecute(Bitmap previewIcon) {
|
||||
|
Loading…
Reference in New Issue
Block a user