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