1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-24 02:12:15 -05:00

Refactor suppression of deleted messages into MessagingController.

Re-enable instant deletes in MessageView

Deleted message suppression should be generalized into a flag cache,
serving Seen, Flagged, and Answered flags, as well.

Copy message to Trash still needs work, so that no duplicates are ever
visible and server-sync is more clean.  This will be especially
important, as the same code will be needed for the future "message
copy/move" facility.
This commit is contained in:
Daniel Applebaum 2009-01-29 13:35:43 +00:00
parent 9fe3656391
commit fe2dfb76d0
3 changed files with 184 additions and 111 deletions

View File

@ -14,6 +14,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -112,6 +113,82 @@ public class MessagingController implements Runnable {
private boolean mBusy; private boolean mBusy;
private Application mApplication; private Application mApplication;
// Key is accountUuid:folderName:messageUid , value is unimportant
private ConcurrentHashMap<String, String> deletedUids = new ConcurrentHashMap<String, String>();
// Key is accountUuid:folderName , value is a long of the highest message UID ever emptied from Trash
private ConcurrentHashMap<String, Long> expungedUid = new ConcurrentHashMap<String, Long>();
private String createMessageKey(Account account, String folder, Message message)
{
return account.getUuid() + ":" + folder + ":" + message.getUid();
}
private String createFolderKey(Account account, String folder)
{
return account.getUuid() + ":" + folder;
}
private void suppressMessage(Account account, String folder, Message message)
{
if (account == null || folder == null || message == null)
{
return;
}
String messKey = createMessageKey(account, folder, message);
Log.d(Email.LOG_TAG, "Suppressing message with key " + messKey);
deletedUids.put(messKey, "true");
}
private void unsuppressMessage(Account account, String folder, Message message)
{
if (account == null || folder == null || message == null)
{
return;
}
String messKey = createMessageKey(account, folder, message);
Log.d(Email.LOG_TAG, "Unsuppressing message with key " + messKey);
deletedUids.remove(messKey);
}
private boolean isMessageSuppressed(Account account, String folder, Message message)
{
if (account == null || folder == null || message == null)
{
return false;
}
String messKey = createMessageKey(account, folder, message);
Log.d(Email.LOG_TAG, "Checking suppression of message with key " + messKey);
if (deletedUids.containsKey(messKey))
{
Log.d(Email.LOG_TAG, "Message with key " + messKey + " is suppressed");
return true;
}
Long expungedUidL = expungedUid.get(createFolderKey(account, folder));
if (expungedUidL != null)
{
long expungedUid = expungedUidL;
String messageUidS = message.getUid();
try
{
long messageUid = Long.parseLong(messageUidS);
if (messageUid <= expungedUid)
{
return false;
}
}
catch (NumberFormatException nfe)
{
// Nothing to do
}
}
return false;
}
private MessagingController(Application application) { private MessagingController(Application application) {
@ -380,7 +457,9 @@ public class MessagingController implements Runnable {
Message[] localMessages = localFolder.getMessages(null); Message[] localMessages = localFolder.getMessages(null);
ArrayList<Message> messages = new ArrayList<Message>(); ArrayList<Message> messages = new ArrayList<Message>();
for (Message message : localMessages) { for (Message message : localMessages) {
if (!message.isSet(Flag.DELETED)) {
if (!message.isSet(Flag.DELETED) &&
isMessageSuppressed(account, localFolder.getName(), message) == false) {
messages.add(message); messages.add(message);
} }
} }
@ -689,10 +768,13 @@ s * critical data as fast as possible, and then we'll fill in the de
* (POP) may not be able to give us headers for * (POP) may not be able to give us headers for
* ENVELOPE, only size. * ENVELOPE, only size.
*/ */
if (isMessageSuppressed(account, folder, message) == false)
{
for (MessagingListener l : getListeners()) { for (MessagingListener l : getListeners()) {
l.synchronizeMailboxNewMessage(account, folder, l.synchronizeMailboxNewMessage(account, folder,
localFolder.getMessage(message.getUid())); localFolder.getMessage(message.getUid()));
} }
}
} }
} }
@ -740,7 +822,8 @@ s * critical data as fast as possible, and then we'll fill in the de
messageChanged = true; messageChanged = true;
} }
} }
if (messageChanged) { if (messageChanged && isMessageSuppressed(account, folder, localMessage) == false)
{
for (MessagingListener l : getListeners()) { for (MessagingListener l : getListeners()) {
l.synchronizeMailboxNewMessage(account, folder, localMessage); l.synchronizeMailboxNewMessage(account, folder, localMessage);
} }
@ -825,13 +908,15 @@ s * critical data as fast as possible, and then we'll fill in the de
// Set a flag indicating this message has now be fully downloaded // Set a flag indicating this message has now be fully downloaded
localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true); localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true);
if (isMessageSuppressed(account, folder, localMessage) == false)
// Update the listener with what we've found {
for (MessagingListener l : getListeners()) { // Update the listener with what we've found
l.synchronizeMailboxNewMessage( for (MessagingListener l : getListeners()) {
account, l.synchronizeMailboxNewMessage(
folder, account,
localMessage); folder,
localMessage);
}
} }
} }
catch (MessagingException me) { catch (MessagingException me) {
@ -919,13 +1004,15 @@ s * critical data as fast as possible, and then we'll fill in the de
// viewed. // viewed.
localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true); localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true);
} }
if (isMessageSuppressed(account, folder, message) == false)
// Update the listener with what we've found {
for (MessagingListener l : getListeners()) { // Update the listener with what we've found
l.synchronizeMailboxNewMessage( for (MessagingListener l : getListeners()) {
account, l.synchronizeMailboxNewMessage(
folder, account,
localFolder.getMessage(message.getUid())); folder,
localFolder.getMessage(message.getUid()));
}
} }
} }
if (Config.LOGV) { if (Config.LOGV) {
@ -1898,6 +1985,8 @@ s * critical data as fast as possible, and then we'll fill in the de
public void deleteMessage(final Account account, final String folder, final Message message, public void deleteMessage(final Account account, final String folder, final Message message,
final MessagingListener listener) { final MessagingListener listener) {
suppressMessage(account, folder, message);
put("deleteMessage", null, new Runnable() { put("deleteMessage", null, new Runnable() {
public void run() { public void run() {
deleteMessageSynchronous(account, folder, message, listener); deleteMessageSynchronous(account, folder, message, listener);
@ -1907,53 +1996,60 @@ s * critical data as fast as possible, and then we'll fill in the de
private void deleteMessageSynchronous(final Account account, final String folder, final Message message, private void deleteMessageSynchronous(final Account account, final String folder, final Message message,
MessagingListener listener) { MessagingListener listener) {
account.getUuid();
message.getUid();
try { try {
Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication);
Folder localFolder = localStore.getFolder(folder); Folder localFolder = localStore.getFolder(folder);
Message lMessage = localFolder.getMessage(message.getUid()); Message lMessage = localFolder.getMessage(message.getUid());
if (lMessage != null)
if (folder.equals(account.getTrashFolderName()))
{ {
if (Config.LOGD) if (folder.equals(account.getTrashFolderName()))
{
Log.d(Email.LOG_TAG, "Deleting message in trash folder, not copying");
}
lMessage.setFlag(Flag.DELETED, true);
}
else
{
Folder localTrashFolder = localStore.getFolder(account.getTrashFolderName());
if (localTrashFolder.exists() == false)
{
localTrashFolder.create(Folder.FolderType.HOLDS_MESSAGES);
}
if (localTrashFolder.exists() == true)
{ {
if (Config.LOGD) if (Config.LOGD)
{ {
Log.d(Email.LOG_TAG, "Deleting message in normal folder, copying"); Log.d(Email.LOG_TAG, "Deleting message in trash folder, not copying");
} }
FetchProfile fp = new FetchProfile(); lMessage.setFlag(Flag.DELETED, true);
fp.add(FetchProfile.Item.ENVELOPE); }
fp.add(FetchProfile.Item.BODY); else
// TODO: Turn the fetch/copy/delete into an atomic move {
localFolder.fetch(new Message[] { lMessage }, fp, null); Folder localTrashFolder = localStore.getFolder(account.getTrashFolderName());
localFolder.copyMessages(new Message[] { lMessage }, localTrashFolder); if (localTrashFolder.exists() == false)
if (folder.equals(account.getOutboxFolderName())) { {
lMessage.setFlag(Flag.X_DESTROYED, true); localTrashFolder.create(Folder.FolderType.HOLDS_MESSAGES);
} }
else { if (localTrashFolder.exists() == true)
lMessage.setFlag(Flag.DELETED, true); {
if (Config.LOGD)
{
Log.d(Email.LOG_TAG, "Deleting message in normal folder, copying");
}
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add(FetchProfile.Item.BODY);
// TODO: Turn the fetch/copy/delete into an atomic move
localFolder.fetch(new Message[] { lMessage }, fp, null);
localFolder.copyMessages(new Message[] { lMessage }, localTrashFolder);
if (folder.equals(account.getOutboxFolderName())) {
lMessage.setFlag(Flag.X_DESTROYED, true);
}
else {
lMessage.setFlag(Flag.DELETED, true);
}
} }
} }
} }
localFolder.close(false); localFolder.close(false);
unsuppressMessage(account, folder, message);
if (listener != null) { if (listener != null) {
listener.messageDeleted(account, folder, message); listener.messageDeleted(account, folder, message);
} }
// for (MessagingListener l : getListeners()) { for (MessagingListener l : getListeners()) {
// l.folderStatusChanged(account, account.getTrashFolderName()); l.folderStatusChanged(account, account.getTrashFolderName());
// } }
if (Config.LOGD) if (Config.LOGD)
{ {

View File

@ -395,8 +395,7 @@ public class FolderMessageList extends ExpandableListActivity
// Lower our priority // Lower our priority
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// Synchronously load the list of local messages // Synchronously load the list of local messages
MessagingController.getInstance(getApplication()).listLocalMessages(
mAccount, mFolder, mAdapter.mListener);
try try
{ {
Store localStore = Store.getInstance(mAccount.getLocalStoreUri(), Store localStore = Store.getInstance(mAccount.getLocalStoreUri(),
@ -418,7 +417,12 @@ public class FolderMessageList extends ExpandableListActivity
// at it's leisure // at it's leisure
MessagingController.getInstance(getApplication()).synchronizeMailbox( MessagingController.getInstance(getApplication()).synchronizeMailbox(
mAccount, mFolder, mAdapter.mListener); mAccount, mFolder, mAdapter.mListener);
} }
else
{
MessagingController.getInstance(getApplication()).listLocalMessages(
mAccount, mFolder, mAdapter.mListener);
}
} }
} }
@ -611,8 +615,9 @@ public class FolderMessageList extends ExpandableListActivity
final FolderInfoHolder folder = (FolderInfoHolder) mAdapter final FolderInfoHolder folder = (FolderInfoHolder) mAdapter
.getGroup(groupPosition); .getGroup(groupPosition);
if (folder.messages.size() == 0) if (folder.messages.size() == 0 || folder.needsRefresh)
{ {
folder.needsRefresh = false;
new Thread(new FolderUpdateWorker(folder.name, false)).start(); new Thread(new FolderUpdateWorker(folder.name, false)).start();
} }
} }
@ -771,24 +776,16 @@ public class FolderMessageList extends ExpandableListActivity
{ {
holder.folder.unreadMessageCount--; holder.folder.unreadMessageCount--;
} }
FolderInfoHolder trashHolder = mAdapter.getFolder(mAccount.getTrashFolderName());
if (trashHolder != null)
{
trashHolder.needsRefresh = true;
}
mAdapter.removeMessage(holder.message.getFolder().getName(), holder.uid); mAdapter.removeMessage(holder.message.getFolder().getName(), holder.uid);
if (holder.folder.name.equals(mAccount.getTrashFolderName()) == false) {
mAdapter.addOrUpdateMessage(mAccount.getTrashFolderName(), holder.message);
}
MessagingController.getInstance(getApplication()).deleteMessage(mAccount, MessagingController.getInstance(getApplication()).deleteMessage(mAccount,
holder.message.getFolder().getName(), holder.message, holder.message.getFolder().getName(), holder.message, null);
new MessagingListener() {
@Override
public void messageDeleted(Account account, String folder, Message message) {
if (account != mAccount) {
return;
}
mAdapter.removeDeletedUid(folder, message.getUid());
}
}
);
} }
@ -832,7 +829,6 @@ public class FolderMessageList extends ExpandableListActivity
public void controllerCommandCompleted(boolean moreToDo) public void controllerCommandCompleted(boolean moreToDo)
{ {
Log.v(Email.LOG_TAG, "Empty Trash background task completed"); Log.v(Email.LOG_TAG, "Empty Trash background task completed");
mAdapter.removeAllDeletedUids(account.getTrashFolderName());
} }
}; };
@ -1280,9 +1276,6 @@ public class FolderMessageList extends ExpandableListActivity
return; return;
} }
FolderInfoHolder holder = getFolder(folder); FolderInfoHolder holder = getFolder(folder);
// if (holder != null) {
// holder.deletedUids.clear();
// }
mHandler.progress(false); mHandler.progress(false);
mHandler.folderLoading(folder, false); mHandler.folderLoading(folder, false);
// mHandler.folderStatus(folder, null); // mHandler.folderStatus(folder, null);
@ -1311,7 +1304,6 @@ public class FolderMessageList extends ExpandableListActivity
if (holder != null) if (holder != null)
{ {
holder.lastChecked = 0; holder.lastChecked = 0;
// holder.deletedUids.clear();
} }
mHandler.folderSyncing(null); mHandler.folderSyncing(null);
} }
@ -1327,7 +1319,17 @@ public class FolderMessageList extends ExpandableListActivity
addOrUpdateMessage(folder, message); addOrUpdateMessage(folder, message);
} }
@Override @Override
public void messageDeleted(Account account,
String folder, Message message)
{
synchronizeMailboxRemovedMessage(account,
folder, message);
}
@Override
public void synchronizeMailboxRemovedMessage(Account account, public void synchronizeMailboxRemovedMessage(Account account,
String folder, Message message) String folder, Message message)
{ {
@ -1422,23 +1424,6 @@ public class FolderMessageList extends ExpandableListActivity
R.drawable.ic_mms_answered_small); R.drawable.ic_mms_answered_small);
} }
public void removeDeletedUid(String folder, String messageUid) {
FolderInfoHolder f = getFolder(folder);
if (f != null)
{
f.deletedUids.remove(messageUid);
}
}
public void removeAllDeletedUids(String folder)
{
FolderInfoHolder f = getFolder(folder);
if (f != null)
{
f.deletedUids.clear();
}
}
public void removeAllMessages(String folder) public void removeAllMessages(String folder)
{ {
FolderInfoHolder f = getFolder(folder); FolderInfoHolder f = getFolder(folder);
@ -1465,9 +1450,7 @@ public class FolderMessageList extends ExpandableListActivity
{ {
return; return;
} }
if (f.deletedUids.contains(messageUid) == false) {
f.deletedUids.add(messageUid);
}
mHandler.removeMessage(f, m); mHandler.removeMessage(f, m);
} }
@ -1489,9 +1472,6 @@ public class FolderMessageList extends ExpandableListActivity
private void addOrUpdateMessage(FolderInfoHolder folder, Message message, private void addOrUpdateMessage(FolderInfoHolder folder, Message message,
boolean sort, boolean notify) boolean sort, boolean notify)
{ {
if (folder.deletedUids.contains(message.getUid())){
return;
}
MessageInfoHolder m = getMessage(folder, message.getUid()); MessageInfoHolder m = getMessage(folder, message.getUid());
if (m == null) if (m == null)
{ {
@ -1855,7 +1835,8 @@ public class FolderMessageList extends ExpandableListActivity
public boolean lastCheckFailed; public boolean lastCheckFailed;
public List<String> deletedUids = Collections.synchronizedList(new ArrayList<String>()); public boolean needsRefresh = false;
/** /**
* Outbox is handled differently from any other folder. * Outbox is handled differently from any other folder.
*/ */

View File

@ -528,27 +528,19 @@ public class MessageView extends Activity
findSurroundingMessagesUid(); findSurroundingMessagesUid();
MessagingListener listener = new MessagingListener()
{
public void messageDeleted(Account account, String folder, Message message)
{
if (mNextMessageUid != null) {
onNext();
}
else if (mPreviousMessageUid != null) {
onPrevious();
} else {
finish();
}
}
};
MessagingListener waitListener = listener;
MessagingController.getInstance(getApplication()).deleteMessage( MessagingController.getInstance(getApplication()).deleteMessage(
accountForDelete, accountForDelete,
folderForDelete, folderForDelete,
messageToDelete, messageToDelete,
waitListener); null);
if (mNextMessageUid != null) {
onNext();
}
else if (mPreviousMessageUid != null) {
onPrevious();
} else {
finish();
}
} }
@ -847,12 +839,16 @@ public class MessageView extends Activity
private void renderAttachments(Part part, int depth) throws MessagingException { private void renderAttachments(Part part, int depth) throws MessagingException {
String contentType = MimeUtility.unfoldAndDecode(part.getContentType()); String contentType = MimeUtility.unfoldAndDecode(part.getContentType());
String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition());
String name = MimeUtility.getHeaderParameter(contentType, "name"); String name = MimeUtility.getHeaderParameter(contentType, "name");
if (name == null)
{
name = MimeUtility.getHeaderParameter(contentDisposition, "filename");
}
if (name != null) { if (name != null) {
/* /*
* We're guaranteed size because LocalStore.fetch puts it there. * We're guaranteed size because LocalStore.fetch puts it there.
*/ */
String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition());
int size = Integer.parseInt(MimeUtility.getHeaderParameter(contentDisposition, "size")); int size = Integer.parseInt(MimeUtility.getHeaderParameter(contentDisposition, "size"));
Attachment attachment = new Attachment(); Attachment attachment = new Attachment();