• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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