mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-27 11:42:16 -05:00
Use a Loader to load the message to view from the database
This commit is contained in:
parent
787c014265
commit
78ed2a23b1
@ -3113,27 +3113,34 @@ public class MessagingController implements Runnable {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the provided message as read if not disabled by the account setting.
|
||||
*
|
||||
* @param account
|
||||
* The account the message belongs to.
|
||||
* @param message
|
||||
* The message to mark as read. This {@link Message} instance will be modify by calling
|
||||
* {@link Message#setFlag(Flag, boolean)} on it.
|
||||
*
|
||||
* @throws MessagingException
|
||||
*
|
||||
* @see Account#isMarkMessageAsReadOnView()
|
||||
*/
|
||||
private void markMessageAsReadOnView(Account account, Message message)
|
||||
public LocalMessage loadMessage(Account account, String folderName, String uid) throws MessagingException {
|
||||
LocalStore localStore = account.getLocalStore();
|
||||
LocalFolder localFolder = localStore.getFolder(folderName);
|
||||
localFolder.open(Folder.OPEN_MODE_RW);
|
||||
|
||||
LocalMessage message = localFolder.getMessage(uid);
|
||||
if (message == null || message.getId() == 0) {
|
||||
throw new IllegalArgumentException("Message not found: folder=" + folderName + ", uid=" + uid);
|
||||
}
|
||||
|
||||
FetchProfile fp = new FetchProfile();
|
||||
fp.add(FetchProfile.Item.BODY);
|
||||
localFolder.fetch(Collections.singletonList(message), fp, null);
|
||||
localFolder.close();
|
||||
|
||||
markMessageAsReadOnView(account, message);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
private void markMessageAsReadOnView(Account account, LocalMessage message)
|
||||
throws MessagingException {
|
||||
|
||||
if (account.isMarkMessageAsReadOnView() && !message.isSet(Flag.SEEN)) {
|
||||
List<Long> messageIds = Collections.singletonList(message.getId());
|
||||
setFlag(account, messageIds, Flag.SEEN, true);
|
||||
|
||||
((LocalMessage) message).setFlagInternal(Flag.SEEN, true);
|
||||
message.setFlagInternal(Flag.SEEN, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4013,7 +4020,7 @@ public class MessagingController implements Runnable {
|
||||
|
||||
@Override
|
||||
public void act(final Account account, final Folder folder,
|
||||
final List<Message> accountMessages) {
|
||||
final List<Message> accountMessages) {
|
||||
suppressMessages(account, messages);
|
||||
|
||||
putBackground("deleteMessages", null, new Runnable() {
|
||||
|
@ -554,4 +554,8 @@ public class LocalMessage extends MimeMessage {
|
||||
private String getAccountUuid() {
|
||||
return getAccount().getUuid();
|
||||
}
|
||||
|
||||
public boolean isBodyMissing() {
|
||||
return getBody() == null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
package com.fsck.k9.ui.message;
|
||||
|
||||
|
||||
import android.content.AsyncTaskLoader;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.activity.MessageReference;
|
||||
import com.fsck.k9.controller.MessagingController;
|
||||
import com.fsck.k9.mail.MessagingException;
|
||||
import com.fsck.k9.mailstore.LocalMessage;
|
||||
|
||||
|
||||
public class LocalMessageLoader extends AsyncTaskLoader<LocalMessage> {
|
||||
private final MessagingController controller;
|
||||
private final Account account;
|
||||
private final MessageReference messageReference;
|
||||
private LocalMessage message;
|
||||
|
||||
public LocalMessageLoader(Context context, MessagingController controller, Account account,
|
||||
MessageReference messageReference) {
|
||||
super(context);
|
||||
this.controller = controller;
|
||||
this.account = account;
|
||||
this.messageReference = messageReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
if (message != null) {
|
||||
super.deliverResult(message);
|
||||
}
|
||||
|
||||
if (takeContentChanged() || message == null) {
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(LocalMessage message) {
|
||||
this.message = message;
|
||||
super.deliverResult(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalMessage loadInBackground() {
|
||||
try {
|
||||
return loadMessageFromDatabase();
|
||||
} catch (Exception e) {
|
||||
Log.e(K9.LOG_TAG, "Error while loading message from database", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private LocalMessage loadMessageFromDatabase() throws MessagingException {
|
||||
return controller.loadMessage(account, messageReference.folderName, messageReference.uid);
|
||||
}
|
||||
}
|
@ -6,13 +6,16 @@ import java.util.Locale;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.LoaderManager.LoaderCallbacks;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.Loader;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.KeyEvent;
|
||||
@ -41,6 +44,7 @@ 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.ui.message.LocalMessageLoader;
|
||||
import com.fsck.k9.view.AttachmentView;
|
||||
import com.fsck.k9.view.AttachmentView.AttachmentFileDownloadCallback;
|
||||
import com.fsck.k9.view.MessageHeader;
|
||||
@ -60,6 +64,8 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
private static final int ACTIVITY_CHOOSE_FOLDER_COPY = 2;
|
||||
private static final int ACTIVITY_CHOOSE_DIRECTORY = 3;
|
||||
|
||||
private static final int LOCAL_MESSAGE_LOADER_ID = 1;
|
||||
|
||||
|
||||
public static MessageViewFragment newInstance(MessageReference reference) {
|
||||
MessageViewFragment fragment = new MessageViewFragment();
|
||||
@ -105,6 +111,8 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private LoaderCallbacks<LocalMessage> localMessageLoaderCallback = new LocalMessageLoaderCallback();
|
||||
|
||||
|
||||
class MessageViewHandler extends Handler {
|
||||
|
||||
@ -117,15 +125,6 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
});
|
||||
}
|
||||
|
||||
public void addAttachment(final View attachmentView) {
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mMessageView.addAttachment(attachmentView);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* A helper for a set of "show a toast" methods */
|
||||
private void showToast(final String message, final int toastLength) {
|
||||
post(new Runnable() {
|
||||
@ -146,16 +145,6 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
showToast(context.getString(R.string.status_network_error), Toast.LENGTH_LONG);
|
||||
}
|
||||
|
||||
public void invalidIdError() {
|
||||
Context context = getActivity();
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
showToast(context.getString(R.string.status_invalid_id_error), Toast.LENGTH_LONG);
|
||||
}
|
||||
|
||||
|
||||
public void fetchingAttachment() {
|
||||
Context context = getActivity();
|
||||
if (context == null) {
|
||||
@ -230,7 +219,12 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
};
|
||||
});
|
||||
|
||||
mMessageView.initialize(this);
|
||||
mMessageView.initialize(this, new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onToggleFlagged();
|
||||
}
|
||||
});
|
||||
mMessageView.downloadRemainderButton().setOnClickListener(this);
|
||||
|
||||
mFragmentListener.messageHeaderViewAvailable(mMessageView.getMessageHeaderView());
|
||||
@ -261,10 +255,6 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
outState.putSerializable(STATE_PGP_DATA, mPgpData);
|
||||
}
|
||||
|
||||
public void displayMessage(MessageReference ref) {
|
||||
displayMessage(ref, true);
|
||||
}
|
||||
|
||||
private void displayMessage(MessageReference ref, boolean resetPgpData) {
|
||||
mMessageReference = ref;
|
||||
if (K9.DEBUG) {
|
||||
@ -283,11 +273,50 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
mMessageView.resetView();
|
||||
mMessageView.resetHeaderView();
|
||||
|
||||
mController.loadMessageForView(mAccount, mMessageReference.folderName, mMessageReference.uid, mListener);
|
||||
startLoadingMessageFromDatabase();
|
||||
|
||||
mFragmentListener.updateMenu();
|
||||
}
|
||||
|
||||
private void startLoadingMessageFromDatabase() {
|
||||
getLoaderManager().initLoader(LOCAL_MESSAGE_LOADER_ID, null, localMessageLoaderCallback);
|
||||
}
|
||||
|
||||
private void onLoadMessageFromDatabaseFinished(LocalMessage message) {
|
||||
displayMessageHeader(message);
|
||||
|
||||
if (message.isBodyMissing()) {
|
||||
startDownloadingMessageBody(message);
|
||||
} else {
|
||||
startExtractingTextAndAttachments(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void onLoadMessageFromDatabaseFailed() {
|
||||
mMessageView.showStatusMessage(mContext.getString(R.string.status_invalid_id_error));
|
||||
}
|
||||
|
||||
private void startDownloadingMessageBody(LocalMessage message) {
|
||||
throw new RuntimeException("Not implemented yet");
|
||||
}
|
||||
|
||||
private void startExtractingTextAndAttachments(LocalMessage message) {
|
||||
//TODO: extract in background thread
|
||||
//TODO: handle decryption and signature verification
|
||||
try {
|
||||
mMessageView.setMessage(mAccount, message, mPgpData, mController, mListener);
|
||||
mMessageView.setShowDownloadButton(message);
|
||||
} catch (MessagingException e) {
|
||||
Log.e(K9.LOG_TAG, "Error while trying to display message", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void displayMessageHeader(LocalMessage message) {
|
||||
mMessageView.setHeaders(message, mAccount);
|
||||
displayMessageSubject(getSubjectForMessage(message));
|
||||
mFragmentListener.updateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from UI thread when user select Delete
|
||||
*/
|
||||
@ -516,6 +545,15 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
}
|
||||
}
|
||||
|
||||
private String getSubjectForMessage(LocalMessage message) {
|
||||
String subject = message.getSubject();
|
||||
if (TextUtils.isEmpty(subject)) {
|
||||
return mContext.getString(R.string.general_no_subject);
|
||||
}
|
||||
|
||||
return subject;
|
||||
}
|
||||
|
||||
public void moveMessage(MessageReference reference, String destFolderName) {
|
||||
mController.moveMessage(mAccount, mMessageReference.folderName, mMessage,
|
||||
destFolderName, null);
|
||||
@ -530,126 +568,28 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
@Override
|
||||
public void loadMessageForViewHeadersAvailable(final Account account, String folder, String uid,
|
||||
final Message message) {
|
||||
if (!mMessageReference.uid.equals(uid) || !mMessageReference.folderName.equals(folder)
|
||||
|| !mMessageReference.accountUuid.equals(account.getUuid())) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clone the message object because the original could be modified by
|
||||
* MessagingController later. This could lead to a ConcurrentModificationException
|
||||
* when that same object is accessed by the UI thread (below).
|
||||
*
|
||||
* See issue 3953
|
||||
*
|
||||
* This is just an ugly hack to get rid of the most pressing problem. A proper way to
|
||||
* fix this is to make Message thread-safe. Or, even better, rewriting the UI code to
|
||||
* access messages via a ContentProvider.
|
||||
*
|
||||
*/
|
||||
final Message clonedMessage = message.clone();
|
||||
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!clonedMessage.isSet(Flag.X_DOWNLOADED_FULL) &&
|
||||
!clonedMessage.isSet(Flag.X_DOWNLOADED_PARTIAL)) {
|
||||
String text = mContext.getString(R.string.message_view_downloading);
|
||||
mMessageView.showStatusMessage(text);
|
||||
}
|
||||
mMessageView.setHeaders(clonedMessage, account);
|
||||
final String subject = clonedMessage.getSubject();
|
||||
if (subject == null || subject.equals("")) {
|
||||
displayMessageSubject(mContext.getString(R.string.general_no_subject));
|
||||
} else {
|
||||
displayMessageSubject(clonedMessage.getSubject());
|
||||
}
|
||||
mMessageView.setOnFlagListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onToggleFlagged();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMessageForViewBodyAvailable(final Account account, String folder,
|
||||
String uid, final Message message) {
|
||||
if (!(message instanceof LocalMessage) ||
|
||||
!mMessageReference.uid.equals(uid) ||
|
||||
!mMessageReference.folderName.equals(folder) ||
|
||||
!mMessageReference.accountUuid.equals(account.getUuid())) {
|
||||
return;
|
||||
}
|
||||
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
mMessage = (LocalMessage) message;
|
||||
mMessageView.setMessage(account, (LocalMessage) message, mPgpData,
|
||||
mController, mListener);
|
||||
mFragmentListener.updateMenu();
|
||||
|
||||
} catch (MessagingException e) {
|
||||
Log.v(K9.LOG_TAG, "loadMessageForViewBodyAvailable", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMessageForViewFailed(Account account, String folder, String uid, final Throwable t) {
|
||||
if (!mMessageReference.uid.equals(uid) || !mMessageReference.folderName.equals(folder)
|
||||
|| !mMessageReference.accountUuid.equals(account.getUuid())) {
|
||||
return;
|
||||
}
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setProgress(false);
|
||||
if (t instanceof IllegalArgumentException) {
|
||||
mHandler.invalidIdError();
|
||||
} else {
|
||||
mHandler.networkError();
|
||||
}
|
||||
if (mMessage == null || mMessage.isSet(Flag.X_DOWNLOADED_PARTIAL)) {
|
||||
mMessageView.showStatusMessage(
|
||||
mContext.getString(R.string.webview_empty_message));
|
||||
}
|
||||
}
|
||||
});
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMessageForViewFinished(Account account, String folder, String uid, final Message message) {
|
||||
if (!mMessageReference.uid.equals(uid) || !mMessageReference.folderName.equals(folder)
|
||||
|| !mMessageReference.accountUuid.equals(account.getUuid())) {
|
||||
return;
|
||||
}
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setProgress(false);
|
||||
mMessageView.setShowDownloadButton(message);
|
||||
}
|
||||
});
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMessageForViewStarted(Account account, String folder, String uid) {
|
||||
if (!mMessageReference.uid.equals(uid) || !mMessageReference.folderName.equals(folder)
|
||||
|| !mMessageReference.accountUuid.equals(account.getUuid())) {
|
||||
return;
|
||||
}
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setProgress(true);
|
||||
}
|
||||
});
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -865,4 +805,26 @@ public class MessageViewFragment extends Fragment implements OnClickListener,
|
||||
public LayoutInflater getFragmentLayoutInflater() {
|
||||
return mLayoutInflater;
|
||||
}
|
||||
|
||||
class LocalMessageLoaderCallback implements LoaderCallbacks<LocalMessage> {
|
||||
@Override
|
||||
public Loader<LocalMessage> onCreateLoader(int id, Bundle args) {
|
||||
return new LocalMessageLoader(mContext, mController, mAccount, mMessageReference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<LocalMessage> loader, LocalMessage message) {
|
||||
mMessage = message;
|
||||
if (message == null) {
|
||||
onLoadMessageFromDatabaseFailed();
|
||||
} else {
|
||||
onLoadMessageFromDatabaseFinished(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<LocalMessage> loader) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
|
||||
private String mText;
|
||||
|
||||
|
||||
public void initialize(Fragment fragment) {
|
||||
public void initialize(Fragment fragment, OnClickListener flagListener) {
|
||||
Activity activity = fragment.getActivity();
|
||||
mMessageContentView = (MessageWebView) findViewById(R.id.message_content);
|
||||
mMessageContentView.configure();
|
||||
@ -124,6 +124,7 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
|
||||
|
||||
mHeaderContainer = (MessageHeader) findViewById(R.id.header_container);
|
||||
mHeaderContainer.setOnLayoutChangedListener(this);
|
||||
mHeaderContainer.setOnFlagListener(flagListener);
|
||||
|
||||
mAttachmentsContainer = findViewById(R.id.attachments_container);
|
||||
mAttachments = (LinearLayout) findViewById(R.id.attachments);
|
||||
@ -493,10 +494,6 @@ public class SingleMessageView extends LinearLayout implements OnClickListener,
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnFlagListener(OnClickListener listener) {
|
||||
mHeaderContainer.setOnFlagListener(listener);
|
||||
}
|
||||
|
||||
public void showAllHeaders() {
|
||||
mHeaderContainer.onShowAdditionalHeaders();
|
||||
}
|
||||
|
@ -153,8 +153,6 @@ public class MessageHeader extends LinearLayout implements OnClickListener {
|
||||
}
|
||||
|
||||
public void setOnFlagListener(OnClickListener listener) {
|
||||
if (mFlagged == null)
|
||||
return;
|
||||
mFlagged.setOnClickListener(listener);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user