diff --git a/src/com/android/email/activity/MessageViewFragmentBase.java b/src/com/android/email/activity/MessageViewFragmentBase.java index d0fe6d44b..c4fc1c059 100644 --- a/src/com/android/email/activity/MessageViewFragmentBase.java +++ b/src/com/android/email/activity/MessageViewFragmentBase.java @@ -1079,7 +1079,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O reloadUiFromMessage(message, mOkToFetch); queryContactStatus(); onMessageShown(mMessageId, mMailboxType); - RecentMailboxManager.getInstance(mContext).touch(message.mMailboxKey); + RecentMailboxManager.getInstance(mContext).touch(mAccountId, message.mMailboxKey); } } diff --git a/src/com/android/email/activity/RecentMailboxManager.java b/src/com/android/email/activity/RecentMailboxManager.java index e7ffd5b28..e9dad78d4 100644 --- a/src/com/android/email/activity/RecentMailboxManager.java +++ b/src/com/android/email/activity/RecentMailboxManager.java @@ -16,18 +16,22 @@ package com.android.email.activity; +import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import com.android.email.Clock; +import com.android.email.Controller; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.MailboxColumns; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.EmailAsyncTask; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Maps; import java.util.ArrayList; +import java.util.HashMap; /** * Manages recent data for mailboxes. @@ -63,14 +67,17 @@ public class RecentMailboxManager { + " AND " + MailboxColumns.LAST_TOUCHED_TIME + ">0 )" + " ORDER BY " + MailboxColumns.LAST_TOUCHED_TIME + " DESC" + " LIMIT ? )"; - private final Context mContext; /** Mailbox types for default "recent mailbox" entries if none exist */ - private static final int[] DEFAULT_RECENT_TYPES = new int[] { + @VisibleForTesting + static final int[] DEFAULT_RECENT_TYPES = new int[] { Mailbox.TYPE_DRAFTS, Mailbox.TYPE_SENT, }; + private final Context mContext; + private final HashMap mDefaultRecentsInitialized; + public static synchronized RecentMailboxManager getInstance(Context context) { if (sInstance == null) { sInstance = new RecentMailboxManager(context); @@ -81,11 +88,12 @@ public class RecentMailboxManager { /** Hide constructor */ private RecentMailboxManager(Context context) { mContext = context; + mDefaultRecentsInitialized = Maps.newHashMap(); } /** Updates the specified mailbox's touch time. Returns an async task for test only. */ - public EmailAsyncTask touch(long mailboxId) { - return fireAndForget(mailboxId, sClock.getTime()); + public EmailAsyncTask touch(long accountId, long mailboxId) { + return fireAndForget(accountId, mailboxId, sClock.getTime()); } /** @@ -98,6 +106,8 @@ public class RecentMailboxManager { * Otherwise, only user defined mailboxes are eligible for the recent list. */ public ArrayList getMostRecent(long accountId, boolean withExclusions) { + ensureDefaultsInitialized(accountId, sClock.getTime()); + String selection = withExclusions ? RECENT_SELECTION_WITH_EXCLUSIONS : RECENT_SELECTION; ArrayList returnList = new ArrayList(); Cursor cursor = mContext.getContentResolver().query(Mailbox.CONTENT_URI, @@ -112,35 +122,47 @@ public class RecentMailboxManager { } finally { cursor.close(); } - if (returnList.size() == 0 && !withExclusions) { - returnList = getDefaultMostRecent(accountId); - } - return returnList; - } - - /** Gets the default recent mailbox list. */ - private ArrayList getDefaultMostRecent(long accountId) { - ArrayList returnList = new ArrayList(); - for (int type : DEFAULT_RECENT_TYPES) { - Mailbox mailbox = Mailbox.restoreMailboxOfType(mContext, accountId, type); - if (mailbox != null) { - returnList.add(mailbox.mId); - } - } return returnList; } /** Updates the last touched time for the mailbox in the background */ - private EmailAsyncTask fireAndForget(final long mailboxId, final long time) { + private EmailAsyncTask fireAndForget( + final long accountId, final long mailboxId, final long time) { return EmailAsyncTask.runAsyncParallel(new Runnable() { @Override public void run() { - ContentValues values = new ContentValues(); - values.put(MailboxColumns.LAST_TOUCHED_TIME, time); - mContext.getContentResolver().update(Mailbox.CONTENT_URI, values, - EmailContent.ID_SELECTION, - new String[] { Long.toString(mailboxId) }); + ensureDefaultsInitialized(accountId, time); + touchMailboxSynchronous(accountId, mailboxId, time); } }); } + + private void touchMailboxSynchronous(long accountId, long mailboxId, long time) { + ContentValues values = new ContentValues(); + values.put(MailboxColumns.LAST_TOUCHED_TIME, time); + mContext.getContentResolver().update( + ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId), + values, null, null); + } + + /** + * Ensures the default recent mailboxes have been set for this account. + */ + private synchronized void ensureDefaultsInitialized(long accountId, long time) { + if (Boolean.TRUE.equals(mDefaultRecentsInitialized.get(accountId))) { + return; + } + + String[] args = new String[] { Long.toString(accountId), Integer.toString(LIMIT_RESULTS) }; + if (EmailContent.count(mContext, Mailbox.CONTENT_URI, RECENT_SELECTION, args) == 0) { + // There are no recent mailboxes at all. Populate with default set. + for (int type : DEFAULT_RECENT_TYPES) { + long mailbox = Controller.getInstance(mContext).findOrCreateMailboxOfType( + accountId, type); + touchMailboxSynchronous(accountId, mailbox, time); + } + } + + mDefaultRecentsInitialized.put(accountId, true); + } } diff --git a/tests/src/com/android/email/activity/RecentMailboxManagerTest.java b/tests/src/com/android/email/activity/RecentMailboxManagerTest.java index adcaacbe6..60ec769d9 100644 --- a/tests/src/com/android/email/activity/RecentMailboxManagerTest.java +++ b/tests/src/com/android/email/activity/RecentMailboxManagerTest.java @@ -19,7 +19,9 @@ package com.android.email.activity; import android.content.ContentValues; import android.content.Context; import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; +import com.android.email.Controller; import com.android.email.DBTestHelper; import com.android.email.MockClock; import com.android.email.provider.ContentCache; @@ -28,6 +30,8 @@ import com.android.emailcommon.provider.EmailContent.MailboxColumns; import com.android.emailcommon.provider.Mailbox; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; /** * Tests for the recent mailbox manager. @@ -35,6 +39,7 @@ import java.util.ArrayList; * You can run this entire test case with: * runtest -c com.android.email.activity.RecentMailboxManagerTest email */ +@MediumTest public class RecentMailboxManagerTest extends AndroidTestCase { private Context mMockContext; @@ -53,6 +58,7 @@ public class RecentMailboxManagerTest extends AndroidTestCase { mMockClock = new MockClock(); RecentMailboxManager.sClock = mMockClock; mManager = RecentMailboxManager.getInstance(mMockContext); + Controller.getInstance(mMockContext).setProviderContext(mMockContext); mMailboxArray = new Mailbox[] { ProviderTestUtils.setupMailbox("inbox", 1L, true, mMockContext, Mailbox.TYPE_INBOX), ProviderTestUtils.setupMailbox("drafts", 1L, true, mMockContext, Mailbox.TYPE_DRAFTS), @@ -77,14 +83,22 @@ public class RecentMailboxManagerTest extends AndroidTestCase { } public void testTouch() throws Exception { + Set defaultRecents = new HashSet() {{ + for (int type : RecentMailboxManager.DEFAULT_RECENT_TYPES) { + add(type); + } + }}; + // Ensure all accounts can be touched for (Mailbox mailbox : mMailboxArray) { // Safety ... default touch time Mailbox untouchedMailbox = Mailbox.restoreMailboxWithId(mMockContext, mailbox.mId); - assertEquals(0L, untouchedMailbox.mLastTouchedTime); + if (!defaultRecents.contains(mailbox.mType)) { + assertEquals(0L, untouchedMailbox.mLastTouchedTime); + } // Touch the mailbox - mManager.touch(mailbox.mId).get(); + mManager.touch(1L, mailbox.mId).get(); // Touch time is actually set Mailbox touchedMailbox = Mailbox.restoreMailboxWithId(mMockContext, mailbox.mId); @@ -123,17 +137,18 @@ public class RecentMailboxManagerTest extends AndroidTestCase { public void testGetMostRecent02() throws Exception { ArrayList testList; // touch some mailboxes - mMockClock.advance(1000L); mManager.touch(mMailboxArray[0].mId); // inbox - mMockClock.advance(1000L); mManager.touch(mMailboxArray[3].mId); // sent + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[0].mId); // inbox + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[3].mId); // sent // need to wait for the last one to ensure getMostRecent() has something to work on - mMockClock.advance(1000L); mManager.touch(mMailboxArray[7].mId).get(); // user mailbox #2 + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[7].mId).get(); // user mailbox 2 - // test recent list not full + // test recent list not full, so is padded with default mailboxes testList = mManager.getMostRecent(1L, false); - assertEquals(3, testList.size()); + assertEquals(4, testList.size()); assertEquals(mMailboxArray[7].mId, (long) testList.get(0)); - assertEquals(mMailboxArray[0].mId, (long) testList.get(1)); - assertEquals(mMailboxArray[3].mId, (long) testList.get(2)); + assertEquals(mMailboxArray[1].mId, (long) testList.get(1)); + assertEquals(mMailboxArray[0].mId, (long) testList.get(2)); + assertEquals(mMailboxArray[3].mId, (long) testList.get(3)); testList = mManager.getMostRecent(1L, true); assertEquals(1, testList.size()); assertEquals(mMailboxArray[7].mId, (long) testList.get(0)); @@ -144,35 +159,37 @@ public class RecentMailboxManagerTest extends AndroidTestCase { ArrayList testList; // touch some more mailboxes - mMockClock.advance(1000L); mManager.touch(mMailboxArray[3].mId); // sent - mMockClock.advance(1000L); mManager.touch(mMailboxArray[4].mId); // trash - mMockClock.advance(1000L); mManager.touch(mMailboxArray[2].mId); // outbox - mMockClock.advance(1000L); mManager.touch(mMailboxArray[8].mId); // user mailbox #3 - mMockClock.advance(1000L); mManager.touch(mMailboxArray[7].mId).get(); // user mailbox #2 + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[3].mId); // sent + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[4].mId); // trash + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[2].mId); // outbox + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[8].mId); // bud_lou + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[7].mId); // costello + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[9].mId).get(); // laurel // test full recent list testList = mManager.getMostRecent(1L, false); assertEquals(5, testList.size()); - assertEquals(mMailboxArray[8].mId, (long) testList.get(0)); - assertEquals(mMailboxArray[7].mId, (long) testList.get(1)); - assertEquals(mMailboxArray[2].mId, (long) testList.get(2)); - assertEquals(mMailboxArray[3].mId, (long) testList.get(3)); - assertEquals(mMailboxArray[4].mId, (long) testList.get(4)); + assertEquals(mMailboxArray[8].mId, (long) testList.get(0)); // bud_lou + assertEquals(mMailboxArray[7].mId, (long) testList.get(1)); // costello + assertEquals(mMailboxArray[9].mId, (long) testList.get(2)); // laurel + assertEquals(mMailboxArray[2].mId, (long) testList.get(3)); // outbox + assertEquals(mMailboxArray[4].mId, (long) testList.get(4)); // trash testList = mManager.getMostRecent(1L, true); - assertEquals(2, testList.size()); + assertEquals(3, testList.size()); assertEquals(mMailboxArray[8].mId, (long) testList.get(0)); assertEquals(mMailboxArray[7].mId, (long) testList.get(1)); + assertEquals(mMailboxArray[9].mId, (long) testList.get(2)); } /** Test limit for system mailboxes */ public void testGetMostRecent04() throws Exception { ArrayList testList; - mMockClock.advance(1000L); mManager.touch(mMailboxArray[0].mId); // inbox - mMockClock.advance(1000L); mManager.touch(mMailboxArray[1].mId); // drafts - mMockClock.advance(1000L); mManager.touch(mMailboxArray[2].mId); // outbox - mMockClock.advance(1000L); mManager.touch(mMailboxArray[3].mId); // sent - mMockClock.advance(1000L); mManager.touch(mMailboxArray[4].mId).get(); // trash + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[0].mId); // inbox + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[1].mId); // drafts + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[2].mId); // outbox + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[3].mId); // sent + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[4].mId).get(); // trash // nothing but system mailboxes testList = mManager.getMostRecent(1L, false); @@ -191,16 +208,16 @@ public class RecentMailboxManagerTest extends AndroidTestCase { ArrayList testList; // test limit for the filtered list - mMockClock.advance(1000L); mManager.touch(mMailboxArray[6].mId); // abbott - mMockClock.advance(1000L); mManager.touch(mMailboxArray[7].mId); // costello - mMockClock.advance(1000L); mManager.touch(mMailboxArray[8].mId); // bud_lou - mMockClock.advance(1000L); mManager.touch(mMailboxArray[9].mId); // laurel - mMockClock.advance(1000L); mManager.touch(mMailboxArray[10].mId); // hardy - mMockClock.advance(1000L); mManager.touch(mMailboxArray[0].mId); // inbox - mMockClock.advance(1000L); mManager.touch(mMailboxArray[1].mId); // drafts - mMockClock.advance(1000L); mManager.touch(mMailboxArray[2].mId); // outbox - mMockClock.advance(1000L); mManager.touch(mMailboxArray[3].mId); // sent - mMockClock.advance(1000L); mManager.touch(mMailboxArray[4].mId).get(); // trash + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[6].mId); // abbott + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[7].mId); // costello + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[8].mId); // bud_lou + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[9].mId); // laurel + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[10].mId); // hardy + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[0].mId); // inbox + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[1].mId); // drafts + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[2].mId); // outbox + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[3].mId); // sent + mMockClock.advance(1000L); mManager.touch(1L, mMailboxArray[4].mId).get(); // trash // nothing but user mailboxes testList = mManager.getMostRecent(1L, false); @@ -230,7 +247,7 @@ public class RecentMailboxManagerTest extends AndroidTestCase { searchMailbox.mFlagVisible = false; searchMailbox.update(mMockContext, cv); - mMockClock.advance(1000L); mManager.touch(searchMailbox.mId).get(); + mMockClock.advance(1000L); mManager.touch(1L, searchMailbox.mId).get(); // Ensure search mailbox isn't returned testList = mManager.getMostRecent(1L, false);