diff --git a/src/com/android/email/Account.java b/src/com/android/email/Account.java index c1e8cb2e4..0e5536948 100644 --- a/src/com/android/email/Account.java +++ b/src/com/android/email/Account.java @@ -30,16 +30,24 @@ import java.util.UUID; * Account stores all of the settings for a single account defined by the user. It is able to save * and delete itself given a Preferences to work with. Each account is defined by a UUID. */ -public class Account implements Serializable { +public class Account implements Serializable, Store.PersistentDataCallbacks { public static final int DELETE_POLICY_NEVER = 0; public static final int DELETE_POLICY_7DAYS = 1; public static final int DELETE_POLICY_ON_DELETE = 2; public static final int CHECK_INTERVAL_NEVER = -1; public static final int CHECK_INTERVAL_PUSH = -2; - - private static final long serialVersionUID = 2975156672298625121L; + /** + * This should never be used for persistance, only for marshalling. + * TODO: Remove serializable (VERY SLOW) and replace with Parcelable + */ + private static final long serialVersionUID = 1L; + + // transient values - do not serialize + private transient Preferences mPreferences; + + // serialized values String mUuid; String mStoreUri; String mLocalStoreUri; @@ -57,6 +65,12 @@ public class Account implements Serializable { int mAccountNumber; boolean mVibrate; String mRingtoneUri; + String mStorePersistent; + + /** + * TODO: all fields should be tagged here + */ + private final String PREF_TAG_STORE_PERSISTENT = ".storePersist"; /** *
@@ -87,6 +101,8 @@ public class Account implements Serializable { * Refresh the account from the stored settings. */ public void refresh(Preferences preferences) { + mPreferences = preferences; + mStoreUri = Utility.base64Decode(preferences.mSharedPreferences.getString(mUuid + ".storeUri", null)); mLocalStoreUri = preferences.mSharedPreferences.getString(mUuid + ".localStoreUri", null); @@ -129,6 +145,9 @@ public class Account implements Serializable { mVibrate = preferences.mSharedPreferences.getBoolean(mUuid + ".vibrate", false); mRingtoneUri = preferences.mSharedPreferences.getString(mUuid + ".ringtone", "content://settings/system/notification_sound"); + + mStorePersistent = preferences.mSharedPreferences.getString( + mUuid + PREF_TAG_STORE_PERSISTENT, null); } public String getUuid() { @@ -223,7 +242,8 @@ public class Account implements Serializable { editor.remove(mUuid + ".accountNumber"); editor.remove(mUuid + ".vibrate"); editor.remove(mUuid + ".ringtone"); - + editor.remove(mUuid + PREF_TAG_STORE_PERSISTENT); + // also delete any deprecated fields editor.remove(mUuid + ".transportUri"); @@ -231,6 +251,8 @@ public class Account implements Serializable { } public void save(Preferences preferences) { + mPreferences = preferences; + if (!preferences.mSharedPreferences.getString("accountUuids", "").contains(mUuid)) { /* * When the account is first created we assign it a unique account number. The @@ -284,12 +306,17 @@ public class Account implements Serializable { editor.putBoolean(mUuid + ".vibrate", mVibrate); editor.putString(mUuid + ".ringtone", mRingtoneUri); + // The following fields are *not* written because they need to be more fine-grained + // and not risk rewriting with old data. + // editor.putString(mUuid + PREF_TAG_STORE_PERSISTENT, mStorePersistent); + // also delete any deprecated fields editor.remove(mUuid + ".transportUri"); editor.commit(); } + @Override public String toString() { return mDescription; } @@ -380,6 +407,44 @@ public class Account implements Serializable { return mAccountNumber; } + /** + * Provides a small place for Stores to store persistent data. This will need to be + * expanded in the future, but is sufficient for now. + * @param storeData Data to persist. All data must be encoded into a string, + * so use base64 or some other encoding if necessary. + */ + public void setPersistentString(String storeData) { + synchronized (this.getClass()) { + mStorePersistent = mPreferences.mSharedPreferences.getString( + mUuid + PREF_TAG_STORE_PERSISTENT, null); + if ((mStorePersistent == null && storeData != null) || + (mStorePersistent != null && !mStorePersistent.equals(storeData))) { + mStorePersistent = storeData; + SharedPreferences.Editor editor = mPreferences.mSharedPreferences.edit(); + editor.putString(mUuid + PREF_TAG_STORE_PERSISTENT, mStorePersistent); + editor.commit(); + } + } + } + + /** + * @return the data saved by the Store, or null if never set. + */ + public String getPersistentString() { + synchronized (this.getClass()) { + mStorePersistent = mPreferences.mSharedPreferences.getString( + mUuid + PREF_TAG_STORE_PERSISTENT, null); + } + return mStorePersistent; + } + + /** + * @return An implementation of Store.PersistentDataCallbacks + */ + public Store.PersistentDataCallbacks getStoreCallbacks() { + return this; + } + @Override public boolean equals(Object o) { if (o instanceof Account) { diff --git a/src/com/android/email/MessagingController.java b/src/com/android/email/MessagingController.java index 46dd9f3fb..cacaad043 100644 --- a/src/com/android/email/MessagingController.java +++ b/src/com/android/email/MessagingController.java @@ -189,7 +189,7 @@ public class MessagingController implements Runnable { l.listFoldersStarted(account); } try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); + Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); Folder[] localFolders = localStore.getPersonalNamespaces(); if (localFolders == null || localFolders.length == 0) { @@ -210,13 +210,13 @@ public class MessagingController implements Runnable { put("listFolders", listener, new Runnable() { public void run() { try { - Store store = Store.getInstance(account.getStoreUri(), mApplication); + Store store = Store.getInstance(account.getStoreUri(), mApplication, + account.getStoreCallbacks()); Folder[] remoteFolders = store.getPersonalNamespaces(); Store localStore = Store.getInstance( - account.getLocalStoreUri(), - mApplication); + account.getLocalStoreUri(), mApplication, null); HashSetremoteFolderNames = new HashSet (); for (int i = 0, count = remoteFolders.length; i < count; i++) { Folder localFolder = localStore.getFolder(remoteFolders[i].getName()); @@ -284,7 +284,7 @@ public class MessagingController implements Runnable { } try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); + Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); Folder localFolder = localStore.getFolder(folder); localFolder.open(OpenMode.READ_WRITE); Message[] localMessages = localFolder.getMessages(null); @@ -311,8 +311,7 @@ public class MessagingController implements Runnable { public void loadMoreMessages(Account account, String folder, MessagingListener listener) { try { LocalStore localStore = (LocalStore) Store.getInstance( - account.getLocalStoreUri(), - mApplication); + account.getLocalStoreUri(), mApplication, null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); localFolder.setVisibleLimit(localFolder.getVisibleLimit() + Email.VISIBLE_LIMIT_INCREMENT); @@ -327,7 +326,7 @@ public class MessagingController implements Runnable { for (Account account : accounts) { try { LocalStore localStore = - (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication); + (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication, null); localStore.resetVisibleLimits(); } catch (MessagingException e) { @@ -387,7 +386,7 @@ public class MessagingController implements Runnable { * the uids within the list. */ final LocalStore localStore = - (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication); + (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication, null); final LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); localFolder.open(OpenMode.READ_WRITE); Message[] localMessages = localFolder.getMessages(null); @@ -396,7 +395,8 @@ public class MessagingController implements Runnable { localUidMap.put(message.getUid(), message); } - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); + Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication, + account.getStoreCallbacks()); Folder remoteFolder = remoteStore.getFolder(folder); /* @@ -753,8 +753,7 @@ public class MessagingController implements Runnable { private void queuePendingCommand(Account account, PendingCommand command) { try { LocalStore localStore = (LocalStore) Store.getInstance( - account.getLocalStoreUri(), - mApplication); + account.getLocalStoreUri(), mApplication, null); localStore.addPendingCommand(command); } catch (Exception e) { @@ -783,8 +782,7 @@ public class MessagingController implements Runnable { private void processPendingCommandsSynchronous(Account account) throws MessagingException { LocalStore localStore = (LocalStore) Store.getInstance( - account.getLocalStoreUri(), - mApplication); + account.getLocalStoreUri(), mApplication, null); ArrayList commands = localStore.getPendingCommands(); for (PendingCommand command : commands) { /* @@ -823,8 +821,7 @@ public class MessagingController implements Runnable { String uid = command.arguments[1]; LocalStore localStore = (LocalStore) Store.getInstance( - account.getLocalStoreUri(), - mApplication); + account.getLocalStoreUri(), mApplication, null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); LocalMessage localMessage = (LocalMessage) localFolder.getMessage(uid); @@ -832,7 +829,8 @@ public class MessagingController implements Runnable { return; } - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); + Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication, + account.getStoreCallbacks()); Folder remoteFolder = remoteStore.getFolder(folder); if (!remoteFolder.exists()) { if (!remoteFolder.create(FolderType.HOLDS_MESSAGES)) { @@ -916,7 +914,8 @@ public class MessagingController implements Runnable { String folder = command.arguments[0]; String uid = command.arguments[1]; - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); + Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication, + account.getStoreCallbacks()); Folder remoteFolder = remoteStore.getFolder(folder); if (!remoteFolder.exists()) { return; @@ -966,7 +965,8 @@ public class MessagingController implements Runnable { String uid = command.arguments[1]; boolean read = Boolean.parseBoolean(command.arguments[2]); - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); + Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication, + account.getStoreCallbacks()); Folder remoteFolder = remoteStore.getFolder(folder); if (!remoteFolder.exists()) { return; @@ -999,7 +999,7 @@ public class MessagingController implements Runnable { final String uid, final boolean seen) { try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); + Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); Folder localFolder = localStore.getFolder(folder); localFolder.open(OpenMode.READ_WRITE); @@ -1021,7 +1021,8 @@ public class MessagingController implements Runnable { put("loadMessageForViewRemote", listener, new Runnable() { public void run() { try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); + Store localStore = Store.getInstance( + account.getLocalStoreUri(), mApplication, null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); localFolder.open(OpenMode.READ_WRITE); @@ -1052,7 +1053,8 @@ public class MessagingController implements Runnable { * fully if possible. */ - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); + Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication, + account.getStoreCallbacks()); Folder remoteFolder = remoteStore.getFolder(folder); remoteFolder.open(OpenMode.READ_WRITE); @@ -1099,7 +1101,7 @@ public class MessagingController implements Runnable { l.loadMessageForViewStarted(account, folder, uid); } try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); + Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(folder); localFolder.open(OpenMode.READ_WRITE); @@ -1185,8 +1187,8 @@ public class MessagingController implements Runnable { put("loadAttachment", listener, new Runnable() { public void run() { try { - LocalStore localStore = - (LocalStore) Store.getInstance(account.getLocalStoreUri(), mApplication); + LocalStore localStore = (LocalStore) Store.getInstance( + account.getLocalStoreUri(), mApplication, null); /* * We clear out any attachments already cached in the entire store and then * we update the passed in message to reflect that there are no cached @@ -1200,7 +1202,8 @@ public class MessagingController implements Runnable { for (Part attachment : attachments) { attachment.setBody(null); } - Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication); + Store remoteStore = Store.getInstance(account.getStoreUri(), mApplication, + account.getStoreCallbacks()); LocalFolder localFolder = (LocalFolder) localStore.getFolder(message.getFolder().getName()); Folder remoteFolder = remoteStore.getFolder(message.getFolder().getName()); @@ -1238,7 +1241,7 @@ public class MessagingController implements Runnable { final Message message, MessagingListener listener) { try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); + Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(account.getOutboxFolderName()); localFolder.open(OpenMode.READ_WRITE); @@ -1278,9 +1281,7 @@ public class MessagingController implements Runnable { */ public void sendPendingMessagesSynchronous(final Account account) { try { - Store localStore = Store.getInstance( - account.getLocalStoreUri(), - mApplication); + Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); Folder localFolder = localStore.getFolder( account.getOutboxFolderName()); if (!localFolder.exists()) { @@ -1364,7 +1365,7 @@ public class MessagingController implements Runnable { return; } try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); + Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); Folder localFolder = localStore.getFolder(folder); Folder localTrashFolder = localStore.getFolder(account.getTrashFolderName()); @@ -1389,7 +1390,8 @@ public class MessagingController implements Runnable { public void run() { // TODO IMAP try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); + Store localStore = Store.getInstance( + account.getLocalStoreUri(), mApplication, null); Folder localFolder = localStore.getFolder(account.getTrashFolderName()); localFolder.open(OpenMode.READ_WRITE); Message[] messages = localFolder.getMessages(null); @@ -1446,7 +1448,7 @@ public class MessagingController implements Runnable { public void saveDraft(final Account account, final Message message) { try { - Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication); + Store localStore = Store.getInstance(account.getLocalStoreUri(), mApplication, null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(account.getDraftsFolderName()); localFolder.open(OpenMode.READ_WRITE); diff --git a/src/com/android/email/activity/AccountShortcutPicker.java b/src/com/android/email/activity/AccountShortcutPicker.java index 554b69076..0e481f22e 100644 --- a/src/com/android/email/activity/AccountShortcutPicker.java +++ b/src/com/android/email/activity/AccountShortcutPicker.java @@ -124,8 +124,7 @@ public class AccountShortcutPicker extends ListActivity implements OnItemClickLi int unreadMessageCount = 0; try { LocalStore localStore = (LocalStore) Store.getInstance( - account.getLocalStoreUri(), - getApplication()); + account.getLocalStoreUri(), getApplication(), null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(Email.INBOX); if (localFolder.exists()) { unreadMessageCount = localFolder.getUnreadMessageCount(); diff --git a/src/com/android/email/activity/Accounts.java b/src/com/android/email/activity/Accounts.java index 20eedcb8b..9dc5d7ac0 100644 --- a/src/com/android/email/activity/Accounts.java +++ b/src/com/android/email/activity/Accounts.java @@ -174,11 +174,13 @@ public class Accounts extends ListActivity implements OnItemClickListener, OnCli // Delete Remote store at first. Store.getInstance( mSelectedContextAccount.getStoreUri(), - getApplication()).delete(); + getApplication(), + mSelectedContextAccount.getStoreCallbacks()).delete(); // If no error, then delete LocalStore Store.getInstance( mSelectedContextAccount.getLocalStoreUri(), - getApplication()).delete(); + getApplication(), + null).delete(); } catch (Exception e) { // Ignore } @@ -299,7 +301,8 @@ public class Accounts extends ListActivity implements OnItemClickListener, OnCli try { LocalStore localStore = (LocalStore) Store.getInstance( account.getLocalStoreUri(), - getApplication()); + getApplication(), + null); LocalFolder localFolder = (LocalFolder) localStore.getFolder(Email.INBOX); if (localFolder.exists()) { unreadMessageCount = localFolder.getUnreadMessageCount(); diff --git a/src/com/android/email/activity/setup/AccountSettings.java b/src/com/android/email/activity/setup/AccountSettings.java index 52536c706..32781b25c 100644 --- a/src/com/android/email/activity/setup/AccountSettings.java +++ b/src/com/android/email/activity/setup/AccountSettings.java @@ -195,7 +195,8 @@ public class AccountSettings extends PreferenceActivity { private void onIncomingSettings() { try { - Store store = Store.getInstance(mAccount.getStoreUri(), getApplication()); + Store store = Store.getInstance(mAccount.getStoreUri(), getApplication(), + mAccount.getStoreCallbacks()); if (store != null) { Class extends android.app.Activity> setting = store.getSettingActivityClass(); if (setting != null) { diff --git a/src/com/android/email/activity/setup/AccountSetupAccountType.java b/src/com/android/email/activity/setup/AccountSetupAccountType.java index 58e910490..b9b9c623c 100644 --- a/src/com/android/email/activity/setup/AccountSetupAccountType.java +++ b/src/com/android/email/activity/setup/AccountSetupAccountType.java @@ -141,7 +141,7 @@ public class AccountSetupAccountType extends Activity implements OnClickListener try { URI uri = new URI(mAccount.getStoreUri()); uri = new URI("eas", uri.getUserInfo(), uri.getHost(), uri.getPort(), null, null, null); - Store store = Store.getInstance(uri.toString(), this); + Store store = Store.getInstance(uri.toString(), this, mAccount.getStoreCallbacks()); return (store != null); } catch (URISyntaxException e) { return false; diff --git a/src/com/android/email/activity/setup/AccountSetupCheckSettings.java b/src/com/android/email/activity/setup/AccountSetupCheckSettings.java index a86ed8f32..829d65028 100644 --- a/src/com/android/email/activity/setup/AccountSetupCheckSettings.java +++ b/src/com/android/email/activity/setup/AccountSetupCheckSettings.java @@ -104,7 +104,8 @@ public class AccountSetupCheckSettings extends Activity implements OnClickListen } if (mCheckIncoming) { setMessage(R.string.account_setup_check_settings_check_incoming_msg); - Store store = Store.getInstance(mAccount.getStoreUri(), getApplication()); + Store store = Store.getInstance(mAccount.getStoreUri(), getApplication(), + mAccount.getStoreCallbacks()); store.checkSettings(); } if (mDestroyed) { diff --git a/src/com/android/email/mail/Store.java b/src/com/android/email/mail/Store.java index 3a5cf881c..a7c39c873 100644 --- a/src/com/android/email/mail/Store.java +++ b/src/com/android/email/mail/Store.java @@ -57,20 +57,22 @@ public abstract class Store { * Static named constructor. It should be overrode by extending class. * Because this method will be called through reflection, it can not be protected. */ - public static Store newInstance(String uri, Context context) + public static Store newInstance(String uri, Context context, PersistentDataCallbacks callbacks) throws MessagingException { throw new MessagingException("Store.newInstance: Unknown scheme in " + uri); } - private static Store instantiateStore(String className, String uri, Context context) + private static Store instantiateStore(String className, String uri, Context context, + PersistentDataCallbacks callbacks) throws MessagingException { Object o = null; try { Class> c = Class.forName(className); // and invoke "newInstance" class method and instantiate store object. java.lang.reflect.Method m = - c.getMethod("newInstance", String.class, Context.class); - o = m.invoke(null, uri, context); + c.getMethod("newInstance", String.class, Context.class, + PersistentDataCallbacks.class); + o = m.invoke(null, uri, context, callbacks); } catch (Exception e) { Log.d(Email.LOG_TAG, String.format( "exception %s invoking %s.newInstance.(String, Context) method for %s", @@ -149,13 +151,14 @@ public abstract class Store { * @return an initialized store of the appropriate class * @throws MessagingException */ - public synchronized static Store getInstance(String uri, Context context) + public synchronized static Store getInstance(String uri, Context context, + PersistentDataCallbacks callbacks) throws MessagingException { Store store = mStores.get(uri); if (store == null) { StoreInfo info = StoreInfo.getStoreInfo(uri, context); if (info != null) { - store = instantiateStore(info.mClassName, uri, context); + store = instantiateStore(info.mClassName, uri, context, callbacks); } if (store != null) { @@ -212,4 +215,23 @@ public abstract class Store { */ public void delete() throws MessagingException { } + + /** + * Callback interface by which a Store can read and write persistent data. + * TODO This needs to be made more generic & flexible + */ + public interface PersistentDataCallbacks { + + /** + * Provides a small place for Stores to store persistent data. + * @param storeData Data to persist. All data must be encoded into a string, + * so use base64 or some other encoding if necessary. + */ + public void setPersistentString(String storeData); + + /** + * @return the data saved by the Store, or null if never set. + */ + public String getPersistentString(); + } } diff --git a/src/com/android/email/mail/exchange/ExchangeStoreExample.java b/src/com/android/email/mail/exchange/ExchangeStoreExample.java index 444fb68b8..2b6af2d96 100644 --- a/src/com/android/email/mail/exchange/ExchangeStoreExample.java +++ b/src/com/android/email/mail/exchange/ExchangeStoreExample.java @@ -43,6 +43,7 @@ public class ExchangeStoreExample extends Store { private final Context mContext; private URI mUri; + private PersistentDataCallbacks mCallbacks; private final ExchangeTransportExample mTransport; private final HashMap mFolders = new HashMap (); @@ -52,9 +53,9 @@ public class ExchangeStoreExample extends Store { /** * Factory method. */ - public static Store newInstance(String uri, Context context) + public static Store newInstance(String uri, Context context, PersistentDataCallbacks callbacks) throws MessagingException { - return new ExchangeStoreExample(uri, context); + return new ExchangeStoreExample(uri, context, callbacks); } /** @@ -64,13 +65,15 @@ public class ExchangeStoreExample extends Store { * @param application * @throws MessagingException */ - private ExchangeStoreExample(String _uri, Context context) throws MessagingException { + private ExchangeStoreExample(String _uri, Context context, PersistentDataCallbacks callbacks) + throws MessagingException { mContext = context; try { mUri = new URI(_uri); } catch (URISyntaxException e) { throw new MessagingException("Invalid uri for ExchangeStoreExample"); } + mCallbacks = callbacks; String scheme = mUri.getScheme(); int connectionSecurity; diff --git a/src/com/android/email/mail/store/ImapStore.java b/src/com/android/email/mail/store/ImapStore.java index ad5844b08..2f924a5b6 100644 --- a/src/com/android/email/mail/store/ImapStore.java +++ b/src/com/android/email/mail/store/ImapStore.java @@ -17,7 +17,6 @@ package com.android.email.mail.store; import com.android.email.Email; -import com.android.email.PeekableInputStream; import com.android.email.Utility; import com.android.email.mail.AuthenticationFailedException; import com.android.email.mail.CertificateValidationException; @@ -112,7 +111,8 @@ public class ImapStore extends Store { /** * Static named constructor. */ - public static Store newInstance(String uri, Context context) throws MessagingException { + public static Store newInstance(String uri, Context context, PersistentDataCallbacks callbacks) + throws MessagingException { return new ImapStore(uri); } diff --git a/src/com/android/email/mail/store/Pop3Store.java b/src/com/android/email/mail/store/Pop3Store.java index 47750a6d1..813879893 100644 --- a/src/com/android/email/mail/store/Pop3Store.java +++ b/src/com/android/email/mail/store/Pop3Store.java @@ -85,7 +85,8 @@ public class Pop3Store extends Store { /** * Static named constructor. */ - public static Store newInstance(String uri, Context context) throws MessagingException { + public static Store newInstance(String uri, Context context, PersistentDataCallbacks callbacks) + throws MessagingException { return new Pop3Store(uri); } diff --git a/src/com/android/email/service/MailService.java b/src/com/android/email/service/MailService.java index 7d1fb00a5..ad8f833e9 100644 --- a/src/com/android/email/service/MailService.java +++ b/src/com/android/email/service/MailService.java @@ -283,7 +283,8 @@ public class MailService extends Service { try { String storeUri = account.getStoreUri(); if (storeUri != null) { - Store store = Store.getInstance(storeUri, this.getBaseContext()); + Store store = Store.getInstance(storeUri, this.getBaseContext(), + account.getStoreCallbacks()); if (store != null) { store.enablePushModeDelivery(enable); } diff --git a/tests/src/com/android/email/AccountUnitTests.java b/tests/src/com/android/email/AccountUnitTests.java index 46ca501ef..4e58b13a8 100644 --- a/tests/src/com/android/email/AccountUnitTests.java +++ b/tests/src/com/android/email/AccountUnitTests.java @@ -16,6 +16,8 @@ package com.android.email; +import com.android.email.mail.Store; + import android.content.SharedPreferences; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; @@ -135,6 +137,59 @@ public class AccountUnitTests extends AndroidTestCase { assertEquals(Account.DELETE_POLICY_ON_DELETE, storedPolicy); } + /** + * Test the new store persistent data code. + * + * This test, and the underlying code, reflect the essential error in the Account class. The + * account objects should have been singletons-per-account. As it stands there are lots of + * them floating around, which is very expensive (we waste a lot of effort creating them) + * and forces slow sync hacks for dynamic data like the store's persistent data. + */ + public void testStorePersistentData() { + + final String TEST_STRING = "This is the store's persistent data."; + final String TEST_STRING_2 = "Rewrite the store data."; + + // create a dummy account + createTestAccount(); + + // confirm null on new account + assertNull(mAccount.getPersistentString()); + + // test write/readback + mAccount.setPersistentString(TEST_STRING); + mAccount.save(mPreferences); + mAccount.refresh(mPreferences); + assertEquals(TEST_STRING, mAccount.getPersistentString()); + + // test that the data is shared across multiple account instantiations + Account account2 = new Account(mPreferences, mUuid); + assertEquals(TEST_STRING, account2.getPersistentString()); + mAccount.setPersistentString(TEST_STRING_2); + assertEquals(TEST_STRING_2, account2.getPersistentString()); + } + + /** + * Test the callbacks for setting & getting persistent data + */ + public void testStorePersistentCallbacks() { + + final String TEST_STRING = "This is the store's persistent data."; + final String TEST_STRING_2 = "Rewrite the store data."; + + // create a dummy account + createTestAccount(); + Store.PersistentDataCallbacks callbacks = mAccount.getStoreCallbacks(); + + // push some data through the interfaces + assertNull(callbacks.getPersistentString()); + callbacks.setPersistentString(TEST_STRING); + assertEquals(TEST_STRING, mAccount.getPersistentString()); + + mAccount.setPersistentString(TEST_STRING_2); + assertEquals(TEST_STRING_2, callbacks.getPersistentString()); + } + /** * Create a dummy account with minimal fields */ diff --git a/tests/src/com/android/email/mail/StoreTests.java b/tests/src/com/android/email/mail/StoreTests.java index 9df89f4e0..ea951f8e0 100644 --- a/tests/src/com/android/email/mail/StoreTests.java +++ b/tests/src/com/android/email/mail/StoreTests.java @@ -38,7 +38,7 @@ public class StoreTests extends AndroidTestCase { assertFalse(info.mPushSupported); // This will throw MessagingException if the result would have been null - Store store = Store.getInstance(storeUri, getContext()); + Store store = Store.getInstance(storeUri, getContext(), null); } /** @@ -54,11 +54,12 @@ public class StoreTests extends AndroidTestCase { assertFalse(info.mPushSupported); // This will throw MessagingException if the result would have been null - Store store = Store.getInstance(storeUri, getContext()); + Store store = Store.getInstance(storeUri, getContext(), null); } /** * Test StoreInfo & Store lookup for EAS accounts + * TODO: EAS store will probably require implementation of Store.PersistentDataCallbacks */ public void testStoreLookupEAS() throws MessagingException { final String storeUri = "eas://user:password@server.com"; @@ -69,10 +70,10 @@ public class StoreTests extends AndroidTestCase { assertTrue(info.mPushSupported); // This will throw MessagingException if the result would have been null - Store store = Store.getInstance(storeUri, getContext()); + Store store = Store.getInstance(storeUri, getContext(), null); } else { try { - Store store = Store.getInstance(storeUri, getContext()); + Store store = Store.getInstance(storeUri, getContext(), null); fail("MessagingException expected when EAS not supported"); } catch (MessagingException me) { // expected - fall through @@ -89,7 +90,7 @@ public class StoreTests extends AndroidTestCase { assertNull(info); try { - Store store = Store.getInstance(storeUri, getContext()); + Store store = Store.getInstance(storeUri, getContext(), null); fail("MessagingException expected from bogus URI scheme"); } catch (MessagingException me) { // expected - fall through diff --git a/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java b/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java index 6f21723c0..ef0b2f6bc 100644 --- a/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java +++ b/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java @@ -50,7 +50,7 @@ public class ImapStoreUnitTests extends AndroidTestCase { // These are needed so we can get at the inner classes mStore = (ImapStore) ImapStore.newInstance("imap://user:password@server:999", - getContext()); + getContext(), null); mFolder = (ImapStore.ImapFolder) mStore.getFolder("INBOX"); // This is needed for parsing mime messages diff --git a/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java b/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java index 02af5f0dd..d05f3b331 100644 --- a/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java +++ b/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java @@ -57,7 +57,7 @@ public class Pop3StoreUnitTests extends AndroidTestCase { // These are needed so we can get at the inner classes mStore = (Pop3Store) Pop3Store.newInstance("pop3://user:password@server:999", - getContext()); + getContext(), null); mFolder = (Pop3Store.Pop3Folder) mStore.getFolder("INBOX"); // This is needed for parsing mime messages