mirror of
https://github.com/moparisthebest/k-9
synced 2025-02-25 23:21:50 -05:00
Made sure the message list is only modified from the UI thread
This commit is contained in:
parent
d97da517fa
commit
16ab1b67bc
@ -360,6 +360,7 @@ public class MessageList
|
|||||||
private static final int ACTION_FOLDER_LOADING = 5;
|
private static final int ACTION_FOLDER_LOADING = 5;
|
||||||
private static final int ACTION_REFRESH_TITLE = 6;
|
private static final int ACTION_REFRESH_TITLE = 6;
|
||||||
private static final int ACTION_PROGRESS = 7;
|
private static final int ACTION_PROGRESS = 7;
|
||||||
|
private static final int ACTION_REMOVE_MESSAGE = 8;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -405,6 +406,37 @@ public class MessageList
|
|||||||
sendMessage(msg);
|
sendMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeMessage(MessageReference messageReference) {
|
||||||
|
android.os.Message msg = android.os.Message.obtain(this, ACTION_REMOVE_MESSAGE,
|
||||||
|
messageReference);
|
||||||
|
sendMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeMessageUid(final MessageReference ref, final String newUid) {
|
||||||
|
// Instead of creating a container to be able to pass both arguments in a Message we
|
||||||
|
// post a Runnable to the message queue.
|
||||||
|
post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mAdapter.changeMessageUid(ref, newUid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addOrUpdateMessages(final Account account, final String folderName,
|
||||||
|
final List<Message> providedMessages, final boolean verifyAgainstSearch) {
|
||||||
|
// We copy the message list because it's later modified by MessagingController
|
||||||
|
final List<Message> messages = new ArrayList<Message>(providedMessages);
|
||||||
|
|
||||||
|
post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mAdapter.addOrUpdateMessages(account, folderName, messages,
|
||||||
|
verifyAgainstSearch);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(android.os.Message msg) {
|
public void handleMessage(android.os.Message msg) {
|
||||||
@ -442,6 +474,11 @@ public class MessageList
|
|||||||
MessageList.this.progress(progress);
|
MessageList.this.progress(progress);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ACTION_REMOVE_MESSAGE: {
|
||||||
|
MessageReference messageReference = (MessageReference) msg.obj;
|
||||||
|
mAdapter.removeMessage(messageReference);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -838,22 +875,21 @@ public class MessageList
|
|||||||
// reread the selected date format preference in case it has changed
|
// reread the selected date format preference in case it has changed
|
||||||
mMessageHelper.refresh();
|
mMessageHelper.refresh();
|
||||||
|
|
||||||
|
mAdapter.markAllMessagesAsDirty();
|
||||||
|
|
||||||
new Thread() {
|
new Thread() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mAdapter.markAllMessagesAsDirty();
|
|
||||||
|
|
||||||
if (mFolderName != null) {
|
if (mFolderName != null) {
|
||||||
mController.listLocalMessagesSynchronous(mAccount, mFolderName, mAdapter.mListener);
|
mController.listLocalMessagesSynchronous(mAccount, mFolderName, mAdapter.mListener);
|
||||||
} else if (mQueryString != null) {
|
} else if (mQueryString != null) {
|
||||||
mController.searchLocalMessagesSynchronous(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
|
mController.searchLocalMessagesSynchronous(mAccountUuids, mFolderNames, null, mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags, mAdapter.mListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mAdapter.pruneDirtyMessages();
|
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
mAdapter.pruneDirtyMessages();
|
||||||
mAdapter.notifyDataSetChanged();
|
mAdapter.notifyDataSetChanged();
|
||||||
restoreListState();
|
restoreListState();
|
||||||
}
|
}
|
||||||
@ -1905,17 +1941,12 @@ public class MessageList
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void synchronizeMailboxAddOrUpdateMessage(Account account, String folder, Message message) {
|
public void synchronizeMailboxAddOrUpdateMessage(Account account, String folder, Message message) {
|
||||||
addOrUpdateMessage(account, folder, message, true);
|
mHandler.addOrUpdateMessages(account, folder, Collections.singletonList(message), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void synchronizeMailboxRemovedMessage(Account account, String folder, Message message) {
|
public void synchronizeMailboxRemovedMessage(Account account, String folder, Message message) {
|
||||||
MessageInfoHolder holder = getMessage(message);
|
mHandler.removeMessage(message.makeMessageReference());
|
||||||
if (holder == null) {
|
|
||||||
Log.w(K9.LOG_TAG, "Got callback to remove non-existent message with UID " + message.getUid());
|
|
||||||
} else {
|
|
||||||
mHandler.removeMessages(Collections.singletonList(holder));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1952,20 +1983,17 @@ public class MessageList
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void listLocalMessagesRemoveMessage(Account account, String folder, Message message) {
|
public void listLocalMessagesRemoveMessage(Account account, String folder, Message message) {
|
||||||
MessageInfoHolder holder = getMessage(message);
|
mHandler.removeMessage(message.makeMessageReference());
|
||||||
if (holder != null) {
|
|
||||||
mHandler.removeMessages(Collections.singletonList(holder));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void listLocalMessagesAddMessages(Account account, String folder, List<Message> messages) {
|
public void listLocalMessagesAddMessages(Account account, String folder, List<Message> messages) {
|
||||||
addOrUpdateMessages(account, folder, messages, false);
|
mHandler.addOrUpdateMessages(account, folder, messages, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void listLocalMessagesUpdateMessage(Account account, String folder, Message message) {
|
public void listLocalMessagesUpdateMessage(Account account, String folder, Message message) {
|
||||||
addOrUpdateMessage(account, folder, message, false);
|
mHandler.addOrUpdateMessages(account, folder, Collections.singletonList(message), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1989,11 +2017,7 @@ public class MessageList
|
|||||||
ref.folderName = folder;
|
ref.folderName = folder;
|
||||||
ref.uid = oldUid;
|
ref.uid = oldUid;
|
||||||
|
|
||||||
MessageInfoHolder holder = getMessage(ref);
|
mHandler.changeMessageUid(ref, newUid);
|
||||||
if (holder != null) {
|
|
||||||
holder.uid = newUid;
|
|
||||||
holder.message.setUid(newUid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2032,27 +2056,26 @@ public class MessageList
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void pruneDirtyMessages() {
|
public void pruneDirtyMessages() {
|
||||||
synchronized (mMessages) {
|
List<MessageInfoHolder> messagesToRemove = new ArrayList<MessageInfoHolder>();
|
||||||
Iterator<MessageInfoHolder> iter = mMessages.iterator();
|
|
||||||
while (iter.hasNext()) {
|
for (MessageInfoHolder holder : mMessages) {
|
||||||
MessageInfoHolder holder = iter.next();
|
|
||||||
if (holder.dirty) {
|
if (holder.dirty) {
|
||||||
if (holder.selected) {
|
messagesToRemove.add(holder);
|
||||||
mSelectedCount--;
|
|
||||||
toggleBatchButtons();
|
|
||||||
}
|
|
||||||
mHandler.removeMessages(Collections.singletonList(holder));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
removeMessages(messagesToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMessage(MessageReference messageReference) {
|
||||||
|
MessageInfoHolder holder = getMessage(messageReference);
|
||||||
|
if (holder == null) {
|
||||||
|
Log.w(K9.LOG_TAG, "Got callback to remove non-existent message with UID " +
|
||||||
|
messageReference.uid);
|
||||||
|
} else {
|
||||||
|
removeMessages(Collections.singletonList(holder));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: Must be called from the UI thread!
|
|
||||||
*
|
|
||||||
* @param holders
|
|
||||||
* Never {@code null}.
|
|
||||||
*/
|
|
||||||
public void removeMessages(final List<MessageInfoHolder> messages) {
|
public void removeMessages(final List<MessageInfoHolder> messages) {
|
||||||
if (messages.isEmpty()) {
|
if (messages.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@ -2074,11 +2097,6 @@ public class MessageList
|
|||||||
toggleBatchButtons();
|
toggleBatchButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: Must be called from the UI thread!
|
|
||||||
*
|
|
||||||
* @param messages
|
|
||||||
*/
|
|
||||||
public void addMessages(final List<MessageInfoHolder> messages) {
|
public void addMessages(final List<MessageInfoHolder> messages) {
|
||||||
if (messages.isEmpty()) {
|
if (messages.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@ -2088,10 +2106,7 @@ public class MessageList
|
|||||||
|
|
||||||
for (final MessageInfoHolder message : messages) {
|
for (final MessageInfoHolder message : messages) {
|
||||||
if (mFolderName == null || (message.folder != null && message.folder.name.equals(mFolderName))) {
|
if (mFolderName == null || (message.folder != null && message.folder.name.equals(mFolderName))) {
|
||||||
int index;
|
int index = Collections.binarySearch(mMessages, message, getComparator());
|
||||||
synchronized (mMessages) {
|
|
||||||
index = Collections.binarySearch(mMessages, message, getComparator());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
index = (index * -1) - 1;
|
index = (index * -1) - 1;
|
||||||
@ -2109,45 +2124,37 @@ public class MessageList
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public void changeMessageUid(MessageReference ref, String newUid) {
|
||||||
* Note: Must be called from the UI thread!
|
MessageInfoHolder holder = getMessage(ref);
|
||||||
*/
|
if (holder != null) {
|
||||||
|
holder.uid = newUid;
|
||||||
|
holder.message.setUid(newUid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void resetUnreadCount() {
|
public void resetUnreadCount() {
|
||||||
if (mQueryString != null) {
|
if (mQueryString != null) {
|
||||||
int unreadCount = 0;
|
int unreadCount = 0;
|
||||||
synchronized (mMessages) {
|
|
||||||
for (MessageInfoHolder holder : mMessages) {
|
for (MessageInfoHolder holder : mMessages) {
|
||||||
unreadCount += holder.read ? 0 : 1;
|
unreadCount += holder.read ? 0 : 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mUnreadMessageCount = unreadCount;
|
mUnreadMessageCount = unreadCount;
|
||||||
refreshTitle();
|
refreshTitle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: Must be called from the UI thread!
|
|
||||||
*/
|
|
||||||
public void sortMessages() {
|
public void sortMessages() {
|
||||||
final Comparator<MessageInfoHolder> chainComparator = getComparator();
|
final Comparator<MessageInfoHolder> chainComparator = getComparator();
|
||||||
|
|
||||||
synchronized (mMessages) {
|
|
||||||
Collections.sort(mMessages, chainComparator);
|
Collections.sort(mMessages, chainComparator);
|
||||||
}
|
|
||||||
|
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addOrUpdateMessage(Account account, String folderName, Message message, boolean verifyAgainstSearch) {
|
public void addOrUpdateMessages(final Account account, final String folderName,
|
||||||
List<Message> messages = new ArrayList<Message>();
|
final List<Message> messages, final boolean verifyAgainstSearch) {
|
||||||
messages.add(message);
|
|
||||||
addOrUpdateMessages(account, folderName, messages, verifyAgainstSearch);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addOrUpdateMessages(final Account account, final String folderName, final List<Message> providedMessages, final boolean verifyAgainstSearch) {
|
|
||||||
// we copy the message list because the callback doesn't expect
|
|
||||||
// the callbacks to mutate it.
|
|
||||||
final List<Message> messages = new ArrayList<Message>(providedMessages);
|
|
||||||
|
|
||||||
boolean needsSort = false;
|
boolean needsSort = false;
|
||||||
final List<MessageInfoHolder> messagesToAdd = new ArrayList<MessageInfoHolder>();
|
final List<MessageInfoHolder> messagesToAdd = new ArrayList<MessageInfoHolder>();
|
||||||
@ -2169,7 +2176,9 @@ public class MessageList
|
|||||||
if (m == null) {
|
if (m == null) {
|
||||||
if (updateForMe(account, folderName)) {
|
if (updateForMe(account, folderName)) {
|
||||||
m = new MessageInfoHolder();
|
m = new MessageInfoHolder();
|
||||||
messageHelper.populate(m, message, new FolderInfoHolder(MessageList.this, messageFolder, messageAccount), messageAccount);
|
FolderInfoHolder folderInfoHolder = new FolderInfoHolder(
|
||||||
|
MessageList.this, messageFolder, messageAccount);
|
||||||
|
messageHelper.populate(m, message, folderInfoHolder, messageAccount);
|
||||||
messagesToAdd.add(m);
|
messagesToAdd.add(m);
|
||||||
} else {
|
} else {
|
||||||
if (mQueryString != null) {
|
if (mQueryString != null) {
|
||||||
@ -2177,49 +2186,57 @@ public class MessageList
|
|||||||
messagesToSearch.add(message);
|
messagesToSearch.add(message);
|
||||||
} else {
|
} else {
|
||||||
m = new MessageInfoHolder();
|
m = new MessageInfoHolder();
|
||||||
messageHelper.populate(m, message, new FolderInfoHolder(MessageList.this, messageFolder, messageAccount), messageAccount);
|
FolderInfoHolder folderInfoHolder = new FolderInfoHolder(
|
||||||
|
MessageList.this, messageFolder, messageAccount);
|
||||||
|
messageHelper.populate(m, message, folderInfoHolder,
|
||||||
|
messageAccount);
|
||||||
messagesToAdd.add(m);
|
messagesToAdd.add(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m.dirty = false; // as we reload the message, unset its dirty flag
|
m.dirty = false; // as we reload the message, unset its dirty flag
|
||||||
messageHelper.populate(m, message, new FolderInfoHolder(MessageList.this, messageFolder, account), account);
|
FolderInfoHolder folderInfoHolder = new FolderInfoHolder(MessageList.this,
|
||||||
|
messageFolder, account);
|
||||||
|
messageHelper.populate(m, message, folderInfoHolder, account);
|
||||||
needsSort = true;
|
needsSort = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!messagesToSearch.isEmpty()) {
|
if (!messagesToSearch.isEmpty()) {
|
||||||
mController.searchLocalMessages(mAccountUuids, mFolderNames, messagesToSearch.toArray(EMPTY_MESSAGE_ARRAY), mQueryString, mIntegrate, mQueryFlags, mForbiddenFlags,
|
mController.searchLocalMessages(mAccountUuids, mFolderNames,
|
||||||
|
messagesToSearch.toArray(EMPTY_MESSAGE_ARRAY), mQueryString, mIntegrate,
|
||||||
|
mQueryFlags, mForbiddenFlags,
|
||||||
new MessagingListener() {
|
new MessagingListener() {
|
||||||
@Override
|
@Override
|
||||||
public void listLocalMessagesAddMessages(Account account, String folder, List<Message> messages) {
|
public void listLocalMessagesAddMessages(Account account, String folder,
|
||||||
addOrUpdateMessages(account, folder, messages, false);
|
List<Message> messages) {
|
||||||
|
mHandler.addOrUpdateMessages(account, folder, messages, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!messagesToRemove.isEmpty()) {
|
if (!messagesToRemove.isEmpty()) {
|
||||||
mHandler.removeMessages(messagesToRemove);
|
removeMessages(messagesToRemove);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!messagesToAdd.isEmpty()) {
|
if (!messagesToAdd.isEmpty()) {
|
||||||
mHandler.addMessages(messagesToAdd);
|
addMessages(messagesToAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsSort) {
|
if (needsSort) {
|
||||||
mHandler.sortMessages();
|
sortMessages();
|
||||||
mHandler.resetUnreadCount();
|
resetUnreadCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public MessageInfoHolder getMessage(Message message) {
|
|
||||||
|
private MessageInfoHolder getMessage(Message message) {
|
||||||
return getMessage(message.makeMessageReference());
|
return getMessage(message.makeMessageReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX TODO - make this not use a for loop
|
// XXX TODO - make this not use a for loop
|
||||||
public MessageInfoHolder getMessage(MessageReference messageReference) {
|
private MessageInfoHolder getMessage(MessageReference messageReference) {
|
||||||
synchronized (mMessages) {
|
|
||||||
for (MessageInfoHolder holder : mMessages) {
|
for (MessageInfoHolder holder : mMessages) {
|
||||||
/*
|
/*
|
||||||
* 2010-06-21 - cketti
|
* 2010-06-21 - cketti
|
||||||
@ -2233,7 +2250,7 @@ public class MessageList
|
|||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2287,11 +2304,9 @@ public class MessageList
|
|||||||
@Override
|
@Override
|
||||||
public Object getItem(int position) {
|
public Object getItem(int position) {
|
||||||
try {
|
try {
|
||||||
synchronized (mMessages) {
|
|
||||||
if (position < mMessages.size()) {
|
if (position < mMessages.size()) {
|
||||||
return mMessages.get(position);
|
return mMessages.get(position);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(K9.LOG_TAG, "getItem(" + position + "), but folder.messages.size() = " + mMessages.size(), e);
|
Log.e(K9.LOG_TAG, "getItem(" + position + "), but folder.messages.size() = " + mMessages.size(), e);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user