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