Add "Accounts" header to the AB spinner
Change-Id: I35e4b7295db16db803ede084cf65fa3f2115f770
This commit is contained in:
parent
49e424c60f
commit
69461503fb
20
res/layout/account_selector_dropdown_header.xml
Normal file
20
res/layout/account_selector_dropdown_header.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/display_name"
|
||||
android:ellipsize="end"
|
||||
style="?android:attr/listSeparatorTextViewStyle" />
|
@ -172,7 +172,6 @@
|
||||
<item quantity="other"><xliff:g id="unread_message_count" example="279">%1$d</xliff:g> unread (<xliff:g id="account">%2$s</xliff:g>)</item>
|
||||
</plurals>
|
||||
|
||||
|
||||
<!-- Notification message in notifications window when 2+ accounts have new mail; e.g, "in 3 accounts". -->
|
||||
<plurals name="notification_new_multi_account_fmt">
|
||||
<!-- Case of "few" (small number of) accounts with unread messages. -->
|
||||
@ -275,6 +274,8 @@
|
||||
<!-- Label shown in the account/mailbox selector to switch to the show all the top-level
|
||||
mailboxes. [CHAR LIMIT=30] -->
|
||||
<string name="mailbox_list_account_selector_show_all_folders">Show all folders</string>
|
||||
<!-- Account list header in the account/mailbox selector. [CHAR LIMIT=30] -->
|
||||
<string name="mailbox_list_account_selector_account_header">Accounts</string>
|
||||
|
||||
<!-- Appears at the bottom of list of messages; user selects to load more messages from that folder. -->
|
||||
<string name="message_list_load_more_messages_action">Load more messages</string>
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.email.activity;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
import com.android.email.R;
|
||||
import com.android.email.data.ClosingMatrixCursor;
|
||||
import com.android.email.data.ThrottlingCursorLoader;
|
||||
@ -28,47 +30,52 @@ import android.content.Context;
|
||||
import android.content.Loader;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.database.MatrixCursor.RowBuilder;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.CursorAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* Adapter for the account selector on {@link UIControllerTwoPane}.
|
||||
* Account selector spinner.
|
||||
*
|
||||
* TODO Test it!
|
||||
*/
|
||||
public class AccountSelectorAdapter extends CursorAdapter {
|
||||
/** Projection used to query from Account */
|
||||
/** meta data column for an account's unread count */
|
||||
private static final String UNREAD_COUNT = "unreadCount";
|
||||
/** meta data column for the row type; used for display purposes */
|
||||
private static final String ROW_TYPE = "rowType";
|
||||
private static final int ROW_TYPE_HEADER = AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
|
||||
@SuppressWarnings("unused")
|
||||
private static final int ROW_TYPE_MAILBOX = 0;
|
||||
private static final int ROW_TYPE_ACCOUNT = 1;
|
||||
private static final int ITEM_VIEW_TYPE_ACCOUNT = 0;
|
||||
/** Projection for account database query */
|
||||
private static final String[] ACCOUNT_PROJECTION = new String[] {
|
||||
EmailContent.RECORD_ID,
|
||||
EmailContent.Account.DISPLAY_NAME,
|
||||
EmailContent.Account.EMAIL_ADDRESS,
|
||||
Account.ID,
|
||||
Account.DISPLAY_NAME,
|
||||
Account.EMAIL_ADDRESS,
|
||||
};
|
||||
|
||||
/**
|
||||
* Projection for the resulting MatrixCursor -- must be {@link #ACCOUNT_PROJECTION}
|
||||
* with "UNREAD_COUNT".
|
||||
* Projection used for the selector display; we add meta data that doesn't exist in the
|
||||
* account database, so, this should be a super-set of {@link #ACCOUNT_PROJECTION}.
|
||||
*/
|
||||
private static final String[] RESULT_PROJECTION = new String[] {
|
||||
EmailContent.RECORD_ID,
|
||||
EmailContent.Account.DISPLAY_NAME,
|
||||
EmailContent.Account.EMAIL_ADDRESS,
|
||||
"UNREAD_COUNT"
|
||||
private static final String[] ADAPTER_PROJECTION = new String[] {
|
||||
ROW_TYPE,
|
||||
Account.ID,
|
||||
Account.DISPLAY_NAME,
|
||||
Account.EMAIL_ADDRESS,
|
||||
UNREAD_COUNT,
|
||||
};
|
||||
|
||||
private static final int ID_COLUMN = 0;
|
||||
private static final int DISPLAY_NAME_COLUMN = 1;
|
||||
private static final int EMAIL_ADDRESS_COLUMN = 2;
|
||||
private static final int UNREAD_COUNT_COLUMN = 3;
|
||||
|
||||
/** Sort order. Show the default account first. */
|
||||
private static final String ORDER_BY =
|
||||
EmailContent.Account.IS_DEFAULT + " desc, " + EmailContent.Account.RECORD_ID;
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
@SuppressWarnings("hiding")
|
||||
private final Context mContext;
|
||||
|
||||
public static Loader<Cursor> createLoader(Context context) {
|
||||
@ -83,27 +90,37 @@ public class AccountSelectorAdapter extends CursorAdapter {
|
||||
|
||||
@Override
|
||||
public View getDropDownView(int position, View convertView, ViewGroup parent) {
|
||||
final View view = mInflater.inflate(R.layout.account_selector_dropdown, parent, false);
|
||||
Cursor c = getCursor();
|
||||
c.moveToPosition(position);
|
||||
|
||||
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 = getAccountDisplayName(position);
|
||||
final String emailAddress = getAccountEmailAddress(position);
|
||||
|
||||
displayNameView.setText(displayName);
|
||||
|
||||
// Show the email address only when it's different from the display name.
|
||||
if (emailAddress.equals(displayName)) {
|
||||
emailAddressView.setVisibility(View.GONE);
|
||||
View view;
|
||||
if (c.getInt(c.getColumnIndex(ROW_TYPE)) == ROW_TYPE_HEADER) {
|
||||
view = mInflater.inflate(R.layout.account_selector_dropdown_header, parent, false);
|
||||
final TextView displayNameView = (TextView) view.findViewById(R.id.display_name);
|
||||
final String displayName = getAccountDisplayName(c);
|
||||
displayNameView.setText(displayName);
|
||||
} else {
|
||||
emailAddressView.setVisibility(View.VISIBLE);
|
||||
emailAddressView.setText(emailAddress);
|
||||
}
|
||||
view = mInflater.inflate(R.layout.account_selector_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);
|
||||
|
||||
unreadCountView.setText(UiUtilities.getMessageCountForUi(mContext,
|
||||
getAccountUnreadCount(position), false));
|
||||
final String displayName = getAccountDisplayName(position);
|
||||
final String emailAddress = getAccountEmailAddress(position);
|
||||
|
||||
displayNameView.setText(displayName);
|
||||
|
||||
// Show the email address only when it's different from the display name.
|
||||
if (displayName.equals(emailAddress)) {
|
||||
emailAddressView.setVisibility(View.GONE);
|
||||
} else {
|
||||
emailAddressView.setVisibility(View.VISIBLE);
|
||||
emailAddressView.setText(emailAddress);
|
||||
}
|
||||
|
||||
unreadCountView.setText(UiUtilities.getMessageCountForUi(mContext,
|
||||
getAccountUnreadCount(position), false));
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
@ -118,9 +135,29 @@ public class AccountSelectorAdapter extends CursorAdapter {
|
||||
return mInflater.inflate(R.layout.account_selector, parent, false);
|
||||
}
|
||||
|
||||
/** @return Account id extracted from a Cursor. */
|
||||
public static long getAccountId(Cursor c) {
|
||||
return c.getLong(ID_COLUMN);
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
Cursor c = getCursor();
|
||||
c.moveToPosition(position);
|
||||
return c.getLong(c.getColumnIndex(ROW_TYPE)) == ROW_TYPE_HEADER
|
||||
? AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER
|
||||
: ITEM_VIEW_TYPE_ACCOUNT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
return (getItemViewType(position) != AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER);
|
||||
}
|
||||
|
||||
public boolean isAccountItem(int position) {
|
||||
Cursor c = getCursor();
|
||||
c.moveToPosition(position);
|
||||
return (c.getLong(c.getColumnIndex(ROW_TYPE)) == ROW_TYPE_ACCOUNT);
|
||||
}
|
||||
|
||||
private String getAccountDisplayName(int position) {
|
||||
@ -138,19 +175,24 @@ public class AccountSelectorAdapter extends CursorAdapter {
|
||||
return c.moveToPosition(position) ? getAccountUnreadCount(c) : 0;
|
||||
}
|
||||
|
||||
/** @return Account name extracted from a Cursor. */
|
||||
public static String getAccountDisplayName(Cursor cursor) {
|
||||
return cursor.getString(DISPLAY_NAME_COLUMN);
|
||||
/** Returns the account ID extracted from the given cursor. */
|
||||
static long getAccountId(Cursor c) {
|
||||
return c.getLong(c.getColumnIndex(Account.ID));
|
||||
}
|
||||
|
||||
/** @return Email address extracted from a Cursor. */
|
||||
public static String getAccountEmailAddress(Cursor cursor) {
|
||||
return cursor.getString(EMAIL_ADDRESS_COLUMN);
|
||||
/** Returns the account name extracted from the given cursor. */
|
||||
static String getAccountDisplayName(Cursor cursor) {
|
||||
return cursor.getString(cursor.getColumnIndex(Account.DISPLAY_NAME));
|
||||
}
|
||||
|
||||
/** @return Unread count extracted from a Cursor. */
|
||||
public static int getAccountUnreadCount(Cursor cursor) {
|
||||
return cursor.getInt(UNREAD_COUNT_COLUMN);
|
||||
/** Returns the email address extracted from the given cursor. */
|
||||
private static String getAccountEmailAddress(Cursor cursor) {
|
||||
return cursor.getString(cursor.getColumnIndex(Account.EMAIL_ADDRESS));
|
||||
}
|
||||
|
||||
/** Returns the unread count extracted from the given cursor. */
|
||||
private static int getAccountUnreadCount(Cursor cursor) {
|
||||
return cursor.getInt(cursor.getColumnIndex(UNREAD_COUNT));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,7 +201,8 @@ public class AccountSelectorAdapter extends CursorAdapter {
|
||||
* - # of unread messages in inbox
|
||||
* - The "Combined view" row if there's more than one account.
|
||||
*/
|
||||
/* package */ static class AccountsLoader extends ThrottlingCursorLoader {
|
||||
@VisibleForTesting
|
||||
static class AccountsLoader extends ThrottlingCursorLoader {
|
||||
private final Context mContext;
|
||||
|
||||
public AccountsLoader(Context context) {
|
||||
@ -171,44 +214,51 @@ public class AccountSelectorAdapter extends CursorAdapter {
|
||||
|
||||
@Override
|
||||
public Cursor loadInBackground() {
|
||||
// Fetch account list
|
||||
final Cursor accountsCursor = super.loadInBackground();
|
||||
|
||||
// Cursor that's actually returned.
|
||||
// Use ClosingMatrixCursor so that accountsCursor gets closed too when it's closed.
|
||||
final MatrixCursor resultCursor = new ClosingMatrixCursor(RESULT_PROJECTION,
|
||||
accountsCursor);
|
||||
accountsCursor.moveToPosition(-1);
|
||||
final MatrixCursor resultCursor
|
||||
= new ClosingMatrixCursor(ADAPTER_PROJECTION, accountsCursor);
|
||||
addAccountsToCursor(resultCursor, accountsCursor);
|
||||
// TODO Add mailbox recent list to the end of the return cursor
|
||||
return Utility.CloseTraceCursorWrapper.get(resultCursor);
|
||||
}
|
||||
|
||||
// Build the cursor...
|
||||
/** Adds the account list [with extra meta data] to the given matrix cursor */
|
||||
private void addAccountsToCursor(MatrixCursor matrixCursor, Cursor accountCursor) {
|
||||
accountCursor.moveToPosition(-1);
|
||||
// Add a header for the accounts
|
||||
matrixCursor.newRow()
|
||||
.add(ROW_TYPE_HEADER)
|
||||
.add(0L)
|
||||
.add(mContext.getString(R.string.mailbox_list_account_selector_account_header))
|
||||
.add(null)
|
||||
.add(0L);
|
||||
int totalUnread = 0;
|
||||
while (accountsCursor.moveToNext()) {
|
||||
while (accountCursor.moveToNext()) {
|
||||
// Add account, with its unread count.
|
||||
final long accountId = accountsCursor.getLong(0);
|
||||
final long accountId = accountCursor.getLong(0);
|
||||
final int unread = Mailbox.getUnreadCountByAccountAndMailboxType(
|
||||
mContext, accountId, Mailbox.TYPE_INBOX);
|
||||
|
||||
RowBuilder rb = resultCursor.newRow();
|
||||
rb.add(accountId);
|
||||
rb.add(getAccountDisplayName(accountsCursor));
|
||||
rb.add(getAccountEmailAddress(accountsCursor));
|
||||
rb.add(unread);
|
||||
matrixCursor.newRow()
|
||||
.add(ROW_TYPE_ACCOUNT)
|
||||
.add(accountId)
|
||||
.add(getAccountDisplayName(accountCursor))
|
||||
.add(getAccountEmailAddress(accountCursor))
|
||||
.add(unread);
|
||||
totalUnread += unread;
|
||||
}
|
||||
// Add "combined view"
|
||||
final int countAccounts = resultCursor.getCount();
|
||||
// Add "combined view" if more than one account exists
|
||||
final int countAccounts = matrixCursor.getCount();
|
||||
if (countAccounts > 1) {
|
||||
RowBuilder rb = resultCursor.newRow();
|
||||
|
||||
// Add ID, display name, # of accounts, total unread count.
|
||||
rb.add(Account.ACCOUNT_ID_COMBINED_VIEW);
|
||||
rb.add(mContext.getResources().getString(
|
||||
R.string.mailbox_list_account_selector_combined_view));
|
||||
rb.add(mContext.getResources().getQuantityString(R.plurals.number_of_accounts,
|
||||
countAccounts, countAccounts));
|
||||
rb.add(totalUnread);
|
||||
matrixCursor.newRow()
|
||||
.add(ROW_TYPE_ACCOUNT)
|
||||
.add(Account.ACCOUNT_ID_COMBINED_VIEW)
|
||||
.add(mContext.getResources().getString(
|
||||
R.string.mailbox_list_account_selector_combined_view))
|
||||
.add(mContext.getResources().getQuantityString(R.plurals.number_of_accounts,
|
||||
countAccounts, countAccounts))
|
||||
.add(totalUnread);
|
||||
}
|
||||
return Utility.CloseTraceCursorWrapper.get(resultCursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.R;
|
||||
import com.android.emailcommon.Logging;
|
||||
import com.android.emailcommon.provider.EmailContent.Account;
|
||||
|
||||
import android.app.ActionBar;
|
||||
@ -50,7 +49,9 @@ public class ActionBarController {
|
||||
new ActionBarNavigationCallback();
|
||||
|
||||
private final AccountSelectorAdapter mAccountsSelectorAdapter;
|
||||
private Cursor mAccountsSelectorCursor;
|
||||
private Cursor mAccountCursor;
|
||||
/** The current account ID; used to determine if the account has changed. */
|
||||
private long mLastAccountIdForDirtyCheck = -1;
|
||||
|
||||
public final Callback mCallback;
|
||||
|
||||
@ -123,12 +124,7 @@ public class ActionBarController {
|
||||
refresh();
|
||||
}
|
||||
|
||||
/** Used only in {@link #refresh()} to determine if the account has changed. */
|
||||
private long mLastAccountIdForDirtyCheck = -1;
|
||||
|
||||
/**
|
||||
* Refresh the content.
|
||||
*/
|
||||
/** Refreshes the action bar display. */
|
||||
public void refresh() {
|
||||
mActionBar.setDisplayOptions(mCallback.shouldShowUp()
|
||||
? ActionBar.DISPLAY_HOME_AS_UP : 0, ActionBar.DISPLAY_HOME_AS_UP);
|
||||
@ -146,6 +142,7 @@ public class ActionBarController {
|
||||
// Update the account list only when the account has changed.
|
||||
if (mLastAccountIdForDirtyCheck != mCallback.getUIAccountId()) {
|
||||
mLastAccountIdForDirtyCheck = mCallback.getUIAccountId();
|
||||
// TODO Need to do this all the time as the recent list is shown here
|
||||
updateAccountList();
|
||||
}
|
||||
}
|
||||
@ -163,13 +160,13 @@ public class ActionBarController {
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||
mAccountsSelectorCursor = data;
|
||||
mAccountCursor = data;
|
||||
updateAccountList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) {
|
||||
mAccountsSelectorCursor = null;
|
||||
mAccountCursor = null;
|
||||
updateAccountList();
|
||||
}
|
||||
});
|
||||
@ -180,10 +177,10 @@ public class ActionBarController {
|
||||
* on the action bar.
|
||||
*/
|
||||
private void updateAccountList() {
|
||||
mAccountsSelectorAdapter.swapCursor(mAccountsSelectorCursor);
|
||||
mAccountsSelectorAdapter.swapCursor(mAccountCursor);
|
||||
|
||||
final ActionBar ab = mActionBar;
|
||||
if (mAccountsSelectorCursor == null) {
|
||||
if (mAccountCursor == null) {
|
||||
// Cursor not ready or closed.
|
||||
mAccountsSelectorAdapter.swapCursor(null);
|
||||
ab.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
|
||||
@ -191,7 +188,7 @@ public class ActionBarController {
|
||||
return;
|
||||
}
|
||||
|
||||
final int count = mAccountsSelectorCursor.getCount();
|
||||
final int count = mAccountCursor.getCount();
|
||||
if (count == 0) {
|
||||
mCallback.onNoAccountsFound();
|
||||
return;
|
||||
@ -199,12 +196,12 @@ public class ActionBarController {
|
||||
|
||||
// If only one acount, don't show the dropdown.
|
||||
if (count == 1) {
|
||||
mAccountsSelectorCursor.moveToFirst();
|
||||
mAccountCursor.moveToFirst();
|
||||
|
||||
// Show the account name as the title.
|
||||
ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE);
|
||||
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
|
||||
ab.setTitle(AccountSelectorAdapter.getAccountDisplayName(mAccountsSelectorCursor));
|
||||
ab.setTitle(AccountSelectorAdapter.getAccountDisplayName(mAccountCursor));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -212,10 +209,10 @@ public class ActionBarController {
|
||||
int defaultSelection = 0;
|
||||
if (mCallback.isAccountSelected()) {
|
||||
final long accountId = mCallback.getUIAccountId();
|
||||
mAccountsSelectorCursor.moveToPosition(-1);
|
||||
mAccountCursor.moveToPosition(-1);
|
||||
int i = 0;
|
||||
while (mAccountsSelectorCursor.moveToNext()) {
|
||||
if (accountId == AccountSelectorAdapter.getAccountId(mAccountsSelectorCursor)) {
|
||||
while (mAccountCursor.moveToNext()) {
|
||||
if (accountId == AccountSelectorAdapter.getAccountId(mAccountCursor)) {
|
||||
defaultSelection = i;
|
||||
break;
|
||||
}
|
||||
@ -234,9 +231,12 @@ public class ActionBarController {
|
||||
|
||||
private class ActionBarNavigationCallback implements ActionBar.OnNavigationListener {
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(int itemPosition, long accountId) {
|
||||
if (accountId != mCallback.getUIAccountId()) {
|
||||
mCallback.onAccountSelected(accountId);
|
||||
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
|
||||
if (mAccountsSelectorAdapter.isAccountItem(itemPosition)
|
||||
&& itemId != mCallback.getUIAccountId()) {
|
||||
mCallback.onAccountSelected(itemId);
|
||||
} else {
|
||||
// TODO handle mailbox item
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user