Merge "Small cleanup."
diff --git a/src/com/android/mail/AccountSpinnerAdapter.java b/src/com/android/mail/AccountSpinnerAdapter.java
index a3107a3..a296dbe 100644
--- a/src/com/android/mail/AccountSpinnerAdapter.java
+++ b/src/com/android/mail/AccountSpinnerAdapter.java
@@ -29,6 +29,8 @@
 import com.android.mail.providers.Account;
 import com.android.mail.providers.Folder;
 import com.android.mail.providers.UIProvider;
+import com.android.mail.ui.RecentFolderList;
+import com.android.mail.utils.LogUtils;
 
 /**
  * An adapter to return the list of accounts and folders for the Account Spinner.
@@ -54,15 +56,15 @@
      */
     static final int NAME_COLUMN = 2;
     /**
-     * Fake folders for now
+     * An object that provides a collection of recent folders, per account.
      */
-    private final String[] mFolders;
+    private RecentFolderList mRecentFolders;
     /**
-     *  Fake unread counts
+     * The actual collection of sorted recent folders obtained from {@link #mRecentFolders}
      */
-    private final int[] mUnreadCounts = {
-            0, 2, 42
-    };
+    private Folder[] mRecentFolderList = new Folder[0];
+
+    /** The folder currently being viewed */
     private Folder mCurrentFolder;
 
     /**
@@ -117,11 +119,6 @@
 
     public AccountSpinnerAdapter(Context context) {
         mInflater = LayoutInflater.from(context);
-        // Fake folder information
-        mFolders = new String[3];
-        mFolders[0] = "Drafts -fake";
-        mFolders[1] = "Sent -fake";
-        mFolders[1] = "Starred -fake";
     }
 
     /**
@@ -140,6 +137,7 @@
      */
     public void setCurrentFolder(Folder folder) {
         mCurrentFolder = folder;
+        mRecentFolderList = mRecentFolders.changeCurrentFolder(folder);
     }
 
     /**
@@ -148,12 +146,15 @@
      */
     public void setCurrentAccount(Account account) {
         mCurrentAccount = account;
+        mRecentFolders = new RecentFolderList(mCurrentAccount);
+        mRecentFolderList = mRecentFolders.getSortedArray(mCurrentFolder);
+        notifyDataSetChanged();
     }
 
     @Override
     public int getCount() {
-        // All the accounts, plus one header, and optionally some folders
-        return mNumAccounts + 1 + mFolders.length;
+        // All the accounts, plus one header, plus recent folders
+        return mNumAccounts + 1 + mRecentFolderList.length;
     }
 
     @Override
@@ -164,7 +165,10 @@
             case TYPE_HEADER:
                 return "account spinner header";
             default:
-                return mFolders[position - mNumAccounts - 1];
+                // The first few positions have accounts, and then the header.
+                final int offset = position - mNumAccounts - 1;
+                // Return the name of the folder at this location.
+                return mRecentFolderList[offset].name;
         }
     }
 
@@ -210,8 +214,9 @@
                 // Change the name of the current folder
                 final int offset = position - mNumAccounts - 1;
                 accountName = (mCurrentAccount == null) ? "" : mCurrentAccount.name;
-                folderName = mFolders[offset];
-                unreadCount = mUnreadCounts[offset];
+                final Folder folder = mRecentFolderList[offset];
+                folderName = folder.name;
+                unreadCount = folder.unreadCount;
                 break;
         }
 
@@ -286,8 +291,9 @@
                 break;
             case TYPE_FOLDER:
                 final int offset = position - mNumAccounts - 1;
-                textLabel = mFolders[offset];
-                unreadCount = mUnreadCounts[offset];
+                final Folder folder = mRecentFolderList[offset];
+                textLabel = folder.name;
+                unreadCount = folder.unreadCount;
                 break;
         }
 
diff --git a/src/com/android/mail/providers/Folder.java b/src/com/android/mail/providers/Folder.java
index 4a86187..8c730b7 100644
--- a/src/com/android/mail/providers/Folder.java
+++ b/src/com/android/mail/providers/Folder.java
@@ -109,6 +109,16 @@
     public int lastSyncResult;
 
     /**
+     * Folder type. 0 is default.
+     */
+    public int type;
+
+    /**
+     * Icon for this folder; 0 implies no icon.
+     */
+    public long iconResId;
+
+    /**
      * Total number of members that comprise an instance of a folder. This is
      * the number of members that need to be serialized or parceled.
      */
@@ -151,6 +161,8 @@
         refreshUri = in.readParcelable(null);
         syncStatus = in.readInt();
         lastSyncResult = in.readInt();
+        type = in.readInt();
+        iconResId = in.readLong();
      }
 
     public Folder(Cursor cursor) {
@@ -171,6 +183,8 @@
         refreshUri = !TextUtils.isEmpty(refresh) ? Uri.parse(refresh) : null;
         syncStatus = cursor.getInt(UIProvider.FOLDER_SYNC_STATUS_COLUMN);
         lastSyncResult = cursor.getInt(UIProvider.FOLDER_LAST_SYNC_RESULT_COLUMN);
+        type = cursor.getInt(UIProvider.FOLDER_TYPE_COLUMN);
+        iconResId = cursor.getLong(UIProvider.FOLDER_ICON_RES_ID_COLUMN);
     }
 
     @Override
@@ -189,6 +203,8 @@
         dest.writeParcelable(refreshUri, 0);
         dest.writeInt(syncStatus);
         dest.writeInt(lastSyncResult);
+        dest.writeInt(type);
+        dest.writeLong(iconResId);
     }
 
     /**
@@ -208,7 +224,9 @@
         out.append(totalCount).append(FOLDER_COMPONENT_SEPARATOR);
         out.append(refreshUri).append(FOLDER_COMPONENT_SEPARATOR);
         out.append(syncStatus).append(FOLDER_COMPONENT_SEPARATOR);
-        out.append(lastSyncResult);
+        out.append(lastSyncResult).append(FOLDER_COMPONENT_SEPARATOR);
+        out.append(type).append(FOLDER_COMPONENT_SEPARATOR);
+        out.append(iconResId);
         return out.toString();
     }
 
@@ -237,6 +255,8 @@
         refreshUri = Uri.parse(folderMembers[10]);
         syncStatus = Integer.valueOf(folderMembers[11]);
         lastSyncResult = Integer.valueOf(folderMembers[12]);
+        type = Integer.valueOf(folderMembers[13]);
+        iconResId = Long.valueOf(folderMembers[14]);
     }
 
     /**
diff --git a/src/com/android/mail/providers/UIProvider.java b/src/com/android/mail/providers/UIProvider.java
index 4687309..dec32f9 100644
--- a/src/com/android/mail/providers/UIProvider.java
+++ b/src/com/android/mail/providers/UIProvider.java
@@ -322,7 +322,9 @@
         FolderColumns.TOTAL_COUNT,
         FolderColumns.REFRESH_URI,
         FolderColumns.SYNC_STATUS,
-        FolderColumns.LAST_SYNC_RESULT
+        FolderColumns.LAST_SYNC_RESULT,
+        FolderColumns.TYPE,
+        FolderColumns.ICON_RES_ID
     };
 
     public static final int FOLDER_ID_COLUMN = 0;
@@ -338,6 +340,18 @@
     public static final int FOLDER_REFRESH_URI_COLUMN = 10;
     public static final int FOLDER_SYNC_STATUS_COLUMN = 11;
     public static final int FOLDER_LAST_SYNC_RESULT_COLUMN = 12;
+    public static final int FOLDER_TYPE_COLUMN = 13;
+    public static final int FOLDER_ICON_RES_ID_COLUMN = 14;
+
+    public static final class FolderType {
+        public static final int DEFAULT = 0;
+        public static final int INBOX = 1;
+        public static final int DRAFT = 2;
+        public static final int OUTBOX = 3;
+        public static final int SENT = 4;
+        public static final int TRASH = 5;
+        public static final int SPAM = 6;
+    }
 
     public static final class FolderCapabilities {
         public static final int SYNCABLE = 0x0001;
@@ -412,7 +426,14 @@
          * LastSyncStatus values defined above
          */
         public static final String LAST_SYNC_RESULT  = "lastSyncResult";
-
+        /**
+         * This long column contains the icon res id for this folder, or 0 if there is none.
+         */
+        public static final String ICON_RES_ID = "iconResId";
+        /**
+         * This int column contains the type of the folder. Zero is default.
+         */
+        public static final String TYPE = "type";
         public FolderColumns() {}
     }
 
diff --git a/src/com/android/mail/ui/FolderSelectorAdapter.java b/src/com/android/mail/ui/FolderSelectorAdapter.java
index 0068279..6bf389d 100644
--- a/src/com/android/mail/ui/FolderSelectorAdapter.java
+++ b/src/com/android/mail/ui/FolderSelectorAdapter.java
@@ -39,7 +39,7 @@
 import java.util.Set;
 
 /**
- * An adapter for translating a {@link LabelList} to a set of selectable views to be used for
+ * An adapter for translating a {@link FolderList} to a set of selectable views to be used for
  * applying labels to one or more conversations.
  */
 public class FolderSelectorAdapter extends BaseAdapter {
diff --git a/src/com/android/mail/ui/RecentFolderList.java b/src/com/android/mail/ui/RecentFolderList.java
new file mode 100644
index 0000000..5406993
--- /dev/null
+++ b/src/com/android/mail/ui/RecentFolderList.java
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2011, Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mail.ui;
+
+import android.text.TextUtils;
+
+import com.android.mail.providers.Account;
+import com.android.mail.providers.Folder;
+import com.android.mail.utils.LogUtils;
+import com.android.mail.utils.LruCache;
+
+import java.util.Collections;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Comparator;
+
+/**
+ * A self-updating list of folder canonical names for the N most recently touched folders, ordered
+ * from least-recently-touched to most-recently-touched. N is a fixed size determined upon
+ * creation.
+ *
+ * RecentFoldersCache returns lists of this type, and will keep them updated when observers are
+ * registered on them.
+ *
+ */
+public final class RecentFolderList {
+    private static final String LOG_TAG = new LogUtils().getLogTag();
+    /**
+     * Compare based on alphanumeric name of the folder, ignoring case.
+     */
+    private static final Comparator<Folder> ALPHABET_IGNORECASE = new Comparator<Folder>() {
+        @Override
+        public int compare(Folder lhs, Folder rhs) {
+            return lhs.name.compareToIgnoreCase(rhs.name);
+        }
+    };
+    private final LruCache<String, Folder> mFolderCache;
+
+    /**
+     * Create a Recent Folder List from the given account. This will query the UIProvider to
+     * retrieve the RecentFolderList from persistent storage (if any).
+     * @param account
+     */
+    public RecentFolderList(Account account) {
+        // We want to show five recent folders, and one space for the current folder (not displayed
+        // to user).
+        final int NUM_ACCOUNTS = 5 + 1;
+        mFolderCache = new LruCache<String, Folder>(NUM_ACCOUNTS);
+    }
+
+    /**
+     * Changes the current folder and returns the updated list of recent folders, <b>not</b>
+     * including the current folder.
+     * @param folder the folder we have changed to.
+     */
+    public Folder[] changeCurrentFolder(Folder folder) {
+        mFolderCache.putElement(folder.id, folder);
+        return getSortedArray(folder);
+    }
+
+    /**
+     * Requests the UIProvider to save this RecentFolderList to persistent storage.
+     */
+    public void save() {
+        // TODO: Implement
+    }
+
+    /**
+     * Generate a sorted array of recent folders, <b>not</b> including the current folder.
+     * @param currentFolder the current folder being displayed.
+     */
+    public Folder[] getSortedArray(Folder currentFolder) {
+        final int spaceForCurrentFolder =
+                (currentFolder != null && mFolderCache.getElement(currentFolder.id) != null)
+                        ? 1 : 0;
+        final int numRecents = mFolderCache.size() - spaceForCurrentFolder;
+        final Folder[] folders = new Folder[numRecents];
+        int i = 0;
+        final List<Folder> recent = new ArrayList<Folder>(mFolderCache.values());
+        Collections.sort(recent, ALPHABET_IGNORECASE);
+        for (Folder f : recent) {
+            if (!TextUtils.equals(f.id, currentFolder.id)) {
+                folders[i++] = f;
+            }
+        }
+        return folders;
+    }
+}
diff --git a/src/com/android/mail/utils/LruCache.java b/src/com/android/mail/utils/LruCache.java
new file mode 100644
index 0000000..22c9e6f
--- /dev/null
+++ b/src/com/android/mail/utils/LruCache.java
@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) 2011, Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mail.utils;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * A simple in-memory LRU cache, which is trivial to implement on top
+ * of JDK's {@link LinkedHashMap}.
+ *
+ * LRU policy is ensured by the underlying LinkedHashMap functionality.
+ */
+public final class LruCache<K, V> extends LinkedHashMap<K, V> {
+    private static final long serialVersionUID = 1L;
+    private final int maxCapacity;
+
+    /**
+     * Creates an instance of LRUCache, with given capacity.
+     *
+     * @param capacity maximum number of elements in the cache. This is also
+     * used as initialCapacity i.e. memory is allocated upfront.
+     */
+    public LruCache(int capacity) {
+        this(capacity, capacity);
+    }
+
+    /**
+     * Creates an instance of LRUCache, with given capacity.
+     *
+     * @param initialCapacity initial capacity of the cache.
+     * @param maxCapacity maximum number of elements in the cache.
+     */
+    private LruCache(int initialCapacity, int maxCapacity) {
+        super(initialCapacity, (float) 0.75, true);
+        this.maxCapacity = maxCapacity;
+    }
+
+    // These methods are needed because the default implementation of LinkedHashMap is *not*
+    // synchronized.
+    /**
+     * Gets an element from the cache, returning the element if found, or null if not
+     * @param key
+     * @return
+     */
+    public synchronized V getElement(K key) {
+        return get(key);
+    }
+
+    /**
+     * Puts an element into the cache.
+     * @param key
+     * @param value, a non-null value.
+     */
+    public synchronized void putElement(K key, V value) {
+        put(key, value);
+    }
+
+    /**
+     * Removes an element from the cache. Returns the removed element, or null if no such element
+     * existed in the cache.
+     * @param key
+     * @return
+     */
+    public synchronized V removeElement(K key) {
+        return remove(key);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * Necessary to override because HashMap increases the capacity of the
+     * hashtable before inserting the elements. However, here we call put() which
+     * checks if we can remove the eldest element before increasing the capacity.
+     */
+    @Override
+    public synchronized void putAll(Map<? extends K, ? extends V> m) {
+        for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
+            put(e.getKey(), e.getValue());
+        }
+    }
+
+    /**
+     * This method is called by LinkedHashMap to check whether the eldest entry
+     * should be removed.
+     *
+     * @param eldest
+     * @return true if element should be removed.
+     */
+    @Override
+    protected synchronized boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+        return size() > maxCapacity;
+    }
+}