1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.bluetooth.mapapi;
18 
19 import android.content.ContentResolver;
20 import android.net.Uri;
21 
22 /**
23  * This class defines the minimum sets of data needed for a client to
24  * implement to claim support for the Bluetooth Message Access Profile.
25  * Access to three data sets are needed:
26  * <ul>
27  *   <li>Message data set containing lists of messages.</li>
28  *   <li>Account data set containing info on the existing accounts, and whether to expose
29  *     these accounts. The content of the account data set is often sensitive information,
30  *     hence care must be taken, not to reveal any personal information nor passwords.
31  *     The accounts in this data base will be exposed in the settings menu, where the user
32  *     is able to enable and disable the EXPOSE_FLAG, and thereby provide access to an
33  *     account from another device, without any password protection the e-mail client
34  *     might provide.</li>
35  *   <li>Folder data set with the folder structure for the messages. Each message is linked to an
36  *     entry in this data set.</li>
37  *   <li>Conversation data set with the thread structure of the messages. Each message is linked
38  *     to an entry in this data set.</li>
39  * </ul>
40  *
41  * To enable that the Bluetooth Message Access Server can detect the content provider implementing
42  * this interface, the {@code provider} tag for the Bluetooth related content provider must
43  * have an intent-filter like the following in the manifest:
44  * <pre class="prettyprint">&lt;provider  android:authorities="[PROVIDER AUTHORITY]"
45  *             android:exported="true"
46  *             android:enabled="true"
47  *             android:permission="android.permission.BLUETOOTH_MAP"&gt;
48  *   ...
49  *      &lt;intent-filter&gt;
50  *          &lt;action android:name="android.content.action.BLEUETOOT_MAP_PROVIDER" /&gt;
51  *       &lt;/intent-filter&gt;
52  *   ...
53  *   &lt;/provider&gt;
54  * [PROVIDER AUTHORITY] shall be the providers authority value which implements this
55  * contract. Only a single authority shall be used. The android.permission.BLUETOOTH_MAP
56  * permission is needed for the provider.
57  */
58 public final class BluetoothMapContract {
59     /** Constructor - should not be used */
BluetoothMapContract()60     private BluetoothMapContract() {
61         /* class should not be instantiated */
62     }
63 
64     /**
65      * Provider interface that should be used as intent-filter action in the provider section of the
66      * manifest file.
67      */
68     public static final String PROVIDER_INTERFACE_EMAIL =
69             "android.bluetooth.action.BLUETOOTH_MAP_PROVIDER";
70 
71     public static final String PROVIDER_INTERFACE_IM =
72             "android.bluetooth.action.BLUETOOTH_MAP_IM_PROVIDER";
73 
74     /**
75      * The Bluetooth Message Access profile allows a remote BT-MAP client to trigger an update of a
76      * folder for a specific e-mail account, register for reception of new messages from the server.
77      *
78      * <p>Additionally the Bluetooth Message Access profile allows a remote BT-MAP client to push a
79      * message to a folder - e.g. outbox or draft. The Bluetooth profile implementation will place a
80      * new message in one of these existing folders through the content provider.
81      *
82      * <p>ContentProvider.call() is used for these purposes, and the METHOD_UPDATE_FOLDER method
83      * name shall trigger an update of the specified folder for a specified account.
84      *
85      * <p>This shall be a non blocking call simply starting the update, and the update should both
86      * send and receive messages, depending on what makes sense for the specified folder. Bundle
87      * extra parameter will carry two INTEGER (long) values: EXTRA_UPDATE_ACCOUNT_ID containing the
88      * account_id EXTRA_UPDATE_FOLDER_ID containing the folder_id of the folder to update
89      *
90      * <p>The status for send complete of messages shall be reported by updating the sent-flag and
91      * e.g. for outbox messages, move them to the sent folder in the message table of the content
92      * provider and trigger a change notification to any attached content observer.
93      */
94     public static final String METHOD_UPDATE_FOLDER = "UpdateFolder";
95 
96     public static final String EXTRA_UPDATE_ACCOUNT_ID = "UpdateAccountId";
97     public static final String EXTRA_UPDATE_FOLDER_ID = "UpdateFolderId";
98 
99     /**
100      * The Bluetooth Message Access profile allows a remote BT-MAP Client to update the owners
101      * presence and chat state
102      *
103      * <p>ContentProvider.call() is used for these purposes, and the METHOD_SET_OWNER_STATUS method
104      * name shall trigger a change in owner/users presence or chat properties for an account or
105      * conversation.
106      *
107      * <p>This shall be a non blocking call simply setting the properties, and the change should be
108      * sent to the remote server/users, depending on what property is changed. Bundle extra
109      * parameter will carry following values: EXTRA_ACCOUNT_ID containing the account_id
110      * EXTRA_PRESENCE_STATE containing the presence state of the owner account EXTRA_PRESENCE_STATUS
111      * containing the presence status text from the owner EXTRA_LAST_ACTIVE containing the last
112      * activity time stamp of the owner account EXTRA_CHAT_STATE containing the chat state of a
113      * specific conversation EXTRA_CONVERSATION_ID containing the conversation that is changed
114      */
115     public static final String METHOD_SET_OWNER_STATUS = "SetOwnerStatus";
116 
117     public static final String EXTRA_ACCOUNT_ID = "AccountId"; // Is this needed
118     public static final String EXTRA_PRESENCE_STATE = "PresenceState";
119     public static final String EXTRA_PRESENCE_STATUS = "PresenceStatus";
120     public static final String EXTRA_LAST_ACTIVE = "LastActive";
121     public static final String EXTRA_CHAT_STATE = "ChatState";
122     public static final String EXTRA_CONVERSATION_ID = "ConversationId";
123 
124     /**
125      * The Bluetooth Message Access profile can inform the messaging application of the Bluetooth
126      * state, whether is is turned 'on' or 'off'
127      *
128      * <p>ContentProvider.call() is used for these purposes, and the METHOD_SET_BLUETOOTH_STATE
129      * method name shall trigger a change in owner/users presence or chat properties for an account
130      * or conversation.
131      *
132      * <p>This shall be a non blocking call simply setting the properties.
133      *
134      * <p>Bundle extra parameter will carry following values: EXTRA_BLUETOOTH_STATE containing the
135      * state of the Bluetooth connectivity
136      */
137     public static final String METHOD_SET_BLUETOOTH_STATE = "SetBtState";
138 
139     public static final String EXTRA_BLUETOOTH_STATE = "BluetoothState";
140 
141     /**
142      * These column names are used as last path segment of the URI (getLastPathSegment()). Access to
143      * a specific row in the tables is done by using the where-clause, hence support for .../#id if
144      * not needed for the Email clients. The URI format for accessing the tables are as follows:
145      * content://ProviderAuthority/TABLE_ACCOUNT
146      * content://ProviderAuthority/account_id/TABLE_MESSAGE
147      * content://ProviderAuthority/account_id/TABLE_FOLDER
148      * content://ProviderAuthority/account_id/TABLE_CONVERSATION
149      * content://ProviderAuthority/account_id/TABLE_CONVOCONTACT
150      */
151 
152     /**
153      * Build URI representing the given Accounts data-set in a Bluetooth provider. When queried, the
154      * direct URI for the account with the given accountID is returned.
155      */
buildAccountUri(String authority)156     public static Uri buildAccountUri(String authority) {
157         return new Uri.Builder()
158                 .scheme(ContentResolver.SCHEME_CONTENT)
159                 .authority(authority)
160                 .appendPath(TABLE_ACCOUNT)
161                 .build();
162     }
163 
164     /**
165      * Build URI representing the given Account data-set with specific Id in a Bluetooth provider.
166      * When queried, the direct URI for the account with the given accountID is returned.
167      */
buildAccountUriwithId(String authority, String accountId)168     public static Uri buildAccountUriwithId(String authority, String accountId) {
169         return new Uri.Builder()
170                 .scheme(ContentResolver.SCHEME_CONTENT)
171                 .authority(authority)
172                 .appendPath(TABLE_ACCOUNT)
173                 .appendPath(accountId)
174                 .build();
175     }
176 
177     /** Build URI representing the entire Message table in a Bluetooth provider. */
buildMessageUri(String authority)178     public static Uri buildMessageUri(String authority) {
179         return new Uri.Builder()
180                 .scheme(ContentResolver.SCHEME_CONTENT)
181                 .authority(authority)
182                 .appendPath(TABLE_MESSAGE)
183                 .build();
184     }
185 
186     /**
187      * Build URI representing the given Message data-set in a Bluetooth provider. When queried, the
188      * URI for the Messages with the given accountID is returned.
189      */
buildMessageUri(String authority, String accountId)190     public static Uri buildMessageUri(String authority, String accountId) {
191         return new Uri.Builder()
192                 .scheme(ContentResolver.SCHEME_CONTENT)
193                 .authority(authority)
194                 .appendPath(accountId)
195                 .appendPath(TABLE_MESSAGE)
196                 .build();
197     }
198 
199     /**
200      * Build URI representing the given Message data-set with specific messageId in a Bluetooth
201      * provider. When queried, the direct URI for the account with the given accountID is returned.
202      */
buildMessageUriWithId(String authority, String accountId, String messageId)203     public static Uri buildMessageUriWithId(String authority, String accountId, String messageId) {
204         return new Uri.Builder()
205                 .scheme(ContentResolver.SCHEME_CONTENT)
206                 .authority(authority)
207                 .appendPath(accountId)
208                 .appendPath(TABLE_MESSAGE)
209                 .appendPath(messageId)
210                 .build();
211     }
212 
213     /**
214      * Build URI representing the given Message data-set in a Bluetooth provider. When queried, the
215      * direct URI for the folder with the given accountID is returned.
216      */
buildFolderUri(String authority, String accountId)217     public static Uri buildFolderUri(String authority, String accountId) {
218         return new Uri.Builder()
219                 .scheme(ContentResolver.SCHEME_CONTENT)
220                 .authority(authority)
221                 .appendPath(accountId)
222                 .appendPath(TABLE_FOLDER)
223                 .build();
224     }
225 
226     /**
227      * Build URI representing the given Message data-set in a Bluetooth provider. When queried, the
228      * direct URI for the conversation with the given accountID is returned.
229      */
buildConversationUri(String authority, String accountId)230     public static Uri buildConversationUri(String authority, String accountId) {
231         return new Uri.Builder()
232                 .scheme(ContentResolver.SCHEME_CONTENT)
233                 .authority(authority)
234                 .appendPath(accountId)
235                 .appendPath(TABLE_CONVERSATION)
236                 .build();
237     }
238 
239     /**
240      * Build URI representing the given Contact data-set in a Bluetooth provider. When queried, the
241      * direct URI for the contacts with the given accountID is returned.
242      */
buildConvoContactsUri(String authority)243     public static Uri buildConvoContactsUri(String authority) {
244         return new Uri.Builder()
245                 .scheme(ContentResolver.SCHEME_CONTENT)
246                 .authority(authority)
247                 .appendPath(TABLE_CONVOCONTACT)
248                 .build();
249     }
250 
251     /**
252      * Build URI representing the given Contact data-set in a Bluetooth provider. When queried, the
253      * direct URI for the contacts with the given accountID is returned.
254      */
buildConvoContactsUri(String authority, String accountId)255     public static Uri buildConvoContactsUri(String authority, String accountId) {
256         return new Uri.Builder()
257                 .scheme(ContentResolver.SCHEME_CONTENT)
258                 .authority(authority)
259                 .appendPath(accountId)
260                 .appendPath(TABLE_CONVOCONTACT)
261                 .build();
262     }
263 
264     /**
265      * Build URI representing the given Contact data-set in a Bluetooth provider. When queried, the
266      * direct URI for the contact with the given contactID and accountID is returned.
267      */
buildConvoContactsUriWithId( String authority, String accountId, String contactId)268     public static Uri buildConvoContactsUriWithId(
269             String authority, String accountId, String contactId) {
270         return new Uri.Builder()
271                 .scheme(ContentResolver.SCHEME_CONTENT)
272                 .authority(authority)
273                 .appendPath(accountId)
274                 .appendPath(TABLE_CONVOCONTACT)
275                 .appendPath(contactId)
276                 .build();
277     }
278 
279     /** @hide */
280     public static final String TABLE_ACCOUNT = "Account";
281 
282     public static final String TABLE_MESSAGE = "Message";
283     public static final String TABLE_MESSAGE_PART = "Part";
284     public static final String TABLE_FOLDER = "Folder";
285     public static final String TABLE_CONVERSATION = "Conversation";
286     public static final String TABLE_CONVOCONTACT = "ConvoContact";
287 
288     /**
289      * Mandatory folders for the Bluetooth message access profile. The email client shall at least
290      * implement the following root folders. E.g. as a mapping for them such that the naming will
291      * match the underlying matching folder ID's.
292      */
293     public static final String FOLDER_NAME_INBOX = "inbox";
294 
295     public static final String FOLDER_NAME_SENT = "sent";
296     public static final String FOLDER_NAME_OUTBOX = "outbox";
297     public static final String FOLDER_NAME_DRAFT = "draft";
298     public static final String FOLDER_NAME_DELETED = "deleted";
299     public static final String FOLDER_NAME_OTHER = "other";
300 
301     /** Folder IDs to be used with Instant Messaging virtual folders */
302     public static final long FOLDER_ID_OTHER = 0;
303 
304     public static final long FOLDER_ID_INBOX = 1;
305     public static final long FOLDER_ID_SENT = 2;
306     public static final long FOLDER_ID_DRAFT = 3;
307     public static final long FOLDER_ID_OUTBOX = 4;
308     public static final long FOLDER_ID_DELETED = 5;
309 
310     /**
311      * To push RFC2822 encoded messages into a folder and read RFC2822 encoded messages from a
312      * folder, the openFile() interface will be used as follows: Open a file descriptor to a
313      * message. Two modes supported for read: With and without attachments. One mode exist for write
314      * and the actual content will be with or without attachments.
315      *
316      * <p>mode will be "r" for read and "w" for write, never "rw".
317      *
318      * <p>URI format: The URI scheme is as follows. For reading messages with attachments:
319      * content://ProviderAuthority/account_id/TABLE_MESSAGE/msgId Note: This shall be an offline
320      * operation, including only message parts and attachments already downloaded to the device.
321      *
322      * <p>For reading messages without attachments:
323      * content://ProviderAuthority/account_id/TABLE_MESSAGE/msgId/FILE_MSG_NO_ATTACHMENTS Note: This
324      * shall be an offline operation, including only message parts already downloaded to the device.
325      *
326      * <p>For downloading and reading messages with attachments:
327      * content://ProviderAuthority/account_id/TABLE_MESSAGE/msgId/FILE_MSG_DOWNLOAD Note: This shall
328      * download the message content and all attachments if possible, else throw an IOException.
329      *
330      * <p>For downloading and reading messages without attachments:
331      * content://ProviderAuthority/account_id/TABLE_MESSAGE/msgId/FILE_MSG_DOWNLOAD_NO_ATTACHMENTS
332      * Note: This shall download the message content if possible, else throw an IOException.
333      *
334      * <p>When reading from the file descriptor, the content provider shall return a stream of bytes
335      * containing a RFC2822 encoded message, as if the message was send to an email server.
336      *
337      * <p>When a byte stream is written to the file descriptor, the content provider shall decode
338      * the RFC2822 encoded data and insert the message into the TABLE_MESSAGE at the ID supplied in
339      * URI - additionally the message content shall be stored in the underlying data base structure
340      * as if the message was received from an email server. The Message ID will be created using a
341      * insert on the TABLE_MESSAGE prior to calling openFile(). Hence the procedure for inserting a
342      * message is: - uri/msgId = insert(uri, value: folderId=xxx) - fd = openFile(uri/msgId) -
343      * fd.write (RFC2822 encoded data)
344      *
345      * <p>The Bluetooth Message Access Client might not know what to put into the From: header nor
346      * have a valid time stamp, hence the content provider shall check if the From: and Date:
347      * headers have been set by the message written, else it must fill in appropriate values.
348      */
349     public static final String FILE_MSG_NO_ATTACHMENTS = "NO_ATTACHMENTS";
350 
351     public static final String FILE_MSG_DOWNLOAD = "DOWNLOAD";
352     public static final String FILE_MSG_DOWNLOAD_NO_ATTACHMENTS = "DOWNLOAD_NO_ATTACHMENTS";
353 
354     /**
355      * Account Table The columns needed to supply account information. The e-mail client app may
356      * choose to expose all e-mails as being from the same account, but it is not recommended, as
357      * this would be a violation of the Bluetooth specification. The Bluetooth Message Access
358      * settings activity will provide the user the ability to change the FLAG_EXPOSE values for each
359      * account in this table. The Bluetooth Message Access service will read the values when
360      * Bluetooth is turned on, and again on every notified change through the content observer
361      * interface.
362      */
363     public interface AccountColumns {
364 
365         /**
366          * The unique ID for a row.
367          *
368          * <p>Type: INTEGER (long)
369          */
370         String _ID = "_id";
371 
372         /**
373          * The account name to display to the user on the device when selecting whether or not to
374          * share the account over Bluetooth.
375          *
376          * <p>The account display name should not reveal any sensitive information e.g. email-
377          * address, as it will be added to the Bluetooth SDP record, which can be read by any
378          * Bluetooth enabled device. (Access to any account content is only provided to
379          * authenticated devices). It is recommended that if the email client uses the email address
380          * as account name, then the address should be obfuscated (i.e. replace "@" with ".")
381          *
382          * <p>Type: TEXT read-only
383          */
384         String ACCOUNT_DISPLAY_NAME = "account_display_name";
385 
386         /**
387          * Expose this account to other authenticated Bluetooth devices. If the expose flag is set,
388          * this account will be listed as an available account to access from another Bluetooth
389          * device.
390          *
391          * <p>This is a read/write flag, that can be set either from within the E-mail client UI or
392          * the Bluetooth settings menu.
393          *
394          * <p>It is recommended to either ask the user whether to expose the account, or set this to
395          * "show" as default.
396          *
397          * <p>This setting shall not be used to enforce whether or not an account should be shared
398          * or not if the account is bound by an administrative security policy. In this case the
399          * email app should not list the account at all if it is not to be sharable over BT.
400          *
401          * <p>Type: INTEGER (boolean) hide = 0, show = 1
402          */
403         String FLAG_EXPOSE = "flag_expose";
404 
405         /**
406          * The account unique identifier representing this account. For most IM clients this will be
407          * the fully qualified user name to which an invite message can be sent, from another use.
408          *
409          * <p>e.g.: "map_test_user_12345@gmail.com" - for a Hangouts account
410          *
411          * <p>This value will only be visible to authenticated Bluetooth devices, and will be
412          * transmitted using an encrypted link.
413          *
414          * <p>Type: TEXT read-only
415          */
416         String ACCOUNT_UCI = "account_uci";
417 
418         /**
419          * The Bluetooth SIG maintains a list of assigned numbers(text strings) for IM clients. If
420          * your client/account has such a string, this is the place to return it. If supported by
421          * both devices, the presence of this prefix will make it possible to respond to a message
422          * by making a voice-call, using the same account information. (The call will be made using
423          * the HandsFree profile)
424          * https://www.bluetooth.org/en-us/specification/assigned-numbers/uniform-caller-identifiers
425          *
426          * <p>e.g.: "hgus" - for Hangouts
427          *
428          * <p>Type: TEXT read-only
429          */
430         String ACCOUNT_UCI_PREFIX = "account_uci_PREFIX";
431     }
432 
433     /**
434      * Message Data Parts Table The columns needed to contain the actual data of the messageparts in
435      * IM messages. Each "part" has its own row and represent a single mime-part in a multipart-mime
436      * formatted message.
437      */
438     public interface MessagePartColumns {
439 
440         /**
441          * The unique ID for a row.
442          *
443          * <p>Type: INTEGER (long) read-only
444          */
445         String _ID = "_id";
446 
447         // FIXME add message parts for IM attachments
448         /**
449          * is this a text part yes/no?
450          *
451          * <p>Type: TEXT read-only
452          */
453         String TEXT = "text";
454 
455         /**
456          * The charset used in the content if it is text or 8BIT if it is binary data
457          *
458          * <p>Type: TEXT read-only
459          */
460         String CHARSET = "charset";
461 
462         /**
463          * The filename representing the data file of the raw data in the database If this is empty,
464          * then it must be text and part of the message body. This is the name that the data will
465          * have when it is included as attachment
466          *
467          * <p>Type: TEXT read-only
468          */
469         String FILENAME = "filename";
470 
471         /**
472          * Identifier for the content in the data. This can be used to refer directly to the data in
473          * the body part.
474          *
475          * <p>Type: TEXT read-only
476          */
477         String CONTENT_ID = "cid";
478 
479         /**
480          * The raw data in either text format or binary format
481          *
482          * <p>Type: BLOB read-only
483          */
484         String RAW_DATA = "raw_data";
485     }
486 
487     /**
488      * The actual message table containing all messages. Content that must support filtering using
489      * WHERE clauses: - To, From, Cc, Bcc, Date, ReadFlag, PriorityFlag, folder_id, account_id
490      * Additional content that must be supplied: - Subject, AttachmentFlag, LoadedState,
491      * MessageSize, AttachmentSize Content that must support update: - FLAG_READ and FOLDER_ID
492      * (FOLDER_ID is used to move a message to deleted) Additional insert of a new message with the
493      * following values shall be supported: - FOLDER_ID
494      *
495      * <p>When doing an insert on this table, the actual content of the message (subject, date etc)
496      * written through file-i/o takes precedence over the inserted values and should overwrite them.
497      */
498     public interface MessageColumns extends EmailMessageColumns {
499 
500         /**
501          * The unique ID for a row.
502          *
503          * <p>Type: INTEGER (long)
504          */
505         String _ID = "_id";
506 
507         /**
508          * The date the message was received as a unix timestamp (miliseconds since 00:00:00 UTC
509          * 1/1-1970).
510          *
511          * <p>Type: INTEGER (long) read-only
512          */
513         String DATE = "date";
514 
515         // TODO REMOVE WHEN Parts Table is in place
516         /**
517          * Message body. Used by Instant Messaging
518          *
519          * <p>Type: TEXT read-only.
520          */
521         String BODY = "body";
522 
523         /**
524          * Message subject.
525          *
526          * <p>Type: TEXT read-only.
527          */
528         String SUBJECT = "subject";
529 
530         /**
531          * Message Read flag
532          *
533          * <p>Type: INTEGER (boolean) unread = 0, read = 1 read/write
534          */
535         String FLAG_READ = "flag_read";
536 
537         /**
538          * Message Priority flag
539          *
540          * <p>Type: INTEGER (boolean) normal priority = 0, high priority = 1 read-only
541          */
542         String FLAG_HIGH_PRIORITY = "high_priority";
543 
544         /**
545          * Reception state - the amount of the message that have been loaded from the server.
546          *
547          * <p>Type: TEXT see RECEPTION_STATE_* constants below read-only
548          */
549         String RECEPTION_STATE = "reception_state";
550 
551         /**
552          * Delivery state - the amount of the message that have been loaded from the server.
553          *
554          * <p>Type: TEXT see DELIVERY_STATE_* constants below read-only
555          */
556         String DEVILERY_STATE = "delivery_state";
557 
558         /**
559          * To be able to filter messages with attachments, we need this flag.
560          *
561          * <p>Type: INTEGER (boolean) no attachment = 0, attachment = 1 read-only
562          */
563         String FLAG_ATTACHMENT = "flag_attachment";
564 
565         /**
566          * The overall size in bytes of the attachments of the message.
567          *
568          * <p>Type: INTEGER
569          */
570         String ATTACHMENT_SIZE = "attachment_size";
571 
572         /**
573          * The mine type of the attachments for the message.
574          *
575          * <p>Type: TEXT read-only
576          */
577         String ATTACHMENT_MINE_TYPES = "attachment_mime_types";
578 
579         /**
580          * The overall size in bytes of the message including any attachments. This value is
581          * informative only and should be the size an email client would display as size for the
582          * message.
583          *
584          * <p>Type: INTEGER read-only
585          */
586         String MESSAGE_SIZE = "message_size";
587 
588         /**
589          * Indicates that the message or a part of it is protected by a DRM scheme.
590          *
591          * <p>Type: INTEGER (boolean) no DRM = 0, DRM protected = 1 read-only
592          */
593         String FLAG_PROTECTED = "flag_protected";
594 
595         /**
596          * A comma-delimited list of FROM addresses in RFC2822 format. The list must be compatible
597          * with Rfc822Tokenizer.tokenize();
598          *
599          * <p>Type: TEXT read-only
600          */
601         String FROM_LIST = "from_list";
602 
603         /**
604          * A comma-delimited list of TO addresses in RFC2822 format. The list must be compatible
605          * with Rfc822Tokenizer.tokenize();
606          *
607          * <p>Type: TEXT read-only
608          */
609         String TO_LIST = "to_list";
610 
611         /**
612          * The unique ID for a row in the folder table in which this message belongs.
613          *
614          * <p>Type: INTEGER (long) read/write
615          */
616         String FOLDER_ID = "folder_id";
617 
618         /**
619          * The unique ID for a row in the account table which owns this message.
620          *
621          * <p>Type: INTEGER (long) read-only
622          */
623         String ACCOUNT_ID = "account_id";
624 
625         /**
626          * The ID identify the thread/conversation a message belongs to. If no thread id is
627          * available, set value to "-1"
628          *
629          * <p>Type: INTEGER (long) read-only
630          */
631         String THREAD_ID = "thread_id";
632 
633         /**
634          * The Name of the thread/conversation a message belongs to.
635          *
636          * <p>Type: TEXT read-only
637          */
638         String THREAD_NAME = "thread_name";
639     }
640 
641     public interface EmailMessageColumns {
642 
643         /**
644          * A comma-delimited list of CC addresses in RFC2822 format. The list must be compatible
645          * with Rfc822Tokenizer.tokenize();
646          *
647          * <p>Type: TEXT read-only
648          */
649         String CC_LIST = "cc_list";
650 
651         /**
652          * A comma-delimited list of BCC addresses in RFC2822 format. The list must be compatible
653          * with Rfc822Tokenizer.tokenize();
654          *
655          * <p>Type: TEXT read-only
656          */
657         String BCC_LIST = "bcc_list";
658 
659         /**
660          * A comma-delimited list of REPLY-TO addresses in RFC2822 format. The list must be
661          * compatible with Rfc822Tokenizer.tokenize();
662          *
663          * <p>Type: TEXT read-only
664          */
665         String REPLY_TO_LIST = "reply_to_List";
666     }
667 
668     /** Indicates the complete message has been delivered to the recipient. */
669     public static final String DELIVERY_STATE_DELIVERED = "delivered";
670 
671     /** Indicates that the complete message has been sent from the MSE to the remote network. */
672     public static final String DELIVERY_STATE_SENT = "sent";
673 
674     /**
675      * Indicates that the message, including any attachments, has been received from the server to
676      * the device.
677      */
678     public static final String RECEPTION_STATE_COMPLETE = "complete";
679 
680     /** Indicates the message is partially received from the email server. */
681     public static final String RECEPTION_STATE_FRACTIONED = "fractioned";
682 
683     /** Indicates that only a notification about the message have been received. */
684     public static final String RECEPTION_STATE_NOTIFICATION = "notification";
685 
686     /**
687      * Message folder structure MAP enforces use of a folder structure with mandatory folders: -
688      * inbox, outbox, sent, deleted, draft User defined folders are supported. The folder table must
689      * provide filtering (use of WHERE clauses) of the following entries: - account_id (linking the
690      * folder to an e-mail account) - parent_id (linking the folders individually) The folder table
691      * must have a folder name for each entry, and the mandatory folders MUST exist for each
692      * account_id. The folders may be empty. Use the FOLDER_NAME_xxx constants for the mandatory
693      * folders. Their names must not be translated into other languages, as the folder browsing is
694      * string based, and many Bluetooth Message Clients will use these strings to navigate to the
695      * folders.
696      */
697     public interface FolderColumns {
698 
699         /**
700          * The unique ID for a row.
701          *
702          * <p>Type: INTEGER (long) read-only
703          */
704         String _ID = "_id";
705 
706         /**
707          * The folder display name to present to the user.
708          *
709          * <p>Type: TEXT read-only
710          */
711         String NAME = "name";
712 
713         /**
714          * The _id-key to the account this folder refers to.
715          *
716          * <p>Type: INTEGER (long) read-only
717          */
718         String ACCOUNT_ID = "account_id";
719 
720         /**
721          * The _id-key to the parent folder. -1 for root folders.
722          *
723          * <p>Type: INTEGER (long) read-only
724          */
725         String PARENT_FOLDER_ID = "parent_id";
726     }
727 
728     /**
729      * Message conversation structure. Enables use of a conversation structure for messages across
730      * folders, further binding contacts to conversations. Content that must be supplied: - Name,
731      * LastActivity, ReadStatus, VersionCounter Content that must support update: - READ_STATUS,
732      * LAST_ACTIVITY and VERSION_COUNTER (VERSION_COUNTER used to validity of _ID) Additional insert
733      * of a new conversation with the following values shall be supported: - FOLDER_ID When querying
734      * this table, the cursor returned must contain one row for each contact member in a thread. For
735      * filter/search parameters attributes to the URI will be used. The following columns must
736      * support filtering: - ConvoContactColumns.NAME - ConversationColumns.THREAD_ID -
737      * ConversationColumns.LAST_ACTIVITY - ConversationColumns.READ_STATUS
738      */
739     public interface ConversationColumns extends ConvoContactColumns {
740 
741         /**
742          * The unique ID for a row.
743          *
744          * <p>Type: INTEGER (long) read-only
745          */
746         // Should not be needed anymore        public static final String _ID = "_id";
747 
748         /**
749          * The unique ID for a Thread.
750          *
751          * <p>Type: INTEGER (long) read-only
752          */
753         String THREAD_ID = "thread_id";
754 
755         /**
756          * The unique ID for a row.
757          *
758          * <p>Type: INTEGER (long) read-only
759          */
760         // TODO: IS THIS NECESSARY - or do we need the thread ID to hold thread Id from message
761         //       or can we be sure we are in control and can use the _ID and put that in the message
762         // DB
763         // public static final String THREAD_ID = "thread_id";
764 
765         /**
766          * The type of conversation, see {@link ConversationType}
767          *
768          * <p>Type: TEXT read-only
769          */
770         // TODO: IS THIS NECESSARY - no conversation type is available in the latest,
771         //        guess it can be found from number of contacts in the conversation
772         // public static final String TYPE = "type";
773 
774         /**
775          * The name of the conversation, e.g. group name in case of group chat
776          *
777          * <p>Type: TEXT read-only
778          */
779         String THREAD_NAME = "thread_name";
780 
781         /**
782          * The time stamp of the last activity in the conversation as a unix timestamp (miliseconds
783          * since 00:00:00 UTC 1/1-1970)
784          *
785          * <p>Type: INTEGER (long) read-only
786          */
787         String LAST_THREAD_ACTIVITY = "last_thread_activity";
788 
789         /**
790          * The status on the conversation, either 'read' or 'unread'
791          *
792          * <p>Type: INTEGER (boolean) unread = 0, read = 1 read/write
793          */
794         String READ_STATUS = "read_status";
795 
796         /**
797          * A counter that keep tack of version of the table content, count up on ID reuse
798          *
799          * <p>Type: INTEGER (long) read-only
800          */
801         // TODO: IS THIS NECESSARY - skal den ligge i databasen?
802         // CB: If we need it, it must be in the database, or initialized with a random value at
803         //     BT-ON
804         // UPDATE: TODO: Change to the last_activity time stamp (as a long value). This will
805         //         provide the information needed for BT clients - currently unused
806         String VERSION_COUNTER = "version_counter";
807 
808         /**
809          * A short description of the latest activity on conversation - typically part of the last
810          * message.
811          *
812          * <p>Type: TEXT read-only
813          */
814         String SUMMARY = "convo_summary";
815     }
816 
817     /**
818      * MAP enables access to contacts for the conversation The conversation table must provide
819      * filtering (using WHERE clauses) of following entries: - convo_id linking contacts to
820      * conversations - x_bt_uid linking contacts to PBAP contacts The conversation contact table
821      * must have a convo_id and a name for each entry.
822      */
823     public interface ConvoContactColumns extends ChatStatusColumns, PresenceColumns {
824         /**
825          * The unique ID for a contact in Conversation
826          *
827          * <p>Type: INTEGER (long) read-only
828          */
829         // Should not be needed anymore        public static final String _ID = "_id";
830 
831         /**
832          * The ID of the conversation the contact is part of.
833          *
834          * <p>Type: INTEGER (long) read-only
835          */
836         String CONVO_ID = "convo_id";
837 
838         /**
839          * The name of contact in instant message application
840          *
841          * <p>Type: TEXT read-only
842          */
843         String NAME = "name";
844 
845         /**
846          * The nickname of contact in instant message group chat conversation.
847          *
848          * <p>Type: TEXT read-only
849          */
850         String NICKNAME = "nickname";
851 
852         /**
853          * The unique ID for all Bluetooth contacts available through PBAP.
854          *
855          * <p>Type: INTEGER (long) read-only
856          */
857         String X_BT_UID = "x_bt_uid";
858 
859         /**
860          * The unique ID for the contact within the domain of the interfacing service. (UCI: Unique
861          * Call Identity) It is expected that a message send to this ID will reach the recipient
862          * regardless through which interface the message is send. For E-mail this will be the
863          * e-mail address, for Google+ this will be the e-mail address associated with the contact
864          * account. This ID
865          *
866          * <p>Type: TEXT read-only
867          */
868         String UCI = "x_bt_uci";
869     }
870 
871     /** The name of query parameter used to filter on recipient */
872     public static final String FILTER_RECIPIENT_SUBSTRING = "rec_sub_str";
873 
874     /** The name of query parameter used to filter on originator */
875     public static final String FILTER_ORIGINATOR_SUBSTRING = "org_sub_str";
876 
877     /**
878      * The name of query parameter used to filter on read status. - true - return only threads with
879      * all messages marked as read - false - return only threads with one or more unread messages -
880      * omitted as query parameter - do not filter on read status
881      */
882     public static final String FILTER_READ_STATUS = "read";
883 
884     /**
885      * Time in ms since epoch. For conversations this will be for last activity as a unix timestamp
886      * (miliseconds since 00:00:00 UTC 1/1-1970)
887      */
888     public static final String FILTER_PERIOD_BEGIN = "t_begin";
889 
890     /**
891      * Time in ms since epoch. For conversations this will be for last activity as a unix timestamp
892      * (miliseconds since 00:00:00 UTC 1/1-1970)
893      */
894     public static final String FILTER_PERIOD_END = "t_end";
895 
896     /** Filter for a specific ThreadId */
897     public static final String FILTER_THREAD_ID = "thread_id";
898 
899     public interface ChatState {
900         int UNKNOWN = 0;
901         int INACITVE = 1;
902         int ACITVE = 2;
903         int COMPOSING = 3;
904         int PAUSED = 4;
905         int GONE = 5;
906     }
907 
908     /**
909      * Instant Messaging contact chat state information MAP enables access to contacts chat state
910      * for the instant messaging application The chat state table must provide filtering (use of
911      * WHERE clauses) of the following entries: - contact_id (linking chat state to contacts) -
912      * thread_id (linking chat state to conversations and messages) The presence table must have a
913      * contact_id for each entry.
914      */
915     public interface ChatStatusColumns {
916 
917         //        /**
918         //         * The contact ID of a instant messaging contact.
919         //         * <P>Type: TEXT </P>
920         //         * read-only
921         //         */
922         //        public static final String CONTACT_ID = "contact_id";
923         //
924         //        /**
925         //         * The thread id for a conversation.
926         //         * <P>Type: INTEGER (long)</P>
927         //         * read-only
928         //         */
929         //        public static final String CONVO_ID = "convo_id";
930 
931         /**
932          * The chat state of contact in conversation, see {@link ChatState}
933          *
934          * <p>Type: INTERGER read-only
935          */
936         String CHAT_STATE = "chat_state";
937 
938         //        /**
939         //         * The geo location of the contact
940         //         * <P>Type: TEXT</P>
941         //         * read-only
942         //         */
943         //// TODO: IS THIS NEEDED - not in latest specification
944         //        public static final String GEOLOC = "geoloc";
945 
946         /**
947          * The time stamp of the last time this contact was active in the conversation
948          *
949          * <p>Type: INTEGER (long) read-only
950          */
951         String LAST_ACTIVE = "last_active";
952     }
953 
954     public interface PresenceState {
955         int UNKNOWN = 0;
956         int OFFLINE = 1;
957         int ONLINE = 2;
958         int AWAY = 3;
959         int DO_NOT_DISTURB = 4;
960         int BUSY = 5;
961         int IN_A_MEETING = 6;
962     }
963 
964     /**
965      * Instant Messaging contact presence information MAP enables access to contacts presences
966      * information for the instant messaging application The presence table must provide filtering
967      * (use of WHERE clauses) of the following entries: - contact_id (linking contacts to presence)
968      * The presence table must have a contact_id for each entry.
969      */
970     public interface PresenceColumns {
971 
972         //        /**
973         //         * The contact ID of a instant messaging contact.
974         //         * <P>Type: TEXT </P>
975         //         * read-only
976         //         */
977         //        public static final String CONTACT_ID = "contact_id";
978 
979         /**
980          * The presence state of contact, see {@link PresenceState}
981          *
982          * <p>Type: INTERGER read-only
983          */
984         String PRESENCE_STATE = "presence_state";
985 
986         /**
987          * The priority of contact presence
988          *
989          * <p>Type: INTERGER read-only
990          */
991         // TODO: IS THIS NEEDED - not in latest specification
992         String PRIORITY = "priority";
993 
994         /**
995          * The last status text from contact
996          *
997          * <p>Type: TEXT read-only
998          */
999         String STATUS_TEXT = "status_text";
1000 
1001         /**
1002          * The time stamp of the last time the contact was online
1003          *
1004          * <p>Type: INTEGER (long) read-only
1005          */
1006         String LAST_ONLINE = "last_online";
1007     }
1008 
1009     /** A projection of all the columns in the Message table */
1010     public static final String[] BT_MESSAGE_PROJECTION =
1011             new String[] {
1012                 MessageColumns._ID,
1013                 MessageColumns.DATE,
1014                 MessageColumns.SUBJECT,
1015                 // TODO REMOVE WHEN Parts Table is in place
1016                 MessageColumns.BODY,
1017                 MessageColumns.MESSAGE_SIZE,
1018                 MessageColumns.FOLDER_ID,
1019                 MessageColumns.FLAG_READ,
1020                 MessageColumns.FLAG_PROTECTED,
1021                 MessageColumns.FLAG_HIGH_PRIORITY,
1022                 MessageColumns.FLAG_ATTACHMENT,
1023                 MessageColumns.ATTACHMENT_SIZE,
1024                 MessageColumns.FROM_LIST,
1025                 MessageColumns.TO_LIST,
1026                 MessageColumns.CC_LIST,
1027                 MessageColumns.BCC_LIST,
1028                 MessageColumns.REPLY_TO_LIST,
1029                 MessageColumns.RECEPTION_STATE,
1030                 MessageColumns.DEVILERY_STATE,
1031                 MessageColumns.THREAD_ID
1032             };
1033 
1034     public static final String[] BT_INSTANT_MESSAGE_PROJECTION =
1035             new String[] {
1036                 MessageColumns._ID,
1037                 MessageColumns.DATE,
1038                 MessageColumns.SUBJECT,
1039                 MessageColumns.MESSAGE_SIZE,
1040                 MessageColumns.FOLDER_ID,
1041                 MessageColumns.FLAG_READ,
1042                 MessageColumns.FLAG_PROTECTED,
1043                 MessageColumns.FLAG_HIGH_PRIORITY,
1044                 MessageColumns.FLAG_ATTACHMENT,
1045                 MessageColumns.ATTACHMENT_SIZE,
1046                 MessageColumns.ATTACHMENT_MINE_TYPES,
1047                 MessageColumns.FROM_LIST,
1048                 MessageColumns.TO_LIST,
1049                 MessageColumns.RECEPTION_STATE,
1050                 MessageColumns.DEVILERY_STATE,
1051                 MessageColumns.THREAD_ID,
1052                 MessageColumns.THREAD_NAME
1053             };
1054 
1055     /** A projection of all the columns in the Account table */
1056     public static final String[] BT_ACCOUNT_PROJECTION =
1057             new String[] {
1058                 AccountColumns._ID, AccountColumns.ACCOUNT_DISPLAY_NAME, AccountColumns.FLAG_EXPOSE,
1059             };
1060 
1061     /**
1062      * A projection of all the columns in the Account table TODO: Is this the way to differentiate
1063      */
1064     public static final String[] BT_IM_ACCOUNT_PROJECTION =
1065             new String[] {
1066                 AccountColumns._ID,
1067                 AccountColumns.ACCOUNT_DISPLAY_NAME,
1068                 AccountColumns.FLAG_EXPOSE,
1069                 AccountColumns.ACCOUNT_UCI,
1070                 AccountColumns.ACCOUNT_UCI_PREFIX
1071             };
1072 
1073     /** A projection of all the columns in the Folder table */
1074     public static final String[] BT_FOLDER_PROJECTION =
1075             new String[] {
1076                 FolderColumns._ID,
1077                 FolderColumns.NAME,
1078                 FolderColumns.ACCOUNT_ID,
1079                 FolderColumns.PARENT_FOLDER_ID
1080             };
1081 
1082     /** A projection of all the columns in the Conversation table */
1083     public static final String[] BT_CONVERSATION_PROJECTION =
1084             new String[] {
1085                 /* Thread information */
1086                 ConversationColumns.THREAD_ID,
1087                 ConversationColumns.THREAD_NAME,
1088                 ConversationColumns.READ_STATUS,
1089                 ConversationColumns.LAST_THREAD_ACTIVITY,
1090                 ConversationColumns.VERSION_COUNTER,
1091                 ConversationColumns.SUMMARY,
1092                 /* Contact information */
1093                 ConversationColumns.UCI,
1094                 ConversationColumns.NAME,
1095                 ConversationColumns.NICKNAME,
1096                 ConversationColumns.CHAT_STATE,
1097                 ConversationColumns.LAST_ACTIVE,
1098                 ConversationColumns.X_BT_UID,
1099                 ConversationColumns.PRESENCE_STATE,
1100                 ConversationColumns.STATUS_TEXT,
1101                 ConversationColumns.PRIORITY
1102             };
1103 
1104     /** A projection of the Contact Info and Presence columns in the Contact Info in table */
1105     public static final String[] BT_CONTACT_CHATSTATE_PRESENCE_PROJECTION =
1106             new String[] {
1107                 ConvoContactColumns.UCI,
1108                 ConvoContactColumns.CONVO_ID,
1109                 ConvoContactColumns.NAME,
1110                 ConvoContactColumns.NICKNAME,
1111                 ConvoContactColumns.X_BT_UID,
1112                 ConvoContactColumns.CHAT_STATE,
1113                 ConvoContactColumns.LAST_ACTIVE,
1114                 ConvoContactColumns.PRESENCE_STATE,
1115                 ConvoContactColumns.PRIORITY,
1116                 ConvoContactColumns.STATUS_TEXT,
1117                 ConvoContactColumns.LAST_ONLINE
1118             };
1119 
1120     /** A projection of the Contact Info the columns in Contacts Info table */
1121     public static final String[] BT_CONTACT_PROJECTION =
1122             new String[] {
1123                 ConvoContactColumns.UCI,
1124                 ConvoContactColumns.CONVO_ID,
1125                 ConvoContactColumns.X_BT_UID,
1126                 ConvoContactColumns.NAME,
1127                 ConvoContactColumns.NICKNAME
1128             };
1129 
1130     /** A projection of all the columns in the Chat Status table */
1131     public static final String[] BT_CHATSTATUS_PROJECTION =
1132             new String[] {
1133                 ChatStatusColumns.CHAT_STATE, ChatStatusColumns.LAST_ACTIVE,
1134             };
1135 
1136     /** A projection of all the columns in the Presence table */
1137     public static final String[] BT_PRESENCE_PROJECTION =
1138             new String[] {
1139                 PresenceColumns.PRESENCE_STATE,
1140                 PresenceColumns.PRIORITY,
1141                 PresenceColumns.STATUS_TEXT,
1142                 PresenceColumns.LAST_ONLINE
1143             };
1144 }
1145