am 580b3f7b: Merge "Fix attachments in search results" into jb-ub-mail-ur10

* commit '580b3f7b380cb72ed66bb92a68e2b194344ce97b':
  Fix attachments in search results
This commit is contained in:
Martin Hibdon 2013-11-06 12:24:39 -08:00 committed by Android Git Automerger
commit 5e78ddd2a0
3 changed files with 63 additions and 24 deletions

View File

@ -657,10 +657,13 @@ class ImapFolder extends Folder {
fetchFields.add(ImapConstants.FETCH_FIELD_BODY_PEEK);
}
// TODO Why are we only fetching the first part given?
final Part fetchPart = fp.getFirstPart();
if (fetchPart != null) {
final String[] partIds =
fetchPart.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA);
// TODO Why can a single part have more than one Id? And why should we only fetch
// the first id if there are more than one?
if (partIds != null) {
fetchFields.add(ImapConstants.FETCH_FIELD_BODY_PEEK_BARE
+ "[" + partIds[0] + "]");
@ -725,7 +728,7 @@ class ImapFolder extends Folder {
parseBodyStructure(bs, message, ImapConstants.TEXT);
} catch (MessagingException e) {
if (Logging.LOGD) {
LogUtils.v(Logging.LOG_TAG, "Error handling message", e);
LogUtils.v(Logging.LOG_TAG, e, "Error handling message");
}
message.setBody(null);
}

View File

@ -98,7 +98,6 @@ public class Utilities {
public static void copyOneMessageToProvider(Context context, Message message,
EmailContent.Message localMessage, int loadStatus) {
try {
EmailContent.Body body = null;
if (localMessage.mId != EmailContent.Message.NO_MESSAGE) {
body = EmailContent.Body.restoreBodyWithMessageId(context, localMessage.mId);
@ -143,12 +142,19 @@ public class Utilities {
// Since we haven't actually loaded the attachment, we're just putting
// a dummy placeholder here. When the user taps on it, we'll load the attachment
// for real.
// TODO: This is not really a great way to model this.... could we at least get
// the file names and mime types from the attachments? Then we could display
// something sensible at least. This may be impossible in POP, but maybe
// we could put a flag on the message indicating that there are undownloaded
// attachments, rather than this dummy placeholder, which causes a lot of
// special case handling in a lot of places.
// TODO: This is not a great way to model this. What we're saying is, we don't
// have the complete message, without paying any attention to what we do have.
// Did the main body exceed the maximum initial size? If so, we really might
// not have any attachments at all, and we just need a button somewhere that
// says "load the rest of the message".
// Or, what if we were able to load some, but not all of the attachments?
// Then we should ideally not be dropping the data we have on the floor.
// Also, what behavior we have here really should be based on what protocol
// we're dealing with. If it's POP, then we don't actually know how many
// attachments we have until we've loaded the complete message.
// If it's IMAP, we should know that, and we should load all attachment
// metadata we can get, regardless of whether or not we have the complete
// message body.
att.mFileName = "";
att.mSize = message.getSize();
att.mMimeType = "text/plain";

View File

@ -310,7 +310,6 @@ public class ImapService extends Service {
LogUtils.e(Logging.LOG_TAG,
"Error while copying downloaded message." + me);
}
}
}
catch (Exception e) {
@ -592,8 +591,9 @@ public class ImapService extends Service {
localMessageMap, unseenMessages);
}
// 11. Refresh the flags for any messages in the local store that we
// didn't just download.
// 11. Refresh the flags for any messages in the local store that we didn't just download.
// TODO This is a bit wasteful because we're also updating any messages we already did get
// the flags and envelope for previously.
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.FLAGS);
remoteFolder.fetch(remoteMessages, fp, null);
@ -1461,21 +1461,25 @@ public class ImapService extends Service {
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();
// First fetch FLAGS and ENVELOPE. In a second pass, we'll fetch STRUCTURE and
// the first body part.
final 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[messageList.size()]), fp,
new MessageRetrievalListener() {
Message[] messageArray = messageList.toArray(new Message[messageList.size()]);
// TODO: Why should we do this with a messageRetrievalListener? It updates the messages
// directly in the messageArray. After making this call, we could simply walk it
// and do all of these operations ourselves.
remoteFolder.fetch(messageArray, fp, new MessageRetrievalListener() {
@Override
public void messageRetrieved(Message message) {
// TODO: Why do we have two separate try/catch blocks here?
// After MR1, we should consolidate this.
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,
@ -1491,10 +1495,8 @@ public class ImapService extends Service {
// This will be used by loadMessageForView, etc. to use the proper remote
// folder
localMessage.mProtocolSearchInfo = mailbox.mServerId;
if (message.getSize() > Store.FETCH_BODY_SANE_SUGGESTED_SIZE) {
flag = EmailContent.Message.FLAG_LOADED_PARTIAL;
}
Utilities.copyOneMessageToProvider(context, message, localMessage, flag);
// Commit the message to the local store
Utilities.saveOrUpdate(localMessage, context);
} catch (MessagingException me) {
LogUtils.e(Logging.LOG_TAG,
"Error while copying downloaded message." + me);
@ -1509,6 +1511,34 @@ public class ImapService extends Service {
public void loadAttachmentProgress(int progress) {
}
});
// Now load the structure for all of the messages:
fp.clear();
fp.add(FetchProfile.Item.STRUCTURE);
remoteFolder.fetch(messageArray, fp, null);
// Finally, load the first body part (i.e. message text).
// This means attachment contents are not yet loaded, but that's okay,
// we'll load them as needed, same as in synced messages.
Message [] oneMessageArray = new Message[1];
for (Message message : messageArray) {
// Build a list of parts we are interested in. Text parts will be downloaded
// right now, attachments will be left for later.
ArrayList<Part> viewables = new ArrayList<Part>();
ArrayList<Part> attachments = new ArrayList<Part>();
MimeUtility.collectParts(message, viewables, attachments);
// Download the viewables immediately
oneMessageArray[0] = message;
for (Part part : viewables) {
fp.clear();
fp.add(part);
remoteFolder.fetch(oneMessageArray, fp, null);
}
// Store the updated message locally and mark it fully loaded
Utilities.copyOneMessageToProvider(context, message, account, destMailbox,
EmailContent.Message.FLAG_LOADED_COMPLETE);
}
// Tell UI that we're done loading messages
statusValues.put(Mailbox.SYNC_TIME, System.currentTimeMillis());
statusValues.put(Mailbox.UI_SYNC_STATUS, UIProvider.SyncStatus.NO_SYNC);