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