diff --git a/res/values/strings.xml b/res/values/strings.xml index 55db0c6bc..cddfc7c36 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -276,6 +276,9 @@ Show all folders Accounts + + + Recent mailboxes(%s) Load more messages diff --git a/src/com/android/email/activity/AccountSelectorAdapter.java b/src/com/android/email/activity/AccountSelectorAdapter.java index 2f800c7c2..996e3b236 100644 --- a/src/com/android/email/activity/AccountSelectorAdapter.java +++ b/src/com/android/email/activity/AccountSelectorAdapter.java @@ -23,9 +23,13 @@ import com.android.email.data.ClosingMatrixCursor; import com.android.email.data.ThrottlingCursorLoader; import com.android.emailcommon.provider.EmailContent; import com.android.emailcommon.provider.EmailContent.Account; +import com.android.emailcommon.provider.EmailContent.MailboxColumns; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.Utility; +import java.util.ArrayList; + +import android.content.ContentUris; import android.content.Context; import android.content.Loader; import android.database.Cursor; @@ -47,11 +51,14 @@ public class AccountSelectorAdapter extends CursorAdapter { private static final String UNREAD_COUNT = "unreadCount"; /** meta data column for the row type; used for display purposes */ private static final String ROW_TYPE = "rowType"; + /** meta data position of the currently selected account in the drop-down list */ + private static final String ACCOUNT_POSITION = "accountPosition"; private static final int ROW_TYPE_HEADER = AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER; @SuppressWarnings("unused") private static final int ROW_TYPE_MAILBOX = 0; private static final int ROW_TYPE_ACCOUNT = 1; private static final int ITEM_VIEW_TYPE_ACCOUNT = 0; + private static final int UNKNOWN_POSITION = -1; /** Projection for account database query */ private static final String[] ACCOUNT_PROJECTION = new String[] { Account.ID, @@ -68,6 +75,7 @@ public class AccountSelectorAdapter extends CursorAdapter { Account.DISPLAY_NAME, Account.EMAIL_ADDRESS, UNREAD_COUNT, + ACCOUNT_POSITION, }; /** Sort order. Show the default account first. */ @@ -78,8 +86,13 @@ public class AccountSelectorAdapter extends CursorAdapter { @SuppressWarnings("hiding") private final Context mContext; - public static Loader createLoader(Context context) { - return new AccountsLoader(context); + /** + * Returns a loader that can populate the account spinner. + * @param context a context + * @param accountId the ID of the currently viewed account + */ + public static Loader createLoader(Context context, long accountId) { + return new AccountsLoader(context, accountId); } public AccountSelectorAdapter(Context context) { @@ -88,6 +101,22 @@ public class AccountSelectorAdapter extends CursorAdapter { mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } + /** + * Invoked when the action bar needs the view of the text in the bar itself. The default + * is to show just the display name of the cursor at the given position. + */ + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (!isAccountItem(position)) { + // asked to show a recent mailbox; instead, show the account associated w/ the mailbox + int newPosition = getAccountPosition(position); + if (newPosition != UNKNOWN_POSITION) { + position = newPosition; + } + } + return super.getView(position, convertView, parent); + } + @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { Cursor c = getCursor(); @@ -175,6 +204,11 @@ public class AccountSelectorAdapter extends CursorAdapter { return c.moveToPosition(position) ? getAccountUnreadCount(c) : 0; } + private int getAccountPosition(int position) { + final Cursor c = getCursor(); + return c.moveToPosition(position) ? getAccountPosition(c) : UNKNOWN_POSITION; + } + /** Returns the account ID extracted from the given cursor. */ static long getAccountId(Cursor c) { return c.getLong(c.getColumnIndex(Account.ID)); @@ -195,6 +229,11 @@ public class AccountSelectorAdapter extends CursorAdapter { return cursor.getInt(cursor.getColumnIndex(UNREAD_COUNT)); } + /** Returns the account position extracted from the given cursor. */ + private static int getAccountPosition(Cursor cursor) { + return cursor.getInt(cursor.getColumnIndex(ACCOUNT_POSITION)); + } + /** * Load the account list. The resulting cursor contains * - Account info @@ -204,12 +243,13 @@ public class AccountSelectorAdapter extends CursorAdapter { @VisibleForTesting static class AccountsLoader extends ThrottlingCursorLoader { private final Context mContext; - - public AccountsLoader(Context context) { + private final long mAccountId; + public AccountsLoader(Context context, long accountId) { // Super class loads a regular account cursor, but we replace it in loadInBackground(). super(context, EmailContent.Account.CONTENT_URI, ACCOUNT_PROJECTION, null, null, ORDER_BY); mContext = context; + mAccountId = accountId; } @Override @@ -218,47 +258,100 @@ public class AccountSelectorAdapter extends CursorAdapter { // Use ClosingMatrixCursor so that accountsCursor gets closed too when it's closed. final MatrixCursor resultCursor = new ClosingMatrixCursor(ADAPTER_PROJECTION, accountsCursor); - addAccountsToCursor(resultCursor, accountsCursor); - // TODO Add mailbox recent list to the end of the return cursor + final int accountPosition = addAccountsToCursor(resultCursor, accountsCursor); + addRecentsToCursor(resultCursor, accountPosition); return Utility.CloseTraceCursorWrapper.get(resultCursor); } /** Adds the account list [with extra meta data] to the given matrix cursor */ - private void addAccountsToCursor(MatrixCursor matrixCursor, Cursor accountCursor) { + private int addAccountsToCursor(MatrixCursor matrixCursor, Cursor accountCursor) { + int accountPosition = UNKNOWN_POSITION; accountCursor.moveToPosition(-1); // Add a header for the accounts - matrixCursor.newRow() - .add(ROW_TYPE_HEADER) - .add(0L) - .add(mContext.getString(R.string.mailbox_list_account_selector_account_header)) - .add(null) - .add(0L); + String header = + mContext.getString(R.string.mailbox_list_account_selector_account_header); + addRow(matrixCursor, ROW_TYPE_HEADER, 0L, header, null, 0, UNKNOWN_POSITION); int totalUnread = 0; + int currentPosition = 1; while (accountCursor.moveToNext()) { // Add account, with its unread count. final long accountId = accountCursor.getLong(0); final int unread = Mailbox.getUnreadCountByAccountAndMailboxType( mContext, accountId, Mailbox.TYPE_INBOX); - matrixCursor.newRow() - .add(ROW_TYPE_ACCOUNT) - .add(accountId) - .add(getAccountDisplayName(accountCursor)) - .add(getAccountEmailAddress(accountCursor)) - .add(unread); + final String name = getAccountDisplayName(accountCursor); + final String emailAddress = getAccountEmailAddress(accountCursor); + addRow(matrixCursor, ROW_TYPE_ACCOUNT, accountId, name, emailAddress, unread, + UNKNOWN_POSITION); totalUnread += unread; + if (accountId == mAccountId) { + accountPosition = currentPosition; + } + currentPosition++; } // Add "combined view" if more than one account exists final int countAccounts = matrixCursor.getCount(); if (countAccounts > 1) { - matrixCursor.newRow() - .add(ROW_TYPE_ACCOUNT) - .add(Account.ACCOUNT_ID_COMBINED_VIEW) - .add(mContext.getResources().getString( - R.string.mailbox_list_account_selector_combined_view)) - .add(mContext.getResources().getQuantityString(R.plurals.number_of_accounts, - countAccounts, countAccounts)) - .add(totalUnread); + final String name = mContext.getResources().getString( + R.string.mailbox_list_account_selector_combined_view); + final String accountCount = mContext.getResources().getQuantityString( + R.plurals.number_of_accounts, countAccounts, countAccounts); + addRow(matrixCursor, ROW_TYPE_ACCOUNT, Account.ACCOUNT_ID_COMBINED_VIEW, + name, accountCount, totalUnread,UNKNOWN_POSITION); } + return accountPosition; + } + + /** + * Adds the recent mailbox list to the given cursor. + * @param matrixCursor the cursor to add the list to + * @param accountPosition the cursor position of the currently selected account + */ + private void addRecentsToCursor(MatrixCursor matrixCursor, int accountPosition) { + if (mAccountId <= 0L || mAccountId == Account.ACCOUNT_ID_COMBINED_VIEW) { + // Currently selected account isn't usable for our purposes + return; + } + String emailAddress = null; + if (accountPosition != UNKNOWN_POSITION) { + matrixCursor.moveToPosition(accountPosition); + emailAddress = + matrixCursor.getString(matrixCursor.getColumnIndex(Account.EMAIL_ADDRESS)); + } + boolean useTwoPane = mContext.getResources().getBoolean(R.bool.use_two_pane); + // Filter system mailboxes if we're using a two-pane view + RecentMailboxManager mailboxManager = RecentMailboxManager.getInstance(mContext); + ArrayList recentMailboxes = mailboxManager.getMostRecent(mAccountId, useTwoPane); + if (!useTwoPane && recentMailboxes.size() == 0) { + // TODO Add default mailboxes to recentMailboxes for the one pane view + } + if (recentMailboxes.size() > 0) { + String mailboxHeader = mContext.getString( + R.string.mailbox_list_account_selector_mailbox_header_fmt, emailAddress); + addRow(matrixCursor, ROW_TYPE_HEADER, 0L, mailboxHeader, null, 0, UNKNOWN_POSITION); + for (long mailboxId : recentMailboxes) { + final int unread = Utility.getFirstRowInt(mContext, + ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId), + new String[] { MailboxColumns.UNREAD_COUNT }, null, null, null, 0); + final Mailbox mailbox = Mailbox.restoreMailboxWithId(mContext, mailboxId); + addRow(matrixCursor, ROW_TYPE_MAILBOX, mailboxId, mailbox.mDisplayName, null, + unread, accountPosition); + } + } + if (!useTwoPane) { + // TODO Add row to view all mailboxes + } + } + + /** Adds a row to the given cursor */ + private void addRow(MatrixCursor cursor, int rowType, long id, String name, + String emailAddress, int unreadCount, int listPosition) { + cursor.newRow() + .add(rowType) + .add(id) + .add(name) + .add(emailAddress) + .add(unreadCount) + .add(listPosition); } } } diff --git a/src/com/android/email/activity/ActionBarController.java b/src/com/android/email/activity/ActionBarController.java index c20e19275..3891a537f 100644 --- a/src/com/android/email/activity/ActionBarController.java +++ b/src/com/android/email/activity/ActionBarController.java @@ -18,6 +18,7 @@ package com.android.email.activity; import com.android.email.R; import com.android.emailcommon.provider.EmailContent.Account; +import com.android.emailcommon.provider.Mailbox; import android.app.ActionBar; import android.app.LoaderManager; @@ -51,7 +52,7 @@ public class ActionBarController { private final AccountSelectorAdapter mAccountsSelectorAdapter; private Cursor mAccountCursor; /** The current account ID; used to determine if the account has changed. */ - private long mLastAccountIdForDirtyCheck = -1; + private long mLastAccountIdForDirtyCheck = Account.NO_ACCOUNT; public final Callback mCallback; @@ -81,12 +82,17 @@ public class ActionBarController { /** * Called when an account is selected on the account spinner. - * - * @param accountId ID of the selected account, or - * {@link Account#ACCOUNT_ID_COMBINED_VIEW}. + * @param accountId ID of the selected account, or {@link Account#ACCOUNT_ID_COMBINED_VIEW}. */ public void onAccountSelected(long accountId); + /** + * Invoked when a recent mailbox is selected on the account spinner. + * @param mailboxId The ID of the selected mailbox, or {@link Mailbox#NO_MAILBOX} if the + * special option "show all mailboxes" was selected. + */ + public void onMailboxSelected(long mailboxId); + /** Called when no accounts are found in the database. */ public void onNoAccountsFound(); } @@ -142,8 +148,13 @@ public class ActionBarController { // Update the account list only when the account has changed. if (mLastAccountIdForDirtyCheck != mCallback.getUIAccountId()) { mLastAccountIdForDirtyCheck = mCallback.getUIAccountId(); - // TODO Need to do this all the time as the recent list is shown here - updateAccountList(); + // If the selected account changes, reload the cursor to update the recent mailboxes + if (mLastAccountIdForDirtyCheck != Account.NO_ACCOUNT) { + mLoaderManager.destroyLoader(LOADER_ID_ACCOUNT_LIST); + loadAccounts(); + } else { + updateAccountList(); + } } } @@ -155,7 +166,7 @@ public class ActionBarController { new LoaderCallbacks() { @Override public Loader onCreateLoader(int id, Bundle args) { - return AccountSelectorAdapter.createLoader(mContext); + return AccountSelectorAdapter.createLoader(mContext, mCallback.getUIAccountId()); } @Override @@ -235,8 +246,8 @@ public class ActionBarController { if (mAccountsSelectorAdapter.isAccountItem(itemPosition) && itemId != mCallback.getUIAccountId()) { mCallback.onAccountSelected(itemId); - } else { - // TODO handle mailbox item + } else if (!mAccountsSelectorAdapter.isAccountItem(itemPosition)) { + mCallback.onMailboxSelected(itemId); } return true; } diff --git a/src/com/android/email/activity/MessageViewFragmentBase.java b/src/com/android/email/activity/MessageViewFragmentBase.java index 582e2df75..e94d5e5af 100644 --- a/src/com/android/email/activity/MessageViewFragmentBase.java +++ b/src/com/android/email/activity/MessageViewFragmentBase.java @@ -1026,6 +1026,7 @@ public abstract class MessageViewFragmentBase extends Fragment implements View.O reloadUiFromMessage(message, mOkToFetch); queryContactStatus(); onMessageShown(mMessageId, mMailboxType); + RecentMailboxManager.getInstance(mContext).touch(message.mMailboxKey); } } diff --git a/src/com/android/email/activity/UIControllerOnePane.java b/src/com/android/email/activity/UIControllerOnePane.java index 1e9c38883..6cb4fd58e 100644 --- a/src/com/android/email/activity/UIControllerOnePane.java +++ b/src/com/android/email/activity/UIControllerOnePane.java @@ -237,6 +237,11 @@ class UIControllerOnePane extends UIControllerBase { return UIControllerOnePane.this.getUIAccountId(); } + @Override + public void onMailboxSelected(long mailboxId) { + // TODO Implement this + } + @Override public boolean isAccountSelected() { return UIControllerOnePane.this.isAccountSelected(); diff --git a/src/com/android/email/activity/UIControllerTwoPane.java b/src/com/android/email/activity/UIControllerTwoPane.java index 58d09b09e..22f945119 100644 --- a/src/com/android/email/activity/UIControllerTwoPane.java +++ b/src/com/android/email/activity/UIControllerTwoPane.java @@ -31,7 +31,6 @@ import com.android.emailcommon.utility.EmailAsyncTask; import com.google.common.annotations.VisibleForTesting; import android.app.Activity; -import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Context; import android.os.Bundle; @@ -954,6 +953,11 @@ class UIControllerTwoPane extends UIControllerBase implements switchAccount(accountId); } + @Override + public void onMailboxSelected(long mailboxId) { + UIControllerTwoPane.this.openMailbox(getUIAccountId(), mailboxId); + } + @Override public void onNoAccountsFound() { Welcome.actionStart(mActivity); diff --git a/tests/src/com/android/email/activity/AccountSelectorAdapterAccountsLoaderTest.java b/tests/src/com/android/email/activity/AccountSelectorAdapterAccountsLoaderTest.java index b98401428..43f57a0c3 100644 --- a/tests/src/com/android/email/activity/AccountSelectorAdapterAccountsLoaderTest.java +++ b/tests/src/com/android/email/activity/AccountSelectorAdapterAccountsLoaderTest.java @@ -46,7 +46,7 @@ public class AccountSelectorAdapterAccountsLoaderTest extends LoaderTestCase { final Account a1 = ProviderTestUtils.setupAccount("a1", true, mProviderContext); { // Only 1 account -- no combined view row. - Loader l = new AccountSelectorAdapter.AccountsLoader(mProviderContext); + Loader l = new AccountSelectorAdapter.AccountsLoader(mProviderContext, 0L); Cursor result = getLoaderResultSynchronously(l); assertEquals(1, result.getCount()); } @@ -54,7 +54,7 @@ public class AccountSelectorAdapterAccountsLoaderTest extends LoaderTestCase { final Account a2 = ProviderTestUtils.setupAccount("a2", true, mProviderContext); { // 2 accounts -- with combined view row, so returns 3 rows. - Loader l = new AccountSelectorAdapter.AccountsLoader(mProviderContext); + Loader l = new AccountSelectorAdapter.AccountsLoader(mProviderContext, 0L); Cursor result = getLoaderResultSynchronously(l); assertEquals(3, result.getCount()); }