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