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