Merge "Improve EmailContent caching..."
This commit is contained in:
commit
0404a331ad
|
@ -30,6 +30,8 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
Uri.parse(EmailContent.CONTENT_URI + "/resetNewMessageCount");
|
||||
public static final Uri NOTIFIER_URI =
|
||||
Uri.parse(EmailContent.CONTENT_NOTIFIER_URI + "/account");
|
||||
public static final Uri DEFAULT_ACCOUNT_ID_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/account/default");
|
||||
|
||||
// Define all pseudo account IDs here to avoid conflict with one another.
|
||||
/**
|
||||
|
@ -545,18 +547,21 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
|
||||
/**
|
||||
* Return the id of the default account. If one hasn't been explicitly specified, return
|
||||
* the first one in the database. For any account saved in the DB, this must be used
|
||||
* to check for the default account - the mIsDefault field is set lazily and may be
|
||||
* incorrect.
|
||||
* the first one in the database (the logic is provided within EmailProvider)
|
||||
* @param context the caller's context
|
||||
* @return the id of the default account, or -1 if there are no accounts
|
||||
*/
|
||||
static public long getDefaultAccountId(Context context) {
|
||||
long id = getDefaultAccountWhere(context, AccountColumns.IS_DEFAULT + "=1");
|
||||
if (id == -1) {
|
||||
id = getDefaultAccountWhere(context, null);
|
||||
Cursor c = context.getContentResolver().query(
|
||||
Account.DEFAULT_ACCOUNT_ID_URI, Account.ID_PROJECTION, null, null, null);
|
||||
try {
|
||||
if (c != null && c.moveToFirst()) {
|
||||
return c.getLong(Account.ID_PROJECTION_COLUMN);
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
return id;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -755,7 +760,7 @@ public final class Account extends EmailContent implements AccountColumns, Parce
|
|||
|
||||
// Now do the Account
|
||||
ContentValues cv = null;
|
||||
if (recvIndex >= 0 || sendIndex >= 0) {
|
||||
if (recvIndex >= 0 || sendIndex >= 0 || policyIndex >= 0) {
|
||||
cv = new ContentValues();
|
||||
if (recvIndex >= 0) {
|
||||
cv.put(Account.HOST_AUTH_KEY_RECV, recvIndex);
|
||||
|
|
|
@ -37,6 +37,8 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
|
|||
public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/mailbox");
|
||||
public static final Uri ADD_TO_FIELD_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/mailboxIdAddToField");
|
||||
public static final Uri FROM_ACCOUNT_AND_TYPE_URI =
|
||||
Uri.parse(EmailContent.CONTENT_URI + "/mailboxIdFromAccountAndType");
|
||||
|
||||
public String mDisplayName;
|
||||
public String mServerId;
|
||||
|
@ -299,13 +301,27 @@ public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns
|
|||
}
|
||||
|
||||
/**
|
||||
* Convenience method to return the id of a given type of Mailbox for a given Account
|
||||
* Convenience method to return the id of a given type of Mailbox for a given Account; the
|
||||
* common Mailbox types (Inbox, Outbox, Sent, Drafts, Trash, and Search) are all cached by
|
||||
* EmailProvider; therefore, we warn if the mailbox is not found in the cache
|
||||
*
|
||||
* @param context the caller's context, used to get a ContentResolver
|
||||
* @param accountId the id of the account to be queried
|
||||
* @param type the mailbox type, as defined above
|
||||
* @return the id of the mailbox, or -1 if not found
|
||||
*/
|
||||
public static long findMailboxOfType(Context context, long accountId, int type) {
|
||||
// First use special URI
|
||||
Uri uri = FROM_ACCOUNT_AND_TYPE_URI.buildUpon().appendPath(Long.toString(accountId))
|
||||
.appendPath(Integer.toString(type)).build();
|
||||
Cursor c = context.getContentResolver().query(uri, ID_PROJECTION, null, null, null);
|
||||
c.moveToFirst();
|
||||
Long mailboxId = c.getLong(ID_PROJECTION_COLUMN);
|
||||
if (mailboxId != null && mailboxId.intValue() != 0) {
|
||||
return mailboxId;
|
||||
} else {
|
||||
Log.w(Logging.LOG_TAG, "========== Mailbox of type " + type + " not found in cache??");
|
||||
}
|
||||
String[] bindArguments = new String[] {Long.toString(type), Long.toString(accountId)};
|
||||
return Utility.getFirstRowLong(context, Mailbox.CONTENT_URI,
|
||||
ID_PROJECTION, WHERE_TYPE_AND_ACCOUNT_KEY, bindArguments, null,
|
||||
|
|
|
@ -16,28 +16,12 @@
|
|||
|
||||
package com.android.email;
|
||||
|
||||
import com.android.email.activity.ContactStatusLoader;
|
||||
import com.android.email.activity.Welcome;
|
||||
import com.android.email.activity.setup.AccountSecurity;
|
||||
import com.android.email.activity.setup.AccountSettings;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.mail.Address;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.Notification.Builder;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.ContentObserver;
|
||||
|
@ -54,6 +38,22 @@ import android.text.TextUtils;
|
|||
import android.text.style.TextAppearanceSpan;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.email.activity.ContactStatusLoader;
|
||||
import com.android.email.activity.Welcome;
|
||||
import com.android.email.activity.setup.AccountSecurity;
|
||||
import com.android.email.activity.setup.AccountSettings;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.mail.Address;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
|
@ -608,10 +608,9 @@ public class NotificationController {
|
|||
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
long lastSeenMessageId = Utility.getFirstRowLong(
|
||||
mContext, Mailbox.CONTENT_URI,
|
||||
mContext, ContentUris.withAppendedId(Mailbox.CONTENT_URI, mMailboxId),
|
||||
new String[] { MailboxColumns.LAST_SEEN_MESSAGE_KEY },
|
||||
EmailContent.ID_SELECTION,
|
||||
new String[] { Long.toString(mMailboxId) }, null, 0, 0L);
|
||||
null, null, null, 0, 0L);
|
||||
Cursor c = resolver.query(
|
||||
Message.CONTENT_URI, EmailContent.ID_PROJECTION,
|
||||
MESSAGE_SELECTION,
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package com.android.email.provider;
|
||||
|
||||
import com.android.email.Email;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.CursorWrapper;
|
||||
|
@ -25,6 +23,10 @@ import android.database.MatrixCursor;
|
|||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
|
||||
import com.android.email.Email;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
@ -89,7 +91,7 @@ public final class ContentCache {
|
|||
private static final ArrayList<ContentCache> sContentCaches = new ArrayList<ContentCache>();
|
||||
// A set of all unclosed, cached cursors; this will typically be a very small set, as cursors
|
||||
// tend to be closed quickly after use. The value, for each cursor, is its reference count
|
||||
/*package*/ static CounterMap<Cursor> sActiveCursors;
|
||||
/*package*/ static final CounterMap<Cursor> sActiveCursors = new CounterMap<Cursor>(24);
|
||||
|
||||
// A set of locked content id's
|
||||
private final CounterMap<String> mLockMap = new CounterMap<String>(4);
|
||||
|
@ -404,7 +406,6 @@ public final class ContentCache {
|
|||
mLogTag = "ContentCache-" + name;
|
||||
sContentCaches.add(this);
|
||||
mTokenList = new TokenList(mName);
|
||||
sActiveCursors = new CounterMap<Cursor>(maxSize);
|
||||
mStats = new Statistics(this);
|
||||
}
|
||||
|
||||
|
@ -436,10 +437,14 @@ public final class ContentCache {
|
|||
return mLruCache.size();
|
||||
}
|
||||
|
||||
private Cursor get(String id) {
|
||||
@VisibleForTesting
|
||||
Cursor get(String id) {
|
||||
return mLruCache.get(id);
|
||||
}
|
||||
|
||||
protected Map<String, Cursor> getSnapshot() {
|
||||
return mLruCache.snapshot();
|
||||
}
|
||||
/**
|
||||
* Try to cache a cursor for the given id and projection; returns a valid cursor, either a
|
||||
* cached cursor (if caching was successful) or the original cursor
|
||||
|
@ -456,7 +461,6 @@ public final class ContentCache {
|
|||
c.moveToPosition(0);
|
||||
return putCursorImpl(c, id, projection, token);
|
||||
}
|
||||
|
||||
public synchronized Cursor putCursorImpl(Cursor c, String id, String[] projection,
|
||||
CacheToken token) {
|
||||
try {
|
||||
|
@ -467,7 +471,7 @@ public final class ContentCache {
|
|||
mStats.mStaleCount++;
|
||||
return c;
|
||||
}
|
||||
if (c != null && projection == mBaseProjection && !sLockCache) {
|
||||
if (c != null && Arrays.equals(projection, mBaseProjection) && !sLockCache) {
|
||||
if (Email.DEBUG && DEBUG_CACHE) {
|
||||
Log.d(mLogTag, "============ Caching cursor for: " + id);
|
||||
}
|
||||
|
@ -723,7 +727,7 @@ public final class ContentCache {
|
|||
}
|
||||
|
||||
// For use with unit tests
|
||||
public static void invalidateAllCachesForTest() {
|
||||
public static void invalidateAllCaches() {
|
||||
for (ContentCache cache: sContentCaches) {
|
||||
cache.invalidate();
|
||||
}
|
||||
|
@ -733,7 +737,7 @@ public final class ContentCache {
|
|||
public static void setLockCacheForTest(boolean lock) {
|
||||
sLockCache = lock;
|
||||
if (sLockCache) {
|
||||
invalidateAllCachesForTest();
|
||||
invalidateAllCaches();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,34 +16,6 @@
|
|||
|
||||
package com.android.email.provider;
|
||||
|
||||
import com.android.email.Email;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.provider.ContentCache.CacheToken;
|
||||
import com.android.email.service.AttachmentDownloadService;
|
||||
import com.android.emailcommon.AccountManagerTypes;
|
||||
import com.android.emailcommon.CalendarProviderStub;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.AccountColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
import com.android.emailcommon.provider.EmailContent.AttachmentColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Body;
|
||||
import com.android.emailcommon.provider.EmailContent.BodyColumns;
|
||||
import com.android.emailcommon.provider.QuickResponse;
|
||||
import com.android.emailcommon.provider.EmailContent.QuickResponseColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.HostAuthColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.PolicyColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.SyncColumns;
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
import com.android.emailcommon.provider.Policy;
|
||||
import com.android.emailcommon.service.LegacyPolicySet;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentProviderOperation;
|
||||
|
@ -66,8 +38,40 @@ import android.provider.ContactsContract;
|
|||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.email.Email;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.provider.ContentCache.CacheToken;
|
||||
import com.android.email.service.AttachmentDownloadService;
|
||||
import com.android.emailcommon.AccountManagerTypes;
|
||||
import com.android.emailcommon.CalendarProviderStub;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.AccountColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
import com.android.emailcommon.provider.EmailContent.AttachmentColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Body;
|
||||
import com.android.emailcommon.provider.EmailContent.BodyColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.HostAuthColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.PolicyColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.QuickResponseColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.SyncColumns;
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
import com.android.emailcommon.provider.Policy;
|
||||
import com.android.emailcommon.provider.QuickResponse;
|
||||
import com.android.emailcommon.service.LegacyPolicySet;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EmailProvider extends ContentProvider {
|
||||
|
||||
|
@ -106,17 +110,24 @@ public class EmailProvider extends ContentProvider {
|
|||
|
||||
private static final String WHERE_ID = EmailContent.RECORD_ID + "=?";
|
||||
|
||||
// This is not a hard limit on accounts, per se, but beyond this, we can't guarantee that all
|
||||
// critical mailboxes, host auth's, accounts, and policies are cached
|
||||
private static final int MAX_CACHED_ACCOUNTS = 16;
|
||||
// Inbox, Drafts, Sent, Outbox, Trash, and Search (these boxes are cached when possible)
|
||||
private static final int NUM_ALWAYS_CACHED_MAILBOXES = 6;
|
||||
|
||||
// We'll cache the following four tables; sizes are best estimates of effective values
|
||||
private static final ContentCache sCacheAccount =
|
||||
new ContentCache("Account", Account.CONTENT_PROJECTION, 4);
|
||||
private static final ContentCache sCacheHostAuth =
|
||||
new ContentCache("HostAuth", HostAuth.CONTENT_PROJECTION, 8);
|
||||
/*package*/ static final ContentCache sCacheMailbox =
|
||||
new ContentCache("Mailbox", Mailbox.CONTENT_PROJECTION, 8);
|
||||
private static final ContentCache sCacheMessage =
|
||||
private final ContentCache mCacheAccount =
|
||||
new ContentCache("Account", Account.CONTENT_PROJECTION, MAX_CACHED_ACCOUNTS);
|
||||
private final ContentCache mCacheHostAuth =
|
||||
new ContentCache("HostAuth", HostAuth.CONTENT_PROJECTION, MAX_CACHED_ACCOUNTS * 2);
|
||||
/*package*/ final ContentCache mCacheMailbox =
|
||||
new ContentCache("Mailbox", Mailbox.CONTENT_PROJECTION,
|
||||
MAX_CACHED_ACCOUNTS * (NUM_ALWAYS_CACHED_MAILBOXES + 2));
|
||||
private final ContentCache mCacheMessage =
|
||||
new ContentCache("Message", Message.CONTENT_PROJECTION, 8);
|
||||
private static final ContentCache sCachePolicy =
|
||||
new ContentCache("Policy", Policy.CONTENT_PROJECTION, 4);
|
||||
private final ContentCache mCachePolicy =
|
||||
new ContentCache("Policy", Policy.CONTENT_PROJECTION, MAX_CACHED_ACCOUNTS);
|
||||
|
||||
// Any changes to the database format *must* include update-in-place code.
|
||||
// Original version: 3
|
||||
|
@ -162,10 +173,12 @@ public class EmailProvider extends ContentProvider {
|
|||
private static final int ACCOUNT_ID_ADD_TO_FIELD = ACCOUNT_BASE + 2;
|
||||
private static final int ACCOUNT_RESET_NEW_COUNT = ACCOUNT_BASE + 3;
|
||||
private static final int ACCOUNT_RESET_NEW_COUNT_ID = ACCOUNT_BASE + 4;
|
||||
private static final int ACCOUNT_DEFAULT_ID = ACCOUNT_BASE + 5;
|
||||
|
||||
private static final int MAILBOX_BASE = 0x1000;
|
||||
private static final int MAILBOX = MAILBOX_BASE;
|
||||
private static final int MAILBOX_ID = MAILBOX_BASE + 1;
|
||||
private static final int MAILBOX_ID_FROM_ACCOUNT_AND_TYPE = MAILBOX_BASE + 2;
|
||||
private static final int MAILBOX_ID_ADD_TO_FIELD = MAILBOX_BASE + 2;
|
||||
|
||||
private static final int MESSAGE_BASE = 0x2000;
|
||||
|
@ -214,32 +227,50 @@ public class EmailProvider extends ContentProvider {
|
|||
private static final String[] TABLE_NAMES = {
|
||||
Account.TABLE_NAME,
|
||||
Mailbox.TABLE_NAME,
|
||||
EmailContent.Message.TABLE_NAME,
|
||||
EmailContent.Attachment.TABLE_NAME,
|
||||
Message.TABLE_NAME,
|
||||
Attachment.TABLE_NAME,
|
||||
HostAuth.TABLE_NAME,
|
||||
EmailContent.Message.UPDATED_TABLE_NAME,
|
||||
EmailContent.Message.DELETED_TABLE_NAME,
|
||||
Message.UPDATED_TABLE_NAME,
|
||||
Message.DELETED_TABLE_NAME,
|
||||
Policy.TABLE_NAME,
|
||||
QuickResponse.TABLE_NAME,
|
||||
EmailContent.Body.TABLE_NAME
|
||||
Body.TABLE_NAME
|
||||
};
|
||||
|
||||
// CONTENT_CACHES MUST remain in the order of the BASE constants above
|
||||
private static final ContentCache[] CONTENT_CACHES = {
|
||||
sCacheAccount,
|
||||
sCacheMailbox,
|
||||
sCacheMessage,
|
||||
private final ContentCache[] mContentCaches = {
|
||||
mCacheAccount,
|
||||
mCacheMailbox,
|
||||
mCacheMessage,
|
||||
null, // Attachment
|
||||
sCacheHostAuth,
|
||||
mCacheHostAuth,
|
||||
null, // Updated message
|
||||
null, // Deleted message
|
||||
sCachePolicy,
|
||||
mCachePolicy,
|
||||
null, // Quick response
|
||||
null // Body
|
||||
};
|
||||
|
||||
// CACHE_PROJECTIONS MUST remain in the order of the BASE constants above
|
||||
private static final String[][] CACHE_PROJECTIONS = {
|
||||
Account.CONTENT_PROJECTION,
|
||||
Mailbox.CONTENT_PROJECTION,
|
||||
Message.CONTENT_PROJECTION,
|
||||
null, // Attachment
|
||||
HostAuth.CONTENT_PROJECTION,
|
||||
null, // Updated message
|
||||
null, // Deleted message
|
||||
Policy.CONTENT_PROJECTION,
|
||||
null, // Quick response
|
||||
null // Body
|
||||
};
|
||||
|
||||
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
|
||||
|
||||
private static final String MAILBOX_PRE_CACHE_SELECTION = MailboxColumns.TYPE + " IN (" +
|
||||
Mailbox.TYPE_INBOX + "," + Mailbox.TYPE_DRAFTS + "," + Mailbox.TYPE_TRASH + "," +
|
||||
Mailbox.TYPE_SENT + "," + Mailbox.TYPE_SEARCH + "," + Mailbox.TYPE_OUTBOX + ")";
|
||||
|
||||
/**
|
||||
* Let's only generate these SQL strings once, as they are used frequently
|
||||
* Note that this isn't relevant for table creation strings, since they are used only once
|
||||
|
@ -301,6 +332,7 @@ public class EmailProvider extends ContentProvider {
|
|||
// A specific account
|
||||
// insert into this URI causes a mailbox to be added to the account
|
||||
matcher.addURI(EmailContent.AUTHORITY, "account/#", ACCOUNT_ID);
|
||||
matcher.addURI(EmailContent.AUTHORITY, "account/default", ACCOUNT_DEFAULT_ID);
|
||||
|
||||
// Special URI to reset the new message count. Only update works, and content values
|
||||
// will be ignored.
|
||||
|
@ -315,7 +347,8 @@ public class EmailProvider extends ContentProvider {
|
|||
// insert into this URI causes a message to be added to the mailbox
|
||||
// ** NOTE For now, the accountKey must be set manually in the values!
|
||||
matcher.addURI(EmailContent.AUTHORITY, "mailbox/#", MAILBOX_ID);
|
||||
|
||||
matcher.addURI(EmailContent.AUTHORITY, "mailboxIdFromAccountAndType/#/#",
|
||||
MAILBOX_ID_FROM_ACCOUNT_AND_TYPE);
|
||||
// All messages
|
||||
matcher.addURI(EmailContent.AUTHORITY, "message", MESSAGE);
|
||||
// A specific message
|
||||
|
@ -383,7 +416,6 @@ public class EmailProvider extends ContentProvider {
|
|||
QUICK_RESPONSE_ACCOUNT_ID);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrap the UriMatcher call so we can throw a runtime exception if an unknown Uri is passed in
|
||||
* @param uri the Uri to match
|
||||
|
@ -778,10 +810,80 @@ public class EmailProvider extends ContentProvider {
|
|||
// Check for any orphaned Messages in the updated/deleted tables
|
||||
deleteOrphans(mDatabase, Message.UPDATED_TABLE_NAME);
|
||||
deleteOrphans(mDatabase, Message.DELETED_TABLE_NAME);
|
||||
|
||||
if (Email.DEBUG) {
|
||||
Log.d(TAG, "EmailProvider pre-caching...");
|
||||
}
|
||||
preCacheData();
|
||||
if (Email.DEBUG) {
|
||||
Log.d(TAG, "Pre-caching finished.");
|
||||
}
|
||||
return mDatabase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-cache all of the items in a given table meeting the selection criteria
|
||||
* @param tableUri the table uri
|
||||
* @param baseProjection the base projection of that table
|
||||
* @param selection the selection criteria
|
||||
*/
|
||||
private void preCacheTable(Uri tableUri, String[] baseProjection, String selection) {
|
||||
Cursor c = query(tableUri, EmailContent.ID_PROJECTION, selection, null, null);
|
||||
try {
|
||||
while (c.moveToNext()) {
|
||||
long id = c.getLong(EmailContent.ID_PROJECTION_COLUMN);
|
||||
Cursor cachedCursor = query(ContentUris.withAppendedId(
|
||||
tableUri, id), baseProjection, null, null, null);
|
||||
if (cachedCursor != null) {
|
||||
// For accounts, create a mailbox type map entry (if necessary)
|
||||
if (tableUri == Account.CONTENT_URI) {
|
||||
getOrCreateAccountMailboxTypeMap(id);
|
||||
}
|
||||
cachedCursor.close();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
private HashMap<Long, HashMap<Integer, Long>> mMailboxTypeMap =
|
||||
new HashMap<Long, HashMap<Integer, Long>>();
|
||||
|
||||
private synchronized HashMap<Integer, Long> getOrCreateAccountMailboxTypeMap(long accountId) {
|
||||
HashMap<Integer, Long> accountMailboxTypeMap = mMailboxTypeMap.get(accountId);
|
||||
if (accountMailboxTypeMap == null) {
|
||||
accountMailboxTypeMap = new HashMap<Integer, Long>();
|
||||
mMailboxTypeMap.put(accountId, accountMailboxTypeMap);
|
||||
}
|
||||
return accountMailboxTypeMap;
|
||||
}
|
||||
|
||||
private synchronized void addToMailboxTypeMap(Cursor c) {
|
||||
long accountId = c.getLong(Mailbox.CONTENT_ACCOUNT_KEY_COLUMN);
|
||||
int type = c.getInt(Mailbox.CONTENT_TYPE_COLUMN);
|
||||
HashMap<Integer, Long> accountMailboxTypeMap = getOrCreateAccountMailboxTypeMap(accountId);
|
||||
accountMailboxTypeMap.put(type, c.getLong(Mailbox.CONTENT_ID_COLUMN));
|
||||
}
|
||||
|
||||
private void preCacheData() {
|
||||
mMailboxTypeMap.clear();
|
||||
|
||||
// Pre-cache accounts, host auth's, policies, and special mailboxes
|
||||
preCacheTable(Account.CONTENT_URI, Account.CONTENT_PROJECTION, null);
|
||||
preCacheTable(HostAuth.CONTENT_URI, HostAuth.CONTENT_PROJECTION, null);
|
||||
preCacheTable(Policy.CONTENT_URI, Policy.CONTENT_PROJECTION, null);
|
||||
preCacheTable(Mailbox.CONTENT_URI, Mailbox.CONTENT_PROJECTION, MAILBOX_PRE_CACHE_SELECTION);
|
||||
|
||||
// Create a map from account,type to a mailbox
|
||||
Map<String, Cursor> snapshot = mCacheMailbox.getSnapshot();
|
||||
Collection<Cursor> values = snapshot.values();
|
||||
if (values != null) {
|
||||
for (Cursor c: values) {
|
||||
addToMailboxTypeMap(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ static SQLiteDatabase getReadableDatabase(Context context) {
|
||||
DatabaseHelper helper = new DatabaseHelper(context, DATABASE_NAME);
|
||||
return helper.getReadableDatabase();
|
||||
|
@ -1175,7 +1277,7 @@ public class EmailProvider extends ContentProvider {
|
|||
boolean messageDeletion = false;
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
|
||||
ContentCache cache = CONTENT_CACHES[table];
|
||||
ContentCache cache = mContentCaches[table];
|
||||
String tableName = TABLE_NAMES[table];
|
||||
int result = -1;
|
||||
|
||||
|
@ -1231,17 +1333,23 @@ public class EmailProvider extends ContentProvider {
|
|||
case ACCOUNT_ID:
|
||||
// Account deletion will clear all of the caches, as HostAuth's,
|
||||
// Mailboxes, and Messages will be deleted in the process
|
||||
sCacheMailbox.invalidate("Delete", uri, selection);
|
||||
sCacheHostAuth.invalidate("Delete", uri, selection);
|
||||
mCacheMailbox.invalidate("Delete", uri, selection);
|
||||
mCacheHostAuth.invalidate("Delete", uri, selection);
|
||||
mCachePolicy.invalidate("Delete", uri, selection);
|
||||
//$FALL-THROUGH$
|
||||
case MAILBOX_ID:
|
||||
// Mailbox deletion will clear the Message cache
|
||||
sCacheMessage.invalidate("Delete", uri, selection);
|
||||
mCacheMessage.invalidate("Delete", uri, selection);
|
||||
//$FALL-THROUGH$
|
||||
case SYNCED_MESSAGE_ID:
|
||||
case MESSAGE_ID:
|
||||
case HOSTAUTH_ID:
|
||||
case POLICY_ID:
|
||||
cache.invalidate("Delete", uri, selection);
|
||||
// Make sure all data is properly cached
|
||||
if (match != MESSAGE_ID) {
|
||||
preCacheData();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1270,18 +1378,29 @@ public class EmailProvider extends ContentProvider {
|
|||
switch(match) {
|
||||
// See the comments above for deletion of ACCOUNT_ID, etc
|
||||
case ACCOUNT:
|
||||
sCacheMailbox.invalidate("Delete", uri, selection);
|
||||
sCacheHostAuth.invalidate("Delete", uri, selection);
|
||||
mCacheMailbox.invalidate("Delete", uri, selection);
|
||||
mCacheHostAuth.invalidate("Delete", uri, selection);
|
||||
mCachePolicy.invalidate("Delete", uri, selection);
|
||||
//$FALL-THROUGH$
|
||||
case MAILBOX:
|
||||
sCacheMessage.invalidate("Delete", uri, selection);
|
||||
mCacheMessage.invalidate("Delete", uri, selection);
|
||||
//$FALL-THROUGH$
|
||||
case MESSAGE:
|
||||
case HOSTAUTH:
|
||||
case POLICY:
|
||||
cache.invalidate("Delete", uri, selection);
|
||||
break;
|
||||
}
|
||||
result = db.delete(tableName, selection, selectionArgs);
|
||||
switch(match) {
|
||||
case ACCOUNT:
|
||||
case MAILBOX:
|
||||
case HOSTAUTH:
|
||||
case POLICY:
|
||||
// Make sure all data is properly cached
|
||||
preCacheData();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1384,9 +1503,11 @@ public class EmailProvider extends ContentProvider {
|
|||
|
||||
try {
|
||||
switch (match) {
|
||||
case MESSAGE:
|
||||
// NOTE: It is NOT legal for production code to insert directly into UPDATED_MESSAGE
|
||||
// or DELETED_MESSAGE; see the comment below for details
|
||||
case UPDATED_MESSAGE:
|
||||
case DELETED_MESSAGE:
|
||||
case MESSAGE:
|
||||
case BODY:
|
||||
case ATTACHMENT:
|
||||
case MAILBOX:
|
||||
|
@ -1396,6 +1517,33 @@ public class EmailProvider extends ContentProvider {
|
|||
case QUICK_RESPONSE:
|
||||
longId = db.insert(TABLE_NAMES[table], "foo", values);
|
||||
resultUri = ContentUris.withAppendedId(uri, longId);
|
||||
switch(match) {
|
||||
case MAILBOX:
|
||||
if (values.containsKey(MailboxColumns.TYPE)) {
|
||||
// Only cache special mailbox types
|
||||
int type = values.getAsInteger(MailboxColumns.TYPE);
|
||||
if (type != Mailbox.TYPE_INBOX && type != Mailbox.TYPE_OUTBOX &&
|
||||
type != Mailbox.TYPE_DRAFTS && type != Mailbox.TYPE_SENT &&
|
||||
type != Mailbox.TYPE_TRASH && type != Mailbox.TYPE_SEARCH) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//$FALL-THROUGH$
|
||||
case ACCOUNT:
|
||||
case HOSTAUTH:
|
||||
case POLICY:
|
||||
// Cache new account, host auth, policy, and some mailbox rows
|
||||
Cursor c = query(resultUri, CACHE_PROJECTIONS[table], null, null, null);
|
||||
if (c != null) {
|
||||
if (match == MAILBOX) {
|
||||
addToMailboxTypeMap(c);
|
||||
} else if (match == ACCOUNT) {
|
||||
getOrCreateAccountMailboxTypeMap(longId);
|
||||
}
|
||||
c.close();
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Clients shouldn't normally be adding rows to these tables, as they are
|
||||
// maintained by triggers. However, we need to be able to do this for unit
|
||||
// testing, so we allow the insert and then throw the same exception that we
|
||||
|
@ -1529,7 +1677,7 @@ public class EmailProvider extends ContentProvider {
|
|||
String tableName = TABLE_NAMES[table];
|
||||
// We can only use the cache if there's no selection
|
||||
if (selection == null) {
|
||||
cache = CONTENT_CACHES[table];
|
||||
cache = mContentCaches[table];
|
||||
}
|
||||
if (cache == null) {
|
||||
ContentCache.notCacheable(uri, selection);
|
||||
|
@ -1537,6 +1685,37 @@ public class EmailProvider extends ContentProvider {
|
|||
|
||||
try {
|
||||
switch (match) {
|
||||
case ACCOUNT_DEFAULT_ID:
|
||||
// Start with a snapshot of the cache
|
||||
Map<String, Cursor> accountCache = mCacheAccount.getSnapshot();
|
||||
long accountId = Account.NO_ACCOUNT;
|
||||
// Find the account with "isDefault" set
|
||||
Collection<Cursor> accounts = accountCache.values();
|
||||
int numAccounts = accounts.size();
|
||||
for (Cursor accountCursor: accounts) {
|
||||
if (accountCursor.getInt(Account.CONTENT_IS_DEFAULT_COLUMN) == 1 ||
|
||||
numAccounts == 1) {
|
||||
accountId = accountCursor.getLong(Account.CONTENT_ID_COLUMN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Return a cursor with an id projection
|
||||
MatrixCursor mc = new MatrixCursor(EmailContent.ID_PROJECTION);
|
||||
mc.addRow(new Object[] {accountId});
|
||||
return mc;
|
||||
case MAILBOX_ID_FROM_ACCOUNT_AND_TYPE:
|
||||
// Get accountId and type and find the mailbox in our map
|
||||
accountId = Long.parseLong(uri.getPathSegments().get(1));
|
||||
int type = Integer.parseInt(uri.getPathSegments().get(2));
|
||||
HashMap<Integer, Long> accountMap = mMailboxTypeMap.get(accountId);
|
||||
mc = new MatrixCursor(EmailContent.ID_PROJECTION);
|
||||
Long mailboxId = null;
|
||||
if (accountMap != null) {
|
||||
mailboxId = accountMap.get(type);
|
||||
}
|
||||
// Return a cursor with an id projection
|
||||
mc.addRow(new Object[] {mailboxId});
|
||||
return mc;
|
||||
case BODY:
|
||||
case MESSAGE:
|
||||
case UPDATED_MESSAGE:
|
||||
|
@ -1547,6 +1726,17 @@ public class EmailProvider extends ContentProvider {
|
|||
case HOSTAUTH:
|
||||
case POLICY:
|
||||
case QUICK_RESPONSE:
|
||||
// Special-case "count of accounts"; it's common and we always know it
|
||||
if (match == ACCOUNT && Arrays.equals(projection, EmailContent.COUNT_COLUMNS) &&
|
||||
selection == null && limit.equals("1")) {
|
||||
int accountCount = mMailboxTypeMap.size();
|
||||
// In the rare case there are MAX_CACHED_ACCOUNTS or more, we can't do this
|
||||
if (accountCount < MAX_CACHED_ACCOUNTS) {
|
||||
mc = new MatrixCursor(projection, 1);
|
||||
mc.addRow(new Object[] {accountCount});
|
||||
return mc;
|
||||
}
|
||||
}
|
||||
c = db.query(tableName, projection,
|
||||
selection, selectionArgs, null, null, sortOrder, limit);
|
||||
break;
|
||||
|
@ -1571,6 +1761,17 @@ public class EmailProvider extends ContentProvider {
|
|||
}
|
||||
c = db.query(tableName, projection, whereWithId(id, selection),
|
||||
selectionArgs, null, null, sortOrder, limit);
|
||||
if (Email.DEBUG) {
|
||||
switch(match) {
|
||||
case ACCOUNT_ID:
|
||||
case HOSTAUTH_ID:
|
||||
case POLICY_ID:
|
||||
case MAILBOX_ID:
|
||||
Log.w(Logging.LOG_TAG,
|
||||
"==== UNCACHED read of " + tableName + ", id = " + id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cache != null) {
|
||||
c = cache.putCursor(c, id, projection, token);
|
||||
}
|
||||
|
@ -1601,7 +1802,7 @@ public class EmailProvider extends ContentProvider {
|
|||
e.printStackTrace();
|
||||
throw e;
|
||||
} finally {
|
||||
if (cache != null && Email.DEBUG) {
|
||||
if (cache != null && c != null && Email.DEBUG) {
|
||||
cache.recordQueryTime(c, System.nanoTime() - time);
|
||||
}
|
||||
}
|
||||
|
@ -1820,11 +2021,12 @@ public class EmailProvider extends ContentProvider {
|
|||
values.remove(MailboxColumns.MESSAGE_COUNT);
|
||||
}
|
||||
|
||||
ContentCache cache = CONTENT_CACHES[table];
|
||||
ContentCache cache = mContentCaches[table];
|
||||
String tableName = TABLE_NAMES[table];
|
||||
String id = "0";
|
||||
|
||||
try {
|
||||
outer:
|
||||
switch (match) {
|
||||
case MAILBOX_ID_ADD_TO_FIELD:
|
||||
case ACCOUNT_ID_ADD_TO_FIELD:
|
||||
|
@ -1876,6 +2078,7 @@ public class EmailProvider extends ContentProvider {
|
|||
case ACCOUNT_ID:
|
||||
case HOSTAUTH_ID:
|
||||
case QUICK_RESPONSE_ID:
|
||||
case POLICY_ID:
|
||||
id = uri.getPathSegments().get(1);
|
||||
if (cache != null) {
|
||||
cache.lock(id);
|
||||
|
@ -1916,18 +2119,41 @@ public class EmailProvider extends ContentProvider {
|
|||
case MAILBOX:
|
||||
case ACCOUNT:
|
||||
case HOSTAUTH:
|
||||
case POLICY:
|
||||
switch(match) {
|
||||
case MESSAGE:
|
||||
// To avoid invalidating the cache on updates, we execute them one at a
|
||||
// time using the XXX_ID uri; these are all executed atomically
|
||||
case ACCOUNT:
|
||||
case MAILBOX:
|
||||
case HOSTAUTH:
|
||||
case POLICY:
|
||||
Cursor c = db.query(tableName, EmailContent.ID_PROJECTION,
|
||||
selection, selectionArgs, null, null, null);
|
||||
db.beginTransaction();
|
||||
result = 0;
|
||||
try {
|
||||
while (c.moveToNext()) {
|
||||
update(ContentUris.withAppendedId(
|
||||
uri, c.getLong(EmailContent.ID_PROJECTION_COLUMN)),
|
||||
values, null, null);
|
||||
result++;
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
c.close();
|
||||
}
|
||||
break outer;
|
||||
// Any cached table other than those above should be invalidated here
|
||||
case MESSAGE:
|
||||
// If we're doing some generic update, the whole cache needs to be
|
||||
// invalidated. This case should be quite rare
|
||||
cache.invalidate("Update", uri, selection);
|
||||
break;
|
||||
//$FALL-THROUGH$
|
||||
default:
|
||||
result = db.update(tableName, values, selection, selectionArgs);
|
||||
break outer;
|
||||
}
|
||||
result = db.update(tableName, values, selection, selectionArgs);
|
||||
break;
|
||||
case ACCOUNT_RESET_NEW_COUNT_ID:
|
||||
id = uri.getPathSegments().get(1);
|
||||
if (cache != null) {
|
||||
|
@ -2105,6 +2331,7 @@ public class EmailProvider extends ContentProvider {
|
|||
// Shouldn't be needed unless we're debugging and interrupt the process
|
||||
Log.w(TAG, "Exception upgrading EmailProvider.db from 17 to 18 " + e);
|
||||
}
|
||||
ContentCache.invalidateAllCaches();
|
||||
}
|
||||
|
||||
/** Upgrades the database from v20 to v21 */
|
||||
|
@ -2206,4 +2433,20 @@ public class EmailProvider extends ContentProvider {
|
|||
Log.w(TAG, "Exception upgrading EmailProvider.db from 24 to 25 " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing purposes, check whether a given row is cached
|
||||
* @param baseUri the base uri of the EmailContent
|
||||
* @param id the row id of the EmailContent
|
||||
* @return whether or not the row is currently cached
|
||||
*/
|
||||
@VisibleForTesting
|
||||
protected boolean isCached(Uri baseUri, long id) {
|
||||
int match = findMatch(baseUri, "isCached");
|
||||
int table = match >> BASE_SHIFT;
|
||||
ContentCache cache = mContentCaches[table];
|
||||
if (cache == null) return false;
|
||||
Cursor cc = cache.get(Long.toString(id));
|
||||
return (cc != null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ public class ControllerProviderOpsTests extends ProviderTestCase2<EmailProvider>
|
|||
mContext = getContext();
|
||||
mTestController = new TestController(mProviderContext, mContext);
|
||||
// Invalidate all caches, since we reset the database for each test
|
||||
ContentCache.invalidateAllCachesForTest();
|
||||
ContentCache.invalidateAllCaches();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -240,7 +240,7 @@ public final class DBTestHelper {
|
|||
ap.attachInfo(providerContext, null);
|
||||
resolver.addProvider(AttachmentUtilities.AUTHORITY, ap);
|
||||
|
||||
ContentCache.invalidateAllCachesForTest();
|
||||
ContentCache.invalidateAllCaches();
|
||||
|
||||
return providerContext;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class SecurityPolicyTests extends ProviderTestCase2<EmailProvider> {
|
|||
super.setUp();
|
||||
mMockContext = new MockContext2(getMockContext(), mContext);
|
||||
// Invalidate all caches, since we reset the database for each test
|
||||
ContentCache.invalidateAllCachesForTest();
|
||||
ContentCache.invalidateAllCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,6 +16,11 @@
|
|||
|
||||
package com.android.email.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.test.InstrumentationTestCase;
|
||||
import android.test.ProviderTestCase2;
|
||||
import android.test.suitebuilder.annotation.LargeTest;
|
||||
|
||||
import com.android.email.Controller;
|
||||
import com.android.email.DBTestHelper;
|
||||
import com.android.email.Email;
|
||||
|
@ -25,11 +30,6 @@ import com.android.emailcommon.mail.MessagingException;
|
|||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
|
||||
import android.content.Context;
|
||||
import android.test.InstrumentationTestCase;
|
||||
import android.test.ProviderTestCase2;
|
||||
import android.test.suitebuilder.annotation.LargeTest;
|
||||
|
||||
/**
|
||||
* Test case for {@link MailboxFinder}.
|
||||
*
|
||||
|
|
|
@ -16,18 +16,6 @@
|
|||
|
||||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.Email;
|
||||
import com.android.email.EmailAddressValidator;
|
||||
import com.android.email.R;
|
||||
import com.android.email.TestUtils;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.mail.Address;
|
||||
import com.android.emailcommon.mail.MessagingException;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -41,6 +29,18 @@ import android.view.View;
|
|||
import android.widget.EditText;
|
||||
import android.widget.MultiAutoCompleteTextView;
|
||||
|
||||
import com.android.email.Email;
|
||||
import com.android.email.EmailAddressValidator;
|
||||
import com.android.email.R;
|
||||
import com.android.email.TestUtils;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.mail.Address;
|
||||
import com.android.emailcommon.mail.MessagingException;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
|
||||
package com.android.email.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import com.android.email.DBTestHelper;
|
||||
import com.android.email.MockClock;
|
||||
import com.android.email.provider.ContentCache;
|
||||
import com.android.email.provider.ProviderTestUtils;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
|
||||
import android.content.Context;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
|
@ -64,6 +64,8 @@ public class RecentMailboxManagerTest extends AndroidTestCase {
|
|||
ProviderTestUtils.setupMailbox("laurel", 1L, true, mMockContext, Mailbox.TYPE_MAIL),
|
||||
ProviderTestUtils.setupMailbox("hardy", 1L, true, mMockContext, Mailbox.TYPE_MAIL),
|
||||
};
|
||||
// Invalidate all caches, since we reset the database for each test
|
||||
ContentCache.invalidateAllCaches();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -55,7 +55,7 @@ public class PolicyTests extends ProviderTestCase2<EmailProvider> {
|
|||
super.setUp();
|
||||
mMockContext = getMockContext();
|
||||
// Invalidate all caches, since we reset the database for each test
|
||||
ContentCache.invalidateAllCachesForTest();
|
||||
ContentCache.invalidateAllCaches();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,23 +16,6 @@
|
|||
|
||||
package com.android.email.provider;
|
||||
|
||||
import com.android.emailcommon.AccountManagerTypes;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.AccountColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
import com.android.emailcommon.provider.EmailContent.AttachmentColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Body;
|
||||
import com.android.emailcommon.provider.EmailContent.BodyColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
import com.android.emailcommon.utility.AccountReconciler;
|
||||
import com.android.emailcommon.utility.TextUtilities;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.AuthenticatorException;
|
||||
import android.accounts.OperationCanceledException;
|
||||
|
@ -49,6 +32,24 @@ import android.os.Parcel;
|
|||
import android.test.MoreAsserts;
|
||||
import android.test.ProviderTestCase2;
|
||||
|
||||
import com.android.emailcommon.AccountManagerTypes;
|
||||
import com.android.emailcommon.provider.Account;
|
||||
import com.android.emailcommon.provider.EmailContent;
|
||||
import com.android.emailcommon.provider.EmailContent.AccountColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Attachment;
|
||||
import com.android.emailcommon.provider.EmailContent.AttachmentColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Body;
|
||||
import com.android.emailcommon.provider.EmailContent.BodyColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.MailboxColumns;
|
||||
import com.android.emailcommon.provider.EmailContent.Message;
|
||||
import com.android.emailcommon.provider.EmailContent.MessageColumns;
|
||||
import com.android.emailcommon.provider.HostAuth;
|
||||
import com.android.emailcommon.provider.Mailbox;
|
||||
import com.android.emailcommon.provider.Policy;
|
||||
import com.android.emailcommon.utility.AccountReconciler;
|
||||
import com.android.emailcommon.utility.TextUtilities;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -81,7 +82,7 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
|||
mMockContext = getMockContext();
|
||||
mProvider = getProvider();
|
||||
// Invalidate all caches, since we reset the database for each test
|
||||
ContentCache.invalidateAllCachesForTest();
|
||||
ContentCache.invalidateAllCaches();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1737,9 +1738,11 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
|||
public void testClearAccountHoldFlags() {
|
||||
Account a1 = ProviderTestUtils.setupAccount("holdflag-1", false, mMockContext);
|
||||
a1.mFlags = Account.FLAGS_NOTIFY_NEW_MAIL;
|
||||
a1.mPolicy = new Policy();
|
||||
a1.save(mMockContext);
|
||||
Account a2 = ProviderTestUtils.setupAccount("holdflag-2", false, mMockContext);
|
||||
a2.mFlags = Account.FLAGS_VIBRATE_ALWAYS | Account.FLAGS_SECURITY_HOLD;
|
||||
a2.mPolicy = new Policy();
|
||||
a2.save(mMockContext);
|
||||
|
||||
// bulk clear
|
||||
|
@ -2120,7 +2123,7 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
|||
public void testUpgradeFromVersion17ToVersion18() {
|
||||
final Context c = mMockContext;
|
||||
// Create accounts
|
||||
Account a1 =createAccount(c, "exchange",
|
||||
Account a1 = createAccount(c, "exchange",
|
||||
ProviderTestUtils.setupHostAuth("eas", "exchange.host.com", true, c),
|
||||
null);
|
||||
Account a2 = createAccount(c, "imap",
|
||||
|
@ -2255,6 +2258,109 @@ public class ProviderTests extends ProviderTestCase2<EmailProvider> {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void testAutoCacheNewContent() {
|
||||
Account account = ProviderTestUtils.setupAccount("account-hostauth", false, mMockContext);
|
||||
// add hostauth data, which should be saved the first time
|
||||
account.mHostAuthRecv = ProviderTestUtils.setupHostAuth("account-hostauth-recv", -1, false,
|
||||
mMockContext);
|
||||
account.mHostAuthSend = ProviderTestUtils.setupHostAuth("account-hostauth-send", -1, false,
|
||||
mMockContext);
|
||||
account.save(mMockContext);
|
||||
assertTrue(mProvider.isCached(Account.CONTENT_URI, account.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, account.mHostAuthRecv.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, account.mHostAuthSend.mId));
|
||||
}
|
||||
|
||||
/** Creates a mailbox; redefine as we need version 17 mailbox values */
|
||||
private Mailbox createTypeMailbox(Context c, long accountId, int type) {
|
||||
Mailbox box = new Mailbox();
|
||||
|
||||
box.mDisplayName = "foo";
|
||||
box.mServerId = "1:1";
|
||||
box.mParentKey = 0;
|
||||
box.mAccountKey = accountId;
|
||||
// Don't care about the fields below ... set them for giggles
|
||||
box.mType = type;
|
||||
box.save(c);
|
||||
return box;
|
||||
}
|
||||
|
||||
public void testAutoCacheInvalidate() {
|
||||
// Create 3 accounts with hostauth and 3 mailboxes each (2 of which are pre-cached)
|
||||
Account a = ProviderTestUtils.setupAccount("account1", false, mMockContext);
|
||||
a.mHostAuthRecv = ProviderTestUtils.setupHostAuth("account-recv", -1, false,
|
||||
mMockContext);
|
||||
a.mHostAuthSend = ProviderTestUtils.setupHostAuth("account-send", -1, false,
|
||||
mMockContext);
|
||||
a.save(mMockContext);
|
||||
Mailbox a1 = createTypeMailbox(mMockContext, a.mId, Mailbox.TYPE_INBOX);
|
||||
Mailbox a2 = createTypeMailbox(mMockContext, a.mId, Mailbox.TYPE_MAIL);
|
||||
Mailbox a3 = createTypeMailbox(mMockContext, a.mId, Mailbox.TYPE_DRAFTS);
|
||||
Account b = ProviderTestUtils.setupAccount("account2", false, mMockContext);
|
||||
b.mHostAuthRecv = ProviderTestUtils.setupHostAuth("account-recv", -1, false,
|
||||
mMockContext);
|
||||
b.mHostAuthSend = ProviderTestUtils.setupHostAuth("accoun-send", -1, false,
|
||||
mMockContext);
|
||||
b.save(mMockContext);
|
||||
Mailbox b1 = createTypeMailbox(mMockContext, b.mId, Mailbox.TYPE_OUTBOX);
|
||||
Mailbox b2 = createTypeMailbox(mMockContext, b.mId, Mailbox.TYPE_MAIL);
|
||||
Mailbox b3 = createTypeMailbox(mMockContext, b.mId, Mailbox.TYPE_SENT);
|
||||
Account c = ProviderTestUtils.setupAccount("account3", false, mMockContext);
|
||||
c.mHostAuthRecv = ProviderTestUtils.setupHostAuth("account-recv", -1, false,
|
||||
mMockContext);
|
||||
c.mHostAuthSend = ProviderTestUtils.setupHostAuth("account-send", -1, false,
|
||||
mMockContext);
|
||||
c.save(mMockContext);
|
||||
Mailbox c1 = createTypeMailbox(mMockContext, c.mId, Mailbox.TYPE_SEARCH);
|
||||
Mailbox c2 = createTypeMailbox(mMockContext, c.mId, Mailbox.TYPE_MAIL);
|
||||
Mailbox c3 = createTypeMailbox(mMockContext, c.mId, Mailbox.TYPE_TRASH);
|
||||
|
||||
// Confirm expected cache state
|
||||
assertTrue(mProvider.isCached(Account.CONTENT_URI, a.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, a.mHostAuthRecv.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, a.mHostAuthSend.mId));
|
||||
assertTrue(mProvider.isCached(Account.CONTENT_URI, b.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, b.mHostAuthRecv.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, b.mHostAuthSend.mId));
|
||||
assertTrue(mProvider.isCached(Account.CONTENT_URI, c.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, c.mHostAuthRecv.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, c.mHostAuthSend.mId));
|
||||
|
||||
assertTrue(mProvider.isCached(Mailbox.CONTENT_URI, a1.mId));
|
||||
assertFalse(mProvider.isCached(Mailbox.CONTENT_URI, a2.mId));
|
||||
assertTrue(mProvider.isCached(Mailbox.CONTENT_URI, a3.mId));
|
||||
assertTrue(mProvider.isCached(Mailbox.CONTENT_URI, b1.mId));
|
||||
assertFalse(mProvider.isCached(Mailbox.CONTENT_URI, b2.mId));
|
||||
assertTrue(mProvider.isCached(Mailbox.CONTENT_URI, b3.mId));
|
||||
assertTrue(mProvider.isCached(Mailbox.CONTENT_URI, c1.mId));
|
||||
assertFalse(mProvider.isCached(Mailbox.CONTENT_URI, c2.mId));
|
||||
assertTrue(mProvider.isCached(Mailbox.CONTENT_URI, c3.mId));
|
||||
|
||||
// Delete account b
|
||||
EmailContent.delete(mMockContext, Account.CONTENT_URI, b.mId);
|
||||
|
||||
// Confirm cache state
|
||||
assertTrue(mProvider.isCached(Account.CONTENT_URI, a.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, a.mHostAuthRecv.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, a.mHostAuthSend.mId));
|
||||
assertFalse(mProvider.isCached(Account.CONTENT_URI, b.mId));
|
||||
assertFalse(mProvider.isCached(HostAuth.CONTENT_URI, b.mHostAuthRecv.mId));
|
||||
assertFalse(mProvider.isCached(HostAuth.CONTENT_URI, b.mHostAuthSend.mId));
|
||||
assertTrue(mProvider.isCached(Account.CONTENT_URI, c.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, c.mHostAuthRecv.mId));
|
||||
assertTrue(mProvider.isCached(HostAuth.CONTENT_URI, c.mHostAuthSend.mId));
|
||||
|
||||
assertTrue(mProvider.isCached(Mailbox.CONTENT_URI, a1.mId));
|
||||
assertFalse(mProvider.isCached(Mailbox.CONTENT_URI, a2.mId));
|
||||
assertTrue(mProvider.isCached(Mailbox.CONTENT_URI, a3.mId));
|
||||
assertFalse(mProvider.isCached(Mailbox.CONTENT_URI, b1.mId));
|
||||
assertFalse(mProvider.isCached(Mailbox.CONTENT_URI, b2.mId));
|
||||
assertFalse(mProvider.isCached(Mailbox.CONTENT_URI, b3.mId));
|
||||
assertTrue(mProvider.isCached(Mailbox.CONTENT_URI, c1.mId));
|
||||
assertFalse(mProvider.isCached(Mailbox.CONTENT_URI, c2.mId));
|
||||
assertTrue(mProvider.isCached(Mailbox.CONTENT_URI, c3.mId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a single pop/imap account from the AccountManager
|
||||
* @param accountManager our AccountManager
|
||||
|
|
|
@ -60,7 +60,7 @@ public class MailboxTests extends ProviderTestCase2<EmailProvider> {
|
|||
mMockContext = getMockContext();
|
||||
mProvider = getProvider();
|
||||
// Invalidate all caches, since we reset the database for each test
|
||||
ContentCache.invalidateAllCachesForTest();
|
||||
ContentCache.invalidateAllCaches();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
|
|
|
@ -16,23 +16,13 @@
|
|||
|
||||
package com.android.emailcommon.provider;
|
||||
|
||||
import com.android.email.provider.ContentCache;
|
||||
import com.android.email.provider.EmailProvider;
|
||||
import com.android.email.provider.ProviderTestUtils;
|
||||
import com.android.emailcommon.provider.QuickResponse;
|
||||
import com.android.emailcommon.utility.Utility;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.test.MoreAsserts;
|
||||
import android.test.ProviderTestCase2;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Arrays;
|
||||
import com.android.email.provider.ContentCache;
|
||||
import com.android.email.provider.EmailProvider;
|
||||
|
||||
/**
|
||||
* Unit tests for the QuickResponse class
|
||||
|
@ -52,7 +42,7 @@ public class QuickResponseTests extends ProviderTestCase2<EmailProvider> {
|
|||
mMockContext = getMockContext();
|
||||
mProvider = getProvider();
|
||||
// Invalidate all caches, since we reset the database for each test
|
||||
ContentCache.invalidateAllCachesForTest();
|
||||
ContentCache.invalidateAllCaches();
|
||||
}
|
||||
|
||||
public void testParcelling() {
|
||||
|
|
Loading…
Reference in New Issue