New account spinner

- Don't use the action bar spinner.
  Instead use a custom view to show the current account.
  (It's not a spinner; now we show the dropdown list by ourselves,
  which gives us more detailed control.)

- Also show the current mailbox name/unread count with the account name.

- Removed the mailbox info loader in ABC.
  Instead, now the AccountSelectorAdapter loader loads the current
  account/mailbox name, and the unread count as extras.

- Now ABC.Callback.onMailboxSelected passed an account ID as well
  as a mailbox ID.

- There's new code paths that can cause the "fragment transaction in
  onLoadFinished" exception.  We need to fix this properly, but
  for now we just use commitAllowingStateLoss().

Bug 4948352

Change-Id: I73bb8b7530f8328ca1c86382ac0a54086ad061d7
This commit is contained in:
Makoto Onuki 2011-06-26 17:15:12 -07:00
parent ad6c48b2d3
commit 4689cb7100
16 changed files with 561 additions and 365 deletions

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!--
TextView for the collapsed account spinner.
TODO: Need to widen maxWidth dynamically when the mailbox name isn't shown
on the action bar.
-->
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/display_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="@dimen/action_bar_account_name_max_width"
style="@style/action_bar_account_name"
/>

View File

@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/action_bar_mailbox_name_left_margin"
android:orientation="horizontal"
>
<TextView
android:id="@+id/mailbox_name"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:maxWidth="@dimen/action_bar_mailbox_name_max_width"
android:textSize="18dp"
android:textColor="@color/text_ternary_color"
android:singleLine="true"
android:ellipsize="end"
android:gravity="left|center"
/>
<TextView
android:id="@+id/unread_count"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_marginLeft="16dp"
style="@style/action_bar_unread_count"
android:gravity="center"
/>
</LinearLayout>

View File

@ -26,8 +26,8 @@
android:layout_height="0dip"
>
<include
android:id="@+id/current_mailbox_container"
layout="@layout/action_bar_current_mailbox"
android:id="@+id/account_spinner"
layout="@layout/action_bar_spinner"
android:visibility="gone"
/>
<include

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2011 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/account_spinner_width"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:orientation="horizontal"
style="@android:style/Widget.Holo.Spinner"
>
<LinearLayout
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:orientation="vertical"
>
<TextView
android:id="@+id/spinner_line_1"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:textSize="16dip"
android:textColor="@color/text_primary_color"
android:singleLine="true"
android:ellipsize="end"
android:gravity="left|center_vertical"
/>
<TextView
android:id="@+id/spinner_line_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12dip"
android:textColor="@color/text_primary_color"
android:singleLine="true"
android:ellipsize="end"
android:gravity="left|center_vertical"
/>
</LinearLayout>
<TextView
android:id="@+id/spinner_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dip"
android:textSize="16dip"
android:textColor="@color/text_primary_color"
android:singleLine="true"
android:ellipsize="none"
android:gravity="center"
/>
</LinearLayout>

View File

@ -17,6 +17,8 @@
<!--
Not a RelativeLayout - we want to hide @id/email_address at runtime and then @id/display_name
should be center-vertical
Popup width is set at runtime from @dimen/account_spinner_dropdown_width
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
@ -25,12 +27,11 @@
android:orientation="horizontal"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:maxWidth="@dimen/account_spinner_dropdown_account_name_max_width"
android:orientation="vertical"
android:gravity="center|left"
>
@ -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"
/>
<TextView
android:id="@+id/email_address"
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_secondary"
/>
</LinearLayout>

View File

@ -53,7 +53,8 @@
<dimen name="setup_item_inset_left">0dip</dimen>
<dimen name="setup_item_inset_right">0dip</dimen>
<dimen name="account_spinner_dropdown_account_name_max_width">352dip</dimen>
<dimen name="account_spinner_width">250dip</dimen>
<dimen name="account_spinner_dropdown_width">300dip</dimen>
<!-- MessageListItem -->
<dimen name="senders_font_size">14sp</dimen>

View File

@ -1153,6 +1153,9 @@ save attachment.</string>
<!-- The hint used in the search box when searching a single mailbox [CHAR LIMIT=35] -->
<string name="search_mailbox_hint">Search <xliff:g example="Inbox">%1$s</xliff:g></string>
<!-- Title shown on the action bar on the mailbox list screen. [CHAR LIMIT=16] -->
<string name="action_bar_mailbox_list_title">Folders</string>
<!-- STOPSHIP Temporary UI DO NOT TRANSLATE-->
<!-- In Mailbox setings, label for email check frequency selector -->
<string name="mailbox_options_check_frequency_label">Folder check frequency</string>

View File

@ -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

View File

@ -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<Cursor> createLoader(Context context, long accountId) {
return new AccountsLoader(context, accountId, UiUtilities.useTwoPane(context));
public static Loader<Cursor> 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:
* <ol>
* <li>headers</li>
@ -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;
}
}
}

View File

@ -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<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return AccountSelectorAdapter.createLoader(mContext, mCallback.getUIAccountId());
return AccountSelectorAdapter.createLoader(mContext, accountId, mailboxId);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAccountCursor = (AccountSelectorAdapter.CursorWithExtras) data;
updateAccountList();
mCursor = (AccountSelectorAdapter.CursorWithExtras) data;
updateTitle();
}
@Override
public void onLoaderReset(Loader<Cursor> 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<Cursor>() {
@Override
public Loader<Cursor> 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<Cursor> 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<Cursor> 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);
}
}
}

View File

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

View File

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

View File

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

View File

@ -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

View File

@ -52,7 +52,7 @@ public class AccountSelectorAdapterAccountsLoaderTest extends LoaderTestCase {
{
// Only 1 account -- no combined view row.
Loader<Cursor> 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<Cursor> l = new AccountSelectorAdapter.AccountsLoader(mProviderContext, 0L,
true);
0L, true);
AccountSelectorAdapter.CursorWithExtras result =
(AccountSelectorAdapter.CursorWithExtras) getLoaderResultSynchronously(l);
assertEquals(3, result.getAccountCount());