diff options
| author | Marc Blank <mblank@google.com> | 2009-12-04 12:49:28 -0800 |
|---|---|---|
| committer | Marc Blank <mblank@google.com> | 2009-12-16 12:01:08 -0800 |
| commit | 608ca667b25e6107d20bf2fac8243a42abfad719 (patch) | |
| tree | 8d0c9da5f9e2f11ca7d0a38f236ebc300297a9fc /src | |
| parent | 14d3745f9556232da05c9cd319c097a3e6f791b5 (diff) | |
| download | android_packages_apps_Email-608ca667b25e6107d20bf2fac8243a42abfad719.tar.gz android_packages_apps_Email-608ca667b25e6107d20bf2fac8243a42abfad719.tar.bz2 android_packages_apps_Email-608ca667b25e6107d20bf2fac8243a42abfad719.zip | |
Don't delete referenced messages from the Exchange server DO NOT MERGE
* Addresses #2287439 incompletely
* The most likely reason for a reply/forward to get stuck in the Outbox
is that the referenced message has been deleted from the client, with
the deletion occuring BEFORE the message gets sent (currently, the two
are completely independent)
* This change causes deletes NOT to be sent to the server if the message
to be deleted is referenced by an outgoing message
Change-Id: Iad3777282385bea82276f363d6f95ba8b07cc01c
Diffstat (limited to 'src')
| -rw-r--r-- | src/com/android/email/provider/EmailContent.java | 6 | ||||
| -rw-r--r-- | src/com/android/exchange/adapter/EmailSyncAdapter.java | 83 |
2 files changed, 67 insertions, 22 deletions
diff --git a/src/com/android/email/provider/EmailContent.java b/src/com/android/email/provider/EmailContent.java index 62c7c537e..955ea0d27 100644 --- a/src/com/android/email/provider/EmailContent.java +++ b/src/com/android/email/provider/EmailContent.java @@ -185,7 +185,9 @@ public abstract class EmailContent { public static final String HTML_REPLY = "htmlReply"; // Replied-to or forwarded body (in text form) public static final String TEXT_REPLY = "textReply"; - // Message id of the source (if this is a reply/forward) + // A reference to a message's unique id used in reply/forward. + // Protocol code can be expected to use this column in determining whether a message can be + // deleted safely (i.e. isn't referenced by other messages) public static final String SOURCE_MESSAGE_KEY = "sourceMessageKey"; // The text to be placed between a reply/forward response and the original message public static final String INTRO_TEXT = "introText"; @@ -519,7 +521,7 @@ public abstract class EmailContent { public String mBcc; public String mReplyTo; - // The following transient members may be used while building and manipulating messages, + // The following transient members may be used while building and manipulating messages, // but they are NOT persisted directly by EmailProvider transient public String mText; transient public String mHtml; diff --git a/src/com/android/exchange/adapter/EmailSyncAdapter.java b/src/com/android/exchange/adapter/EmailSyncAdapter.java index 6a5d2a5cd..946ae4e95 100644 --- a/src/com/android/exchange/adapter/EmailSyncAdapter.java +++ b/src/com/android/exchange/adapter/EmailSyncAdapter.java @@ -24,6 +24,7 @@ import com.android.email.provider.EmailProvider; import com.android.email.provider.EmailContent.Account; import com.android.email.provider.EmailContent.AccountColumns; import com.android.email.provider.EmailContent.Attachment; +import com.android.email.provider.EmailContent.Body; import com.android.email.provider.EmailContent.Mailbox; import com.android.email.provider.EmailContent.Message; import com.android.email.provider.EmailContent.MessageColumns; @@ -65,8 +66,10 @@ public class EmailSyncAdapter extends AbstractSyncAdapter { private static final String[] MESSAGE_ID_SUBJECT_PROJECTION = new String[] { Message.RECORD_ID, MessageColumns.SUBJECT }; + private static final String WHERE_BODY_SOURCE_MESSAGE_KEY = Body.SOURCE_MESSAGE_KEY + "=?"; - String[] bindArguments = new String[2]; + String[] mBindArguments = new String[2]; + String[] mBindArgument = new String[1]; ArrayList<Long> mDeletedIdList = new ArrayList<Long>(); ArrayList<Long> mUpdatedIdList = new ArrayList<Long>(); @@ -308,10 +311,10 @@ public class EmailSyncAdapter extends AbstractSyncAdapter { } private Cursor getServerIdCursor(String serverId, String[] projection) { - bindArguments[0] = serverId; - bindArguments[1] = mMailboxIdAsString; + mBindArguments[0] = serverId; + mBindArguments[1] = mMailboxIdAsString; return mContentResolver.query(Message.CONTENT_URI, projection, - WHERE_SERVER_ID_AND_MAILBOX_KEY, bindArguments, null); + WHERE_SERVER_ID_AND_MAILBOX_KEY, mBindArguments, null); } private void deleteParser(ArrayList<Long> deletes, int entryTag) throws IOException { @@ -562,46 +565,86 @@ public class EmailSyncAdapter extends AbstractSyncAdapter { return sb.toString(); } - @Override - public boolean sendLocalChanges(Serializer s) throws IOException { - ContentResolver cr = mContext.getContentResolver(); - - // Never upsync from these folders - if (mMailbox.mType == Mailbox.TYPE_DRAFTS || mMailbox.mType == Mailbox.TYPE_OUTBOX) { - return false; + /** + * Note that messages in the deleted database preserve the message's unique id; therefore, we + * can utilize this id to find references to the message. The only reference situation at this + * point is in the Body table; it is when sending messages via SmartForward and SmartReply + */ + private boolean messageReferenced(ContentResolver cr, long id) { + mBindArgument[0] = Long.toString(id); + // See if this id is referenced in a body + Cursor c = cr.query(Body.CONTENT_URI, Body.ID_PROJECTION, WHERE_BODY_SOURCE_MESSAGE_KEY, + mBindArgument, null); + try { + return c.moveToFirst(); + } finally { + c.close(); } + } + + /*private*/ /** + * Serialize commands to delete items from the server; as we find items to delete, add their + * id's to the deletedId's array + * + * @param s the Serializer we're using to create post data + * @param deletedIds ids whose deletions are being sent to the server + * @param first whether or not this is the first command being sent + * @return true if SYNC_COMMANDS hasn't been sent (false otherwise) + * @throws IOException + */ + boolean sendDeletedItems(Serializer s, ArrayList<Long> deletedIds, boolean first) + throws IOException { + ContentResolver cr = mContext.getContentResolver(); // Find any of our deleted items Cursor c = cr.query(Message.DELETED_CONTENT_URI, Message.LIST_PROJECTION, MessageColumns.MAILBOX_KEY + '=' + mMailbox.mId, null, null); - boolean first = true; // We keep track of the list of deleted item id's so that we can remove them from the // deleted table after the server receives our command - mDeletedIdList.clear(); + deletedIds.clear(); try { while (c.moveToNext()) { String serverId = c.getString(Message.LIST_SERVER_ID_COLUMN); // Keep going if there's no serverId if (serverId == null) { continue; + // Also check if this message is referenced elsewhere + } else if (messageReferenced(cr, c.getLong(Message.CONTENT_ID_COLUMN))) { + userLog("Postponing deletion of referenced message: ", serverId); + continue; } else if (first) { s.start(Tags.SYNC_COMMANDS); first = false; } // Send the command to delete this message s.start(Tags.SYNC_DELETE).data(Tags.SYNC_SERVER_ID, serverId).end(); - mDeletedIdList.add(c.getLong(Message.LIST_ID_COLUMN)); + deletedIds.add(c.getLong(Message.LIST_ID_COLUMN)); } } finally { c.close(); } + return first; + } + + @Override + public boolean sendLocalChanges(Serializer s) throws IOException { + ContentResolver cr = mContext.getContentResolver(); + + // Never upsync from these folders + if (mMailbox.mType == Mailbox.TYPE_DRAFTS || mMailbox.mType == Mailbox.TYPE_OUTBOX) { + return false; + } + + // This code is split out for unit testing purposes + boolean firstCommand = sendDeletedItems(s, mDeletedIdList, true); + // Find our trash mailbox, since deletions will have been moved there... long trashMailboxId = Mailbox.findMailboxOfType(mContext, mMailbox.mAccountKey, Mailbox.TYPE_TRASH); // Do the same now for updated items - c = cr.query(Message.UPDATED_CONTENT_URI, Message.LIST_PROJECTION, + Cursor c = cr.query(Message.UPDATED_CONTENT_URI, Message.LIST_PROJECTION, MessageColumns.MAILBOX_KEY + '=' + mMailbox.mId, null, null); // We keep track of the list of updated item id's as we did above with deleted items @@ -627,9 +670,9 @@ public class EmailSyncAdapter extends AbstractSyncAdapter { } // If the message is now in the trash folder, it has been deleted by the user if (currentCursor.getLong(UPDATES_MAILBOX_KEY_COLUMN) == trashMailboxId) { - if (first) { + if (firstCommand) { s.start(Tags.SYNC_COMMANDS); - first = false; + firstCommand = false; } // Send the command to delete this message s.start(Tags.SYNC_DELETE).data(Tags.SYNC_SERVER_ID, serverId).end(); @@ -659,9 +702,9 @@ public class EmailSyncAdapter extends AbstractSyncAdapter { continue; } - if (first) { + if (firstCommand) { s.start(Tags.SYNC_COMMANDS); - first = false; + firstCommand = false; } // Send the change to "read" and "favorite" (flagged) s.start(Tags.SYNC_CHANGE) @@ -708,7 +751,7 @@ public class EmailSyncAdapter extends AbstractSyncAdapter { c.close(); } - if (!first) { + if (!firstCommand) { s.end(); // SYNC_COMMANDS } return false; |
