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