Home | History | Annotate | Download | only in activity
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.email.activity;
     18 
     19 import android.content.ContentResolver;
     20 import android.content.ContentUris;
     21 import android.content.Context;
     22 import android.content.Loader;
     23 import android.database.Cursor;
     24 import android.database.MatrixCursor;
     25 import android.view.LayoutInflater;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.widget.AdapterView;
     29 import android.widget.CursorAdapter;
     30 import android.widget.TextView;
     31 
     32 import com.android.email.FolderProperties;
     33 import com.android.email.R;
     34 import com.android.email.ResourceHelper;
     35 import com.android.email.data.ClosingMatrixCursor;
     36 import com.android.email.data.ThrottlingCursorLoader;
     37 import com.android.emailcommon.provider.Account;
     38 import com.android.emailcommon.provider.EmailContent;
     39 import com.android.emailcommon.provider.EmailContent.AccountColumns;
     40 import com.android.emailcommon.provider.EmailContent.MailboxColumns;
     41 import com.android.emailcommon.provider.Mailbox;
     42 import com.android.emailcommon.utility.Utility;
     43 import com.google.common.annotations.VisibleForTesting;
     44 import com.google.common.base.Preconditions;
     45 
     46 import java.util.ArrayList;
     47 import java.util.Collection;
     48 
     49 /**
     50  * Account selector spinner.
     51  *
     52  * TODO Test it!
     53  */
     54 public class AccountSelectorAdapter extends CursorAdapter {
     55     /** meta data column for an message count (unread or total, depending on row) */
     56     private static final String MESSAGE_COUNT = "unreadCount";
     57 
     58     /** meta data column for the row type; used for display purposes */
     59     private static final String ROW_TYPE = "rowType";
     60 
     61     /** meta data position of the currently selected account in the drop-down list */
     62     private static final String ACCOUNT_POSITION = "accountPosition";
     63 
     64     /** "account id" virtual column name for the matrix cursor */
     65     private static final String ACCOUNT_ID = "accountId";
     66 
     67     private static final int ROW_TYPE_HEADER = AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
     68     @SuppressWarnings("unused")
     69     private static final int ROW_TYPE_MAILBOX = 0;
     70     private static final int ROW_TYPE_ACCOUNT = 1;
     71     private static final int ITEM_VIEW_TYPE_ACCOUNT = 0;
     72     static final int UNKNOWN_POSITION = -1;
     73     /** Projection for account database query */
     74     private static final String[] ACCOUNT_PROJECTION = new String[] {
     75         EmailContent.RECORD_ID,
     76         Account.DISPLAY_NAME,
     77         Account.EMAIL_ADDRESS,
     78     };
     79     /**
     80      * Projection used for the selector display; we add meta data that doesn't exist in the
     81      * account database, so, this should be a super-set of {@link #ACCOUNT_PROJECTION}.
     82      */
     83     private static final String[] ADAPTER_PROJECTION = new String[] {
     84         ROW_TYPE,
     85         EmailContent.RECORD_ID,
     86         Account.DISPLAY_NAME,
     87         Account.EMAIL_ADDRESS,
     88         MESSAGE_COUNT,
     89         ACCOUNT_POSITION, // TODO Probably we don't really need this
     90         ACCOUNT_ID,
     91     };
     92 
     93     /** Sort order.  Show the default account first. */
     94     private static final String ORDER_BY = Account.IS_DEFAULT + " desc, " + Account.RECORD_ID;
     95 
     96     @SuppressWarnings("hiding")
     97     private final Context mContext;
     98     private final LayoutInflater mInflater;
     99     private final ResourceHelper mResourceHelper;
    100 
    101     /**
    102      * Returns a loader that can populate the account spinner.
    103      * @param context a context
    104      * @param accountId the ID of the currently viewed account
    105      */
    106     public static Loader<Cursor> createLoader(Context context, long accountId, long mailboxId) {
    107         return new AccountsLoader(context, accountId, mailboxId, UiUtilities.useTwoPane(context));
    108     }
    109 
    110     public AccountSelectorAdapter(Context context) {
    111         super(context, null, 0 /* no auto-requery */);
    112         mContext = context;
    113         mInflater = LayoutInflater.from(context);
    114         mResourceHelper = ResourceHelper.getInstance(context);
    115     }
    116 
    117     /**
    118      * {@inheritDoc}
    119      *
    120      * The account selector view can contain one of four types of row data:
    121      * <ol>
    122      * <li>headers</li>
    123      * <li>accounts</li>
    124      * <li>recent mailboxes</li>
    125      * <li>"show all folders"</li>
    126      * </ol>
    127      * Headers are handled separately as they have a unique layout and cannot be interacted with.
    128      * Accounts, recent mailboxes and "show all folders" all have the same interaction model and
    129      * share a very similar layout. The single difference is that both accounts and recent
    130      * mailboxes display an unread count; whereas "show all folders" does not. To determine
    131      * if a particular row is "show all folders" verify that a) it's not an account row and
    132      * b) it's ID is {@link Mailbox#NO_MAILBOX}.
    133      *
    134      * TODO Use recycled views.  ({@link #getViewTypeCount} and {@link #getItemViewType})
    135      */
    136     @Override
    137     public View getView(int position, View convertView, ViewGroup parent) {
    138         Cursor c = getCursor();
    139         c.moveToPosition(position);
    140         View view;
    141         if (c.getInt(c.getColumnIndex(ROW_TYPE)) == ROW_TYPE_HEADER) {
    142             view = mInflater.inflate(R.layout.action_bar_spinner_dropdown_header, parent, false);
    143             final TextView displayNameView = (TextView) view.findViewById(R.id.display_name);
    144             final String displayName = getDisplayName(c);
    145             displayNameView.setText(displayName);
    146         } else {
    147             view = mInflater.inflate(R.layout.action_bar_spinner_dropdown, parent, false);
    148             final TextView displayNameView = (TextView) view.findViewById(R.id.display_name);
    149             final TextView emailAddressView = (TextView) view.findViewById(R.id.email_address);
    150             final TextView unreadCountView = (TextView) view.findViewById(R.id.unread_count);
    151             final View chipView = view.findViewById(R.id.color_chip);
    152 
    153             final String displayName = getDisplayName(c);
    154             final String emailAddress = getAccountEmailAddress(c);
    155 
    156             displayNameView.setText(displayName);
    157 
    158             // Show the email address only when it's different from the display name.
    159             boolean isAccount = isAccountItem(c);
    160             if (displayName.equals(emailAddress) || !isAccount) {
    161                 emailAddressView.setVisibility(View.GONE);
    162             } else {
    163                 emailAddressView.setVisibility(View.VISIBLE);
    164                 emailAddressView.setText(emailAddress);
    165             }
    166 
    167             long id = getId(c);
    168             if (isAccount || id != Mailbox.NO_MAILBOX) {
    169                 unreadCountView.setVisibility(View.VISIBLE);
    170                 unreadCountView.setText(UiUtilities.getMessageCountForUi(mContext,
    171                         getAccountUnreadCount(c), true));
    172 
    173                 // If we're on a combined account, show the color chip indicators for all real
    174                 // accounts so it can be used as a legend.
    175                 boolean isCombinedActive =
    176                         ((CursorWithExtras) c).getAccountId() == Account.ACCOUNT_ID_COMBINED_VIEW;
    177 
    178                 if (isCombinedActive && Account.isNormalAccount(id)) {
    179                     chipView.setBackgroundColor(mResourceHelper.getAccountColor(id));
    180                     chipView.setVisibility(View.VISIBLE);
    181                 } else {
    182                     chipView.setVisibility(View.GONE);
    183                 }
    184             } else {
    185                 unreadCountView.setVisibility(View.INVISIBLE);
    186                 chipView.setVisibility(View.GONE);
    187             }
    188 
    189         }
    190         return view;
    191     }
    192 
    193     @Override
    194     public View newView(Context context, Cursor cursor, ViewGroup parent) {
    195         return null; // we don't reuse views.  This method never gets called.
    196     }
    197 
    198     @Override
    199     public void bindView(View view, Context context, Cursor cursor) {
    200         // we don't reuse views.  This method never gets called.
    201     }
    202 
    203     @Override
    204     public int getViewTypeCount() {
    205         return 2;
    206     }
    207 
    208     @Override
    209     public int getItemViewType(int position) {
    210         Cursor c = getCursor();
    211         c.moveToPosition(position);
    212         return c.getLong(c.getColumnIndex(ROW_TYPE)) == ROW_TYPE_HEADER
    213                 ? AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER
    214                 : ITEM_VIEW_TYPE_ACCOUNT;
    215     }
    216 
    217     @Override
    218     public boolean isEnabled(int position) {
    219         return (getItemViewType(position) != AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER);
    220     }
    221 
    222     public boolean isAccountItem(int position) {
    223         Cursor c = getCursor();
    224         c.moveToPosition(position);
    225         return isAccountItem(c);
    226     }
    227 
    228     public boolean isAccountItem(Cursor c) {
    229         return (c.getLong(c.getColumnIndex(ROW_TYPE)) == ROW_TYPE_ACCOUNT);
    230     }
    231 
    232     public boolean isMailboxItem(int position) {
    233         Cursor c = getCursor();
    234         c.moveToPosition(position);
    235         return (c.getLong(c.getColumnIndex(ROW_TYPE)) == ROW_TYPE_MAILBOX);
    236     }
    237 
    238     private int getAccountUnreadCount(Cursor c) {
    239         return getMessageCount(c);
    240     }
    241 
    242     /**
    243      * Returns the account/mailbox ID extracted from the given cursor.
    244      */
    245     private static long getId(Cursor c) {
    246         return c.getLong(c.getColumnIndex(EmailContent.RECORD_ID));
    247     }
    248 
    249     /**
    250      * @return ID of the account / mailbox for a row
    251      */
    252     public long getId(int position) {
    253         final Cursor c = getCursor();
    254         return c.moveToPosition(position) ? getId(c) : Account.NO_ACCOUNT;
    255     }
    256 
    257     /**
    258      * @return ID of the account for a row
    259      */
    260     public long getAccountId(int position) {
    261         final Cursor c = getCursor();
    262         return c.moveToPosition(position)
    263                 ? c.getLong(c.getColumnIndex(ACCOUNT_ID))
    264                 : Account.NO_ACCOUNT;
    265     }
    266 
    267     /** Returns the account name extracted from the given cursor. */
    268     static String getDisplayName(Cursor cursor) {
    269         return cursor.getString(cursor.getColumnIndex(Account.DISPLAY_NAME));
    270     }
    271 
    272     /** Returns the email address extracted from the given cursor. */
    273     private static String getAccountEmailAddress(Cursor cursor) {
    274         return cursor.getString(cursor.getColumnIndex(Account.EMAIL_ADDRESS));
    275     }
    276 
    277     /**
    278      * Returns the message count (unread or total, depending on row) extracted from the given
    279      * cursor.
    280      */
    281     private static int getMessageCount(Cursor cursor) {
    282         return cursor.getInt(cursor.getColumnIndex(MESSAGE_COUNT));
    283     }
    284 
    285     private static String sCombinedViewDisplayName;
    286     private static String getCombinedViewDisplayName(Context c) {
    287         if (sCombinedViewDisplayName == null) {
    288             sCombinedViewDisplayName = c.getResources().getString(
    289                     R.string.mailbox_list_account_selector_combined_view);
    290         }
    291         return sCombinedViewDisplayName;
    292     }
    293 
    294     /**
    295      * Load the account list.  The resulting cursor contains
    296      * - Account info
    297      * - # of unread messages in inbox
    298      * - The "Combined view" row if there's more than one account.
    299      */
    300     @VisibleForTesting
    301     static class AccountsLoader extends ThrottlingCursorLoader {
    302         private final Context mContext;
    303         private final long mAccountId;
    304         private final long mMailboxId;
    305         private final boolean mUseTwoPane; // Injectable for test
    306         private final FolderProperties mFolderProperties;
    307 
    308         @VisibleForTesting
    309         AccountsLoader(Context context, long accountId, long mailboxId, boolean useTwoPane) {
    310             // Super class loads a regular account cursor, but we replace it in loadInBackground().
    311             super(context, Account.CONTENT_URI, ACCOUNT_PROJECTION, null, null,
    312                     ORDER_BY);
    313             mContext = context;
    314             mAccountId = accountId;
    315             mMailboxId = mailboxId;
    316             mFolderProperties = FolderProperties.getInstance(mContext);
    317             mUseTwoPane = useTwoPane;
    318         }
    319 
    320         @Override
    321         public Cursor loadInBackground() {
    322             final Cursor accountsCursor = super.loadInBackground();
    323             // Use ClosingMatrixCursor so that accountsCursor gets closed too when it's closed.
    324             final CursorWithExtras resultCursor
    325                     = new CursorWithExtras(ADAPTER_PROJECTION, accountsCursor);
    326             final int accountPosition = addAccountsToCursor(resultCursor, accountsCursor);
    327             addMailboxesToCursor(resultCursor, accountPosition);
    328 
    329             resultCursor.setAccountMailboxInfo(getContext(), mAccountId, mMailboxId);
    330             return resultCursor;
    331         }
    332 
    333         /** Adds the account list [with extra meta data] to the given matrix cursor */
    334         private int addAccountsToCursor(CursorWithExtras matrixCursor, Cursor accountCursor) {
    335             int accountPosition = UNKNOWN_POSITION;
    336             accountCursor.moveToPosition(-1);
    337 
    338             matrixCursor.mAccountCount = accountCursor.getCount();
    339             int totalUnread = 0;
    340             while (accountCursor.moveToNext()) {
    341                 // Add account, with its unread count.
    342                 final long accountId = accountCursor.getLong(0);
    343                 final int unread = Mailbox.getUnreadCountByAccountAndMailboxType(
    344                         mContext, accountId, Mailbox.TYPE_INBOX);
    345                 final String name = getDisplayName(accountCursor);
    346                 final String emailAddress = getAccountEmailAddress(accountCursor);
    347                 addRow(matrixCursor, ROW_TYPE_ACCOUNT, accountId, name, emailAddress, unread,
    348                     UNKNOWN_POSITION, accountId);
    349                 totalUnread += unread;
    350                 if (accountId == mAccountId) {
    351                     accountPosition = accountCursor.getPosition();
    352                 }
    353             }
    354             // Add "combined view" if more than one account exists
    355             final int countAccounts = accountCursor.getCount();
    356             if (countAccounts > 1) {
    357                 final String accountCount = mContext.getResources().getQuantityString(
    358                         R.plurals.number_of_accounts, countAccounts, countAccounts);
    359                 addRow(matrixCursor, ROW_TYPE_ACCOUNT, Account.ACCOUNT_ID_COMBINED_VIEW,
    360                         getCombinedViewDisplayName(mContext),
    361                         accountCount, totalUnread, UNKNOWN_POSITION,
    362                         Account.ACCOUNT_ID_COMBINED_VIEW);
    363 
    364                 // Increment the account count for the combined account.
    365                 matrixCursor.mAccountCount++;
    366             }
    367             return accountPosition;
    368         }
    369 
    370         /**
    371          * Adds the recent mailbox list / "show all folders" to the given cursor.
    372          *
    373          * @param matrixCursor the cursor to add the list to
    374          * @param accountPosition the cursor position of the currently selected account
    375          */
    376         private void addMailboxesToCursor(CursorWithExtras matrixCursor, int accountPosition) {
    377             if (mAccountId == Account.NO_ACCOUNT) {
    378                 return; // Account not selected
    379             }
    380             if (mAccountId == Account.ACCOUNT_ID_COMBINED_VIEW) {
    381                 if (!mUseTwoPane) {
    382                     // TODO We may want a header for this to separate it from the account list
    383                     addShowAllFoldersRow(matrixCursor, accountPosition);
    384                 }
    385                 return;
    386             }
    387             String emailAddress = null;
    388             if (accountPosition != UNKNOWN_POSITION) {
    389                 matrixCursor.moveToPosition(accountPosition);
    390                 emailAddress =
    391                         matrixCursor.getString(matrixCursor.getColumnIndex(Account.EMAIL_ADDRESS));
    392             }
    393             RecentMailboxManager mailboxManager = RecentMailboxManager.getInstance(mContext);
    394             ArrayList<Long> recentMailboxes = null;
    395             if (!mUseTwoPane) {
    396                 // Do not display recent mailboxes in the account spinner for the two pane view
    397                 recentMailboxes = mailboxManager.getMostRecent(mAccountId, mUseTwoPane);
    398             }
    399             final int recentCount = (recentMailboxes == null) ? 0 : recentMailboxes.size();
    400             matrixCursor.mRecentCount = recentCount;
    401 
    402             if (!mUseTwoPane) {
    403                 // "Recent mailboxes" header
    404                 addHeaderRow(matrixCursor, mContext.getString(
    405                         R.string.mailbox_list_account_selector_mailbox_header_fmt, emailAddress));
    406             }
    407 
    408             if (recentCount > 0) {
    409                 addMailboxRows(matrixCursor, accountPosition, recentMailboxes);
    410             }
    411 
    412             if (!mUseTwoPane) {
    413                 addShowAllFoldersRow(matrixCursor, accountPosition);
    414             }
    415         }
    416 
    417         private void addShowAllFoldersRow(CursorWithExtras matrixCursor, int accountPosition) {
    418             matrixCursor.mHasShowAllFolders = true;
    419             String name = mContext.getString(
    420                     R.string.mailbox_list_account_selector_show_all_folders);
    421             addRow(matrixCursor, ROW_TYPE_MAILBOX, Mailbox.NO_MAILBOX, name, null, 0,
    422                     accountPosition, mAccountId);
    423         }
    424 
    425 
    426         private static final String[] RECENT_MAILBOX_INFO_PROJECTION = new String[] {
    427             MailboxColumns.ID, MailboxColumns.DISPLAY_NAME, MailboxColumns.TYPE,
    428             MailboxColumns.UNREAD_COUNT, MailboxColumns.MESSAGE_COUNT
    429         };
    430 
    431         private void addMailboxRows(MatrixCursor matrixCursor, int accountPosition,
    432                 Collection<Long> mailboxIds) {
    433             Cursor c = mContext.getContentResolver().query(
    434                     Mailbox.CONTENT_URI, RECENT_MAILBOX_INFO_PROJECTION,
    435                     Utility.buildInSelection(MailboxColumns.ID, mailboxIds), null,
    436                     RecentMailboxManager.RECENT_MAILBOXES_SORT_ORDER);
    437             try {
    438                 c.moveToPosition(-1);
    439                 while (c.moveToNext()) {
    440                     addRow(matrixCursor, ROW_TYPE_MAILBOX,
    441                             c.getLong(c.getColumnIndex(MailboxColumns.ID)),
    442                             mFolderProperties.getDisplayName(c), null,
    443                             mFolderProperties.getMessageCount(c), accountPosition, mAccountId);
    444                 }
    445             } finally {
    446                 c.close();
    447             }
    448         }
    449 
    450         private void addHeaderRow(MatrixCursor cursor, String name) {
    451             addRow(cursor, ROW_TYPE_HEADER, 0L, name, null, 0, UNKNOWN_POSITION,
    452                     Account.NO_ACCOUNT);
    453         }
    454 
    455         /** Adds a row to the given cursor */
    456         private void addRow(MatrixCursor cursor, int rowType, long id, String name,
    457                 String emailAddress, int messageCount, int listPosition, long accountId) {
    458             cursor.newRow()
    459                 .add(rowType)
    460                 .add(id)
    461                 .add(name)
    462                 .add(emailAddress)
    463                 .add(messageCount)
    464                 .add(listPosition)
    465                 .add(accountId);
    466         }
    467     }
    468 
    469     /** Cursor with some extra meta data. */
    470     static class CursorWithExtras extends ClosingMatrixCursor {
    471 
    472         /** Number of account elements, including the combined account row. */
    473         private int mAccountCount;
    474         /** Number of recent mailbox elements */
    475         private int mRecentCount;
    476         private boolean mHasShowAllFolders;
    477 
    478         private boolean mAccountExists;
    479 
    480         /**
    481          * Account ID that's loaded.
    482          */
    483         private long mAccountId;
    484         private String mAccountDisplayName;
    485 
    486         /**
    487          * Mailbox ID that's loaded.
    488          */
    489         private long mMailboxId;
    490         private String mMailboxDisplayName;
    491         private int mMailboxMessageCount;
    492 
    493         @VisibleForTesting
    494         CursorWithExtras(String[] columnNames, Cursor innerCursor) {
    495             super(columnNames, innerCursor);
    496         }
    497 
    498         private static final String[] ACCOUNT_INFO_PROJECTION = new String[] {
    499             AccountColumns.DISPLAY_NAME,
    500         };
    501         private static final String[] MAILBOX_INFO_PROJECTION = new String[] {
    502             MailboxColumns.ID, MailboxColumns.DISPLAY_NAME, MailboxColumns.TYPE,
    503             MailboxColumns.UNREAD_COUNT, MailboxColumns.MESSAGE_COUNT
    504         };
    505 
    506         /**
    507          * Set the current account/mailbox info.
    508          */
    509         @VisibleForTesting
    510         void setAccountMailboxInfo(Context context, long accountId, long mailboxId) {
    511             mAccountId = accountId;
    512             mMailboxId = mailboxId;
    513 
    514             // Get account info
    515             if (accountId == Account.ACCOUNT_ID_COMBINED_VIEW) {
    516                 // We need to treat ACCOUNT_ID_COMBINED_VIEW specially...
    517                 mAccountExists = true;
    518                 mAccountDisplayName = getCombinedViewDisplayName(context);
    519                 if (mailboxId != Mailbox.NO_MAILBOX) {
    520                     setCombinedMailboxInfo(context, mailboxId);
    521                 }
    522                 return;
    523             }
    524 
    525             mAccountDisplayName = Utility.getFirstRowString(context,
    526                     ContentUris.withAppendedId(Account.CONTENT_URI, accountId),
    527                     ACCOUNT_INFO_PROJECTION, null, null, null, 0, null);
    528             if (mAccountDisplayName == null) {
    529                 // Account gone!
    530                 mAccountExists = false;
    531                 return;
    532             }
    533             mAccountExists = true;
    534 
    535             // If mailbox not specified, done.
    536             if (mMailboxId == Mailbox.NO_MAILBOX) {
    537                 return;
    538             }
    539             // Combined mailbox?
    540             // Unfortunately this can happen even when account != ACCOUNT_ID_COMBINED_VIEW,
    541             // when you open "starred" on 2-pane on non-combined view.
    542             if (mMailboxId < 0) {
    543                 setCombinedMailboxInfo(context, mailboxId);
    544                 return;
    545             }
    546 
    547             // Get mailbox info
    548             final ContentResolver r = context.getContentResolver();
    549             final Cursor mailboxCursor = r.query(
    550                     ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId),
    551                     MAILBOX_INFO_PROJECTION, null, null, null);
    552             try {
    553                 if (mailboxCursor.moveToFirst()) {
    554                     final FolderProperties fp = FolderProperties.getInstance(context);
    555                     mMailboxDisplayName = fp.getDisplayName(mailboxCursor);
    556                     mMailboxMessageCount = fp.getMessageCount(mailboxCursor);
    557                 }
    558             } finally {
    559                 mailboxCursor.close();
    560             }
    561         }
    562 
    563         private void setCombinedMailboxInfo(Context context, long mailboxId) {
    564             Preconditions.checkState(mailboxId < -1, "Not combined mailbox");
    565             mMailboxDisplayName = FolderProperties.getInstance(context)
    566                     .getCombinedMailboxName(mMailboxId);
    567 
    568             mMailboxMessageCount = FolderProperties.getMessageCountForCombinedMailbox(
    569                     context, mailboxId);
    570         }
    571 
    572         /**
    573          * Returns the cursor position of the item with the given ID. Or {@link #UNKNOWN_POSITION}
    574          * if the given ID does not exist.
    575          */
    576         int getPosition(long id) {
    577             moveToPosition(-1);
    578             while(moveToNext()) {
    579                 if (id == getId(this)) {
    580                     return getPosition();
    581                 }
    582             }
    583             return UNKNOWN_POSITION;
    584         }
    585 
    586         public int getAccountCount() {
    587             return mAccountCount;
    588         }
    589 
    590         @VisibleForTesting
    591         public int getRecentMailboxCount() {
    592             return mRecentCount;
    593         }
    594 
    595         /**
    596          * @return true if the cursor has more than one selectable item so we should enable the
    597          *     spinner.
    598          */
    599         public boolean shouldEnableSpinner() {
    600             return mHasShowAllFolders || (mAccountCount + mRecentCount > 1);
    601         }
    602 
    603         public long getAccountId() {
    604             return mAccountId;
    605         }
    606 
    607         public String getAccountDisplayName() {
    608             return mAccountDisplayName;
    609         }
    610 
    611         @VisibleForTesting
    612         public long getMailboxId() {
    613             return mMailboxId;
    614         }
    615 
    616         public String getMailboxDisplayName() {
    617             return mMailboxDisplayName;
    618         }
    619 
    620         public int getMailboxMessageCount() {
    621             return mMailboxMessageCount;
    622         }
    623 
    624         /**
    625          * @return {@code true} if the specified accuont exists.
    626          */
    627         public boolean accountExists() {
    628             return mAccountExists;
    629         }
    630     }
    631 }
    632