diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index b51f83dc7b0..cf6b0de7734 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -1544,14 +1544,21 @@ private boolean shouldImportMessage(final Account account, final String folder, return true; } + private static class WrappedException extends RuntimeException { + public WrappedException(final Exception cause) { + super(cause); + } + } + private void downloadSmallMessages(final Account account, final Folder remoteFolder, final LocalFolder localFolder, - ArrayList smallMessages, + final ArrayList smallMessages, final AtomicInteger progress, final int unreadBeforeStart, final AtomicInteger newMessages, final int todo, - FetchProfile fp) throws MessagingException { + final FetchProfile fp) + throws MessagingException { final String folder = remoteFolder.getName(); final Date earliestDate = account.getEarliestPollDate(); @@ -1559,62 +1566,75 @@ private void downloadSmallMessages(final Account account, final Folder remoteFol if (K9.DEBUG) Log.d(K9.LOG_TAG, "SYNC: Fetching small messages for folder " + folder); - remoteFolder.fetch(smallMessages.toArray(new Message[smallMessages.size()]), - fp, new MessageRetrievalListener() { - @Override - public void messageFinished(final Message message, int number, int ofTotal) { - try { - - if (!shouldImportMessage(account, folder, message, progress, earliestDate)) { - progress.incrementAndGet(); - - return; - } - - // Store the updated message locally - final Message localMessage = localFolder.storeSmallMessage(message, new Runnable() { - @Override - public void run() { - progress.incrementAndGet(); - } - }); - - // Increment the number of "new messages" if the newly downloaded message is - // not marked as read. - if (!localMessage.isSet(Flag.SEEN)) { - newMessages.incrementAndGet(); - } + try { + localFolder.executeRunnableInTransaction(new Runnable() { + @Override + public void run() { + try { + remoteFolder.fetch(smallMessages.toArray(new Message[smallMessages.size()]), + fp, new MessageRetrievalListener() { + @Override + public void messageFinished(final Message message, int number, int ofTotal) { + try { - if (K9.DEBUG) - Log.v(K9.LOG_TAG, "About to notify listeners that we got a new small message " - + account + ":" + folder + ":" + message.getUid()); + if (!shouldImportMessage(account, folder, message, progress, earliestDate)) { + progress.incrementAndGet(); + + return; + } + + // Store the updated message locally + final Message localMessage = localFolder.storeSmallMessage(message, new Runnable() { + @Override + public void run() { + progress.incrementAndGet(); + } + }); + + // Increment the number of "new messages" if the newly downloaded message is + // not marked as read. + if (!localMessage.isSet(Flag.SEEN)) { + newMessages.incrementAndGet(); + } + + if (K9.DEBUG) + Log.v(K9.LOG_TAG, "About to notify listeners that we got a new small message " + + account + ":" + folder + ":" + message.getUid()); + + // Update the listener with what we've found + for (MessagingListener l : getListeners()) { + l.synchronizeMailboxAddOrUpdateMessage(account, folder, localMessage); + l.synchronizeMailboxProgress(account, folder, progress.get(), todo); + if (!localMessage.isSet(Flag.SEEN)) { + l.synchronizeMailboxNewMessage(account, folder, localMessage); + } + } + // Send a notification of this message + + if (shouldNotifyForMessage(account, localFolder, message)) { + notifyAccount(mApplication, account, message, unreadBeforeStart, newMessages); + } + + } catch (MessagingException me) { + addErrorMessage(account, null, me); + Log.e(K9.LOG_TAG, "SYNC: fetch small messages", me); + } + } - // Update the listener with what we've found - for (MessagingListener l : getListeners()) { - l.synchronizeMailboxAddOrUpdateMessage(account, folder, localMessage); - l.synchronizeMailboxProgress(account, folder, progress.get(), todo); - if (!localMessage.isSet(Flag.SEEN)) { - l.synchronizeMailboxNewMessage(account, folder, localMessage); - } - } - // Send a notification of this message + @Override + public void messageStarted(String uid, int number, int ofTotal) {} - if (shouldNotifyForMessage(account, localFolder, message)) { - notifyAccount(mApplication, account, message, unreadBeforeStart, newMessages); + @Override + public void messagesFinished(int total) {} + }); + } catch (MessagingException me) { + throw new WrappedException(me); } - - } catch (MessagingException me) { - addErrorMessage(account, null, me); - Log.e(K9.LOG_TAG, "SYNC: fetch small messages", me); } - } - - @Override - public void messageStarted(String uid, int number, int ofTotal) {} - - @Override - public void messagesFinished(int total) {} - }); + }); + } catch (WrappedException we) { + throw (MessagingException) we.getCause(); + } if (K9.DEBUG) Log.d(K9.LOG_TAG, "SYNC: Done fetching small messages for folder " + folder); diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java index 4d35ef3c6e2..8eff89f1404 100644 --- a/src/com/fsck/k9/mail/store/LocalStore.java +++ b/src/com/fsck/k9/mail/store/LocalStore.java @@ -2008,6 +2008,23 @@ public Message doDbWork(final SQLiteDatabase db) throws WrappedException, Unavai }); } + /** + * Execute runnable within a transactional context, useful for batching + * multiple independently transactional methods, e.g., + * storeSmallMessage. + */ + public void executeRunnableInTransaction(final Runnable runnable) + throws MessagingException { + database.execute(true, new DbCallback() { + @Override + public Void doDbWork(final SQLiteDatabase db) + throws WrappedException, UnavailableStorageException { + runnable.run(); + return null; + } + }); + } + /** * The method differs slightly from the contract; If an incoming message already has a uid * assigned and it matches the uid of an existing message then this message will replace the