1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 package com.android.emailcommon.provider; 19 20 import android.content.ContentUris; 21 import android.content.ContentValues; 22 import android.content.Context; 23 import android.database.Cursor; 24 import android.net.Uri; 25 import android.os.Parcel; 26 import android.os.Parcelable; 27 import android.util.Log; 28 29 import com.android.emailcommon.Logging; 30 import com.android.emailcommon.provider.EmailContent.MailboxColumns; 31 import com.android.emailcommon.provider.EmailContent.SyncColumns; 32 import com.android.emailcommon.utility.Utility; 33 34 public class Mailbox extends EmailContent implements SyncColumns, MailboxColumns, Parcelable { 35 public static final String TABLE_NAME = "Mailbox"; 36 @SuppressWarnings("hiding") 37 public static final Uri CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/mailbox"); 38 public static final Uri ADD_TO_FIELD_URI = 39 Uri.parse(EmailContent.CONTENT_URI + "/mailboxIdAddToField"); 40 public static final Uri FROM_ACCOUNT_AND_TYPE_URI = 41 Uri.parse(EmailContent.CONTENT_URI + "/mailboxIdFromAccountAndType"); 42 43 public String mDisplayName; 44 public String mServerId; 45 public String mParentServerId; 46 public long mParentKey; 47 public long mAccountKey; 48 public int mType; 49 public int mDelimiter; 50 public String mSyncKey; 51 public int mSyncLookback; 52 public int mSyncInterval; 53 public long mSyncTime; 54 public boolean mFlagVisible = true; 55 public int mFlags; 56 public int mVisibleLimit; 57 public String mSyncStatus; 58 public long mLastSeenMessageKey; 59 public long mLastTouchedTime; 60 61 public static final int CONTENT_ID_COLUMN = 0; 62 public static final int CONTENT_DISPLAY_NAME_COLUMN = 1; 63 public static final int CONTENT_SERVER_ID_COLUMN = 2; 64 public static final int CONTENT_PARENT_SERVER_ID_COLUMN = 3; 65 public static final int CONTENT_ACCOUNT_KEY_COLUMN = 4; 66 public static final int CONTENT_TYPE_COLUMN = 5; 67 public static final int CONTENT_DELIMITER_COLUMN = 6; 68 public static final int CONTENT_SYNC_KEY_COLUMN = 7; 69 public static final int CONTENT_SYNC_LOOKBACK_COLUMN = 8; 70 public static final int CONTENT_SYNC_INTERVAL_COLUMN = 9; 71 public static final int CONTENT_SYNC_TIME_COLUMN = 10; 72 public static final int CONTENT_FLAG_VISIBLE_COLUMN = 11; 73 public static final int CONTENT_FLAGS_COLUMN = 12; 74 public static final int CONTENT_VISIBLE_LIMIT_COLUMN = 13; 75 public static final int CONTENT_SYNC_STATUS_COLUMN = 14; 76 public static final int CONTENT_PARENT_KEY_COLUMN = 15; 77 public static final int CONTENT_LAST_SEEN_MESSAGE_KEY_COLUMN = 16; 78 public static final int CONTENT_LAST_TOUCHED_TIME_COLUMN = 17; 79 80 /** 81 * <em>NOTE</em>: If fields are added or removed, the method {@link #getHashes()} 82 * MUST be updated. 83 */ 84 public static final String[] CONTENT_PROJECTION = new String[] { 85 RECORD_ID, MailboxColumns.DISPLAY_NAME, MailboxColumns.SERVER_ID, 86 MailboxColumns.PARENT_SERVER_ID, MailboxColumns.ACCOUNT_KEY, MailboxColumns.TYPE, 87 MailboxColumns.DELIMITER, MailboxColumns.SYNC_KEY, MailboxColumns.SYNC_LOOKBACK, 88 MailboxColumns.SYNC_INTERVAL, MailboxColumns.SYNC_TIME, 89 MailboxColumns.FLAG_VISIBLE, MailboxColumns.FLAGS, MailboxColumns.VISIBLE_LIMIT, 90 MailboxColumns.SYNC_STATUS, MailboxColumns.PARENT_KEY, 91 MailboxColumns.LAST_SEEN_MESSAGE_KEY, MailboxColumns.LAST_TOUCHED_TIME, 92 }; 93 94 private static final String ACCOUNT_AND_MAILBOX_TYPE_SELECTION = 95 MailboxColumns.ACCOUNT_KEY + " =? AND " + 96 MailboxColumns.TYPE + " =?"; 97 private static final String MAILBOX_TYPE_SELECTION = 98 MailboxColumns.TYPE + " =?"; 99 /** Selection by server pathname for a given account */ 100 public static final String PATH_AND_ACCOUNT_SELECTION = 101 MailboxColumns.SERVER_ID + "=? and " + MailboxColumns.ACCOUNT_KEY + "=?"; 102 103 private static final String[] MAILBOX_SUM_OF_UNREAD_COUNT_PROJECTION = new String [] { 104 "sum(" + MailboxColumns.UNREAD_COUNT + ")" 105 }; 106 private static final int UNREAD_COUNT_COUNT_COLUMN = 0; 107 private static final String[] MAILBOX_SUM_OF_MESSAGE_COUNT_PROJECTION = new String [] { 108 "sum(" + MailboxColumns.MESSAGE_COUNT + ")" 109 }; 110 private static final int MESSAGE_COUNT_COUNT_COLUMN = 0; 111 112 private static final String[] MAILBOX_TYPE_PROJECTION = new String [] { 113 MailboxColumns.TYPE 114 }; 115 private static final int MAILBOX_TYPE_TYPE_COLUMN = 0; 116 117 private static final String[] MAILBOX_DISPLAY_NAME_PROJECTION = new String [] { 118 MailboxColumns.DISPLAY_NAME 119 }; 120 private static final int MAILBOX_DISPLAY_NAME_COLUMN = 0; 121 122 public static final long NO_MAILBOX = -1; 123 124 // Sentinel values for the mSyncInterval field of both Mailbox records 125 public static final int CHECK_INTERVAL_NEVER = -1; 126 public static final int CHECK_INTERVAL_PUSH = -2; 127 // The following two sentinel values are used by EAS 128 // Ping indicates that the EAS mailbox is synced based on a "ping" from the server 129 public static final int CHECK_INTERVAL_PING = -3; 130 // Push-Hold indicates an EAS push or ping Mailbox shouldn't sync just yet 131 public static final int CHECK_INTERVAL_PUSH_HOLD = -4; 132 133 // Sentinel for PARENT_KEY. Use NO_MAILBOX for toplevel mailboxes (i.e. no parents). 134 public static final long PARENT_KEY_UNINITIALIZED = 0L; 135 136 private static final String WHERE_TYPE_AND_ACCOUNT_KEY = 137 MailboxColumns.TYPE + "=? and " + MailboxColumns.ACCOUNT_KEY + "=?"; 138 139 public static final Integer[] INVALID_DROP_TARGETS = new Integer[] {Mailbox.TYPE_DRAFTS, 140 Mailbox.TYPE_OUTBOX, Mailbox.TYPE_SENT}; 141 142 public static final String USER_VISIBLE_MAILBOX_SELECTION = 143 MailboxColumns.TYPE + "<" + Mailbox.TYPE_NOT_EMAIL + 144 " AND " + MailboxColumns.FLAG_VISIBLE + "=1"; 145 146 // Types of mailboxes. The list is ordered to match a typical UI presentation, e.g. 147 // placing the inbox at the top. 148 // Arrays of "special_mailbox_display_names" and "special_mailbox_icons" are depends on 149 // types Id of mailboxes. 150 /** No type specified */ 151 public static final int TYPE_NONE = -1; 152 /** The "main" mailbox for the account, almost always referred to as "Inbox" */ 153 public static final int TYPE_INBOX = 0; 154 // Types of mailboxes 155 /** Generic mailbox that holds mail */ 156 public static final int TYPE_MAIL = 1; 157 /** Parent-only mailbox; does not hold any mail */ 158 public static final int TYPE_PARENT = 2; 159 /** Drafts mailbox */ 160 public static final int TYPE_DRAFTS = 3; 161 /** Local mailbox associated with the account's outgoing mail */ 162 public static final int TYPE_OUTBOX = 4; 163 /** Sent mail; mail that was sent from the account */ 164 public static final int TYPE_SENT = 5; 165 /** Deleted mail */ 166 public static final int TYPE_TRASH = 6; 167 /** Junk mail */ 168 public static final int TYPE_JUNK = 7; 169 /** Search results */ 170 public static final int TYPE_SEARCH = 8; 171 172 // Types after this are used for non-mail mailboxes (as in EAS) 173 public static final int TYPE_NOT_EMAIL = 0x40; 174 public static final int TYPE_CALENDAR = 0x41; 175 public static final int TYPE_CONTACTS = 0x42; 176 public static final int TYPE_TASKS = 0x43; 177 public static final int TYPE_EAS_ACCOUNT_MAILBOX = 0x44; 178 public static final int TYPE_UNKNOWN = 0x45; 179 180 public static final int TYPE_NOT_SYNCABLE = 0x100; 181 // A mailbox that holds Messages that are attachments 182 public static final int TYPE_ATTACHMENT = 0x101; 183 184 // Bit field flags; each is defined below 185 // Warning: Do not read these flags until POP/IMAP/EAS all populate them 186 /** No flags set */ 187 public static final int FLAG_NONE = 0; 188 /** Has children in the mailbox hierarchy */ 189 public static final int FLAG_HAS_CHILDREN = 1<<0; 190 /** Children are visible in the UI */ 191 public static final int FLAG_CHILDREN_VISIBLE = 1<<1; 192 /** cannot receive "pushed" mail */ 193 public static final int FLAG_CANT_PUSH = 1<<2; 194 /** can hold emails (i.e. some parent mailboxes cannot themselves contain mail) */ 195 public static final int FLAG_HOLDS_MAIL = 1<<3; 196 /** can be used as a target for moving messages within the account */ 197 public static final int FLAG_ACCEPTS_MOVED_MAIL = 1<<4; 198 /** can be used as a target for appending messages */ 199 public static final int FLAG_ACCEPTS_APPENDED_MAIL = 1<<5; 200 201 // Magic mailbox ID's 202 // NOTE: This is a quick solution for merged mailboxes. I would rather implement this 203 // with a more generic way of packaging and sharing queries between activities 204 public static final long QUERY_ALL_INBOXES = -2; 205 public static final long QUERY_ALL_UNREAD = -3; 206 public static final long QUERY_ALL_FAVORITES = -4; 207 public static final long QUERY_ALL_DRAFTS = -5; 208 public static final long QUERY_ALL_OUTBOX = -6; 209 210 public Mailbox() { 211 mBaseUri = CONTENT_URI; 212 } 213 214 /** 215 * Restore a Mailbox from the database, given its unique id 216 * @param context 217 * @param id 218 * @return the instantiated Mailbox 219 */ 220 public static Mailbox restoreMailboxWithId(Context context, long id) { 221 return EmailContent.restoreContentWithId(context, Mailbox.class, 222 Mailbox.CONTENT_URI, Mailbox.CONTENT_PROJECTION, id); 223 } 224 225 /** 226 * Builds a new mailbox with "typical" settings for a system mailbox, such as a local "Drafts" 227 * mailbox. This is useful for protocols like POP3 or IMAP who don't have certain local 228 * system mailboxes synced with the server. 229 * Note: the mailbox is not persisted - clients must call {@link #save} themselves. 230 */ 231 public static Mailbox newSystemMailbox(long accountId, int mailboxType, String name) { 232 if (mailboxType == Mailbox.TYPE_MAIL) { 233 throw new IllegalArgumentException("Cannot specify TYPE_MAIL for a system mailbox"); 234 } 235 Mailbox box = new Mailbox(); 236 box.mAccountKey = accountId; 237 box.mType = mailboxType; 238 box.mSyncInterval = Account.CHECK_INTERVAL_NEVER; 239 box.mFlagVisible = true; 240 box.mServerId = box.mDisplayName = name; 241 box.mParentKey = Mailbox.NO_MAILBOX; 242 box.mFlags = Mailbox.FLAG_HOLDS_MAIL; 243 return box; 244 } 245 246 /** 247 * Returns a Mailbox from the database, given its pathname and account id. All mailbox 248 * paths for a particular account must be unique. Paths are stored in the column 249 * {@link MailboxColumns#SERVER_ID} for want of yet another column in the table. 250 * @param context 251 * @param accountId the ID of the account 252 * @param path the fully qualified, remote pathname 253 */ 254 public static Mailbox restoreMailboxForPath(Context context, long accountId, String path) { 255 Cursor c = context.getContentResolver().query( 256 Mailbox.CONTENT_URI, 257 Mailbox.CONTENT_PROJECTION, 258 Mailbox.PATH_AND_ACCOUNT_SELECTION, 259 new String[] { path, Long.toString(accountId) }, 260 null); 261 if (c == null) throw new ProviderUnavailableException(); 262 try { 263 Mailbox mailbox = null; 264 if (c.moveToFirst()) { 265 mailbox = getContent(c, Mailbox.class); 266 if (c.moveToNext()) { 267 Log.w(Logging.LOG_TAG, "Multiple mailboxes named \"" + path + "\""); 268 } 269 } else { 270 Log.i(Logging.LOG_TAG, "Could not find mailbox at \"" + path + "\""); 271 } 272 return mailbox; 273 } finally { 274 c.close(); 275 } 276 } 277 278 /** 279 * Returns a {@link Mailbox} for the given path. If the path is not in the database, a new 280 * mailbox will be created. 281 */ 282 public static Mailbox getMailboxForPath(Context context, long accountId, String path) { 283 Mailbox mailbox = restoreMailboxForPath(context, accountId, path); 284 if (mailbox == null) { 285 mailbox = new Mailbox(); 286 } 287 return mailbox; 288 } 289 290 @Override 291 public void restore(Cursor cursor) { 292 mBaseUri = CONTENT_URI; 293 mId = cursor.getLong(CONTENT_ID_COLUMN); 294 mDisplayName = cursor.getString(CONTENT_DISPLAY_NAME_COLUMN); 295 mServerId = cursor.getString(CONTENT_SERVER_ID_COLUMN); 296 mParentServerId = cursor.getString(CONTENT_PARENT_SERVER_ID_COLUMN); 297 mParentKey = cursor.getLong(CONTENT_PARENT_KEY_COLUMN); 298 mAccountKey = cursor.getLong(CONTENT_ACCOUNT_KEY_COLUMN); 299 mType = cursor.getInt(CONTENT_TYPE_COLUMN); 300 mDelimiter = cursor.getInt(CONTENT_DELIMITER_COLUMN); 301 mSyncKey = cursor.getString(CONTENT_SYNC_KEY_COLUMN); 302 mSyncLookback = cursor.getInt(CONTENT_SYNC_LOOKBACK_COLUMN); 303 mSyncInterval = cursor.getInt(CONTENT_SYNC_INTERVAL_COLUMN); 304 mSyncTime = cursor.getLong(CONTENT_SYNC_TIME_COLUMN); 305 mFlagVisible = cursor.getInt(CONTENT_FLAG_VISIBLE_COLUMN) == 1; 306 mFlags = cursor.getInt(CONTENT_FLAGS_COLUMN); 307 mVisibleLimit = cursor.getInt(CONTENT_VISIBLE_LIMIT_COLUMN); 308 mSyncStatus = cursor.getString(CONTENT_SYNC_STATUS_COLUMN); 309 mLastSeenMessageKey = cursor.getLong(CONTENT_LAST_SEEN_MESSAGE_KEY_COLUMN); 310 mLastTouchedTime = cursor.getLong(CONTENT_LAST_TOUCHED_TIME_COLUMN); 311 } 312 313 @Override 314 public ContentValues toContentValues() { 315 ContentValues values = new ContentValues(); 316 values.put(MailboxColumns.DISPLAY_NAME, mDisplayName); 317 values.put(MailboxColumns.SERVER_ID, mServerId); 318 values.put(MailboxColumns.PARENT_SERVER_ID, mParentServerId); 319 values.put(MailboxColumns.PARENT_KEY, mParentKey); 320 values.put(MailboxColumns.ACCOUNT_KEY, mAccountKey); 321 values.put(MailboxColumns.TYPE, mType); 322 values.put(MailboxColumns.DELIMITER, mDelimiter); 323 values.put(MailboxColumns.SYNC_KEY, mSyncKey); 324 values.put(MailboxColumns.SYNC_LOOKBACK, mSyncLookback); 325 values.put(MailboxColumns.SYNC_INTERVAL, mSyncInterval); 326 values.put(MailboxColumns.SYNC_TIME, mSyncTime); 327 values.put(MailboxColumns.FLAG_VISIBLE, mFlagVisible); 328 values.put(MailboxColumns.FLAGS, mFlags); 329 values.put(MailboxColumns.VISIBLE_LIMIT, mVisibleLimit); 330 values.put(MailboxColumns.SYNC_STATUS, mSyncStatus); 331 values.put(MailboxColumns.LAST_SEEN_MESSAGE_KEY, mLastSeenMessageKey); 332 values.put(MailboxColumns.LAST_TOUCHED_TIME, mLastTouchedTime); 333 return values; 334 } 335 336 /** 337 * Convenience method to return the id of a given type of Mailbox for a given Account; the 338 * common Mailbox types (Inbox, Outbox, Sent, Drafts, Trash, and Search) are all cached by 339 * EmailProvider; therefore, we warn if the mailbox is not found in the cache 340 * 341 * @param context the caller's context, used to get a ContentResolver 342 * @param accountId the id of the account to be queried 343 * @param type the mailbox type, as defined above 344 * @return the id of the mailbox, or -1 if not found 345 */ 346 public static long findMailboxOfType(Context context, long accountId, int type) { 347 // First use special URI 348 Uri uri = FROM_ACCOUNT_AND_TYPE_URI.buildUpon().appendPath(Long.toString(accountId)) 349 .appendPath(Integer.toString(type)).build(); 350 Cursor c = context.getContentResolver().query(uri, ID_PROJECTION, null, null, null); 351 if (c != null) { 352 try { 353 c.moveToFirst(); 354 Long mailboxId = c.getLong(ID_PROJECTION_COLUMN); 355 if (mailboxId != null 356 && mailboxId != 0L 357 && mailboxId != NO_MAILBOX) { 358 return mailboxId; 359 } 360 } finally { 361 c.close(); 362 } 363 } 364 // Fallback to querying the database directly. 365 String[] bindArguments = new String[] {Long.toString(type), Long.toString(accountId)}; 366 return Utility.getFirstRowLong(context, Mailbox.CONTENT_URI, 367 ID_PROJECTION, WHERE_TYPE_AND_ACCOUNT_KEY, bindArguments, null, 368 ID_PROJECTION_COLUMN, NO_MAILBOX); 369 } 370 371 /** 372 * Convenience method that returns the mailbox found using the method above 373 */ 374 public static Mailbox restoreMailboxOfType(Context context, long accountId, int type) { 375 long mailboxId = findMailboxOfType(context, accountId, type); 376 if (mailboxId != Mailbox.NO_MAILBOX) { 377 return Mailbox.restoreMailboxWithId(context, mailboxId); 378 } 379 return null; 380 } 381 382 public static int getUnreadCountByAccountAndMailboxType(Context context, long accountId, 383 int type) { 384 return Utility.getFirstRowInt(context, Mailbox.CONTENT_URI, 385 MAILBOX_SUM_OF_UNREAD_COUNT_PROJECTION, 386 ACCOUNT_AND_MAILBOX_TYPE_SELECTION, 387 new String[] { String.valueOf(accountId), String.valueOf(type) }, 388 null, UNREAD_COUNT_COUNT_COLUMN, 0); 389 } 390 391 public static int getUnreadCountByMailboxType(Context context, int type) { 392 return Utility.getFirstRowInt(context, Mailbox.CONTENT_URI, 393 MAILBOX_SUM_OF_UNREAD_COUNT_PROJECTION, 394 MAILBOX_TYPE_SELECTION, 395 new String[] { String.valueOf(type) }, null, UNREAD_COUNT_COUNT_COLUMN, 0); 396 } 397 398 public static int getMessageCountByMailboxType(Context context, int type) { 399 return Utility.getFirstRowInt(context, Mailbox.CONTENT_URI, 400 MAILBOX_SUM_OF_MESSAGE_COUNT_PROJECTION, 401 MAILBOX_TYPE_SELECTION, 402 new String[] { String.valueOf(type) }, null, MESSAGE_COUNT_COUNT_COLUMN, 0); 403 } 404 405 /** 406 * Return the mailbox for a message with a given id 407 * @param context the caller's context 408 * @param messageId the id of the message 409 * @return the mailbox, or null if the mailbox doesn't exist 410 */ 411 public static Mailbox getMailboxForMessageId(Context context, long messageId) { 412 long mailboxId = Message.getKeyColumnLong(context, messageId, 413 MessageColumns.MAILBOX_KEY); 414 if (mailboxId != -1) { 415 return Mailbox.restoreMailboxWithId(context, mailboxId); 416 } 417 return null; 418 } 419 420 /** 421 * @return mailbox type, or -1 if mailbox not found. 422 */ 423 public static int getMailboxType(Context context, long mailboxId) { 424 Uri url = ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId); 425 return Utility.getFirstRowInt(context, url, MAILBOX_TYPE_PROJECTION, 426 null, null, null, MAILBOX_TYPE_TYPE_COLUMN, -1); 427 } 428 429 /** 430 * @return mailbox display name, or null if mailbox not found. 431 */ 432 public static String getDisplayName(Context context, long mailboxId) { 433 Uri url = ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId); 434 return Utility.getFirstRowString(context, url, MAILBOX_DISPLAY_NAME_PROJECTION, 435 null, null, null, MAILBOX_DISPLAY_NAME_COLUMN); 436 } 437 438 /** 439 * @param mailboxId ID of a mailbox. This method accepts magic mailbox IDs, such as 440 * {@link #QUERY_ALL_INBOXES}. (They're all non-refreshable.) 441 * @return true if a mailbox is refreshable. 442 */ 443 public static boolean isRefreshable(Context context, long mailboxId) { 444 if (mailboxId < 0) { 445 return false; // magic mailboxes 446 } 447 switch (getMailboxType(context, mailboxId)) { 448 case -1: // not found 449 case TYPE_DRAFTS: 450 case TYPE_OUTBOX: 451 return false; 452 } 453 return true; 454 } 455 456 /** 457 * @return whether or not this mailbox supports moving messages out of it 458 */ 459 public boolean canHaveMessagesMoved() { 460 switch (mType) { 461 case TYPE_INBOX: 462 case TYPE_MAIL: 463 case TYPE_TRASH: 464 case TYPE_JUNK: 465 return true; 466 } 467 return false; // TYPE_DRAFTS, TYPE_OUTBOX, TYPE_SENT, etc 468 } 469 470 /** 471 * @return whether or not this mailbox retrieves its data from the server (as opposed to just 472 * a local mailbox that is never synced). 473 */ 474 public boolean loadsFromServer(String protocol) { 475 if (HostAuth.SCHEME_EAS.equals(protocol)) { 476 return mType != Mailbox.TYPE_DRAFTS 477 && mType != Mailbox.TYPE_OUTBOX 478 && mType != Mailbox.TYPE_SEARCH 479 && mType < Mailbox.TYPE_NOT_SYNCABLE; 480 481 } else if (HostAuth.SCHEME_IMAP.equals(protocol)) { 482 // TODO: actually use a sync flag when creating the mailboxes. Right now we use an 483 // approximation for IMAP. 484 return mType != Mailbox.TYPE_DRAFTS 485 && mType != Mailbox.TYPE_OUTBOX 486 && mType != Mailbox.TYPE_SEARCH; 487 488 } else if (HostAuth.SCHEME_POP3.equals(protocol)) { 489 return TYPE_INBOX == mType; 490 } 491 492 return false; 493 } 494 495 /** 496 * @return true if messages in a mailbox of a type can be replied/forwarded. 497 */ 498 public static boolean isMailboxTypeReplyAndForwardable(int type) { 499 return (type != TYPE_TRASH) && (type != TYPE_DRAFTS); 500 } 501 502 /** 503 * Returns a set of hashes that can identify this mailbox. These can be used to 504 * determine if any of the fields have been modified. 505 */ 506 public Object[] getHashes() { 507 Object[] hash = new Object[CONTENT_PROJECTION.length]; 508 509 hash[CONTENT_ID_COLUMN] 510 = mId; 511 hash[CONTENT_DISPLAY_NAME_COLUMN] 512 = mDisplayName; 513 hash[CONTENT_SERVER_ID_COLUMN] 514 = mServerId; 515 hash[CONTENT_PARENT_SERVER_ID_COLUMN] 516 = mParentServerId; 517 hash[CONTENT_ACCOUNT_KEY_COLUMN] 518 = mAccountKey; 519 hash[CONTENT_TYPE_COLUMN] 520 = mType; 521 hash[CONTENT_DELIMITER_COLUMN] 522 = mDelimiter; 523 hash[CONTENT_SYNC_KEY_COLUMN] 524 = mSyncKey; 525 hash[CONTENT_SYNC_LOOKBACK_COLUMN] 526 = mSyncLookback; 527 hash[CONTENT_SYNC_INTERVAL_COLUMN] 528 = mSyncInterval; 529 hash[CONTENT_SYNC_TIME_COLUMN] 530 = mSyncTime; 531 hash[CONTENT_FLAG_VISIBLE_COLUMN] 532 = mFlagVisible; 533 hash[CONTENT_FLAGS_COLUMN] 534 = mFlags; 535 hash[CONTENT_VISIBLE_LIMIT_COLUMN] 536 = mVisibleLimit; 537 hash[CONTENT_SYNC_STATUS_COLUMN] 538 = mSyncStatus; 539 hash[CONTENT_PARENT_KEY_COLUMN] 540 = mParentKey; 541 hash[CONTENT_LAST_SEEN_MESSAGE_KEY_COLUMN] 542 = mLastSeenMessageKey; 543 hash[CONTENT_LAST_TOUCHED_TIME_COLUMN] 544 = mLastTouchedTime; 545 return hash; 546 } 547 548 // Parcelable 549 @Override 550 public int describeContents() { 551 return 0; 552 } 553 554 // Parcelable 555 @Override 556 public void writeToParcel(Parcel dest, int flags) { 557 dest.writeParcelable(mBaseUri, flags); 558 dest.writeLong(mId); 559 dest.writeString(mDisplayName); 560 dest.writeString(mServerId); 561 dest.writeString(mParentServerId); 562 dest.writeLong(mParentKey); 563 dest.writeLong(mAccountKey); 564 dest.writeInt(mType); 565 dest.writeInt(mDelimiter); 566 dest.writeString(mSyncKey); 567 dest.writeInt(mSyncLookback); 568 dest.writeInt(mSyncInterval); 569 dest.writeLong(mSyncTime); 570 dest.writeInt(mFlagVisible ? 1 : 0); 571 dest.writeInt(mFlags); 572 dest.writeInt(mVisibleLimit); 573 dest.writeString(mSyncStatus); 574 dest.writeLong(mLastSeenMessageKey); 575 dest.writeLong(mLastTouchedTime); 576 } 577 578 public Mailbox(Parcel in) { 579 mBaseUri = in.readParcelable(null); 580 mId = in.readLong(); 581 mDisplayName = in.readString(); 582 mServerId = in.readString(); 583 mParentServerId = in.readString(); 584 mParentKey = in.readLong(); 585 mAccountKey = in.readLong(); 586 mType = in.readInt(); 587 mDelimiter = in.readInt(); 588 mSyncKey = in.readString(); 589 mSyncLookback = in.readInt(); 590 mSyncInterval = in.readInt(); 591 mSyncTime = in.readLong(); 592 mFlagVisible = in.readInt() == 1; 593 mFlags = in.readInt(); 594 mVisibleLimit = in.readInt(); 595 mSyncStatus = in.readString(); 596 mLastSeenMessageKey = in.readLong(); 597 mLastTouchedTime = in.readLong(); 598 } 599 600 public static final Parcelable.Creator<Mailbox> CREATOR = new Parcelable.Creator<Mailbox>() { 601 @Override 602 public Mailbox createFromParcel(Parcel source) { 603 return new Mailbox(source); 604 } 605 606 @Override 607 public Mailbox[] newArray(int size) { 608 return new Mailbox[size]; 609 } 610 }; 611 } 612