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