More Store cleanup

Change-Id: I8f542175b4468c7a320322a57bfdaf19a7320165
This commit is contained in:
Marc Blank 2011-06-29 14:47:21 -07:00
parent aa46bc3919
commit 0b8e04c84d
10 changed files with 48 additions and 243 deletions

View File

@ -254,6 +254,18 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
}
}
/**
* Returns a {@link Mailbox} for the given path. If the path is not in the database, a new
* mailbox will be created.
*/
public static Mailbox getMailboxForPath(Context context, long accountId, String path) {
Mailbox mailbox = restoreMailboxForPath(context, accountId, path);
if (mailbox == null) {
mailbox = new Mailbox();
}
return mailbox;
}
@Override
public void restore(Cursor cursor) {
mBaseUri = CONTENT_URI;

View File

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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.
-->
<!--
This file contains configuration data for commonly-used email store.
==== CONTENT GUIDELINES ====
This file should only be used for email store that are considered "universal"
and are appropriate for *all* android platform devices. These entries must be accessible
from all networks. It should be reasonable for any user to obtain an account on these
networks, and test accounts must be easily obtainable. No entries should be added
that are device, product, or carrier-specific.
Entries that are device, product or carrier-specific should be added as overlays
in the appropriate stores_product.xml file.
-->
<stores>
<store scheme="local" class="com.android.email.mail.store.LocalStore" />
<store scheme="pop3" class="com.android.email.mail.store.Pop3Store" />
<store scheme="imap" class="com.android.email.mail.store.ImapStore" />
<store scheme="eas" class="com.android.email.mail.store.ExchangeStore"
push="true" visibleLimitDefault="-1" visibleLimitIncrement="-1" />
</stores>

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Email stores that are considered "universal" and are appropriate for *all* android
platform devices should be defined in stores.xml.
Entries that are device, product or carrier-specific should be added as overlays
in the appropriate stores_product.xml file.
Because overlays must correspond to an existing platform resource, this empty placeholder
is included in the platform build.
-->
<stores_product>
<!-- THIS SECTION MUST REMAIN EMPTY -->
<!-- Actual entries should be in the overlay files found elsewhere -->
</stores_product>

View File

@ -31,7 +31,6 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
import com.android.email.mail.Store;
import com.android.email.mail.store.Pop3Store.Pop3Message;
import com.android.email.provider.AccountBackupRestore;
import com.android.email.service.EmailServiceUtils;
@ -1096,16 +1095,6 @@ public class Controller {
return; // Already deleted?
}
try {
// Remove the store instance from cache
Store oldStore = Store.removeInstance(account, context);
if (oldStore != null) {
oldStore.delete(); // If the store was removed, delete it
}
} catch (MessagingException e) {
Log.w(Logging.LOG_TAG, "Failed to delete store", e);
}
Uri uri = ContentUris.withAppendedId(
Account.CONTENT_URI, accountId);
context.getContentResolver().delete(uri, null, null);

View File

@ -17,12 +17,13 @@
package com.android.email.mail;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.util.Log;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.mail.store.ExchangeStore;
import com.android.email.mail.store.ImapStore;
import com.android.email.mail.store.Pop3Store;
import com.android.emailcommon.Logging;
import com.android.emailcommon.mail.Folder;
import com.android.emailcommon.mail.MessagingException;
@ -32,21 +33,13 @@ import com.android.emailcommon.provider.HostAuth;
import com.android.emailcommon.provider.Mailbox;
import com.google.common.annotations.VisibleForTesting;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
/**
* Store is the access point for an email message store. It's location can be
* local or remote and no specific protocol is defined. Store is intended to
* loosely model in combination the JavaMail classes javax.mail.Store and
* javax.mail.Folder along with some additional functionality to improve
* performance on mobile devices. Implementations of this class should focus on
* making as few network connections as possible.
* Store is the legacy equivalent of the Account class
*/
public abstract class Store {
/**
* A global suggestion to Store implementors on how much of the body
* should be returned on FetchProfile.Item.BODY_SANE requests.
@ -55,13 +48,21 @@ public abstract class Store {
@VisibleForTesting
static final HashMap<HostAuth, Store> sStores = new HashMap<HostAuth, Store>();
protected Context mContext;
protected Account mAccount;
protected Transport mTransport;
protected String mUsername;
protected String mPassword;
static final HashMap<String, Class<? extends Store>> sStoreClasses =
new HashMap<String, Class<? extends Store>>();
{
sStoreClasses.put(HostAuth.SCHEME_EAS, ExchangeStore.class);
sStoreClasses.put(HostAuth.SCHEME_IMAP, ImapStore.class);
sStoreClasses.put(HostAuth.SCHEME_POP3, Pop3Store.class);
}
/**
* Static named constructor. It should be overrode by extending class.
* Because this method will be called through reflection, it can not be protected.
@ -71,83 +72,6 @@ public abstract class Store {
+ account.mDisplayName);
}
private static Store instantiateStore(String className, Account account, Context context)
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", Account.class, Context.class);
// TODO Do the stores _really need a context? Is there a way to not pass it along?
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",
e.toString(), className, account.mDisplayName));
throw new MessagingException("can not instantiate Store for " + account.mDisplayName);
}
if (!(o instanceof Store)) {
throw new MessagingException(
account.mDisplayName + ": " + className + " create incompatible object");
}
return (Store) o;
}
/**
* Look up descriptive information about a particular type of store.
*/
public static class StoreInfo {
public String mScheme;
public String mClassName;
public boolean mPushSupported = false;
public int mVisibleLimitDefault;
public int mVisibleLimitIncrement;
public int mAccountInstanceLimit;
// TODO cache result for performance - silly to keep reading the XML
public static StoreInfo getStoreInfo(String scheme, Context context) {
StoreInfo result = getStoreInfo(R.xml.stores_product, scheme, context);
if (result == null) {
result = getStoreInfo(R.xml.stores, scheme, context);
}
return result;
}
public static StoreInfo getStoreInfo(int resourceId, String scheme, Context context) {
try {
XmlResourceParser xml = context.getResources().getXml(resourceId);
int xmlEventType;
// walk through stores.xml file.
while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
if (xmlEventType == XmlResourceParser.START_TAG &&
"store".equals(xml.getName())) {
String xmlScheme = xml.getAttributeValue(null, "scheme");
if (scheme != null && scheme.startsWith(xmlScheme)) {
StoreInfo result = new StoreInfo();
result.mScheme = xmlScheme;
result.mClassName = xml.getAttributeValue(null, "class");
result.mPushSupported = xml.getAttributeBooleanValue(
null, "push", false);
result.mVisibleLimitDefault = xml.getAttributeIntValue(
null, "visibleLimitDefault", Email.VISIBLE_LIMIT_DEFAULT);
result.mVisibleLimitIncrement = xml.getAttributeIntValue(
null, "visibleLimitIncrement", Email.VISIBLE_LIMIT_INCREMENT);
result.mAccountInstanceLimit = xml.getAttributeIntValue(
null, "accountInstanceLimit", -1);
return result;
}
}
}
} catch (XmlPullParserException e) {
// ignore
} catch (IOException e) {
// ignore
}
return null;
}
}
/**
* Get an instance of a mail store for the given account. The account must be valid (i.e. has
* at least an incoming server name).
@ -167,20 +91,22 @@ public abstract class Store {
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);
Class<? extends Store> klass = sStoreClasses.get(hostAuth.mProtocol);
try {
// invoke "newInstance" class method
Method m = klass.getMethod("newInstance", Account.class, Context.class);
store = (Store)m.invoke(null, account, appContext);
} catch (Exception e) {
Log.d(Logging.LOG_TAG, String.format(
"exception %s invoking method %s#newInstance(Account, Context) for %s",
e.toString(), klass.getName(), account.mDisplayName));
throw new MessagingException("Can't instantiate Store for " + account.mDisplayName);
}
// Don't cache this unless it's we've got a saved HostAUth
if (store != null && (hostAuth.mId != EmailContent.NOT_SAVED)) {
// Don't cache this unless it's we've got a saved HostAuth
if (hostAuth.mId != EmailContent.NOT_SAVED) {
sStores.put(hostAuth, store);
}
}
if (store == null) {
throw new MessagingException("Cannot find store for account " + account.mDisplayName);
}
return store;
}
@ -235,13 +161,6 @@ public abstract class Store {
public abstract Bundle checkSettings() throws MessagingException;
/**
* Delete Store and its corresponding resources.
* @throws MessagingException
*/
public void delete() throws MessagingException {
}
/**
* Handle discovery of account settings using only the user's email address and password
* @param context the context of the caller
@ -255,18 +174,6 @@ public abstract class Store {
return null;
}
/**
* Returns a {@link Mailbox} for the given path. If the path is not in the database, a new
* mailbox will be created.
*/
protected static Mailbox getMailboxForPath(Context context, long accountId, String path) {
Mailbox mailbox = Mailbox.restoreMailboxForPath(context, accountId, path);
if (mailbox == null) {
mailbox = new Mailbox();
}
return mailbox;
}
/**
* Updates the fields within the given mailbox. Only the fields that are important to
* non-EAS accounts are modified.

View File

@ -353,7 +353,7 @@ public class ImapStore extends Store {
private ImapFolder addMailbox(Context context, long accountId, String mailboxPath,
char delimiter, boolean selectable) {
ImapFolder folder = (ImapFolder) getFolder(mailboxPath);
Mailbox mailbox = getMailboxForPath(context, accountId, mailboxPath);
Mailbox mailbox = Mailbox.getMailboxForPath(context, accountId, mailboxPath);
if (mailbox.isSaved()) {
// existing mailbox
// mailbox retrieved from database; save hash _before_ updating fields

View File

@ -151,7 +151,7 @@ public class Pop3Store extends Store {
@Override
public Folder[] updateFolders() {
Mailbox mailbox = getMailboxForPath(mContext, mAccount.mId, POP3_MAILBOX_NAME);
Mailbox mailbox = Mailbox.getMailboxForPath(mContext, mAccount.mId, POP3_MAILBOX_NAME);
updateMailbox(mailbox, mAccount.mId, POP3_MAILBOX_NAME, '\0', true, Mailbox.TYPE_INBOX);
// Force the parent key to be "no mailbox" for the mail POP3 mailbox
mailbox.mParentKey = Mailbox.NO_MAILBOX;

View File

@ -16,10 +16,6 @@
package com.android.email.activity.setup;
import com.android.email.mail.Store;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
@ -29,6 +25,9 @@ import android.preference.PreferenceFragment;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.MediumTest;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
import java.net.URISyntaxException;
/**
@ -38,7 +37,7 @@ import java.net.URISyntaxException;
* TODO: These cannot run in the single-pane mode, and need to be refactored into single-pane
* and multi-pane versions. Until then, they are all disabled.
*
* To execute: runtest -c com.android.email.activity.setup.AccountSettingsXLTests email
* To execute: runtest -c com.android.email.activity.setup.AccountSettingsTests email
*/
@MediumTest
public class AccountSettingsTests extends ActivityInstrumentationTestCase2<AccountSettings> {
@ -111,12 +110,6 @@ public class AccountSettingsTests extends ActivityInstrumentationTestCase2<Accou
* Test that EAS accounts are displayed with a push option
*/
public void disable_testPushOptionEAS() throws Throwable {
// This test should only be run if EAS is supported
if (Store.StoreInfo.getStoreInfo("eas", getInstrumentation().getTargetContext())
== null) {
return;
}
Intent i = getTestIntent("Name", "eas://user:password@server.com",
"eas://user:password@server.com");
setActivityIntent(i);

View File

@ -16,11 +16,6 @@
package com.android.email.activity.setup;
import com.android.email.R;
import com.android.email.mail.Store;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
import android.content.Context;
import android.content.Intent;
import android.test.ActivityInstrumentationTestCase2;
@ -30,6 +25,10 @@ import android.widget.CheckBox;
import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import com.android.email.R;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.HostAuth;
import java.net.URISyntaxException;
/**
@ -82,12 +81,6 @@ public class AccountSetupOptionsTests
*/
public void testPushOptionEAS()
throws URISyntaxException {
// This test should only be run if EAS is supported
if (Store.StoreInfo.getStoreInfo("eas", this.getInstrumentation().getTargetContext())
== null) {
return;
}
Intent i = getTestIntent("Name", "eas://user:password@server.com");
this.setActivityIntent(i);
@ -118,11 +111,6 @@ public class AccountSetupOptionsTests
*/
public void testBackgroundAttachmentsEas()
throws URISyntaxException {
// This test should only be run if EAS is supported
if (Store.StoreInfo.getStoreInfo("eas", this.getInstrumentation().getTargetContext())
== null) {
return;
}
checkBackgroundAttachments("eas://user:password@server.com", true);
}

View File

@ -20,8 +20,6 @@ import android.content.Context;
import android.test.ProviderTestCase2;
import android.test.suitebuilder.annotation.MediumTest;
import com.android.email.Email;
import com.android.email.mail.Store.StoreInfo;
import com.android.email.provider.EmailProvider;
import com.android.email.provider.ProviderTestUtils;
import com.android.emailcommon.mail.MessagingException;
@ -54,32 +52,6 @@ public class StoreTests extends ProviderTestCase2<EmailProvider> {
super(EmailProvider.class, EmailContent.AUTHORITY);
}
public void testGetStoreInfo() {
StoreInfo testInfo;
// POP3
testInfo = Store.StoreInfo.getStoreInfo("pop3", mContext);
assertNotNull(testInfo);
assertNotNull(testInfo.mScheme);
assertNotNull(testInfo.mClassName);
assertFalse(testInfo.mPushSupported);
assertEquals(Email.VISIBLE_LIMIT_DEFAULT, testInfo.mVisibleLimitDefault);
assertEquals(Email.VISIBLE_LIMIT_INCREMENT, testInfo.mVisibleLimitIncrement);
// IMAP
testInfo = Store.StoreInfo.getStoreInfo("imap", mContext);
assertNotNull(testInfo);
assertNotNull(testInfo.mScheme);
assertNotNull(testInfo.mClassName);
assertFalse(testInfo.mPushSupported);
assertEquals(Email.VISIBLE_LIMIT_DEFAULT, testInfo.mVisibleLimitDefault);
assertEquals(Email.VISIBLE_LIMIT_INCREMENT, testInfo.mVisibleLimitIncrement);
// Unknown
testInfo = Store.StoreInfo.getStoreInfo("unknownscheme", mContext);
assertNull(testInfo);
}
public void testGetInstance() throws MessagingException {
Store testStore;