diff --git a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java index e0503adbc..f3bb793f7 100644 --- a/emailcommon/src/com/android/emailcommon/provider/EmailContent.java +++ b/emailcommon/src/com/android/emailcommon/provider/EmailContent.java @@ -16,6 +16,7 @@ package com.android.emailcommon.provider; +import com.android.emailcommon.Logging; import com.android.emailcommon.utility.TextUtilities; import com.android.emailcommon.utility.Utility; @@ -33,6 +34,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.text.TextUtils; +import android.util.Log; import java.io.File; import java.net.URI; @@ -2250,6 +2252,10 @@ public abstract class EmailContent { MailboxColumns.TYPE + " =?"; private static final String MAILBOX_TYPE_SELECTION = MailboxColumns.TYPE + " =?"; + /** Selection by display name for a given account */ + private static final String NAME_AND_ACCOUNT_SELECTION = + MailboxColumns.DISPLAY_NAME + "=? and " + MailboxColumns.ACCOUNT_KEY + "=?"; + private static final String[] MAILBOX_SUM_OF_UNREAD_COUNT_PROJECTION = new String [] { "sum(" + MailboxColumns.UNREAD_COUNT + ")" }; @@ -2387,6 +2393,38 @@ public abstract class EmailContent { } } + /** + * Returns a Mailbox from the database, given its pathname and account id. All mailbox + * paths for a particular account must be unique. + * @param context + * @param accountId the ID of the account + * @param path the fully qualified, remote pathname + */ + public static Mailbox restoreMailboxForPath(Context context, long accountId, String path) { + Cursor c = context.getContentResolver().query( + Mailbox.CONTENT_URI, + Mailbox.CONTENT_PROJECTION, + Mailbox.NAME_AND_ACCOUNT_SELECTION, + new String[] { path, Long.toString(accountId) }, + null); +// TODO for mblank; uncomment when you submit CL Iab059f9a68eecd797914a6229f1ff9c03d0f0800 +// if (c == null) throw new ProviderUnavailableException(); + try { + Mailbox mailbox = null; + if (c.moveToFirst()) { + mailbox = getContent(c, Mailbox.class); + if (c.moveToNext()) { + Log.w(Logging.LOG_TAG, "Multiple mailboxes named \"" + path + "\""); + } + } else { + Log.i(Logging.LOG_TAG, "Could not find mailbox at \"" + path + "\""); + } + return mailbox; + } finally { + c.close(); + } + } + @Override public void restore(Cursor cursor) { mBaseUri = CONTENT_URI; diff --git a/src/com/android/email/MessagingController.java b/src/com/android/email/MessagingController.java index 5bd0c7542..a52e1a681 100644 --- a/src/com/android/email/MessagingController.java +++ b/src/com/android/email/MessagingController.java @@ -36,6 +36,7 @@ import com.android.emailcommon.mail.Message; import com.android.emailcommon.mail.MessagingException; import com.android.emailcommon.mail.Part; import com.android.emailcommon.provider.EmailContent; +import com.android.emailcommon.provider.EmailContent.Account; import com.android.emailcommon.provider.EmailContent.Attachment; import com.android.emailcommon.provider.EmailContent.AttachmentColumns; import com.android.emailcommon.provider.EmailContent.Mailbox; @@ -197,38 +198,23 @@ public class MessagingController implements Runnable { return mListeners.isActiveListener(listener); } - /** - * Lightweight class for capturing local mailboxes in an account. Just the columns - * necessary for a sync. - */ - private static class LocalMailboxInfo { - private static final int COLUMN_ID = 0; - private static final int COLUMN_DISPLAY_NAME = 1; - private static final int COLUMN_ACCOUNT_KEY = 2; - private static final int COLUMN_TYPE = 3; + private static final int MAILBOX_COLUMN_ID = 0; + private static final int MAILBOX_COLUMN_DISPLAY_NAME = 1; + private static final int MAILBOX_COLUMN_TYPE = 2; - private static final String[] PROJECTION = new String[] { - EmailContent.RECORD_ID, - MailboxColumns.DISPLAY_NAME, MailboxColumns.ACCOUNT_KEY, MailboxColumns.TYPE, - }; - - final long mId; - final String mDisplayName; - final long mAccountKey; - final int mType; - - public LocalMailboxInfo(Cursor c) { - mId = c.getLong(COLUMN_ID); - mDisplayName = c.getString(COLUMN_DISPLAY_NAME); - mAccountKey = c.getLong(COLUMN_ACCOUNT_KEY); - mType = c.getInt(COLUMN_TYPE); - } - } + /** Small projection for just the columns required for a sync. */ + private static final String[] MAILBOX_PROJECTION = new String[] { + MailboxColumns.ID, + MailboxColumns.DISPLAY_NAME, + MailboxColumns.TYPE, + }; /** - * Asynchronously synchronize the folder list. If the specified {@link MessagingListener} - * is not {@code null}, it must have been previously added to the set of listeners using the - * {@link #addListener(MessagingListener)}. Otherwise, no actions will be performed. + * Synchronize the folder list with the remote server. Synchronization occurs in the + * background and results are passed through the {@link MessagingListener}. If the + * given listener is not {@code null}, it must have been previously added to the set + * of listeners using the {@link #addListener(MessagingListener)}. Otherwise, no + * actions will be performed. * * TODO this needs to cache the remote folder list * TODO break out an inner listFoldersSynchronized which could simplify checkMail @@ -237,101 +223,71 @@ public class MessagingController implements Runnable { * @param listener A listener to notify */ void listFolders(final long accountId, MessagingListener listener) { - final EmailContent.Account account = - EmailContent.Account.restoreAccountWithId(mContext, accountId); + final Account account = Account.restoreAccountWithId(mContext, accountId); if (account == null) { + Log.i(Logging.LOG_TAG, "Could not load account id " + accountId + + ". Has it been removed?"); return; } mListeners.listFoldersStarted(accountId); put("listFolders", listener, new Runnable() { + // TODO For now, mailbox addition occurs in the server-dependent store implementation, + // but, mailbox removal occurs here. Instead, each store should be responsible for + // content synchronization (addition AND removal) since each store will likely need + // to implement it's own, unique synchronization methodology. public void run() { Cursor localFolderCursor = null; try { - // Step 1: Get remote folders, make a list, and add any local folders - // that don't already exist. - + // Step 1: Get remote mailboxes Store store = Store.getInstance(account, mContext, null); - - Folder[] remoteFolders = store.getAllFolders(); - + Folder[] remoteFolders = store.updateFolders(); HashSet remoteFolderNames = new HashSet(); for (int i = 0, count = remoteFolders.length; i < count; i++) { remoteFolderNames.add(remoteFolders[i].getName()); } - HashMap localFolders = - new HashMap(); - HashSet localFolderNames = new HashSet(); + // Step 2: Get local mailboxes localFolderCursor = mContext.getContentResolver().query( EmailContent.Mailbox.CONTENT_URI, - LocalMailboxInfo.PROJECTION, + MAILBOX_PROJECTION, EmailContent.MailboxColumns.ACCOUNT_KEY + "=?", new String[] { String.valueOf(account.mId) }, null); + + // Step 3: Remove any local mailbox not on the remote list while (localFolderCursor.moveToNext()) { - LocalMailboxInfo info = new LocalMailboxInfo(localFolderCursor); - localFolders.put(info.mDisplayName, info); - localFolderNames.add(info.mDisplayName); - } - - // Short circuit the rest if the sets are the same (the usual case) - if (!remoteFolderNames.equals(localFolderNames)) { - - // They are different, so we have to do some adds and drops - - // Drops first, to make things smaller rather than larger - HashSet localsToDrop = new HashSet(localFolderNames); - localsToDrop.removeAll(remoteFolderNames); - for (String localNameToDrop : localsToDrop) { - LocalMailboxInfo localInfo = localFolders.get(localNameToDrop); - // Exclusion list - never delete local special folders, irrespective - // of server-side existence. - switch (localInfo.mType) { - case Mailbox.TYPE_INBOX: - case Mailbox.TYPE_DRAFTS: - case Mailbox.TYPE_OUTBOX: - case Mailbox.TYPE_SENT: - case Mailbox.TYPE_TRASH: - break; - default: - // Drop all attachment files related to this mailbox - AttachmentUtilities.deleteAllMailboxAttachmentFiles( - mContext, accountId, localInfo.mId); - // Delete the mailbox. Triggers will take care of - // related Message, Body and Attachment records. - Uri uri = ContentUris.withAppendedId( - EmailContent.Mailbox.CONTENT_URI, localInfo.mId); - mContext.getContentResolver().delete(uri, null, null); - break; - } + String mailboxPath + = localFolderCursor.getString(MAILBOX_COLUMN_DISPLAY_NAME); + // Short circuit if we have a remote mailbox with the same name + if (remoteFolderNames.contains(mailboxPath)) { + continue; } - // Now do the adds - remoteFolderNames.removeAll(localFolderNames); - for (String remoteNameToAdd : remoteFolderNames) { - EmailContent.Mailbox box = new EmailContent.Mailbox(); - box.mDisplayName = remoteNameToAdd; - // box.mServerId; - // box.mParentServerId; - // box.mParentKey; - box.mAccountKey = account.mId; - box.mType = LegacyConversions.inferMailboxTypeFromName( - mContext, remoteNameToAdd); - // box.mDelimiter; - // box.mSyncKey; - // box.mSyncLookback; - // box.mSyncFrequency; - // box.mSyncTime; - // box.mUnreadCount; - box.mFlagVisible = true; - // box.mFlags; - box.mVisibleLimit = Email.VISIBLE_LIMIT_DEFAULT; - box.save(mContext); + int mailboxType = localFolderCursor.getInt(MAILBOX_COLUMN_TYPE); + long mailboxId = localFolderCursor.getLong(MAILBOX_COLUMN_ID); + switch (mailboxType) { + case Mailbox.TYPE_INBOX: + case Mailbox.TYPE_DRAFTS: + case Mailbox.TYPE_OUTBOX: + case Mailbox.TYPE_SENT: + case Mailbox.TYPE_TRASH: + // Never, ever delete special mailboxes + break; + default: + // Drop all attachment files related to this mailbox + AttachmentUtilities.deleteAllMailboxAttachmentFiles( + mContext, accountId, mailboxId); + // Delete the mailbox; database triggers take care of related + // Message, Body and Attachment records + Uri uri = ContentUris.withAppendedId( + Mailbox.CONTENT_URI, mailboxId); + mContext.getContentResolver().delete(uri, null, null); + break; } } mListeners.listFoldersFinished(accountId); } catch (Exception e) { - mListeners.listFoldersFailed(accountId, ""); + mListeners.listFoldersFailed(accountId, e.toString()); } finally { if (localFolderCursor != null) { localFolderCursor.close(); diff --git a/src/com/android/email/mail/Store.java b/src/com/android/email/mail/Store.java index 9e2829a69..c06a7c04c 100644 --- a/src/com/android/email/mail/Store.java +++ b/src/com/android/email/mail/Store.java @@ -17,13 +17,14 @@ package com.android.email.mail; import com.android.email.Email; +import com.android.email.LegacyConversions; import com.android.email.R; import com.android.emailcommon.Logging; import com.android.emailcommon.mail.Folder; import com.android.emailcommon.mail.MessagingException; import com.android.emailcommon.provider.EmailContent.Account; import com.android.emailcommon.provider.EmailContent.HostAuth; -import com.android.emailcommon.utility.Utility; +import com.android.emailcommon.provider.EmailContent.Mailbox; import com.google.common.annotations.VisibleForTesting; import org.xmlpull.v1.XmlPullParserException; @@ -35,6 +36,7 @@ import android.text.TextUtils; import android.util.Log; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; /** @@ -274,7 +276,14 @@ public abstract class Store { public abstract Folder getFolder(String name) throws MessagingException; - public abstract Folder[] getAllFolders() throws MessagingException; + /** + * Updates the local list of mailboxes according to what is located on the remote server. + * Note: This does not perform folder synchronization and it will not remove mailboxes + * that are stored locally but not remotely. + * @return The set of remote folders + * @throws MessagingException If there was a problem connecting to the remote server + */ + public abstract Folder[] updateFolders() throws MessagingException; public abstract Bundle checkSettings() throws MessagingException; @@ -328,4 +337,59 @@ public abstract class Store { throws MessagingException { return null; } + + /** + * Returns a {@link Mailbox} for the given path. If the path is not in the database, a new + * mailbox will be created. + */ + private static Mailbox getMailboxForPath(Context context, long accountId, String path) { + Mailbox mailbox = Mailbox.restoreMailboxForPath(context, accountId, path); + if (mailbox == null) { + mailbox = new Mailbox(); + } + return mailbox; + } + + /** + * Adds the mailbox with the given path to the folder list and to the database. If the folder + * already exists on the server (e.g. the path is identical), the database row will be updated. + * Otherwise, a new database row will be inserted. + * @param folders the list of folders + * @param mailboxPath The path of the mailbox to add + * @param delimiter A path delimiter. May be {@code null} if there is no delimiter. + */ + protected void addMailbox(Context context, long accountId, String mailboxPath, String delimiter, + ArrayList folders) throws MessagingException { + char delimiterChar = 0; + if (!TextUtils.isEmpty(delimiter)) { + delimiterChar = delimiter.charAt(0); + } + folders.add(getFolder(mailboxPath)); + Mailbox mailbox = getMailboxForPath(context, accountId, mailboxPath); + mailbox.mAccountKey = accountId; + mailbox.mDelimiter = delimiterChar; + mailbox.mDisplayName = mailboxPath; + //mailbox.mFlags; + mailbox.mFlagVisible = true; + //mailbox.mParentKey; + //mailbox.mParentServerId; + mailbox.mServerId = mailboxPath; + //mailbox.mServerId; + //mailbox.mSyncFrequency; + //mailbox.mSyncKey; + //mailbox.mSyncLookback; + //mailbox.mSyncTime; + mailbox.mType = LegacyConversions.inferMailboxTypeFromName(context, mailboxPath); + //box.mUnreadCount; + mailbox.mVisibleLimit = Email.VISIBLE_LIMIT_DEFAULT; + + // TODO This is horribly inefficient. Only update db if the mailbox has really changed + if (mailbox.isSaved()) { + mailbox.update(context, mailbox.toContentValues()); + } else { + mailbox.save(context); + } + // TODO ?? Add mailbox to Folder object ?? + } + } diff --git a/src/com/android/email/mail/store/ExchangeStore.java b/src/com/android/email/mail/store/ExchangeStore.java index f99469f01..55148ded2 100644 --- a/src/com/android/email/mail/store/ExchangeStore.java +++ b/src/com/android/email/mail/store/ExchangeStore.java @@ -80,7 +80,7 @@ public class ExchangeStore extends Store { } @Override - public Folder[] getAllFolders() { + public Folder[] updateFolders() { return null; } diff --git a/src/com/android/email/mail/store/ImapStore.java b/src/com/android/email/mail/store/ImapStore.java index f47c405ad..0c2c68423 100644 --- a/src/com/android/email/mail/store/ImapStore.java +++ b/src/com/android/email/mail/store/ImapStore.java @@ -93,6 +93,7 @@ public class ImapStore extends Store { static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.SEEN, Flag.FLAGGED }; private final Context mContext; + private final Account mAccount; private Transport mRootTransport; private String mUsername; private String mPassword; @@ -140,6 +141,7 @@ public class ImapStore extends Store { */ private ImapStore(Context context, Account account) throws MessagingException { mContext = context; + mAccount = account; HostAuth recvAuth = account.getOrCreateHostAuthRecv(context); if (recvAuth == null || !STORE_SCHEME_IMAP.equalsIgnoreCase(recvAuth.mProtocol)) { @@ -359,7 +361,7 @@ public class ImapStore extends Store { } @Override - public Folder[] getAllFolders() throws MessagingException { + public Folder[] updateFolders() throws MessagingException { ImapConnection connection = getConnection(); try { ArrayList folders = new ArrayList(); @@ -379,8 +381,8 @@ public class ImapStore extends Store { // Get folder name. ImapString encodedFolder = response.getStringOrEmpty(3); if (encodedFolder.isEmpty()) continue; - String folder = decodeFolderName(encodedFolder.getString(), mPathPrefix); - if (ImapConstants.INBOX.equalsIgnoreCase(folder)) { + String folderName = decodeFolderName(encodedFolder.getString(), mPathPrefix); + if (ImapConstants.INBOX.equalsIgnoreCase(folderName)) { continue; } @@ -389,11 +391,12 @@ public class ImapStore extends Store { includeFolder = false; } if (includeFolder) { - folders.add(getFolder(folder)); + String delimiter = response.getStringOrEmpty(2).toString(); + addMailbox(mContext, mAccount.mId, folderName, delimiter, folders); } } } - folders.add(getFolder(ImapConstants.INBOX)); + addMailbox(mContext, mAccount.mId, ImapConstants.INBOX, null, folders); return folders.toArray(new Folder[] {}); } catch (IOException ioe) { connection.close(); diff --git a/src/com/android/email/mail/store/Pop3Store.java b/src/com/android/email/mail/store/Pop3Store.java index 589d1a495..40d8c5eba 100644 --- a/src/com/android/email/mail/store/Pop3Store.java +++ b/src/com/android/email/mail/store/Pop3Store.java @@ -19,6 +19,7 @@ package com.android.email.mail.store; import com.android.email.Email; import com.android.email.mail.Store; import com.android.email.mail.Transport; +import com.android.email.mail.store.imap.ImapConstants; import com.android.email.mail.transport.MailTransport; import com.android.emailcommon.Logging; import com.android.emailcommon.internet.MimeMessage; @@ -53,6 +54,8 @@ public class Pop3Store extends Store { private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED }; + private final Context mContext; + private final Account mAccount; private Transport mTransport; private String mUsername; private String mPassword; @@ -95,6 +98,9 @@ public class Pop3Store extends Store { * Creates a new store for the given account. */ private Pop3Store(Context context, Account account) throws MessagingException { + mContext = context; + mAccount = account; + HostAuth recvAuth = account.getOrCreateHostAuthRecv(context); if (recvAuth == null || !STORE_SCHEME_POP3.equalsIgnoreCase(recvAuth.mProtocol)) { throw new MessagingException("Unsupported protocol"); @@ -148,10 +154,10 @@ public class Pop3Store extends Store { } @Override - public Folder[] getAllFolders() { - return new Folder[] { - getFolder("INBOX"), - }; + public Folder[] updateFolders() throws MessagingException { + ArrayList folders = new ArrayList(); + addMailbox(mContext, mAccount.mId, "INBOX", null, folders); + return folders.toArray(new Folder[] {}); } /** diff --git a/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java b/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java index b291eeaf3..f3afbdc58 100644 --- a/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java +++ b/tests/src/com/android/email/mail/store/ImapStoreUnitTests.java @@ -1212,7 +1212,7 @@ public class ImapStoreUnitTests extends InstrumentationTestCase { "* lIST (\\HAsNoChildren) \"/\" \"&ZeVnLIqe-\"", // Japanese folder name getNextTag(true) + " oK SUCCESS" }); - Folder[] folders = mStore.getAllFolders(); + Folder[] folders = mStore.updateFolders(); ArrayList list = new ArrayList(); for (Folder f : folders) { @@ -2087,7 +2087,7 @@ public class ImapStoreUnitTests extends InstrumentationTestCase { "* LIST () \"/\" \"" + FOLDER_2 + "\"", getNextTag(true) + " OK SUCCESS" }); - final Folder[] folders = mStore.getAllFolders(); + final Folder[] folders = mStore.updateFolders(); ArrayList list = new ArrayList(); for (Folder f : folders) { diff --git a/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java b/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java index e6276fb1a..9461c396f 100644 --- a/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java +++ b/tests/src/com/android/email/mail/store/Pop3StoreUnitTests.java @@ -246,10 +246,10 @@ public class Pop3StoreUnitTests extends InstrumentationTestCase { /** * Test small Store & Folder functions that manage folders & namespace */ - public void testStoreFoldersFunctions() { + public void testStoreFoldersFunctions() throws MessagingException { // getPersonalNamespaces() always returns INBOX folder - Folder[] folders = mStore.getAllFolders(); + Folder[] folders = mStore.updateFolders(); assertEquals(1, folders.length); assertSame(mFolder, folders[0]); @@ -326,8 +326,8 @@ public class Pop3StoreUnitTests extends InstrumentationTestCase { /** * Lightweight test to confirm that POP3 hasn't implemented any folder roles yet. */ - public void testNoFolderRolesYet() { - Folder[] remoteFolders = mStore.getAllFolders(); + public void testNoFolderRolesYet() throws MessagingException { + Folder[] remoteFolders = mStore.updateFolders(); for (Folder folder : remoteFolders) { assertEquals(Folder.FolderRole.UNKNOWN, folder.getRole()); } diff --git a/tests/src/com/android/email/provider/ProviderTestUtils.java b/tests/src/com/android/email/provider/ProviderTestUtils.java index bfc7cc328..ecdffb447 100644 --- a/tests/src/com/android/email/provider/ProviderTestUtils.java +++ b/tests/src/com/android/email/provider/ProviderTestUtils.java @@ -117,9 +117,12 @@ public class ProviderTestUtils extends Assert { Context context) { return setupMailbox(name, accountId, saveIt, context, Mailbox.TYPE_MAIL); } - public static Mailbox setupMailbox(String name, long accountId, boolean saveIt, Context context, int type) { + return setupMailbox(name, accountId, saveIt, context, type, '/'); + } + public static Mailbox setupMailbox(String name, long accountId, boolean saveIt, + Context context, int type, char delimiter) { Mailbox box = new Mailbox(); box.mDisplayName = name; @@ -128,7 +131,7 @@ public class ProviderTestUtils extends Assert { box.mParentKey = 4; box.mAccountKey = accountId; box.mType = type; - box.mDelimiter = 1; + box.mDelimiter = delimiter; box.mSyncKey = "sync-key-" + name; box.mSyncLookback = 2; box.mSyncInterval = EmailContent.Account.CHECK_INTERVAL_NEVER; diff --git a/tests/src/com/android/email/provider/ProviderTests.java b/tests/src/com/android/email/provider/ProviderTests.java index 4b91d7f80..73d1d05b4 100644 --- a/tests/src/com/android/email/provider/ProviderTests.java +++ b/tests/src/com/android/email/provider/ProviderTests.java @@ -2093,22 +2093,55 @@ public class ProviderTests extends ProviderTestCase2 { assertEquals(-1, Account.getAccountIdForMessageId(c, 12345)); } - public void testGetAccountMailboxFromMessageId() { + public void testGetMailboxForMessageId() { final Context c = mMockContext; - Account a = ProviderTestUtils.setupAccount("acct", true, c); - Mailbox b1 = ProviderTestUtils.setupMailbox("box1", a.mId, true, c, Mailbox.TYPE_MAIL); - Mailbox b2 = ProviderTestUtils.setupMailbox("box2", a.mId, true, c, Mailbox.TYPE_MAIL); + Mailbox b1 = ProviderTestUtils.setupMailbox("box1", 1, true, c, Mailbox.TYPE_MAIL); + Mailbox b2 = ProviderTestUtils.setupMailbox("box2", 1, true, c, Mailbox.TYPE_MAIL); Message m1 = createMessage(c, b1, false, false); Message m2 = createMessage(c, b2, false, false); - ProviderTestUtils.assertAccountEqual("x", a, Account.getAccountForMessageId(c, m1.mId)); - ProviderTestUtils.assertAccountEqual("x", a, Account.getAccountForMessageId(c, m2.mId)); - // Restore the mailboxes, since the unread & total counts will have changed - b1 = Mailbox.restoreMailboxWithId(c, b1.mId); - b2 = Mailbox.restoreMailboxWithId(c, b2.mId); ProviderTestUtils.assertMailboxEqual("x", b1, Mailbox.getMailboxForMessageId(c, m1.mId)); ProviderTestUtils.assertMailboxEqual("x", b2, Mailbox.getMailboxForMessageId(c, m2.mId)); } + public void testRestoreMailboxWithId() { + final Context c = mMockContext; + Mailbox testMailbox; + + testMailbox = ProviderTestUtils.setupMailbox("box1", 1, true, c, Mailbox.TYPE_MAIL); + ProviderTestUtils.assertMailboxEqual( + "x", testMailbox, Mailbox.restoreMailboxWithId(c, testMailbox.mId)); + testMailbox = ProviderTestUtils.setupMailbox("box2", 1, true, c, Mailbox.TYPE_MAIL); + ProviderTestUtils.assertMailboxEqual( + "x", testMailbox, Mailbox.restoreMailboxWithId(c, testMailbox.mId)); + // Unknown IDs + assertNull(Mailbox.restoreMailboxWithId(c, 8)); + assertNull(Mailbox.restoreMailboxWithId(c, -1)); + assertNull(Mailbox.restoreMailboxWithId(c, Long.MAX_VALUE)); + } + + public void testRestoreMailboxForPath() { + final Context c = mMockContext; + Mailbox testMailbox; + testMailbox = ProviderTestUtils.setupMailbox("a/b/c/box", 1, true, c, Mailbox.TYPE_MAIL); + ProviderTestUtils.assertMailboxEqual( + "x", testMailbox, Mailbox.restoreMailboxForPath(c, 1, "a/b/c/box")); + // Same name, different account; no match + assertNull(Mailbox.restoreMailboxForPath(c, 2, "a/b/c/box")); + // Substring; no match + assertNull(Mailbox.restoreMailboxForPath(c, 1, "a/b/c")); + // Wild cards not supported; no match + assertNull(Mailbox.restoreMailboxForPath(c, 1, "a/b/c/%")); + } + + public void testGetAccountForMessageId() { + final Context c = mMockContext; + Account a = ProviderTestUtils.setupAccount("acct", true, c); + Message m1 = ProviderTestUtils.setupMessage("1", a.mId, 1, true, true, c, false, false); + Message m2 = ProviderTestUtils.setupMessage("1", a.mId, 2, true, true, c, false, false); + ProviderTestUtils.assertAccountEqual("x", a, Account.getAccountForMessageId(c, m1.mId)); + ProviderTestUtils.assertAccountEqual("x", a, Account.getAccountForMessageId(c, m2.mId)); + } + public void testGetAccountGetInboxIdTest() { final Context c = mMockContext;