Folder.java revision 0e627fd594f3809e2bede76379a3348267185196
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    /** An immutable, empty conversation list */
191    public static final Collection<Folder> EMPTY = Collections.emptyList();
192
193    public static final class Builder {
194        private int mId;
195        private String mPersistentId;
196        private Uri mUri;
197        private String mName;
198        private int mCapabilities;
199        private boolean mHasChildren;
200        private int mSyncWindow;
201        private Uri mConversationListUri;
202        private Uri mChildFoldersListUri;
203        private int mUnseenCount;
204        private int mUnreadCount;
205        private int mTotalCount;
206        private Uri mRefreshUri;
207        private int mSyncStatus;
208        private int mLastSyncResult;
209        private int mType;
210        private int mIconResId;
211        private int mNotificationIconResId;
212        private String mBgColor;
213        private String mFgColor;
214        private Uri mLoadMoreUri;
215        private String mHierarchicalDesc;
216        private Uri mParent;
217        private long mLastMessageTimestamp;
218
219        public Folder build() {
220            return new Folder(mId, mPersistentId, mUri, mName, mCapabilities,
221                    mHasChildren, mSyncWindow, mConversationListUri, mChildFoldersListUri,
222                    mUnseenCount, mUnreadCount, mTotalCount, mRefreshUri, mSyncStatus,
223                    mLastSyncResult, mType, mIconResId, mNotificationIconResId, mBgColor,
224                    mFgColor, mLoadMoreUri, mHierarchicalDesc, mParent,
225                    mLastMessageTimestamp);
226        }
227
228        public Builder setId(final int id) {
229            mId = id;
230            return this;
231        }
232        public Builder setPersistentId(final String persistentId) {
233            mPersistentId = persistentId;
234            return this;
235        }
236        public Builder setUri(final Uri uri) {
237            mUri = uri;
238            return this;
239        }
240        public Builder setName(final String name) {
241            mName = name;
242            return this;
243        }
244        public Builder setCapabilities(final int capabilities) {
245            mCapabilities = capabilities;
246            return this;
247        }
248        public Builder setHasChildren(final boolean hasChildren) {
249            mHasChildren = hasChildren;
250            return this;
251        }
252        public Builder setSyncWindow(final int syncWindow) {
253            mSyncWindow = syncWindow;
254            return this;
255        }
256        public Builder setConversationListUri(final Uri conversationListUri) {
257            mConversationListUri = conversationListUri;
258            return this;
259        }
260        public Builder setChildFoldersListUri(final Uri childFoldersListUri) {
261            mChildFoldersListUri = childFoldersListUri;
262            return this;
263        }
264        public Builder setUnseenCount(final int unseenCount) {
265            mUnseenCount = unseenCount;
266            return this;
267        }
268        public Builder setUnreadCount(final int unreadCount) {
269            mUnreadCount = unreadCount;
270            return this;
271        }
272        public Builder setTotalCount(final int totalCount) {
273            mTotalCount = totalCount;
274            return this;
275        }
276        public Builder setRefreshUri(final Uri refreshUri) {
277            mRefreshUri = refreshUri;
278            return this;
279        }
280        public Builder setSyncStatus(final int syncStatus) {
281            mSyncStatus = syncStatus;
282            return this;
283        }
284        public Builder setLastSyncResult(final int lastSyncResult) {
285            mLastSyncResult = lastSyncResult;
286            return this;
287        }
288        public Builder setType(final int type) {
289            mType = type;
290            return this;
291        }
292        public Builder setIconResId(final int iconResId) {
293            mIconResId = iconResId;
294            return this;
295        }
296        public Builder setNotificationIconResId(final int notificationIconResId) {
297            mNotificationIconResId = notificationIconResId;
298            return this;
299        }
300        public Builder setBgColor(final String bgColor) {
301            mBgColor = bgColor;
302            return this;
303        }
304        public Builder setFgColor(final String fgColor) {
305            mFgColor = fgColor;
306            return this;
307        }
308        public Builder setLoadMoreUri(final Uri loadMoreUri) {
309            mLoadMoreUri = loadMoreUri;
310            return this;
311        }
312        public Builder setHierarchicalDesc(final String hierarchicalDesc) {
313            mHierarchicalDesc = hierarchicalDesc;
314            return this;
315        }
316        public Builder setParent(final Uri parent) {
317            mParent = parent;
318            return this;
319        }
320        public Builder setLastMessageTimestamp(final long lastMessageTimestamp) {
321            mLastMessageTimestamp = lastMessageTimestamp;
322            return this;
323        }
324    }
325
326    public Folder(int id, String persistentId, Uri uri, String name, int capabilities,
327            boolean hasChildren, int syncWindow, Uri conversationListUri, Uri childFoldersListUri,
328            int unseenCount, int unreadCount, int totalCount, Uri refreshUri, int syncStatus,
329            int lastSyncResult, int type, int iconResId, int notificationIconResId, String bgColor,
330            String fgColor, Uri loadMoreUri, String hierarchicalDesc, Uri parent,
331            final long lastMessageTimestamp) {
332        this.id = id;
333        this.persistentId = persistentId;
334        this.folderUri = new FolderUri(uri);
335        this.name = name;
336        this.capabilities = capabilities;
337        this.hasChildren = hasChildren;
338        this.syncWindow = syncWindow;
339        this.conversationListUri = conversationListUri;
340        this.childFoldersListUri = childFoldersListUri;
341        this.unseenCount = unseenCount;
342        this.unreadCount = unreadCount;
343        this.totalCount = totalCount;
344        this.refreshUri = refreshUri;
345        this.syncStatus = syncStatus;
346        this.lastSyncResult = lastSyncResult;
347        this.type = type;
348        this.iconResId = iconResId;
349        this.notificationIconResId = notificationIconResId;
350        this.bgColor = bgColor;
351        this.fgColor = fgColor;
352        if (bgColor != null) {
353            this.bgColorInt = Integer.parseInt(bgColor);
354        }
355        if (fgColor != null) {
356            this.fgColorInt = Integer.parseInt(fgColor);
357        }
358        this.loadMoreUri = loadMoreUri;
359        this.hierarchicalDesc = hierarchicalDesc;
360        this.lastMessageTimestamp = lastMessageTimestamp;
361        this.parent = parent;
362    }
363
364    public Folder(Cursor cursor) {
365        id = cursor.getInt(UIProvider.FOLDER_ID_COLUMN);
366        persistentId = cursor.getString(UIProvider.FOLDER_PERSISTENT_ID_COLUMN);
367        folderUri =
368                new FolderUri(Uri.parse(cursor.getString(UIProvider.FOLDER_URI_COLUMN)));
369        name = cursor.getString(UIProvider.FOLDER_NAME_COLUMN);
370        capabilities = cursor.getInt(UIProvider.FOLDER_CAPABILITIES_COLUMN);
371        // 1 for true, 0 for false.
372        hasChildren = cursor.getInt(UIProvider.FOLDER_HAS_CHILDREN_COLUMN) == 1;
373        syncWindow = cursor.getInt(UIProvider.FOLDER_SYNC_WINDOW_COLUMN);
374        String convList = cursor.getString(UIProvider.FOLDER_CONVERSATION_LIST_URI_COLUMN);
375        conversationListUri = !TextUtils.isEmpty(convList) ? Uri.parse(convList) : null;
376        String childList = cursor.getString(UIProvider.FOLDER_CHILD_FOLDERS_LIST_COLUMN);
377        childFoldersListUri = (hasChildren && !TextUtils.isEmpty(childList)) ? Uri.parse(childList)
378                : null;
379        unseenCount = cursor.getInt(UIProvider.FOLDER_UNSEEN_COUNT_COLUMN);
380        unreadCount = cursor.getInt(UIProvider.FOLDER_UNREAD_COUNT_COLUMN);
381        totalCount = cursor.getInt(UIProvider.FOLDER_TOTAL_COUNT_COLUMN);
382        String refresh = cursor.getString(UIProvider.FOLDER_REFRESH_URI_COLUMN);
383        refreshUri = !TextUtils.isEmpty(refresh) ? Uri.parse(refresh) : null;
384        syncStatus = cursor.getInt(UIProvider.FOLDER_SYNC_STATUS_COLUMN);
385        lastSyncResult = cursor.getInt(UIProvider.FOLDER_LAST_SYNC_RESULT_COLUMN);
386        type = cursor.getInt(UIProvider.FOLDER_TYPE_COLUMN);
387        iconResId = cursor.getInt(UIProvider.FOLDER_ICON_RES_ID_COLUMN);
388        notificationIconResId = cursor.getInt(UIProvider.FOLDER_NOTIFICATION_ICON_RES_ID_COLUMN);
389        bgColor = cursor.getString(UIProvider.FOLDER_BG_COLOR_COLUMN);
390        fgColor = cursor.getString(UIProvider.FOLDER_FG_COLOR_COLUMN);
391        if (bgColor != null) {
392            bgColorInt = Integer.parseInt(bgColor);
393        }
394        if (fgColor != null) {
395            fgColorInt = Integer.parseInt(fgColor);
396        }
397        String loadMore = cursor.getString(UIProvider.FOLDER_LOAD_MORE_URI_COLUMN);
398        loadMoreUri = !TextUtils.isEmpty(loadMore) ? Uri.parse(loadMore) : null;
399        hierarchicalDesc = cursor.getString(UIProvider.FOLDER_HIERARCHICAL_DESC_COLUMN);
400        lastMessageTimestamp = cursor.getLong(UIProvider.FOLDER_LAST_MESSAGE_TIMESTAMP_COLUMN);
401        // A null parent URI means that this is a top-level folder.
402        final String parentString = cursor.getString(UIProvider.FOLDER_PARENT_URI_COLUMN);
403        parent = parentString == null ? Uri.EMPTY : Uri.parse(parentString);
404    }
405
406    /**
407     * Public object that knows how to construct Folders given Cursors.
408     */
409    public static final CursorCreator<Folder> FACTORY = new CursorCreator<Folder>() {
410        @Override
411        public Folder createFromCursor(Cursor c) {
412            return new Folder(c);
413        }
414
415        @Override
416        public String toString() {
417            return "Folder CursorCreator";
418        }
419    };
420
421    public Folder(Parcel in, ClassLoader loader) {
422        id = in.readInt();
423        persistentId = in.readString();
424        folderUri = new FolderUri((Uri) in.readParcelable(loader));
425        name = in.readString();
426        capabilities = in.readInt();
427        // 1 for true, 0 for false.
428        hasChildren = in.readInt() == 1;
429        syncWindow = in.readInt();
430        conversationListUri = in.readParcelable(loader);
431        childFoldersListUri = in.readParcelable(loader);
432        unseenCount = in.readInt();
433        unreadCount = in.readInt();
434        totalCount = in.readInt();
435        refreshUri = in.readParcelable(loader);
436        syncStatus = in.readInt();
437        lastSyncResult = in.readInt();
438        type = in.readInt();
439        iconResId = in.readInt();
440        notificationIconResId = in.readInt();
441        bgColor = in.readString();
442        fgColor = in.readString();
443        if (bgColor != null) {
444            bgColorInt = Integer.parseInt(bgColor);
445        }
446        if (fgColor != null) {
447            fgColorInt = Integer.parseInt(fgColor);
448        }
449        loadMoreUri = in.readParcelable(loader);
450        hierarchicalDesc = in.readString();
451        parent = in.readParcelable(loader);
452        lastMessageTimestamp = in.readLong();
453        parent = in.readParcelable(loader);
454     }
455
456    @Override
457    public void writeToParcel(Parcel dest, int flags) {
458        dest.writeInt(id);
459        dest.writeString(persistentId);
460        dest.writeParcelable(folderUri != null ? folderUri.fullUri : null, 0);
461        dest.writeString(name);
462        dest.writeInt(capabilities);
463        // 1 for true, 0 for false.
464        dest.writeInt(hasChildren ? 1 : 0);
465        dest.writeInt(syncWindow);
466        dest.writeParcelable(conversationListUri, 0);
467        dest.writeParcelable(childFoldersListUri, 0);
468        dest.writeInt(unseenCount);
469        dest.writeInt(unreadCount);
470        dest.writeInt(totalCount);
471        dest.writeParcelable(refreshUri, 0);
472        dest.writeInt(syncStatus);
473        dest.writeInt(lastSyncResult);
474        dest.writeInt(type);
475        dest.writeInt(iconResId);
476        dest.writeInt(notificationIconResId);
477        dest.writeString(bgColor);
478        dest.writeString(fgColor);
479        dest.writeParcelable(loadMoreUri, 0);
480        dest.writeString(hierarchicalDesc);
481        dest.writeParcelable(parent, 0);
482        dest.writeLong(lastMessageTimestamp);
483        dest.writeParcelable(parent, 0);
484    }
485
486    /**
487     * Construct a folder that queries for search results. Do not call on the UI
488     * thread.
489     */
490    public static ObjectCursorLoader<Folder> forSearchResults(Account account, String query,
491            Context context) {
492        if (account.searchUri != null) {
493            final Uri.Builder searchBuilder = account.searchUri.buildUpon();
494            searchBuilder.appendQueryParameter(UIProvider.SearchQueryParameters.QUERY, query);
495            final Uri searchUri = searchBuilder.build();
496            return new ObjectCursorLoader<Folder>(context, searchUri, UIProvider.FOLDERS_PROJECTION,
497                    FACTORY);
498        }
499        return null;
500    }
501
502    public static HashMap<Uri, Folder> hashMapForFolders(List<Folder> rawFolders) {
503        final HashMap<Uri, Folder> folders = new HashMap<Uri, Folder>();
504        for (Folder f : rawFolders) {
505            folders.put(f.folderUri.getComparisonUri(), f);
506        }
507        return folders;
508    }
509
510    /**
511     * Constructor that leaves everything uninitialized.
512     */
513    private Folder() {
514        name = FOLDER_UNINITIALIZED;
515    }
516
517    /**
518     * Creates a new instance of a folder object that is <b>not</b> initialized.  The caller is
519     * expected to fill in the details. Used only for testing.
520     * @return a new instance of an unsafe folder.
521     */
522    @VisibleForTesting
523    public static Folder newUnsafeInstance() {
524        return new Folder();
525    }
526
527    public static final ClassLoaderCreator<Folder> CREATOR = new ClassLoaderCreator<Folder>() {
528        @Override
529        public Folder createFromParcel(Parcel source) {
530            return new Folder(source, null);
531        }
532
533        @Override
534        public Folder createFromParcel(Parcel source, ClassLoader loader) {
535            return new Folder(source, loader);
536        }
537
538        @Override
539        public Folder[] newArray(int size) {
540            return new Folder[size];
541        }
542    };
543
544    @Override
545    public int describeContents() {
546        // Return a sort of version number for this parcelable folder. Starting with zero.
547        return 0;
548    }
549
550    @Override
551    public boolean equals(Object o) {
552        if (o == null || !(o instanceof Folder)) {
553            return false;
554        }
555        return Objects.equal(folderUri, ((Folder) o).folderUri);
556    }
557
558    @Override
559    public int hashCode() {
560        return folderUri == null ? 0 : folderUri.hashCode();
561    }
562
563    @Override
564    public String toString() {
565        // log extra info at DEBUG level or finer
566        final StringBuilder sb = new StringBuilder("[folder id=");
567        sb.append(id);
568        if (LogUtils.isLoggable(LOG_TAG, LogUtils.DEBUG)) {
569            sb.append(", uri=");
570            sb.append(folderUri);
571            sb.append(", name=");
572            sb.append(name);
573        }
574        sb.append("]");
575        return sb.toString();
576    }
577
578    @Override
579    public int compareTo(Folder other) {
580        return name.compareToIgnoreCase(other.name);
581    }
582
583    /**
584     * Returns a boolean indicating whether network activity (sync) is occuring for this folder.
585     */
586    public boolean isSyncInProgress() {
587        return UIProvider.SyncStatus.isSyncInProgress(syncStatus);
588    }
589
590    public boolean supportsCapability(int capability) {
591        return (capabilities & capability) != 0;
592    }
593
594    // Show black text on a transparent swatch for system folders, effectively hiding the
595    // swatch (see bug 2431925).
596    public static void setFolderBlockColor(Folder folder, View colorBlock) {
597        if (colorBlock == null) {
598            return;
599        }
600        boolean showBg =
601                !TextUtils.isEmpty(folder.bgColor) && (folder.type & FolderType.INBOX_SECTION) == 0;
602        final int backgroundColor = showBg ? Integer.parseInt(folder.bgColor) : 0;
603        if (backgroundColor == Utils.getDefaultFolderBackgroundColor(colorBlock.getContext())) {
604            showBg = false;
605        }
606        if (!showBg) {
607            colorBlock.setBackgroundDrawable(null);
608            colorBlock.setVisibility(View.GONE);
609        } else {
610            PaintDrawable paintDrawable = new PaintDrawable();
611            paintDrawable.getPaint().setColor(backgroundColor);
612            colorBlock.setBackgroundDrawable(paintDrawable);
613            colorBlock.setVisibility(View.VISIBLE);
614        }
615    }
616
617    public static void setIcon(Folder folder, ImageView iconView) {
618        if (iconView == null) {
619            return;
620        }
621        final int icon = folder.iconResId;
622        if (icon > 0) {
623            iconView.setImageResource(icon);
624            iconView.setVisibility(View.VISIBLE);
625        } else {
626            iconView.setVisibility(View.GONE);
627        }
628    }
629
630    /**
631     * Return if the type of the folder matches a provider defined folder.
632     */
633    public boolean isProviderFolder() {
634        return !isType(UIProvider.FolderType.DEFAULT);
635    }
636
637    public int getBackgroundColor(int defaultColor) {
638        return bgColor != null ? bgColorInt : defaultColor;
639    }
640
641    public int getForegroundColor(int defaultColor) {
642        return fgColor != null ? fgColorInt : defaultColor;
643    }
644
645    /**
646     * Get just the uri's from an arraylist of folders.
647     */
648    public static String[] getUriArray(List<Folder> folders) {
649        if (folders == null || folders.size() == 0) {
650            return new String[0];
651        }
652        final String[] folderUris = new String[folders.size()];
653        int i = 0;
654        for (Folder folder : folders) {
655            folderUris[i] = folder.folderUri.toString();
656            i++;
657        }
658        return folderUris;
659    }
660
661    /**
662     * Returns a boolean indicating whether this Folder object has been initialized
663     */
664    public boolean isInitialized() {
665        return !name.equals(FOLDER_UNINITIALIZED) && conversationListUri != null &&
666                !NULL_STRING_URI.equals(conversationListUri.toString());
667    }
668
669    public boolean isType(final int folderType) {
670        return isType(type, folderType);
671    }
672
673    /**
674     * Checks if <code>typeMask</code> is of the specified {@link FolderType}
675     *
676     * @return <code>true</code> if the mask contains the specified
677     *         {@link FolderType}, <code>false</code> otherwise
678     */
679    public static boolean isType(final int typeMask, final int folderType) {
680        return (typeMask & folderType) != 0;
681    }
682
683    public boolean isInbox() {
684        return isType(UIProvider.FolderType.INBOX);
685    }
686
687    /**
688     * Return if this is the trash folder.
689     */
690    public boolean isTrash() {
691        return isType(UIProvider.FolderType.TRASH);
692    }
693
694    /**
695     * Return if this is a draft folder.
696     */
697    public boolean isDraft() {
698        return isType(UIProvider.FolderType.DRAFT);
699    }
700
701    /**
702     * Whether this folder supports only showing important messages.
703     */
704    public boolean isImportantOnly() {
705        return supportsCapability(
706                UIProvider.FolderCapabilities.ONLY_IMPORTANT);
707    }
708
709    /**
710     * Whether this is the special folder just used to display all mail for an account.
711     */
712    public boolean isViewAll() {
713        return isType(UIProvider.FolderType.ALL_MAIL);
714    }
715
716    /**
717     * @return a non-user facing English string describing this folder's type
718     */
719    public String getTypeDescription() {
720        final String desc;
721        if (isType(FolderType.INBOX_SECTION)) {
722            desc = "inbox_section";
723        } else if (isInbox()) {
724            desc = "inbox";
725        } else if (isDraft()) {
726            desc = "draft";
727        } else if (isImportantOnly()) {
728            desc = "important";
729        } else if (isType(FolderType.OUTBOX)) {
730            desc = "outbox";
731        } else if (isType(FolderType.SENT)) {
732            desc = "sent";
733        } else if (isType(FolderType.SPAM)) {
734            desc = "spam";
735        } else if (isType(FolderType.STARRED)) {
736            desc = "starred";
737        } else if (isTrash()) {
738            desc = "trash";
739        } else if (isType(FolderType.UNREAD)) {
740            desc = "unread";
741        } else if (isViewAll()) {
742            desc = "all_mail";
743        } else if (isProviderFolder()) {
744            desc = "(other)";
745        } else {
746            desc = "user_folder";
747        }
748        return desc;
749    }
750
751    /**
752     * True if the previous sync was successful, false otherwise.
753     * @return
754     */
755    public final boolean wasSyncSuccessful() {
756        return ((lastSyncResult & 0x0f) == UIProvider.LastSyncResult.SUCCESS);
757    }
758
759    /**
760     * Returns true if unread count should be suppressed for this folder. This is done for folders
761     * where the unread count is meaningless: trash or drafts, for instance.
762     * @return true if unread count should be suppressed for this object.
763     */
764    public final boolean isUnreadCountHidden() {
765        return (isDraft() || isTrash() || isType(FolderType.OUTBOX));
766    }
767
768    @Deprecated
769    public static Folder fromString(String inString) {
770         if (TextUtils.isEmpty(inString)) {
771             return null;
772         }
773         final Folder f = new Folder();
774         int indexOf = inString.indexOf(SPLITTER);
775         int id = -1;
776         if (indexOf != -1) {
777             id = Integer.valueOf(inString.substring(0, indexOf));
778         } else {
779             // If no separator was found, we can't parse this folder and the
780             // TextUtils.split call would also fail. Return null.
781             return null;
782         }
783         final String[] split = TextUtils.split(inString, SPLITTER_REGEX);
784         if (split.length < 20) {
785             LogUtils.e(LOG_TAG, "split.length %d", split.length);
786             return null;
787         }
788         f.id = id;
789         int index = 1;
790         f.folderUri = new FolderUri(Folder.getValidUri(split[index++]));
791         f.name = split[index++];
792         f.hasChildren = Integer.parseInt(split[index++]) != 0;
793         f.capabilities = Integer.parseInt(split[index++]);
794         f.syncWindow = Integer.parseInt(split[index++]);
795         f.conversationListUri = getValidUri(split[index++]);
796         f.childFoldersListUri = getValidUri(split[index++]);
797         f.unreadCount = Integer.parseInt(split[index++]);
798         f.totalCount = Integer.parseInt(split[index++]);
799         f.refreshUri = getValidUri(split[index++]);
800         f.syncStatus = Integer.parseInt(split[index++]);
801         f.lastSyncResult = Integer.parseInt(split[index++]);
802         f.type = Integer.parseInt(split[index++]);
803         f.iconResId = Integer.parseInt(split[index++]);
804         f.bgColor = split[index++];
805         f.fgColor = split[index++];
806         if (f.bgColor != null) {
807             f.bgColorInt = Integer.parseInt(f.bgColor);
808         }
809         if (f.fgColor != null) {
810             f.fgColorInt = Integer.parseInt(f.fgColor);
811         }
812         f.loadMoreUri = getValidUri(split[index++]);
813         f.hierarchicalDesc = split[index++];
814         f.parent = Folder.getValidUri(split[index++]);
815         return f;
816     }
817
818    private static Uri getValidUri(String uri) {
819         if (TextUtils.isEmpty(uri)) {
820             return null;
821         }
822         return Uri.parse(uri);
823    }
824}
825