Home | History | Annotate | Download | only in providers
      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     /** 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:" + persistentId;
    723         } else if (isInbox()) {
    724             desc = "inbox:" + persistentId;
    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:" + persistentId;
    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