RecentFolderList.java revision 27e85f244604c8de53b76b135e0dd6f2bf3cad96
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.ContentResolver; 20import android.content.ContentValues; 21import android.content.Context; 22import android.database.Cursor; 23import android.text.TextUtils; 24 25import com.android.mail.providers.Account; 26import com.android.mail.providers.Folder; 27import com.android.mail.providers.UIProvider; 28import com.android.mail.utils.LogUtils; 29import com.android.mail.utils.LruCache; 30 31import java.util.Collections; 32import java.util.ArrayList; 33import java.util.List; 34import java.util.Comparator; 35 36/** 37 * A self-updating list of folder canonical names for the N most recently touched folders, ordered 38 * from least-recently-touched to most-recently-touched. N is a fixed size determined upon 39 * creation. 40 * 41 * RecentFoldersCache returns lists of this type, and will keep them updated when observers are 42 * registered on them. 43 * 44 */ 45public final class RecentFolderList { 46 private static final String LOG_TAG = new LogUtils().getLogTag(); 47 /** The application context */ 48 private final Context mContext; 49 /** The current account */ 50 private Account mAccount; 51 /** 52 * Compare based on alphanumeric name of the folder, ignoring case. 53 */ 54 private static final Comparator<Folder> ALPHABET_IGNORECASE = new Comparator<Folder>() { 55 @Override 56 public int compare(Folder lhs, Folder rhs) { 57 return lhs.name.compareToIgnoreCase(rhs.name); 58 } 59 }; 60 private final LruCache<String, Folder> mFolderCache; 61 /** 62 * We want to show five recent folders, and one space for the current folder (not displayed 63 * to the user). 64 */ 65 private final static int NUM_FOLDERS = 5 + 1; 66 67 /** 68 * Create a Recent Folder List from the given account. This will query the UIProvider to 69 * retrieve the RecentFolderList from persistent storage (if any). 70 * @param account 71 */ 72 public RecentFolderList(Account account, Context context) { 73 mContext = context; 74 mAccount = account; 75 mFolderCache = new LruCache<String, Folder>(NUM_FOLDERS); 76 loadFromUiProvider(); 77 } 78 79 public void changeCurrentAccount(Account account) { 80 saveToUiProvider(); 81 mAccount = account; 82 loadFromUiProvider(); 83 } 84 85 /** 86 * Load the account information from the UI provider. 87 */ 88 private void loadFromUiProvider() { 89 if (mAccount == null || mAccount.recentFolderListUri == null) 90 return; 91 mFolderCache.clear(); 92 final ContentResolver mResolver = mContext.getContentResolver(); 93 // TODO(viki): Bad idea. Use a loader. 94 Cursor data = mResolver.query(mAccount.recentFolderListUri, UIProvider.FOLDERS_PROJECTION, 95 null, null, null); 96 if (data == null || data.getCount() <= 0) { 97 // No pre-stored recent folder list. Let's return an empty folder list. 98 return; 99 } 100 // Populate the recent folder cache from the UiProvider. 101 int i = 0; 102 while (data.moveToNext()) { 103 assert (data.getColumnCount() == UIProvider.FOLDERS_PROJECTION.length); 104 Folder folder = new Folder(data); 105 mFolderCache.putElement(folder.id, folder); 106 i++; 107 if (i >= NUM_FOLDERS) 108 break; 109 } 110 } 111 112 /** 113 * Changes the current folder and returns the updated list of recent folders, <b>not</b> 114 * including the current folder. 115 * @param folder the folder we have changed to. 116 */ 117 public Folder[] changeCurrentFolder(Folder folder) { 118 mFolderCache.putElement(folder.id, folder); 119 // Update the UiProvider with the current recent folder list. 120 saveToUiProvider(); 121 return getSortedArray(folder); 122 } 123 124 /** 125 * Requests the UIProvider to save this RecentFolderList to persistent storage. 126 */ 127 public void saveToUiProvider() { 128 if (mAccount == null || mFolderCache.isEmpty() || mAccount.recentFolderListUri == null) 129 return; 130 // Write the current recent folder list into the account. 131 // Store the ID of the folder and the last touched timestamp. 132 ContentValues values = new ContentValues(); 133 final long now = System.currentTimeMillis(); 134 for (String id : mFolderCache.keySet()) { 135 values.put(id, now); 136 } 137 final ContentResolver mResolver = mContext.getContentResolver(); 138 mResolver.update(mAccount.recentFolderListUri, values, null, null); 139 } 140 141 /** 142 * Generate a sorted array of recent folders, <b>not</b> including the current folder. 143 * @param currentFolder the current folder being displayed. 144 */ 145 public Folder[] getSortedArray(Folder currentFolder) { 146 final int spaceForCurrentFolder = 147 (currentFolder != null && mFolderCache.getElement(currentFolder.id) != null) 148 ? 1 : 0; 149 final int numRecents = mFolderCache.size() - spaceForCurrentFolder; 150 final Folder[] folders = new Folder[numRecents]; 151 int i = 0; 152 final List<Folder> recent = new ArrayList<Folder>(mFolderCache.values()); 153 Collections.sort(recent, ALPHABET_IGNORECASE); 154 for (Folder f : recent) { 155 if (currentFolder == null || !TextUtils.equals(f.id, currentFolder.id)) { 156 folders[i++] = f; 157 } 158 } 159 return folders; 160 } 161} 162