1/*******************************************************************************
2 *      Copyright (C) 2011 Google Inc.
3 *      Licensed to The Android Open Source Project.
4 *
5 *      Licensed under the Apache License, Version 2.0 (the "License");
6 *      you may not use this file except in compliance with the License.
7 *      You may obtain a copy of the License at
8 *
9 *           http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *      Unless required by applicable law or agreed to in writing, software
12 *      distributed under the License is distributed on an "AS IS" BASIS,
13 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *      See the License for the specific language governing permissions and
15 *      limitations under the License.
16 *******************************************************************************/
17
18package com.android.mail.providers;
19
20import android.content.ContentProvider;
21import android.content.ContentValues;
22import android.database.Cursor;
23import android.net.Uri;
24import android.os.Bundle;
25import android.os.Parcelable;
26import android.provider.BaseColumns;
27import android.provider.OpenableColumns;
28import android.text.TextUtils;
29
30import com.google.common.annotations.VisibleForTesting;
31import com.google.common.collect.ImmutableList;
32import com.google.common.collect.ImmutableMap;
33
34import java.util.Map;
35import java.util.regex.Pattern;
36
37public class UIProvider {
38    public static final String EMAIL_SEPARATOR = ",";
39    public static final long INVALID_CONVERSATION_ID = -1;
40    public static final long INVALID_MESSAGE_ID = -1;
41
42    /**
43     * Values for the current state of a Folder/Account; note that it's possible that more than one
44     * sync is in progress
45     */
46    public static final class SyncStatus {
47        /**
48         * No sync in progress
49         */
50        public static final int NO_SYNC = 0;
51        /**
52         * A user-requested sync/refresh is in progress. This occurs when the user taps on the
53         * refresh icon in the action bar.
54         */
55        public static final int USER_REFRESH = 1<<0;
56        /**
57         * A user-requested live query is in progress. This occurs when the user goes past the end
58         * of the fetched results in the conversation list.
59         */
60        public static final int LIVE_QUERY = 1<<1;
61        /** Please use the constant {@link #LIVE_QUERY} instead. */
62        @Deprecated
63        public static final int USER_QUERY = 1<<1;
64        /**
65         * A background sync is in progress. This happens on <b>no</b> user interaction.
66         */
67        public static final int BACKGROUND_SYNC = 1<<2;
68        /**
69         * An initial sync is needed for this Account/Folder to be used. This is account-wide, when
70         * the user has added an account, and the first sync has not completed successfully.
71         */
72        public static final int INITIAL_SYNC_NEEDED = 1<<3;
73        /**
74         * Manual sync is required. This is account-wide, when the user has disabled sync on the
75         * Gmail account.
76         */
77        public static final int MANUAL_SYNC_REQUIRED = 1<<4;
78        /**
79         * Account initialization is required.
80         */
81        public static final int ACCOUNT_INITIALIZATION_REQUIRED = 1<<5;
82
83        public static boolean isSyncInProgress(int syncStatus) {
84            return 0 != (syncStatus & (BACKGROUND_SYNC |
85                    USER_REFRESH |
86                    LIVE_QUERY));
87        }
88    }
89
90    /**
91     * Values for the result of the last attempted sync of a Folder/Account
92     */
93    public static final class LastSyncResult {
94        /** The sync completed successfully */
95        public static final int SUCCESS = 0;
96        /** The sync wasn't completed due to a connection error */
97        public static final int CONNECTION_ERROR = 1;
98        /** The sync wasn't completed due to an authentication error */
99        public static final int AUTH_ERROR = 2;
100        /** The sync wasn't completed due to a security error */
101        public static final int SECURITY_ERROR = 3;
102        /** The sync wasn't completed due to a low memory condition */
103        public static final int STORAGE_ERROR = 4;
104        /** The sync wasn't completed due to an internal error/exception */
105        public static final int INTERNAL_ERROR = 5;
106        /** The sync wasn't completed due to an error in the mail server */
107        public static final int SERVER_ERROR = 6;
108
109        public static String toString(int result) {
110            switch (result) {
111                case SUCCESS: return "success";
112                case CONNECTION_ERROR: return "connection_error";
113                case AUTH_ERROR: return "auth_error";
114                case SECURITY_ERROR: return "security_error";
115                case STORAGE_ERROR: return "storage_error";
116                case INTERNAL_ERROR: return "internal_error";
117                case SERVER_ERROR: return "server_error";
118                default: throw new IllegalArgumentException("Invalid LastSyncResult: " + result);
119            }
120        }
121    }
122
123    /**
124     * Combines the reason for the sync request (user vs. background sync) with the status of the
125     * request (success vs failure reason) into a single integer value.
126     *
127     * @param syncStatus {@link SyncStatus} value describing the reason for the sync
128     * @param lastSyncResult {@link LastSyncResult} value describing the result of the sync
129     * @return a single integer packed with the status and result values
130     */
131    @VisibleForTesting
132    public static int createSyncValue(int syncStatus, int lastSyncResult) {
133        return lastSyncResult | (syncStatus << 4);
134    }
135
136    /**
137     * @param lastSyncValue value containing the {@link SyncStatus} and {@link LastSyncResult}
138     * @return the {@link LastSyncResult} within the <code>lastSyncValue</code>
139     */
140    public static int getResultFromLastSyncResult(int lastSyncValue) {
141        return lastSyncValue & 0x0f;
142    }
143
144    /**
145     * @param lastSyncValue value containing the {@link SyncStatus} and {@link LastSyncResult}
146     * @return the {@link SyncStatus} within the <code>lastSyncValue</code>
147     */
148    public static int getStatusFromLastSyncResult(int lastSyncValue) {
149        return lastSyncValue >> 4;
150    }
151
152    // The actual content provider should define its own authority
153    public static final String AUTHORITY = "com.android.mail.providers";
154
155    public static final String ACCOUNT_LIST_TYPE =
156            "vnd.android.cursor.dir/vnd.com.android.mail.account";
157    public static final String ACCOUNT_TYPE =
158            "vnd.android.cursor.item/vnd.com.android.mail.account";
159
160    /**
161     * Query parameter key that can be used to control the behavior of list queries.  The value
162     * must be a serialized {@link ListParams} object.  UIProvider implementations are not
163     * required to respect this query parameter
164     */
165    public static final String LIST_PARAMS_QUERY_PARAMETER = "listParams";
166    public static final String LABEL_QUERY_PARAMETER = "label";
167    public static final String SEEN_QUERY_PARAMETER = "seen";
168
169    /**
170     * Query parameter that can be used to specify a parent for a the returned folder object from a
171     * query. When set, if a folder is returned that does not have a true parent, it will use this
172     * uri as its parent uri.
173     */
174    public static final String DEFAULT_PARENT_QUERY_PARAMETER = "defaultParent";
175
176    public static final Map<String, Class<?>> ACCOUNTS_COLUMNS_NO_CAPABILITIES =
177            new ImmutableMap.Builder<String, Class<?>>()
178            .put(AccountColumns._ID, Integer.class)
179            .put(AccountColumns.NAME, String.class)
180            .put(AccountColumns.SENDER_NAME, String.class)
181            .put(AccountColumns.ACCOUNT_MANAGER_NAME, String.class)
182            .put(AccountColumns.ACCOUNT_ID, String.class)
183            .put(AccountColumns.TYPE, String.class)
184            .put(AccountColumns.PROVIDER_VERSION, Integer.class)
185            .put(AccountColumns.URI, String.class)
186            .put(AccountColumns.FOLDER_LIST_URI, String.class)
187            .put(AccountColumns.FULL_FOLDER_LIST_URI, String.class)
188            .put(AccountColumns.ALL_FOLDER_LIST_URI, String.class)
189            .put(AccountColumns.SEARCH_URI, String.class)
190            .put(AccountColumns.ACCOUNT_FROM_ADDRESSES, String.class)
191            .put(AccountColumns.EXPUNGE_MESSAGE_URI, String.class)
192            .put(AccountColumns.UNDO_URI, String.class)
193            .put(AccountColumns.SETTINGS_INTENT_URI, String.class)
194            .put(AccountColumns.SYNC_STATUS, Integer.class)
195            .put(AccountColumns.HELP_INTENT_URI, String.class)
196            .put(AccountColumns.SEND_FEEDBACK_INTENT_URI, String.class)
197            .put(AccountColumns.REAUTHENTICATION_INTENT_URI, String.class)
198            .put(AccountColumns.COMPOSE_URI, String.class)
199            .put(AccountColumns.MIME_TYPE, String.class)
200            .put(AccountColumns.RECENT_FOLDER_LIST_URI, String.class)
201            .put(AccountColumns.COLOR, Integer.class)
202            .put(AccountColumns.DEFAULT_RECENT_FOLDER_LIST_URI, String.class)
203            .put(AccountColumns.MANUAL_SYNC_URI, String.class)
204            .put(AccountColumns.VIEW_INTENT_PROXY_URI, String.class)
205            .put(AccountColumns.ACCOUNT_COOKIE_QUERY_URI, String.class)
206            .put(AccountColumns.SettingsColumns.SIGNATURE, String.class)
207            .put(AccountColumns.SettingsColumns.AUTO_ADVANCE, Integer.class)
208            .put(AccountColumns.SettingsColumns.SNAP_HEADERS, Integer.class)
209            .put(AccountColumns.SettingsColumns.REPLY_BEHAVIOR, Integer.class)
210            .put(AccountColumns.SettingsColumns.CONV_LIST_ICON, Integer.class)
211            .put(AccountColumns.SettingsColumns.CONFIRM_DELETE, Integer.class)
212            .put(AccountColumns.SettingsColumns.CONFIRM_ARCHIVE, Integer.class)
213            .put(AccountColumns.SettingsColumns.CONFIRM_SEND, Integer.class)
214            .put(AccountColumns.SettingsColumns.DEFAULT_INBOX, String.class)
215            .put(AccountColumns.SettingsColumns.DEFAULT_INBOX_NAME, String.class)
216            .put(AccountColumns.SettingsColumns.FORCE_REPLY_FROM_DEFAULT, Integer.class)
217            .put(AccountColumns.SettingsColumns.MAX_ATTACHMENT_SIZE, Integer.class)
218            .put(AccountColumns.SettingsColumns.SWIPE, Integer.class)
219            .put(AccountColumns.SettingsColumns.IMPORTANCE_MARKERS_ENABLED, Integer.class)
220            .put(AccountColumns.SettingsColumns.SHOW_CHEVRONS_ENABLED, Integer.class)
221            .put(AccountColumns.SettingsColumns.SETUP_INTENT_URI, String.class)
222            .put(AccountColumns.SettingsColumns.CONVERSATION_VIEW_MODE, Integer.class)
223            .put(AccountColumns.SettingsColumns.VEILED_ADDRESS_PATTERN, String.class)
224            .put(AccountColumns.UPDATE_SETTINGS_URI, String.class)
225            .put(AccountColumns.ENABLE_MESSAGE_TRANSFORMS, Integer.class)
226            .put(AccountColumns.SYNC_AUTHORITY, String.class)
227            .put(AccountColumns.QUICK_RESPONSE_URI, String.class)
228            .put(AccountColumns.SETTINGS_FRAGMENT_CLASS, String.class)
229            .put(AccountColumns.SettingsColumns.MOVE_TO_INBOX, String.class)
230            .put(AccountColumns.SettingsColumns.SHOW_IMAGES, Integer.class)
231            .put(AccountColumns.SettingsColumns.WELCOME_TOUR_SHOWN_VERSION, Integer.class)
232            .put(AccountColumns.SECURITY_HOLD, Integer.class)
233            .put(AccountColumns.ACCOUNT_SECURITY_URI, String.class)
234            .build();
235
236    public static final Map<String, Class<?>> ACCOUNTS_COLUMNS =
237            new ImmutableMap.Builder<String, Class<?>>()
238            .putAll(ACCOUNTS_COLUMNS_NO_CAPABILITIES)
239            .put(AccountColumns.CAPABILITIES, Integer.class)
240            .build();
241
242    // pull out the keyset from above to form the projection
243    public static final String[] ACCOUNTS_PROJECTION =
244            ACCOUNTS_COLUMNS.keySet().toArray(new String[ACCOUNTS_COLUMNS.size()]);
245
246    public static final
247            String[] ACCOUNTS_PROJECTION_NO_CAPABILITIES = ACCOUNTS_COLUMNS_NO_CAPABILITIES.keySet()
248                    .toArray(new String[ACCOUNTS_COLUMNS_NO_CAPABILITIES.size()]);
249
250    public static final class AccountCapabilities {
251        /**
252         * Whether folders can be synchronized back to the server.
253         */
254        public static final int SYNCABLE_FOLDERS = 0x0001;
255        /**
256         * Whether the server allows reporting spam back.
257         */
258        public static final int REPORT_SPAM = 0x0002;
259        /**
260         * Whether the server allows reporting phishing back.
261         */
262        public static final int REPORT_PHISHING = 0x0004;
263        /**
264         * Whether the server supports a concept of Archive: removing mail from the Inbox but
265         * keeping it around.
266         */
267        public static final int ARCHIVE = 0x0008;
268        /**
269         * Whether the server will stop notifying on updates to this thread? This requires
270         * THREADED_CONVERSATIONS to be true, otherwise it should be ignored.
271         */
272        public static final int MUTE = 0x0010;
273        /**
274         * Whether the server supports searching over all messages. This requires SYNCABLE_FOLDERS
275         * to be true, otherwise it should be ignored.
276         */
277        public static final int SERVER_SEARCH = 0x0020;
278        /**
279         * Whether the server supports constraining search to a single folder. Requires
280         * SYNCABLE_FOLDERS, otherwise it should be ignored.
281         */
282        public static final int FOLDER_SERVER_SEARCH = 0x0040;
283        /**
284         * Whether the server sends us sanitized HTML (guaranteed to not contain malicious HTML).
285         */
286        public static final int SERVER_SANITIZED_HTML = 0x0080;
287        /**
288         * Whether the server allows synchronization of draft messages. This does NOT require
289         * SYNCABLE_FOLDERS to be set.
290         */
291        public static final int DRAFT_SYNCHRONIZATION = 0x0100;
292        /**
293         * Does the server allow the user to compose mails (and reply) using addresses other than
294         * their account name? For instance, GMail allows users to set FROM addresses that are
295         * different from account@gmail.com address. For instance, user@gmail.com could have another
296         * FROM: address like user@android.com. If the user has enabled multiple FROM address, he
297         * can compose (and reply) using either address.
298         */
299        public static final int MULTIPLE_FROM_ADDRESSES = 0x0200;
300        /**
301         * Whether the server allows the original message to be included in the reply by setting a
302         * flag on the reply. If we can avoid including the entire previous message, we save on
303         * bandwidth (replies are shorter).
304         */
305        public static final int SMART_REPLY = 0x0400;
306        /**
307         * Does this account support searching locally, on the device? This requires the backend
308         * storage to support a mechanism for searching.
309         */
310        public static final int LOCAL_SEARCH = 0x0800;
311        /**
312         * Whether the server supports a notion of threaded conversations: where replies to messages
313         * are tagged to keep conversations grouped. This could be full threading (each message
314         * lists its parent) or conversation-level threading (each message lists one conversation
315         * which it belongs to)
316         */
317        public static final int THREADED_CONVERSATIONS = 0x1000;
318        /**
319         * Whether the server supports allowing a conversation to be in multiple folders. (Or allows
320         * multiple folders on a single conversation)
321         */
322        public static final int MULTIPLE_FOLDERS_PER_CONV = 0x2000;
323        /**
324         * Whether the provider supports undoing operations. If it doesn't, never show the undo bar.
325         */
326        public static final int UNDO = 0x4000;
327        /**
328         * Whether the account provides help content.
329         */
330        public static final int HELP_CONTENT = 0x8000;
331        /**
332         * Whether the account provides a way to send feedback content.
333         */
334        public static final int SEND_FEEDBACK = 0x10000;
335        /**
336         * Whether the account provides a mechanism for marking conversations as important.
337         */
338        public static final int MARK_IMPORTANT = 0x20000;
339        /**
340         * Whether initial conversation queries should use a limit parameter
341         */
342        public static final int INITIAL_CONVERSATION_LIMIT = 0x40000;
343        /**
344         * Whether the account is not a real account, i.e. Combined View
345         */
346        public static final int VIRTUAL_ACCOUNT = 0x80000;
347        /**
348         * Whether the account supports discarding drafts from a conversation.  This should be
349         * removed when all providers support this capability
350         */
351        public static final int DISCARD_CONVERSATION_DRAFTS = 0x100000;
352        /**
353         * Whether the account supports emptying the trash folder
354         */
355        public static final int EMPTY_TRASH = 0x200000;
356        /**
357         * Whether the account supports emptying the spam folder
358         */
359        public static final int EMPTY_SPAM = 0x400000;
360        /**
361         * Whether the account supports nested folders
362         */
363        public static final int NESTED_FOLDERS = 0x800000;
364        /**
365         * Whether the client is permitted to sanitize HTML for this account.
366         */
367        public static final int CLIENT_SANITIZED_HTML = 0x1000000;
368    }
369
370    public static final class AccountColumns implements BaseColumns {
371        /**
372         * This string column contains the human visible name for the account.
373         */
374        public static final String NAME = "name";
375
376        /**
377         * This string column contains the real name associated with the account, e.g. "John Doe"
378         */
379        public static final String SENDER_NAME = "senderName";
380
381        /**
382         * This string column contains the account manager name of this account.
383         */
384        public static final String ACCOUNT_MANAGER_NAME = "accountManagerName";
385
386        /**
387         * This string column contains the account id of this account.
388         */
389        public static final String ACCOUNT_ID = "accountId";
390
391        /**
392         * This integer contains the type of the account: Google versus non google. This is not
393         * returned by the UIProvider, rather this is a notion in the system.
394         */
395        public static final String TYPE = "type";
396
397        /**
398         * This integer column returns the version of the UI provider schema from which this
399         * account provider will return results.
400         */
401        public static final String PROVIDER_VERSION = "providerVersion";
402
403        /**
404         * This string column contains the uri to directly access the information for this account.
405         */
406        public static final String URI = "accountUri";
407
408        /**
409         * This integer column contains a bit field of the possible capabilities that this account
410         * supports.
411         */
412        public static final String CAPABILITIES = "capabilities";
413
414        /**
415         * This string column contains the content provider uri to return the
416         * list of top level folders for this account.
417         */
418        public static final String FOLDER_LIST_URI = "folderListUri";
419
420        /**
421         * This string column contains the content provider uri to return the
422         * list of all real folders for this account.
423         */
424        public static final String FULL_FOLDER_LIST_URI = "fullFolderListUri";
425
426        /**
427         * This string column contains the content provider uri to return the
428         * list of all real and synthetic folders for this account.
429         */
430        public static final String ALL_FOLDER_LIST_URI = "allFolderListUri";
431
432        /**
433         * This string column contains the content provider uri that can be queried for search
434         * results.
435         * The supported query parameters are limited to those listed
436         * in {@link SearchQueryParameters}
437         * The cursor returned from this query is expected have one row, where the columnm are a
438         * subset of the columns specified in {@link FolderColumns}
439         */
440        public static final String SEARCH_URI = "searchUri";
441
442        /**
443         * This string column contains a json array of json objects representing
444         * custom from addresses for this account or null if there are none.
445         */
446        public static final String ACCOUNT_FROM_ADDRESSES = "accountFromAddresses";
447
448        /**
449         * This string column contains the content provider uri that can be used
450         * to expunge a message from this account. NOTE: This might be better to
451         * be an update operation on the messageUri.
452         * When {@link android.content.ContentResolver#update(Uri, ContentValues, String, String[])}
453         * is called with this uri, the {@link ContentValues} object is expected to have
454         * {@link BaseColumns#_ID} specified with the local message id of the message.
455         */
456        public static final String EXPUNGE_MESSAGE_URI = "expungeMessageUri";
457
458        /**
459         * This string column contains the content provider uri that can be used
460         * to undo the last committed action.
461         */
462        public static final String UNDO_URI = "undoUri";
463
464        /**
465         * Uri for EDIT intent that will cause the settings screens for this account type to be
466         * shown.
467         * Optionally, extra values from {@link EditSettingsExtras} can be used to indicate
468         * which settings the user wants to edit.
469         * TODO: When we want to support a heterogeneous set of account types, this value may need
470         * to be moved to a global content provider.
471         */
472        public static final String SETTINGS_INTENT_URI = "accountSettingsIntentUri";
473
474        /**
475         * Uri for VIEW intent that will cause the help screens for this account type to be
476         * shown.
477         * TODO: When we want to support a heterogeneous set of account types, this value may need
478         * to be moved to a global content provider.
479         */
480        public static final String HELP_INTENT_URI = "helpIntentUri";
481
482        /**
483         * Uri for VIEW intent that will cause the send feedback for this account type to be
484         * shown.
485         * TODO: When we want to support a heterogeneous set of account types, this value may need
486         * to be moved to a global content provider.
487         */
488        public static final String SEND_FEEDBACK_INTENT_URI = "sendFeedbackIntentUri";
489
490        /**
491         * Uri for VIEW intent that will cause the user to be prompted for authentication for
492         * this account.  startActivityForResult() will be called with this intent. Activities that
493         * handle this intent are expected to return {@link android.app.Activity#RESULT_OK} if the
494         * user successfully authenticated.
495         */
496        public static final String REAUTHENTICATION_INTENT_URI = "reauthenticationUri";
497
498        /**
499         * This int column contains the current sync status of the account (the logical AND of the
500         * sync status of folders in this account)
501         */
502        public static final String SYNC_STATUS = "syncStatus";
503        /**
504         * Uri for VIEW intent that will cause the compose screens for this type
505         * of account to be shown.
506         */
507        public static final String COMPOSE_URI = "composeUri";
508        /**
509         * Mime-type defining this account.
510         */
511        public static final String MIME_TYPE = "mimeType";
512        /**
513         * URI for location of recent folders viewed on this account.
514         */
515        public static final String RECENT_FOLDER_LIST_URI = "recentFolderListUri";
516        /**
517         * URI for default recent folders for this account, if any.
518         */
519        public static final String DEFAULT_RECENT_FOLDER_LIST_URI = "defaultRecentFolderListUri";
520        /**
521         * Color (integer) used for this account (for Email/Combined view)
522         */
523        public static final String COLOR = "color";
524        /**
525         * URI for forcing a manual sync of this account.
526         */
527        public static final String MANUAL_SYNC_URI = "manualSyncUri";
528        /**
529         * Optional URI of this account for proxying view intents.
530         */
531        public static final String VIEW_INTENT_PROXY_URI = "viewProxyUri";
532        /**
533         * Optional URI for querying for the cookie needed for accessing inline content.  The cookie
534         * specified here will be set on the uri specified in the
535         * {@link ConversationColumns#CONVERSATION_BASE_URI} column. The cursor returned from this
536         * query is expected have one row, where the columns are specified in
537         * {@link AccountCookieColumns}
538         */
539        public static final String ACCOUNT_COOKIE_QUERY_URI = "accountCookieUri";
540        /**
541         * URI to be used with an update() ContentResolver call with a {@link ContentValues} object
542         * where the keys are from the {@link AccountColumns.SettingsColumns}, and the values are
543         * the new values.
544         */
545        public static final String UPDATE_SETTINGS_URI = "updateSettingsUri";
546        /**
547         * Whether message transforms (HTML DOM manipulation) should be enabled.
548         */
549        public static final String ENABLE_MESSAGE_TRANSFORMS = "enableMessageTransforms";
550        /**
551         * Sync authority to use.
552         */
553        public static final String SYNC_AUTHORITY = "syncAuthority";
554        /**
555         * URI for querying this account's quick responses
556         */
557        public static final String QUICK_RESPONSE_URI = "quickResponseUri";
558        /**
559         * Fragment class name for account settings
560         */
561        public static final String SETTINGS_FRAGMENT_CLASS = "settingsFragmentClass";
562        /**
563         * Whether this account is on a security hold
564         */
565        public static final String SECURITY_HOLD = "securityHold";
566        /**
567         * Uri to access the account security activity.
568         */
569        public static final String ACCOUNT_SECURITY_URI = "accountSecurityUri";
570
571        public static final class SettingsColumns {
572            /**
573             * String column containing the contents of the signature for this account.  If no
574             * signature has been specified, the value will be null.
575             */
576            public static final String SIGNATURE = "signature";
577
578            /**
579             * Integer column containing the user's specified auto-advance policy.  This value will
580             * be one of the values in {@link UIProvider.AutoAdvance}
581             */
582            public static final String AUTO_ADVANCE = "auto_advance";
583
584            /**
585             * Integer column contaning the user's specified snap header preference.  This value
586             * will be one of the values in {@link UIProvider.SnapHeaderValue}
587             */
588            public static final String SNAP_HEADERS = "snap_headers";
589
590            /**
591             * Integer column containing the user's specified default reply behavior.  This value
592             * will be one of the values in {@link UIProvider.DefaultReplyBehavior}
593             */
594            public static final String REPLY_BEHAVIOR = "reply_behavior";
595
596            /**
597             * Integer column containing the user's preference for whether to show sender images
598             * or not in the conversation list view.  This value will be one of the values in
599             * {@link UIProvider.ConversationListIcon}.
600             */
601            public static final String CONV_LIST_ICON = "conversation_list_icon";
602
603            /**
604             * Integer column containing the user's specified confirm delete preference value.
605             * A non zero value indicates that the user has indicated that a confirmation should
606             * be shown when a delete action is performed.
607             */
608            public static final String CONFIRM_DELETE = "confirm_delete";
609
610            /**
611             * Integer column containing the user's specified confirm archive preference value.
612             * A non zero value indicates that the user has indicated that a confirmation should
613             * be shown when an archive action is performed.
614             */
615            public static final String CONFIRM_ARCHIVE = "confirm_archive";
616
617            /**
618             * Integer column containing the user's specified confirm send preference value.
619             * A non zero value indicates that the user has indicated that a confirmation should
620             * be shown when a send action is performed.
621             */
622            public static final String CONFIRM_SEND = "confirm_send";
623            /**
624             * String containing the URI for the default inbox for this account.
625             */
626            public static final String DEFAULT_INBOX = "default_inbox";
627            /**
628             * String containing the name of the default Inbox for this account
629             */
630            public static final String DEFAULT_INBOX_NAME = "default_inbox_name";
631            /**
632             * Integer column containing a non zero value if replies should always be sent from
633             * a default address instead of a recipient.
634             */
635            public static final String FORCE_REPLY_FROM_DEFAULT = "force_reply_from_default";
636            /**
637             * Integer column containing the max attachment size in kb.
638             */
639            public static final String MAX_ATTACHMENT_SIZE = "max_attachment_size";
640            /**
641             * Integer column containing a value matching one of the constants from {@link Swipe}
642             */
643            public static final String SWIPE = "swipe";
644            /**
645             * Integer column containing whether importance markers are enabled.
646             */
647            public static final String IMPORTANCE_MARKERS_ENABLED = "importance_markers_enabled";
648            /**
649             * Integer column containing whether chevrons should be shown.
650             * Chevrons are personal level indicators:
651             * an arrow ( › ) by messages sent to my address (not a mailing list),
652             * and a double arrow ( » ) by messages sent only to me.
653             */
654            public static final String SHOW_CHEVRONS_ENABLED = "show_chevrons_enabled";
655            /**
656             * Uri for EDIT intent that will cause account-specific setup UI to be shown. If not
657             * null, this intent should be used when an account is "entered" (i.e. viewing a folder
658             * in the account, etc.)
659             */
660            public static final String SETUP_INTENT_URI = "setup_intent_uri";
661            /**
662             * The regex that defines a veiled address, something that must be hidden from user
663             * view because it is temporary, long and clumsy.
664             */
665            public static final String VEILED_ADDRESS_PATTERN = "veiled_address_pattern";
666            /**
667             * Integer column containing the Conversation view mode.  This value will match one of
668             * constants from  {@link ConversationViewMode}
669             */
670            public static final String CONVERSATION_VIEW_MODE = "conversation_view_mode";
671            /**
672             * String containing the URI for the inbox conversations should be moved to for this
673             * account.
674             */
675            public static final String MOVE_TO_INBOX = "move_to_inbox";
676            /**
677             * Show images in conversation view.
678             */
679            public static final String SHOW_IMAGES = "show_images";
680
681            /**
682             * The version of the welcome tour that user saw on android device.
683             */
684            public static final String WELCOME_TOUR_SHOWN_VERSION = "welcome_tour_shown_version";
685        }
686    }
687
688    public static final String[] QUICK_RESPONSE_PROJECTION = {
689        BaseColumns._ID,
690        QuickResponseColumns.TEXT,
691        QuickResponseColumns.URI
692    };
693
694    public static final class QuickResponseColumns {
695        /**
696         * Text of the Quick Response
697         */
698        public static final String TEXT = "quickResponse";
699        /**
700         * URI to access this row directly
701         */
702        public static final String URI = "uri";
703    }
704
705    public static final String[] ACCOUNT_COOKIE_PROJECTION = {
706        AccountCookieColumns.COOKIE
707    };
708
709    public static final class AccountCookieColumns {
710        /**
711         * String column containing the cookie string for this account.
712         */
713        public static final String COOKIE = "cookie";
714    }
715
716    public static final class SearchQueryParameters {
717        /**
718         * Parameter used to specify the search query.
719         */
720        public static final String QUERY = "query";
721
722        /*
723        * This parameter is set by ACTION_SEARCH to differentiate one ACTION_SEARCH from another.
724        * This is necessary because the Uri we construct for each query is only based on the
725        * search query string. However, subsequent searches with the same string will confuse
726        * the underlying provider into thinking that it's still the same "session", thus it will
727        * keep the data it had before. This is a problem when we do search on some keyword, then
728        * without navigating away we do the same search again (expecting to see new results there
729        * and outdated results gone). By keying the Uri on both search query and a unique id,
730        * we ensure that old data gets properly destroyed.
731        * @see UnifiedGmail, MailEngine#getConversationCursorForQuery.
732        */
733        public static final String QUERY_IDENTIFER = "query_identifier";
734
735        private SearchQueryParameters() {}
736    }
737
738    public static final class ConversationListQueryParameters {
739        public static final String DEFAULT_LIMIT = "50";
740        /**
741         * Parameter used to limit the number of rows returned by a conversation list query
742         */
743        public static final String LIMIT = "limit";
744
745        /**
746         * Parameter used to control whether the this query a remote server.
747         */
748        public static final String USE_NETWORK = "use_network";
749
750        /**
751         * Parameter used to allow the caller to indicate desire to receive all notifications.
752         * (Including ones for user initiated actions)
753         */
754        public static final String ALL_NOTIFICATIONS = "all_notifications";
755
756        private ConversationListQueryParameters() {}
757    }
758
759    // We define a "folder" as anything that contains a list of conversations.
760    public static final String FOLDER_LIST_TYPE =
761            "vnd.android.cursor.dir/vnd.com.android.mail.folder";
762    public static final String FOLDER_TYPE =
763            "vnd.android.cursor.item/vnd.com.android.mail.folder";
764
765    public static final String[] FOLDERS_PROJECTION = {
766        FolderColumns._ID,
767        FolderColumns.PERSISTENT_ID,
768        FolderColumns.URI,
769        FolderColumns.NAME,
770        FolderColumns.HAS_CHILDREN,
771        FolderColumns.CAPABILITIES,
772        FolderColumns.SYNC_WINDOW,
773        FolderColumns.CONVERSATION_LIST_URI,
774        FolderColumns.CHILD_FOLDERS_LIST_URI,
775        FolderColumns.UNSEEN_COUNT,
776        FolderColumns.UNREAD_COUNT,
777        FolderColumns.TOTAL_COUNT,
778        FolderColumns.REFRESH_URI,
779        FolderColumns.SYNC_STATUS,
780        FolderColumns.LAST_SYNC_RESULT,
781        FolderColumns.TYPE,
782        FolderColumns.ICON_RES_ID,
783        FolderColumns.NOTIFICATION_ICON_RES_ID,
784        FolderColumns.BG_COLOR,
785        FolderColumns.FG_COLOR,
786        FolderColumns.LOAD_MORE_URI,
787        FolderColumns.HIERARCHICAL_DESC,
788        FolderColumns.LAST_MESSAGE_TIMESTAMP,
789        FolderColumns.PARENT_URI
790    };
791
792    public static final String[] FOLDERS_PROJECTION_WITH_UNREAD_SENDERS =
793            (new ImmutableList.Builder<String>()
794                    .addAll(ImmutableList.copyOf(FOLDERS_PROJECTION))
795                    .add(FolderColumns.UNREAD_SENDERS)
796                    .build().toArray(new String[0]));
797
798    public static final int FOLDER_ID_COLUMN = 0;
799    public static final int FOLDER_PERSISTENT_ID_COLUMN = 1;
800    public static final int FOLDER_URI_COLUMN = 2;
801    public static final int FOLDER_NAME_COLUMN = 3;
802    public static final int FOLDER_HAS_CHILDREN_COLUMN = 4;
803    public static final int FOLDER_CAPABILITIES_COLUMN = 5;
804    public static final int FOLDER_SYNC_WINDOW_COLUMN = 6;
805    public static final int FOLDER_CONVERSATION_LIST_URI_COLUMN = 7;
806    public static final int FOLDER_CHILD_FOLDERS_LIST_COLUMN = 8;
807    public static final int FOLDER_UNSEEN_COUNT_COLUMN = 9;
808    public static final int FOLDER_UNREAD_COUNT_COLUMN = 10;
809    public static final int FOLDER_TOTAL_COUNT_COLUMN = 11;
810    public static final int FOLDER_REFRESH_URI_COLUMN = 12;
811    public static final int FOLDER_SYNC_STATUS_COLUMN = 13;
812    public static final int FOLDER_LAST_SYNC_RESULT_COLUMN = 14;
813    public static final int FOLDER_TYPE_COLUMN = 15;
814    public static final int FOLDER_ICON_RES_ID_COLUMN = 16;
815    public static final int FOLDER_NOTIFICATION_ICON_RES_ID_COLUMN = 17;
816    public static final int FOLDER_BG_COLOR_COLUMN = 18;
817    public static final int FOLDER_FG_COLOR_COLUMN = 19;
818    public static final int FOLDER_LOAD_MORE_URI_COLUMN = 20;
819    public static final int FOLDER_HIERARCHICAL_DESC_COLUMN = 21;
820    public static final int FOLDER_LAST_MESSAGE_TIMESTAMP_COLUMN = 22;
821    public static final int FOLDER_PARENT_URI_COLUMN = 23;
822
823    public static final class FolderType {
824        /** A user defined label. */
825        public static final int DEFAULT = 1 << 0;
826        /** A system defined inbox */
827        public static final int INBOX = 1 << 1;
828        /** A system defined containing mails to be edited before sending. */
829        public static final int DRAFT = 1 << 2;
830        /** A system defined folder containing mails <b>to be</b> sent */
831        public static final int OUTBOX = 1 << 3;
832        /** A system defined folder containing sent mails */
833        public static final int SENT = 1 << 4;
834        /** A system defined trash folder */
835        public static final int TRASH = 1 << 5;
836        /** A system defined spam folder */
837        public static final int SPAM = 1 << 6;
838        /** A system defined starred folder */
839        public static final int STARRED = 1 << 7;
840        /** Any other system label that we do not have a specific name for. */
841        public static final int OTHER_PROVIDER_FOLDER = 1 << 8;
842        /** All mail folder */
843        public static final int ALL_MAIL = 1 << 9;
844        /** Gmail's inbox sections */
845        public static final int INBOX_SECTION = 1 << 10;
846        /** A system defined unread folder */
847        public static final int UNREAD = 1 << 11;
848        /** A "fake" search folder */
849        public static final int SEARCH = 1 << 12;
850    }
851
852    public static final class FolderCapabilities {
853        // FEEL FREE TO USE 0x0001, 0x0002, 0x0004
854        // was previously SYNCABLE, PARENT, CAN_HOLD_MAIL
855        // folders so we removed that value
856        public static final int CAN_ACCEPT_MOVED_MESSAGES = 0x0008;
857
858         /**
859         * For accounts that support archive, this will indicate that this folder supports
860         * the archive functionality.
861         */
862        public static final int ARCHIVE = 0x0010;
863
864        /**
865         * This will indicated that this folder supports the delete functionality.
866         */
867        public static final int DELETE = 0x0020;
868
869        /**
870         * For accounts that support report spam, this will indicate that this folder supports
871         * the report spam functionality.
872         */
873        public static final int REPORT_SPAM = 0x0040;
874
875        /**
876         * For accounts that support report spam, this will indicate that this folder supports
877         * the mark not spam functionality.
878         */
879        public static final int MARK_NOT_SPAM = 0x0080;
880
881        /**
882         * For accounts that support mute, this will indicate if a mute is performed from within
883         * this folder, the action is destructive.
884         */
885        public static final int DESTRUCTIVE_MUTE = 0x0100;
886
887        /**
888         * Indicates that a folder supports settings (sync lookback, etc.)
889         */
890        public static final int SUPPORTS_SETTINGS = 0x0200;
891
892        /**
893         * All the messages in this folder are important.
894         */
895        public static final int ONLY_IMPORTANT = 0x0400;
896
897        /**
898         * Deletions in this folder can't be undone (could include archive if desirable)
899         */
900        public static final int DELETE_ACTION_FINAL = 0x0800;
901
902        /**
903         * This folder is virtual, i.e. contains conversations potentially pulled from other
904         * folders, potentially even from different accounts.  Examples might be a "starred"
905         * folder, or an "unread" folder (per account or provider-wide)
906         */
907        public static final int IS_VIRTUAL = 0x1000;
908
909        /**
910         * For accounts that support report phishing, this will indicate that this folder supports
911         * the report phishing functionality.
912         */
913        public static final int REPORT_PHISHING = 0x2000;
914
915        /**
916         * The flag indicates that the user has the ability to move conversations
917         * from this folder.
918         */
919        public static final int ALLOWS_REMOVE_CONVERSATION = 0x4000;
920
921        /**
922         * The flag indicates that the user has the ability to move conversations to or from this
923         * Folder in the same operation as other Folder changes (usually through
924         * {@link com.android.mail.ui.MultiFoldersSelectionDialog}).
925         */
926        public static final int MULTI_MOVE = 0x8000;
927
928        /**
929         * This flag indicates that a conversation may be moved from this folder into the account's
930         * inbox.
931         */
932        public static final int ALLOWS_MOVE_TO_INBOX = 0x10000;
933
934        /**
935         * For folders that typically represent outgoing mail, this indicates the client should
936         * display recipients rather than the standard list of senders.
937         */
938        public static final int SHOW_RECIPIENTS = 0x20000;
939
940        /**
941         * We only want the icons of certain folders to be tinted with their
942         * {@link FolderColumns#BG_COLOR}, this indicates when we want that to happen.
943         */
944        public static final int TINT_ICON = 0x40000;
945
946        /**
947         * We want to only show unseen count and never unread count for some folders. This differs
948         * from {@link Folder#isUnreadCountHidden()} where the expected alternative is to show the
949         * total count of messages. Here we wish to show either unseen or nothing at all.
950         */
951        public static final int UNSEEN_COUNT_ONLY = 0x80000;
952    }
953
954    public static final class FolderColumns implements BaseColumns {
955        /**
956         * This string column contains an id for the folder that is constant across devices, or
957         * null if there is no constant id.
958         */
959        public static final String PERSISTENT_ID = "persistentId";
960        /**
961         * This string column contains the uri of the folder.
962         */
963        public static final String URI = "folderUri";
964        /**
965         * This string column contains the human visible name for the folder.
966         */
967        public static final String NAME = "name";
968        /**
969         * This int column represents the capabilities of the folder specified by
970         * FolderCapabilities flags.
971         */
972        public static final String CAPABILITIES = "capabilities";
973        /**
974         * This int column represents whether or not this folder has any
975         * child folders.
976         */
977        public static final String HAS_CHILDREN = "hasChildren";
978        /**
979         * This int column represents how large the sync window is.
980         */
981        public static final String SYNC_WINDOW = "syncWindow";
982        /**
983         * This string column contains the content provider uri to return the
984         * list of conversations for this folder.
985         */
986        public static final String CONVERSATION_LIST_URI = "conversationListUri";
987        /**
988         * This string column contains the content provider uri to return the
989         * list of child folders of this folder.
990         */
991        public static final String CHILD_FOLDERS_LIST_URI = "childFoldersListUri";
992        /**
993         * This int column contains the current unseen count for the folder, if known.
994         */
995        public static final String UNSEEN_COUNT = "unseenCount";
996        /**
997         * This int column contains the current unread count for the folder.
998         */
999        public static final String UNREAD_COUNT = "unreadCount";
1000
1001        public static final String TOTAL_COUNT = "totalCount";
1002        /**
1003         * This string column contains the content provider uri to force a
1004         * refresh of this folder.
1005         */
1006        public static final  String REFRESH_URI = "refreshUri";
1007        /**
1008         * This int column contains current sync status of the folder; some combination of the
1009         * SyncStatus bits defined above
1010         */
1011        public static final String SYNC_STATUS  = "syncStatus";
1012        /**
1013         * This int column contains the sync status of the last sync attempt; one of the
1014         * LastSyncStatus values defined above
1015         */
1016        public static final String LAST_SYNC_RESULT  = "lastSyncResult";
1017        /**
1018         * This int column contains the icon res id for this folder, or 0 if there is none.
1019         */
1020        public static final String ICON_RES_ID = "iconResId";
1021        /**
1022         * This int column contains the notification icon res id for this folder, or 0 if there is
1023         * none.
1024         */
1025        public static final String NOTIFICATION_ICON_RES_ID = "notificationIconResId";
1026        /**
1027         * This int column contains the type of the folder. Zero is default.
1028         */
1029        public static final String TYPE = "type";
1030        /**
1031         * String representing the integer background color associated with this
1032         * folder, or null.
1033         */
1034        public static final String BG_COLOR = "bgColor";
1035        /**
1036         * String representing the integer of the foreground color associated
1037         * with this folder, or null.
1038         */
1039        public static final String FG_COLOR = "fgColor";
1040        /**
1041         * String with the content provider Uri used to request more items in the folder, or null.
1042         */
1043        public static final String LOAD_MORE_URI = "loadMoreUri";
1044
1045        /**
1046         * Possibly empty string that describes the full hierarchy of a folder
1047         * along with its name.
1048         */
1049        public static final String HIERARCHICAL_DESC = "hierarchicalDesc";
1050
1051        /**
1052         * The timestamp of the last message received in this folder.
1053         */
1054        public static final String LAST_MESSAGE_TIMESTAMP = "lastMessageTimestamp";
1055
1056        /**
1057         * The URI, possibly null, of the parent folder.
1058         */
1059        public static final String PARENT_URI = "parentUri";
1060
1061        /**
1062         * A string of unread senders sorted by date, so we don't have to fetch this in multiple
1063         * queries
1064         */
1065        public static final String UNREAD_SENDERS = "unreadSenders";
1066
1067        public FolderColumns() {}
1068    }
1069
1070    // We define a "folder" as anything that contains a list of conversations.
1071    public static final String CONVERSATION_LIST_TYPE =
1072            "vnd.android.cursor.dir/vnd.com.android.mail.conversation";
1073    public static final String CONVERSATION_TYPE =
1074            "vnd.android.cursor.item/vnd.com.android.mail.conversation";
1075
1076
1077    public static final String[] CONVERSATION_PROJECTION = {
1078        BaseColumns._ID,
1079        ConversationColumns.URI,
1080        ConversationColumns.MESSAGE_LIST_URI,
1081        ConversationColumns.SUBJECT,
1082        ConversationColumns.SNIPPET,
1083        ConversationColumns.CONVERSATION_INFO,
1084        ConversationColumns.DATE_RECEIVED_MS,
1085        ConversationColumns.HAS_ATTACHMENTS,
1086        ConversationColumns.NUM_MESSAGES,
1087        ConversationColumns.NUM_DRAFTS,
1088        ConversationColumns.SENDING_STATE,
1089        ConversationColumns.PRIORITY,
1090        ConversationColumns.READ,
1091        ConversationColumns.SEEN,
1092        ConversationColumns.STARRED,
1093        ConversationColumns.RAW_FOLDERS,
1094        ConversationColumns.FLAGS,
1095        ConversationColumns.PERSONAL_LEVEL,
1096        ConversationColumns.SPAM,
1097        ConversationColumns.PHISHING,
1098        ConversationColumns.MUTED,
1099        ConversationColumns.COLOR,
1100        ConversationColumns.ACCOUNT_URI,
1101        ConversationColumns.SENDER_INFO,
1102        ConversationColumns.CONVERSATION_BASE_URI,
1103        ConversationColumns.REMOTE,
1104        ConversationColumns.ORDER_KEY
1105    };
1106
1107    /**
1108     * This integer corresponds to the number of rows of queries that specify the
1109     * {@link UIProvider#CONVERSATION_PROJECTION} projection will fit in a single
1110     * {@link android.database.CursorWindow}
1111     */
1112    public static final int CONVERSATION_PROJECTION_QUERY_CURSOR_WINDOW_LIMIT = 1500;
1113
1114    // These column indexes only work when the caller uses the
1115    // default CONVERSATION_PROJECTION defined above.
1116    public static final int CONVERSATION_ID_COLUMN = 0;
1117    public static final int CONVERSATION_URI_COLUMN = 1;
1118    public static final int CONVERSATION_MESSAGE_LIST_URI_COLUMN = 2;
1119    public static final int CONVERSATION_SUBJECT_COLUMN = 3;
1120    public static final int CONVERSATION_SNIPPET_COLUMN = 4;
1121    public static final int CONVERSATION_INFO_COLUMN = 5;
1122    public static final int CONVERSATION_DATE_RECEIVED_MS_COLUMN = 6;
1123    public static final int CONVERSATION_HAS_ATTACHMENTS_COLUMN = 7;
1124    public static final int CONVERSATION_NUM_MESSAGES_COLUMN = 8;
1125    public static final int CONVERSATION_NUM_DRAFTS_COLUMN = 9;
1126    public static final int CONVERSATION_SENDING_STATE_COLUMN = 10;
1127    public static final int CONVERSATION_PRIORITY_COLUMN = 11;
1128    public static final int CONVERSATION_READ_COLUMN = 12;
1129    public static final int CONVERSATION_SEEN_COLUMN = 13;
1130    public static final int CONVERSATION_STARRED_COLUMN = 14;
1131    public static final int CONVERSATION_RAW_FOLDERS_COLUMN = 15;
1132    public static final int CONVERSATION_FLAGS_COLUMN = 16;
1133    public static final int CONVERSATION_PERSONAL_LEVEL_COLUMN = 17;
1134    public static final int CONVERSATION_IS_SPAM_COLUMN = 18;
1135    public static final int CONVERSATION_IS_PHISHING_COLUMN = 19;
1136    public static final int CONVERSATION_MUTED_COLUMN = 20;
1137    public static final int CONVERSATION_COLOR_COLUMN = 21;
1138    public static final int CONVERSATION_ACCOUNT_URI_COLUMN = 22;
1139    public static final int CONVERSATION_SENDER_INFO_COLUMN = 23;
1140    public static final int CONVERSATION_BASE_URI_COLUMN = 24;
1141    public static final int CONVERSATION_REMOTE_COLUMN = 25;
1142    public static final int CONVERSATION_ORDER_KEY_COLUMN = 26;
1143
1144    public static final class ConversationSendingState {
1145        public static final int OTHER = 0;
1146        public static final int QUEUED = 1;
1147        public static final int SENDING = 2;
1148        public static final int SENT = 3;
1149        public static final int RETRYING = 4;
1150        public static final int SEND_ERROR = -1;
1151    }
1152
1153    public static final class ConversationPriority {
1154        public static final int DEFAULT = 0;
1155        public static final int IMPORTANT = 1;
1156        public static final int LOW = 0;
1157        public static final int HIGH = 1;
1158    }
1159
1160    public static final class ConversationPersonalLevel {
1161        public static final int NOT_TO_ME = 0;
1162        public static final int TO_ME_AND_OTHERS = 1;
1163        public static final int ONLY_TO_ME = 2;
1164    }
1165
1166    public static final class ConversationFlags {
1167        public static final int REPLIED = 1<<2;
1168        public static final int FORWARDED = 1<<3;
1169        public static final int CALENDAR_INVITE = 1<<4;
1170    }
1171
1172    public static final class ConversationPhishing {
1173        public static final int NOT_PHISHING = 0;
1174        public static final int PHISHING = 1;
1175    }
1176
1177    /**
1178     * Names of columns representing fields in a Conversation.
1179     */
1180    public static final class ConversationColumns {
1181        public static final String URI = "conversationUri";
1182        /**
1183         * This string column contains the content provider uri to return the
1184         * list of messages for this conversation.
1185         * The cursor returned by this query can return a {@link android.os.Bundle}
1186         * from a call to {@link android.database.Cursor#getExtras()}.  This Bundle may have
1187         * values with keys listed in {@link CursorExtraKeys}
1188         */
1189        public static final String MESSAGE_LIST_URI = "messageListUri";
1190        /**
1191         * This string column contains the subject string for a conversation.
1192         */
1193        public static final String SUBJECT = "subject";
1194        /**
1195         * This string column contains the snippet string for a conversation.
1196         */
1197        public static final String SNIPPET = "snippet";
1198        /**
1199         * @deprecated
1200         */
1201        @Deprecated
1202        public static final String SENDER_INFO = "senderInfo";
1203        /**
1204         * This blob column contains the byte-array representation of the Parceled
1205         * ConversationInfo object for a conversation.
1206         *
1207         * @deprecated providers should implement
1208         * {@link ConversationCursorCommand#COMMAND_GET_CONVERSATION_INFO} instead.
1209         */
1210        @Deprecated
1211        public static final String CONVERSATION_INFO = "conversationInfo";
1212        /**
1213         * This long column contains the time in ms of the latest update to a
1214         * conversation.
1215         */
1216        public static final String DATE_RECEIVED_MS = "dateReceivedMs";
1217
1218        /**
1219         * This boolean column contains whether any messages in this conversation
1220         * have attachments.
1221         */
1222        public static final String HAS_ATTACHMENTS = "hasAttachments";
1223
1224        /**
1225         * This int column contains the number of messages in this conversation.
1226         * For unthreaded, this will always be 1.
1227         */
1228        public static final String NUM_MESSAGES = "numMessages";
1229
1230        /**
1231         * This int column contains the number of drafts associated with this
1232         * conversation.
1233         */
1234        public static final String NUM_DRAFTS = "numDrafts";
1235
1236        /**
1237         * This int column contains the state of drafts and replies associated
1238         * with this conversation. Use ConversationSendingState to interpret
1239         * this field.
1240         */
1241        public static final String SENDING_STATE = "sendingState";
1242
1243        /**
1244         * This int column contains the priority of this conversation. Use
1245         * ConversationPriority to interpret this field.
1246         */
1247        public static final String PRIORITY = "priority";
1248
1249        /**
1250         * This int column indicates whether the conversation has been read
1251         */
1252        public static final String READ = "read";
1253
1254        /**
1255         * This int column indicates whether the conversation has been seen
1256         */
1257        public static final String SEEN = "seen";
1258
1259        /**
1260         * This int column indicates whether the conversation has been starred
1261         */
1262        public static final String STARRED = "starred";
1263
1264        /**
1265         * This blob column contains the marshalled form of a Parceled
1266         * {@FolderList} object. Ideally, only ever use this for
1267         * rendering the folder list for a conversation.
1268         *
1269         * @deprecated providers should implement
1270         * {@link ConversationCursorCommand#COMMAND_GET_RAW_FOLDERS} instead.
1271         */
1272        @Deprecated
1273        public static final String RAW_FOLDERS = "rawFolders";
1274        public static final String FLAGS = "conversationFlags";
1275        /**
1276         * This int column indicates the personal level of a conversation per
1277         * {@link ConversationPersonalLevel}.
1278         */
1279        public static final String PERSONAL_LEVEL = "personalLevel";
1280
1281        /**
1282         * This int column indicates whether the conversation is marked spam.
1283         */
1284        public static final String SPAM = "spam";
1285
1286        /**
1287         * This int column indicates whether the conversation is marked phishing.
1288         */
1289        public static final String PHISHING = "phishing";
1290
1291        /**
1292         * This int column indicates whether the conversation was muted.
1293         */
1294        public static final String MUTED = "muted";
1295
1296        /**
1297         * This int column contains a color for the conversation (used in Email only)
1298         */
1299        public static final String COLOR = "color";
1300
1301        /**
1302         * This String column contains the Uri for this conversation's account
1303         */
1304        public static final String ACCOUNT_URI = "accountUri";
1305        /**
1306         * This int column indicates whether a conversation is remote (non-local), and would require
1307         * a network fetch to load.
1308         */
1309        public static final String REMOTE = "remote";
1310        /**
1311         * This int column indicates whether the conversation was displayed on the UI and the
1312         * user got a chance to read it. The UI does not read this value, it is meant only to
1313         * write the status back to the provider. As a result, it is not available in the
1314         * {@link Conversation} object.
1315         */
1316        public static final String VIEWED = "viewed";
1317        /**
1318         * This String column contains the base uri for this conversation.  This uri can be used
1319         * when handling relative urls in the message content
1320         */
1321        public static final String CONVERSATION_BASE_URI = "conversationBaseUri";
1322
1323        /**
1324         * This long column contains the data that is used for ordering the result.
1325         */
1326        public static final String ORDER_KEY = "orderKey";
1327
1328        private ConversationColumns() {
1329        }
1330    }
1331
1332    public static final class ConversationCursorCommand {
1333
1334        public static final String COMMAND_RESPONSE_OK = "ok";
1335        public static final String COMMAND_RESPONSE_FAILED = "failed";
1336
1337        /**
1338         * Incoming bundles may include this key with an Integer bitfield value. See below for bit
1339         * values.
1340         */
1341        public static final String COMMAND_KEY_OPTIONS = "options";
1342
1343        /**
1344         * Clients must set this bit when the {@link Cursor#respond(Bundle)} call is being used to
1345         * fetch a {@link Parcelable}. It serves as a hint that this call requires the cursor
1346         * position to first safely be moved.
1347         */
1348        public static final int OPTION_MOVE_POSITION = 0x01;
1349
1350        /**
1351         * This bundle key has a boolean value: true to indicate that this cursor has been shown
1352         * to the user.
1353         * <p>
1354         * A provider that implements this command should include this key in its response with a
1355         * value of {@link #COMMAND_RESPONSE_OK} or {@link #COMMAND_RESPONSE_FAILED}.
1356         */
1357        public static final String COMMAND_KEY_SET_VISIBILITY = "setVisibility";
1358
1359        /**
1360         * This key has a boolean value: true to indicate that this folder list is shown to the user
1361         * either on first call (launcher/widget/notification) or after switching from an existing
1362         * folder: Inbox -> Folder. Repeated calls are sent when switching back to the folder. Inbox
1363         * -> Folder -> Spam -> Folder will generate two calls to respond() with the value true for
1364         * "Folder".
1365         * <p>
1366         * A provider that implements this command should include the
1367         * {@link #COMMAND_KEY_SET_VISIBILITY} key in its response with a value of
1368         * {@link #COMMAND_RESPONSE_OK} or {@link #COMMAND_RESPONSE_FAILED}. This is <b>always</b>
1369         * set with {@link #COMMAND_KEY_SET_VISIBILITY} because this is only set when the folder
1370         * list is made visible.
1371         */
1372        public static final String COMMAND_KEY_ENTERED_FOLDER = "enteredFolder";
1373
1374        /**
1375         * This key has an int value, indicating the position that the UI wants to notify the
1376         * provider that the data from a specified row is being shown to the user.
1377         * <p>
1378         * A provider that implements this command should include the
1379         * {@link #COMMAND_NOTIFY_CURSOR_UI_POSITION_CHANGE} key in its response with a value of
1380         * {@link #COMMAND_RESPONSE_OK} or {@link #COMMAND_RESPONSE_FAILED}.
1381         */
1382        public static final String COMMAND_NOTIFY_CURSOR_UI_POSITION_CHANGE = "uiPositionChange";
1383
1384        /**
1385         * Rather than jamming a {@link ConversationInfo} into a byte-array blob to be read out of
1386         * a cursor, providers can optionally implement this command to directly return the object
1387         * in a Bundle.
1388         * <p>
1389         * The requestor (UI code) will place a meaningless value in the request Bundle. The UI will
1390         * also move the cursor position to the desired place prior to calling respond(). Providers
1391         * should just use {@link Bundle#containsKey(String)} to check for this kind of request and
1392         * generate an object at the current cursor position.
1393         * <p>
1394         * A provider that implements this command should include the
1395         * {@link #COMMAND_GET_CONVERSATION_INFO} key in its response with a
1396         * {@link ConversationInfo} Parcelable object as its value.
1397         */
1398        public static final String COMMAND_GET_CONVERSATION_INFO =
1399                ConversationColumns.CONVERSATION_INFO;
1400
1401        /**
1402         * Rather than jamming a {@link FolderList} into a byte-array blob to be read out of
1403         * a cursor, providers can optionally implement this command to directly return the object
1404         * in a Bundle.
1405         * <p>
1406         * The requestor (UI code) will place a meaningless value in the request Bundle. The UI will
1407         * also move the cursor position to the desired place prior to calling respond(). Providers
1408         * should just use {@link Bundle#containsKey(String)} to check for this kind of request and
1409         * generate an object at the current cursor position.
1410         * <p>
1411         * A provider that implements this command should include the
1412         * {@link #COMMAND_GET_RAW_FOLDERS} key in its response with a
1413         * {@link FolderList} Parcelable object as its value.
1414         */
1415        public static final String COMMAND_GET_RAW_FOLDERS = ConversationColumns.RAW_FOLDERS;
1416
1417        private ConversationCursorCommand() {}
1418    }
1419
1420    /**
1421     * List of operations that can can be performed on a conversation. These operations are applied
1422     * with {@link ContentProvider#update(Uri, ContentValues, String, String[])}
1423     * where the conversation uri is specified, and the ContentValues specifies the operation to
1424     * be performed.
1425     * <p/>
1426     * The operation to be performed is specified in the ContentValues by
1427     * the {@link ConversationOperations#OPERATION_KEY}
1428     * <p/>
1429     * Note not all UI providers will support these operations.  {@link AccountCapabilities} can
1430     * be used to determine which operations are supported.
1431     */
1432    public static final class ConversationOperations {
1433        /**
1434         * ContentValues key used to specify the operation to be performed
1435         */
1436        public static final String OPERATION_KEY = "operation";
1437
1438        /**
1439         * Archive operation
1440         */
1441        public static final String ARCHIVE = "archive";
1442
1443        /**
1444         * Mute operation
1445         */
1446        public static final String MUTE = "mute";
1447
1448        /**
1449         * Report spam operation
1450         */
1451        public static final String REPORT_SPAM = "report_spam";
1452
1453        /**
1454         * Report not spam operation
1455         */
1456        public static final String REPORT_NOT_SPAM = "report_not_spam";
1457
1458        /**
1459         * Report phishing operation
1460         */
1461        public static final String REPORT_PHISHING = "report_phishing";
1462
1463        /**
1464         * Discard drafts operation
1465         */
1466        public static final String DISCARD_DRAFTS = "discard_drafts";
1467
1468        /**
1469         * Move all failed messages into drafts operation
1470         */
1471        public static final String MOVE_FAILED_TO_DRAFTS = "move_failed_to_drafts";
1472
1473        /**
1474         * Update conversation folder(s) operation. ContentValues passed as part
1475         * of this update will be of the format (FOLDERS_UPDATED, csv of updated
1476         * folders) where the comma separated values of the updated folders will
1477         * be of the format: folderuri/ADD_VALUE. ADD_VALUE will be true if the
1478         * folder was added, false if it was removed.
1479         */
1480        public static final String FOLDERS_UPDATED = "folders_updated";
1481        public static final String FOLDERS_UPDATED_SPLIT_PATTERN = ",";
1482
1483        public static final class Parameters {
1484            /**
1485             * Boolean indicating whether the undo for this operation should be suppressed
1486             */
1487            public static final String SUPPRESS_UNDO = "suppress_undo";
1488
1489            private Parameters() {}
1490        }
1491
1492        private ConversationOperations() {
1493        }
1494    }
1495
1496    /**
1497     * Methods that can be "called" using the account uri, through
1498     * {@link android.content.ContentResolver#call(Uri,String,String,Bundle)}
1499     * Note, the arg parmateter of call should be the account uri.
1500     */
1501    public static final class AccountCallMethods {
1502        /**
1503         * Save message method.  The Bundle for the call to
1504         * {@link android.content.ContentResolver#call(Uri,String,String,Bundle)} should have the
1505         * columns specified in {@link MessageColumns}, and if this is a save for an existing
1506         * message, an entry for the {@link MessageColumns#URI} should reference the existing
1507         * message
1508         *
1509         * The Bundle returned will contain the message uri in the returned bundled with the
1510         * {@link MessageColumns#URI} key.
1511         */
1512        public static final String SAVE_MESSAGE = "save_message";
1513
1514        /**
1515         * Send message method.  The Bundle for the call to
1516         * {@link android.content.ContentResolver#call(Uri,String,String,Bundle)} should have the
1517         * columns specified in {@link MessageColumns}, and if this is a send of an existing
1518         * message, an entry for the {@link MessageColumns#URI} should reference the existing
1519         * message
1520         *
1521         * The Bundle returned will contain the message uri in the returned bundled with the
1522         * {@link MessageColumns#URI} key.
1523         */
1524        public static final String SEND_MESSAGE = "send_message";
1525
1526        /**
1527         * Change account method.  The Bundle for the call to
1528         * {@link android.content.ContentResolver#call(Uri,String,String,Bundle)} should have the
1529         * columns specified in {@link SetCurrentAccountColumns}
1530         *
1531         * The Bundle returned will be empty.
1532         */
1533        public static final String SET_CURRENT_ACCOUNT = "set_current_account";
1534
1535        private AccountCallMethods() {}
1536    }
1537
1538    /**
1539     * Keys used for parameters to {@link AccountCallMethods#SEND_MESSAGE} or
1540     * {@link AccountCallMethods#SAVE_MESSAGE} methods.
1541     */
1542    public static final class SendOrSaveMethodParamKeys {
1543        /**
1544         * Bundle key used to store any opened file descriptors.
1545         * The keys of this Bundle are the contentUri for each attachment, and the
1546         * values are {@link android.os.ParcelFileDescriptor} objects.
1547         */
1548        public static final String OPENED_FD_MAP = "opened_fds";
1549
1550        private SendOrSaveMethodParamKeys() {}
1551    }
1552
1553    public static final class DraftType {
1554        public static final int NOT_A_DRAFT = 0;
1555        public static final int COMPOSE = 1;
1556        public static final int REPLY = 2;
1557        public static final int REPLY_ALL = 3;
1558        public static final int FORWARD = 4;
1559
1560        private DraftType() {}
1561    }
1562
1563    /**
1564     * Class for the enum values to determine whether this
1565     * string should be displayed as a high priority warning
1566     * or a low priority warning. The current design has
1567     * high priority warnings in red while low priority warnings
1568     * are grey.
1569     */
1570    public static final class SpamWarningLevel {
1571        public static final int NO_WARNING = 0;
1572        public static final int LOW_WARNING = 1;
1573        public static final int HIGH_WARNING = 2;
1574
1575        private SpamWarningLevel() {}
1576    }
1577
1578    /**
1579     * Class for the enum values to determine which type
1580     * of link to show in the spam warning.
1581     */
1582    public static final class SpamWarningLinkType {
1583        public static final int NO_LINK = 0;
1584        public static final int IGNORE_WARNING = 1;
1585        public static final int REPORT_PHISHING = 2;
1586
1587        private SpamWarningLinkType() {}
1588    }
1589
1590    public static final String[] MESSAGE_PROJECTION = {
1591        BaseColumns._ID,
1592        MessageColumns.SERVER_ID,
1593        MessageColumns.URI,
1594        MessageColumns.CONVERSATION_ID,
1595        MessageColumns.SUBJECT,
1596        MessageColumns.SNIPPET,
1597        MessageColumns.FROM,
1598        MessageColumns.TO,
1599        MessageColumns.CC,
1600        MessageColumns.BCC,
1601        MessageColumns.REPLY_TO,
1602        MessageColumns.DATE_RECEIVED_MS,
1603        MessageColumns.BODY_HTML,
1604        MessageColumns.BODY_TEXT,
1605        MessageColumns.EMBEDS_EXTERNAL_RESOURCES,
1606        MessageColumns.REF_MESSAGE_ID,
1607        MessageColumns.DRAFT_TYPE,
1608        MessageColumns.APPEND_REF_MESSAGE_CONTENT,
1609        MessageColumns.HAS_ATTACHMENTS,
1610        MessageColumns.ATTACHMENT_LIST_URI,
1611        MessageColumns.ATTACHMENT_BY_CID_URI,
1612        MessageColumns.MESSAGE_FLAGS,
1613        MessageColumns.ALWAYS_SHOW_IMAGES,
1614        MessageColumns.READ,
1615        MessageColumns.SEEN,
1616        MessageColumns.STARRED,
1617        MessageColumns.QUOTE_START_POS,
1618        MessageColumns.ATTACHMENTS,
1619        MessageColumns.CUSTOM_FROM_ADDRESS,
1620        MessageColumns.MESSAGE_ACCOUNT_URI,
1621        MessageColumns.EVENT_INTENT_URI,
1622        MessageColumns.SPAM_WARNING_STRING,
1623        MessageColumns.SPAM_WARNING_LEVEL,
1624        MessageColumns.SPAM_WARNING_LINK_TYPE,
1625        MessageColumns.VIA_DOMAIN,
1626        MessageColumns.SENDING_STATE,
1627        MessageColumns.CLIPPED,
1628        MessageColumns.PERMALINK
1629    };
1630
1631    /** Separates attachment info parts in strings in a message. */
1632    @Deprecated
1633    public static final String MESSAGE_ATTACHMENT_INFO_SEPARATOR = "\n";
1634    public static final String MESSAGE_LIST_TYPE =
1635            "vnd.android.cursor.dir/vnd.com.android.mail.message";
1636    public static final String MESSAGE_TYPE =
1637            "vnd.android.cursor.item/vnd.com.android.mail.message";
1638
1639    public static final int MESSAGE_ID_COLUMN = 0;
1640    public static final int MESSAGE_SERVER_ID_COLUMN = 1;
1641    public static final int MESSAGE_URI_COLUMN = 2;
1642    public static final int MESSAGE_CONVERSATION_URI_COLUMN = 3;
1643    public static final int MESSAGE_SUBJECT_COLUMN = 4;
1644    public static final int MESSAGE_SNIPPET_COLUMN = 5;
1645    public static final int MESSAGE_FROM_COLUMN = 6;
1646    public static final int MESSAGE_TO_COLUMN = 7;
1647    public static final int MESSAGE_CC_COLUMN = 8;
1648    public static final int MESSAGE_BCC_COLUMN = 9;
1649    public static final int MESSAGE_REPLY_TO_COLUMN = 10;
1650    public static final int MESSAGE_DATE_RECEIVED_MS_COLUMN = 11;
1651    public static final int MESSAGE_BODY_HTML_COLUMN = 12;
1652    public static final int MESSAGE_BODY_TEXT_COLUMN = 13;
1653    public static final int MESSAGE_EMBEDS_EXTERNAL_RESOURCES_COLUMN = 14;
1654    public static final int MESSAGE_REF_MESSAGE_URI_COLUMN = 15;
1655    public static final int MESSAGE_DRAFT_TYPE_COLUMN = 16;
1656    public static final int MESSAGE_APPEND_REF_MESSAGE_CONTENT_COLUMN = 17;
1657    public static final int MESSAGE_HAS_ATTACHMENTS_COLUMN = 18;
1658    public static final int MESSAGE_ATTACHMENT_LIST_URI_COLUMN = 19;
1659    public static final int MESSAGE_ATTACHMENT_BY_CID_URI_COLUMN = 20;
1660    public static final int MESSAGE_FLAGS_COLUMN = 21;
1661    public static final int MESSAGE_ALWAYS_SHOW_IMAGES_COLUMN = 22;
1662    public static final int MESSAGE_READ_COLUMN = 23;
1663    public static final int MESSAGE_SEEN_COLUMN = 24;
1664    public static final int MESSAGE_STARRED_COLUMN = 25;
1665    public static final int QUOTED_TEXT_OFFSET_COLUMN = 26;
1666    public static final int MESSAGE_ATTACHMENTS_COLUMN = 27;
1667    public static final int MESSAGE_CUSTOM_FROM_ADDRESS_COLUMN = 28;
1668    public static final int MESSAGE_ACCOUNT_URI_COLUMN = 29;
1669    public static final int MESSAGE_EVENT_INTENT_COLUMN = 30;
1670    public static final int MESSAGE_SPAM_WARNING_STRING_ID_COLUMN = 31;
1671    public static final int MESSAGE_SPAM_WARNING_LEVEL_COLUMN = 32;
1672    public static final int MESSAGE_SPAM_WARNING_LINK_TYPE_COLUMN = 33;
1673    public static final int MESSAGE_VIA_DOMAIN_COLUMN = 34;
1674    public static final int MESSAGE_SENDING_STATE_COLUMN = 35;
1675    public static final int MESSAGE_CLIPPED_COLUMN = 36;
1676    public static final int MESSAGE_PERMALINK_COLUMN = 37;
1677
1678    public static final class CursorStatus {
1679        // The cursor is actively loading more data
1680        public static final int LOADING =      1 << 0;
1681
1682        // The cursor is currently not loading more data, but more data may be available
1683        public static final int LOADED =       1 << 1;
1684
1685        // An error occured while loading data
1686        public static final int ERROR =        1 << 2;
1687
1688        // The cursor is loaded, and there will be no more data
1689        public static final int COMPLETE =     1 << 3;
1690
1691        public static boolean isWaitingForResults(int cursorStatus) {
1692            return 0 != (cursorStatus & LOADING);
1693        }
1694    }
1695
1696
1697    public static final class CursorExtraKeys {
1698        /**
1699         * This integer column contains the staus of the message cursor.  The value will be
1700         * one defined in {@link CursorStatus}.
1701         */
1702        public static final String EXTRA_STATUS = "cursor_status";
1703
1704        /**
1705         * Used for finding the cause of an error.
1706         * TODO: define these values
1707         */
1708        public static final String EXTRA_ERROR = "cursor_error";
1709
1710
1711        /**
1712         * This integer column contains the total message count for this folder.
1713         */
1714        public static final String EXTRA_TOTAL_COUNT = "cursor_total_count";
1715    }
1716
1717    public static final class AccountCursorExtraKeys {
1718        /**
1719         * This integer column contains the staus of the account cursor.  The value will be
1720         * 1 if all accounts have been fully loaded or 0 if the account list hasn't been fully
1721         * initialized
1722         */
1723        public static final String ACCOUNTS_LOADED = "accounts_loaded";
1724    }
1725
1726
1727    public static final class MessageFlags {
1728        public static final int REPLIED =           1 << 2;
1729        public static final int FORWARDED =         1 << 3;
1730        public static final int CALENDAR_INVITE =   1 << 4;
1731    }
1732
1733    public static final class MessageColumns {
1734        /**
1735         * This string column contains a content provider URI that points to this single message.
1736         */
1737        public static final String URI = "messageUri";
1738        /**
1739         * This string column contains a server-assigned ID for this message.
1740         */
1741        public static final String SERVER_ID = "serverMessageId";
1742        public static final String CONVERSATION_ID = "conversationId";
1743        /**
1744         * This string column contains the subject of a message.
1745         */
1746        public static final String SUBJECT = "subject";
1747        /**
1748         * This string column contains a snippet of the message body.
1749         */
1750        public static final String SNIPPET = "snippet";
1751        /**
1752         * This string column contains the single email address (and optionally name) of the sender.
1753         */
1754        public static final String FROM = "fromAddress";
1755        /**
1756         * This string column contains a comma-delimited list of "To:" recipient email addresses.
1757         */
1758        public static final String TO = "toAddresses";
1759        /**
1760         * This string column contains a comma-delimited list of "CC:" recipient email addresses.
1761         */
1762        public static final String CC = "ccAddresses";
1763        /**
1764         * This string column contains a comma-delimited list of "BCC:" recipient email addresses.
1765         * This value will be null for incoming messages.
1766         */
1767        public static final String BCC = "bccAddresses";
1768        /**
1769         * This string column contains the single email address (and optionally name) of the
1770         * sender's reply-to address.
1771         */
1772        public static final String REPLY_TO = "replyToAddress";
1773        /**
1774         * This long column contains the timestamp (in millis) of receipt of the message.
1775         */
1776        public static final String DATE_RECEIVED_MS = "dateReceivedMs";
1777        /**
1778         * This string column contains the HTML form of the message body, if available. If not,
1779         * a provider must populate BODY_TEXT.
1780         */
1781        public static final String BODY_HTML = "bodyHtml";
1782        /**
1783         * This string column contains the plaintext form of the message body, if HTML is not
1784         * otherwise available. If HTML is available, this value should be left empty (null).
1785         */
1786        public static final String BODY_TEXT = "bodyText";
1787        public static final String EMBEDS_EXTERNAL_RESOURCES = "bodyEmbedsExternalResources";
1788        /**
1789         * This string column contains an opaque string used by the sendMessage api.
1790         */
1791        public static final String REF_MESSAGE_ID = "refMessageId";
1792        /**
1793         * This integer column contains the type of this draft, or zero (0) if this message is not a
1794         * draft. See {@link DraftType} for possible values.
1795         */
1796        public static final String DRAFT_TYPE = "draftType";
1797        /**
1798         * This boolean column indicates whether an outgoing message should trigger special quoted
1799         * text processing upon send. The value should default to zero (0) for protocols that do
1800         * not support or require this flag, and for all incoming messages.
1801         */
1802        public static final String APPEND_REF_MESSAGE_CONTENT = "appendRefMessageContent";
1803        /**
1804         * This boolean column indicates whether a message has attachments. The list of attachments
1805         * can be retrieved using the URI in {@link MessageColumns#ATTACHMENT_LIST_URI}.
1806         */
1807        public static final String HAS_ATTACHMENTS = "hasAttachments";
1808        /**
1809         * This string column contains the content provider URI for the list of
1810         * attachments associated with this message.<br>
1811         * <br>
1812         * The resulting cursor MUST have the columns as defined in
1813         * {@link com.android.ex.photo.provider.PhotoContract.PhotoViewColumns}.
1814         */
1815        public static final String ATTACHMENT_LIST_URI = "attachmentListUri";
1816        /**
1817         * This string column contains the content provider URI for the details of an attachment
1818         * associated with this message. (CID to be appended at the time the URI is used)
1819         */
1820        public static final String ATTACHMENT_BY_CID_URI = "attachmentByCidUri";
1821        /**
1822         * This long column is a bit field of flags defined in {@link MessageFlags}.
1823         */
1824        public static final String MESSAGE_FLAGS = "messageFlags";
1825        /**
1826         * This integer column represents whether the user has specified that images should always
1827         * be shown.  The value of "1" indicates that the user has specified that images should be
1828         * shown, while the value of "0" indicates that the user should be prompted before loading
1829         * any external images.
1830         */
1831        public static final String ALWAYS_SHOW_IMAGES = "alwaysShowImages";
1832
1833        /**
1834         * This boolean column indicates whether the message has been read
1835         */
1836        public static final String READ = "read";
1837
1838        /**
1839         * This boolean column indicates whether the message has been seen
1840         */
1841        public static final String SEEN = "seen";
1842
1843        /**
1844         * This boolean column indicates whether the message has been starred
1845         */
1846        public static final String STARRED = "starred";
1847
1848        /**
1849         * This integer column represents the offset in the message of quoted
1850         * text. If include_quoted_text is zero, the value contained in this
1851         * column is invalid.
1852         */
1853        public static final String QUOTE_START_POS = "quotedTextStartPos";
1854
1855        /**
1856         * This string columns contains a JSON array of serialized {@link Attachment} objects.
1857         */
1858        public static final String ATTACHMENTS = "attachments";
1859        public static final String CUSTOM_FROM_ADDRESS = "customFrom";
1860        /**
1861         * Uri of the account associated with this message. Except in the case
1862         * of showing a combined view, this column is almost always empty.
1863         */
1864        public static final String MESSAGE_ACCOUNT_URI = "messageAccountUri";
1865        /**
1866         * Intent Uri to launch when the user wants to view an event in their calendar, or null.
1867         */
1868        public static final String EVENT_INTENT_URI = "eventIntentUri";
1869        /**
1870         * This string column contains the string for the spam
1871         * warning of this message, or null if there is no spam warning for the message.
1872         */
1873        public static final String SPAM_WARNING_STRING = "spamWarningString";
1874        /**
1875         * This integer column contains the level of spam warning of this message,
1876         * or zero (0) if this message does not have a warning level.
1877         * See {@link SpamWarningLevel} for possible values.
1878         */
1879        public static final String SPAM_WARNING_LEVEL = "spamWarningLevel";
1880        /**
1881         * This integer column contains the type of link for the spam warning
1882         * of this message, or zero (0) if this message does not have a link type.
1883         * See {@link SpamWarningLinkType} for possible values.
1884         */
1885        public static final String SPAM_WARNING_LINK_TYPE = "spamWarningLinkType";
1886        /**
1887         * This string column contains the string for the via domain
1888         * to be included if this message was sent via an alternate
1889         * domain. This column should be null if no via domain exists.
1890         */
1891        public static final String VIA_DOMAIN = "viaDomain";
1892        /**
1893         * This int column indicates whether the message is an outgoing message in the process
1894         * of being sent. See {@link com.android.mail.providers.UIProvider.ConversationSendingState}
1895         */
1896        public static final String SENDING_STATE = "sendingState";
1897        /**
1898         * This boolean column indicates whether the message body has been clipped.
1899         */
1900        public static final String CLIPPED = "clipped";
1901        /**
1902         * This string column contains the permalink value of the conversation
1903         * for which this message belongs or null if one does not exist.
1904         */
1905        public static final String PERMALINK = "permalink";
1906
1907        private MessageColumns() {}
1908    }
1909
1910     public static final class SetCurrentAccountColumns {
1911        /**
1912         * This column contains the Account object Parcelable.
1913         */
1914        public static final String ACCOUNT = "account";
1915
1916        private SetCurrentAccountColumns() {}
1917    }
1918
1919    /**
1920     * List of operations that can can be performed on a message. These operations are applied
1921     * with {@link ContentProvider#update(Uri, ContentValues, String, String[])}
1922     * where the message uri is specified, and the ContentValues specifies the operation to
1923     * be performed, e.g. values.put(RESPOND_COLUMN, RESPOND_ACCEPT)
1924     * <p/>
1925     * Note not all UI providers will support these operations.
1926     */
1927    public static final class MessageOperations {
1928        /**
1929         * Respond to a calendar invitation
1930         */
1931        public static final String RESPOND_COLUMN = "respond";
1932
1933        public static final int RESPOND_ACCEPT = 1;
1934        public static final int RESPOND_TENTATIVE = 2;
1935        public static final int RESPOND_DECLINE = 3;
1936
1937        private MessageOperations() {
1938        }
1939    }
1940
1941    public static final String ATTACHMENT_LIST_TYPE =
1942            "vnd.android.cursor.dir/vnd.com.android.mail.attachment";
1943    public static final String ATTACHMENT_TYPE =
1944            "vnd.android.cursor.item/vnd.com.android.mail.attachment";
1945
1946    public static final String[] ATTACHMENT_PROJECTION = {
1947        AttachmentColumns.NAME,
1948        AttachmentColumns.SIZE,
1949        AttachmentColumns.URI,
1950        AttachmentColumns.CONTENT_TYPE,
1951        AttachmentColumns.STATE,
1952        AttachmentColumns.DESTINATION,
1953        AttachmentColumns.DOWNLOADED_SIZE,
1954        AttachmentColumns.CONTENT_URI,
1955        AttachmentColumns.THUMBNAIL_URI,
1956        AttachmentColumns.PREVIEW_INTENT_URI,
1957        AttachmentColumns.PROVIDER_DATA,
1958        AttachmentColumns.SUPPORTS_DOWNLOAD_AGAIN,
1959        AttachmentColumns.TYPE,
1960        AttachmentColumns.FLAGS,
1961        AttachmentColumns.CONTENT_ID
1962    };
1963    public static final int ATTACHMENT_NAME_COLUMN = 0;
1964    public static final int ATTACHMENT_SIZE_COLUMN = 1;
1965    public static final int ATTACHMENT_URI_COLUMN = 2;
1966    public static final int ATTACHMENT_CONTENT_TYPE_COLUMN = 3;
1967    public static final int ATTACHMENT_STATE_COLUMN = 4;
1968    public static final int ATTACHMENT_DESTINATION_COLUMN = 5;
1969    public static final int ATTACHMENT_DOWNLOADED_SIZE_COLUMN = 6;
1970    public static final int ATTACHMENT_CONTENT_URI_COLUMN = 7;
1971    public static final int ATTACHMENT_THUMBNAIL_URI_COLUMN = 8;
1972    public static final int ATTACHMENT_PREVIEW_INTENT_COLUMN = 9;
1973    public static final int ATTACHMENT_SUPPORTS_DOWNLOAD_AGAIN_COLUMN = 10;
1974    public static final int ATTACHMENT_TYPE_COLUMN = 11;
1975    public static final int ATTACHMENT_FLAGS_COLUMN = 12;
1976    public static final int ATTACHMENT_CONTENT_ID_COLUMN = 13;
1977
1978    /** Separates attachment info parts in strings in the database. */
1979    public static final String ATTACHMENT_INFO_SEPARATOR = "\n"; // use to join
1980    public static final Pattern ATTACHMENT_INFO_SEPARATOR_PATTERN =
1981            Pattern.compile(ATTACHMENT_INFO_SEPARATOR); // use to split
1982    public static final String ATTACHMENT_INFO_DELIMITER = "|"; // use to join
1983    // use to split
1984    public static final Pattern ATTACHMENT_INFO_DELIMITER_PATTERN = Pattern.compile("\\|");
1985
1986    /**
1987     * Valid states for the {@link AttachmentColumns#STATE} column.
1988     *
1989     */
1990    public static final class AttachmentState {
1991        /**
1992         * The full attachment is not present on device. When used as a command,
1993         * setting this state will tell the provider to cancel a download in
1994         * progress.
1995         * <p>
1996         * Valid next states: {@link #DOWNLOADING}, {@link #PAUSED}
1997         */
1998        public static final int NOT_SAVED = 0;
1999        /**
2000         * The most recent attachment download attempt failed. The current UI
2001         * design does not require providers to persist this state, but
2002         * providers must return this state at least once after a download
2003         * failure occurs. This state may not be used as a command.
2004         * <p>
2005         * Valid next states: {@link #DOWNLOADING}
2006         */
2007        public static final int FAILED = 1;
2008        /**
2009         * The attachment is currently being downloaded by the provider.
2010         * {@link AttachmentColumns#DOWNLOADED_SIZE} should reflect the current
2011         * download progress while in this state. When used as a command,
2012         * setting this state will tell the provider to initiate a download to
2013         * the accompanying destination in {@link AttachmentColumns#DESTINATION}
2014         * .
2015         * <p>
2016         * Valid next states: {@link #NOT_SAVED}, {@link #FAILED},
2017         * {@link #SAVED}
2018         */
2019        public static final int DOWNLOADING = 2;
2020        /**
2021         * The attachment was successfully downloaded to the destination in
2022         * {@link AttachmentColumns#DESTINATION}. If a provider later detects
2023         * that a download is missing, it should reset the state to
2024         * {@link #NOT_SAVED}. This state may not be used as a command on its
2025         * own. To move a file from cache to external, update
2026         * {@link AttachmentColumns#DESTINATION}.
2027         * <p>
2028         * Valid next states: {@link #NOT_SAVED}, {@link #PAUSED}
2029         */
2030        public static final int SAVED = 3;
2031        /**
2032         * This is only used as a command, not as a state. The attachment is
2033         * currently being redownloaded by the provider.
2034         * {@link AttachmentColumns#DOWNLOADED_SIZE} should reflect the current
2035         * download progress while in this state. When used as a command,
2036         * setting this state will tell the provider to initiate a download to
2037         * the accompanying destination in {@link AttachmentColumns#DESTINATION}
2038         * .
2039         */
2040        public static final int REDOWNLOADING = 4;
2041        /**
2042         * The attachment is either pending or paused in the download manager.
2043         * {@link AttachmentColumns#DOWNLOADED_SIZE} should reflect the current
2044         * download progress while in this state. This state may not be used as
2045         * a command on its own.
2046         * <p>
2047         * Valid next states: {@link #DOWNLOADING}, {@link #FAILED}
2048         */
2049        public static final int PAUSED = 5;
2050
2051        private AttachmentState() {}
2052    }
2053
2054    public static final class AttachmentDestination {
2055
2056        /**
2057         * The attachment will be or is already saved to the app-private cache partition.
2058         */
2059        public static final int CACHE = 0;
2060        /**
2061         * The attachment will be or is already saved to external shared device storage.
2062         * This value should be 1 since saveToSd is often used in a similar way
2063         */
2064        public static final int EXTERNAL = 1;
2065
2066        private AttachmentDestination() {}
2067    }
2068
2069    public static final class AttachmentColumns {
2070        /**
2071         * This string column is the attachment's file name, intended for display in UI. It is not
2072         * the full path of the file.
2073         */
2074        public static final String NAME = OpenableColumns.DISPLAY_NAME;
2075        /**
2076         * This integer column is the file size of the attachment, in bytes.
2077         */
2078        public static final String SIZE = OpenableColumns.SIZE;
2079        /**
2080         * This column is a {@link android.net.Uri} that can be queried to
2081         * monitor download state and progress for this individual attachment
2082         * (resulting cursor has one single row for this attachment).
2083         */
2084        public static final String URI = "uri";
2085        /**
2086         * This string column is the MIME type of the attachment.
2087         */
2088        public static final String CONTENT_TYPE = "contentType";
2089        /**
2090         * This integer column is the current downloading state of the
2091         * attachment as defined in {@link AttachmentState}.
2092         * <p>
2093         * Providers must accept updates to {@link #URI} with new values of
2094         * this column to initiate or cancel downloads.
2095         */
2096        public static final String STATE = "state";
2097        /**
2098         * This integer column is the file destination for the current download
2099         * in progress (when {@link #STATE} is
2100         * {@link AttachmentState#DOWNLOADING}) or the resulting downloaded file
2101         * ( when {@link #STATE} is {@link AttachmentState#SAVED}), as defined
2102         * in {@link AttachmentDestination}. This value is undefined in any
2103         * other state.
2104         * <p>
2105         * Providers must accept updates to {@link #URI} with new values of
2106         * this column to move an existing downloaded file.
2107         */
2108        public static final String DESTINATION = "destination";
2109        /**
2110         * This integer column is the current number of bytes downloaded when
2111         * {@link #STATE} is {@link AttachmentState#DOWNLOADING}. This value is
2112         * undefined in any other state.
2113         */
2114        public static final String DOWNLOADED_SIZE = "downloadedSize";
2115        /**
2116         * This column is a {@link android.net.Uri} that points to the
2117         * downloaded local file when {@link #STATE} is
2118         * {@link AttachmentState#SAVED}. This value is undefined in any other
2119         * state.
2120         */
2121        public static final String CONTENT_URI = "contentUri";
2122        /**
2123         * This column is a {@link android.net.Uri} that points to a local
2124         * thumbnail file for the attachment. Providers that do not support
2125         * downloading attachment thumbnails may leave this null.
2126         */
2127        public static final String THUMBNAIL_URI = "thumbnailUri";
2128        /**
2129         * This column is an {@link android.net.Uri} used in an
2130         * {@link android.content.Intent#ACTION_VIEW} Intent to launch a preview
2131         * activity that allows the user to efficiently view an attachment
2132         * without having to first download the entire file. Providers that do
2133         * not support previewing attachments may leave this null.
2134         */
2135        public static final String PREVIEW_INTENT_URI = "previewIntentUri";
2136        /**
2137         * This column contains provider-specific private data as JSON string.
2138         */
2139        public static final String PROVIDER_DATA = "providerData";
2140
2141        /**
2142         * This column represents whether this attachment supports the ability to be downloaded
2143         * again.
2144         */
2145        public static final String SUPPORTS_DOWNLOAD_AGAIN = "supportsDownloadAgain";
2146        /**
2147         * This column represents the visibility type of this attachment. One of the
2148         * {@link AttachmentType} constants.
2149         */
2150        public static final String TYPE = "type";
2151
2152        /**
2153         * This column holds various bitwise flags for status information.
2154         */
2155        public static final String FLAGS = "flags";
2156
2157        /**
2158         * This column holds the RFC 2392 content id of the email part for this attachment, if
2159         * possible; otherwise it holds an identifier unique to the parent message.
2160         */
2161        public static final String CONTENT_ID = "contentId";
2162
2163        private AttachmentColumns() {}
2164    }
2165
2166    public static final class AttachmentContentValueKeys {
2167        public static final String RENDITION = "rendition";
2168        public static final String ADDITIONAL_PRIORITY = "additionalPriority";
2169        public static final String DELAY_DOWNLOAD = "delayDownload";
2170    }
2171
2172    /**
2173     * Indicates a version of an attachment.
2174     */
2175    public static final class AttachmentRendition {
2176
2177        /** A smaller or simpler version of the attachment, such as a scaled-down image or an HTML
2178         * version of a document. Not always available.
2179         */
2180        public static final int SIMPLE = 0;
2181        /**
2182         * The full version of an attachment if it can be handled on the device, otherwise the
2183         * preview.
2184         */
2185        public static final int BEST = 1;
2186
2187        private static final String SIMPLE_STRING = "SIMPLE";
2188        private static final String BEST_STRING = "BEST";
2189
2190        /**
2191         * Prefer renditions in this order.
2192         */
2193        public static final int[] PREFERRED_RENDITIONS = new int[]{BEST, SIMPLE};
2194
2195        public static int parseRendition(String rendition) {
2196            if (TextUtils.equals(rendition, SIMPLE_STRING)) {
2197                return SIMPLE;
2198            } else if (TextUtils.equals(rendition, BEST_STRING)) {
2199                return BEST;
2200            }
2201
2202            throw new IllegalArgumentException(String.format("Unknown rendition %s", rendition));
2203        }
2204
2205        public static String toString(int rendition) {
2206            if (rendition == BEST) {
2207                return BEST_STRING;
2208            } else if (rendition == SIMPLE) {
2209                return SIMPLE_STRING;
2210            }
2211
2212            throw new IllegalArgumentException(String.format("Unknown rendition %d", rendition));
2213        }
2214    }
2215
2216    /**
2217     * Indicates the visibility type of an attachment.
2218     */
2219    public static final class AttachmentType {
2220        public static final int STANDARD = 0;
2221        public static final int INLINE_CURRENT_MESSAGE = 1;
2222        public static final int INLINE_QUOTED_MESSAGE = 2;
2223    }
2224
2225    public static final String[] UNDO_PROJECTION = {
2226        ConversationColumns.MESSAGE_LIST_URI
2227    };
2228    public static final int UNDO_MESSAGE_LIST_COLUMN = 0;
2229
2230    // Parameter used to indicate the sequence number for an undoable operation
2231    public static final String SEQUENCE_QUERY_PARAMETER = "seq";
2232
2233    /**
2234     * Parameter used to force UI notifications in an operation involving
2235     * {@link ConversationOperations#OPERATION_KEY}.
2236     */
2237    public static final String FORCE_UI_NOTIFICATIONS_QUERY_PARAMETER = "forceUiNotifications";
2238
2239    /**
2240     * Parameter used to allow returning hidden folders.
2241     */
2242    public static final String ALLOW_HIDDEN_FOLDERS_QUERY_PARAM = "allowHiddenFolders";
2243
2244    public static final String AUTO_ADVANCE_MODE_OLDER = "older";
2245    public static final String AUTO_ADVANCE_MODE_NEWER = "newer";
2246    public static final String AUTO_ADVANCE_MODE_LIST = "list";
2247
2248    /**
2249     * Settings for auto advancing when the current conversation has been destroyed.
2250     */
2251    public static final class AutoAdvance {
2252        /** No setting specified. */
2253        public static final int UNSET = 0;
2254        /** Go to the older message (if available) */
2255        public static final int OLDER = 1;
2256        /** Go to the newer message (if available) */
2257        public static final int NEWER = 2;
2258        /** Go back to conversation list*/
2259        public static final int LIST = 3;
2260        /** The default option is to go to the list */
2261        public static final int DEFAULT = LIST;
2262
2263        /**
2264         * Gets the int value for the given auto advance setting.
2265         *
2266         * @param autoAdvanceSetting The string setting, such as "newer", "older", "list"
2267         */
2268        public static int getAutoAdvanceInt(final String autoAdvanceSetting) {
2269            final int autoAdvance;
2270
2271            if (AUTO_ADVANCE_MODE_NEWER.equals(autoAdvanceSetting)) {
2272                autoAdvance = NEWER;
2273            } else if (AUTO_ADVANCE_MODE_OLDER.equals(autoAdvanceSetting)) {
2274                autoAdvance = OLDER;
2275            } else if (AUTO_ADVANCE_MODE_LIST.equals(autoAdvanceSetting)) {
2276                autoAdvance = LIST;
2277            } else {
2278                autoAdvance = UNSET;
2279            }
2280
2281            return autoAdvance;
2282        }
2283
2284        public static String getAutoAdvanceStr(int autoAdvance) {
2285            final String str;
2286
2287            switch (autoAdvance) {
2288                case OLDER:
2289                    str = AUTO_ADVANCE_MODE_OLDER;
2290                    break;
2291                case NEWER:
2292                    str = AUTO_ADVANCE_MODE_NEWER;
2293                    break;
2294                case LIST:
2295                    str = AUTO_ADVANCE_MODE_LIST;
2296                    break;
2297                default:
2298                    str = "unset";
2299                    break;
2300            }
2301
2302            return str;
2303        }
2304    }
2305
2306    /**
2307     * Settings for what swipe should do.
2308     */
2309    public static final class Swipe {
2310        /** Archive or remove label, if available. */
2311        public static final int ARCHIVE = 0;
2312        /** Delete */
2313        public static final int DELETE = 1;
2314        /** No swipe */
2315        public static final int DISABLED = 2;
2316        /** Default is delete */
2317        public static final int DEFAULT = ARCHIVE;
2318    }
2319
2320    /**
2321     * Settings for Conversation view mode.
2322     */
2323    public static final class ConversationViewMode {
2324        /**
2325         * The user hasn't specified a mode.
2326         */
2327        public static final int UNDEFINED = -1;
2328        /**
2329         * Default to fit the conversation to screen view
2330         */
2331        public static final int OVERVIEW = 0;
2332        /**
2333         * Conversation text size should be the device default, and wide conversations may
2334         * require panning
2335         */
2336        public static final int READING = 1;
2337        public static final int DEFAULT = OVERVIEW;
2338    }
2339
2340    public static final class SnapHeaderValue {
2341        public static final int ALWAYS = 0;
2342        public static final int PORTRAIT_ONLY = 1;
2343        public static final int NEVER = 2;
2344    }
2345
2346    public static final class DefaultReplyBehavior {
2347        public static final int REPLY = 0;
2348        public static final int REPLY_ALL = 1;
2349    }
2350
2351    /**
2352     * Setting for whether to show sender images in conversation list.
2353     */
2354    public static final class ConversationListIcon {
2355        public static final int SENDER_IMAGE = 1;
2356        public static final int NONE = 2;
2357        public static final int DEFAULT = 1; // Default to show sender image
2358    }
2359
2360    /**
2361     * Action for an intent used to update/create new notifications.  The mime type of this
2362     * intent should be set to the mimeType of the account that is generating this notification.
2363     * An intent of this action is required to have the following extras:
2364     * {@link UpdateNotificationExtras#EXTRA_FOLDER} {@link UpdateNotificationExtras#EXTRA_ACCOUNT}
2365     */
2366    public static final String ACTION_UPDATE_NOTIFICATION =
2367            "com.android.mail.action.update_notification";
2368
2369    public static final class UpdateNotificationExtras {
2370        /**
2371         * Parcelable extra containing a {@link Uri} to a {@link Folder}
2372         */
2373        public static final String EXTRA_FOLDER = "notification_extra_folder";
2374
2375        /**
2376         * Parcelable extra containing a {@link Uri} to an {@link Account}
2377         */
2378        public static final String EXTRA_ACCOUNT = "notification_extra_account";
2379
2380        /**
2381         * Integer extra containing the update unread count for the account/folder.
2382         * If this value is 0, the UI will not block the intent to allow code to clear notifications
2383         * to run.
2384         */
2385        public static final String EXTRA_UPDATED_UNREAD_COUNT = "notification_updated_unread_count";
2386
2387        /**
2388         * Integer extra containing the update unseen count for the account/folder.
2389         */
2390        public static final String EXTRA_UPDATED_UNSEEN_COUNT = "notification_updated_unseen_count";
2391    }
2392
2393    public static final class EditSettingsExtras {
2394        /**
2395         * Parcelable extra containing account for which the user wants to
2396         * modify settings
2397         */
2398        public static final String EXTRA_ACCOUNT = "extra_account";
2399
2400        /**
2401         * Parcelable extra containing folder for which the user wants to
2402         * modify settings
2403         */
2404        public static final String EXTRA_FOLDER = "extra_folder";
2405
2406        /**
2407         * Boolean extra which is set true if the user wants to "manage folders"
2408         */
2409        public static final String EXTRA_MANAGE_FOLDERS = "extra_manage_folders";
2410    }
2411
2412    public static final class SendFeedbackExtras {
2413        /**
2414         * Optional boolean extras which indicates that the user is reporting a problem.
2415         */
2416        public static final String EXTRA_REPORTING_PROBLEM = "reporting_problem";
2417        /**
2418         * Optional Parcelable extra containing the screenshot of the screen where the user
2419         * is reporting a problem.
2420         */
2421        public static final String EXTRA_SCREEN_SHOT = "screen_shot";
2422    }
2423
2424    public static final class ViewProxyExtras {
2425        /**
2426         * Uri extra passed to the proxy which indicates the original Uri that was intended to be
2427         * viewed.
2428         */
2429        public static final String EXTRA_ORIGINAL_URI = "original_uri";
2430        /**
2431         * String extra passed to the proxy which indicates the account being viewed.
2432         */
2433        public static final String EXTRA_ACCOUNT_NAME = "account_name";
2434        /**
2435         * String extra passed from the proxy which indicates the salt used to generate the digest.
2436         */
2437        public static final String EXTRA_SALT = "salt";
2438        /**
2439         * Byte[] extra passed from the proxy which indicates the digest of the salted account name.
2440         */
2441        public static final String EXTRA_ACCOUNT_DIGEST = "digest";
2442    }
2443}
2444