Folder.java revision baf93640bfdb8f3a85ad36f90123dcb57dc5c6e9
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.content.CursorLoader; 22import android.database.Cursor; 23import android.graphics.drawable.PaintDrawable; 24import android.net.Uri; 25import android.net.Uri.Builder; 26import android.os.Parcel; 27import android.os.Parcelable; 28import android.text.TextUtils; 29import android.view.View; 30import android.widget.ImageView; 31 32import com.android.mail.utils.LogTag; 33import com.android.mail.utils.LogUtils; 34import com.android.mail.utils.Utils; 35 36import com.google.common.base.Objects; 37import com.google.common.collect.ImmutableList; 38import com.google.common.collect.Maps; 39 40import java.util.ArrayList; 41import java.util.Collection; 42import java.util.Collections; 43import java.util.HashMap; 44import java.util.Map; 45import java.util.regex.Pattern; 46 47/** 48 * A folder is a collection of conversations, and perhaps other folders. 49 */ 50public class Folder implements Parcelable, Comparable<Folder> { 51 /** 52 * 53 */ 54 private static final String FOLDER_UNINITIALIZED = "Uninitialized!"; 55 56 // TODO: remove this once we figure out which folder is returning a "null" string as the 57 // conversation list uri 58 private static final String NULL_STRING_URI = "null"; 59 private static final String LOG_TAG = LogTag.getLogTag(); 60 61 // Try to match the order of members with the order of constants in UIProvider. 62 63 /** 64 * Unique id of this folder. 65 */ 66 public int id; 67 68 /** 69 * The content provider URI that returns this folder for this account. 70 */ 71 public Uri uri; 72 73 /** 74 * The human visible name for this folder. 75 */ 76 public String name; 77 78 /** 79 * The possible capabilities that this folder supports. 80 */ 81 public int capabilities; 82 83 /** 84 * Whether or not this folder has children folders. 85 */ 86 public boolean hasChildren; 87 88 /** 89 * How large the synchronization window is: how many days worth of data is retained on the 90 * device. 91 */ 92 public int syncWindow; 93 94 /** 95 * The content provider URI to return the list of conversations in this 96 * folder. 97 */ 98 public Uri conversationListUri; 99 100 /** 101 * The content provider URI to return the list of child folders of this folder. 102 */ 103 public Uri childFoldersListUri; 104 105 /** 106 * The number of messages that are unread in this folder. 107 */ 108 public int unreadCount; 109 110 /** 111 * The total number of messages in this folder. 112 */ 113 public int totalCount; 114 115 /** 116 * The content provider URI to force a refresh of this folder. 117 */ 118 public Uri refreshUri; 119 120 /** 121 * The current sync status of the folder 122 */ 123 public int syncStatus; 124 125 /** 126 * A packed integer containing the last synced result, and the request code. The 127 * value is (requestCode << 4) | syncResult 128 * syncResult is a value from {@link UIProvider.LastSyncResult} 129 * requestCode is a value from: {@link UIProvider.SyncStatus}, 130 */ 131 public int lastSyncResult; 132 133 /** 134 * Folder type. 0 is default. 135 */ 136 public int type; 137 138 /** 139 * Icon for this folder; 0 implies no icon. 140 */ 141 public long iconResId; 142 143 public String bgColor; 144 public String fgColor; 145 146 /** 147 * The content provider URI to request additional conversations 148 */ 149 public Uri loadMoreUri; 150 151 /** 152 * The possibly empty name of this folder with full hierarchy. 153 * The expected format is: parent/folder1/folder2/folder3/folder4 154 */ 155 public String hierarchicalDesc; 156 157 /** 158 * Parent folder of this folder, or null if there is none. This is set as 159 * part of the execution of the application and not obtained or stored via 160 * the provider. 161 */ 162 public Folder parent; 163 164 /** An immutable, empty conversation list */ 165 public static final Collection<Folder> EMPTY = Collections.emptyList(); 166 167 public static final String SPLITTER = "^*^"; 168 private static final Pattern SPLITTER_REGEX = Pattern.compile("\\^\\*\\^"); 169 public static final String FOLDERS_SPLIT = "^**^"; 170 private static final Pattern FOLDERS_SPLIT_REGEX = Pattern.compile("\\^\\*\\*\\^"); 171 172 public Folder(Parcel in) { 173 id = in.readInt(); 174 uri = in.readParcelable(null); 175 name = in.readString(); 176 capabilities = in.readInt(); 177 // 1 for true, 0 for false. 178 hasChildren = in.readInt() == 1; 179 syncWindow = in.readInt(); 180 conversationListUri = in.readParcelable(null); 181 childFoldersListUri = in.readParcelable(null); 182 unreadCount = in.readInt(); 183 totalCount = in.readInt(); 184 refreshUri = in.readParcelable(null); 185 syncStatus = in.readInt(); 186 lastSyncResult = in.readInt(); 187 type = in.readInt(); 188 iconResId = in.readLong(); 189 bgColor = in.readString(); 190 fgColor = in.readString(); 191 loadMoreUri = in.readParcelable(null); 192 hierarchicalDesc = in.readString(); 193 parent = in.readParcelable(null); 194 } 195 196 public Folder(Cursor cursor) { 197 id = cursor.getInt(UIProvider.FOLDER_ID_COLUMN); 198 uri = Uri.parse(cursor.getString(UIProvider.FOLDER_URI_COLUMN)); 199 name = cursor.getString(UIProvider.FOLDER_NAME_COLUMN); 200 capabilities = cursor.getInt(UIProvider.FOLDER_CAPABILITIES_COLUMN); 201 // 1 for true, 0 for false. 202 hasChildren = cursor.getInt(UIProvider.FOLDER_HAS_CHILDREN_COLUMN) == 1; 203 syncWindow = cursor.getInt(UIProvider.FOLDER_SYNC_WINDOW_COLUMN); 204 String convList = cursor.getString(UIProvider.FOLDER_CONVERSATION_LIST_URI_COLUMN); 205 conversationListUri = !TextUtils.isEmpty(convList) ? Uri.parse(convList) : null; 206 String childList = cursor.getString(UIProvider.FOLDER_CHILD_FOLDERS_LIST_COLUMN); 207 childFoldersListUri = (hasChildren && !TextUtils.isEmpty(childList)) ? Uri.parse(childList) 208 : null; 209 unreadCount = cursor.getInt(UIProvider.FOLDER_UNREAD_COUNT_COLUMN); 210 totalCount = cursor.getInt(UIProvider.FOLDER_TOTAL_COUNT_COLUMN); 211 String refresh = cursor.getString(UIProvider.FOLDER_REFRESH_URI_COLUMN); 212 refreshUri = !TextUtils.isEmpty(refresh) ? Uri.parse(refresh) : null; 213 syncStatus = cursor.getInt(UIProvider.FOLDER_SYNC_STATUS_COLUMN); 214 lastSyncResult = cursor.getInt(UIProvider.FOLDER_LAST_SYNC_RESULT_COLUMN); 215 type = cursor.getInt(UIProvider.FOLDER_TYPE_COLUMN); 216 iconResId = cursor.getLong(UIProvider.FOLDER_ICON_RES_ID_COLUMN); 217 bgColor = cursor.getString(UIProvider.FOLDER_BG_COLOR_COLUMN); 218 fgColor = cursor.getString(UIProvider.FOLDER_FG_COLOR_COLUMN); 219 String loadMore = cursor.getString(UIProvider.FOLDER_LOAD_MORE_URI_COLUMN); 220 loadMoreUri = !TextUtils.isEmpty(loadMore) ? Uri.parse(loadMore) : null; 221 hierarchicalDesc = cursor.getString(UIProvider.FOLDER_HIERARCHICAL_DESC_COLUMN); 222 parent = null; 223 } 224 225 @Override 226 public void writeToParcel(Parcel dest, int flags) { 227 dest.writeInt(id); 228 dest.writeParcelable(uri, 0); 229 dest.writeString(name); 230 dest.writeInt(capabilities); 231 // 1 for true, 0 for false. 232 dest.writeInt(hasChildren ? 1 : 0); 233 dest.writeInt(syncWindow); 234 dest.writeParcelable(conversationListUri, 0); 235 dest.writeParcelable(childFoldersListUri, 0); 236 dest.writeInt(unreadCount); 237 dest.writeInt(totalCount); 238 dest.writeParcelable(refreshUri, 0); 239 dest.writeInt(syncStatus); 240 dest.writeInt(lastSyncResult); 241 dest.writeInt(type); 242 dest.writeLong(iconResId); 243 dest.writeString(bgColor); 244 dest.writeString(fgColor); 245 dest.writeParcelable(loadMoreUri, 0); 246 dest.writeString(hierarchicalDesc); 247 dest.writeParcelable(parent, 0); 248 } 249 250 /** 251 * Construct a folder that queries for search results. Do not call on the UI 252 * thread. 253 */ 254 public static CursorLoader forSearchResults(Account account, String query, Context context) { 255 if (account.searchUri != null) { 256 Builder searchBuilder = account.searchUri.buildUpon(); 257 searchBuilder.appendQueryParameter(UIProvider.SearchQueryParameters.QUERY, query); 258 Uri searchUri = searchBuilder.build(); 259 return new CursorLoader(context, searchUri, UIProvider.FOLDERS_PROJECTION, null, null, 260 null); 261 } 262 return null; 263 } 264 265 public static HashMap<Uri, Folder> hashMapForFolders(ArrayList<Folder> rawFolders) { 266 final HashMap<Uri, Folder> folders = new HashMap<Uri, Folder>(); 267 for (Folder f : rawFolders) { 268 folders.put(f.uri, f); 269 } 270 return folders; 271 } 272 273 private static Uri getValidUri(String uri) { 274 if (TextUtils.isEmpty(uri)) { 275 return null; 276 } 277 return Uri.parse(uri); 278 } 279 280 /** 281 * Constructor that leaves everything uninitialized. 282 */ 283 private Folder() { 284 name = FOLDER_UNINITIALIZED; 285 } 286 287 /** 288 * Creates a new instance of a folder object that is <b>not</b> initialized. The caller is 289 * expected to fill in the details. This resulting instance is not guaranteed to work 290 * correctly, and might break functionality. Use at your own risk!! 291 * @return a new instance of an unsafe folder. 292 */ 293 public static Folder newUnsafeInstance() { 294 return new Folder(); 295 } 296 297 @SuppressWarnings("hiding") 298 public static final Creator<Folder> CREATOR = new Creator<Folder>() { 299 @Override 300 public Folder createFromParcel(Parcel source) { 301 return new Folder(source); 302 } 303 304 @Override 305 public Folder[] newArray(int size) { 306 return new Folder[size]; 307 } 308 }; 309 310 @Override 311 public int describeContents() { 312 // Return a sort of version number for this parcelable folder. Starting with zero. 313 return 0; 314 } 315 316 @Override 317 public boolean equals(Object o) { 318 if (o == null || !(o instanceof Folder)) { 319 return false; 320 } 321 return Objects.equal(uri, ((Folder) o).uri); 322 } 323 324 @Override 325 public int hashCode() { 326 return uri == null ? 0 : uri.hashCode(); 327 } 328 329 @Override 330 public int compareTo(Folder other) { 331 return name.compareToIgnoreCase(other.name); 332 } 333 334 /** 335 * Create a Folder map from a string of serialized folders. This can only be done on the output 336 * of {@link #serialize(Map)}. 337 * @param serializedFolder A string obtained from {@link #serialize(Map)} 338 * @return a Map of folder name to folder. 339 */ 340 public static Map<String, Folder> parseFoldersFromString(String serializedFoldersString) { 341 if (TextUtils.isEmpty(serializedFoldersString)) { 342 return null; 343 } 344 Map<String, Folder> folderMap = Maps.newHashMap(); 345 ArrayList<Folder> folders = Folder.getFoldersArray(serializedFoldersString); 346 for (Folder folder : folders) { 347 if (folder.name != FOLDER_UNINITIALIZED) { 348 folderMap.put(folder.name, folder); 349 } 350 } 351 return folderMap; 352 } 353 354 /** 355 * Returns a boolean indicating whether network activity (sync) is occuring for this folder. 356 */ 357 public boolean isSyncInProgress() { 358 return UIProvider.SyncStatus.isSyncInProgress(syncStatus); 359 } 360 361 /** 362 * Serialize the given list of folders 363 * @param folderMap A valid map of folder names to Folders 364 * @return a string containing a serialized output of folder maps. 365 */ 366 public static String serialize(Map<String, Folder> folderMap) { 367 return getSerializedFolderString(folderMap.values()); 368 } 369 370 public boolean supportsCapability(int capability) { 371 return (capabilities & capability) != 0; 372 } 373 374 // Show black text on a transparent swatch for system folders, effectively hiding the 375 // swatch (see bug 2431925). 376 public static void setFolderBlockColor(Folder folder, View colorBlock) { 377 if (colorBlock == null) { 378 return; 379 } 380 boolean showBg = !TextUtils.isEmpty(folder.bgColor); 381 final int backgroundColor = showBg ? Integer.parseInt(folder.bgColor) : 0; 382 if (backgroundColor == Utils.getDefaultFolderBackgroundColor(colorBlock.getContext())) { 383 showBg = false; 384 } 385 if (!showBg) { 386 colorBlock.setBackgroundDrawable(null); 387 colorBlock.setVisibility(View.GONE); 388 } else { 389 PaintDrawable paintDrawable = new PaintDrawable(); 390 paintDrawable.getPaint().setColor(backgroundColor); 391 colorBlock.setBackgroundDrawable(paintDrawable); 392 colorBlock.setVisibility(View.VISIBLE); 393 } 394 } 395 396 public static void setIcon(Folder folder, ImageView iconView) { 397 if (iconView == null) { 398 return; 399 } 400 final long icon = folder.iconResId; 401 if (icon > 0) { 402 iconView.setImageResource((int)icon); 403 iconView.setVisibility(View.VISIBLE); 404 } else { 405 iconView.setVisibility(View.INVISIBLE); 406 } 407 } 408 409 /** 410 * Return if the type of the folder matches a provider defined folder. 411 */ 412 public boolean isProviderFolder() { 413 return type != UIProvider.FolderType.DEFAULT; 414 } 415 416 public int getBackgroundColor(int defaultColor) { 417 return TextUtils.isEmpty(bgColor) ? defaultColor : Integer.parseInt(bgColor); 418 } 419 420 public int getForegroundColor(int defaultColor) { 421 return TextUtils.isEmpty(fgColor) ? defaultColor : Integer.parseInt(fgColor); 422 } 423 424 public static String getSerializedFolderString(Collection<Folder> folders) { 425 final StringBuilder folderList = new StringBuilder(); 426 int i = 0; 427 for (Folder folderEntry : folders) { 428 folderList.append(Folder.toString(folderEntry)); 429 if (i < folders.size()) { 430 folderList.append(FOLDERS_SPLIT); 431 } 432 i++; 433 } 434 return folderList.toString(); 435 } 436 437 public static Folder fromString(String inString) { 438 if (TextUtils.isEmpty(inString)) { 439 return null; 440 } 441 final Folder f = new Folder(); 442 int indexOf = inString.indexOf(SPLITTER); 443 int id = -1; 444 if (indexOf != -1) { 445 id = Integer.valueOf(inString.substring(0, indexOf)); 446 } else { 447 // If no separator was found, we can't parse this folder and the 448 // TextUtils.split call would also fail. Return null. 449 LogUtils.w(LOG_TAG, "Problem parsing folderId: original string: %s", inString); 450 return null; 451 } 452 final String[] split = TextUtils.split(inString, SPLITTER_REGEX); 453 if (split.length < 20) { 454 return null; 455 } 456 f.id = id; 457 f.uri = Folder.getValidUri(split[1]); 458 f.name = split[2]; 459 f.hasChildren = Integer.parseInt(split[3]) != 0; 460 f.capabilities = Integer.parseInt(split[4]); 461 f.syncWindow = Integer.parseInt(split[5]); 462 f.conversationListUri = getValidUri(split[6]); 463 f.childFoldersListUri = getValidUri(split[7]); 464 f.unreadCount = Integer.parseInt(split[8]); 465 f.totalCount = Integer.parseInt(split[9]); 466 f.refreshUri = getValidUri(split[10]); 467 f.syncStatus = Integer.parseInt(split[11]); 468 f.lastSyncResult = Integer.parseInt(split[12]); 469 f.type = Integer.parseInt(split[13]); 470 f.iconResId = Integer.parseInt(split[14]); 471 f.bgColor = split[15]; 472 f.fgColor = split[16]; 473 f.loadMoreUri = getValidUri(split[17]); 474 f.hierarchicalDesc = split[18]; 475 f.parent = Folder.fromString(split[19]); 476 return f; 477 } 478 479 /** 480 * Create a string representation of a folder. 481 */ 482 public static String createAsString(int id, Uri uri, String name, boolean hasChildren, 483 int capabilities, int syncWindow, Uri convListUri, Uri childFoldersListUri, 484 int unreadCount, int totalCount, Uri refreshUri, int syncStatus, int lastSyncResult, 485 int type, long iconResId, String bgColor, String fgColor, Uri loadMore, 486 String hierarchicalDesc, Folder parent) { 487 StringBuilder builder = new StringBuilder(); 488 builder.append(id); 489 builder.append(SPLITTER); 490 builder.append(uri); 491 builder.append(SPLITTER); 492 builder.append(name); 493 builder.append(SPLITTER); 494 builder.append(hasChildren ? 1 : 0); 495 builder.append(SPLITTER); 496 builder.append(capabilities); 497 builder.append(SPLITTER); 498 builder.append(syncWindow); 499 builder.append(SPLITTER); 500 builder.append(convListUri); 501 builder.append(SPLITTER); 502 builder.append(childFoldersListUri); 503 builder.append(SPLITTER); 504 builder.append(unreadCount); 505 builder.append(SPLITTER); 506 builder.append(totalCount); 507 builder.append(SPLITTER); 508 builder.append(refreshUri); 509 builder.append(SPLITTER); 510 builder.append(syncStatus); 511 builder.append(SPLITTER); 512 builder.append(lastSyncResult); 513 builder.append(SPLITTER); 514 builder.append(type); 515 builder.append(SPLITTER); 516 builder.append(iconResId); 517 builder.append(SPLITTER); 518 builder.append(bgColor != null ? bgColor : ""); 519 builder.append(SPLITTER); 520 builder.append(fgColor != null ? fgColor : ""); 521 builder.append(SPLITTER); 522 builder.append(loadMore); 523 builder.append(SPLITTER); 524 builder.append(hierarchicalDesc); 525 builder.append(SPLITTER); 526 if (parent != null) { 527 builder.append(Folder.toString(parent)); 528 } else { 529 builder.append(""); 530 } 531 return builder.toString(); 532 } 533 534 public static String toString(Folder folder) { 535 return createAsString(folder.id, folder.uri, folder.name, folder.hasChildren, 536 folder.capabilities, folder.syncWindow, folder.conversationListUri, 537 folder.childFoldersListUri, folder.unreadCount, folder.totalCount, 538 folder.refreshUri, folder.syncStatus, folder.lastSyncResult, folder.type, 539 folder.iconResId, folder.bgColor, folder.fgColor, folder.loadMoreUri, 540 folder.hierarchicalDesc, folder.parent); 541 } 542 543 /** 544 * Returns a comma separated list of folder URIs for all the folders in the collection. 545 * @param folders 546 * @return 547 */ 548 public final static String getUriString(Collection<Folder> folders) { 549 final StringBuilder uris = new StringBuilder(); 550 boolean first = true; 551 for (Folder f : folders) { 552 if (first) { 553 first = false; 554 } else { 555 uris.append(','); 556 } 557 uris.append(f.uri.toString()); 558 } 559 return uris.toString(); 560 } 561 562 563 /** 564 * Get an array of folders from a rawFolders string. 565 */ 566 public static ArrayList<Folder> getFoldersArray(String rawFolders) { 567 if (TextUtils.isEmpty(rawFolders)) { 568 return null; 569 } 570 ArrayList<Folder> folders = new ArrayList<Folder>(); 571 String[] split = TextUtils.split(rawFolders, FOLDERS_SPLIT_REGEX); 572 Folder f; 573 for (String folder : split) { 574 f = Folder.fromString(folder); 575 if (f != null) { 576 folders.add(f); 577 } 578 } 579 return folders; 580 } 581 582 /** 583 * Get just the uri's from an arraylist of folders. 584 */ 585 public final static String[] getUriArray(ArrayList<Folder> folders) { 586 if (folders == null || folders.size() == 0) { 587 return new String[0]; 588 } 589 String[] folderUris = new String[folders.size()]; 590 int i = 0; 591 for (Folder folder : folders) { 592 folderUris[i] = folder.uri.toString(); 593 i++; 594 } 595 return folderUris; 596 } 597 598 /** 599 * Returns true if a conversation assigned to the needle will be assigned to the collection of 600 * folders in the haystack. False otherwise. This method is safe to call with null 601 * arguments. 602 * This method returns true under two circumstances 603 * <ul><li> If the URI of the needle was found in the collection of URIs that comprise the 604 * haystack. 605 * </li><li> If the needle is of the type Inbox, and at least one of the folders in the haystack 606 * are of type Inbox. <em>Rationale</em>: there are special folders that are marked as inbox, 607 * and the user might not have the control to assign conversations to them. This happens for 608 * the Priority Inbox in Gmail. When you assign a conversation to an Inbox folder, it will 609 * continue to appear in the Priority Inbox. However, the URI of Priority Inbox and Inbox will 610 * be different. So a direct equality check is insufficient. 611 * </li></ul> 612 * @param haystack a collection of folders, possibly overlapping 613 * @param needle a folder 614 * @return true if a conversation inside the needle will be in the folders in the haystack. 615 */ 616 public final static boolean containerIncludes(Collection<Folder> haystack, Folder needle) { 617 // If the haystack is empty, it cannot contain anything. 618 if (haystack == null || haystack.size() <= 0) { 619 return false; 620 } 621 // The null folder exists everywhere. 622 if (needle == null) { 623 return true; 624 } 625 boolean hasInbox = false; 626 // Get currently active folder info and compare it to the list 627 // these conversations have been given; if they no longer contain 628 // the selected folder, delete them from the list. 629 final Uri toFind = needle.uri; 630 for (Folder f : haystack) { 631 if (toFind.equals(f.uri)) { 632 return true; 633 } 634 hasInbox |= (f.type == UIProvider.FolderType.INBOX); 635 } 636 // Did not find the URI of needle directly. If the needle is an Inbox and one of the folders 637 // was an inbox, then the needle is contained (check Javadoc for explanation). 638 final boolean needleIsInbox = (needle.type == UIProvider.FolderType.INBOX); 639 return needleIsInbox ? hasInbox : false; 640 } 641 642 /** 643 * Returns a boolean indicating whether this Folder object has been initialized 644 */ 645 public boolean isInitialized() { 646 return name != FOLDER_UNINITIALIZED && conversationListUri != null && 647 !NULL_STRING_URI.equals(conversationListUri.toString()); 648 } 649 650 /** 651 * Returns a collection of a single folder. This method always returns a valid collection 652 * even if the input folder is null. 653 * @param in a folder, possibly null. 654 * @return a collection of the folder. 655 */ 656 public static Collection<Folder> listOf(Folder in) { 657 final Collection<Folder> target = (in == null) ? EMPTY : ImmutableList.of(in); 658 return target; 659 } 660 661 /** 662 * Return if this is the trash folder. 663 */ 664 public boolean isTrash() { 665 return type == UIProvider.FolderType.TRASH; 666 } 667 668 /** 669 * Return if this is a draft folder. 670 */ 671 public boolean isDraft() { 672 return type == UIProvider.FolderType.DRAFT; 673 } 674 675 /** 676 * Whether this folder supports only showing important messages. 677 */ 678 public boolean isImportantOnly() { 679 return supportsCapability( 680 UIProvider.FolderCapabilities.ONLY_IMPORTANT); 681 } 682 683 /** 684 * Whether this is the special folder just used to display all mail for an account. 685 */ 686 public boolean isViewAll() { 687 return type == UIProvider.FolderType.ALL_MAIL; 688 } 689 690 /** 691 * True if the previous sync was successful, false otherwise. 692 * @return 693 */ 694 public final boolean wasSyncSuccessful() { 695 return ((lastSyncResult & 0x0f) == UIProvider.LastSyncResult.SUCCESS); 696 } 697 698 /** 699 * Don't use this for ANYTHING but the FolderListAdapter. It does not have 700 * all the fields. 701 */ 702 public static Folder getDeficientDisplayOnlyFolder(Cursor cursor) { 703 Folder f = Folder.newUnsafeInstance(); 704 f.id = cursor.getInt(UIProvider.FOLDER_ID_COLUMN); 705 f.uri = Utils.getValidUri(cursor.getString(UIProvider.FOLDER_URI_COLUMN)); 706 f.unreadCount = cursor.getInt(UIProvider.FOLDER_UNREAD_COUNT_COLUMN); 707 f.conversationListUri = Utils.getValidUri(cursor 708 .getString(UIProvider.FOLDER_CONVERSATION_LIST_URI_COLUMN)); 709 f.type = cursor.getInt(UIProvider.FOLDER_TYPE_COLUMN); 710 f.capabilities = cursor.getInt(UIProvider.FOLDER_CAPABILITIES_COLUMN); 711 f.bgColor = cursor.getString(UIProvider.FOLDER_BG_COLOR_COLUMN); 712 f.name = cursor.getString(UIProvider.FOLDER_NAME_COLUMN); 713 return f; 714 } 715} 716