RecentFolderList.java revision e173d396447016a18c5b59c92422c3e85630ee91
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;
30
31import java.util.ArrayList;
32import java.util.Collections;
33import java.util.Comparator;
34import java.util.List;
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 TAG = "RecentFolderList";
47    /** The application context */
48    private final Context mContext;
49    /** The AbstractActivityController that created us*/
50    private final AbstractActivityController mController;
51    /** The current account */
52    private Account mAccount = null;
53
54    private final LruCache<String, Folder> mFolderCache;
55    /**
56     *  We want to show at most five recent folders
57     */
58    private final static int MAX_RECENT_FOLDERS = 5;
59    /**
60     *  We exclude the default inbox for the account and the current folder; these might be the
61     *  same, but we'll allow for both
62     */
63    private final static int MAX_EXCLUDED_FOLDERS = 2;
64
65    /**
66     * Compare based on alphanumeric name of the folder, ignoring case.
67     */
68    private static final Comparator<Folder> ALPHABET_IGNORECASE = new Comparator<Folder>() {
69        @Override
70        public int compare(Folder lhs, Folder rhs) {
71            return lhs.name.compareToIgnoreCase(rhs.name);
72        }
73    };
74    /**
75     * Class to store the recent folder list asynchronously.
76     */
77    private class StoreRecent extends AsyncTask<Void, Void, Void> {
78        final Account mAccount;
79        final Folder mFolder;
80
81        public StoreRecent(Account account, Folder folder) {
82            mAccount = account;
83            mFolder = folder;
84        }
85
86        @Override
87        protected Void doInBackground(Void... v) {
88            if (mAccount == null) {
89                LogUtils.w(TAG, "No account set for setting recent folders?");
90                return null;
91            }
92            Uri uri = mAccount.recentFolderListUri;
93            if (uri != null) {
94                ContentValues values = new ContentValues();
95                values.put(mFolder.uri.toString(), System.currentTimeMillis());
96                // TODO: Remove when well tested
97                LogUtils.i(TAG, "Save: " + mFolder.name);
98                mContext.getContentResolver().update(uri, values, null, null);
99            }
100            return null;
101        }
102    }
103
104    /**
105     * Create a Recent Folder List from the given account. This will query the UIProvider to
106     * retrieve the RecentFolderList from persistent storage (if any).
107     * @param account
108     */
109    public RecentFolderList(Context context, AbstractActivityController controller) {
110        mFolderCache = new LruCache<String, Folder>(MAX_RECENT_FOLDERS);
111        mContext = context;
112        mController = controller;
113    }
114
115    /**
116     * Change the current account. When a cursor over the recent folders for this account is
117     * available, the client <b>must</b> call {@link #loadFromUiProvider(Cursor)} with the updated
118     * cursor. Till then, the recent account list will be empty.
119     * @param account the new current account
120     */
121    public void setCurrentAccount(Account account) {
122        mAccount = account;
123        mFolderCache.clear();
124    }
125
126    /**
127     * Load the account information from the UI provider given the cursor over the recent folders.
128     * @param c a cursor over the recent folders.
129     */
130    public void loadFromUiProvider(Cursor c) {
131        if (mAccount == null || c == null) {
132            return;
133        }
134        int i = 0;
135        while (c.moveToNext()) {
136            Folder folder = new Folder(c);
137            mFolderCache.putElement(folder.uri.toString(), folder);
138            // TODO: Remove when well tested
139            LogUtils.i(TAG, "Account " + mAccount.name + ", Recent: " + folder.name);
140            if (++i == (MAX_RECENT_FOLDERS + MAX_EXCLUDED_FOLDERS))
141                break;
142        }
143    }
144
145    /**
146     * Marks the given folder as 'accessed' by the user interface, its entry is updated in the
147     * recent folder list, and the current time is written to the provider
148     * @param folder the folder we touched
149     */
150    public void touchFolder(Folder folder) {
151        mFolderCache.putElement(folder.uri.toString(), folder);
152        new StoreRecent(mAccount, folder).execute();
153    }
154
155    /**
156     * Generate a sorted list of recent folders, excluding the passed in folder (if any) and
157     * the current account's default inbox
158     * @param excludedFolder the folder to be excluded (typically the current folder)
159     */
160    public ArrayList<Folder> getRecentFolderList(Folder excludedFolder) {
161        ArrayList<Uri> excludedUris = new ArrayList<Uri>();
162        if (excludedFolder != null) {
163            excludedUris.add(excludedFolder.uri);
164        }
165        Settings settings = mController.getSettings();
166        if (settings != null) {
167            // This could already be in the list, but that's ok
168            excludedUris.add(settings.defaultInbox);
169        }
170        final List<Folder> recent = new ArrayList<Folder>(mFolderCache.values());
171        Collections.sort(recent, ALPHABET_IGNORECASE);
172        ArrayList<Folder> recentFolders = new ArrayList<Folder>();
173        for (Folder f : recent) {
174            if (!excludedUris.contains(f.uri)) {
175                recentFolders.add(f);
176            }
177            if (recentFolders.size() == MAX_RECENT_FOLDERS) break;
178        }
179        return recentFolders;
180    }
181}
182