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