Folder.java revision baf93640bfdb8f3a85ad36f90123dcb57dc5c6e9
1/*******************************************************************************
2 *      Copyright (C) 2012 Google Inc.
3 *      Licensed to The Android Open Source Project.
4 *
5 *      Licensed under the Apache License, Version 2.0 (the "License");
6 *      you may not use this file except in compliance with the License.
7 *      You may obtain a copy of the License at
8 *
9 *           http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *      Unless required by applicable law or agreed to in writing, software
12 *      distributed under the License is distributed on an "AS IS" BASIS,
13 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *      See the License for the specific language governing permissions and
15 *      limitations under the License.
16 *******************************************************************************/
17
18package com.android.mail.providers;
19
20import android.content.Context;
21import android.content.CursorLoader;
22import android.database.Cursor;
23import android.graphics.drawable.PaintDrawable;
24import android.net.Uri;
25import android.net.Uri.Builder;
26import android.os.Parcel;
27import android.os.Parcelable;
28import android.text.TextUtils;
29import android.view.View;
30import android.widget.ImageView;
31
32import com.android.mail.utils.LogTag;
33import com.android.mail.utils.LogUtils;
34import com.android.mail.utils.Utils;
35
36import com.google.common.base.Objects;
37import com.google.common.collect.ImmutableList;
38import com.google.common.collect.Maps;
39
40import java.util.ArrayList;
41import java.util.Collection;
42import java.util.Collections;
43import java.util.HashMap;
44import java.util.Map;
45import java.util.regex.Pattern;
46
47/**
48 * A folder is a collection of conversations, and perhaps other folders.
49 */
50public class Folder implements Parcelable, Comparable<Folder> {
51    /**
52     *
53     */
54    private static final String FOLDER_UNINITIALIZED = "Uninitialized!";
55
56    // TODO: remove this once we figure out which folder is returning a "null" string as the
57    // conversation list uri
58    private static final String NULL_STRING_URI = "null";
59    private static final String LOG_TAG = LogTag.getLogTag();
60
61    // Try to match the order of members with the order of constants in UIProvider.
62
63    /**
64     * Unique id of this folder.
65     */
66    public int id;
67
68    /**
69     * The content provider URI that returns this folder for this account.
70     */
71    public Uri uri;
72
73    /**
74     * The human visible name for this folder.
75     */
76    public String name;
77
78    /**
79     * The possible capabilities that this folder supports.
80     */
81    public int capabilities;
82
83    /**
84     * Whether or not this folder has children folders.
85     */
86    public boolean hasChildren;
87
88    /**
89     * How large the synchronization window is: how many days worth of data is retained on the
90     * device.
91     */
92    public int syncWindow;
93
94    /**
95     * The content provider URI to return the list of conversations in this
96     * folder.
97     */
98    public Uri conversationListUri;
99
100    /**
101     * The content provider URI to return the list of child folders of this folder.
102     */
103    public Uri childFoldersListUri;
104
105    /**
106     * The number of messages that are unread in this folder.
107     */
108    public int unreadCount;
109
110    /**
111     * The total number of messages in this folder.
112     */
113    public int totalCount;
114
115    /**
116     * The content provider URI to force a refresh of this folder.
117     */
118    public Uri refreshUri;
119
120    /**
121     * The current sync status of the folder
122     */
123    public int syncStatus;
124
125    /**
126     * A packed integer containing the last synced result, and the request code. The
127     * value is (requestCode << 4) | syncResult
128     * syncResult is a value from {@link UIProvider.LastSyncResult}
129     * requestCode is a value from: {@link UIProvider.SyncStatus},
130     */
131    public int lastSyncResult;
132
133    /**
134     * Folder type. 0 is default.
135     */
136    public int type;
137
138    /**
139     * Icon for this folder; 0 implies no icon.
140     */
141    public long iconResId;
142
143    public String bgColor;
144    public String fgColor;
145
146    /**
147     * The content provider URI to request additional conversations
148     */
149    public Uri loadMoreUri;
150
151    /**
152     * The possibly empty name of this folder with full hierarchy.
153     * The expected format is: parent/folder1/folder2/folder3/folder4
154     */
155    public String hierarchicalDesc;
156
157    /**
158     * Parent folder of this folder, or null if there is none. This is set as
159     * part of the execution of the application and not obtained or stored via
160     * the provider.
161     */
162    public Folder parent;
163
164    /** An immutable, empty conversation list */
165    public static final Collection<Folder> EMPTY = Collections.emptyList();
166
167    public static final String SPLITTER = "^*^";
168    private static final Pattern SPLITTER_REGEX = Pattern.compile("\\^\\*\\^");
169    public static final String FOLDERS_SPLIT = "^**^";
170    private static final Pattern FOLDERS_SPLIT_REGEX = Pattern.compile("\\^\\*\\*\\^");
171
172    public Folder(Parcel in) {
173        id = in.readInt();
174        uri = in.readParcelable(null);
175        name = in.readString();
176        capabilities = in.readInt();
177        // 1 for true, 0 for false.
178        hasChildren = in.readInt() == 1;
179        syncWindow = in.readInt();
180        conversationListUri = in.readParcelable(null);
181        childFoldersListUri = in.readParcelable(null);
182        unreadCount = in.readInt();
183        totalCount = in.readInt();
184        refreshUri = in.readParcelable(null);
185        syncStatus = in.readInt();
186        lastSyncResult = in.readInt();
187        type = in.readInt();
188        iconResId = in.readLong();
189        bgColor = in.readString();
190        fgColor = in.readString();
191        loadMoreUri = in.readParcelable(null);
192        hierarchicalDesc = in.readString();
193        parent = in.readParcelable(null);
194     }
195
196    public Folder(Cursor cursor) {
197        id = cursor.getInt(UIProvider.FOLDER_ID_COLUMN);
198        uri = Uri.parse(cursor.getString(UIProvider.FOLDER_URI_COLUMN));
199        name = cursor.getString(UIProvider.FOLDER_NAME_COLUMN);
200        capabilities = cursor.getInt(UIProvider.FOLDER_CAPABILITIES_COLUMN);
201        // 1 for true, 0 for false.
202        hasChildren = cursor.getInt(UIProvider.FOLDER_HAS_CHILDREN_COLUMN) == 1;
203        syncWindow = cursor.getInt(UIProvider.FOLDER_SYNC_WINDOW_COLUMN);
204        String convList = cursor.getString(UIProvider.FOLDER_CONVERSATION_LIST_URI_COLUMN);
205        conversationListUri = !TextUtils.isEmpty(convList) ? Uri.parse(convList) : null;
206        String childList = cursor.getString(UIProvider.FOLDER_CHILD_FOLDERS_LIST_COLUMN);
207        childFoldersListUri = (hasChildren && !TextUtils.isEmpty(childList)) ? Uri.parse(childList)
208                : null;
209        unreadCount = cursor.getInt(UIProvider.FOLDER_UNREAD_COUNT_COLUMN);
210        totalCount = cursor.getInt(UIProvider.FOLDER_TOTAL_COUNT_COLUMN);
211        String refresh = cursor.getString(UIProvider.FOLDER_REFRESH_URI_COLUMN);
212        refreshUri = !TextUtils.isEmpty(refresh) ? Uri.parse(refresh) : null;
213        syncStatus = cursor.getInt(UIProvider.FOLDER_SYNC_STATUS_COLUMN);
214        lastSyncResult = cursor.getInt(UIProvider.FOLDER_LAST_SYNC_RESULT_COLUMN);
215        type = cursor.getInt(UIProvider.FOLDER_TYPE_COLUMN);
216        iconResId = cursor.getLong(UIProvider.FOLDER_ICON_RES_ID_COLUMN);
217        bgColor = cursor.getString(UIProvider.FOLDER_BG_COLOR_COLUMN);
218        fgColor = cursor.getString(UIProvider.FOLDER_FG_COLOR_COLUMN);
219        String loadMore = cursor.getString(UIProvider.FOLDER_LOAD_MORE_URI_COLUMN);
220        loadMoreUri = !TextUtils.isEmpty(loadMore) ? Uri.parse(loadMore) : null;
221        hierarchicalDesc = cursor.getString(UIProvider.FOLDER_HIERARCHICAL_DESC_COLUMN);
222        parent = null;
223    }
224
225    @Override
226    public void writeToParcel(Parcel dest, int flags) {
227        dest.writeInt(id);
228        dest.writeParcelable(uri, 0);
229        dest.writeString(name);
230        dest.writeInt(capabilities);
231        // 1 for true, 0 for false.
232        dest.writeInt(hasChildren ? 1 : 0);
233        dest.writeInt(syncWindow);
234        dest.writeParcelable(conversationListUri, 0);
235        dest.writeParcelable(childFoldersListUri, 0);
236        dest.writeInt(unreadCount);
237        dest.writeInt(totalCount);
238        dest.writeParcelable(refreshUri, 0);
239        dest.writeInt(syncStatus);
240        dest.writeInt(lastSyncResult);
241        dest.writeInt(type);
242        dest.writeLong(iconResId);
243        dest.writeString(bgColor);
244        dest.writeString(fgColor);
245        dest.writeParcelable(loadMoreUri, 0);
246        dest.writeString(hierarchicalDesc);
247        dest.writeParcelable(parent, 0);
248    }
249
250    /**
251     * Construct a folder that queries for search results. Do not call on the UI
252     * thread.
253     */
254    public static CursorLoader forSearchResults(Account account, String query, Context context) {
255        if (account.searchUri != null) {
256            Builder searchBuilder = account.searchUri.buildUpon();
257            searchBuilder.appendQueryParameter(UIProvider.SearchQueryParameters.QUERY, query);
258            Uri searchUri = searchBuilder.build();
259            return new CursorLoader(context, searchUri, UIProvider.FOLDERS_PROJECTION, null, null,
260                    null);
261        }
262        return null;
263    }
264
265    public static HashMap<Uri, Folder> hashMapForFolders(ArrayList<Folder> rawFolders) {
266        final HashMap<Uri, Folder> folders = new HashMap<Uri, Folder>();
267        for (Folder f : rawFolders) {
268            folders.put(f.uri, f);
269        }
270        return folders;
271    }
272
273    private static Uri getValidUri(String uri) {
274        if (TextUtils.isEmpty(uri)) {
275            return null;
276        }
277        return Uri.parse(uri);
278    }
279
280    /**
281     * Constructor that leaves everything uninitialized.
282     */
283    private Folder() {
284        name = FOLDER_UNINITIALIZED;
285    }
286
287    /**
288     * Creates a new instance of a folder object that is <b>not</b> initialized.  The caller is
289     * expected to fill in the details. This resulting instance is not guaranteed to work
290     * correctly, and might break functionality.  Use at your own risk!!
291     * @return a new instance of an unsafe folder.
292     */
293    public static Folder newUnsafeInstance() {
294        return new Folder();
295    }
296
297    @SuppressWarnings("hiding")
298    public static final Creator<Folder> CREATOR = new Creator<Folder>() {
299        @Override
300        public Folder createFromParcel(Parcel source) {
301            return new Folder(source);
302        }
303
304        @Override
305        public Folder[] newArray(int size) {
306            return new Folder[size];
307        }
308    };
309
310    @Override
311    public int describeContents() {
312        // Return a sort of version number for this parcelable folder. Starting with zero.
313        return 0;
314    }
315
316    @Override
317    public boolean equals(Object o) {
318        if (o == null || !(o instanceof Folder)) {
319            return false;
320        }
321        return Objects.equal(uri, ((Folder) o).uri);
322    }
323
324    @Override
325    public int hashCode() {
326        return uri == null ? 0 : uri.hashCode();
327    }
328
329    @Override
330    public int compareTo(Folder other) {
331        return name.compareToIgnoreCase(other.name);
332    }
333
334    /**
335     * Create a Folder map from a string of serialized folders. This can only be done on the output
336     * of {@link #serialize(Map)}.
337     * @param serializedFolder A string obtained from {@link #serialize(Map)}
338     * @return a Map of folder name to folder.
339     */
340    public static Map<String, Folder> parseFoldersFromString(String serializedFoldersString) {
341        if (TextUtils.isEmpty(serializedFoldersString)) {
342            return null;
343        }
344        Map<String, Folder> folderMap = Maps.newHashMap();
345        ArrayList<Folder> folders = Folder.getFoldersArray(serializedFoldersString);
346        for (Folder folder : folders) {
347            if (folder.name != FOLDER_UNINITIALIZED) {
348                folderMap.put(folder.name, folder);
349            }
350        }
351        return folderMap;
352    }
353
354    /**
355     * Returns a boolean indicating whether network activity (sync) is occuring for this folder.
356     */
357    public boolean isSyncInProgress() {
358        return UIProvider.SyncStatus.isSyncInProgress(syncStatus);
359    }
360
361    /**
362     * Serialize the given list of folders
363     * @param folderMap A valid map of folder names to Folders
364     * @return a string containing a serialized output of folder maps.
365     */
366    public static String serialize(Map<String, Folder> folderMap) {
367        return getSerializedFolderString(folderMap.values());
368    }
369
370    public boolean supportsCapability(int capability) {
371        return (capabilities & capability) != 0;
372    }
373
374    // Show black text on a transparent swatch for system folders, effectively hiding the
375    // swatch (see bug 2431925).
376    public static void setFolderBlockColor(Folder folder, View colorBlock) {
377        if (colorBlock == null) {
378            return;
379        }
380        boolean showBg = !TextUtils.isEmpty(folder.bgColor);
381        final int backgroundColor = showBg ? Integer.parseInt(folder.bgColor) : 0;
382        if (backgroundColor == Utils.getDefaultFolderBackgroundColor(colorBlock.getContext())) {
383            showBg = false;
384        }
385        if (!showBg) {
386            colorBlock.setBackgroundDrawable(null);
387            colorBlock.setVisibility(View.GONE);
388        } else {
389            PaintDrawable paintDrawable = new PaintDrawable();
390            paintDrawable.getPaint().setColor(backgroundColor);
391            colorBlock.setBackgroundDrawable(paintDrawable);
392            colorBlock.setVisibility(View.VISIBLE);
393        }
394    }
395
396    public static void setIcon(Folder folder, ImageView iconView) {
397        if (iconView == null) {
398            return;
399        }
400        final long icon = folder.iconResId;
401        if (icon > 0) {
402            iconView.setImageResource((int)icon);
403            iconView.setVisibility(View.VISIBLE);
404        } else {
405            iconView.setVisibility(View.INVISIBLE);
406        }
407    }
408
409    /**
410     * Return if the type of the folder matches a provider defined folder.
411     */
412    public boolean isProviderFolder() {
413        return type != UIProvider.FolderType.DEFAULT;
414    }
415
416    public int getBackgroundColor(int defaultColor) {
417        return TextUtils.isEmpty(bgColor) ? defaultColor : Integer.parseInt(bgColor);
418    }
419
420    public int getForegroundColor(int defaultColor) {
421        return TextUtils.isEmpty(fgColor) ? defaultColor : Integer.parseInt(fgColor);
422    }
423
424    public static String getSerializedFolderString(Collection<Folder> folders) {
425        final StringBuilder folderList = new StringBuilder();
426        int i = 0;
427        for (Folder folderEntry : folders) {
428            folderList.append(Folder.toString(folderEntry));
429            if (i < folders.size()) {
430                folderList.append(FOLDERS_SPLIT);
431            }
432            i++;
433        }
434        return folderList.toString();
435    }
436
437    public static Folder fromString(String inString) {
438        if (TextUtils.isEmpty(inString)) {
439            return null;
440        }
441        final Folder f = new Folder();
442        int indexOf = inString.indexOf(SPLITTER);
443        int id = -1;
444        if (indexOf != -1) {
445            id = Integer.valueOf(inString.substring(0, indexOf));
446        } else {
447            // If no separator was found, we can't parse this folder and the
448            // TextUtils.split call would also fail. Return null.
449            LogUtils.w(LOG_TAG, "Problem parsing folderId: original string: %s", inString);
450            return null;
451        }
452        final String[] split = TextUtils.split(inString, SPLITTER_REGEX);
453        if (split.length < 20) {
454            return null;
455        }
456        f.id = id;
457        f.uri = Folder.getValidUri(split[1]);
458        f.name = split[2];
459        f.hasChildren = Integer.parseInt(split[3]) != 0;
460        f.capabilities = Integer.parseInt(split[4]);
461        f.syncWindow = Integer.parseInt(split[5]);
462        f.conversationListUri = getValidUri(split[6]);
463        f.childFoldersListUri = getValidUri(split[7]);
464        f.unreadCount = Integer.parseInt(split[8]);
465        f.totalCount = Integer.parseInt(split[9]);
466        f.refreshUri = getValidUri(split[10]);
467        f.syncStatus = Integer.parseInt(split[11]);
468        f.lastSyncResult = Integer.parseInt(split[12]);
469        f.type = Integer.parseInt(split[13]);
470        f.iconResId = Integer.parseInt(split[14]);
471        f.bgColor = split[15];
472        f.fgColor = split[16];
473        f.loadMoreUri = getValidUri(split[17]);
474        f.hierarchicalDesc = split[18];
475        f.parent = Folder.fromString(split[19]);
476        return f;
477    }
478
479    /**
480     * Create a string representation of a folder.
481     */
482    public static String createAsString(int id, Uri uri, String name, boolean hasChildren,
483            int capabilities, int syncWindow, Uri convListUri, Uri childFoldersListUri,
484            int unreadCount, int totalCount, Uri refreshUri, int syncStatus, int lastSyncResult,
485            int type, long iconResId, String bgColor, String fgColor, Uri loadMore,
486            String hierarchicalDesc, Folder parent) {
487        StringBuilder builder = new StringBuilder();
488        builder.append(id);
489        builder.append(SPLITTER);
490        builder.append(uri);
491        builder.append(SPLITTER);
492        builder.append(name);
493        builder.append(SPLITTER);
494        builder.append(hasChildren ? 1 : 0);
495        builder.append(SPLITTER);
496        builder.append(capabilities);
497        builder.append(SPLITTER);
498        builder.append(syncWindow);
499        builder.append(SPLITTER);
500        builder.append(convListUri);
501        builder.append(SPLITTER);
502        builder.append(childFoldersListUri);
503        builder.append(SPLITTER);
504        builder.append(unreadCount);
505        builder.append(SPLITTER);
506        builder.append(totalCount);
507        builder.append(SPLITTER);
508        builder.append(refreshUri);
509        builder.append(SPLITTER);
510        builder.append(syncStatus);
511        builder.append(SPLITTER);
512        builder.append(lastSyncResult);
513        builder.append(SPLITTER);
514        builder.append(type);
515        builder.append(SPLITTER);
516        builder.append(iconResId);
517        builder.append(SPLITTER);
518        builder.append(bgColor != null ? bgColor : "");
519        builder.append(SPLITTER);
520        builder.append(fgColor != null ? fgColor : "");
521        builder.append(SPLITTER);
522        builder.append(loadMore);
523        builder.append(SPLITTER);
524        builder.append(hierarchicalDesc);
525        builder.append(SPLITTER);
526        if (parent != null) {
527            builder.append(Folder.toString(parent));
528        } else {
529            builder.append("");
530        }
531        return builder.toString();
532    }
533
534    public static String toString(Folder folder) {
535        return createAsString(folder.id, folder.uri, folder.name, folder.hasChildren,
536                folder.capabilities, folder.syncWindow, folder.conversationListUri,
537                folder.childFoldersListUri, folder.unreadCount, folder.totalCount,
538                folder.refreshUri, folder.syncStatus, folder.lastSyncResult, folder.type,
539                folder.iconResId, folder.bgColor, folder.fgColor, folder.loadMoreUri,
540                folder.hierarchicalDesc, folder.parent);
541    }
542
543    /**
544     * Returns a comma separated list of folder URIs for all the folders in the collection.
545     * @param folders
546     * @return
547     */
548    public final static String getUriString(Collection<Folder> folders) {
549        final StringBuilder uris = new StringBuilder();
550        boolean first = true;
551        for (Folder f : folders) {
552            if (first) {
553                first = false;
554            } else {
555                uris.append(',');
556            }
557            uris.append(f.uri.toString());
558        }
559        return uris.toString();
560    }
561
562
563    /**
564     * Get an array of folders from a rawFolders string.
565     */
566    public static ArrayList<Folder> getFoldersArray(String rawFolders) {
567        if (TextUtils.isEmpty(rawFolders)) {
568            return null;
569        }
570        ArrayList<Folder> folders = new ArrayList<Folder>();
571        String[] split = TextUtils.split(rawFolders, FOLDERS_SPLIT_REGEX);
572        Folder f;
573        for (String folder : split) {
574            f = Folder.fromString(folder);
575            if (f != null) {
576                folders.add(f);
577            }
578        }
579        return folders;
580    }
581
582    /**
583     * Get just the uri's from an arraylist of folders.
584     */
585    public final static String[] getUriArray(ArrayList<Folder> folders) {
586        if (folders == null || folders.size() == 0) {
587            return new String[0];
588        }
589        String[] folderUris = new String[folders.size()];
590        int i = 0;
591        for (Folder folder : folders) {
592            folderUris[i] = folder.uri.toString();
593            i++;
594        }
595        return folderUris;
596    }
597
598    /**
599     * Returns true if a conversation assigned to the needle will be assigned to the collection of
600     * folders in the haystack. False otherwise. This method is safe to call with null
601     * arguments.
602     * This method returns true under two circumstances
603     * <ul><li> If the URI of the needle was found in the collection of URIs that comprise the
604     * haystack.
605     * </li><li> If the needle is of the type Inbox, and at least one of the folders in the haystack
606     * are of type Inbox. <em>Rationale</em>: there are special folders that are marked as inbox,
607     * and the user might not have the control to assign conversations to them. This happens for
608     * the Priority Inbox in Gmail. When you assign a conversation to an Inbox folder, it will
609     * continue to appear in the Priority Inbox. However, the URI of Priority Inbox and Inbox will
610     * be different. So a direct equality check is insufficient.
611     * </li></ul>
612     * @param haystack a collection of folders, possibly overlapping
613     * @param needle a folder
614     * @return true if a conversation inside the needle will be in the folders in the haystack.
615     */
616    public final static boolean containerIncludes(Collection<Folder> haystack, Folder needle) {
617        // If the haystack is empty, it cannot contain anything.
618        if (haystack == null || haystack.size() <= 0) {
619            return false;
620        }
621        // The null folder exists everywhere.
622        if (needle == null) {
623            return true;
624        }
625        boolean hasInbox = false;
626        // Get currently active folder info and compare it to the list
627        // these conversations have been given; if they no longer contain
628        // the selected folder, delete them from the list.
629        final Uri toFind = needle.uri;
630        for (Folder f : haystack) {
631            if (toFind.equals(f.uri)) {
632                return true;
633            }
634            hasInbox |= (f.type == UIProvider.FolderType.INBOX);
635        }
636        // Did not find the URI of needle directly. If the needle is an Inbox and one of the folders
637        // was an inbox, then the needle is contained (check Javadoc for explanation).
638        final boolean needleIsInbox = (needle.type == UIProvider.FolderType.INBOX);
639        return needleIsInbox ? hasInbox : false;
640    }
641
642    /**
643     * Returns a boolean indicating whether this Folder object has been initialized
644     */
645    public boolean isInitialized() {
646        return name != FOLDER_UNINITIALIZED && conversationListUri != null &&
647                !NULL_STRING_URI.equals(conversationListUri.toString());
648    }
649
650    /**
651     * Returns a collection of a single folder. This method always returns a valid collection
652     * even if the input folder is null.
653     * @param in a folder, possibly null.
654     * @return a collection of the folder.
655     */
656    public static Collection<Folder> listOf(Folder in) {
657        final Collection<Folder> target = (in == null) ? EMPTY : ImmutableList.of(in);
658        return target;
659    }
660
661    /**
662     * Return if this is the trash folder.
663     */
664    public boolean isTrash() {
665        return type == UIProvider.FolderType.TRASH;
666    }
667
668    /**
669     * Return if this is a draft folder.
670     */
671    public boolean isDraft() {
672        return type == UIProvider.FolderType.DRAFT;
673    }
674
675    /**
676     * Whether this folder supports only showing important messages.
677     */
678    public boolean isImportantOnly() {
679        return supportsCapability(
680                UIProvider.FolderCapabilities.ONLY_IMPORTANT);
681    }
682
683    /**
684     * Whether this is the special folder just used to display all mail for an account.
685     */
686    public boolean isViewAll() {
687        return type == UIProvider.FolderType.ALL_MAIL;
688    }
689
690    /**
691     * True if the previous sync was successful, false otherwise.
692     * @return
693     */
694    public final boolean wasSyncSuccessful() {
695        return ((lastSyncResult & 0x0f) == UIProvider.LastSyncResult.SUCCESS);
696    }
697
698    /**
699     * Don't use this for ANYTHING but the FolderListAdapter. It does not have
700     * all the fields.
701     */
702    public static Folder getDeficientDisplayOnlyFolder(Cursor cursor) {
703        Folder f = Folder.newUnsafeInstance();
704        f.id = cursor.getInt(UIProvider.FOLDER_ID_COLUMN);
705        f.uri = Utils.getValidUri(cursor.getString(UIProvider.FOLDER_URI_COLUMN));
706        f.unreadCount = cursor.getInt(UIProvider.FOLDER_UNREAD_COUNT_COLUMN);
707        f.conversationListUri = Utils.getValidUri(cursor
708                .getString(UIProvider.FOLDER_CONVERSATION_LIST_URI_COLUMN));
709        f.type = cursor.getInt(UIProvider.FOLDER_TYPE_COLUMN);
710        f.capabilities = cursor.getInt(UIProvider.FOLDER_CAPABILITIES_COLUMN);
711        f.bgColor = cursor.getString(UIProvider.FOLDER_BG_COLOR_COLUMN);
712        f.name = cursor.getString(UIProvider.FOLDER_NAME_COLUMN);
713        return f;
714    }
715}
716