Mailbox.java revision d42e14ad722db6eb1a8e6b0696abb6d4a88fac4e
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 18package com.android.emailcommon.provider; 19 20import android.content.ContentResolver; 21import android.content.ContentUris; 22import android.content.ContentValues; 23import android.content.Context; 24import android.database.Cursor; 25import android.net.Uri; 26import android.os.Parcel; 27import android.os.Parcelable; 28import android.util.SparseBooleanArray; 29 30import com.android.emailcommon.Logging; 31import com.android.emailcommon.R; 32import com.android.emailcommon.provider.EmailContent.MailboxColumns; 33import com.android.emailcommon.utility.Utility; 34import com.android.mail.utils.LogUtils; 35 36public class Mailbox extends EmailContent implements MailboxColumns, Parcelable { 37 /** 38 * Sync extras key when syncing a mailbox to specify which mailbox to sync. 39 */ 40 public static final String SYNC_EXTRA_MAILBOX_ID = "__mailboxId__"; 41 /** 42 * Value for {@link #SYNC_EXTRA_MAILBOX_ID} when requesting an account only sync. 43 */ 44 public static final long SYNC_EXTRA_MAILBOX_ID_ACCOUNT_ONLY = -2; 45 /** 46 * Value for {@link #SYNC_EXTRA_MAILBOX_ID} when (re)starting push. 47 */ 48 public static final long SYNC_EXTRA_MAILBOX_ID_PUSH_ONLY = -3; 49 /** 50 * Sync extras key when syncing a mailbox to specify how many additional messages to sync. 51 */ 52 public static final String SYNC_EXTRA_DELTA_MESSAGE_COUNT = "__deltaMessageCount__"; 53 54 public static final String TABLE_NAME = "Mailbox"; 55 56 public static Uri CONTENT_URI; 57 public static Uri MESSAGE_COUNT_URI; 58 59 public static void initMailbox() { 60 CONTENT_URI = Uri.parse(EmailContent.CONTENT_URI + "/mailbox"); 61 MESSAGE_COUNT_URI = Uri.parse(EmailContent.CONTENT_URI + "/mailboxCount"); 62 } 63 64 public String mDisplayName; 65 public String mServerId; 66 public String mParentServerId; 67 public long mParentKey; 68 public long mAccountKey; 69 public int mType; 70 public int mDelimiter; 71 public String mSyncKey; 72 public int mSyncLookback; 73 public int mSyncInterval; 74 public long mSyncTime; 75 public boolean mFlagVisible = true; 76 public int mFlags; 77 public String mSyncStatus; 78 public long mLastTouchedTime; 79 public int mUiSyncStatus; 80 public int mUiLastSyncResult; 81 public int mTotalCount; 82 public String mHierarchicalName; 83 public long mLastFullSyncTime; 84 85 public static final int CONTENT_ID_COLUMN = 0; 86 public static final int CONTENT_DISPLAY_NAME_COLUMN = 1; 87 public static final int CONTENT_SERVER_ID_COLUMN = 2; 88 public static final int CONTENT_PARENT_SERVER_ID_COLUMN = 3; 89 public static final int CONTENT_ACCOUNT_KEY_COLUMN = 4; 90 public static final int CONTENT_TYPE_COLUMN = 5; 91 public static final int CONTENT_DELIMITER_COLUMN = 6; 92 public static final int CONTENT_SYNC_KEY_COLUMN = 7; 93 public static final int CONTENT_SYNC_LOOKBACK_COLUMN = 8; 94 public static final int CONTENT_SYNC_INTERVAL_COLUMN = 9; 95 public static final int CONTENT_SYNC_TIME_COLUMN = 10; 96 public static final int CONTENT_FLAG_VISIBLE_COLUMN = 11; 97 public static final int CONTENT_FLAGS_COLUMN = 12; 98 public static final int CONTENT_SYNC_STATUS_COLUMN = 13; 99 public static final int CONTENT_PARENT_KEY_COLUMN = 14; 100 public static final int CONTENT_LAST_TOUCHED_TIME_COLUMN = 15; 101 public static final int CONTENT_UI_SYNC_STATUS_COLUMN = 16; 102 public static final int CONTENT_UI_LAST_SYNC_RESULT_COLUMN = 17; 103 public static final int CONTENT_TOTAL_COUNT_COLUMN = 18; 104 public static final int CONTENT_HIERARCHICAL_NAME_COLUMN = 19; 105 public static final int CONTENT_LAST_FULL_SYNC_COLUMN = 20; 106 107 /** 108 * <em>NOTE</em>: If fields are added or removed, the method {@link #getHashes()} 109 * MUST be updated. 110 */ 111 public static final String[] CONTENT_PROJECTION = new String[] { 112 RECORD_ID, MailboxColumns.DISPLAY_NAME, MailboxColumns.SERVER_ID, 113 MailboxColumns.PARENT_SERVER_ID, MailboxColumns.ACCOUNT_KEY, MailboxColumns.TYPE, 114 MailboxColumns.DELIMITER, MailboxColumns.SYNC_KEY, MailboxColumns.SYNC_LOOKBACK, 115 MailboxColumns.SYNC_INTERVAL, MailboxColumns.SYNC_TIME, MailboxColumns.FLAG_VISIBLE, 116 MailboxColumns.FLAGS, MailboxColumns.SYNC_STATUS, MailboxColumns.PARENT_KEY, 117 MailboxColumns.LAST_TOUCHED_TIME, MailboxColumns.UI_SYNC_STATUS, 118 MailboxColumns.UI_LAST_SYNC_RESULT, MailboxColumns.TOTAL_COUNT, 119 MailboxColumns.HIERARCHICAL_NAME, MailboxColumns.LAST_FULL_SYNC_TIME 120 }; 121 122 /** Selection by server pathname for a given account */ 123 public static final String PATH_AND_ACCOUNT_SELECTION = 124 MailboxColumns.SERVER_ID + "=? and " + MailboxColumns.ACCOUNT_KEY + "=?"; 125 126 private static final String[] MAILBOX_TYPE_PROJECTION = new String [] { 127 MailboxColumns.TYPE 128 }; 129 private static final int MAILBOX_TYPE_TYPE_COLUMN = 0; 130 131 private static final String[] MAILBOX_DISPLAY_NAME_PROJECTION = new String [] { 132 MailboxColumns.DISPLAY_NAME 133 }; 134 private static final int MAILBOX_DISPLAY_NAME_COLUMN = 0; 135 136 /** 137 * Projection to use when reading {@link MailboxColumns#ACCOUNT_KEY} for a mailbox. 138 */ 139 private static final String[] ACCOUNT_KEY_PROJECTION = { MailboxColumns.ACCOUNT_KEY }; 140 private static final int ACCOUNT_KEY_PROJECTION_ACCOUNT_KEY_COLUMN = 0; 141 142 public static final long NO_MAILBOX = -1; 143 144 // Sentinel values for the mSyncInterval field of both Mailbox records 145 @Deprecated 146 public static final int CHECK_INTERVAL_NEVER = -1; 147 @Deprecated 148 public static final int CHECK_INTERVAL_PUSH = -2; 149 // The following two sentinel values are used by EAS 150 // Ping indicates that the EAS mailbox is synced based on a "ping" from the server 151 @Deprecated 152 public static final int CHECK_INTERVAL_PING = -3; 153 // Push-Hold indicates an EAS push or ping Mailbox shouldn't sync just yet 154 @Deprecated 155 public static final int CHECK_INTERVAL_PUSH_HOLD = -4; 156 157 // Sentinel for PARENT_KEY. Use NO_MAILBOX for toplevel mailboxes (i.e. no parents). 158 public static final long PARENT_KEY_UNINITIALIZED = 0L; 159 160 private static final String WHERE_TYPE_AND_ACCOUNT_KEY = 161 MailboxColumns.TYPE + "=? and " + MailboxColumns.ACCOUNT_KEY + "=?"; 162 163 public static final Integer[] INVALID_DROP_TARGETS = new Integer[] {Mailbox.TYPE_DRAFTS, 164 Mailbox.TYPE_OUTBOX, Mailbox.TYPE_SENT}; 165 166 public static final String USER_VISIBLE_MAILBOX_SELECTION = 167 MailboxColumns.TYPE + "<" + Mailbox.TYPE_NOT_EMAIL + 168 " AND " + MailboxColumns.FLAG_VISIBLE + "=1"; 169 170 /** Selection for all mailboxes that explicitly say they want to sync for an account. */ 171 private static final String SYNCING_AND_ACCOUNT_SELECTION = 172 MailboxColumns.SYNC_INTERVAL + "=1 and " + MailboxColumns.ACCOUNT_KEY + "=?"; 173 174 /** Selection for mailboxes that say they want to sync, plus outbox, for an account. */ 175 private static final String OUTBOX_PLUS_SYNCING_AND_ACCOUNT_SELECTION = "(" 176 + MailboxColumns.TYPE + "=" + Mailbox.TYPE_OUTBOX + " or " 177 + MailboxColumns.SYNC_INTERVAL + "=1) and " + MailboxColumns.ACCOUNT_KEY + "=?"; 178 179 // Types of mailboxes. The list is ordered to match a typical UI presentation, e.g. 180 // placing the inbox at the top. 181 // Arrays of "special_mailbox_display_names" and "special_mailbox_icons" are depends on 182 // types Id of mailboxes. 183 /** No type specified */ 184 public static final int TYPE_NONE = -1; 185 /** The "main" mailbox for the account, almost always referred to as "Inbox" */ 186 public static final int TYPE_INBOX = 0; 187 // Types of mailboxes 188 /** Generic mailbox that holds mail */ 189 public static final int TYPE_MAIL = 1; 190 /** Parent-only mailbox; does not hold any mail */ 191 public static final int TYPE_PARENT = 2; 192 /** Drafts mailbox */ 193 public static final int TYPE_DRAFTS = 3; 194 /** Local mailbox associated with the account's outgoing mail */ 195 public static final int TYPE_OUTBOX = 4; 196 /** Sent mail; mail that was sent from the account */ 197 public static final int TYPE_SENT = 5; 198 /** Deleted mail */ 199 public static final int TYPE_TRASH = 6; 200 /** Junk mail */ 201 public static final int TYPE_JUNK = 7; 202 /** Search results */ 203 public static final int TYPE_SEARCH = 8; 204 /** Starred (virtual) */ 205 public static final int TYPE_STARRED = 9; 206 /** All unread mail (virtual) */ 207 public static final int TYPE_UNREAD = 10; 208 209 // Types after this are used for non-mail mailboxes (as in EAS) 210 public static final int TYPE_NOT_EMAIL = 0x40; 211 public static final int TYPE_CALENDAR = 0x41; 212 public static final int TYPE_CONTACTS = 0x42; 213 public static final int TYPE_TASKS = 0x43; 214 @Deprecated 215 public static final int TYPE_EAS_ACCOUNT_MAILBOX = 0x44; 216 public static final int TYPE_UNKNOWN = 0x45; 217 218 /** 219 * Specifies which mailbox types may be synced from server, and what the default sync interval 220 * value should be. 221 * If a mailbox type is in this array, then it can be synced. 222 * If the mailbox type is mapped to true in this array, then new mailboxes of that type should 223 * be set to automatically sync (either with the periodic poll, or with push, as determined 224 * by the account's sync settings). 225 * See {@link #isSyncableType} and {@link #getDefaultSyncStateForType} for how to access this 226 * data. 227 */ 228 private static final SparseBooleanArray SYNCABLE_TYPES; 229 static { 230 SYNCABLE_TYPES = new SparseBooleanArray(7); 231 SYNCABLE_TYPES.put(TYPE_INBOX, true); 232 SYNCABLE_TYPES.put(TYPE_MAIL, false); 233 SYNCABLE_TYPES.put(TYPE_DRAFTS, true); 234 SYNCABLE_TYPES.put(TYPE_SENT, true); 235 SYNCABLE_TYPES.put(TYPE_TRASH, false); 236 SYNCABLE_TYPES.put(TYPE_CALENDAR, true); 237 SYNCABLE_TYPES.put(TYPE_CONTACTS, true); 238 } 239 240 public static final int TYPE_NOT_SYNCABLE = 0x100; 241 // A mailbox that holds Messages that are attachments 242 public static final int TYPE_ATTACHMENT = 0x101; 243 244 /** 245 * For each of the following folder types, we expect there to be exactly one folder of that 246 * type per account. 247 * Each sync adapter must do the following: 248 * 1) On initial sync: For each type that was not found from the server, create a local folder. 249 * 2) On folder delete: If it's of a required type, convert it to local rather than delete. 250 * 3) On folder add: If it's of a required type, convert the local folder to server. 251 * 4) When adding a duplicate (either initial sync or folder add): Error. 252 */ 253 public static final int[] REQUIRED_FOLDER_TYPES = 254 { TYPE_INBOX, TYPE_DRAFTS, TYPE_OUTBOX, TYPE_SENT, TYPE_TRASH }; 255 256 // Default "touch" time for system mailboxes 257 public static final int DRAFTS_DEFAULT_TOUCH_TIME = 2; 258 public static final int SENT_DEFAULT_TOUCH_TIME = 1; 259 260 // Bit field flags; each is defined below 261 // Warning: Do not read these flags until POP/IMAP/EAS all populate them 262 /** No flags set */ 263 public static final int FLAG_NONE = 0; 264 /** Has children in the mailbox hierarchy */ 265 public static final int FLAG_HAS_CHILDREN = 1<<0; 266 /** Children are visible in the UI */ 267 public static final int FLAG_CHILDREN_VISIBLE = 1<<1; 268 /** cannot receive "pushed" mail */ 269 public static final int FLAG_CANT_PUSH = 1<<2; 270 /** can hold emails (i.e. some parent mailboxes cannot themselves contain mail) */ 271 public static final int FLAG_HOLDS_MAIL = 1<<3; 272 /** can be used as a target for moving messages within the account */ 273 public static final int FLAG_ACCEPTS_MOVED_MAIL = 1<<4; 274 /** can be used as a target for appending messages */ 275 public static final int FLAG_ACCEPTS_APPENDED_MAIL = 1<<5; 276 /** has user settings (sync lookback, etc.) */ 277 public static final int FLAG_SUPPORTS_SETTINGS = 1<<6; 278 279 // Magic mailbox ID's 280 // NOTE: This is a quick solution for merged mailboxes. I would rather implement this 281 // with a more generic way of packaging and sharing queries between activities 282 public static final long QUERY_ALL_INBOXES = -2; 283 public static final long QUERY_ALL_UNREAD = -3; 284 public static final long QUERY_ALL_FAVORITES = -4; 285 public static final long QUERY_ALL_DRAFTS = -5; 286 public static final long QUERY_ALL_OUTBOX = -6; 287 288 /** 289 * Specifies how many messages will be shown in a folder when it is first synced. 290 */ 291 public static final int FIRST_SYNC_MESSAGE_COUNT = 25; 292 293 public Mailbox() { 294 mBaseUri = CONTENT_URI; 295 } 296 297 public static String getSystemMailboxName(Context context, int mailboxType) { 298 int resId = -1; 299 switch (mailboxType) { 300 case Mailbox.TYPE_INBOX: 301 resId = R.string.mailbox_name_server_inbox; 302 break; 303 case Mailbox.TYPE_OUTBOX: 304 resId = R.string.mailbox_name_server_outbox; 305 break; 306 case Mailbox.TYPE_DRAFTS: 307 resId = R.string.mailbox_name_server_drafts; 308 break; 309 case Mailbox.TYPE_TRASH: 310 resId = R.string.mailbox_name_server_trash; 311 break; 312 case Mailbox.TYPE_SENT: 313 resId = R.string.mailbox_name_server_sent; 314 break; 315 case Mailbox.TYPE_JUNK: 316 resId = R.string.mailbox_name_server_junk; 317 break; 318 case Mailbox.TYPE_STARRED: 319 resId = R.string.mailbox_name_server_starred; 320 break; 321 case Mailbox.TYPE_UNREAD: 322 resId = R.string.mailbox_name_server_all_unread; 323 break; 324 default: 325 throw new IllegalArgumentException("Illegal mailbox type"); 326 } 327 return context.getString(resId); 328 } 329 330 /** 331 * Restore a Mailbox from the database, given its unique id 332 * @param context 333 * @param id 334 * @return the instantiated Mailbox 335 */ 336 public static Mailbox restoreMailboxWithId(Context context, long id) { 337 return EmailContent.restoreContentWithId(context, Mailbox.class, 338 Mailbox.CONTENT_URI, Mailbox.CONTENT_PROJECTION, id); 339 } 340 341 /** 342 * Builds a new mailbox with "typical" settings for a system mailbox, such as a local "Drafts" 343 * mailbox. This is useful for protocols like POP3 or IMAP who don't have certain local 344 * system mailboxes synced with the server. 345 * Note: the mailbox is not persisted - clients must call {@link #save} themselves. 346 */ 347 public static Mailbox newSystemMailbox(Context context, long accountId, int mailboxType) { 348 // Sync interval and flags are different based on mailbox type. 349 // TODO: Sync interval doesn't seem to be used anywhere, make it matter or get rid of it. 350 final int syncInterval; 351 final int flags; 352 switch (mailboxType) { 353 case TYPE_INBOX: 354 flags = Mailbox.FLAG_HOLDS_MAIL | Mailbox.FLAG_ACCEPTS_MOVED_MAIL; 355 syncInterval = 0; 356 break; 357 case TYPE_SENT: 358 case TYPE_TRASH: 359 flags = Mailbox.FLAG_HOLDS_MAIL; 360 syncInterval = 0; 361 break; 362 case TYPE_DRAFTS: 363 case TYPE_OUTBOX: 364 flags = Mailbox.FLAG_HOLDS_MAIL; 365 syncInterval = Account.CHECK_INTERVAL_NEVER; 366 break; 367 default: 368 throw new IllegalArgumentException("Bad mailbox type for newSystemMailbox: " + 369 mailboxType); 370 } 371 372 Mailbox box = new Mailbox(); 373 box.mAccountKey = accountId; 374 box.mType = mailboxType; 375 box.mSyncInterval = syncInterval; 376 box.mFlagVisible = true; 377 // TODO: Fix how display names work. 378 box.mServerId = box.mDisplayName = getSystemMailboxName(context, mailboxType); 379 box.mParentKey = Mailbox.NO_MAILBOX; 380 box.mFlags = flags; 381 return box; 382 } 383 384 /** 385 * Returns a Mailbox from the database, given its pathname and account id. All mailbox 386 * paths for a particular account must be unique. Paths are stored in the column 387 * {@link MailboxColumns#SERVER_ID} for want of yet another column in the table. 388 * @param context 389 * @param accountId the ID of the account 390 * @param path the fully qualified, remote pathname 391 */ 392 public static Mailbox restoreMailboxForPath(Context context, long accountId, String path) { 393 Cursor c = context.getContentResolver().query( 394 Mailbox.CONTENT_URI, 395 Mailbox.CONTENT_PROJECTION, 396 Mailbox.PATH_AND_ACCOUNT_SELECTION, 397 new String[] { path, Long.toString(accountId) }, 398 null); 399 if (c == null) throw new ProviderUnavailableException(); 400 try { 401 Mailbox mailbox = null; 402 if (c.moveToFirst()) { 403 mailbox = getContent(c, Mailbox.class); 404 if (c.moveToNext()) { 405 LogUtils.w(Logging.LOG_TAG, "Multiple mailboxes named \"" + path + "\""); 406 } 407 } else { 408 LogUtils.i(Logging.LOG_TAG, "Could not find mailbox at \"" + path + "\""); 409 } 410 return mailbox; 411 } finally { 412 c.close(); 413 } 414 } 415 416 /** 417 * Returns a {@link Mailbox} for the given path. If the path is not in the database, a new 418 * mailbox will be created. 419 */ 420 public static Mailbox getMailboxForPath(Context context, long accountId, String path) { 421 Mailbox mailbox = restoreMailboxForPath(context, accountId, path); 422 if (mailbox == null) { 423 mailbox = new Mailbox(); 424 } 425 return mailbox; 426 } 427 428 /** 429 * Check if a mailbox type can be synced with the server. 430 * @param mailboxType The type to check. 431 * @return Whether this type is syncable. 432 */ 433 public static boolean isSyncableType(final int mailboxType) { 434 return SYNCABLE_TYPES.indexOfKey(mailboxType) >= 0; 435 } 436 437 /** 438 * Check if a mailbox type should sync with the server by default. 439 * @param mailboxType The type to check. 440 * @return Whether this type should default to syncing. 441 */ 442 public static boolean getDefaultSyncStateForType(final int mailboxType) { 443 return SYNCABLE_TYPES.get(mailboxType); 444 } 445 446 /** 447 * Check whether this mailbox is syncable. It has to be both a server synced mailbox, and 448 * of a syncable able. 449 * @return Whether this mailbox is syncable. 450 */ 451 public boolean isSyncable() { 452 return (mTotalCount >= 0) && isSyncableType(mType); 453 } 454 455 @Override 456 public void restore(Cursor cursor) { 457 mBaseUri = CONTENT_URI; 458 mId = cursor.getLong(CONTENT_ID_COLUMN); 459 mDisplayName = cursor.getString(CONTENT_DISPLAY_NAME_COLUMN); 460 mServerId = cursor.getString(CONTENT_SERVER_ID_COLUMN); 461 mParentServerId = cursor.getString(CONTENT_PARENT_SERVER_ID_COLUMN); 462 mParentKey = cursor.getLong(CONTENT_PARENT_KEY_COLUMN); 463 mAccountKey = cursor.getLong(CONTENT_ACCOUNT_KEY_COLUMN); 464 mType = cursor.getInt(CONTENT_TYPE_COLUMN); 465 mDelimiter = cursor.getInt(CONTENT_DELIMITER_COLUMN); 466 mSyncKey = cursor.getString(CONTENT_SYNC_KEY_COLUMN); 467 mSyncLookback = cursor.getInt(CONTENT_SYNC_LOOKBACK_COLUMN); 468 mSyncInterval = cursor.getInt(CONTENT_SYNC_INTERVAL_COLUMN); 469 mSyncTime = cursor.getLong(CONTENT_SYNC_TIME_COLUMN); 470 mFlagVisible = cursor.getInt(CONTENT_FLAG_VISIBLE_COLUMN) == 1; 471 mFlags = cursor.getInt(CONTENT_FLAGS_COLUMN); 472 mSyncStatus = cursor.getString(CONTENT_SYNC_STATUS_COLUMN); 473 mLastTouchedTime = cursor.getLong(CONTENT_LAST_TOUCHED_TIME_COLUMN); 474 mUiSyncStatus = cursor.getInt(CONTENT_UI_SYNC_STATUS_COLUMN); 475 mUiLastSyncResult = cursor.getInt(CONTENT_UI_LAST_SYNC_RESULT_COLUMN); 476 mTotalCount = cursor.getInt(CONTENT_TOTAL_COUNT_COLUMN); 477 mHierarchicalName = cursor.getString(CONTENT_HIERARCHICAL_NAME_COLUMN); 478 mLastFullSyncTime = cursor.getInt(CONTENT_LAST_FULL_SYNC_COLUMN); 479 } 480 481 @Override 482 public ContentValues toContentValues() { 483 ContentValues values = new ContentValues(); 484 values.put(MailboxColumns.DISPLAY_NAME, mDisplayName); 485 values.put(MailboxColumns.SERVER_ID, mServerId); 486 values.put(MailboxColumns.PARENT_SERVER_ID, mParentServerId); 487 values.put(MailboxColumns.PARENT_KEY, mParentKey); 488 values.put(MailboxColumns.ACCOUNT_KEY, mAccountKey); 489 values.put(MailboxColumns.TYPE, mType); 490 values.put(MailboxColumns.DELIMITER, mDelimiter); 491 values.put(MailboxColumns.SYNC_KEY, mSyncKey); 492 values.put(MailboxColumns.SYNC_LOOKBACK, mSyncLookback); 493 values.put(MailboxColumns.SYNC_INTERVAL, mSyncInterval); 494 values.put(MailboxColumns.SYNC_TIME, mSyncTime); 495 values.put(MailboxColumns.FLAG_VISIBLE, mFlagVisible); 496 values.put(MailboxColumns.FLAGS, mFlags); 497 values.put(MailboxColumns.SYNC_STATUS, mSyncStatus); 498 values.put(MailboxColumns.LAST_TOUCHED_TIME, mLastTouchedTime); 499 values.put(MailboxColumns.UI_SYNC_STATUS, mUiSyncStatus); 500 values.put(MailboxColumns.UI_LAST_SYNC_RESULT, mUiLastSyncResult); 501 values.put(MailboxColumns.TOTAL_COUNT, mTotalCount); 502 values.put(MailboxColumns.HIERARCHICAL_NAME, mHierarchicalName); 503 values.put(MailboxColumns.LAST_FULL_SYNC_TIME, mLastFullSyncTime); 504 return values; 505 } 506 507 /** 508 * Store the updated message count in the database. 509 * @param c 510 * @param count 511 */ 512 public void updateMessageCount(final Context c, final int count) { 513 if (count != mTotalCount) { 514 ContentValues values = new ContentValues(); 515 values.put(MailboxColumns.TOTAL_COUNT, count); 516 update(c, values); 517 mTotalCount = count; 518 } 519 } 520 521 /** 522 * Store the last full sync time in the database. 523 * @param c 524 * @param syncTime 525 */ 526 public void updateLastFullSyncTime(final Context c, final long syncTime) { 527 if (syncTime != mLastFullSyncTime) { 528 ContentValues values = new ContentValues(); 529 values.put(MailboxColumns.LAST_FULL_SYNC_TIME, syncTime); 530 update(c, values); 531 mLastFullSyncTime = syncTime; 532 } 533 } 534 535 /** 536 * Convenience method to return the id of a given type of Mailbox for a given Account; the 537 * common Mailbox types (Inbox, Outbox, Sent, Drafts, Trash, and Search) are all cached by 538 * EmailProvider; therefore, we warn if the mailbox is not found in the cache 539 * 540 * @param context the caller's context, used to get a ContentResolver 541 * @param accountId the id of the account to be queried 542 * @param type the mailbox type, as defined above 543 * @return the id of the mailbox, or -1 if not found 544 */ 545 public static long findMailboxOfType(Context context, long accountId, int type) { 546 String[] bindArguments = new String[] {Long.toString(type), Long.toString(accountId)}; 547 return Utility.getFirstRowLong(context, Mailbox.CONTENT_URI, 548 ID_PROJECTION, WHERE_TYPE_AND_ACCOUNT_KEY, bindArguments, null, 549 ID_PROJECTION_COLUMN, NO_MAILBOX); 550 } 551 552 /** 553 * Convenience method that returns the mailbox found using the method above 554 */ 555 public static Mailbox restoreMailboxOfType(Context context, long accountId, int type) { 556 long mailboxId = findMailboxOfType(context, accountId, type); 557 if (mailboxId != Mailbox.NO_MAILBOX) { 558 return Mailbox.restoreMailboxWithId(context, mailboxId); 559 } 560 return null; 561 } 562 563 /** 564 * Return the mailbox for a message with a given id 565 * @param context the caller's context 566 * @param messageId the id of the message 567 * @return the mailbox, or null if the mailbox doesn't exist 568 */ 569 public static Mailbox getMailboxForMessageId(Context context, long messageId) { 570 long mailboxId = Message.getKeyColumnLong(context, messageId, 571 MessageColumns.MAILBOX_KEY); 572 if (mailboxId != -1) { 573 return Mailbox.restoreMailboxWithId(context, mailboxId); 574 } 575 return null; 576 } 577 578 /** 579 * @return mailbox type, or -1 if mailbox not found. 580 */ 581 public static int getMailboxType(Context context, long mailboxId) { 582 Uri url = ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId); 583 return Utility.getFirstRowInt(context, url, MAILBOX_TYPE_PROJECTION, 584 null, null, null, MAILBOX_TYPE_TYPE_COLUMN, -1); 585 } 586 587 /** 588 * @return mailbox display name, or null if mailbox not found. 589 */ 590 public static String getDisplayName(Context context, long mailboxId) { 591 Uri url = ContentUris.withAppendedId(Mailbox.CONTENT_URI, mailboxId); 592 return Utility.getFirstRowString(context, url, MAILBOX_DISPLAY_NAME_PROJECTION, 593 null, null, null, MAILBOX_DISPLAY_NAME_COLUMN); 594 } 595 596 public static int getMailboxMessageCount(Context c, long mailboxId) { 597 Cursor cursor = c.getContentResolver().query( 598 ContentUris.withAppendedId(MESSAGE_COUNT_URI, mailboxId), null, null, null, null); 599 if (cursor != null) { 600 try { 601 if (cursor.moveToFirst()) { 602 return cursor.getInt(0); 603 } 604 } finally { 605 cursor.close(); 606 } 607 } 608 return 0; 609 } 610 611 /** 612 * @param mailboxId ID of a mailbox. This method accepts magic mailbox IDs, such as 613 * {@link #QUERY_ALL_INBOXES}. (They're all non-refreshable.) 614 * @return true if a mailbox is refreshable. 615 */ 616 public static boolean isRefreshable(Context context, long mailboxId) { 617 if (mailboxId < 0) { 618 return false; // magic mailboxes 619 } 620 switch (getMailboxType(context, mailboxId)) { 621 case -1: // not found 622 case TYPE_DRAFTS: 623 case TYPE_OUTBOX: 624 return false; 625 } 626 return true; 627 } 628 629 /** 630 * @return whether or not this mailbox supports moving messages out of it 631 */ 632 public boolean canHaveMessagesMoved() { 633 switch (mType) { 634 case TYPE_INBOX: 635 case TYPE_MAIL: 636 case TYPE_TRASH: 637 case TYPE_JUNK: 638 return true; 639 } 640 return false; // TYPE_DRAFTS, TYPE_OUTBOX, TYPE_SENT, etc 641 } 642 643 /** 644 * Returns a set of hashes that can identify this mailbox. These can be used to 645 * determine if any of the fields have been modified. 646 */ 647 public Object[] getHashes() { 648 Object[] hash = new Object[CONTENT_PROJECTION.length]; 649 650 hash[CONTENT_ID_COLUMN] 651 = mId; 652 hash[CONTENT_DISPLAY_NAME_COLUMN] 653 = mDisplayName; 654 hash[CONTENT_SERVER_ID_COLUMN] 655 = mServerId; 656 hash[CONTENT_PARENT_SERVER_ID_COLUMN] 657 = mParentServerId; 658 hash[CONTENT_ACCOUNT_KEY_COLUMN] 659 = mAccountKey; 660 hash[CONTENT_TYPE_COLUMN] 661 = mType; 662 hash[CONTENT_DELIMITER_COLUMN] 663 = mDelimiter; 664 hash[CONTENT_SYNC_KEY_COLUMN] 665 = mSyncKey; 666 hash[CONTENT_SYNC_LOOKBACK_COLUMN] 667 = mSyncLookback; 668 hash[CONTENT_SYNC_INTERVAL_COLUMN] 669 = mSyncInterval; 670 hash[CONTENT_SYNC_TIME_COLUMN] 671 = mSyncTime; 672 hash[CONTENT_FLAG_VISIBLE_COLUMN] 673 = mFlagVisible; 674 hash[CONTENT_FLAGS_COLUMN] 675 = mFlags; 676 hash[CONTENT_SYNC_STATUS_COLUMN] 677 = mSyncStatus; 678 hash[CONTENT_PARENT_KEY_COLUMN] 679 = mParentKey; 680 hash[CONTENT_LAST_TOUCHED_TIME_COLUMN] 681 = mLastTouchedTime; 682 hash[CONTENT_UI_SYNC_STATUS_COLUMN] 683 = mUiSyncStatus; 684 hash[CONTENT_UI_LAST_SYNC_RESULT_COLUMN] 685 = mUiLastSyncResult; 686 hash[CONTENT_TOTAL_COUNT_COLUMN] 687 = mTotalCount; 688 hash[CONTENT_HIERARCHICAL_NAME_COLUMN] 689 = mHierarchicalName; 690 return hash; 691 } 692 693 // Parcelable 694 @Override 695 public int describeContents() { 696 return 0; 697 } 698 699 // Parcelable 700 @Override 701 public void writeToParcel(Parcel dest, int flags) { 702 dest.writeParcelable(mBaseUri, flags); 703 dest.writeLong(mId); 704 dest.writeString(mDisplayName); 705 dest.writeString(mServerId); 706 dest.writeString(mParentServerId); 707 dest.writeLong(mParentKey); 708 dest.writeLong(mAccountKey); 709 dest.writeInt(mType); 710 dest.writeInt(mDelimiter); 711 dest.writeString(mSyncKey); 712 dest.writeInt(mSyncLookback); 713 dest.writeInt(mSyncInterval); 714 dest.writeLong(mSyncTime); 715 dest.writeInt(mFlagVisible ? 1 : 0); 716 dest.writeInt(mFlags); 717 dest.writeString(mSyncStatus); 718 dest.writeLong(mLastTouchedTime); 719 dest.writeInt(mUiSyncStatus); 720 dest.writeInt(mUiLastSyncResult); 721 dest.writeInt(mTotalCount); 722 dest.writeString(mHierarchicalName); 723 dest.writeLong(mLastFullSyncTime); 724 } 725 726 public Mailbox(Parcel in) { 727 mBaseUri = in.readParcelable(null); 728 mId = in.readLong(); 729 mDisplayName = in.readString(); 730 mServerId = in.readString(); 731 mParentServerId = in.readString(); 732 mParentKey = in.readLong(); 733 mAccountKey = in.readLong(); 734 mType = in.readInt(); 735 mDelimiter = in.readInt(); 736 mSyncKey = in.readString(); 737 mSyncLookback = in.readInt(); 738 mSyncInterval = in.readInt(); 739 mSyncTime = in.readLong(); 740 mFlagVisible = in.readInt() == 1; 741 mFlags = in.readInt(); 742 mSyncStatus = in.readString(); 743 mLastTouchedTime = in.readLong(); 744 mUiSyncStatus = in.readInt(); 745 mUiLastSyncResult = in.readInt(); 746 mTotalCount = in.readInt(); 747 mHierarchicalName = in.readString(); 748 mLastFullSyncTime = in.readLong(); 749 } 750 751 public static final Parcelable.Creator<Mailbox> CREATOR = new Parcelable.Creator<Mailbox>() { 752 @Override 753 public Mailbox createFromParcel(Parcel source) { 754 return new Mailbox(source); 755 } 756 757 @Override 758 public Mailbox[] newArray(int size) { 759 return new Mailbox[size]; 760 } 761 }; 762 763 @Override 764 public String toString() { 765 return "[Mailbox " + mId + ": " + mDisplayName + "]"; 766 } 767 768 /** 769 * Get the mailboxes that want to receive push updates for an account. 770 * @param cr The {@link ContentResolver}. 771 * @param accountId The id for the account that is pushing. 772 * @return A cursor (suitable for use with {@link #restore}) with all mailboxes we should sync. 773 */ 774 public static Cursor getMailboxesForPush(final ContentResolver cr, final long accountId) { 775 return cr.query(Mailbox.CONTENT_URI, Mailbox.CONTENT_PROJECTION, 776 SYNCING_AND_ACCOUNT_SELECTION, new String[] { Long.toString(accountId) }, null); 777 } 778 779 /** 780 * Get the mailbox ids for an account that should sync when we do a full account sync. 781 * @param cr The {@link ContentResolver}. 782 * @param accountId The id for the account that is pushing. 783 * @return A cursor (with one column, containing ids) with all mailbox ids we should sync. 784 */ 785 public static Cursor getMailboxIdsForSync(final ContentResolver cr, final long accountId) { 786 return cr.query(Mailbox.CONTENT_URI, Mailbox.ID_PROJECTION, 787 OUTBOX_PLUS_SYNCING_AND_ACCOUNT_SELECTION, 788 new String[] { Long.toString(accountId) }, null); 789 } 790 791 /** 792 * Get the account id for a mailbox. 793 * @param context The {@link Context}. 794 * @param mailboxId The id of the mailbox we're interested in, as a {@link String}. 795 * @return The account id for the mailbox, or {@link Account#NO_ACCOUNT} if the mailbox doesn't 796 * exist. 797 */ 798 public static long getAccountIdForMailbox(final Context context, final String mailboxId) { 799 return Utility.getFirstRowLong(context, 800 Mailbox.CONTENT_URI.buildUpon().appendEncodedPath(mailboxId).build(), 801 ACCOUNT_KEY_PROJECTION, null, null, null, 802 ACCOUNT_KEY_PROJECTION_ACCOUNT_KEY_COLUMN, Account.NO_ACCOUNT); 803 } 804} 805