• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 package com.android.mail.providers;
19 
20 import android.content.Context;
21 import android.database.Cursor;
22 import android.graphics.drawable.PaintDrawable;
23 import android.net.Uri;
24 import android.net.Uri.Builder;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.text.TextUtils;
28 import android.view.View;
29 import android.widget.ImageView;
30 
31 import com.android.mail.content.CursorCreator;
32 import com.android.mail.content.ObjectCursorLoader;
33 import com.android.mail.providers.UIProvider.FolderType;
34 import com.android.mail.utils.FolderUri;
35 import com.android.mail.utils.LogTag;
36 import com.android.mail.utils.LogUtils;
37 import com.android.mail.utils.Utils;
38 import com.google.common.annotations.VisibleForTesting;
39 import com.google.common.base.Objects;
40 
41 import java.util.Collection;
42 import java.util.Collections;
43 import java.util.HashMap;
44 import java.util.List;
45 import 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
51 public 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 
build()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 
setId(final int id)234         public Builder setId(final int id) {
235             mId = id;
236             return this;
237         }
setPersistentId(final String persistentId)238         public Builder setPersistentId(final String persistentId) {
239             mPersistentId = persistentId;
240             return this;
241         }
setUri(final Uri uri)242         public Builder setUri(final Uri uri) {
243             mUri = uri;
244             return this;
245         }
setName(final String name)246         public Builder setName(final String name) {
247             mName = name;
248             return this;
249         }
setCapabilities(final int capabilities)250         public Builder setCapabilities(final int capabilities) {
251             mCapabilities = capabilities;
252             return this;
253         }
setHasChildren(final boolean hasChildren)254         public Builder setHasChildren(final boolean hasChildren) {
255             mHasChildren = hasChildren;
256             return this;
257         }
setSyncWindow(final int syncWindow)258         public Builder setSyncWindow(final int syncWindow) {
259             mSyncWindow = syncWindow;
260             return this;
261         }
setConversationListUri(final Uri conversationListUri)262         public Builder setConversationListUri(final Uri conversationListUri) {
263             mConversationListUri = conversationListUri;
264             return this;
265         }
setChildFoldersListUri(final Uri childFoldersListUri)266         public Builder setChildFoldersListUri(final Uri childFoldersListUri) {
267             mChildFoldersListUri = childFoldersListUri;
268             return this;
269         }
setUnseenCount(final int unseenCount)270         public Builder setUnseenCount(final int unseenCount) {
271             mUnseenCount = unseenCount;
272             return this;
273         }
setUnreadCount(final int unreadCount)274         public Builder setUnreadCount(final int unreadCount) {
275             mUnreadCount = unreadCount;
276             return this;
277         }
setTotalCount(final int totalCount)278         public Builder setTotalCount(final int totalCount) {
279             mTotalCount = totalCount;
280             return this;
281         }
setRefreshUri(final Uri refreshUri)282         public Builder setRefreshUri(final Uri refreshUri) {
283             mRefreshUri = refreshUri;
284             return this;
285         }
setSyncStatus(final int syncStatus)286         public Builder setSyncStatus(final int syncStatus) {
287             mSyncStatus = syncStatus;
288             return this;
289         }
setLastSyncResult(final int lastSyncResult)290         public Builder setLastSyncResult(final int lastSyncResult) {
291             mLastSyncResult = lastSyncResult;
292             return this;
293         }
setType(final int type)294         public Builder setType(final int type) {
295             mType = type;
296             return this;
297         }
setIconResId(final int iconResId)298         public Builder setIconResId(final int iconResId) {
299             mIconResId = iconResId;
300             return this;
301         }
setNotificationIconResId(final int notificationIconResId)302         public Builder setNotificationIconResId(final int notificationIconResId) {
303             mNotificationIconResId = notificationIconResId;
304             return this;
305         }
setBgColor(final String bgColor)306         public Builder setBgColor(final String bgColor) {
307             mBgColor = bgColor;
308             return this;
309         }
setFgColor(final String fgColor)310         public Builder setFgColor(final String fgColor) {
311             mFgColor = fgColor;
312             return this;
313         }
setLoadMoreUri(final Uri loadMoreUri)314         public Builder setLoadMoreUri(final Uri loadMoreUri) {
315             mLoadMoreUri = loadMoreUri;
316             return this;
317         }
setHierarchicalDesc(final String hierarchicalDesc)318         public Builder setHierarchicalDesc(final String hierarchicalDesc) {
319             mHierarchicalDesc = hierarchicalDesc;
320             return this;
321         }
setParent(final Uri parent)322         public Builder setParent(final Uri parent) {
323             mParent = parent;
324             return this;
325         }
setLastMessageTimestamp(final long lastMessageTimestamp)326         public Builder setLastMessageTimestamp(final long lastMessageTimestamp) {
327             mLastMessageTimestamp = lastMessageTimestamp;
328             return this;
329         }
setUnreadSenders(final String unreadSenders)330         public Builder setUnreadSenders(final String unreadSenders) {
331             mUnreadSenders = unreadSenders;
332             return this;
333         }
334     }
335 
Folder(int id, String persistentId, Uri uri, String name, int capabilities, boolean hasChildren, int syncWindow, Uri conversationListUri, Uri childFoldersListUri, int unseenCount, int unreadCount, int totalCount, Uri refreshUri, int syncStatus, int lastSyncResult, int type, int iconResId, int notificationIconResId, String bgColor, String fgColor, Uri loadMoreUri, String hierarchicalDesc, Uri parent, final long lastMessageTimestamp, final String unreadSenders)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 
Folder(Cursor cursor)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 
Folder(Parcel in, ClassLoader loader)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
writeToParcel(Parcel dest, int flags)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      */
forSearchResults(Account account, String query, Context context)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 
hashMapForFolders(List<Folder> rawFolders)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      */
Folder()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
newUnsafeInstance()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
describeContents()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
equals(Object o)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
hashCode()579     public int hashCode() {
580         return folderUri == null ? 0 : folderUri.hashCode();
581     }
582 
583     @Override
toString()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
compareTo(Folder other)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      */
isSyncInProgress()606     public boolean isSyncInProgress() {
607         return UIProvider.SyncStatus.isSyncInProgress(syncStatus);
608     }
609 
supportsCapability(int capability)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).
setFolderBlockColor(Folder folder, View colorBlock)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 
setIcon(Folder folder, ImageView iconView)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      */
isProviderFolder()653     public boolean isProviderFolder() {
654         return !isType(UIProvider.FolderType.DEFAULT);
655     }
656 
getBackgroundColor(int defaultColor)657     public int getBackgroundColor(int defaultColor) {
658         return bgColor != null ? bgColorInt : defaultColor;
659     }
660 
getForegroundColor(int defaultColor)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      */
getUriArray(List<Folder> folders)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      */
isInitialized()684     public boolean isInitialized() {
685         return !name.equals(FOLDER_UNINITIALIZED) && conversationListUri != null &&
686                 !NULL_STRING_URI.equals(conversationListUri.toString());
687     }
688 
isType(final int folderType)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      */
isType(final int typeMask, final int folderType)699     public static boolean isType(final int typeMask, final int folderType) {
700         return (typeMask & folderType) != 0;
701     }
702 
isInbox()703     public boolean isInbox() {
704         return isType(UIProvider.FolderType.INBOX);
705     }
706 
707     /**
708      * Return if this is the trash folder.
709      */
isTrash()710     public boolean isTrash() {
711         return isType(UIProvider.FolderType.TRASH);
712     }
713 
714     /**
715      * Return if this is a draft folder.
716      */
isDraft()717     public boolean isDraft() {
718         return isType(UIProvider.FolderType.DRAFT);
719     }
720 
721     /**
722      * Whether this folder supports only showing important messages.
723      */
isImportantOnly()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      */
isViewAll()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      */
getTypeDescription()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      */
wasSyncSuccessful()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      */
isUnreadCountHidden()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
fromString(String inString)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 
getValidUri(String uri)847     private static Uri getValidUri(String uri) {
848         if (TextUtils.isEmpty(uri)) {
849             return null;
850         }
851         return Uri.parse(uri);
852     }
853 }
854