From f74a45d44367c52411f2ed362969ccf2cf20434b Mon Sep 17 00:00:00 2001 From: Andy Stadler <> Date: Sat, 18 Apr 2009 19:40:29 -0700 Subject: [PATCH] AI 146538: am: CL 146134 Add persistence API for remote stores & folders to use while syncing. This provides a key-value store, per folder, that can be used by network Stores to record persistent data such as sync status, server keys, etc. Note that, by definition, this only applies to remote folders (e.g. IMAP, POP3). You'll see everywhere that LocalFolder is passed null, and this is correct - LocalFolder *is* persistent storage and does not need external help. Note to reviewers: The core changes are Folder.java, LocalStore.java, and LocalStoreUnitTests.java, so please give them the bulk of your reviewer attention. The other files are just following along with minor API changes. Of those, the one worth close examination is MessagingController.java, which is the only place in the system where remote Folders are bonded with Local Folders and thus where this new API comes into play. Note to jham: Can you please take a look at LocalStore.LocalFolder.setPersistentString() and recommend better SQL foo than my primitive test-then-update-or-insert logic, which is not transactional or threadsafe. Original author: stadler Automated import of CL 146538 --- .../android/email/MessagingController.java | 38 +++++++++++-------- .../android/email/mail/store/ImapStore.java | 4 +- .../android/email/mail/store/Pop3Store.java | 8 ++-- .../email/mail/store/ImapStoreUnitTests.java | 2 +- .../email/mail/store/Pop3StoreUnitTests.java | 4 +- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/com/android/email/MessagingController.java b/src/com/android/email/MessagingController.java index cacaad043..26d513910 100644 --- a/src/com/android/email/MessagingController.java +++ b/src/com/android/email/MessagingController.java @@ -286,7 +286,7 @@ public class MessagingController implements Runnable { try { Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); Folder localFolder = localStore.getFolder(folder); - localFolder.open(OpenMode.READ_WRITE); + localFolder.open(OpenMode.READ_WRITE, null); Message[] localMessages = localFolder.getMessages(null); ArrayList messages = new ArrayList(); for (Message message : localMessages) { @@ -388,7 +388,7 @@ public class MessagingController implements Runnable { final LocalStore localStore = (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication, null); final LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); - localFolder.open(OpenMode.READ_WRITE); + localFolder.open(OpenMode.READ_WRITE, null); Message[] localMessages = localFolder.getMessages(null); HashMap localUidMap = new HashMap(); for (Message message : localMessages) { @@ -441,7 +441,7 @@ public class MessagingController implements Runnable { /* * Open the remote folder. This pre-loads certain metadata like message count. */ - remoteFolder.open(OpenMode.READ_WRITE); + remoteFolder.open(OpenMode.READ_WRITE, localFolder.getPersistentCallbacks()); /* * Trash any remote messages that are marked as trashed locally. @@ -837,7 +837,7 @@ public class MessagingController implements Runnable { return; } } - remoteFolder.open(OpenMode.READ_WRITE); + remoteFolder.open(OpenMode.READ_WRITE, localFolder.getPersistentCallbacks()); if (remoteFolder.getMode() != OpenMode.READ_WRITE) { return; } @@ -914,13 +914,17 @@ public class MessagingController implements Runnable { String folder = command.arguments[0]; String uid = command.arguments[1]; + LocalStore localStore = (LocalStore) Store.getInstance( + account.getLocalStoreUri(), mApplication, null); + LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); + Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication, account.getStoreCallbacks()); Folder remoteFolder = remoteStore.getFolder(folder); if (!remoteFolder.exists()) { return; } - remoteFolder.open(OpenMode.READ_WRITE); + remoteFolder.open(OpenMode.READ_WRITE, localFolder.getPersistentCallbacks()); if (remoteFolder.getMode() != OpenMode.READ_WRITE) { return; } @@ -965,13 +969,17 @@ public class MessagingController implements Runnable { String uid = command.arguments[1]; boolean read = Boolean.parseBoolean(command.arguments[2]); + LocalStore localStore = (LocalStore) Store.getInstance( + account.getLocalStoreUri(), mApplication, null); + LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); + Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication, account.getStoreCallbacks()); Folder remoteFolder = remoteStore.getFolder(folder); if (!remoteFolder.exists()) { return; } - remoteFolder.open(OpenMode.READ_WRITE); + remoteFolder.open(OpenMode.READ_WRITE, localFolder.getPersistentCallbacks()); if (remoteFolder.getMode() != OpenMode.READ_WRITE) { return; } @@ -1001,7 +1009,7 @@ public class MessagingController implements Runnable { try { Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); Folder localFolder = localStore.getFolder(folder); - localFolder.open(OpenMode.READ_WRITE); + localFolder.open(OpenMode.READ_WRITE, null); Message message = localFolder.getMessage(uid); message.setFlag(Flag.SEEN, seen); @@ -1024,7 +1032,7 @@ public class MessagingController implements Runnable { Store localStore = Store.getInstance( account.getLocalStoreUri(), mApplication, null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); - localFolder.open(OpenMode.READ_WRITE); + localFolder.open(OpenMode.READ_WRITE, null); Message message = localFolder.getMessage(uid); @@ -1056,7 +1064,7 @@ public class MessagingController implements Runnable { Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication, account.getStoreCallbacks()); Folder remoteFolder = remoteStore.getFolder(folder); - remoteFolder.open(OpenMode.READ_WRITE); + remoteFolder.open(OpenMode.READ_WRITE, localFolder.getPersistentCallbacks()); // Get the remote message and fully download it Message remoteMessage = remoteFolder.getMessage(uid); @@ -1103,7 +1111,7 @@ public class MessagingController implements Runnable { try { Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); - localFolder.open(OpenMode.READ_WRITE); + localFolder.open(OpenMode.READ_WRITE, null); Message message = localFolder.getMessage(uid); @@ -1207,7 +1215,7 @@ public class MessagingController implements Runnable { LocalFolder localFolder = (LocalFolder) localStore.getFolder(message.getFolder().getName()); Folder remoteFolder = remoteStore.getFolder(message.getFolder().getName()); - remoteFolder.open(OpenMode.READ_WRITE); + remoteFolder.open(OpenMode.READ_WRITE, localFolder.getPersistentCallbacks()); FetchProfile fp = new FetchProfile(); fp.add(part); @@ -1244,7 +1252,7 @@ public class MessagingController implements Runnable { Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(account.getOutboxFolderName()); - localFolder.open(OpenMode.READ_WRITE); + localFolder.open(OpenMode.READ_WRITE, null); localFolder.appendMessages(new Message[] { message }); @@ -1287,7 +1295,7 @@ public class MessagingController implements Runnable { if (!localFolder.exists()) { return; } - localFolder.open(OpenMode.READ_WRITE); + localFolder.open(OpenMode.READ_WRITE, null); Message[] localMessages = localFolder.getMessages(null); @@ -1393,7 +1401,7 @@ public class MessagingController implements Runnable { Store localStore = Store.getInstance( account.getLocalStoreUri(), mApplication, null); Folder localFolder = localStore.getFolder(account.getTrashFolderName()); - localFolder.open(OpenMode.READ_WRITE); + localFolder.open(OpenMode.READ_WRITE, null); Message[] messages = localFolder.getMessages(null); localFolder.setFlags(messages, new Flag[] { Flag.DELETED @@ -1451,7 +1459,7 @@ public class MessagingController implements Runnable { Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(account.getDraftsFolderName()); - localFolder.open(OpenMode.READ_WRITE); + localFolder.open(OpenMode.READ_WRITE, null); localFolder.appendMessages(new Message[] { message }); diff --git a/src/com/android/email/mail/store/ImapStore.java b/src/com/android/email/mail/store/ImapStore.java index 2f924a5b6..1b09b6c85 100644 --- a/src/com/android/email/mail/store/ImapStore.java +++ b/src/com/android/email/mail/store/ImapStore.java @@ -29,6 +29,7 @@ import com.android.email.mail.MessagingException; import com.android.email.mail.Part; import com.android.email.mail.Store; import com.android.email.mail.Transport; +import com.android.email.mail.Folder.PersistentDataCallbacks; import com.android.email.mail.internet.MimeBodyPart; import com.android.email.mail.internet.MimeHeader; import com.android.email.mail.internet.MimeMessage; @@ -325,7 +326,8 @@ public class ImapStore extends Store { this.mName = name; } - public void open(OpenMode mode) throws MessagingException { + public void open(OpenMode mode, PersistentDataCallbacks callbacks) + throws MessagingException { if (isOpen() && mMode == mode) { // Make sure the connection is valid. If it's not we'll close it down and continue // on to get a new one. diff --git a/src/com/android/email/mail/store/Pop3Store.java b/src/com/android/email/mail/store/Pop3Store.java index 813879893..57aaef91b 100644 --- a/src/com/android/email/mail/store/Pop3Store.java +++ b/src/com/android/email/mail/store/Pop3Store.java @@ -28,6 +28,7 @@ import com.android.email.mail.MessagingException; import com.android.email.mail.Store; import com.android.email.mail.Transport; import com.android.email.mail.Folder.OpenMode; +import com.android.email.mail.Folder.PersistentDataCallbacks; import com.android.email.mail.internet.MimeMessage; import com.android.email.mail.transport.LoggingInputStream; import com.android.email.mail.transport.MailTransport; @@ -179,7 +180,7 @@ public class Pop3Store extends Store { public void checkSettings() throws MessagingException { Pop3Folder folder = new Pop3Folder("INBOX"); try { - folder.open(OpenMode.READ_WRITE); + folder.open(OpenMode.READ_WRITE, null); folder.checkSettings(); } finally { folder.close(false); // false == don't expunge anything @@ -229,7 +230,8 @@ public class Pop3Store extends Store { } @Override - public synchronized void open(OpenMode mode) throws MessagingException { + public synchronized void open(OpenMode mode, PersistentDataCallbacks callbacks) + throws MessagingException { if (mTransport.isOpen()) { return; } @@ -855,7 +857,7 @@ public class Pop3Store extends Store { */ private String executeSensitiveCommand(String command, String sensitiveReplacement) throws IOException, MessagingException { - open(OpenMode.READ_WRITE); + open(OpenMode.READ_WRITE, null); if (command != null) { mTransport.writeLine(command, sensitiveReplacement); diff --git a/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java b/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java index ef0b2f6bc..a956bc0f7 100644 --- a/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java +++ b/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java @@ -66,7 +66,7 @@ public class ImapStoreUnitTests extends AndroidTestCase { // try to open it setupOpenFolder(mockTransport); - mFolder.open(OpenMode.READ_WRITE); + mFolder.open(OpenMode.READ_WRITE, null); // TODO: inject specific facts in the initial folder SELECT and check them here } diff --git a/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java b/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java index d05f3b331..f0b8d8e6f 100644 --- a/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java +++ b/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java @@ -129,7 +129,7 @@ public class Pop3StoreUnitTests extends AndroidTestCase { // try to open it setupOpenFolder(mockTransport, 0, null); - mFolder.open(OpenMode.READ_ONLY); + mFolder.open(OpenMode.READ_ONLY, null); } /** @@ -569,7 +569,7 @@ public class Pop3StoreUnitTests extends AndroidTestCase { private void openFolderWithMessage(MockTransport mockTransport) throws MessagingException { // try to open it setupOpenFolder(mockTransport, 1, null); - mFolder.open(OpenMode.READ_ONLY); + mFolder.open(OpenMode.READ_ONLY, null); // check message count assertEquals(1, mFolder.getMessageCount());