Folder.java revision 42fe486e9e80a13d7f94573af1000f883a5d9dab
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.database.Cursor;
22import android.graphics.drawable.PaintDrawable;
23import android.net.Uri;
24import android.net.Uri.Builder;
25import android.os.Parcel;
26import android.os.Parcelable;
27import android.text.TextUtils;
28import android.view.View;
29import android.widget.ImageView;
30
31import com.android.mail.content.CursorCreator;
32import com.android.mail.content.ObjectCursorLoader;
33import com.android.mail.providers.UIProvider.FolderType;
34import com.android.mail.utils.FolderUri;
35import com.android.mail.utils.LogTag;
36import com.android.mail.utils.LogUtils;
37import com.android.mail.utils.Utils;
38import com.google.common.annotations.VisibleForTesting;
39import com.google.common.base.Objects;
40
41import java.util.Collection;
42import java.util.Collections;
43import java.util.HashMap;
44import java.util.List;
45import java.util.regex.Pattern;
46
47/**
48 * A folder is a collection of conversations, and perhaps other folders.
49 */
50// TODO: make most of these fields final
51public class Folder implements Parcelable, Comparable<Folder> {
52
53    @Deprecated
54    public static final String SPLITTER = "^*^";
55    @Deprecated
56    private static final Pattern SPLITTER_REGEX = Pattern.compile("\\^\\*\\^");
57
58    private static final String FOLDER_UNINITIALIZED = "Uninitialized!";
59
60    // TODO: remove this once we figure out which folder is returning a "null" string as the
61    // conversation list uri
62    private static final String NULL_STRING_URI = "null";
63    private static final String LOG_TAG = LogTag.getLogTag();
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     * Persistent (across installations) id of this folder.
74     */
75    public String persistentId;
76
77    /**
78     * The content provider URI that returns this folder for this account.
79     */
80    public FolderUri folderUri;
81
82    /**
83     * The human visible name for this folder.
84     */
85    public String name;
86
87    /**
88     * The possible capabilities that this folder supports.
89     */
90    public int capabilities;
91
92    /**
93     * Whether or not this folder has children folders.
94     */
95    public boolean hasChildren;
96
97    /**
98     * How large the synchronization window is: how many days worth of data is retained on the
99     * device.
100     */
101    public int syncWindow;
102
103    /**
104     * The content provider URI to return the list of conversations in this
105     * folder.
106     */
107    public Uri conversationListUri;
108
109    /**
110     * The content provider URI to return the list of child folders of this folder.
111     */
112    public Uri childFoldersListUri;
113
114    /**
115     * The number of messages that are unseen in this folder.
116     */
117    public int unseenCount;
118
119    /**
120     * The number of messages that are unread in this folder.
121     */
122    public int unreadCount;
123
124    /**
125     * The total number of messages in this folder.
126     */
127    public int totalCount;
128
129    /**
130     * The content provider URI to force a refresh of this folder.
131     */
132    public Uri refreshUri;
133
134    /**
135     * The current sync status of the folder
136     */
137    public int syncStatus;
138
139    /**
140     * A packed integer containing the last synced result, and the request code. The
141     * value is (requestCode << 4) | syncResult
142     * syncResult is a value from {@link UIProvider.LastSyncResult}
143     * requestCode is a value from: {@link UIProvider.SyncStatus},
144     */
145    public int lastSyncResult;
146
147    /**
148     * Folder type bit mask. 0 is default.
149     * @see FolderType
150     */
151    public int type;
152
153    /**
154     * Icon for this folder; 0 implies no icon.
155     */
156    public int iconResId;
157
158    /**
159     * Notification icon for this folder; 0 implies no icon.
160     */
161    public int notificationIconResId;
162
163    public String bgColor;
164    public String fgColor;
165
166    public int bgColorInt;
167    public int fgColorInt;
168
169    /**
170     * The content provider URI to request additional conversations
171     */
172    public Uri loadMoreUri;
173
174    /**
175     * The possibly empty name of this folder with full hierarchy.
176     * The expected format is: parent/folder1/folder2/folder3/folder4
177     */
178    public String hierarchicalDesc;
179
180    /**
181     * Parent folder of this folder, or null if there is none.
182     */
183    public Uri parent;
184
185    /**
186     * The time at which the last message was received.
187     */
188    public long lastMessageTimestamp;
189
190    /**
191     * A string of unread senders sorted by date, so we don't have to fetch this in multiple queries
192     */
193    public String unreadSenders;
194
195    /** An immutable, empty conversation list */
196    public static final Collection<Folder> EMPTY = Collections.emptyList();
197
198    public static final class Builder {
199        private int mId;
200        private String mPersistentId;
201        private Uri mUri;
202        private String mName;
203        private int mCapabilities;
204        private boolean mHasChildren;
205        private int mSyncWindow;
206        private Uri mConversationListUri;
207        private Uri mChildFoldersListUri;
208        private int mUnseenCount;
209        private int mUnreadCount;
210        private int mTotalCount;
211        private Uri mRefreshUri;
212        private int mSyncStatus;
213        private int mLastSyncResult;
214        private int mType;
215        private int mIconResId;
216        private int mNotificationIconResId;
217        private String mBgColor;
218        private String mFgColor;
219        private Uri mLoadMoreUri;
220        private String mHierarchicalDesc;
221        private Uri mParent;
222        private long mLastMessageTimestamp;
223        private String mUnreadSenders;
224
225        public Folder build() {
226            return new Folder(mId, mPersistentId, mUri, mName, mCapabilities,
227                    mHasChildren, mSyncWindow, mConversationListUri, mChildFoldersListUri,
228                    mUnseenCount, mUnreadCount, mTotalCount, mRefreshUri, mSyncStatus,
229                    mLastSyncResult, mType, mIconResId, mNotificationIconResId, mBgColor,
230                    mFgColor, mLoadMoreUri, mHierarchicalDesc, mParent,
231                    mLastMessageTimestamp, mUnreadSenders);
232        }
233
234        public Builder setId(final int id) {
235            mId = id;
236            return this;
237        }
238        public Builder setPersistentId(final String persistentId) {
239            mPersistentId = persistentId;
240            return this;
241        }
242        public Builder setUri(final Uri uri) {
243            mUri = uri;
244            return this;
245        }
246        public Builder setName(final String name) {
247            mName = name;
248            return this;
249        }
250        public Builder setCapabilities(final int capabilities) {
251            mCapabilities = capabilities;
252            return this;
253        }
254        public Builder setHasChildren(final boolean hasChildren) {
255            mHasChildren = hasChildren;
256            return this;
257        }
258        public Builder setSyncWindow(final int syncWindow) {
259            mSyncWindow = syncWindow;
260            return this;
261        }
262        public Builder setConversationListUri(final Uri conversationListUri) {
263            mConversationListUri = conversationListUri;
264            return this;
265        }
266        public Builder setChildFoldersListUri(final Uri childFoldersListUri) {
267            mChildFoldersListUri = childFoldersListUri;
268            return this;
269        }
270        public Builder setUnseenCount(final int unseenCount) {
271            mUnseenCount = unseenCount;
272            return this;
273        }
274        public Builder setUnreadCount(final int unreadCount) {
275            mUnreadCount = unreadCount;
276            return this;
277        }
278        public Builder setTotalCount(final int totalCount) {
279            mTotalCount = totalCount;
280            return this;
281        }
282        public Builder setRefreshUri(final Uri refreshUri) {
283            mRefreshUri = refreshUri;
284            return this;
285        }
286        public Builder setSyncStatus(final int syncStatus) {
287            mSyncStatus = syncStatus;
288            return this;
289        }
290        public Builder setLastSyncResult(final int lastSyncResult) {
291            mLastSyncResult = lastSyncResult;
292            return this;
293        }
294        public Builder setType(final int type) {
295            mType = type;
296            return this;
297        }
298        public Builder setIconResId(final int iconResId) {
299            mIconResId = iconResId;
300            return this;
301        }
302        public Builder setNotificationIconResId(final int notificationIconResId) {
303            mNotificationIconResId = notificationIconResId;
304            return this;
305        }
306        public Builder setBgColor(final String bgColor) {
307            mBgColor = bgColor;
308            return this;
309        }
310        public Builder setFgColor(final String fgColor) {
311            mFgColor = fgColor;
312            return this;
313        }
314        public Builder setLoadMoreUri(final Uri loadMoreUri) {
315            mLoadMoreUri = loadMoreUri;
316            return this;
317        }
318        public Builder setHierarchicalDesc(final String hierarchicalDesc) {
319            mHierarchicalDesc = hierarchicalDesc;
320            return this;
321        }
322        public Builder setParent(final Uri parent) {
323            mParent = parent;
324            return this;
325        }
326        public Builder setLastMessageTimestamp(final long lastMessageTimestamp) {
327            mLastMessageTimestamp = lastMessageTimestamp;
328            return this;
329        }
330        public Builder setUnreadSenders(final String unreadSenders) {
331            mUnreadSenders = unreadSenders;
332            return this;
333        }
334    }
335
336    public Folder(int id, String persistentId, Uri uri, String name, int capabilities,
337            boolean hasChildren, int syncWindow, Uri conversationListUri, Uri childFoldersListUri,
338            int unseenCount, int unreadCount, int totalCount, Uri refreshUri, int syncStatus,
339            int lastSyncResult, int type, int iconResId, int notificationIconResId, String bgColor,
340            String fgColor, Uri loadMoreUri, String hierarchicalDesc, Uri parent,
341            final long lastMessageTimestamp, final String unreadSenders) {
342        this.id = id;
343        this.persistentId = persistentId;
344        this.folderUri = new FolderUri(uri);
345        this.name = name;
346        this.capabilities = capabilities;
347        this.hasChildren = hasChildren;
348        this.syncWindow = syncWindow;
349        this.conversationListUri = conversationListUri;
350        this.childFoldersListUri = childFoldersListUri;
351        this.unseenCount = unseenCount;
352        this.unreadCount = unreadCount;
353        this.totalCount = totalCount;
354        this.refreshUri = refreshUri;
355        this.syncStatus = syncStatus;
356        this.lastSyncResult = lastSyncResult;
357        this.type = type;
358        this.iconResId = iconResId;
359        this.notificationIconResId = notificationIconResId;
360        this.bgColor = bgColor;
361        this.fgColor = fgColor;
362        if (bgColor != null) {
363            this.bgColorInt = Integer.parseInt(bgColor);
364        }
365        if (fgColor != null) {
366            this.fgColorInt = Integer.parseInt(fgColor);
367        }
368        this.loadMoreUri = loadMoreUri;
369        this.hierarchicalDesc = hierarchicalDesc;
370        this.lastMessageTimestamp = lastMessageTimestamp;
371        this.parent = parent;
372        this.unreadSenders = unreadSenders;
373    }
374
375    public Folder(Cursor cursor) {
376        id = cursor.getInt(UIProvider.FOLDER_ID_COLUMN);
377        persistentId = cursor.getString(UIProvider.FOLDER_PERSISTENT_ID_COLUMN);
378        folderUri =
379                new FolderUri(Uri.parse(cursor.getString(UIProvider.FOLDER_URI_COLUMN)));
380        name = cursor.getString(UIProvider.FOLDER_NAME_COLUMN);
381        capabilities = cursor.getInt(UIProvider.FOLDER_CAPABILITIES_COLUMN);
382        // 1 for true, 0 for false.
383        hasChildren = cursor.getInt(UIProvider.FOLDER_HAS_CHILDREN_COLUMN) == 1;
384        syncWindow = cursor.getInt(UIProvider.FOLDER_SYNC_WINDOW_COLUMN);
385        String convList = cursor.getString(UIProvider.FOLDER_CONVERSATION_LIST_URI_COLUMN);
386        conversationListUri = !TextUtils.isEmpty(convList) ? Uri.parse(convList) : null;
387        String childList = cursor.getString(UIProvider.FOLDER_CHILD_FOLDERS_LIST_COLUMN);
388        childFoldersListUri = (hasChildren && !TextUtils.isEmpty(childList)) ? Uri.parse(childList)
389                : null;
390        unseenCount = cursor.getInt(UIProvider.FOLDER_UNSEEN_COUNT_COLUMN);
391        unreadCount = cursor.getInt(UIProvider.FOLDER_UNREAD_COUNT_COLUMN);
392        totalCount = cursor.getInt(UIProvider.FOLDER_TOTAL_COUNT_COLUMN);
393        String refresh = cursor.getString(UIProvider.FOLDER_REFRESH_URI_COLUMN);
394        refreshUri = !TextUtils.isEmpty(refresh) ? Uri.parse(refresh) : null;
395        syncStatus = cursor.getInt(UIProvider.FOLDER_SYNC_STATUS_COLUMN);
396        lastSyncResult = cursor.getInt(UIProvider.FOLDER_LAST_SYNC_RESULT_COLUMN);
397        type = cursor.getInt(UIProvider.FOLDER_TYPE_COLUMN);
398        iconResId = cursor.getInt(UIProvider.FOLDER_ICON_RES_ID_COLUMN);
399        notificationIconResId = cursor.getInt(UIProvider.FOLDER_NOTIFICATION_ICON_RES_ID_COLUMN);
400        bgColor = cursor.getString(UIProvider.FOLDER_BG_COLOR_COLUMN);
401        fgColor = cursor.getString(UIProvider.FOLDER_FG_COLOR_COLUMN);
402        if (bgColor != null) {
403            bgColorInt = Integer.parseInt(bgColor);
404        }
405        if (fgColor != null) {
406            fgColorInt = Integer.parseInt(fgColor);
407        }
408        String loadMore = cursor.getString(UIProvider.FOLDER_LOAD_MORE_URI_COLUMN);
409        loadMoreUri = !TextUtils.isEmpty(loadMore) ? Uri.parse(loadMore) : null;
410        hierarchicalDesc = cursor.getString(UIProvider.FOLDER_HIERARCHICAL_DESC_COLUMN);
411        lastMessageTimestamp = cursor.getLong(UIProvider.FOLDER_LAST_MESSAGE_TIMESTAMP_COLUMN);
412        // A null parent URI means that this is a top-level folder.
413        final String parentString = cursor.getString(UIProvider.FOLDER_PARENT_URI_COLUMN);
414        parent = parentString == null ? Uri.EMPTY : Uri.parse(parentString);
415        final int unreadSendersColumn =
416                cursor.getColumnIndex(UIProvider.FolderColumns.UNREAD_SENDERS);
417        if (unreadSendersColumn != -1) {
418            unreadSenders = cursor.getString(unreadSendersColumn);
419        } else {
420            unreadSenders = null;
421        }
422    }
423
424    /**
425     * Public object that knows how to construct Folders given Cursors.
426     */
427    public static final CursorCreator<Folder> FACTORY = new CursorCreator<Folder>() {
428        @Override
429        public Folder createFromCursor(Cursor c) {
430            return new Folder(c);
431        }
432
433        @Override
434        public String toString() {
435            return "Folder CursorCreator";
436        }
437    };
438
439    public Folder(Parcel in, ClassLoader loader) {
440        id = in.readInt();
441        persistentId = in.readString();
442        folderUri = new FolderUri((Uri) in.readParcelable(loader));
443        name = in.readString();
444        capabilities = in.readInt();
445        // 1 for true, 0 for false.
446        hasChildren = in.readInt() == 1;
447        syncWindow = in.readInt();
448        conversationListUri = in.readParcelable(loader);
449        childFoldersListUri = in.readParcelable(loader);
450        unseenCount = in.readInt();
451        unreadCount = in.readInt();
452        totalCount = in.readInt();
453        refreshUri = in.readParcelable(loader);
454        syncStatus = in.readInt();
455        lastSyncResult = in.readInt();
456        type = in.readInt();
457        iconResId = in.readInt();
458        notificationIconResId = in.readInt();
459        bgColor = in.readString();
460        fgColor = in.readString();
461        if (bgColor != null) {
462            bgColorInt = Integer.parseInt(bgColor);
463        }
464        if (fgColor != null) {
465            fgColorInt = Integer.parseInt(fgColor);
466        }
467        loadMoreUri = in.readParcelable(loader);
468        hierarchicalDesc = in.readString();
469        parent = in.readParcelable(loader);
470        lastMessageTimestamp = in.readLong();
471        parent = in.readParcelable(loader);
472        unreadSenders = in.readString();
473     }
474
475    @Override
476    public void writeToParcel(Parcel dest, int flags) {
477        dest.writeInt(id);
478        dest.writeString(persistentId);
479        dest.writeParcelable(folderUri != null ? folderUri.fullUri : null, 0);
480        dest.writeString(name);
481        dest.writeInt(capabilities);
482        // 1 for true, 0 for false.
483        dest.writeInt(hasChildren ? 1 : 0);
484        dest.writeInt(syncWindow);
485        dest.writeParcelable(conversationListUri, 0);
486        dest.writeParcelable(childFoldersListUri, 0);
487        dest.writeInt(unseenCount);
488        dest.writeInt(unreadCount);
489        dest.writeInt(totalCount);
490        dest.writeParcelable(refreshUri, 0);
491        dest.writeInt(syncStatus);
492        dest.writeInt(lastSyncResult);
493        dest.writeInt(type);
494        dest.writeInt(iconResId);
495        dest.writeInt(notificationIconResId);
496        dest.writeString(bgColor);
497        dest.writeString(fgColor);
498        dest.writeParcelable(loadMoreUri, 0);
499        dest.writeString(hierarchicalDesc);
500        dest.writeParcelable(parent, 0);
501        dest.writeLong(lastMessageTimestamp);
502        dest.writeParcelable(parent, 0);
503        dest.writeString(unreadSenders);
504    }
505
506    /**
507     * Construct a folder that queries for search results. Do not call on the UI
508     * thread.
509     */
510    public static ObjectCursorLoader<Folder> forSearchResults(Account account, String query,
511            Context context) {
512        if (account.searchUri != null) {
513            final Uri.Builder searchBuilder = account.searchUri.buildUpon();
514            searchBuilder.appendQueryParameter(UIProvider.SearchQueryParameters.QUERY, query);
515            final Uri searchUri = searchBuilder.build();
516            return new ObjectCursorLoader<Folder>(context, searchUri, UIProvider.FOLDERS_PROJECTION,
517                    FACTORY);
518        }
519        return null;
520    }
521
522    public static HashMap<Uri, Folder> hashMapForFolders(List<Folder> rawFolders) {
523        final HashMap<Uri, Folder> folders = new HashMap<Uri, Folder>();
524        for (Folder f : rawFolders) {
525            folders.put(f.folderUri.getComparisonUri(), f);
526        }
527        return folders;
528    }
529
530    /**
531     * Constructor that leaves everything uninitialized.
532     */
533    private Folder() {
534        name = FOLDER_UNINITIALIZED;
535    }
536
537    /**
538     * Creates a new instance of a folder object that is <b>not</b> initialized.  The caller is
539     * expected to fill in the details. Used only for testing.
540     * @return a new instance of an unsafe folder.
541     */
542    @VisibleForTesting
543    public static Folder newUnsafeInstance() {
544        return new Folder();
545    }
546
547    public static final ClassLoaderCreator<Folder> CREATOR = new ClassLoaderCreator<Folder>() {
548        @Override
549        public Folder createFromParcel(Parcel source) {
550            return new Folder(source, null);
551        }
552
553        @Override
554        public Folder createFromParcel(Parcel source, ClassLoader loader) {
555            return new Folder(source, loader);
556        }
557
558        @Override
559        public Folder[] newArray(int size) {
560            return new Folder[size];
561        }
562    };
563
564    @Override
565    public int describeContents() {
566        // Return a sort of version number for this parcelable folder. Starting with zero.
567        return 0;
568    }
569
570    @Override
571    public boolean equals(Object o) {
572        if (o == null || !(o instanceof Folder)) {
573            return false;
574        }
575        return Objects.equal(folderUri, ((Folder) o).folderUri);
576    }
577
578    @Override
579    public int hashCode() {
580        return folderUri == null ? 0 : folderUri.hashCode();
581    }
582
583    @Override
584    public String toString() {
585        // log extra info at DEBUG level or finer
586        final StringBuilder sb = new StringBuilder("[folder id=");
587        sb.append(id);
588        if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
589            sb.append(", uri=");
590            sb.append(folderUri);
591            sb.append(", name=");
592            sb.append(name);
593        }
594        sb.append("]");
595        return sb.toString();
596    }
597
598    @Override
599    public int compareTo(Folder other) {
600        return name.compareToIgnoreCase(other.name);
601    }
602
603    /**
604     * Returns a boolean indicating whether network activity (sync) is occuring for this folder.
605     */
606    public boolean isSyncInProgress() {
607        return UIProvider.SyncStatus.isSyncInProgress(syncStatus);
608    }
609
610    public boolean supportsCapability(int capability) {
611        return (capabilities & capability) != 0;
612    }
613
614    // Show black text on a transparent swatch for system folders, effectively hiding the
615    // swatch (see bug 2431925).
616    public static void setFolderBlockColor(Folder folder, View colorBlock) {
617        if (colorBlock == null) {
618            return;
619        }
620        boolean showBg =
621                !TextUtils.isEmpty(folder.bgColor) && (folder.type & FolderType.INBOX_SECTION) == 0;
622        final int backgroundColor = showBg ? Integer.parseInt(folder.bgColor) : 0;
623        if (backgroundColor == Utils.getDefaultFolderBackgroundColor(colorBlock.getContext())) {
624            showBg = false;
625        }
626        if (!showBg) {
627            colorBlock.setBackgroundDrawable(null);
628            colorBlock.setVisibility(View.GONE);
629        } else {
630            PaintDrawable paintDrawable = new PaintDrawable();
631            paintDrawable.getPaint().setColor(backgroundColor);
632            colorBlock.setBackgroundDrawable(paintDrawable);
633            colorBlock.setVisibility(View.VISIBLE);
634        }
635    }
636
637    public static void setIcon(Folder folder, ImageView iconView) {
638        if (iconView == null) {
639            return;
640        }
641        final int icon = folder.iconResId;
642        if (icon > 0) {
643            iconView.setImageResource(icon);
644            iconView.setVisibility(View.VISIBLE);
645        } else {
646            iconView.setVisibility(View.GONE);
647        }
648    }
649
650    /**
651     * Return if the type of the folder matches a provider defined folder.
652     */
653    public boolean isProviderFolder() {
654        return !isType(UIProvider.FolderType.DEFAULT);
655    }
656
657    public int getBackgroundColor(int defaultColor) {
658        return bgColor != null ? bgColorInt : defaultColor;
659    }
660
661    public int getForegroundColor(int defaultColor) {
662        return fgColor != null ? fgColorInt : defaultColor;
663    }
664
665    /**
666     * Get just the uri's from an arraylist of folders.
667     */
668    public static String[] getUriArray(List<Folder> folders) {
669        if (folders == null || folders.size() == 0) {
670            return new String[0];
671        }
672        final String[] folderUris = new String[folders.size()];
673        int i = 0;
674        for (Folder folder : folders) {
675            folderUris[i] = folder.folderUri.toString();
676            i++;
677        }
678        return folderUris;
679    }
680
681    /**
682     * Returns a boolean indicating whether this Folder object has been initialized
683     */
684    public boolean isInitialized() {
685        return !name.equals(FOLDER_UNINITIALIZED) && conversationListUri != null &&
686                !NULL_STRING_URI.equals(conversationListUri.toString());
687    }
688
689    public boolean isType(final int folderType) {
690        return isType(type, folderType);
691    }
692
693    /**
694     * Checks if <code>typeMask</code> is of the specified {@link FolderType}
695     *
696     * @return <code>true</code> if the mask contains the specified
697     *         {@link FolderType}, <code>false</code> otherwise
698     */
699    public static boolean isType(final int typeMask, final int folderType) {
700        return (typeMask & folderType) != 0;
701    }
702
703    public boolean isInbox() {
704        return isType(UIProvider.FolderType.INBOX);
705    }
706
707    /**
708     * Return if this is the trash folder.
709     */
710    public boolean isTrash() {
711        return isType(UIProvider.FolderType.TRASH);
712    }
713
714    /**
715     * Return if this is a draft folder.
716     */
717    public boolean isDraft() {
718        return isType(UIProvider.FolderType.DRAFT);
719    }
720
721    /**
722     * Whether this folder supports only showing important messages.
723     */
724    public boolean isImportantOnly() {
725        return supportsCapability(
726                UIProvider.FolderCapabilities.ONLY_IMPORTANT);
727    }
728
729    /**
730     * Whether this is the special folder just used to display all mail for an account.
731     */
732    public boolean isViewAll() {
733        return isType(UIProvider.FolderType.ALL_MAIL);
734    }
735
736    /**
737     * @return a non-user facing English string describing this folder's type
738     */
739    public String getTypeDescription() {
740        final String desc;
741        if (isType(FolderType.INBOX_SECTION)) {
742            desc = "inbox_section:" + persistentId;
743        } else if (isInbox()) {
744            desc = "inbox:" + persistentId;
745        } else if (isDraft()) {
746            desc = "draft";
747        } else if (isImportantOnly()) {
748            desc = "important";
749        } else if (isType(FolderType.OUTBOX)) {
750            desc = "outbox";
751        } else if (isType(FolderType.SENT)) {
752            desc = "sent";
753        } else if (isType(FolderType.SPAM)) {
754            desc = "spam";
755        } else if (isType(FolderType.STARRED)) {
756            desc = "starred";
757        } else if (isTrash()) {
758            desc = "trash";
759        } else if (isType(FolderType.UNREAD)) {
760            desc = "unread";
761        } else if (isViewAll()) {
762            desc = "all_mail";
763        } else if (isProviderFolder()) {
764            desc = "other:" + persistentId;
765        } else {
766            desc = "user_folder";
767        }
768        return desc;
769    }
770
771    /**
772     * True if the previous sync was successful, false otherwise.
773     * @return
774     */
775    public final boolean wasSyncSuccessful() {
776        return ((lastSyncResult & 0x0f) == UIProvider.LastSyncResult.SUCCESS);
777    }
778
779    /**
780     * Returns true if unread count should be suppressed for this folder. This is done for folders
781     * where the unread count is meaningless: trash or drafts, for instance.
782     * @return true if unread count should be suppressed for this object.
783     */
784    public final boolean isUnreadCountHidden() {
785        return (isDraft() || isTrash() || isType(FolderType.OUTBOX));
786    }
787
788    /**
789     * This method is only used for parsing folders out of legacy intent extras, and only the
790     * folderUri and conversationListUri fields are actually read before the object is discarded.
791     * TODO: replace this with a parsing function that just directly returns those values
792     * @param inString UR8 or earlier EXTRA_FOLDER intent extra string
793     * @return Constructed folder object
794     */
795    @Deprecated
796    public static Folder fromString(String inString) {
797        if (TextUtils.isEmpty(inString)) {
798            return null;
799        }
800        final Folder f = new Folder();
801        int indexOf = inString.indexOf(SPLITTER);
802        int id = -1;
803        if (indexOf != -1) {
804            id = Integer.valueOf(inString.substring(0, indexOf));
805        } else {
806            // If no separator was found, we can't parse this folder and the
807            // TextUtils.split call would also fail. Return null.
808            return null;
809        }
810        final String[] split = TextUtils.split(inString, SPLITTER_REGEX);
811        if (split.length < 20) {
812            LogUtils.e(LOG_TAG, "split.length %d", split.length);
813            return null;
814        }
815        f.id = id;
816        int index = 1;
817        f.folderUri = new FolderUri(Folder.getValidUri(split[index++]));
818        f.name = split[index++];
819        f.hasChildren = Integer.parseInt(split[index++]) != 0;
820        f.capabilities = Integer.parseInt(split[index++]);
821        f.syncWindow = Integer.parseInt(split[index++]);
822        f.conversationListUri = getValidUri(split[index++]);
823        f.childFoldersListUri = getValidUri(split[index++]);
824        f.unreadCount = Integer.parseInt(split[index++]);
825        f.totalCount = Integer.parseInt(split[index++]);
826        f.refreshUri = getValidUri(split[index++]);
827        f.syncStatus = Integer.parseInt(split[index++]);
828        f.lastSyncResult = Integer.parseInt(split[index++]);
829        f.type = Integer.parseInt(split[index++]);
830        f.iconResId = Integer.parseInt(split[index++]);
831        f.bgColor = split[index++];
832        f.fgColor = split[index++];
833        if (f.bgColor != null) {
834            f.bgColorInt = Integer.parseInt(f.bgColor);
835        }
836        if (f.fgColor != null) {
837            f.fgColorInt = Integer.parseInt(f.fgColor);
838        }
839        f.loadMoreUri = getValidUri(split[index++]);
840        f.hierarchicalDesc = split[index++];
841        f.parent = Folder.getValidUri(split[index++]);
842        f.unreadSenders = null;
843
844        return f;
845    }
846
847    private static Uri getValidUri(String uri) {
848        if (TextUtils.isEmpty(uri)) {
849            return null;
850        }
851        return Uri.parse(uri);
852    }
853}
854