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;
21bc748acc02add75ccd04691931464547d998ec08Marc Blankimport android.net.Uri;
22fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwalimport android.os.AsyncTask;
2346b5b33c4de296b5c3b61b031db9d36bf429be6aTony Mantlerimport android.support.annotation.NonNull;
241a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
25177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwalimport com.android.mail.content.ObjectCursor;
261a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport com.android.mail.providers.Account;
277c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwalimport com.android.mail.providers.AccountObserver;
281a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport com.android.mail.providers.Folder;
29167faa8584750e37781f22ad7e6d61003029f954Marc Blankimport com.android.mail.providers.Settings;
30a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedyimport com.android.mail.providers.UIProvider.FolderType;
31259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedyimport com.android.mail.utils.FolderUri;
321a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport com.android.mail.utils.LogUtils;
331a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport com.android.mail.utils.LruCache;
3410ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blankimport com.android.mail.utils.Utils;
355a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrookimport com.google.common.collect.Lists;
361a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
371a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport java.util.ArrayList;
383232a96e0ea88741dc39acf17d49e9c22b61c707Marc Blankimport java.util.Collections;
391a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalimport java.util.Comparator;
403232a96e0ea88741dc39acf17d49e9c22b61c707Marc Blankimport java.util.List;
415a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrookimport java.util.concurrent.atomic.AtomicInteger;
421a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
431a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal/**
441a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * A self-updating list of folder canonical names for the N most recently touched folders, ordered
451a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * from least-recently-touched to most-recently-touched. N is a fixed size determined upon
461a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * creation.
471a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal *
481a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * RecentFoldersCache returns lists of this type, and will keep them updated when observers are
491a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal * registered on them.
501a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal *
511a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal */
521a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwalpublic final class RecentFolderList {
53bc748acc02add75ccd04691931464547d998ec08Marc Blank    private static final String TAG = "RecentFolderList";
5427e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    /** The application context */
5527e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    private final Context mContext;
5627e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    /** The current account */
57ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal    private Account mAccount = null;
58bc748acc02add75ccd04691931464547d998ec08Marc Blank
592c0032dd2a4996680ab6e1958fe80a2ebcd01ef3Vikram Aggarwal    /** The actual cache: map of folder URIs to folder objects. */
605a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook    private final LruCache<String, RecentFolderListEntry> mFolderCache;
61bc748acc02add75ccd04691931464547d998ec08Marc Blank    /**
62167faa8584750e37781f22ad7e6d61003029f954Marc Blank     *  We want to show at most five recent folders
63bc748acc02add75ccd04691931464547d998ec08Marc Blank     */
64167faa8584750e37781f22ad7e6d61003029f954Marc Blank    private final static int MAX_RECENT_FOLDERS = 5;
65167faa8584750e37781f22ad7e6d61003029f954Marc Blank    /**
66167faa8584750e37781f22ad7e6d61003029f954Marc Blank     *  We exclude the default inbox for the account and the current folder; these might be the
67167faa8584750e37781f22ad7e6d61003029f954Marc Blank     *  same, but we'll allow for both
68167faa8584750e37781f22ad7e6d61003029f954Marc Blank     */
69167faa8584750e37781f22ad7e6d61003029f954Marc Blank    private final static int MAX_EXCLUDED_FOLDERS = 2;
70bc748acc02add75ccd04691931464547d998ec08Marc Blank
717c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    private final AccountObserver mAccountObserver = new AccountObserver() {
727c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        @Override
737c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        public void onChanged(Account newAccount) {
747c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal            setCurrentAccount(newAccount);
757c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        }
767c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    };
777c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
781a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    /**
791a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     * Compare based on alphanumeric name of the folder, ignoring case.
801a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     */
811a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    private static final Comparator<Folder> ALPHABET_IGNORECASE = new Comparator<Folder>() {
821a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal        @Override
831a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal        public int compare(Folder lhs, Folder rhs) {
841a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal            return lhs.name.compareToIgnoreCase(rhs.name);
851a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal        }
861a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    };
87fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal    /**
88fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal     * Class to store the recent folder list asynchronously.
89fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal     */
90bc748acc02add75ccd04691931464547d998ec08Marc Blank    private class StoreRecent extends AsyncTask<Void, Void, Void> {
917c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        /**
927c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal         * Copy {@link RecentFolderList#mAccount} in case the account changes between when the
937c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal         * AsyncTask is created and when it is executed.
947c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal         */
957c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        @SuppressWarnings("hiding")
967c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        private final Account mAccount;
977c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        private final Folder mFolder;
98fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal
99792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal        /**
100792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal         * Create a new asynchronous task to store the recent folder list. Both the account
101792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal         * and the folder should be non-null.
10250ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal         * @param account the current account for this folder.
10350ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal         * @param folder the folder which is to be stored.
104792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal         */
105bc748acc02add75ccd04691931464547d998ec08Marc Blank        public StoreRecent(Account account, Folder folder) {
106792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal            assert (account != null && folder != null);
107c972b18618baa79b2825b5661d7cd11fffb1d3a1Marc Blank            mAccount = account;
108bc748acc02add75ccd04691931464547d998ec08Marc Blank            mFolder = folder;
109fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal        }
110fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal
111fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal        @Override
112bc748acc02add75ccd04691931464547d998ec08Marc Blank        protected Void doInBackground(Void... v) {
113677cbef2083fdbfeb6cc20384a5405614b6694b2Vikram Aggarwal            final Uri uri = mAccount.recentFolderListUri;
11410ddc197b8c3df994ee3575b7abac4c36ea81c1fMarc Blank            if (!Utils.isEmpty(uri)) {
115bc748acc02add75ccd04691931464547d998ec08Marc Blank                ContentValues values = new ContentValues();
11627d89ada3e8d1b17357a7064e1f47f3c15686412Vikram Aggarwal                // Only the folder URIs are provided. Providers are free to update their specific
11727d89ada3e8d1b17357a7064e1f47f3c15686412Vikram Aggarwal                // information, though most will probably write the current timestamp.
118259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy                values.put(mFolder.folderUri.fullUri.toString(), 0);
119ad6a275b1a6fdb714893696cd8899e1de1d7d59cPaul Westbrook                LogUtils.i(TAG, "Save: %s", mFolder.name);
120bc748acc02add75ccd04691931464547d998ec08Marc Blank                mContext.getContentResolver().update(uri, values, null, null);
121bc748acc02add75ccd04691931464547d998ec08Marc Blank            }
122fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal            return null;
123fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal        }
124fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal    }
1251a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
1261a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    /**
1271a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     * Create a Recent Folder List from the given account. This will query the UIProvider to
1281a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     * retrieve the RecentFolderList from persistent storage (if any).
12950ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal     * @param context the context for the activity
1301a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     */
131025eba8bfd4d0b5e248b6de0bda6f1129170fb41Vikram Aggarwal    public RecentFolderList(Context context) {
1325a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        mFolderCache = new LruCache<String, RecentFolderListEntry>(
1335a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook                MAX_RECENT_FOLDERS + MAX_EXCLUDED_FOLDERS);
134fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal        mContext = context;
13527e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    }
13627e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal
137ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal    /**
1387c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal     * Initialize the {@link RecentFolderList} with a controllable activity.
13950ff0e50f1a27144e55e4184f48e433439727e7bVikram Aggarwal     * @param activity the underlying activity
1407c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal     */
1417c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    public void initialize(ControllableActivity activity){
1427c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        setCurrentAccount(mAccountObserver.initialize(activity.getAccountController()));
1437c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    }
1447c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
1457c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    /**
146167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * Change the current account. When a cursor over the recent folders for this account is
147177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal     * available, the client <b>must</b> call {@link
148177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal     * #loadFromUiProvider(com.android.mail.content.ObjectCursor)} with the updated
149167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * cursor. Till then, the recent account list will be empty.
150167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * @param account the new current account
151ec5cbf79b825c6f96d45e85015319c66470b7e57Vikram Aggarwal     */
1527c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    private void setCurrentAccount(Account account) {
15322e3f1e5f94dd69359dcf8dbbfaee3f4aed44fb8Andy Huang        final boolean accountSwitched = (mAccount == null) || !mAccount.matches(account);
15427e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal        mAccount = account;
1559e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal        // Clear the cache only if we moved from alice@example.com -> alice@work.com
1569e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal        if (accountSwitched) {
1579e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal            mFolderCache.clear();
1589e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal        }
15927e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    }
16027e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal
16127e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal    /**
162fa4b47e4a1962010ec3c8ea7476ac1e701f461b4Vikram Aggarwal     * Load the account information from the UI provider given the cursor over the recent folders.
163167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * @param c a cursor over the recent folders.
16427e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal     */
165177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal    public void loadFromUiProvider(ObjectCursor<Folder> c) {
166167faa8584750e37781f22ad7e6d61003029f954Marc Blank        if (mAccount == null || c == null) {
1679e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal            LogUtils.e(TAG, "RecentFolderList.loadFromUiProvider: bad input. mAccount=%s,cursor=%s",
1689e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal                    mAccount, c);
16927e85f244604c8de53b76b135e0dd6f2bf3cad96Vikram Aggarwal            return;
170bc748acc02add75ccd04691931464547d998ec08Marc Blank        }
17127d89ada3e8d1b17357a7064e1f47f3c15686412Vikram Aggarwal        LogUtils.d(TAG, "Number of recents = %d", c.getCount());
172317348a7d1d5f18ab2b994d377366bfbcb55cf6aPaul Westbrook        if (!c.moveToLast()) {
1739e357e62d206dc7cacd00d79b3dc693384d98f4eVikram Aggarwal            LogUtils.e(TAG, "Not able to move to last in recent labels cursor");
174317348a7d1d5f18ab2b994d377366bfbcb55cf6aPaul Westbrook            return;
175317348a7d1d5f18ab2b994d377366bfbcb55cf6aPaul Westbrook        }
176f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        // Add them backwards, since the most recent values are at the beginning in the cursor.
177f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        // This enables older values to fall off the LRU cache. Also, read all values, just in case
178f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        // there are duplicates in the cursor.
179f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        do {
180177097fad8fc26b8a215f9f1af6dd5fd2c8eb06cVikram Aggarwal            final Folder folder = c.getModel();
1815a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook            final RecentFolderListEntry entry = new RecentFolderListEntry(folder);
182259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy            mFolderCache.putElement(folder.folderUri.fullUri.toString(), entry);
18326a20758413f0f8629ea71a0943304e3ae740165Tony Mantler            LogUtils.v(TAG, "Account %s, Recent: %s", mAccount.getEmailAddress(), folder.name);
184f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        } while (c.moveToPrevious());
1851a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    }
1861a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
1871a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    /**
188bc748acc02add75ccd04691931464547d998ec08Marc Blank     * Marks the given folder as 'accessed' by the user interface, its entry is updated in the
189792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal     * recent folder list, and the current time is written to the provider. This should never
190792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal     * be called with a null folder.
191167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * @param folder the folder we touched
1921a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     */
19346b5b33c4de296b5c3b61b031db9d36bf429be6aTony Mantler    public void touchFolder(@NonNull Folder folder, Account account) {
194792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal        // We haven't got a valid account yet, cannot proceed.
1952675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank        if (mAccount == null || !mAccount.equals(account)) {
1962675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank            if (account != null) {
1972675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank                setCurrentAccount(account);
1982675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank            } else {
1992675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank                LogUtils.w(TAG, "No account set for setting recent folders?");
2002675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank                return;
2012675dbc9c1904ec3fb0ab588560f04a68a806bc9Marc Blank            }
202792ccbac8b579fc1077712d82144a31fd92241d0Vikram Aggarwal        }
203a313d18ea41cb95b584382a15a437562f10c1061Scott Kennedy
204a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy        if (folder.isProviderFolder() || folder.isType(FolderType.SEARCH)) {
205a158ac8a41239300a2f50b38ed17167aeef4ff4bScott Kennedy            LogUtils.d(TAG, "Not touching recent folder because it's provider or search folder");
206a313d18ea41cb95b584382a15a437562f10c1061Scott Kennedy            return;
207a313d18ea41cb95b584382a15a437562f10c1061Scott Kennedy        }
208a313d18ea41cb95b584382a15a437562f10c1061Scott Kennedy
2095a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        final RecentFolderListEntry entry = new RecentFolderListEntry(folder);
210259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy        mFolderCache.putElement(folder.folderUri.fullUri.toString(), entry);
211bc748acc02add75ccd04691931464547d998ec08Marc Blank        new StoreRecent(mAccount, folder).execute();
2121a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    }
2131a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal
2141a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    /**
215167faa8584750e37781f22ad7e6d61003029f954Marc Blank     * Generate a sorted list of recent folders, excluding the passed in folder (if any) and
216f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal     * default inbox for the current account. This must be called <em>after</em>
217025eba8bfd4d0b5e248b6de0bda6f1129170fb41Vikram Aggarwal     * {@link #setCurrentAccount(Account)} has been called.
218f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal     * Returns a list of size {@value #MAX_RECENT_FOLDERS} or smaller.
21958cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal     * @param excludedFolderUri the uri of folder to be excluded (typically the current folder)
2201a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal     */
221259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy    public ArrayList<Folder> getRecentFolderList(final FolderUri excludedFolderUri) {
222259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy        final ArrayList<FolderUri> excludedUris = new ArrayList<FolderUri>();
22358cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal        if (excludedFolderUri != null) {
22458cad2eea744d41a11c0124e91308e38108d242eVikram Aggarwal            excludedUris.add(excludedFolderUri);
225167faa8584750e37781f22ad7e6d61003029f954Marc Blank        }
226259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy        final FolderUri defaultInbox = (mAccount == null)
227259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy                ? FolderUri.EMPTY
228259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy                : new FolderUri(Settings.getDefaultInboxUri(mAccount.settings));
229259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy        if (!defaultInbox.equals(FolderUri.EMPTY)) {
2301e57e67c1a59b6d3b00d935fab91805689cb6f74Vikram Aggarwal            excludedUris.add(defaultInbox);
231167faa8584750e37781f22ad7e6d61003029f954Marc Blank        }
2325a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        final List<RecentFolderListEntry> recent = Lists.newArrayList();
2335a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        recent.addAll(mFolderCache.values());
2345a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        Collections.sort(recent);
2355a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
2365a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        final ArrayList<Folder> recentFolders = Lists.newArrayList();
2375a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        for (final RecentFolderListEntry entry : recent) {
238259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy            if (!excludedUris.contains(entry.mFolder.folderUri)) {
2395a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook                recentFolders.add(entry.mFolder);
2401a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal            }
241f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal            if (recentFolders.size() == MAX_RECENT_FOLDERS) {
242f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal                break;
243f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal            }
2441a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal        }
2455a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
246f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        // Sort the values as the very last step.
247f991bee361aa30d6546582ed6fef0229e74ee2f8Vikram Aggarwal        Collections.sort(recentFolders, ALPHABET_IGNORECASE);
2485a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
249167faa8584750e37781f22ad7e6d61003029f954Marc Blank        return recentFolders;
2501a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal    }
2517c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
2527c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    /**
2537c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal     * Destroys this instance. The object is unusable after this has been called.
2547c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal     */
2557c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    public void destroy() {
2567c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        mAccountObserver.unregisterAndDestroy();
2577c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    }
2585a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
2595a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook    private static class RecentFolderListEntry implements Comparable<RecentFolderListEntry> {
2605a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        private static final AtomicInteger SEQUENCE_GENERATOR = new AtomicInteger();
2615a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
2625a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        private final Folder mFolder;
2635a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        private final int mSequence;
2645a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
2655a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        RecentFolderListEntry(Folder folder) {
2665a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook            mFolder = folder;
2675a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook            mSequence = SEQUENCE_GENERATOR.getAndIncrement();
2685a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        }
2695a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook
2705a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        /**
2715a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook         * Ensure that RecentFolderListEntry objects with greater sequence number will appear
2725a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook         * before objects with lower sequence numbers
2735a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook         */
2745a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        @Override
2755a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        public int compareTo(RecentFolderListEntry t) {
2765a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook            return t.mSequence - mSequence;
2775a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook        }
2785a64acd84e6385e8dbc461e98a2fdd8c3176cdccPaul Westbrook    }
2791a4bcc08699356eeaa25d8ad144a1a00cea76cd0Vikram Aggarwal}
280