Add IMAP support for the "replied" state in messages
* Handle replied in new messages and updates * Code added for upsyncing replied state, but the CL for setting this state isn't yet submitted Change-Id: I6f3ff56475d70f686f96ed6a84fae3468f42b1c8
This commit is contained in:
parent
7891106a7d
commit
50a092c3d6
@ -584,17 +584,9 @@ public class Controller {
|
||||
// If this is a reply/forward, indicate it as such on the source.
|
||||
long sourceKey = message.mSourceKey;
|
||||
if (sourceKey != Message.NO_MESSAGE) {
|
||||
Message source = Message.restoreMessageWithId(mProviderContext, sourceKey);
|
||||
if (source != null) {
|
||||
boolean isReply = (message.mFlags & Message.FLAG_TYPE_REPLY) != 0;
|
||||
int flagUpdate = isReply ? Message.FLAG_REPLIED_TO : Message.FLAG_FORWARDED;
|
||||
uri = ContentUris.withAppendedId(Message.CONTENT_URI, sourceKey);
|
||||
cv.clear();
|
||||
cv.put(MessageColumns.FLAGS, source.mFlags | flagUpdate);
|
||||
resolver.update(uri, cv, null, null);
|
||||
} else {
|
||||
Log.w(Logging.LOG_TAG, "Unable to find source message for a reply/forward");
|
||||
}
|
||||
boolean isReply = (message.mFlags & Message.FLAG_TYPE_REPLY) != 0;
|
||||
int flagUpdate = isReply ? Message.FLAG_REPLIED_TO : Message.FLAG_FORWARDED;
|
||||
setMessageAnsweredOrForwarded(sourceKey, flagUpdate);
|
||||
}
|
||||
|
||||
sendPendingMessages(accountId);
|
||||
@ -871,6 +863,46 @@ public class Controller {
|
||||
return setMessageBoolean(messageId, EmailContent.MessageColumns.FLAG_READ, isRead);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a message record and ping MessagingController, if necessary
|
||||
*
|
||||
* @param messageId the message to update
|
||||
* @param cv the ContentValues used in the update
|
||||
*/
|
||||
private void updateMessageSync(long messageId, ContentValues cv) {
|
||||
Uri uri = ContentUris.withAppendedId(EmailContent.Message.SYNCED_CONTENT_URI, messageId);
|
||||
mProviderContext.getContentResolver().update(uri, cv, null, null);
|
||||
|
||||
// Service runs automatically, MessagingController needs a kick
|
||||
long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId);
|
||||
if (accountId == Account.NO_ACCOUNT) return;
|
||||
if (isMessagingController(accountId)) {
|
||||
mLegacyController.processPendingActions(accountId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the answered status of a message
|
||||
*
|
||||
* @param messageId the message to update
|
||||
* @return the AsyncTask that will execute the changes (for testing only)
|
||||
*/
|
||||
public void setMessageAnsweredOrForwarded(final long messageId,
|
||||
final int flag) {
|
||||
EmailAsyncTask.runAsyncParallel(new Runnable() {
|
||||
public void run() {
|
||||
Message msg = Message.restoreMessageWithId(mProviderContext, messageId);
|
||||
if (msg == null) {
|
||||
Log.w(Logging.LOG_TAG, "Unable to find source message for a reply/forward");
|
||||
return;
|
||||
}
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(MessageColumns.FLAGS, msg.mFlags | flag);
|
||||
updateMessageSync(messageId, cv);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set/clear the favorite status of a message
|
||||
*
|
||||
@ -897,18 +929,7 @@ public class Controller {
|
||||
public void run() {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(columnName, columnValue);
|
||||
Uri uri = ContentUris.withAppendedId(
|
||||
EmailContent.Message.SYNCED_CONTENT_URI, messageId);
|
||||
mProviderContext.getContentResolver().update(uri, cv, null, null);
|
||||
|
||||
// Service runs automatically, MessagingController needs a kick
|
||||
long accountId = Account.getAccountIdForMessageId(mProviderContext, messageId);
|
||||
if (accountId == -1) {
|
||||
return;
|
||||
}
|
||||
if (isMessagingController(accountId)) {
|
||||
mLegacyController.processPendingActions(accountId);
|
||||
}
|
||||
updateMessageSync(messageId, cv);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -16,6 +16,13 @@
|
||||
|
||||
package com.android.email;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.internet.MimeBodyPart;
|
||||
import com.android.emailcommon.internet.MimeHeader;
|
||||
@ -37,13 +44,6 @@ import com.android.emailcommon.utility.AttachmentUtilities;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -96,6 +96,9 @@ public class LegacyConversions {
|
||||
localMessage.mSubject = subject;
|
||||
}
|
||||
localMessage.mFlagRead = message.isSet(Flag.SEEN);
|
||||
if (message.isSet(Flag.ANSWERED)) {
|
||||
localMessage.mFlags |= EmailContent.Message.FLAG_REPLIED_TO;
|
||||
}
|
||||
|
||||
// Keep the message in the "unloaded" state until it has (at least) a display name.
|
||||
// This prevents early flickering of empty messages in POP download.
|
||||
|
@ -103,6 +103,7 @@ public class MessagingController implements Runnable {
|
||||
|
||||
private static final Flag[] FLAG_LIST_SEEN = new Flag[] { Flag.SEEN };
|
||||
private static final Flag[] FLAG_LIST_FLAGGED = new Flag[] { Flag.FLAGGED };
|
||||
private static final Flag[] FLAG_LIST_ANSWERED = new Flag[] { Flag.ANSWERED };
|
||||
|
||||
/**
|
||||
* We write this into the serverId field of messages that will never be upsynced.
|
||||
@ -388,10 +389,12 @@ public class MessagingController implements Runnable {
|
||||
private static final int COLUMN_FLAG_FAVORITE = 2;
|
||||
private static final int COLUMN_FLAG_LOADED = 3;
|
||||
private static final int COLUMN_SERVER_ID = 4;
|
||||
private static final int COLUMN_FLAGS = 7;
|
||||
private static final String[] PROJECTION = new String[] {
|
||||
EmailContent.RECORD_ID,
|
||||
MessageColumns.FLAG_READ, MessageColumns.FLAG_FAVORITE, MessageColumns.FLAG_LOADED,
|
||||
SyncColumns.SERVER_ID, MessageColumns.MAILBOX_KEY, MessageColumns.ACCOUNT_KEY
|
||||
SyncColumns.SERVER_ID, MessageColumns.MAILBOX_KEY, MessageColumns.ACCOUNT_KEY,
|
||||
MessageColumns.FLAGS
|
||||
};
|
||||
|
||||
final long mId;
|
||||
@ -399,6 +402,7 @@ public class MessagingController implements Runnable {
|
||||
final boolean mFlagFavorite;
|
||||
final int mFlagLoaded;
|
||||
final String mServerId;
|
||||
final int mFlags;
|
||||
|
||||
public LocalMessageInfo(Cursor c) {
|
||||
mId = c.getLong(COLUMN_ID);
|
||||
@ -406,6 +410,7 @@ public class MessagingController implements Runnable {
|
||||
mFlagFavorite = c.getInt(COLUMN_FLAG_FAVORITE) != 0;
|
||||
mFlagLoaded = c.getInt(COLUMN_FLAG_LOADED);
|
||||
mServerId = c.getString(COLUMN_SERVER_ID);
|
||||
mFlags = c.getInt(COLUMN_FLAGS);
|
||||
// Note: mailbox key and account key not needed - they are projected for the SELECT
|
||||
}
|
||||
}
|
||||
@ -855,6 +860,7 @@ public class MessagingController implements Runnable {
|
||||
remoteFolder.fetch(remoteMessages, fp, null);
|
||||
boolean remoteSupportsSeen = false;
|
||||
boolean remoteSupportsFlagged = false;
|
||||
boolean remoteSupportsAnswered = false;
|
||||
for (Flag flag : remoteFolder.getPermanentFlags()) {
|
||||
if (flag == Flag.SEEN) {
|
||||
remoteSupportsSeen = true;
|
||||
@ -862,9 +868,12 @@ public class MessagingController implements Runnable {
|
||||
if (flag == Flag.FLAGGED) {
|
||||
remoteSupportsFlagged = true;
|
||||
}
|
||||
if (flag == Flag.ANSWERED) {
|
||||
remoteSupportsAnswered = true;
|
||||
}
|
||||
}
|
||||
// Update the SEEN & FLAGGED (star) flags (if supported remotely - e.g. not for POP3)
|
||||
if (remoteSupportsSeen || remoteSupportsFlagged) {
|
||||
// Update SEEN/FLAGGED/ANSWERED (star) flags (if supported remotely - e.g. not for POP3)
|
||||
if (remoteSupportsSeen || remoteSupportsFlagged || remoteSupportsAnswered) {
|
||||
for (Message remoteMessage : remoteMessages) {
|
||||
LocalMessageInfo localMessageInfo = localMessageMap.get(remoteMessage.getUid());
|
||||
if (localMessageInfo == null) {
|
||||
@ -876,12 +885,22 @@ public class MessagingController implements Runnable {
|
||||
boolean localFlagged = localMessageInfo.mFlagFavorite;
|
||||
boolean remoteFlagged = remoteMessage.isSet(Flag.FLAGGED);
|
||||
boolean newFlagged = (remoteSupportsFlagged && (localFlagged != remoteFlagged));
|
||||
if (newSeen || newFlagged) {
|
||||
int localFlags = localMessageInfo.mFlags;
|
||||
boolean localAnswered = (localFlags & EmailContent.Message.FLAG_REPLIED_TO) != 0;
|
||||
boolean remoteAnswered = remoteMessage.isSet(Flag.ANSWERED);
|
||||
boolean newAnswered = (remoteSupportsAnswered && (localAnswered != remoteAnswered));
|
||||
if (newSeen || newFlagged || newAnswered) {
|
||||
Uri uri = ContentUris.withAppendedId(
|
||||
EmailContent.Message.CONTENT_URI, localMessageInfo.mId);
|
||||
ContentValues updateValues = new ContentValues();
|
||||
updateValues.put(EmailContent.Message.FLAG_READ, remoteSeen);
|
||||
updateValues.put(EmailContent.Message.FLAG_FAVORITE, remoteFlagged);
|
||||
updateValues.put(MessageColumns.FLAG_READ, remoteSeen);
|
||||
updateValues.put(MessageColumns.FLAG_FAVORITE, remoteFlagged);
|
||||
if (remoteAnswered) {
|
||||
localFlags |= EmailContent.Message.FLAG_REPLIED_TO;
|
||||
} else {
|
||||
localFlags &= ~EmailContent.Message.FLAG_REPLIED_TO;
|
||||
}
|
||||
updateValues.put(MessageColumns.FLAGS, localFlags);
|
||||
resolver.update(uri, updateValues, null, null);
|
||||
}
|
||||
}
|
||||
@ -1307,6 +1326,7 @@ public class MessagingController implements Runnable {
|
||||
boolean changeRead = false;
|
||||
boolean changeFlagged = false;
|
||||
boolean changeMailbox = false;
|
||||
boolean changeAnswered = false;
|
||||
|
||||
EmailContent.Message oldMessage =
|
||||
EmailContent.getContent(updates, EmailContent.Message.class);
|
||||
@ -1327,11 +1347,14 @@ public class MessagingController implements Runnable {
|
||||
}
|
||||
changeRead = oldMessage.mFlagRead != newMessage.mFlagRead;
|
||||
changeFlagged = oldMessage.mFlagFavorite != newMessage.mFlagFavorite;
|
||||
changeAnswered = (oldMessage.mFlags & EmailContent.Message.FLAG_REPLIED_TO) !=
|
||||
(newMessage.mFlags & EmailContent.Message.FLAG_REPLIED_TO);
|
||||
}
|
||||
|
||||
// Load the remote store if it will be needed
|
||||
if (remoteStore == null &&
|
||||
(changeMoveToTrash || changeRead || changeFlagged || changeMailbox)) {
|
||||
(changeMoveToTrash || changeRead || changeFlagged || changeMailbox ||
|
||||
changeAnswered)) {
|
||||
remoteStore = Store.getInstance(account, mContext);
|
||||
}
|
||||
|
||||
@ -1340,9 +1363,9 @@ public class MessagingController implements Runnable {
|
||||
// Move message to trash
|
||||
processPendingMoveToTrash(remoteStore, account, mailbox, oldMessage,
|
||||
newMessage);
|
||||
} else if (changeRead || changeFlagged || changeMailbox) {
|
||||
} else if (changeRead || changeFlagged || changeMailbox || changeAnswered) {
|
||||
processPendingDataChange(remoteStore, mailbox, changeRead, changeFlagged,
|
||||
changeMailbox, oldMessage, newMessage);
|
||||
changeMailbox, changeAnswered, oldMessage, newMessage);
|
||||
}
|
||||
|
||||
// Finally, delete the update
|
||||
@ -1426,8 +1449,9 @@ public class MessagingController implements Runnable {
|
||||
* @param newMessage the current version of the message
|
||||
*/
|
||||
private void processPendingDataChange(Store remoteStore, Mailbox mailbox, boolean changeRead,
|
||||
boolean changeFlagged, boolean changeMailbox, EmailContent.Message oldMessage,
|
||||
final EmailContent.Message newMessage) throws MessagingException {
|
||||
boolean changeFlagged, boolean changeMailbox, boolean changeAnswered,
|
||||
EmailContent.Message oldMessage, final EmailContent.Message newMessage)
|
||||
throws MessagingException {
|
||||
// New mailbox is the mailbox this message WILL be in (same as the one it WAS in if it isn't
|
||||
// being moved
|
||||
Mailbox newMailbox = mailbox;
|
||||
@ -1465,6 +1489,8 @@ public class MessagingController implements Runnable {
|
||||
"Update for msg id=" + newMessage.mId
|
||||
+ " read=" + newMessage.mFlagRead
|
||||
+ " flagged=" + newMessage.mFlagFavorite
|
||||
+ " answered="
|
||||
+ ((newMessage.mFlags & EmailContent.Message.FLAG_REPLIED_TO) != 0)
|
||||
+ " new mailbox=" + newMessage.mMailboxKey);
|
||||
}
|
||||
Message[] messages = new Message[] { remoteMessage };
|
||||
@ -1474,6 +1500,10 @@ public class MessagingController implements Runnable {
|
||||
if (changeFlagged) {
|
||||
remoteFolder.setFlags(messages, FLAG_LIST_FLAGGED, newMessage.mFlagFavorite);
|
||||
}
|
||||
if (changeAnswered) {
|
||||
remoteFolder.setFlags(messages, FLAG_LIST_ANSWERED,
|
||||
(newMessage.mFlags & EmailContent.Message.FLAG_REPLIED_TO) != 0);
|
||||
}
|
||||
if (changeMailbox) {
|
||||
Folder toFolder = remoteStore.getFolder(newMailbox.mServerId);
|
||||
if (!remoteFolder.exists()) {
|
||||
|
@ -62,7 +62,8 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
class ImapFolder extends Folder {
|
||||
private final static Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.SEEN, Flag.FLAGGED };
|
||||
private final static Flag[] PERMANENT_FLAGS =
|
||||
{ Flag.DELETED, Flag.SEEN, Flag.FLAGGED, Flag.ANSWERED };
|
||||
private static final int COPY_BUFFER_SIZE = 16*1024;
|
||||
|
||||
private final ImapStore mStore;
|
||||
@ -993,6 +994,8 @@ class ImapFolder extends Folder {
|
||||
flagList.append(" " + ImapConstants.FLAG_DELETED);
|
||||
} else if (flag == Flag.FLAGGED) {
|
||||
flagList.append(" " + ImapConstants.FLAG_FLAGGED);
|
||||
} else if (flag == Flag.ANSWERED) {
|
||||
flagList.append(" " + ImapConstants.FLAG_ANSWERED);
|
||||
}
|
||||
}
|
||||
allFlags = flagList.substring(1);
|
||||
|
Loading…
Reference in New Issue
Block a user