diff --git a/src/com/android/email/MessagingController.java b/src/com/android/email/MessagingController.java index e0ca6c848..87522d201 100644 --- a/src/com/android/email/MessagingController.java +++ b/src/com/android/email/MessagingController.java @@ -14,6 +14,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -112,8 +113,84 @@ public class MessagingController implements Runnable { private boolean mBusy; private Application mApplication; + // Key is accountUuid:folderName:messageUid , value is unimportant + private ConcurrentHashMap deletedUids = new ConcurrentHashMap(); + // Key is accountUuid:folderName , value is a long of the highest message UID ever emptied from Trash + private ConcurrentHashMap expungedUid = new ConcurrentHashMap(); + + 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) { mApplication = application; mThread = new Thread(this); @@ -380,7 +457,9 @@ public class MessagingController implements Runnable { Message[] localMessages = localFolder.getMessages(null); ArrayList messages = new ArrayList(); for (Message message : localMessages) { - if (!message.isSet(Flag.DELETED)) { + + if (!message.isSet(Flag.DELETED) && + isMessageSuppressed(account, localFolder.getName(), message) == false) { 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 * ENVELOPE, only size. */ + if (isMessageSuppressed(account, folder, message) == false) + { for (MessagingListener l : getListeners()) { l.synchronizeMailboxNewMessage(account, folder, 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; } } - if (messageChanged) { + if (messageChanged && isMessageSuppressed(account, folder, localMessage) == false) + { for (MessagingListener l : getListeners()) { 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 localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true); - - // Update the listener with what we've found - for (MessagingListener l : getListeners()) { - l.synchronizeMailboxNewMessage( - account, - folder, - localMessage); + if (isMessageSuppressed(account, folder, localMessage) == false) + { + // Update the listener with what we've found + for (MessagingListener l : getListeners()) { + l.synchronizeMailboxNewMessage( + account, + folder, + localMessage); + } } } catch (MessagingException me) { @@ -919,13 +1004,15 @@ s * critical data as fast as possible, and then we'll fill in the de // viewed. localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true); } - - // Update the listener with what we've found - for (MessagingListener l : getListeners()) { - l.synchronizeMailboxNewMessage( - account, - folder, - localFolder.getMessage(message.getUid())); + if (isMessageSuppressed(account, folder, message) == false) + { + // Update the listener with what we've found + for (MessagingListener l : getListeners()) { + l.synchronizeMailboxNewMessage( + account, + folder, + localFolder.getMessage(message.getUid())); + } } } 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, final MessagingListener listener) { + suppressMessage(account, folder, message); + put("deleteMessage", null, new Runnable() { public void run() { 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, MessagingListener listener) { + + account.getUuid(); + message.getUid(); + try { Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); Folder localFolder = localStore.getFolder(folder); Message lMessage = localFolder.getMessage(message.getUid()); - - if (folder.equals(account.getTrashFolderName())) + if (lMessage != null) { - if (Config.LOGD) - { - 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 (folder.equals(account.getTrashFolderName())) { 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(); - 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); + lMessage.setFlag(Flag.DELETED, true); + } + else + { + Folder localTrashFolder = localStore.getFolder(account.getTrashFolderName()); + if (localTrashFolder.exists() == false) + { + localTrashFolder.create(Folder.FolderType.HOLDS_MESSAGES); } - else { - lMessage.setFlag(Flag.DELETED, true); + if (localTrashFolder.exists() == 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); + unsuppressMessage(account, folder, message); if (listener != null) { listener.messageDeleted(account, folder, message); } -// for (MessagingListener l : getListeners()) { -// l.folderStatusChanged(account, account.getTrashFolderName()); -// } + for (MessagingListener l : getListeners()) { + l.folderStatusChanged(account, account.getTrashFolderName()); + } if (Config.LOGD) { diff --git a/src/com/android/email/activity/FolderMessageList.java b/src/com/android/email/activity/FolderMessageList.java index 0dc5d5473..1c0e2f3d2 100644 --- a/src/com/android/email/activity/FolderMessageList.java +++ b/src/com/android/email/activity/FolderMessageList.java @@ -395,8 +395,7 @@ public class FolderMessageList extends ExpandableListActivity // Lower our priority Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // Synchronously load the list of local messages - MessagingController.getInstance(getApplication()).listLocalMessages( - mAccount, mFolder, mAdapter.mListener); + try { Store localStore = Store.getInstance(mAccount.getLocalStoreUri(), @@ -418,7 +417,12 @@ public class FolderMessageList extends ExpandableListActivity // at it's leisure MessagingController.getInstance(getApplication()).synchronizeMailbox( 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 .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(); } } @@ -771,24 +776,16 @@ public class FolderMessageList extends ExpandableListActivity { holder.folder.unreadMessageCount--; } + FolderInfoHolder trashHolder = mAdapter.getFolder(mAccount.getTrashFolderName()); + if (trashHolder != null) + { + trashHolder.needsRefresh = true; + } 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, - holder.message.getFolder().getName(), holder.message, - new MessagingListener() { - @Override - public void messageDeleted(Account account, String folder, Message message) { - if (account != mAccount) { - return; - } - mAdapter.removeDeletedUid(folder, message.getUid()); - } - } - ); + holder.message.getFolder().getName(), holder.message, null); } @@ -832,7 +829,6 @@ public class FolderMessageList extends ExpandableListActivity public void controllerCommandCompleted(boolean moreToDo) { Log.v(Email.LOG_TAG, "Empty Trash background task completed"); - mAdapter.removeAllDeletedUids(account.getTrashFolderName()); } }; @@ -1280,9 +1276,6 @@ public class FolderMessageList extends ExpandableListActivity return; } FolderInfoHolder holder = getFolder(folder); -// if (holder != null) { -// holder.deletedUids.clear(); -// } mHandler.progress(false); mHandler.folderLoading(folder, false); // mHandler.folderStatus(folder, null); @@ -1311,7 +1304,6 @@ public class FolderMessageList extends ExpandableListActivity if (holder != null) { holder.lastChecked = 0; - // holder.deletedUids.clear(); } mHandler.folderSyncing(null); } @@ -1327,7 +1319,17 @@ public class FolderMessageList extends ExpandableListActivity addOrUpdateMessage(folder, message); } + + @Override + public void messageDeleted(Account account, + String folder, Message message) + { + synchronizeMailboxRemovedMessage(account, + folder, message); + } + + @Override public void synchronizeMailboxRemovedMessage(Account account, String folder, Message message) { @@ -1421,23 +1423,6 @@ public class FolderMessageList extends ExpandableListActivity mAnsweredIcon = getResources().getDrawable( 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) { @@ -1465,9 +1450,7 @@ public class FolderMessageList extends ExpandableListActivity { return; } - if (f.deletedUids.contains(messageUid) == false) { - f.deletedUids.add(messageUid); - } + mHandler.removeMessage(f, m); } @@ -1489,9 +1472,6 @@ public class FolderMessageList extends ExpandableListActivity private void addOrUpdateMessage(FolderInfoHolder folder, Message message, boolean sort, boolean notify) { - if (folder.deletedUids.contains(message.getUid())){ - return; - } MessageInfoHolder m = getMessage(folder, message.getUid()); if (m == null) { @@ -1855,7 +1835,8 @@ public class FolderMessageList extends ExpandableListActivity public boolean lastCheckFailed; - public List deletedUids = Collections.synchronizedList(new ArrayList()); + public boolean needsRefresh = false; + /** * Outbox is handled differently from any other folder. */ diff --git a/src/com/android/email/activity/MessageView.java b/src/com/android/email/activity/MessageView.java index ad2617a6d..474391220 100644 --- a/src/com/android/email/activity/MessageView.java +++ b/src/com/android/email/activity/MessageView.java @@ -528,27 +528,19 @@ public class MessageView extends Activity 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( accountForDelete, folderForDelete, 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 { String contentType = MimeUtility.unfoldAndDecode(part.getContentType()); + String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition()); String name = MimeUtility.getHeaderParameter(contentType, "name"); + if (name == null) + { + name = MimeUtility.getHeaderParameter(contentDisposition, "filename"); + } if (name != null) { /* * We're guaranteed size because LocalStore.fetch puts it there. */ - String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition()); int size = Integer.parseInt(MimeUtility.getHeaderParameter(contentDisposition, "size")); Attachment attachment = new Attachment();