Merge "some brain dead typing shortening"
diff --git a/emailcommon/src/com/android/emailcommon/provider/Mailbox.java b/emailcommon/src/com/android/emailcommon/provider/Mailbox.java
index 9e292ce..589a3a0 100644
--- a/emailcommon/src/com/android/emailcommon/provider/Mailbox.java
+++ b/emailcommon/src/com/android/emailcommon/provider/Mailbox.java
@@ -390,7 +390,6 @@
}
switch (getMailboxType(context, mailboxId)) {
case -1: // not found
- case TYPE_SEARCH:
case TYPE_DRAFTS:
case TYPE_OUTBOX:
return false;
diff --git a/emailcommon/src/com/android/emailcommon/service/SearchParams.java b/emailcommon/src/com/android/emailcommon/service/SearchParams.java
index 1107aca..9c4ab2e 100644
--- a/emailcommon/src/com/android/emailcommon/service/SearchParams.java
+++ b/emailcommon/src/com/android/emailcommon/service/SearchParams.java
@@ -16,15 +16,15 @@
package com.android.emailcommon.service;
-import com.android.emailcommon.provider.Mailbox;
-
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.emailcommon.provider.Mailbox;
+
public class SearchParams implements Parcelable {
public static final long ALL_MAILBOXES = Mailbox.NO_MAILBOX;
- private static final int DEFAULT_LIMIT = 20;
+ private static final int DEFAULT_LIMIT = 10; // Need input on what this number should be
private static final int DEFAULT_OFFSET = 0;
// The id of the mailbox to be searched; if -1, all mailboxes MUST be searched
diff --git a/src/com/android/email/Controller.java b/src/com/android/email/Controller.java
index 2069481..0023469 100644
--- a/src/com/android/email/Controller.java
+++ b/src/com/android/email/Controller.java
@@ -62,6 +62,7 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.ConcurrentHashMap;
@@ -392,8 +393,7 @@
IEmailService service = getServiceForAccount(accountId);
if (service != null) {
- // Service implementation
- try {
+ try {
service.startSync(mailboxId, userRequest);
} catch (RemoteException e) {
// TODO Change exception handling to be consistent with however this method
@@ -409,7 +409,8 @@
Account.restoreAccountWithId(mProviderContext, accountId);
Mailbox mailbox =
Mailbox.restoreMailboxWithId(mProviderContext, mailboxId);
- if (account == null || mailbox == null) {
+ if (account == null || mailbox == null ||
+ mailbox.mType == Mailbox.TYPE_SEARCH) {
return;
}
mLegacyController.synchronizeMailbox(account, mailbox, mLegacyListener);
@@ -669,12 +670,20 @@
* @param mailboxId the mailbox
*/
public void loadMoreMessages(final long mailboxId) {
- Utility.runAsync(new Runnable() {
+ EmailAsyncTask.runAsyncParallel(new Runnable() {
public void run() {
Mailbox mailbox = Mailbox.restoreMailboxWithId(mProviderContext, mailboxId);
if (mailbox == null) {
return;
}
+ if (mailbox.mType == Mailbox.TYPE_SEARCH) {
+ try {
+ searchMore(mailbox.mAccountKey);
+ } catch (MessagingException e) {
+ // Nothing to be done
+ }
+ return;
+ }
Account account = Account.restoreAccountWithId(mProviderContext,
mailbox.mAccountKey);
if (account == null) {
@@ -886,6 +895,16 @@
});
}
+ private static final HashMap<Long, SearchParams> sSearchParamsMap =
+ new HashMap<Long, SearchParams>();
+
+ public void searchMore(long accountId) throws MessagingException {
+ SearchParams params = sSearchParamsMap.get(accountId);
+ if (params == null) return;
+ params.mOffset += params.mLimit;
+ searchMessages(accountId, params);
+ }
+
/**
* Search for messages on the (IMAP) server; do not call this on the UI thread!
* @param accountId the id of the account to be searched
@@ -898,7 +917,8 @@
Mailbox searchMailbox = getSearchMailbox(accountId);
if (searchMailbox == null) return;
final long searchMailboxId = searchMailbox.mId;
-
+ // Save this away (per account)
+ sSearchParamsMap.put(accountId, searchParams);
IEmailService service = getServiceForAccount(accountId);
if (service != null) {
// Service implementation
@@ -918,18 +938,20 @@
return;
}
- // Delete existing contents of search mailbox
- ContentResolver resolver = mContext.getContentResolver();
- resolver.delete(Message.CONTENT_URI, Message.MAILBOX_KEY + "=" + searchMailboxId,
- null);
- ContentValues cv = new ContentValues();
- // For now, use the actual query as the name of the mailbox
- cv.put(Mailbox.DISPLAY_NAME, searchParams.mFilter);
- // But use the server id of the actual mailbox we're searching; this allows full
- // message loading to work normally (clever, huh?)
- cv.put(MailboxColumns.SERVER_ID, actualMailbox.mServerId);
- resolver.update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, searchMailboxId), cv,
- null, null);
+ if (searchParams.mOffset == 0) {
+ // Delete existing contents of search mailbox
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.delete(Message.CONTENT_URI, Message.MAILBOX_KEY + "=" + searchMailboxId,
+ null);
+ ContentValues cv = new ContentValues();
+ // For now, use the actual query as the name of the mailbox
+ cv.put(Mailbox.DISPLAY_NAME, searchParams.mFilter);
+ // But use the server id of the actual mailbox we're searching; this allows full
+ // message loading to work normally (clever, huh?)
+ cv.put(MailboxColumns.SERVER_ID, actualMailbox.mServerId);
+ resolver.update(ContentUris.withAppendedId(Mailbox.CONTENT_URI, searchMailboxId),
+ cv, null, null);
+ }
// Do the search
if (Email.DEBUG) {
Log.d(Logging.LOG_TAG, "Search: " + searchParams.mFilter);
diff --git a/src/com/android/email/MessagingController.java b/src/com/android/email/MessagingController.java
index 19471d1..5517e9c 100644
--- a/src/com/android/email/MessagingController.java
+++ b/src/com/android/email/MessagingController.java
@@ -108,6 +108,14 @@
*/
private static final String LOCAL_SERVERID_PREFIX = "Local-";
+ /**
+ * Cache search results by account; this allows for "load more" support without having to
+ * redo the search (which can be quite slow). SortableMessage is a smallish class, so memory
+ * shouldn't be an issue
+ */
+ private static final HashMap<Long, SortableMessage[]> sSearchResults =
+ new HashMap<Long, SortableMessage[]>();
+
private static final ContentValues PRUNE_ATTACHMENT_CV = new ContentValues();
static {
PRUNE_ATTACHMENT_CV.putNull(AttachmentColumns.CONTENT_URI);
@@ -572,8 +580,19 @@
}
}
- public void searchMailbox(long accountId, SearchParams searchParams, final long destMailboxId)
+ public void searchMailbox(long accountId, SearchParams searchParams, long destMailboxId)
throws MessagingException {
+ try {
+ searchMailboxImpl(accountId, searchParams, destMailboxId);
+ } finally {
+ // Tell UI that we're done loading any search results (no harm calling this even if we
+ // encountered an error or never sent a "started" message)
+ mListeners.synchronizeMailboxFinished(accountId, destMailboxId, 0, 0, null);
+ }
+ }
+
+ private void searchMailboxImpl(long accountId, SearchParams searchParams,
+ final long destMailboxId) throws MessagingException {
final Account account = Account.restoreAccountWithId(mContext, accountId);
final Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, searchParams.mMailboxId);
final Mailbox destMailbox = Mailbox.restoreMailboxWithId(mContext, destMailboxId);
@@ -583,77 +602,92 @@
return;
}
+ // Tell UI that we're loading messages
+ mListeners.synchronizeMailboxStarted(accountId, destMailbox.mId);
+
Store remoteStore = Store.getInstance(account, mContext, null);
Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId);
remoteFolder.open(OpenMode.READ_WRITE, null);
- // Get the "bare" messages (basically uid)
- Message[] remoteMessages = remoteFolder.getMessages(searchParams, null);
- int remoteCount = remoteMessages.length;
- if (remoteCount > 0) {
- SortableMessage[] sortableMessages = new SortableMessage[remoteCount];
- int i = 0;
- for (Message msg : remoteMessages) {
- sortableMessages[i++] = new SortableMessage(msg, Long.parseLong(msg.getUid()));
- }
- // Sort the uid's, most recent first
- // Note: Not all servers will be nice and return results in the order we request them;
- // those that do will see messages arrive from newest to oldest (i.e. the "right" order)
- Arrays.sort(sortableMessages, new Comparator<SortableMessage>() {
- @Override
- public int compare(SortableMessage lhs, SortableMessage rhs) {
- return lhs.mUid > rhs.mUid ? -1 : lhs.mUid < rhs.mUid ? 1 : 0;
+ SortableMessage[] sortableMessages = new SortableMessage[0];
+ if (searchParams.mOffset == 0) {
+ // Get the "bare" messages (basically uid)
+ Message[] remoteMessages = remoteFolder.getMessages(searchParams, null);
+ int remoteCount = remoteMessages.length;
+ if (remoteCount > 0) {
+ sortableMessages = new SortableMessage[remoteCount];
+ int i = 0;
+ for (Message msg : remoteMessages) {
+ sortableMessages[i++] = new SortableMessage(msg, Long.parseLong(msg.getUid()));
}
- });
- final ArrayList<Message> messageList = new ArrayList<Message>();
- // Now create a list sized for our visible limit and fill it in
- int messageListSize = Math.min(remoteCount, Email.VISIBLE_LIMIT_DEFAULT);
- for (i = 0; i < messageListSize; i++) {
- messageList.add(sortableMessages[i].mMessage);
+ // Sort the uid's, most recent first
+ // Note: Not all servers will be nice and return results in the order of request;
+ // those that do will see messages arrive from newest to oldest
+ Arrays.sort(sortableMessages, new Comparator<SortableMessage>() {
+ @Override
+ public int compare(SortableMessage lhs, SortableMessage rhs) {
+ return lhs.mUid > rhs.mUid ? -1 : lhs.mUid < rhs.mUid ? 1 : 0;
+ }
+ });
+ sSearchResults.put(accountId, sortableMessages);
}
- // Get everything in one pass, rather than two (as in sync); this starts getting us
- // usable results quickly.
- FetchProfile fp = new FetchProfile();
- fp.add(FetchProfile.Item.FLAGS);
- fp.add(FetchProfile.Item.ENVELOPE);
- fp.add(FetchProfile.Item.STRUCTURE);
- fp.add(FetchProfile.Item.BODY_SANE);
- remoteFolder.fetch(messageList.toArray(new Message[0]), fp,
- new MessageRetrievalListener() {
- public void messageRetrieved(Message message) {
- try {
- // Determine if the new message was already known (e.g. partial)
- // And create or reload the full message info
- EmailContent.Message localMessage = new EmailContent.Message();
- try {
- // Copy the fields that are available into the message
- LegacyConversions.updateMessageFields(localMessage,
- message, account.mId, mailbox.mId);
- // Commit the message to the local store
- saveOrUpdate(localMessage, mContext);
- localMessage.mMailboxKey = destMailboxId;
- // We load 50k or so; maybe it's complete, maybe not...
- int flag = EmailContent.Message.FLAG_LOADED_COMPLETE;
- if (message.getSize() > Store.FETCH_BODY_SANE_SUGGESTED_SIZE) {
- flag = EmailContent.Message.FLAG_LOADED_PARTIAL;
- }
- copyOneMessageToProvider(message, localMessage, flag, mContext);
- } catch (MessagingException me) {
- Log.e(Logging.LOG_TAG,
- "Error while copying downloaded message." + me);
- }
- } catch (Exception e) {
- Log.e(Logging.LOG_TAG,
- "Error while storing downloaded message." + e.toString());
- }
- }
+ } else {
+ sortableMessages = sSearchResults.get(accountId);
+ }
- @Override
- public void loadAttachmentProgress(int progress) {
+ int numSearchResults = sortableMessages.length;
+ int numToLoad = Math.min(numSearchResults - searchParams.mOffset, searchParams.mLimit);
+ if (numToLoad <= 0) {
+ return;
+ }
+
+ final ArrayList<Message> messageList = new ArrayList<Message>();
+ for (int i = searchParams.mOffset; i < numToLoad + searchParams.mOffset; i++) {
+ messageList.add(sortableMessages[i].mMessage);
+ }
+ // Get everything in one pass, rather than two (as in sync); this starts getting us
+ // usable results quickly.
+ FetchProfile fp = new FetchProfile();
+ fp.add(FetchProfile.Item.FLAGS);
+ fp.add(FetchProfile.Item.ENVELOPE);
+ fp.add(FetchProfile.Item.STRUCTURE);
+ fp.add(FetchProfile.Item.BODY_SANE);
+ remoteFolder.fetch(messageList.toArray(new Message[0]), fp,
+ new MessageRetrievalListener() {
+ public void messageRetrieved(Message message) {
+ try {
+ // Determine if the new message was already known (e.g. partial)
+ // And create or reload the full message info
+ EmailContent.Message localMessage = new EmailContent.Message();
+ try {
+ // Copy the fields that are available into the message
+ LegacyConversions.updateMessageFields(localMessage,
+ message, account.mId, mailbox.mId);
+ // Commit the message to the local store
+ saveOrUpdate(localMessage, mContext);
+ localMessage.mMailboxKey = destMailboxId;
+ // We load 50k or so; maybe it's complete, maybe not...
+ int flag = EmailContent.Message.FLAG_LOADED_COMPLETE;
+ if (message.getSize() > Store.FETCH_BODY_SANE_SUGGESTED_SIZE) {
+ flag = EmailContent.Message.FLAG_LOADED_PARTIAL;
}
- });
- }
- }
+ copyOneMessageToProvider(message, localMessage, flag, mContext);
+ } catch (MessagingException me) {
+ Log.e(Logging.LOG_TAG,
+ "Error while copying downloaded message." + me);
+ }
+ } catch (Exception e) {
+ Log.e(Logging.LOG_TAG,
+ "Error while storing downloaded message." + e.toString());
+ }
+ }
+
+ @Override
+ public void loadAttachmentProgress(int progress) {
+ }
+ });
+ }
+
/**
* Generic synchronizer - used for POP3 and IMAP.