diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java index 006932392..a7ad6a0d4 100644 --- a/src/com/fsck/k9/activity/MessageList.java +++ b/src/com/fsck/k9/activity/MessageList.java @@ -8,6 +8,7 @@ import java.util.EnumMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.Future; import android.app.AlertDialog; import android.app.Dialog; @@ -72,6 +73,8 @@ import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.Message; +import com.fsck.k9.mail.Store; +import com.fsck.k9.mail.store.ImapStore; import com.fsck.k9.mail.store.LocalStore; import com.fsck.k9.mail.store.LocalStore.LocalFolder; import com.fsck.k9.mail.store.StorageManager; @@ -300,6 +303,7 @@ public class MessageList extends K9ListActivity implements OnItemClickListener { private boolean mRemoteSearch = false; private String mSearchAccount = null; private String mSearchFolder = null; + private Future mRemoteSearchFuture = null; private boolean mIntegrate = false; private String[] mAccountUuids = null; private String[] mFolderNames = null; @@ -983,7 +987,7 @@ public class MessageList extends K9ListActivity implements OnItemClickListener { if (mAdapter.isEmpty()) { if (mRemoteSearch) { //TODO: Support flag based search - mController.searchRemoteMessages(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener); + mRemoteSearchFuture = mController.searchRemoteMessages(mSearchAccount, mSearchFolder, mQueryString, null, null, mAdapter.mListener); } else if (mFolderName != null) { mController.listLocalMessages(mAccount, mFolderName, mAdapter.mListener); // Hide the archive button if we don't have an archive folder. @@ -1585,6 +1589,36 @@ public class MessageList extends K9ListActivity implements OnItemClickListener { mController.sendPendingMessages(account, mAdapter.mListener); } + /** + * We need to do some special clean up when leaving a remote search result screen. If no remote search is + * in progress, this method does nothing special. + */ + @Override + public void onBackPressed() { + // If we represent a remote search, then kill that before going back. + if(mSearchAccount != null && mSearchFolder != null && mRemoteSearchFuture != null) { + try { + Log.i(K9.LOG_TAG, "Remote search in progress, attempting to abort..."); + // Canceling the future stops any message fetches in progress. + final boolean cancelSuccess = mRemoteSearchFuture.cancel(true); // mayInterruptIfRunning = true + if (!cancelSuccess) { + Log.e(K9.LOG_TAG, "Could not cancel remote search future."); + } + // Closing the folder will kill off the connection if we're mid-search. + final Account searchAccount = Preferences.getPreferences(this).getAccount(mSearchAccount); + final Store remoteStore = searchAccount.getRemoteStore(); + final Folder remoteFolder = remoteStore.getFolder(mSearchFolder); + remoteFolder.close(); + // Send a remoteSearchFinished() message for good measure. + mAdapter.mListener.remoteSearchFinished(searchAccount, mSearchFolder, 0, null); + } catch (Exception e) { + // Since the user is going back, log and squash any exceptions. + Log.e(K9.LOG_TAG, "Could not abort remote search before going back", e); + } + } + super.onBackPressed(); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index b235ebeb4..d5860a4c3 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -1,4 +1,3 @@ - package com.fsck.k9.controller; import java.io.CharArrayWriter; @@ -16,13 +15,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -790,7 +783,7 @@ public class MessagingController implements Runnable { - public void searchRemoteMessages(final String acctUuid, final String folderName, final String query, final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener) { + public Future searchRemoteMessages(final String acctUuid, final String folderName, final String query, final Flag[] requiredFlags, final Flag[] forbiddenFlags, final MessagingListener listener) { if (K9.DEBUG) { String msg = "searchRemoteMessages (" + "acct=" + acctUuid @@ -800,7 +793,7 @@ public class MessagingController implements Runnable { Log.i(K9.LOG_TAG, msg); } - threadPool.execute(new Runnable() { + return threadPool.submit(new Runnable() { @Override public void run() { searchRemoteMessagesSynchronous(acctUuid, folderName, query, requiredFlags, forbiddenFlags, listener); @@ -852,11 +845,15 @@ public class MessagingController implements Runnable { } catch (Exception e) { - Log.e(K9.LOG_TAG, "Could not complete remote search", e); - if (listener != null) { - listener.remoteSearchFailed(acct, null, e.getMessage()); + if (Thread.currentThread().isInterrupted()) { + Log.i(K9.LOG_TAG, "Caught exception on aborted remote search; safe to ignore.", e); + } else { + Log.e(K9.LOG_TAG, "Could not complete remote search", e); + if (listener != null) { + listener.remoteSearchFailed(acct, null, e.getMessage()); + } + addErrorMessage(acct, null, e); } - addErrorMessage(acct, null, e); } finally { if (listener != null) { listener.remoteSearchFinished(acct, folderName, 0, extraResults); diff --git a/src/com/fsck/k9/mail/store/ImapStore.java b/src/com/fsck/k9/mail/store/ImapStore.java index 02c83eb28..11f27e327 100644 --- a/src/com/fsck/k9/mail/store/ImapStore.java +++ b/src/com/fsck/k9/mail/store/ImapStore.java @@ -820,7 +820,7 @@ public class ImapStore extends Store { private volatile boolean mExists; private ImapStore store = null; Map msgSeqUidMap = new ConcurrentHashMap(); - + private boolean mInSearch = false; public ImapFolder(ImapStore nStore, String name) { super(nStore.getAccount()); @@ -1000,7 +1000,13 @@ public class ImapStore extends Store { } synchronized (this) { - releaseConnection(mConnection); + // If we are mid-search and we get a close request, we gotta trash the connection. + if (mInSearch && mConnection != null) { + Log.i(K9.LOG_TAG, "IMAP search was aborted, shutting down connection."); + mConnection.close(); + } else { + releaseConnection(mConnection); + } mConnection = null; } } @@ -2307,11 +2313,11 @@ public class ImapStore extends Store { open(OpenMode.READ_ONLY); checkOpen(); - //don't pass listener--we don't want to add messages until we've downloaded them + mInSearch = true; + // don't pass listener--we don't want to add messages until we've downloaded them return search(searcher, null); - } catch (Exception e) { - Log.e(K9.LOG_TAG, "Exception caught during remote search", e); - throw new MessagingException("Error during search: " + e.toString()); + } finally { + mInSearch = false; } }