• 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