RecentFolderList.java revision 025eba8bfd4d0b5e248b6de0bda6f1129170fb41
1/** 2 * Copyright (c) 2011, Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.mail.ui; 18 19import android.content.ContentValues; 20import android.content.Context; 21import android.database.Cursor; 22import android.net.Uri; 23import android.os.AsyncTask; 24 25import com.android.mail.providers.Account; 26import com.android.mail.providers.Folder; 27import com.android.mail.providers.Settings; 28import com.android.mail.utils.LogUtils; 29import com.android.mail.utils.LruCache; 30import com.android.mail.utils.Utils; 31 32import java.util.ArrayList; 33import java.util.Collections; 34import java.util.Comparator; 35import java.util.List; 36 37/** 38 * A self-updating list of folder canonical names for the N most recently touched folders, ordered 39 * from least-recently-touched to most-recently-touched. N is a fixed size determined upon 40 * creation. 41 * 42 * RecentFoldersCache returns lists of this type, and will keep them updated when observers are 43 * registered on them. 44 * 45 */ 46public final class RecentFolderList { 47 private static final String TAG = "RecentFolderList"; 48 /** The application context */ 49 private final Context mContext; 50 /** The current account */ 51 private Account mAccount = null; 52 53 private final LruCache<String, Folder> mFolderCache; 54 /** 55 * We want to show at most five recent folders 56 */ 57 private final static int MAX_RECENT_FOLDERS = 5; 58 /** 59 * We exclude the default inbox for the account and the current folder; these might be the 60 * same, but we'll allow for both 61 */ 62 private final static int MAX_EXCLUDED_FOLDERS = 2; 63 64 /** 65 * Compare based on alphanumeric name of the folder, ignoring case. 66 */ 67 private static final Comparator<Folder> ALPHABET_IGNORECASE = new Comparator<Folder>() { 68 @Override 69 public int compare(Folder lhs, Folder rhs) { 70 return lhs.name.compareToIgnoreCase(rhs.name); 71 } 72 }; 73 /** 74 * Class to store the recent folder list asynchronously. 75 */ 76 private class StoreRecent extends AsyncTask<Void, Void, Void> { 77 final Account mAccount; 78 final Folder mFolder; 79 80 /** 81 * Create a new asynchronous task to store the recent folder list. Both the account 82 * and the folder should be non-null. 83 * @param account 84 * @param folder 85 */ 86 public StoreRecent(Account account, Folder folder) { 87 assert (account != null && folder != null); 88 mAccount = account; 89 mFolder = folder; 90 } 91 92 @Override 93 protected Void doInBackground(Void... v) { 94 Uri uri = mAccount.recentFolderListUri; 95 if (!Utils.isEmpty(uri)) { 96 ContentValues values = new ContentValues(); 97 values.put(mFolder.uri.toString(), System.currentTimeMillis()); 98 // TODO: Remove when well tested 99 LogUtils.i(TAG, "Save: %s", mFolder.name); 100 mContext.getContentResolver().update(uri, values, null, null); 101 } 102 return null; 103 } 104 } 105 106 /** 107 * Create a Recent Folder List from the given account. This will query the UIProvider to 108 * retrieve the RecentFolderList from persistent storage (if any). 109 * @param account 110 */ 111 public RecentFolderList(Context context) { 112 mFolderCache = new LruCache<String, Folder>(MAX_RECENT_FOLDERS); 113 mContext = context; 114 } 115 116 /** 117 * Change the current account. When a cursor over the recent folders for this account is 118 * available, the client <b>must</b> call {@link #loadFromUiProvider(Cursor)} with the updated 119 * cursor. Till then, the recent account list will be empty. 120 * @param account the new current account 121 */ 122 public void setCurrentAccount(Account account) { 123 mAccount = account; 124 mFolderCache.clear(); 125 } 126 127 /** 128 * Load the account information from the UI provider given the cursor over the recent folders. 129 * @param c a cursor over the recent folders. 130 */ 131 public void loadFromUiProvider(Cursor c) { 132 if (mAccount == null || c == null) { 133 return; 134 } 135 int i = 0; 136 while (c.moveToNext()) { 137 Folder folder = new Folder(c); 138 mFolderCache.putElement(folder.uri.toString(), folder); 139 // TODO: Remove when well tested 140 LogUtils.i(TAG, "Account %s, Recent: %s", mAccount.name, folder.name); 141 if (++i == (MAX_RECENT_FOLDERS + MAX_EXCLUDED_FOLDERS)) 142 break; 143 } 144 } 145 146 /** 147 * Marks the given folder as 'accessed' by the user interface, its entry is updated in the 148 * recent folder list, and the current time is written to the provider. This should never 149 * be called with a null folder. 150 * @param folder the folder we touched 151 */ 152 public void touchFolder(Folder folder, Account account) { 153 // We haven't got a valid account yet, cannot proceed. 154 if (mAccount == null || !mAccount.equals(account)) { 155 if (account != null) { 156 setCurrentAccount(account); 157 } else { 158 LogUtils.w(TAG, "No account set for setting recent folders?"); 159 return; 160 } 161 } 162 assert (folder != null); 163 mFolderCache.putElement(folder.uri.toString(), folder); 164 new StoreRecent(mAccount, folder).execute(); 165 } 166 167 /** 168 * Generate a sorted list of recent folders, excluding the passed in folder (if any) and 169 * the current account's default inbox. This must be called <em>after</em> 170 * {@link #setCurrentAccount(Account)} has been called. 171 * @param excludedFolder the folder to be excluded (typically the current folder) 172 */ 173 public ArrayList<Folder> getRecentFolderList(Folder excludedFolder) { 174 final ArrayList<Uri> excludedUris = new ArrayList<Uri>(); 175 if (excludedFolder != null) { 176 excludedUris.add(excludedFolder.uri); 177 } 178 final Uri defaultInbox = Settings.getDefaultInboxUri(mAccount.settings); 179 if (!defaultInbox.equals(Uri.EMPTY)) { 180 // This could already be in the list, but that's ok 181 excludedUris.add(defaultInbox); 182 } 183 final List<Folder> recent = new ArrayList<Folder>(mFolderCache.values()); 184 Collections.sort(recent, ALPHABET_IGNORECASE); 185 final ArrayList<Folder> recentFolders = new ArrayList<Folder>(); 186 for (Folder f : recent) { 187 if (!excludedUris.contains(f.uri)) { 188 recentFolders.add(f); 189 } 190 if (recentFolders.size() == MAX_RECENT_FOLDERS) break; 191 } 192 return recentFolders; 193 } 194} 195