RecentFolderList.java revision 22e3f1e5f94dd69359dcf8dbbfaee3f4aed44fb8
11a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal/**
21a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * Copyright (c) 2011, Google Inc.
31a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal *
41a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * Licensed under the Apache License, Version 2.0 (the "License");
51a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * you may not use this file except in compliance with the License.
61a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * You may obtain a copy of the License at
71a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal *
81a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal *     http://www.apache.org/licenses/LICENSE-2.0
91a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal *
101a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * Unless required by applicable law or agreed to in writing, software
111a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * distributed under the License is distributed on an "AS IS" BASIS,
121a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * See the License for the specific language governing permissions and
141a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * limitations under the License.
151a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal */
161a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
171a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalpackage com.android.mail.ui;
181a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
1927e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwalimport android.content.ContentValues;
2027e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwalimport android.content.Context;
2127e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwalimport android.database.Cursor;
22bc748acc02add75ccd04691931464547d998ec08Marc Blankimport android.net.Uri;
23fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwalimport android.os.AsyncTask;
241a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
251a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport com.android.mail.providers.Account;
267c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwalimport com.android.mail.providers.AccountObserver;
271a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport com.android.mail.providers.Folder;
28167faa8584750e37781f22ad7e6d61003029f954Marc Blankimport com.android.mail.providers.Settings;
291a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport com.android.mail.utils.LogUtils;
301a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport com.android.mail.utils.LruCache;
3110ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blankimport com.android.mail.utils.Utils;
325a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrookimport com.google.common.collect.Lists;
331a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
341a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport java.util.ArrayList;
353232a96e0ea88741dc39acf17d49e9c22b61c707Marc Blankimport java.util.Collections;
361a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport java.util.Comparator;
373232a96e0ea88741dc39acf17d49e9c22b61c707Marc Blankimport java.util.List;
385a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrookimport java.util.concurrent.atomic.AtomicInteger;
391a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
401a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal/**
411a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * A self-updating list of folder canonical names for the N most recently touched folders, ordered
421a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * from least-recently-touched to most-recently-touched. N is a fixed size determined upon
431a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * creation.
441a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal *
451a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * RecentFoldersCache returns lists of this type, and will keep them updated when observers are
461a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * registered on them.
471a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal *
481a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal */
491a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalpublic final class RecentFolderList {
50bc748acc02add75ccd04691931464547d998ec08Marc Blank    private static final String TAG = "RecentFolderList";
5127e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    /** The application context */
5227e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    private final Context mContext;
5327e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    /** The current account */
54ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal    private Account mAccount = null;
55bc748acc02add75ccd04691931464547d998ec08Marc Blank
562c0032dd2a4996680ab6e1958fe80a2ebcd01ef3Vikram Aggarwal    /** The actual cache: map of folder URIs to folder objects. */
575a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook    private final LruCache<String, RecentFolderListEntry> mFolderCache;
58bc748acc02add75ccd04691931464547d998ec08Marc Blank    /**
59167faa8584750e37781f22ad7e6d61003029f954Marc Blank     *  We want to show at most five recent folders
60bc748acc02add75ccd04691931464547d998ec08Marc Blank     */
61167faa8584750e37781f22ad7e6d61003029f954Marc Blank    private final static int MAX_RECENT_FOLDERS = 5;
62167faa8584750e37781f22ad7e6d61003029f954Marc Blank    /**
63167faa8584750e37781f22ad7e6d61003029f954Marc Blank     *  We exclude the default inbox for the account and the current folder; these might be the
64167faa8584750e37781f22ad7e6d61003029f954Marc Blank     *  same, but we'll allow for both
65167faa8584750e37781f22ad7e6d61003029f954Marc Blank     */
66167faa8584750e37781f22ad7e6d61003029f954Marc Blank    private final static int MAX_EXCLUDED_FOLDERS = 2;
67bc748acc02add75ccd04691931464547d998ec08Marc Blank
687c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    private final AccountObserver mAccountObserver = new AccountObserver() {
697c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        @Override
707c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        public void onChanged(Account newAccount) {
717c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal            setCurrentAccount(newAccount);
727c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        }
737c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    };
747c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
751a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    /**
761a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     * Compare based on alphanumeric name of the folder, ignoring case.
771a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     */
781a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    private static final Comparator<Folder> ALPHABET_IGNORECASE = new Comparator<Folder>() {
791a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal        @Override
801a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal        public int compare(Folder lhs, Folder rhs) {
811a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal            return lhs.name.compareToIgnoreCase(rhs.name);
821a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal        }
831a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    };
84fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal    /**
85fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal     * Class to store the recent folder list asynchronously.
86fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal     */
87bc748acc02add75ccd04691931464547d998ec08Marc Blank    private class StoreRecent extends AsyncTask<Void, Void, Void> {
887c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        /**
897c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal         * Copy {@link RecentFolderList#mAccount} in case the account changes between when the
907c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal         * AsyncTask is created and when it is executed.
917c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal         */
927c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        @SuppressWarnings("hiding")
937c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        private final Account mAccount;
947c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        private final Folder mFolder;
95fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal
96792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal        /**
97792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal         * Create a new asynchronous task to store the recent folder list. Both the account
98792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal         * and the folder should be non-null.
99792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal         * @param account
100792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal         * @param folder
101792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal         */
102bc748acc02add75ccd04691931464547d998ec08Marc Blank        public StoreRecent(Account account, Folder folder) {
103792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal            assert (account != null && folder != null);
104c972b18618baa79b2825b5661d7cd11fffb1d3a1Marc Blank            mAccount = account;
105bc748acc02add75ccd04691931464547d998ec08Marc Blank            mFolder = folder;
106fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal        }
107fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal
108fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal        @Override
109bc748acc02add75ccd04691931464547d998ec08Marc Blank        protected Void doInBackground(Void... v) {
110677cbef2083fdbfeb6cc20384a5405614b6694b2Vikram Aggarwal            final Uri uri = mAccount.recentFolderListUri;
11110ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blank            if (!Utils.isEmpty(uri)) {
112bc748acc02add75ccd04691931464547d998ec08Marc Blank                ContentValues values = new ContentValues();
11327d89ada3e8d1b17357a7064e1f47f3c15686412Vikram Aggarwal                // Only the folder URIs are provided. Providers are free to update their specific
11427d89ada3e8d1b17357a7064e1f47f3c15686412Vikram Aggarwal                // information, though most will probably write the current timestamp.
11527d89ada3e8d1b17357a7064e1f47f3c15686412Vikram Aggarwal                values.put(mFolder.uri.toString(), 0);
116ad6a275b1a6fdb714893696cd8899e1de1d7d59cPaul Westbrook                LogUtils.i(TAG, "Save: %s", mFolder.name);
117bc748acc02add75ccd04691931464547d998ec08Marc Blank                mContext.getContentResolver().update(uri, values, null, null);
118bc748acc02add75ccd04691931464547d998ec08Marc Blank            }
119fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal            return null;
120fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal        }
121fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal    }
1221a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
1231a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    /**
1241a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     * Create a Recent Folder List from the given account. This will query the UIProvider to
1251a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     * retrieve the RecentFolderList from persistent storage (if any).
1267c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal     * @param context
1271a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     */
128025eba8bfd4d0b5e248b6de0bda6f1129170fb41Vikram Aggarwal    public RecentFolderList(Context context) {
1295a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        mFolderCache = new LruCache<String, RecentFolderListEntry>(
1305a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook                MAX_RECENT_FOLDERS + MAX_EXCLUDED_FOLDERS);
131fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal        mContext = context;
13227e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    }
13327e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal
134ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal    /**
1357c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal     * Initialize the {@link RecentFolderList} with a controllable activity.
1367c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal     * @param activity
1377c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal     */
1387c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    public void initialize(ControllableActivity activity){
1397c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        setCurrentAccount(mAccountObserver.initialize(activity.getAccountController()));
1407c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    }
1417c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
1427c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    /**
143167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * Change the current account. When a cursor over the recent folders for this account is
144167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * available, the client <b>must</b> call {@link #loadFromUiProvider(Cursor)} with the updated
145167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * cursor. Till then, the recent account list will be empty.
146167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * @param account the new current account
147ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal     */
1487c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    private void setCurrentAccount(Account account) {
14922e3f1e5f94dd69359dcf8dbbfaee3f4aed44fb8Andy Huang        final boolean accountSwitched = (mAccount == null) || !mAccount.matches(account);
15027e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal        mAccount = account;
1519e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal        // Clear the cache only if we moved from alice@example.com -> alice@work.com
1529e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal        if (accountSwitched) {
1539e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal            mFolderCache.clear();
1549e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal        }
15527e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    }
15627e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal
15727e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    /**
158fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal     * Load the account information from the UI provider given the cursor over the recent folders.
159167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * @param c a cursor over the recent folders.
16027e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal     */
161167faa8584750e37781f22ad7e6d61003029f954Marc Blank    public void loadFromUiProvider(Cursor c) {
162167faa8584750e37781f22ad7e6d61003029f954Marc Blank        if (mAccount == null || c == null) {
1639e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal            LogUtils.e(TAG, "RecentFolderList.loadFromUiProvider: bad input. mAccount=%s,cursor=%s",
1649e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal                    mAccount, c);
16527e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal            return;
166bc748acc02add75ccd04691931464547d998ec08Marc Blank        }
16727d89ada3e8d1b17357a7064e1f47f3c15686412Vikram Aggarwal        LogUtils.d(TAG, "Number of recents = %d", c.getCount());
168317348a7d1d5f18ab2b994d377366bfbcb55cf6aPaul Westbrook        if (!c.moveToLast()) {
1699e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal            LogUtils.e(TAG, "Not able to move to last in recent labels cursor");
170317348a7d1d5f18ab2b994d377366bfbcb55cf6aPaul Westbrook            return;
171317348a7d1d5f18ab2b994d377366bfbcb55cf6aPaul Westbrook        }
172f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        // Add them backwards, since the most recent values are at the beginning in the cursor.
173f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        // This enables older values to fall off the LRU cache. Also, read all values, just in case
174f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        // there are duplicates in the cursor.
175f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        do {
17627d89ada3e8d1b17357a7064e1f47f3c15686412Vikram Aggarwal            final Folder folder = new Folder(c);
1775a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook            final RecentFolderListEntry entry = new RecentFolderListEntry(folder);
1785a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook            mFolderCache.putElement(folder.uri.toString(), entry);
17927d89ada3e8d1b17357a7064e1f47f3c15686412Vikram Aggarwal            LogUtils.v(TAG, "Account %s, Recent: %s", mAccount.name, folder.name);
180f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        } while (c.moveToPrevious());
1811a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    }
1821a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
1831a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    /**
184bc748acc02add75ccd04691931464547d998ec08Marc Blank     * Marks the given folder as 'accessed' by the user interface, its entry is updated in the
185792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal     * recent folder list, and the current time is written to the provider. This should never
186792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal     * be called with a null folder.
187167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * @param folder the folder we touched
1881a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     */
1892675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank    public void touchFolder(Folder folder, Account account) {
190792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal        // We haven't got a valid account yet, cannot proceed.
1912675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank        if (mAccount == null || !mAccount.equals(account)) {
1922675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank            if (account != null) {
1932675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank                setCurrentAccount(account);
1942675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank            } else {
1952675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank                LogUtils.w(TAG, "No account set for setting recent folders?");
1962675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank                return;
1972675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank            }
198792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal        }
199792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal        assert (folder != null);
2005a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        final RecentFolderListEntry entry = new RecentFolderListEntry(folder);
2015a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        mFolderCache.putElement(folder.uri.toString(), entry);
202bc748acc02add75ccd04691931464547d998ec08Marc Blank        new StoreRecent(mAccount, folder).execute();
2031a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    }
2041a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
2051a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    /**
206167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * Generate a sorted list of recent folders, excluding the passed in folder (if any) and
207f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal     * default inbox for the current account. This must be called <em>after</em>
208025eba8bfd4d0b5e248b6de0bda6f1129170fb41Vikram Aggarwal     * {@link #setCurrentAccount(Account)} has been called.
209f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal     * Returns a list of size {@value #MAX_RECENT_FOLDERS} or smaller.
21058cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal     * @param excludedFolderUri the uri of folder to be excluded (typically the current folder)
2111a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     */
21258cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal    public ArrayList<Folder> getRecentFolderList(Uri excludedFolderUri) {
213025eba8bfd4d0b5e248b6de0bda6f1129170fb41Vikram Aggarwal        final ArrayList<Uri> excludedUris = new ArrayList<Uri>();
21458cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal        if (excludedFolderUri != null) {
21558cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal            excludedUris.add(excludedFolderUri);
216167faa8584750e37781f22ad7e6d61003029f954Marc Blank        }
2179da85df06175d25c52a09e08df3b02d1fd9cc6b7Vikram Aggarwal        final Uri defaultInbox = (mAccount == null) ?
218f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal                Uri.EMPTY : Settings.getDefaultInboxUri(mAccount.settings);
2191e57e67c1a59b6d3b00d935fab91805689cb6f74Vikram Aggarwal        if (!defaultInbox.equals(Uri.EMPTY)) {
2201e57e67c1a59b6d3b00d935fab91805689cb6f74Vikram Aggarwal            excludedUris.add(defaultInbox);
221167faa8584750e37781f22ad7e6d61003029f954Marc Blank        }
2225a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        final List<RecentFolderListEntry> recent = Lists.newArrayList();
2235a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        recent.addAll(mFolderCache.values());
2245a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        Collections.sort(recent);
2255a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
2265a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        final ArrayList<Folder> recentFolders = Lists.newArrayList();
2275a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        for (final RecentFolderListEntry entry : recent) {
2285a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook            if (!excludedUris.contains(entry.mFolder.uri)) {
2295a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook                recentFolders.add(entry.mFolder);
2301a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal            }
231f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal            if (recentFolders.size() == MAX_RECENT_FOLDERS) {
232f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal                break;
233f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal            }
2341a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal        }
2355a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
236f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        // Sort the values as the very last step.
237f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        Collections.sort(recentFolders, ALPHABET_IGNORECASE);
2385a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
239167faa8584750e37781f22ad7e6d61003029f954Marc Blank        return recentFolders;
2401a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    }
2417c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
2427c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    /**
2437c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal     * Destroys this instance. The object is unusable after this has been called.
2447c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal     */
2457c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    public void destroy() {
2467c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        mAccountObserver.unregisterAndDestroy();
2477c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    }
2485a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
2495a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook    private static class RecentFolderListEntry implements Comparable<RecentFolderListEntry> {
2505a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        private static final AtomicInteger SEQUENCE_GENERATOR = new AtomicInteger();
2515a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
2525a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        private final Folder mFolder;
2535a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        private final int mSequence;
2545a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
2555a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        RecentFolderListEntry(Folder folder) {
2565a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook            mFolder = folder;
2575a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook            mSequence = SEQUENCE_GENERATOR.getAndIncrement();
2585a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        }
2595a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
2605a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        /**
2615a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook         * Ensure that RecentFolderListEntry objects with greater sequence number will appear
2625a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook         * before objects with lower sequence numbers
2635a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook         */
2645a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        @Override
2655a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        public int compareTo(RecentFolderListEntry t) {
2665a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook            return t.mSequence - mSequence;
2675a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        }
2685a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook    }
2691a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal}
270