Clean up Store implementation

* Remove unused argument from newInstance/constructor
* Create ServiceStore class, the superclass of ExchangeStore (and,
  eventually, all Stores, until they can go away completely)

Change-Id: Ic5237236c5349ecf006538c58b63c1efe8e4ea61
This commit is contained in:
Marc Blank 2011-06-29 12:47:56 -07:00
parent 06421df25d
commit 35b0e95ca7
11 changed files with 152 additions and 129 deletions

View File

@ -258,7 +258,7 @@ public class MessagingController implements Runnable {
Cursor localFolderCursor = null;
try {
// Step 1: Get remote mailboxes
Store store = Store.getInstance(account, mContext, null);
Store store = Store.getInstance(account, mContext);
Folder[] remoteFolders = store.updateFolders();
HashSet<String> remoteFolderNames = new HashSet<String>();
for (int i = 0, count = remoteFolders.length; i < count; i++) {
@ -615,7 +615,7 @@ public class MessagingController implements Runnable {
// Tell UI that we're loading messages
mListeners.synchronizeMailboxStarted(accountId, destMailbox.mId);
Store remoteStore = Store.getInstance(account, mContext, null);
Store remoteStore = Store.getInstance(account, mContext);
Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId);
remoteFolder.open(OpenMode.READ_WRITE, null);
@ -761,7 +761,7 @@ public class MessagingController implements Runnable {
// 2. Open the remote folder and create the remote folder if necessary
Store remoteStore = Store.getInstance(account, mContext, null);
Store remoteStore = Store.getInstance(account, mContext);
Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId);
/*
@ -1023,8 +1023,7 @@ public class MessagingController implements Runnable {
put("processPendingActions", null, new Runnable() {
public void run() {
try {
Account account =
Account.restoreAccountWithId(mContext, accountId);
Account account = Account.restoreAccountWithId(mContext, accountId);
if (account == null) {
return;
}
@ -1148,7 +1147,7 @@ public class MessagingController implements Runnable {
// Load the remote store if it will be needed
if (remoteStore == null && deleteFromTrash) {
remoteStore = Store.getInstance(account, mContext, null);
remoteStore = Store.getInstance(account, mContext);
}
// Dispatch here for specific change types
@ -1219,8 +1218,7 @@ public class MessagingController implements Runnable {
while (upsyncs1.moveToNext()) {
// Load the remote store if it will be needed
if (remoteStore == null) {
remoteStore =
Store.getInstance(account, mContext, null);
remoteStore = Store.getInstance(account, mContext);
}
// Load the mailbox if it will be needed
if (mailbox == null) {
@ -1249,8 +1247,7 @@ public class MessagingController implements Runnable {
while (upsyncs2.moveToNext()) {
// Load the remote store if it will be needed
if (remoteStore == null) {
remoteStore =
Store.getInstance(account, mContext, null);
remoteStore = Store.getInstance(account, mContext);
}
// Load the mailbox if it will be needed
if (mailbox == null) {
@ -1335,7 +1332,7 @@ public class MessagingController implements Runnable {
// Load the remote store if it will be needed
if (remoteStore == null &&
(changeMoveToTrash || changeRead || changeFlagged || changeMailbox)) {
remoteStore = Store.getInstance(account, mContext, null);
remoteStore = Store.getInstance(account, mContext);
}
// Dispatch here for specific change types
@ -1826,17 +1823,14 @@ public class MessagingController implements Runnable {
// 2. Open the remote folder.
// TODO combine with common code in loadAttachment
Account account =
Account.restoreAccountWithId(mContext, message.mAccountKey);
Mailbox mailbox =
Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey);
Account account = Account.restoreAccountWithId(mContext, message.mAccountKey);
Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, message.mMailboxKey);
if (account == null || mailbox == null) {
mListeners.loadMessageForViewFailed(messageId, "null account or mailbox");
return;
}
Store remoteStore =
Store.getInstance(account, mContext, null);
Store remoteStore = Store.getInstance(account, mContext);
String remoteServerId = mailbox.mServerId;
// If this is a search result, use the protocolSearchInfo field to get the
// correct remote location
@ -1895,10 +1889,8 @@ public class MessagingController implements Runnable {
// 2. Open the remote folder.
// TODO all of these could be narrower projections
Account account =
Account.restoreAccountWithId(mContext, accountId);
Mailbox mailbox =
Mailbox.restoreMailboxWithId(mContext, mailboxId);
Account account = Account.restoreAccountWithId(mContext, accountId);
Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, mailboxId);
EmailContent.Message message =
EmailContent.Message.restoreMessageWithId(mContext, messageId);
@ -1910,8 +1902,7 @@ public class MessagingController implements Runnable {
return;
}
Store remoteStore =
Store.getInstance(account, mContext, null);
Store remoteStore = Store.getInstance(account, mContext);
Folder remoteFolder = remoteStore.getFolder(mailbox.mServerId);
remoteFolder.open(OpenMode.READ_WRITE, null);
@ -2007,7 +1998,7 @@ public class MessagingController implements Runnable {
mListeners.sendPendingMessagesStarted(account.mId, -1);
Sender sender = Sender.getInstance(mContext, account);
Store remoteStore = Store.getInstance(account, mContext, null);
Store remoteStore = Store.getInstance(account, mContext);
boolean requireMoveMessageToSentFolder = remoteStore.requireCopyMessageToSentFolder();
ContentValues moveToSentValues = null;
if (requireMoveMessageToSentFolder) {
@ -2098,8 +2089,7 @@ public class MessagingController implements Runnable {
// here if we somehow don't have a sent folder, but this should never happen
// because the call to sendMessage() would have built one previously.
long inboxId = -1;
Account account =
Account.restoreAccountWithId(mContext, accountId);
Account account = Account.restoreAccountWithId(mContext, accountId);
if (account != null) {
long sentboxId = Mailbox.findMailboxOfType(mContext, accountId,
Mailbox.TYPE_SENT);

View File

@ -16,17 +16,6 @@
package com.android.email.activity.setup;
import com.android.email.R;
import com.android.email.mail.Sender;
import com.android.email.mail.Store;
import com.android.emailcommon.Logging;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.provider.Policy;
import com.android.emailcommon.service.EmailServiceProxy;
import com.android.emailcommon.utility.Utility;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@ -41,6 +30,17 @@ import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import com.android.email.R;
import com.android.email.mail.Sender;
import com.android.email.mail.Store;
import com.android.emailcommon.Logging;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.provider.Policy;
import com.android.emailcommon.service.EmailServiceProxy;
import com.android.emailcommon.utility.Utility;
/**
* Check incoming or outgoing settings, or perform autodiscovery.
*
@ -420,7 +420,7 @@ public class AccountCheckSettingsFragment extends Fragment {
if (isCancelled()) return null;
publishProgress(STATE_CHECK_AUTODISCOVER);
Log.d(Logging.LOG_TAG, "Begin auto-discover for " + mCheckEmail);
Store store = Store.getInstance(mAccount, mContext, null);
Store store = Store.getInstance(mAccount, mContext);
Bundle result = store.autoDiscover(mContext, mCheckEmail, mCheckPassword);
// Result will be one of:
// null: remote exception - proceed to manual setup
@ -448,7 +448,7 @@ public class AccountCheckSettingsFragment extends Fragment {
if (isCancelled()) return null;
Log.d(Logging.LOG_TAG, "Begin check of incoming email settings");
publishProgress(STATE_CHECK_INCOMING);
Store store = Store.getInstance(mAccount, mContext, null);
Store store = Store.getInstance(mAccount, mContext);
Bundle bundle = store.checkSettings();
int resultCode = MessagingException.UNSPECIFIED_EXCEPTION;
if (bundle != null) {

View File

@ -16,17 +16,6 @@
package com.android.email.activity.setup;
import com.android.email.Controller;
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
import com.android.email.activity.IntentUtilities;
import com.android.email.mail.Sender;
import com.android.email.mail.Store;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent.AccountColumns;
import com.android.emailcommon.utility.Utility;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
@ -47,6 +36,17 @@ import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import com.android.email.Controller;
import com.android.email.R;
import com.android.email.activity.ActivityHelper;
import com.android.email.activity.IntentUtilities;
import com.android.email.mail.Sender;
import com.android.email.mail.Store;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent.AccountColumns;
import com.android.emailcommon.utility.Utility;
import java.util.List;
/**
@ -661,7 +661,7 @@ public class AccountSettings extends PreferenceActivity {
*/
public void onIncomingSettings(Account account) {
try {
Store store = Store.getInstance(account, getApplication(), null);
Store store = Store.getInstance(account, getApplication());
if (store != null) {
Class<? extends android.app.Activity> setting = store.getSettingActivityClass();
if (setting != null) {

View File

@ -78,14 +78,12 @@ 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(Account account, Context context,
PersistentDataCallbacks callbacks) throws MessagingException {
static Store newInstance(Account account, Context context) throws MessagingException {
throw new MessagingException("Store#newInstance: Unknown scheme in "
+ account.mDisplayName);
}
private static Store instantiateStore(String className, Account account, Context context,
PersistentDataCallbacks callbacks)
private static Store instantiateStore(String className, Account account, Context context)
throws MessagingException {
Object o = null;
try {
@ -95,7 +93,7 @@ public abstract class Store {
c.getMethod("newInstance", Account.class, Context.class,
PersistentDataCallbacks.class);
// TODO Do the stores _really need a context? Is there a way to not pass it along?
o = m.invoke(null, account, context, callbacks);
o = m.invoke(null, account, context);
} catch (Exception e) {
Log.d(Logging.LOG_TAG, String.format(
"exception %s invoking method %s#newInstance(Account, Context) for %s",
@ -176,23 +174,20 @@ public abstract class Store {
* @return an initialized store of the appropriate class
* @throws MessagingException If the store cannot be obtained or if the account is invalid.
*/
public synchronized static Store getInstance(Account account, Context context,
PersistentDataCallbacks callbacks) throws MessagingException {
public synchronized static Store getInstance(Account account, Context context)
throws MessagingException {
HostAuth hostAuth = account.getOrCreateHostAuthRecv(context);
Store store = sStores.get(hostAuth);
if (store == null) {
Context appContext = context.getApplicationContext();
StoreInfo info = StoreInfo.getStoreInfo(hostAuth.mProtocol, context);
if (info != null) {
store = instantiateStore(info.mClassName, account, appContext, callbacks);
store = instantiateStore(info.mClassName, account, appContext);
}
// Don't cache this unless it's we've got a saved HostAUth
if (store != null && (hostAuth.mId != EmailContent.NOT_SAVED)) {
sStores.put(hostAuth, store);
}
} else {
// update the callbacks, which may have been null at creation time.
store.setPersistentDataCallbacks(callbacks);
}
if (store == null) {

View File

@ -17,75 +17,39 @@
package com.android.email.mail.store;
import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import com.android.email.mail.Store;
import com.android.email.service.EmailServiceUtils;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.service.EmailServiceProxy;
import com.android.emailcommon.service.IEmailService;
/**
* Our Exchange service does not use the sender/store model.
*/
public class ExchangeStore extends Store {
private final HostAuth mHostAuth;
public class ExchangeStore extends ServiceStore {
/**
* Static named constructor.
*/
public static Store newInstance(Account account, Context context,
PersistentDataCallbacks callbacks) throws MessagingException {
return new ExchangeStore(account, context, callbacks);
public static Store newInstance(Account account, Context context) throws MessagingException {
return new ExchangeStore(account, context);
}
/**
* Creates a new store for the given account.
*/
private ExchangeStore(Account account, Context context, PersistentDataCallbacks callbacks)
throws MessagingException {
mContext = context;
mHostAuth = account.getOrCreateHostAuthRecv(mContext);
}
@Override
public Bundle checkSettings() throws MessagingException {
/**
* Here's where we check the settings for EAS.
* @throws MessagingException if we can't authenticate the account
*/
try {
IEmailService svc = EmailServiceUtils.getExchangeService(mContext, null);
// Use a longer timeout for the validate command. Note that the instanceof check
// shouldn't be necessary; we'll do it anyway, just to be safe
if (svc instanceof EmailServiceProxy) {
((EmailServiceProxy)svc).setTimeout(90);
}
return svc.validate(mHostAuth);
} catch (RemoteException e) {
throw new MessagingException("Call to validate generated an exception", e);
}
}
/**
* We handle AutoDiscover for Exchange 2007 (and later) here, wrapping the EmailService call.
* The service call returns a HostAuth and we return null if there was a service issue
*/
@Override
public Bundle autoDiscover(Context context, String username, String password) {
try {
return EmailServiceUtils.getExchangeService(context, null).autoDiscover(
username, password);
} catch (RemoteException e) {
return null;
}
public ExchangeStore(Account account, Context context) throws MessagingException {
super(account, context);
}
@Override
public Class<? extends android.app.Activity> getSettingActivityClass() {
return com.android.email.activity.setup.AccountSetupExchange.class;
}
@Override
protected IEmailService getService() {
return EmailServiceUtils.getExchangeService(mContext, null);
}
}

View File

@ -16,6 +16,14 @@
package com.android.email.mail.store;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import com.android.email.LegacyConversions;
import com.android.email.Preferences;
import com.android.email.VendorPolicyLoader;
@ -40,14 +48,6 @@ import com.android.emailcommon.utility.Utility;
import com.beetstra.jutf7.CharsetProvider;
import com.google.common.annotations.VisibleForTesting;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
@ -101,8 +101,7 @@ public class ImapStore extends Store {
/**
* Static named constructor.
*/
public static Store newInstance(Account account, Context context,
PersistentDataCallbacks callbacks) throws MessagingException {
public static Store newInstance(Account account, Context context) throws MessagingException {
return new ImapStore(context, account);
}

View File

@ -86,8 +86,7 @@ public class Pop3Store extends Store {
/**
* Static named constructor.
*/
public static Store newInstance(Account account, Context context,
PersistentDataCallbacks callbacks) throws MessagingException {
public static Store newInstance(Account account, Context context) throws MessagingException {
return new Pop3Store(context, account);
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.email.mail.store;
import android.content.Context;
import android.os.Bundle;
import android.os.RemoteException;
import com.android.email.mail.Store;
import com.android.emailcommon.mail.MessagingException;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.service.EmailServiceProxy;
import com.android.emailcommon.service.IEmailService;
/**
* Base class for service-based stores
*/
public abstract class ServiceStore extends Store {
protected final HostAuth mHostAuth;
protected abstract IEmailService getService();
/**
* Creates a new store for the given account.
*/
public ServiceStore(Account account, Context context) throws MessagingException {
mContext = context;
mHostAuth = account.getOrCreateHostAuthRecv(mContext);
}
@Override
public Bundle checkSettings() throws MessagingException {
/**
* Here's where we check the settings
* @throws MessagingException if we can't authenticate the account
*/
try {
IEmailService svc = getService();
// Use a longer timeout for the validate command. Note that the instanceof check
// shouldn't be necessary; we'll do it anyway, just to be safe
if (svc instanceof EmailServiceProxy) {
((EmailServiceProxy)svc).setTimeout(90);
}
return svc.validate(mHostAuth);
} catch (RemoteException e) {
throw new MessagingException("Call to validate generated an exception", e);
}
}
/**
* We handle AutoDiscover here, wrapping the EmailService call. The service call returns a
* HostAuth and we return null if there was a service issue
*/
@Override
public Bundle autoDiscover(Context context, String username, String password) {
try {
return getService().autoDiscover(username, password);
} catch (RemoteException e) {
return null;
}
}
}

View File

@ -91,7 +91,7 @@ public class StoreTests extends ProviderTestCase2<EmailProvider> {
testAuth.mProtocol = "pop3";
testAccount.save(mMockContext);
testStore = Store.getInstance(testAccount, getContext(), null);
testStore = Store.getInstance(testAccount, getContext());
assertEquals(1, Store.sStores.size());
assertSame(testStore, Store.sStores.get(testAccount.mId));
Store.sStores.clear();
@ -103,7 +103,7 @@ public class StoreTests extends ProviderTestCase2<EmailProvider> {
testAuth.mAddress = "imap.google.com";
testAuth.mProtocol = "imap";
testAccount.save(mMockContext);
testStore = Store.getInstance(testAccount, getContext(), null);
testStore = Store.getInstance(testAccount, getContext());
assertEquals(1, Store.sStores.size());
assertSame(testStore, Store.sStores.get(testAccount.mId));
Store.sStores.clear();
@ -114,7 +114,7 @@ public class StoreTests extends ProviderTestCase2<EmailProvider> {
testAuth.mAddress = "unknown.google.com";
testAuth.mProtocol = "unknown";
try {
testStore = Store.getInstance(testAccount, getContext(), null);
testStore = Store.getInstance(testAccount, getContext());
fail("Store#getInstance() should have thrown an exception");
} catch (MessagingException expected) {
}

View File

@ -154,7 +154,7 @@ public class ImapStoreUnitTests extends InstrumentationTestCase {
testAuth.setLogin("user", "password");
testAuth.setConnection("imap", "server", 999);
testAccount.mHostAuthRecv = testAuth;
mStore = (ImapStore) ImapStore.newInstance(testAccount, mTestContext, null);
mStore = (ImapStore) ImapStore.newInstance(testAccount, mTestContext);
mFolder = (ImapFolder) mStore.getFolder(FOLDER_NAME);
resetTag();
}
@ -350,7 +350,7 @@ public class ImapStoreUnitTests extends InstrumentationTestCase {
testAuth.setConnection("imap", "server", 999);
testAccount = new Account();
testAccount.mHostAuthRecv = testAuth;
ImapStore testStore1A = (ImapStore) ImapStore.newInstance(testAccount, mTestContext, null);
ImapStore testStore1A = (ImapStore) ImapStore.newInstance(testAccount, mTestContext);
// store 1b
testAuth = new HostAuth();
@ -358,7 +358,7 @@ public class ImapStoreUnitTests extends InstrumentationTestCase {
testAuth.setConnection("imap", "server", 999);
testAccount = new Account();
testAccount.mHostAuthRecv = testAuth;
ImapStore testStore1B = (ImapStore) ImapStore.newInstance(testAccount, mTestContext, null);
ImapStore testStore1B = (ImapStore) ImapStore.newInstance(testAccount, mTestContext);
// store 2
testAuth = new HostAuth();
@ -366,7 +366,7 @@ public class ImapStoreUnitTests extends InstrumentationTestCase {
testAuth.setConnection("imap", "server", 999);
testAccount = new Account();
testAccount.mHostAuthRecv = testAuth;
ImapStore testStore2 = (ImapStore) ImapStore.newInstance(testAccount, mTestContext, null);
ImapStore testStore2 = (ImapStore) ImapStore.newInstance(testAccount, mTestContext);
String capabilities = CAPABILITY_RESPONSE.flatten();
String id1a = ImapStore.getImapId(mTestContext, "user1", "host-name", capabilities);

View File

@ -65,8 +65,7 @@ public class Pop3StoreUnitTests extends InstrumentationTestCase {
testAuth.setLogin("user", "password");
testAuth.setConnection("pop3", "server", 999);
testAccount.mHostAuthRecv = testAuth;
mStore = (Pop3Store) Pop3Store.newInstance(
testAccount, getInstrumentation().getContext(), null);
mStore = (Pop3Store) Pop3Store.newInstance(testAccount, getInstrumentation().getContext());
mFolder = (Pop3Store.Pop3Folder) mStore.getFolder("INBOX");
}