diff --git a/res/layout/account_selector.xml b/res/layout/account_selector.xml deleted file mode 100644 index a546552a4..000000000 --- a/res/layout/account_selector.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - diff --git a/res/layout/action_bar_current_mailbox.xml b/res/layout/action_bar_current_mailbox.xml deleted file mode 100644 index 5759b3840..000000000 --- a/res/layout/action_bar_current_mailbox.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - diff --git a/res/layout/action_bar_custom_view.xml b/res/layout/action_bar_custom_view.xml index 609ba824d..c2f412d30 100644 --- a/res/layout/action_bar_custom_view.xml +++ b/res/layout/action_bar_custom_view.xml @@ -26,8 +26,8 @@ android:layout_height="0dip" > + + + + + + + + + diff --git a/res/layout/account_selector_dropdown.xml b/res/layout/action_bar_spinner_dropdown.xml similarity index 87% rename from res/layout/account_selector_dropdown.xml rename to res/layout/action_bar_spinner_dropdown.xml index 3c4c79b24..8e9f5bef3 100644 --- a/res/layout/account_selector_dropdown.xml +++ b/res/layout/action_bar_spinner_dropdown.xml @@ -17,6 +17,8 @@ @@ -38,14 +39,12 @@ android:id="@+id/display_name" android:layout_width="match_parent" android:layout_height="wrap_content" - android:maxWidth="@dimen/account_spinner_dropdown_account_name_max_width" style="@style/action_bar_account_name" /> diff --git a/res/layout/account_selector_dropdown_header.xml b/res/layout/action_bar_spinner_dropdown_header.xml similarity index 100% rename from res/layout/account_selector_dropdown_header.xml rename to res/layout/action_bar_spinner_dropdown_header.xml diff --git a/res/values/dimensions.xml b/res/values/dimensions.xml index a75e8ffe6..29d147eb9 100644 --- a/res/values/dimensions.xml +++ b/res/values/dimensions.xml @@ -53,7 +53,8 @@ 0dip 0dip - 352dip + 250dip + 300dip 14sp diff --git a/res/values/strings.xml b/res/values/strings.xml index 6f4598cc8..0515e6e05 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1153,6 +1153,9 @@ save attachment. Search %1$s + + Folders + Folder check frequency diff --git a/src/com/android/email/FolderProperties.java b/src/com/android/email/FolderProperties.java index 9b95404f7..fdcaa8d48 100644 --- a/src/com/android/email/FolderProperties.java +++ b/src/com/android/email/FolderProperties.java @@ -71,10 +71,7 @@ public class FolderProperties { return sInstance; } - /** - * Lookup names of localized special mailboxes - */ - private String getDisplayName(int type, long mailboxId) { + public String getCombinedMailboxName(long mailboxId) { // Special combined mailboxes int resId = 0; @@ -91,13 +88,21 @@ public class FolderProperties { if (resId != 0) { return mContext.getString(resId); } - - if (type < mSpecialMailbox.length) { - return mSpecialMailbox[type]; - } return null; } + /** + * Lookup names of localized special mailboxes + */ + private String getDisplayName(int type, long mailboxId) { + String name = getCombinedMailboxName(mailboxId); + + if ((name == null) && (type < mSpecialMailbox.length)) { + name = mSpecialMailbox[type]; + } + return name; + } + /** * Return the display name for a mailbox for UI. For normal mailboxes, it just returns * {@code originalDisplayName}, but for special mailboxes (such as combined mailboxes) it diff --git a/src/com/android/email/activity/AccountSelectorAdapter.java b/src/com/android/email/activity/AccountSelectorAdapter.java index 60978ebbd..52149fc11 100644 --- a/src/com/android/email/activity/AccountSelectorAdapter.java +++ b/src/com/android/email/activity/AccountSelectorAdapter.java @@ -24,12 +24,14 @@ import com.android.email.data.ClosingMatrixCursor; import com.android.email.data.ThrottlingCursorLoader; 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.MailboxColumns; import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.Utility; import java.util.ArrayList; +import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; import android.content.Loader; @@ -50,10 +52,16 @@ import android.widget.TextView; public class AccountSelectorAdapter extends CursorAdapter { /** meta data column for an message count (unread or total, depending on row) */ private static final String MESSAGE_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"; + + /** "account id" virtual column name for the matrix cursor */ + private static final String ACCOUNT_ID = "accountId"; + private static final int ROW_TYPE_HEADER = AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER; @SuppressWarnings("unused") private static final int ROW_TYPE_MAILBOX = 0; @@ -77,6 +85,7 @@ public class AccountSelectorAdapter extends CursorAdapter { Account.EMAIL_ADDRESS, MESSAGE_COUNT, ACCOUNT_POSITION, + ACCOUNT_ID, }; /** Sort order. Show the default account first. */ @@ -92,8 +101,8 @@ public class AccountSelectorAdapter extends CursorAdapter { * @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, UiUtilities.useTwoPane(context)); + public static Loader createLoader(Context context, long accountId, long mailboxId) { + return new AccountsLoader(context, accountId, mailboxId, UiUtilities.useTwoPane(context)); } public AccountSelectorAdapter(Context context) { @@ -103,22 +112,8 @@ public class AccountSelectorAdapter extends CursorAdapter { } /** - * 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); - } - - /** + * {@inheritDoc} + * * The account selector view can contain one of four types of row data: *
    *
  1. headers
  2. @@ -132,26 +127,27 @@ public class AccountSelectorAdapter extends CursorAdapter { * mailboxes display an unread count; whereas "show all folders" does not. To determine * if a particular row is "show all folders" verify that a) it's not an account row and * b) it's ID is {@link Mailbox#NO_MAILBOX}. + * + * TODO Use recycled views. ({@link #getViewTypeCount} and {@link #getItemViewType}) */ @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { + public View getView(int position, View convertView, ViewGroup parent) { Cursor c = getCursor(); c.moveToPosition(position); - View view; if (c.getInt(c.getColumnIndex(ROW_TYPE)) == ROW_TYPE_HEADER) { - view = mInflater.inflate(R.layout.account_selector_dropdown_header, parent, false); + view = mInflater.inflate(R.layout.action_bar_spinner_dropdown_header, parent, false); final TextView displayNameView = (TextView) view.findViewById(R.id.display_name); final String displayName = getDisplayName(c); displayNameView.setText(displayName); } else { - view = mInflater.inflate(R.layout.account_selector_dropdown, parent, false); + view = mInflater.inflate(R.layout.action_bar_spinner_dropdown, parent, false); final TextView displayNameView = (TextView) view.findViewById(R.id.display_name); final TextView emailAddressView = (TextView) view.findViewById(R.id.email_address); final TextView unreadCountView = (TextView) view.findViewById(R.id.unread_count); - final String displayName = getDisplayName(position); - final String emailAddress = getAccountEmailAddress(position); + final String displayName = getDisplayName(c); + final String emailAddress = getAccountEmailAddress(c); displayNameView.setText(displayName); @@ -163,12 +159,12 @@ public class AccountSelectorAdapter extends CursorAdapter { emailAddressView.setText(emailAddress); } - boolean isAccount = isAccountItem(position); + boolean isAccount = isAccountItem(c); long id = getId(c); if (isAccount || id != Mailbox.NO_MAILBOX) { unreadCountView.setVisibility(View.VISIBLE); unreadCountView.setText(UiUtilities.getMessageCountForUi(mContext, - getAccountUnreadCount(position), true)); + getAccountUnreadCount(c), true)); } else { unreadCountView.setVisibility(View.INVISIBLE); } @@ -177,14 +173,13 @@ public class AccountSelectorAdapter extends CursorAdapter { } @Override - public void bindView(View view, Context context, Cursor cursor) { - TextView textView = (TextView) view.findViewById(R.id.display_name); - textView.setText(getDisplayName(cursor)); + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return null; // we don't reuse views. This method never gets called. } @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.account_selector, parent, false); + public void bindView(View view, Context context, Cursor cursor) { + // we don't reuse views. This method never gets called. } @Override @@ -209,6 +204,10 @@ public class AccountSelectorAdapter extends CursorAdapter { public boolean isAccountItem(int position) { Cursor c = getCursor(); c.moveToPosition(position); + return isAccountItem(c); + } + + public boolean isAccountItem(Cursor c) { return (c.getLong(c.getColumnIndex(ROW_TYPE)) == ROW_TYPE_ACCOUNT); } @@ -218,24 +217,8 @@ public class AccountSelectorAdapter extends CursorAdapter { return (c.getLong(c.getColumnIndex(ROW_TYPE)) == ROW_TYPE_MAILBOX); } - private String getDisplayName(int position) { - final Cursor c = getCursor(); - return c.moveToPosition(position) ? getDisplayName(c) : null; - } - - private String getAccountEmailAddress(int position) { - final Cursor c = getCursor(); - return c.moveToPosition(position) ? getAccountEmailAddress(c) : null; - } - - private int getAccountUnreadCount(int position) { - final Cursor c = getCursor(); - return c.moveToPosition(position) ? getMessageCount(c) : 0; - } - - int getAccountPosition(int position) { - final Cursor c = getCursor(); - return c.moveToPosition(position) ? getAccountPosition(c) : UNKNOWN_POSITION; + private int getAccountUnreadCount(Cursor c) { + return getMessageCount(c); } /** @@ -245,6 +228,24 @@ public class AccountSelectorAdapter extends CursorAdapter { return c.getLong(c.getColumnIndex(EmailContent.RECORD_ID)); } + /** + * @return ID of the account / mailbox for a row + */ + public long getId(int position) { + final Cursor c = getCursor(); + return c.moveToPosition(position) ? getId(c) : Account.NO_ACCOUNT; + } + + /** + * @return ID of the account for a row + */ + public long getAccountId(int position) { + final Cursor c = getCursor(); + return c.moveToPosition(position) + ? c.getLong(c.getColumnIndex(ACCOUNT_ID)) + : Account.NO_ACCOUNT; + } + /** Returns the account name extracted from the given cursor. */ static String getDisplayName(Cursor cursor) { return cursor.getString(cursor.getColumnIndex(Account.DISPLAY_NAME)); @@ -263,9 +264,13 @@ public class AccountSelectorAdapter extends CursorAdapter { return cursor.getInt(cursor.getColumnIndex(MESSAGE_COUNT)); } - /** Returns the account position extracted from the given cursor. */ - private static int getAccountPosition(Cursor cursor) { - return cursor.getInt(cursor.getColumnIndex(ACCOUNT_POSITION)); + private static String sCombinedViewDisplayName; + private static String getCombinedViewDisplayName(Context c) { + if (sCombinedViewDisplayName == null) { + sCombinedViewDisplayName = c.getResources().getString( + R.string.mailbox_list_account_selector_combined_view); + } + return sCombinedViewDisplayName; } /** @@ -278,16 +283,18 @@ public class AccountSelectorAdapter extends CursorAdapter { static class AccountsLoader extends ThrottlingCursorLoader { private final Context mContext; private final long mAccountId; + private final long mMailboxId; private final boolean mUseTwoPane; // Injectable for test private final FolderProperties mFolderProperties; @VisibleForTesting - AccountsLoader(Context context, long accountId, boolean useTwoPane) { + AccountsLoader(Context context, long accountId, long mailboxId, boolean useTwoPane) { // Super class loads a regular account cursor, but we replace it in loadInBackground(). super(context, Account.CONTENT_URI, ACCOUNT_PROJECTION, null, null, ORDER_BY); mContext = context; mAccountId = accountId; + mMailboxId = mailboxId; mFolderProperties = FolderProperties.getInstance(mContext); mUseTwoPane = useTwoPane; } @@ -300,17 +307,19 @@ public class AccountSelectorAdapter extends CursorAdapter { = new CursorWithExtras(ADAPTER_PROJECTION, accountsCursor); final int accountPosition = addAccountsToCursor(resultCursor, accountsCursor); addRecentsToCursor(resultCursor, accountPosition); - return Utility.CloseTraceCursorWrapper.get(resultCursor); + + resultCursor.setAccountMailboxInfo(getContext(), mAccountId, mMailboxId); + return resultCursor; } /** Adds the account list [with extra meta data] to the given matrix cursor */ private int addAccountsToCursor(CursorWithExtras matrixCursor, Cursor accountCursor) { int accountPosition = UNKNOWN_POSITION; accountCursor.moveToPosition(-1); + // Add a header for the accounts - String header = - mContext.getString(R.string.mailbox_list_account_selector_account_header); - addRow(matrixCursor, ROW_TYPE_HEADER, 0L, header, null, 0, UNKNOWN_POSITION); + addHeaderRow(matrixCursor, mContext.getString( + R.string.mailbox_list_account_selector_account_header)); matrixCursor.mAccountCount = accountCursor.getCount(); int totalUnread = 0; @@ -323,7 +332,7 @@ public class AccountSelectorAdapter extends CursorAdapter { final String name = getDisplayName(accountCursor); final String emailAddress = getAccountEmailAddress(accountCursor); addRow(matrixCursor, ROW_TYPE_ACCOUNT, accountId, name, emailAddress, unread, - UNKNOWN_POSITION); + UNKNOWN_POSITION, accountId); totalUnread += unread; if (accountId == mAccountId) { accountPosition = currentPosition; @@ -333,12 +342,12 @@ public class AccountSelectorAdapter extends CursorAdapter { // Add "combined view" if more than one account exists final int countAccounts = accountCursor.getCount(); if (countAccounts > 1) { - 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); + getCombinedViewDisplayName(mContext), + accountCount, totalUnread, UNKNOWN_POSITION, + Account.ACCOUNT_ID_COMBINED_VIEW); // Increment the account count for the combined account. matrixCursor.mAccountCount++; @@ -373,9 +382,8 @@ public class AccountSelectorAdapter extends CursorAdapter { if (!mUseTwoPane) { // "Recent mailboxes" header - 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); + addHeaderRow(matrixCursor, mContext.getString( + R.string.mailbox_list_account_selector_mailbox_header_fmt, emailAddress)); } if (recentCount > 0) { @@ -389,7 +397,7 @@ public class AccountSelectorAdapter extends CursorAdapter { String name = mContext.getString( R.string.mailbox_list_account_selector_show_all_folders); addRow(matrixCursor, ROW_TYPE_MAILBOX, Mailbox.NO_MAILBOX, name, null, 0, - accountPosition); + accountPosition, mAccountId); } } @@ -408,33 +416,114 @@ public class AccountSelectorAdapter extends CursorAdapter { } addRow(matrixCursor, ROW_TYPE_MAILBOX, mailboxId, mFolderProperties.getDisplayName(c), null, - mFolderProperties.getMessageCount(c), accountPosition); + mFolderProperties.getMessageCount(c), accountPosition, mAccountId); + } + + private void addHeaderRow(MatrixCursor cursor, String name) { + addRow(cursor, ROW_TYPE_HEADER, 0L, name, null, 0, UNKNOWN_POSITION, + Account.NO_ACCOUNT); } /** Adds a row to the given cursor */ private void addRow(MatrixCursor cursor, int rowType, long id, String name, - String emailAddress, int messageCount, int listPosition) { + String emailAddress, int messageCount, int listPosition, long accountId) { cursor.newRow() .add(rowType) .add(id) .add(name) .add(emailAddress) .add(messageCount) - .add(listPosition); + .add(listPosition) + .add(accountId); } } /** Cursor with some extra meta data. */ static class CursorWithExtras extends ClosingMatrixCursor { + /** Number of account elements, including the combined account row. */ private int mAccountCount; /** Number of recent mailbox elements */ private int mRecentCount; + private boolean mAccountExists; + + /** + * Account ID that's loaded. + */ + private long mAccountId; + private String mAccountDisplayName; + + /** + * Mailbox ID that's loaded. + */ + private long mMailboxId; + private String mMailboxDisplayName; + private int mMailboxMessageCount; + private CursorWithExtras(String[] columnNames, Cursor innerCursor) { super(columnNames, innerCursor); } + private static final String[] ACCOUNT_INFO_PROJECTION = new String[] { + AccountColumns.DISPLAY_NAME, + }; + private static final String[] MAILBOX_INFO_PROJECTION = new String[] { + MailboxColumns.ID, MailboxColumns.DISPLAY_NAME, MailboxColumns.TYPE, + MailboxColumns.UNREAD_COUNT, MailboxColumns.MESSAGE_COUNT + }; + + /** + * Set the current account/mailbox info. + */ + private void setAccountMailboxInfo(Context context, long accountId, long mailboxId) { + mAccountId = accountId; + mMailboxId = mailboxId; + + // Get account info + if (accountId == Account.ACCOUNT_ID_COMBINED_VIEW) { + // We need to treat ACCOUNT_ID_COMBINED_VIEW specially... + mAccountExists = true; + mAccountDisplayName = getCombinedViewDisplayName(context); + mMailboxDisplayName = FolderProperties.getInstance(context) + .getCombinedMailboxName(mMailboxId); + + // TODO Would be nicer to show message count for combined mailboxes too.. + mMailboxMessageCount = 0; + return; + } + + mAccountDisplayName = Utility.getFirstRowString(context, + ContentUris.withAppendedId(Account.CONTENT_URI, accountId), + ACCOUNT_INFO_PROJECTION, null, null, null, 0, null); + if (mAccountDisplayName == null) { + // Account gone! + mAccountExists = false; + return; + } + mAccountExists = true; + + // If mailbox not specified, done. + if (mMailboxId == Mailbox.NO_MAILBOX) { + return; + } + + // Get mailbox info + final ContentResolver r = context.getContentResolver(); + final Cursor mailboxCursor = r.query( + ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId), + MAILBOX_INFO_PROJECTION, null, null, null); + try { + if (mailboxCursor.moveToFirst()) { + final FolderProperties fp = FolderProperties.getInstance(context); + mMailboxDisplayName = fp.getDisplayName(mailboxCursor); + mMailboxMessageCount = fp.getMessageCount(mailboxCursor); + } + } finally { + mailboxCursor.close(); + } + } + /** * Returns the cursor position of the item with the given ID. Or {@link #UNKNOWN_POSITION} * if the given ID does not exist. @@ -456,5 +545,32 @@ public class AccountSelectorAdapter extends CursorAdapter { public int getRecentMailboxCount() { return mRecentCount; } + + public long getAccountId() { + return mAccountId; + } + + public String getAccountDisplayName() { + return mAccountDisplayName; + } + + public long getMailboxId() { + return mMailboxId; + } + + public String getMailboxDisplayName() { + return mMailboxDisplayName; + } + + public int getMailboxMessageCount() { + return mMailboxMessageCount; + } + + /** + * @return {@code true} if the specified accuont exists. + */ + public boolean accountExists() { + return mAccountExists; + } } } diff --git a/src/com/android/email/activity/ActionBarController.java b/src/com/android/email/activity/ActionBarController.java index 2a3997388..0ff830680 100644 --- a/src/com/android/email/activity/ActionBarController.java +++ b/src/com/android/email/activity/ActionBarController.java @@ -16,30 +16,29 @@ package com.android.email.activity; +import com.android.email.R; +import com.android.emailcommon.provider.Account; +import com.android.emailcommon.provider.Mailbox; +import com.android.emailcommon.utility.Utility; + import android.app.ActionBar; import android.app.LoaderManager; import android.app.LoaderManager.LoaderCallbacks; -import android.content.ContentUris; import android.content.Context; import android.content.Loader; import android.database.Cursor; import android.os.Bundle; +import android.os.Handler; import android.text.TextUtils; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ListPopupWindow; +import android.widget.ListView; import android.widget.SearchView; import android.widget.TextView; -import com.android.email.FolderProperties; -import com.android.email.R; -import com.android.email.data.ThrottlingCursorLoader; -import com.android.emailcommon.Logging; -import com.android.emailcommon.provider.Account; -import com.android.emailcommon.provider.EmailContent; -import com.android.emailcommon.provider.EmailContent.MailboxColumns; -import com.android.emailcommon.provider.Mailbox; - /** * Manages the account name and the custom view part on the action bar. * @@ -68,25 +67,29 @@ public class ActionBarController { private static final int LOADER_ID_ACCOUNT_LIST = EmailActivity.ACTION_BAR_CONTROLLER_LOADER_ID_BASE + 0; - private static final int LOADER_ID_MAILBOX - = EmailActivity.ACTION_BAR_CONTROLLER_LOADER_ID_BASE + 1; private final Context mContext; private final LoaderManager mLoaderManager; private final ActionBar mActionBar; + /** "Folders" label shown with account name on 1-pane mailbox list */ + private final String mAllFoldersLabel; + private final View mActionBarCustomView; - private final View mMailboxNameContainer; - private final TextView mMailboxNameView; - private final TextView mUnreadCountView; + private final View mAccountSpinner; + private final TextView mAccountSpinnerLine1View; + private final TextView mAccountSpinnerLine2View; + private final TextView mAccountSpinnerCountView; + private final View mSearchContainer; private final SearchView mSearchView; - private final ActionBarNavigationCallback mActionBarNavigationCallback = - new ActionBarNavigationCallback(); + private final AccountDropdownPopup mAccountDropdown; private final AccountSelectorAdapter mAccountsSelectorAdapter; - private AccountSelectorAdapter.CursorWithExtras mAccountCursor; + + private AccountSelectorAdapter.CursorWithExtras mCursor; + /** The current account ID; used to determine if the account has changed. */ private long mLastAccountIdForDirtyCheck = Account.NO_ACCOUNT; @@ -103,6 +106,20 @@ public class ActionBarController { } public interface Callback { + /** Values for {@link #getTitleMode}. Show only account name */ + public static final int TITLE_MODE_ACCOUNT_NAME_ONLY = 0; + /** Show the current account name with "Folders" */ + public static final int TITLE_MODE_ACCOUNT_WITH_ALL_FOLDERS_LABEL = 1; + /** Show the current account name and the current mailbox name */ + public static final int TITLE_MODE_ACCOUNT_WITH_MAILBOX = 2; + /** + * Show the current message subject. Actual subject is obtained via + * {@link #getMessageSubject()}. + * + * NOT IMPLEMENTED YET + */ + public static final int TITLE_MODE_MESSAGE_SUBJECT = 3; + /** @return true if an account is selected. */ public boolean isAccountSelected(); @@ -118,8 +135,13 @@ public class ActionBarController { */ public long getMailboxId(); - /** @return true if the current mailbox name should be shown. */ - public boolean shouldShowMailboxName(); + /** + * @return constants such as {@link #TITLE_MODE_ACCOUNT_NAME_ONLY}. + */ + public int getTitleMode(); + + /** @see #TITLE_MODE_MESSAGE_SUBJECT */ + public String getMessageSubject(); /** @return the "UP" arrow should be shown. */ public boolean shouldShowUp(); @@ -132,10 +154,12 @@ public class ActionBarController { /** * Invoked when a recent mailbox is selected on the account spinner. + * + * @param accountId ID of the selected account, or {@link Account#ACCOUNT_ID_COMBINED_VIEW}. * @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); + public void onMailboxSelected(long accountId, long mailboxId); /** Called when no accounts are found in the database. */ public void onNoAccountsFound(); @@ -159,42 +183,58 @@ public class ActionBarController { mLoaderManager = loaderManager; mActionBar = actionBar; mCallback = callback; + mAllFoldersLabel = mContext.getResources().getString( + R.string.action_bar_mailbox_list_title); mAccountsSelectorAdapter = new AccountSelectorAdapter(mContext); - mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE - | ActionBar.DISPLAY_SHOW_HOME - | ActionBar.DISPLAY_SHOW_CUSTOM); + // Configure action bar. + mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_CUSTOM); // Prepare the custom view final LayoutInflater inflater = LayoutInflater.from(mContext); mActionBarCustomView = inflater.inflate(R.layout.action_bar_custom_view, null); final ActionBar.LayoutParams customViewLayout = new ActionBar.LayoutParams( - ActionBar.LayoutParams.MATCH_PARENT, + ActionBar.LayoutParams.WRAP_CONTENT, ActionBar.LayoutParams.MATCH_PARENT); - customViewLayout.setMargins(0 , 0, 0, 0); + customViewLayout.setMargins(0, 0, 0, 0); mActionBar.setCustomView(mActionBarCustomView, customViewLayout); - // Mailbox name / unread count - mMailboxNameContainer = UiUtilities.getView(mActionBarCustomView, - R.id.current_mailbox_container); - mMailboxNameView = UiUtilities.getView(mMailboxNameContainer, R.id.mailbox_name); - mUnreadCountView = UiUtilities.getView(mMailboxNameContainer, R.id.unread_count); + // Account spinner + mAccountSpinner = UiUtilities.getView(mActionBarCustomView, R.id.account_spinner); + + mAccountSpinnerLine1View = UiUtilities.getView(mActionBarCustomView, R.id.spinner_line_1); + mAccountSpinnerLine2View = UiUtilities.getView(mActionBarCustomView, R.id.spinner_line_2); + mAccountSpinnerCountView = UiUtilities.getView(mActionBarCustomView, R.id.spinner_count); // Search mSearchContainer = UiUtilities.getView(mActionBarCustomView, R.id.search_container); mSearchView = UiUtilities.getView(mSearchContainer, R.id.search_view); mSearchView.setSubmitButtonEnabled(true); mSearchView.setOnQueryTextListener(mOnQueryText); + + // Account dropdown + mAccountDropdown = new AccountDropdownPopup(mContext); + mAccountDropdown.setAdapter(mAccountsSelectorAdapter); + + mAccountSpinner.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + if (mAccountsSelectorAdapter.getCount() > 0) { + mAccountDropdown.show(); + } + } + }); } /** Must be called from {@link UIControllerBase#onActivityCreated()} */ public void onActivityCreated() { - loadAccounts(); refresh(); } /** Must be called from {@link UIControllerBase#onActivityDestroy()} */ public void onActivityDestroy() { + if (mAccountDropdown.isShowing()) { + mAccountDropdown.dismiss(); + } } /** Must be called from {@link UIControllerBase#onSaveInstanceState} */ @@ -234,11 +274,6 @@ public class ActionBarController { } mSearchMode = MODE_SEARCH; - // Need to force it to mode "standard" to hide it. - mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); - mActionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); - mSearchContainer.setVisibility(View.VISIBLE); - // Focus on the search input box and throw up the IME if specified. // TODO: HACK. this is a workaround IME not popping up. mSearchView.setIconified(false); @@ -251,11 +286,6 @@ public class ActionBarController { return; } mSearchMode = MODE_NORMAL; - mSearchContainer.setVisibility(View.GONE); - mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE); - - // Force update of account list when we exit search. - updateAccountList(); refresh(); mCallback.onSearchExit(); @@ -277,187 +307,141 @@ public class ActionBarController { /** Refreshes the action bar display. */ public void refresh() { + // The actual work is in refreshInernal(), but we don't call it directly here, because: + // 1. refresh() is called very often. + // 2. to avoid nested fragment transaction. + // refresh is often called during a fragment transaction, but updateTitle() may call + // a callback which would initiate another fragment transaction. + final Handler h = Utility.getMainThreadHandler(); + h.removeCallbacks(mRefreshRunnable); + h.post(mRefreshRunnable); + } + + private final Runnable mRefreshRunnable = new Runnable() { + @Override public void run() { + refreshInernal(); + } + }; + private void refreshInernal() { final boolean showUp = isInSearchMode() || mCallback.shouldShowUp(); mActionBar.setDisplayOptions(showUp ? ActionBar.DISPLAY_HOME_AS_UP : 0, ActionBar.DISPLAY_HOME_AS_UP); - if (isInSearchMode()) { - mMailboxNameContainer.setVisibility(View.GONE); - } else { - mMailboxNameContainer.setVisibility(mCallback.shouldShowMailboxName() - ? View.VISIBLE : View.GONE); - } - - // Update the account list only when the account has changed. - if (mLastAccountIdForDirtyCheck != mCallback.getUIAccountId()) { - mLastAccountIdForDirtyCheck = mCallback.getUIAccountId(); - // 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(); - } - } - - // Update current mailbox info + final long accountId = mCallback.getUIAccountId(); final long mailboxId = mCallback.getMailboxId(); - if (mailboxId == Mailbox.NO_MAILBOX) { - clearMailboxInfo(); - } else { - if (mLastMailboxIdForDirtyCheck != mailboxId) { - mLastMailboxIdForDirtyCheck = mailboxId; - loadMailboxInfo(mailboxId); + if ((mLastAccountIdForDirtyCheck != accountId) + || (mLastMailboxIdForDirtyCheck != mailboxId)) { + mLastAccountIdForDirtyCheck = accountId; + mLastMailboxIdForDirtyCheck = mailboxId; + + if (accountId != Account.NO_ACCOUNT) { + loadAccountMailboxInfo(accountId, mailboxId); } } + + updateTitle(); } /** - * Load account cursor, and update the action bar. + * Load account/mailbox info, and account/recent mailbox list. */ - private void loadAccounts() { - mLoaderManager.initLoader(LOADER_ID_ACCOUNT_LIST, null, + private void loadAccountMailboxInfo(final long accountId, final long mailboxId) { + mLoaderManager.restartLoader(LOADER_ID_ACCOUNT_LIST, null, new LoaderCallbacks() { @Override public Loader onCreateLoader(int id, Bundle args) { - return AccountSelectorAdapter.createLoader(mContext, mCallback.getUIAccountId()); + return AccountSelectorAdapter.createLoader(mContext, accountId, mailboxId); } @Override public void onLoadFinished(Loader loader, Cursor data) { - mAccountCursor = (AccountSelectorAdapter.CursorWithExtras) data; - updateAccountList(); + mCursor = (AccountSelectorAdapter.CursorWithExtras) data; + updateTitle(); } @Override public void onLoaderReset(Loader loader) { - mAccountCursor = null; - updateAccountList(); + mCursor = null; + updateTitle(); } }); } /** - * Called when the LOADER_ID_ACCOUNT_LIST loader loads the data. Update the account spinner - * on the action bar. + * Update the "title" part. */ - private void updateAccountList() { - mAccountsSelectorAdapter.swapCursor(mAccountCursor); + private void updateTitle() { + mAccountsSelectorAdapter.swapCursor(mCursor); - if (mSearchMode == MODE_SEARCH) { - // In search mode, so we don't care about the account list - it'll get updated when - // it goes visible again. + if (mCursor == null) { + // Initial load not finished. + mActionBarCustomView.setVisibility(View.GONE); return; } + mActionBarCustomView.setVisibility(View.VISIBLE); - final ActionBar ab = mActionBar; - if (mAccountCursor == null) { - // Cursor not ready or closed. - ab.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); - ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); - return; - } - - final int count = mAccountCursor.getAccountCount() + mAccountCursor.getRecentMailboxCount(); - if (count == 0) { + if (mCursor.getAccountCount() == 0) { mCallback.onNoAccountsFound(); return; } - // If only one account, don't show the drop down. - int selectedPosition = mAccountCursor.getPosition(mCallback.getUIAccountId()); - if (count == 1) { - // Show the account name as the title. - ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE); - ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); - if (selectedPosition >= 0) { - mAccountCursor.moveToPosition(selectedPosition); - ab.setTitle(AccountSelectorAdapter.getDisplayName(mAccountCursor)); - } + if ((mCursor.getAccountId() != Account.NO_ACCOUNT) && !mCursor.accountExists()) { + // Accoutn specified, but not exists. Switch to the default account. + mCallback.onAccountSelected(Account.getDefaultAccountId(mContext)); + + // STOPSHIP If in search mode, we should close the activity. Probably + // we should jsut call onSearchExit() instead? return; } - // Update the drop down list. - if (ab.getNavigationMode() != ActionBar.NAVIGATION_MODE_LIST) { - ab.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); - ab.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); - ab.setListNavigationCallbacks(mAccountsSelectorAdapter, mActionBarNavigationCallback); + if (mSearchMode == MODE_SEARCH) { + // In search mode, so we don't care about the account list - it'll get updated when + // it goes visible again. + mAccountSpinner.setVisibility(View.GONE); + mSearchContainer.setVisibility(View.VISIBLE); + return; } - // Find the currently selected account, and select it. - if (selectedPosition >= 0) { - ab.setSelectedNavigationItem(selectedPosition); + + final int mTitleMode = mCallback.getTitleMode(); + + // TODO Handle TITLE_MODE_MESSAGE_SUBJECT + + // Account spinner visible. + mAccountSpinner.setVisibility(View.VISIBLE); + mSearchContainer.setVisibility(View.GONE); + + // Get mailbox name + final String mailboxName; + if (mTitleMode == Callback.TITLE_MODE_ACCOUNT_WITH_ALL_FOLDERS_LABEL) { + mailboxName = mAllFoldersLabel; + } else if (mTitleMode == Callback.TITLE_MODE_ACCOUNT_WITH_MAILBOX) { + mailboxName = mCursor.getMailboxDisplayName(); + } else { + mailboxName = null; } - } - private class ActionBarNavigationCallback implements ActionBar.OnNavigationListener { - @Override - public boolean onNavigationItemSelected(int itemPosition, long itemId) { - if (mAccountsSelectorAdapter.isAccountItem(itemPosition) - && itemId != mCallback.getUIAccountId()) { - mCallback.onAccountSelected(itemId); - } else if (mAccountsSelectorAdapter.isMailboxItem(itemPosition)) { - mCallback.onMailboxSelected(itemId); - // We need to update the selection, otherwise the user is unable to select the - // recent folder a second time w/o first selecting another item in the spinner - int selectedPosition = mAccountsSelectorAdapter.getAccountPosition(itemPosition); - if (selectedPosition != AccountSelectorAdapter.UNKNOWN_POSITION) { - mActionBar.setSelectedNavigationItem(selectedPosition); - } - } else { - Log.i(Logging.LOG_TAG, - "Invalid type selected in ActionBarController at index " + itemPosition); - } - return true; + if (TextUtils.isEmpty(mailboxName)) { + mAccountSpinnerLine1View.setText(mCursor.getAccountDisplayName()); + + // Only here we change the visibility of line 2, so line 1 will be vertically-centered. + mAccountSpinnerLine2View.setVisibility(View.GONE); + } else { + mAccountSpinnerLine1View.setText(mailboxName); + mAccountSpinnerLine2View.setVisibility(View.VISIBLE); // Make sure it's visible again. + mAccountSpinnerLine2View.setText(mCursor.getAccountDisplayName()); } - } + mAccountSpinnerCountView.setText(UiUtilities.getMessageCountForUi( + mContext, mCursor.getMailboxMessageCount(), true)); - private static final String[] MAILBOX_NAME_COUNT_PROJECTION = new String[] { - MailboxColumns.ID, MailboxColumns.DISPLAY_NAME, MailboxColumns.TYPE, - MailboxColumns.UNREAD_COUNT, MailboxColumns.MESSAGE_COUNT - }; + boolean spinnerEnabled = (mCursor.getAccountCount() + mCursor.getRecentMailboxCount()) > 1; - private void loadMailboxInfo(final long mailboxId) { - clearMailboxInfo(); - if (mailboxId < 0) { - // TODO FIXME - return; // Can't get combined mailbox name with this + if (spinnerEnabled) { + mAccountSpinner.setClickable(true); + } else { + mAccountSpinner.setClickable(false); + // TODO There's nothing to select -- we should remove the spinner triangle. + // (The small triangle shown at the right bottom corner) } - mLoaderManager.restartLoader(LOADER_ID_MAILBOX, null, - new LoaderCallbacks() { - @Override - public Loader onCreateLoader(int id, Bundle args) { - return new ThrottlingCursorLoader(mContext, - ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId), - MAILBOX_NAME_COUNT_PROJECTION, null, null, null); - } - - @Override - public void onLoadFinished(Loader loader, Cursor cursor) { - if (!cursor.moveToFirst()) { - clearMailboxInfo(); - return; - } - // Update action bar - FolderProperties fp = FolderProperties.getInstance(mContext); - updateMailboxInfo( - fp.getDisplayName(cursor), - fp.getMessageCount(cursor) - ); - } - - @Override - public void onLoaderReset(Loader loader) { - } - }); - } - - private void clearMailboxInfo() { - updateMailboxInfo("", 0); - } - - private void updateMailboxInfo(String mailboxName, int count) { - mMailboxNameView.setText(mailboxName); - mUnreadCountView.setText(UiUtilities.getMessageCountForUi(mContext, count, true)); } private final SearchView.OnQueryTextListener mOnQueryText @@ -475,4 +459,44 @@ public class ActionBarController { } }; + private void onAccountSpinnerItemClicked(int position) { + if (mAccountsSelectorAdapter == null) { // just in case... + return; + } + final long accountId = mAccountsSelectorAdapter.getAccountId(position); + + if (mAccountsSelectorAdapter.isAccountItem(position)) { + mCallback.onAccountSelected(accountId); + } else if (mAccountsSelectorAdapter.isMailboxItem(position)) { + mCallback.onMailboxSelected(accountId, + mAccountsSelectorAdapter.getId(position)); + } + } + + // Based on Spinner.DropdownPopup + private class AccountDropdownPopup extends ListPopupWindow { + public AccountDropdownPopup(Context context) { + super(context); + + setAnchorView(mAccountSpinner); + setModal(true); + setPromptPosition(POSITION_PROMPT_ABOVE); + setOnItemClickListener(new OnItemClickListener() { + public void onItemClick(AdapterView parent, View v, int position, long id) { + onAccountSpinnerItemClicked(position); + dismiss(); + } + }); + } + + @Override + public void show() { + setWidth(mContext.getResources().getDimensionPixelSize( + R.dimen.account_spinner_dropdown_width)); + setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); + super.show(); + // List view is instantiated in super.show(), so we need to do this after... + getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); + } + } } diff --git a/src/com/android/email/activity/MailboxListFragment.java b/src/com/android/email/activity/MailboxListFragment.java index ff50afb0e..08522a150 100644 --- a/src/com/android/email/activity/MailboxListFragment.java +++ b/src/com/android/email/activity/MailboxListFragment.java @@ -190,6 +190,11 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList private long mParentMailboxId; private long mHighlightedMailboxId; + /** + * Becomes {@code true} once we determine which mailbox to use as the parent. + */ + private boolean mParentDetermined; + /** * ID of the mailbox that should be highlighted when the next cursor is loaded. */ @@ -551,7 +556,7 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList /** * @return {@code true} if top-level mailboxes are shown. {@code false} otherwise. */ - public boolean isRoot() { + private boolean isRoot() { return mParentMailboxId == Mailbox.NO_MAILBOX; } @@ -580,6 +585,19 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList return true; } + /** + * @return {@code true} if the fragment is showing nested mailboxes and we can go one level up. + * {@code false} otherwise, meaning we're showing the top level mailboxes *OR* + * we're still loading initial data and we can't determine if we're going to show + * top-level or not. + */ + public boolean canNavigateUp() { + if (!mParentDetermined) { + return false; // We can't determine yet... + } + return !isRoot(); + } + /** * A task to determine what parent mailbox ID/highlighted mailbox ID to use for the "UP" * navigation, given the current parent mailbox ID, the highlighted mailbox ID, and {@link @@ -781,6 +799,8 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList mListAdapter.swapCursor(null); setListShown(false); } else { + mParentDetermined = true; // Okay now we're sure which mailbox is the parent. + mListAdapter.swapCursor(cursor); setListShown(true); diff --git a/src/com/android/email/activity/UIControllerBase.java b/src/com/android/email/activity/UIControllerBase.java index 121cd4cf1..24633ccdd 100644 --- a/src/com/android/email/activity/UIControllerBase.java +++ b/src/com/android/email/activity/UIControllerBase.java @@ -431,12 +431,12 @@ abstract class UIControllerBase implements MailboxListFragment.Callback, /** * Show the default view for the given account. * - * No-op if the given account is already selected. - * * @param accountId ID of the account to load. Can be {@link Account#ACCOUNT_ID_COMBINED_VIEW}. * Must never be {@link Account#NO_ACCOUNT}. + * @param forceShowInbox If {@code false} and the given account is already selected, do nothing. + * If {@code false}, we always change the view even if the account is selected. */ - public final void switchAccount(long accountId) { + public final void switchAccount(long accountId, boolean forceShowInbox) { if (Account.isSecurityHold(mActivity, accountId)) { ActivityHelper.showSecurityHoldDialog(mActivity, accountId); @@ -444,7 +444,7 @@ abstract class UIControllerBase implements MailboxListFragment.Callback, return; } - if (accountId == getUIAccountId()) { + if (accountId == getUIAccountId() && !forceShowInbox) { // Do nothing if the account is already selected. Not even going back to the inbox. return; } diff --git a/src/com/android/email/activity/UIControllerOnePane.java b/src/com/android/email/activity/UIControllerOnePane.java index dd564a340..11cfcfe88 100644 --- a/src/com/android/email/activity/UIControllerOnePane.java +++ b/src/com/android/email/activity/UIControllerOnePane.java @@ -55,7 +55,9 @@ class UIControllerOnePane extends UIControllerBase { // MailboxListFragment.Callback @Override public void onAccountSelected(long accountId) { - switchAccount(accountId); + // It's from combined view, so "forceShowInbox" doesn't really matter. + // (We're always switching accounts.) + switchAccount(accountId, true); } // MailboxListFragment.Callback @@ -94,7 +96,7 @@ class UIControllerOnePane extends UIControllerBase { // MessageListFragment.Callback @Override public void onMailboxNotFound() { - switchAccount(getUIAccountId()); + switchAccount(getUIAccountId(), true); } // MessageListFragment.Callback @@ -202,15 +204,26 @@ class UIControllerOnePane extends UIControllerBase { // This is all temporary as we'll have a different action bar controller for 1-pane. private class ActionBarControllerCallback implements ActionBarController.Callback { @Override - public boolean shouldShowMailboxName() { - return false; // no mailbox name/unread count. + public int getTitleMode() { + if (isMailboxListInstalled()) { + return TITLE_MODE_ACCOUNT_WITH_ALL_FOLDERS_LABEL; + } + // TODO Return TITLE_MODE_MESSAGE_SUBJECT if isMessageViewInstalled() + return TITLE_MODE_ACCOUNT_WITH_MAILBOX; } + public String getMessageSubject() { + if (isMessageViewInstalled()) { + return "TODO: Return current message subject here"; + } else { + return null; + } + } @Override public boolean shouldShowUp() { return isMessageViewInstalled() - || (isMailboxListInstalled() && !getMailboxListFragment().isRoot()); + || (isMailboxListInstalled() && getMailboxListFragment().canNavigateUp()); } @Override @@ -224,11 +237,11 @@ class UIControllerOnePane extends UIControllerBase { } @Override - public void onMailboxSelected(long mailboxId) { + public void onMailboxSelected(long accountId, long mailboxId) { if (mailboxId == Mailbox.NO_MAILBOX) { showAllMailboxes(); } else { - openMailbox(getUIAccountId(), mailboxId); + openMailbox(accountId, mailboxId); } } @@ -239,7 +252,7 @@ class UIControllerOnePane extends UIControllerBase { @Override public void onAccountSelected(long accountId) { - switchAccount(accountId); + switchAccount(accountId, true); // Always go to inbox } @Override @@ -434,7 +447,8 @@ class UIControllerOnePane extends UIControllerBase { */ private void commitFragmentTransaction(FragmentTransaction ft) { if (!ft.isEmpty()) { - ft.commit(); + // STOPSHIP Don't use AllowingStateLoss. See b/4519430 + ft.commitAllowingStateLoss(); mFragmentManager.executePendingTransactions(); } } diff --git a/src/com/android/email/activity/UIControllerTwoPane.java b/src/com/android/email/activity/UIControllerTwoPane.java index f75c7eb37..571763d46 100644 --- a/src/com/android/email/activity/UIControllerTwoPane.java +++ b/src/com/android/email/activity/UIControllerTwoPane.java @@ -44,10 +44,7 @@ import java.util.Set; * so that we can easily switch between synchronous and asynchronous transactions. */ class UIControllerTwoPane extends UIControllerBase implements - ThreePaneLayout.Callback, - MailboxListFragment.Callback, - MessageListFragment.Callback, - MessageViewFragment.Callback { + ThreePaneLayout.Callback { @VisibleForTesting static final int MAILBOX_REFRESH_MIN_INTERVAL = 30 * 1000; // in milliseconds @@ -75,8 +72,6 @@ class UIControllerTwoPane extends UIControllerBase implements // ThreePaneLayoutCallback @Override public void onVisiblePanesChanged(int previousVisiblePanes) { - refreshActionBar(); - // If the right pane is gone, remove the message view. final int visiblePanes = mThreePane.getVisiblePanes(); @@ -89,6 +84,7 @@ class UIControllerTwoPane extends UIControllerBase implements if (isMessageListInstalled()) { getMessageListFragment().onHidden((visiblePanes & ThreePaneLayout.PANE_MIDDLE) == 0); } + refreshActionBar(); } // MailboxListFragment$Callback @@ -103,7 +99,9 @@ class UIControllerTwoPane extends UIControllerBase implements // MailboxListFragment$Callback @Override public void onAccountSelected(long accountId) { - switchAccount(accountId); + // It's from combined view, so "forceShowInbox" doesn't really matter. + // (We're always switching accounts.) + switchAccount(accountId, true); } // MailboxListFragment$Callback @@ -427,7 +425,8 @@ class UIControllerTwoPane extends UIControllerBase implements Log.d(Logging.LOG_TAG, this + " commitFragmentTransaction: " + ft); } if (!ft.isEmpty()) { - ft.commit(); + // STOPSHIP Don't use AllowingStateLoss. See b/4519430 + ft.commitAllowingStateLoss(); mFragmentManager.executePendingTransactions(); } } @@ -818,12 +817,12 @@ class UIControllerTwoPane extends UIControllerBase implements @Override public void onAccountSelected(long accountId) { - switchAccount(accountId); + switchAccount(accountId, false); } @Override - public void onMailboxSelected(long mailboxId) { - openMailbox(getUIAccountId(), mailboxId); + public void onMailboxSelected(long accountId, long mailboxId) { + openMailbox(accountId, mailboxId); } @Override @@ -833,9 +832,32 @@ class UIControllerTwoPane extends UIControllerBase implements } @Override - public boolean shouldShowMailboxName() { - // Show when the left pane is hidden. - return (mThreePane.getVisiblePanes() & ThreePaneLayout.PANE_LEFT) == 0; + public int getTitleMode() { + final int visiblePanes = mThreePane.getVisiblePanes(); + if ((mThreePane.getVisiblePanes() & ThreePaneLayout.PANE_LEFT) != 0) { + // Mailbox list visible + return TITLE_MODE_ACCOUNT_NAME_ONLY; + } + if ((mThreePane.getVisiblePanes() & ThreePaneLayout.PANE_MIDDLE) != 0) { + // Message list + message view + return TITLE_MODE_ACCOUNT_WITH_MAILBOX; + } + if ((mThreePane.getVisiblePanes() & ThreePaneLayout.PANE_RIGHT) != 0) { + // Message view only (message list collapsed) + // TODO return TITLE_MODE_MESSAGE_SUBJECT + return TITLE_MODE_ACCOUNT_WITH_MAILBOX; + } + + // Shouldn't happen, but just in case + return TITLE_MODE_ACCOUNT_NAME_ONLY; + } + + public String getMessageSubject() { + if (isMessageViewInstalled()) { + return "TODO: Return current message subject here"; + } else { + return null; + } } @Override @@ -843,7 +865,7 @@ class UIControllerTwoPane extends UIControllerBase implements final int visiblePanes = mThreePane.getVisiblePanes(); final boolean leftPaneHidden = ((visiblePanes & ThreePaneLayout.PANE_LEFT) == 0); return leftPaneHidden - || (isMailboxListInstalled() && !getMailboxListFragment().isRoot()); + || (isMailboxListInstalled() && getMailboxListFragment().canNavigateUp()); } @Override diff --git a/tests/src/com/android/email/activity/AccountSelectorAdapterAccountsLoaderTest.java b/tests/src/com/android/email/activity/AccountSelectorAdapterAccountsLoaderTest.java index 97b0a6712..16e258ad7 100644 --- a/tests/src/com/android/email/activity/AccountSelectorAdapterAccountsLoaderTest.java +++ b/tests/src/com/android/email/activity/AccountSelectorAdapterAccountsLoaderTest.java @@ -52,7 +52,7 @@ public class AccountSelectorAdapterAccountsLoaderTest extends LoaderTestCase { { // Only 1 account -- no combined view row. Loader l = new AccountSelectorAdapter.AccountsLoader(mProviderContext, 0L, - true); + 0L, true); AccountSelectorAdapter.CursorWithExtras result = (AccountSelectorAdapter.CursorWithExtras) getLoaderResultSynchronously(l); assertEquals(1, result.getAccountCount()); @@ -64,7 +64,7 @@ public class AccountSelectorAdapterAccountsLoaderTest extends LoaderTestCase { { // 2 accounts -- with combined view row, so returns 3 account rows. Loader l = new AccountSelectorAdapter.AccountsLoader(mProviderContext, 0L, - true); + 0L, true); AccountSelectorAdapter.CursorWithExtras result = (AccountSelectorAdapter.CursorWithExtras) getLoaderResultSynchronously(l); assertEquals(3, result.getAccountCount());