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