RecentFolderList.java revision e0828393e175c9293c86a7490225f324cbec5eef
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        if (mAccount.recentFolderListUri != null
139                && !TextUtils.equals("null", mAccount.recentFolderListUri.toString())) {
140            mResolver.update(mAccount.recentFolderListUri, values, null, null);
141        }
142    }
143
144    /**
145     * Generate a sorted array of recent folders, <b>not</b> including the current folder.
146     * @param currentFolder the current folder being displayed.
147     */
148    public Folder[] getSortedArray(Folder currentFolder) {
149        final int spaceForCurrentFolder =
150                (currentFolder != null && mFolderCache.getElement(currentFolder.id) != null)
151                        ? 1 : 0;
152        final int numRecents = mFolderCache.size() - spaceForCurrentFolder;
153        final Folder[] folders = new Folder[numRecents];
154        int i = 0;
155        final List<Folder> recent = new ArrayList<Folder>(mFolderCache.values());
156        Collections.sort(recent, ALPHABET_IGNORECASE);
157        for (Folder f : recent) {
158            if (currentFolder == null || !TextUtils.equals(f.id, currentFolder.id)) {
159                folders[i++] = f;
160            }
161        }
162        return folders;
163    }
164}
165