Fixup recent mailboxes.

The default recent list should be pre-populated and fall off the list as
normal. The previous implementation showed a default list if there were
no touched mailboxes, but then the default list disappeared as soon as
there was one touched.

Bug: 5020673
Change-Id: Ifad607a9d36feff837ab42d039ce9209f223f345
This commit is contained in:
Ben Komalo 2011-07-14 10:21:41 -07:00
parent acd985efb4
commit d6ad9b8c03
3 changed files with 101 additions and 62 deletions

View File

@ -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);
}
}

View File

@ -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<Long, Boolean> 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<Void, Void, Void> touch(long mailboxId) {
return fireAndForget(mailboxId, sClock.getTime());
public EmailAsyncTask<Void, Void, Void> 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<Long> getMostRecent(long accountId, boolean withExclusions) {
ensureDefaultsInitialized(accountId, sClock.getTime());
String selection = withExclusions ? RECENT_SELECTION_WITH_EXCLUSIONS : RECENT_SELECTION;
ArrayList<Long> returnList = new ArrayList<Long>();
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<Long> getDefaultMostRecent(long accountId) {
ArrayList<Long> returnList = new ArrayList<Long>();
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<Void, Void, Void> fireAndForget(final long mailboxId, final long time) {
private EmailAsyncTask<Void, Void, Void> 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);
}
}

View File

@ -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<Integer> defaultRecents = new HashSet<Integer>() {{
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<Long> 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<Long> 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<Long> 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<Long> 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);