am 66ac290b
: Fix a bug causing duplicate messages to be added
* commit '66ac290b353302256e85d319c0ce623277dfdad3': Fix a bug causing duplicate messages to be added
This commit is contained in:
commit
b2947f4702
@ -68,6 +68,8 @@ import java.util.Comparator;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class ImapService extends Service {
|
public class ImapService extends Service {
|
||||||
// TODO get these from configurations or settings.
|
// TODO get these from configurations or settings.
|
||||||
@ -195,11 +197,12 @@ public class ImapService extends Service {
|
|||||||
private static final int COLUMN_FLAG_LOADED = 3;
|
private static final int COLUMN_FLAG_LOADED = 3;
|
||||||
private static final int COLUMN_SERVER_ID = 4;
|
private static final int COLUMN_SERVER_ID = 4;
|
||||||
private static final int COLUMN_FLAGS = 7;
|
private static final int COLUMN_FLAGS = 7;
|
||||||
|
private static final int COLUMN_TIMESTAMP = 8;
|
||||||
private static final String[] PROJECTION = new String[] {
|
private static final String[] PROJECTION = new String[] {
|
||||||
EmailContent.RECORD_ID,
|
EmailContent.RECORD_ID,
|
||||||
MessageColumns.FLAG_READ, MessageColumns.FLAG_FAVORITE, MessageColumns.FLAG_LOADED,
|
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
|
MessageColumns.FLAGS, MessageColumns.TIMESTAMP
|
||||||
};
|
};
|
||||||
|
|
||||||
final long mId;
|
final long mId;
|
||||||
@ -208,6 +211,7 @@ public class ImapService extends Service {
|
|||||||
final int mFlagLoaded;
|
final int mFlagLoaded;
|
||||||
final String mServerId;
|
final String mServerId;
|
||||||
final int mFlags;
|
final int mFlags;
|
||||||
|
final long mTimestamp;
|
||||||
|
|
||||||
public LocalMessageInfo(Cursor c) {
|
public LocalMessageInfo(Cursor c) {
|
||||||
mId = c.getLong(COLUMN_ID);
|
mId = c.getLong(COLUMN_ID);
|
||||||
@ -216,6 +220,7 @@ public class ImapService extends Service {
|
|||||||
mFlagLoaded = c.getInt(COLUMN_FLAG_LOADED);
|
mFlagLoaded = c.getInt(COLUMN_FLAG_LOADED);
|
||||||
mServerId = c.getString(COLUMN_SERVER_ID);
|
mServerId = c.getString(COLUMN_SERVER_ID);
|
||||||
mFlags = c.getInt(COLUMN_FLAGS);
|
mFlags = c.getInt(COLUMN_FLAGS);
|
||||||
|
mTimestamp = c.getLong(COLUMN_TIMESTAMP);
|
||||||
// Note: mailbox key and account key not needed - they are projected for the SELECT
|
// Note: mailbox key and account key not needed - they are projected for the SELECT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -498,12 +503,20 @@ public class ImapService extends Service {
|
|||||||
|
|
||||||
// 8. Get the all of the local messages within the sync window, and create
|
// 8. Get the all of the local messages within the sync window, and create
|
||||||
// an index of the uids.
|
// an index of the uids.
|
||||||
// It's important that we only get local messages that are inside our sync window.
|
// The IMAP query for messages ignores time, and only looks at the date part of the endDate.
|
||||||
// In a later step, we will delete any messages that are in localMessageMap but
|
// So if we query for messages since Aug 11 at 3:00 PM, we can get messages from any time
|
||||||
// are not in our remote message list.
|
// on Aug 11. Our IMAP query results can include messages up to 24 hours older than endDate,
|
||||||
|
// or up to 25 hours older at a daylight savings transition.
|
||||||
|
// It is important that we have the Id of any local message that could potentially be
|
||||||
|
// returned by the IMAP query, or we will create duplicate copies of the same messages.
|
||||||
|
// So we will increase our local query range by this much.
|
||||||
|
// Note that this complicates deletion: It's not okay to delete anything that is in the
|
||||||
|
// localMessageMap but not in the remote result, because we know that we may be getting
|
||||||
|
// Ids of local messages that are outside the IMAP query window.
|
||||||
Cursor localUidCursor = null;
|
Cursor localUidCursor = null;
|
||||||
HashMap<String, LocalMessageInfo> localMessageMap = new HashMap<String, LocalMessageInfo>();
|
HashMap<String, LocalMessageInfo> localMessageMap = new HashMap<String, LocalMessageInfo>();
|
||||||
try {
|
try {
|
||||||
|
final long queryEndDate = endDate - DateUtils.DAY_IN_MILLIS - DateUtils.HOUR_IN_MILLIS;
|
||||||
localUidCursor = resolver.query(
|
localUidCursor = resolver.query(
|
||||||
EmailContent.Message.CONTENT_URI,
|
EmailContent.Message.CONTENT_URI,
|
||||||
LocalMessageInfo.PROJECTION,
|
LocalMessageInfo.PROJECTION,
|
||||||
@ -513,7 +526,7 @@ public class ImapService extends Service {
|
|||||||
new String[] {
|
new String[] {
|
||||||
String.valueOf(account.mId),
|
String.valueOf(account.mId),
|
||||||
String.valueOf(mailbox.mId),
|
String.valueOf(mailbox.mId),
|
||||||
String.valueOf(endDate) },
|
String.valueOf(queryEndDate) },
|
||||||
null);
|
null);
|
||||||
while (localUidCursor.moveToNext()) {
|
while (localUidCursor.moveToNext()) {
|
||||||
LocalMessageInfo info = new LocalMessageInfo(localUidCursor);
|
LocalMessageInfo info = new LocalMessageInfo(localUidCursor);
|
||||||
@ -626,29 +639,30 @@ public class ImapService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 13. Remove messages that are in the local store and in the current sync window,
|
// 13. Remove messages that are in the local store and in the current sync window,
|
||||||
// but no longer on the remote store.
|
// but no longer on the remote store. Note that localMessageMap can contain messages
|
||||||
final HashSet<String> localUidsToDelete = new HashSet<String>(localMessageMap.keySet());
|
// that are not actually in our sync window. We need to check the timestamp to ensure
|
||||||
localUidsToDelete.removeAll(remoteUidMap.keySet());
|
// that it is before deleting.
|
||||||
|
for (final LocalMessageInfo info : localMessageMap.values()) {
|
||||||
|
// If this message is inside our sync window, and we cannot find it in our list
|
||||||
|
// of remote messages, then we know it's been deleted from the server.
|
||||||
|
if (info.mTimestamp >= endDate && !remoteUidMap.containsKey(info.mServerId)) {
|
||||||
|
// Delete associated data (attachment files)
|
||||||
|
// Attachment & Body records are auto-deleted when we delete the Message record
|
||||||
|
AttachmentUtilities.deleteAllAttachmentFiles(context, account.mId, info.mId);
|
||||||
|
|
||||||
for (String uidToDelete : localUidsToDelete) {
|
// Delete the message itself
|
||||||
LocalMessageInfo infoToDelete = localMessageMap.get(uidToDelete);
|
Uri uriToDelete = ContentUris.withAppendedId(
|
||||||
|
EmailContent.Message.CONTENT_URI, info.mId);
|
||||||
|
resolver.delete(uriToDelete, null, null);
|
||||||
|
|
||||||
// Delete associated data (attachment files)
|
// Delete extra rows (e.g. synced or deleted)
|
||||||
// Attachment & Body records are auto-deleted when we delete the Message record
|
Uri syncRowToDelete = ContentUris.withAppendedId(
|
||||||
AttachmentUtilities.deleteAllAttachmentFiles(context, account.mId, infoToDelete.mId);
|
EmailContent.Message.UPDATED_CONTENT_URI, info.mId);
|
||||||
|
resolver.delete(syncRowToDelete, null, null);
|
||||||
// Delete the message itself
|
Uri deletERowToDelete = ContentUris.withAppendedId(
|
||||||
Uri uriToDelete = ContentUris.withAppendedId(
|
EmailContent.Message.UPDATED_CONTENT_URI, info.mId);
|
||||||
EmailContent.Message.CONTENT_URI, infoToDelete.mId);
|
resolver.delete(deletERowToDelete, null, null);
|
||||||
resolver.delete(uriToDelete, null, null);
|
}
|
||||||
|
|
||||||
// Delete extra rows (e.g. synced or deleted)
|
|
||||||
Uri syncRowToDelete = ContentUris.withAppendedId(
|
|
||||||
EmailContent.Message.UPDATED_CONTENT_URI, infoToDelete.mId);
|
|
||||||
resolver.delete(syncRowToDelete, null, null);
|
|
||||||
Uri deletERowToDelete = ContentUris.withAppendedId(
|
|
||||||
EmailContent.Message.UPDATED_CONTENT_URI, infoToDelete.mId);
|
|
||||||
resolver.delete(deletERowToDelete, null, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadUnsyncedMessages(context, account, remoteFolder, unsyncedMessages, mailbox);
|
loadUnsyncedMessages(context, account, remoteFolder, unsyncedMessages, mailbox);
|
||||||
|
Loading…
Reference in New Issue
Block a user