Home | History | Annotate | Download | only in mapapi
      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 /**
     24  * This class defines the minimum sets of data needed for an E-mail client to
     25  * implement to claim support for the Bluetooth Message Access Profile.
     26  * Access to three data sets are needed:
     27  * <ul>
     28  *   <li>Message data set containing lists of messages.</li>
     29  *   <li>Account data set containing info on the existing accounts, and whether to expose
     30  *     these accounts. The content of the account data set is often sensitive information,
     31  *     hence care must be taken, not to reveal any personal information nor passwords.
     32  *     The accounts in this data base will be exposed in the settings menu, where the user
     33  *     is able to enable and disable the EXPOSE_FLAG, and thereby provide access to an
     34  *     account from another device, without any password protection the e-mail client
     35  *     might provide.</li>
     36  *   <li>Folder data set with the folder structure for the messages. Each message is linked to an
     37  *     entry in this data set.</li>
     38  * </ul>
     39  *
     40  * To enable that the Bluetooth Message Access Server can detect the content provider implementing
     41  * this interface, the {@code provider} tag for the bluetooth related content provider must
     42  * have an intent-filter like the following in the manifest:
     43  * <pre class="prettyprint">&lt;provider  android:authorities="[PROVIDER AUTHORITY]"
     44               android:exported="true"
     45               android:enabled="true"
     46               android:permission="android.permission.BLUETOOTH_MAP"&gt;
     47  *   ...
     48  *      &lt;intent-filter&gt;
     49            &lt;action android:name="android.content.action.BLEUETOOT_MAP_PROVIDER" /&gt;
     50         &lt;/intent-filter&gt;
     51  *   ...
     52  *   &lt;/provider&gt;
     53  * [PROVIDER AUTHORITY] shall be the providers authority value which implements this
     54  * contract. Only a single authority shall be used. The android.permission.BLUETOOTH_MAP
     55  * permission is needed for the provider.
     56  */
     57 public final class BluetoothMapContract {
     58     /**
     59      * Constructor - should not be used
     60      */
     61     private BluetoothMapContract(){
     62       /* class should not be instantiated */
     63     }
     64 
     65     /**
     66      * Provider interface that should be used as intent-filter action in the provider section
     67      * of the manifest file.
     68      */
     69     public static final String PROVIDER_INTERFACE = "android.bluetooth.action.BLUETOOTH_MAP_PROVIDER";
     70 
     71     /**
     72      * The Bluetooth Message Access profile allows a remote BT-MAP client to trigger
     73      * an update of a folder for a specific e-mail account, register for reception
     74      * of new messages from the server.
     75      *
     76      * Additionally the Bluetooth Message Access profile allows a remote BT-MAP client
     77      * to push a message to a folder - e.g. outbox or draft. The Bluetooth profile
     78      * implementation will place a new message in one of these existing folders through
     79      * the content provider.
     80      *
     81      * ContentProvider.call() is used for these purposes, and the METHOD_UPDATE_FOLDER
     82      * method name shall trigger an update of the specified folder for a specified
     83      * account.
     84      *
     85      * This shall be a non blocking call simply starting the update, and the update should
     86      * both send and receive messages, depending on what makes sense for the specified
     87      * folder.
     88      * Bundle extra parameter will carry two INTEGER (long) values:
     89      *   EXTRA_UPDATE_ACCOUNT_ID containing the account_id
     90      *   EXTRA_UPDATE_FOLDER_ID containing the folder_id of the folder to update
     91      *
     92      * The status for send complete of messages shall be reported by updating the sent-flag
     93      * and e.g. for outbox messages, move them to the sent folder in the message table of the
     94      * content provider and trigger a change notification to any attached content observer.
     95      */
     96     public static final String METHOD_UPDATE_FOLDER = "UpdateFolder";
     97     public static final String EXTRA_UPDATE_ACCOUNT_ID = "UpdateAccountId";
     98     public static final String EXTRA_UPDATE_FOLDER_ID = "UpdateFolderId";
     99 
    100     /**
    101      * These column names are used as last path segment of the URI (getLastPathSegment()).
    102      * Access to a specific row in the tables is done by using the where-clause, hence
    103      * support for .../#id if not needed for the Email clients.
    104      * The URI format for accessing the tables are as follows:
    105      *   content://ProviderAuthority/TABLE_ACCOUNT
    106      *   content://ProviderAuthority/account_id/TABLE_MESSAGE
    107      *   content://ProviderAuthority/account_id/TABLE_FOLDER
    108      */
    109 
    110     /**
    111      * Build URI representing the given Accounts data-set in a
    112      * bluetooth provider. When queried, the direct URI for the account
    113      * with the given accountID is returned.
    114      */
    115     public static Uri buildAccountUri(String authority) {
    116         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
    117                 .authority(authority).appendPath(TABLE_ACCOUNT).build();
    118     }
    119     /**
    120      * Build URI representing the given Account data-set with specific Id in a
    121      * Bluetooth provider. When queried, the direct URI for the account
    122      * with the given accountID is returned.
    123      */
    124     public static Uri buildAccountUriwithId(String authority, String accountId) {
    125         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
    126                 .authority(authority)
    127                 .appendPath(TABLE_ACCOUNT)
    128                 .appendPath(accountId)
    129                 .build();
    130     }
    131     /**
    132      * Build URI representing the entire Message table in a
    133      * bluetooth provider.
    134      */
    135     public static Uri buildMessageUri(String authority) {
    136         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
    137                 .authority(authority)
    138                 .appendPath(TABLE_MESSAGE)
    139                 .build();
    140     }
    141     /**
    142      * Build URI representing the given Message data-set in a
    143      * bluetooth provider. When queried, the URI for the Messages
    144      * with the given accountID is returned.
    145      */
    146     public static Uri buildMessageUri(String authority, String accountId) {
    147         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
    148                 .authority(authority)
    149                 .appendPath(accountId)
    150                 .appendPath(TABLE_MESSAGE)
    151                 .build();
    152     }
    153     /**
    154      * Build URI representing the given Message data-set with specific messageId in a
    155      * bluetooth provider. When queried, the direct URI for the account
    156      * with the given accountID is returned.
    157      */
    158     public static Uri buildMessageUriWithId(String authority, String accountId,String messageId) {
    159         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
    160                 .authority(authority)
    161                 .appendPath(accountId)
    162                 .appendPath(TABLE_MESSAGE)
    163                 .appendPath(messageId)
    164                 .build();
    165     }
    166     /**
    167      * Build URI representing the given Message data-set in a
    168      * bluetooth provider. When queried, the direct URI for the account
    169      * with the given accountID is returned.
    170      */
    171     public static Uri buildFolderUri(String authority, String accountId) {
    172         return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
    173                 .authority(authority)
    174                 .appendPath(accountId)
    175                 .appendPath(TABLE_FOLDER)
    176                 .build();
    177     }
    178 
    179     /**
    180      *  @hide
    181      */
    182     public static final String TABLE_ACCOUNT = "Account";
    183     public static final String TABLE_MESSAGE = "Message";
    184     public static final String TABLE_FOLDER  = "Folder";
    185 
    186     /**
    187      * Mandatory folders for the Bluetooth message access profile.
    188      * The email client shall at least implement the following root folders.
    189      * E.g. as a mapping for them such that the naming will match the underlying
    190      * matching folder ID's.
    191      */
    192     public static final String FOLDER_NAME_INBOX   = "inbox";
    193     public static final String FOLDER_NAME_OUTBOX  = "outbox";
    194     public static final String FOLDER_NAME_SENT    = "sent";
    195     public static final String FOLDER_NAME_DELETED = "deleted";
    196     public static final String FOLDER_NAME_DRAFT   = "draft";
    197 
    198 
    199     /**
    200      * To push RFC2822 encoded messages into a folder and read RFC2822 encoded messages from
    201      * a folder, the openFile() interface will be used as follows:
    202      * Open a file descriptor to a message.
    203      * Two modes supported for read: With and without attachments.
    204      * One mode exist for write and the actual content will be with or without
    205      * attachments.
    206      *
    207      * mode will be "r" for read and "w" for write, never "rw".
    208      *
    209      * URI format:
    210      * The URI scheme is as follows.
    211      * For reading messages with attachments:
    212      *   content://ProviderAuthority/account_id/TABLE_MESSAGE/msgId
    213      *   Note: This shall be an offline operation, including only message parts and attachments
    214      *         already downloaded to the device.
    215      *
    216      * For reading messages without attachments:
    217      *   content://ProviderAuthority/account_id/TABLE_MESSAGE/msgId/FILE_MSG_NO_ATTACHMENTS
    218      *   Note: This shall be an offline operation, including only message parts already
    219      *         downloaded to the device.
    220      *
    221      * For downloading and reading messages with attachments:
    222      *   content://ProviderAuthority/account_id/TABLE_MESSAGE/msgId/FILE_MSG_DOWNLOAD
    223      *   Note: This shall download the message content and all attachments if possible,
    224      *         else throw an IOException.
    225      *
    226      * For downloading and reading messages without attachments:
    227      *   content://ProviderAuthority/account_id/TABLE_MESSAGE/msgId/FILE_MSG_DOWNLOAD_NO_ATTACHMENTS
    228      *   Note: This shall download the message content if possible, else throw an IOException.
    229      *
    230      * When reading from the file descriptor, the content provider shall return a stream
    231      * of bytes containing a RFC2822 encoded message, as if the message was send to an email
    232      * server.
    233      *
    234      * When a byte stream is written to the file descriptor, the content provider shall
    235      * decode the RFC2822 encoded data and insert the message into the TABLE_MESSAGE at the ID
    236      * supplied in URI - additionally the message content shall be stored in the underlying
    237      * data base structure as if the message was received from an email server. The Message ID
    238      * will be created using a insert on the TABLE_MESSAGE prior to calling openFile().
    239      * Hence the procedure for inserting a message is:
    240      *  - uri/msgId = insert(uri, value: folderId=xxx)
    241      *  - fd = openFile(uri/msgId)
    242      *  - fd.write (RFC2822 encoded data)
    243      *
    244      *  The Bluetooth Message Access Client might not know what to put into the From:
    245      *  header nor have a valid time stamp, hence the content provider shall check
    246      *  if the From: and Date: headers have been set by the message written, else
    247      *  it must fill in appropriate values.
    248      */
    249     public static final String FILE_MSG_NO_ATTACHMENTS = "NO_ATTACHMENTS";
    250     public static final String FILE_MSG_DOWNLOAD = "DOWNLOAD";
    251     public static final String FILE_MSG_DOWNLOAD_NO_ATTACHMENTS = "DOWNLOAD_NO_ATTACHMENTS";
    252 
    253     /**
    254      * Account Table
    255      * The columns needed to supply account information.
    256      * The e-mail client app may choose to expose all e-mails as being from the same account,
    257      * but it is not recommended, as this would be a violation of the Bluetooth specification.
    258      * The Bluetooth Message Access settings activity will provide the user the ability to
    259      * change the FLAG_EXPOSE values for each account in this table.
    260      * The Bluetooth Message Access service will read the values when Bluetooth is turned on,
    261      * and again on every notified change through the content observer interface.
    262      */
    263     public interface AccountColumns {
    264 
    265         /**
    266          * The unique ID for a row.
    267          * <P>Type: INTEGER (long)</P>
    268          */
    269         public static final String _ID = "_id";
    270 
    271         /**
    272          * The account name to display to the user on the device when selecting whether
    273          * or not to share the account over Bluetooth.
    274          *
    275          * The account display name should not reveal any sensitive information e.g. email-
    276          * address, as it will be added to the Bluetooth SDP record, which can be read by
    277          * any Bluetooth enabled device. (Access to any account content is only provided to
    278          * authenticated devices). It is recommended that if the email client uses the email
    279          * address as account name, then the address should be obfuscated (i.e. replace "@"
    280          * with ".")
    281          * <P>Type: TEXT</P>
    282          * read-only
    283          */
    284         public static final String ACCOUNT_DISPLAY_NAME = "account_display_name";
    285 
    286         /**
    287          * Expose this account to other authenticated Bluetooth devices. If the expose flag
    288          * is set, this account will be listed as an available account to access from another
    289          * Bluetooth device.
    290          *
    291          * This is a read/write flag, that can be set either from within the E-mail client
    292          * UI or the Bluetooth settings menu.
    293          *
    294          * It is recommended to either ask the user whether to expose the account, or set this
    295          * to "show" as default.
    296          *
    297          * This setting shall not be used to enforce whether or not an account should be shared
    298          * or not if the account is bound by an administrative security policy. In this case
    299          * the email app should not list the account at all if it is not to be shareable over BT.
    300          *
    301          * <P>Type: INTEGER (boolean) hide = 0, show = 1</P>
    302          */
    303         public static final String FLAG_EXPOSE = "flag_expose";
    304 
    305     }
    306 
    307     /**
    308      * The actual message table containing all messages.
    309      * Content that must support filtering using WHERE clauses:
    310      *   - To, From, Cc, Bcc, Date, ReadFlag, PriorityFlag, folder_id, account_id
    311      * Additional content that must be supplied:
    312      *   - Subject, AttachmentFlag, LoadedState, MessageSize, AttachmentSize
    313      * Content that must support update:
    314      *   - FLAG_READ and FOLDER_ID (FOLDER_ID is used to move a message to deleted)
    315      * Additional insert of a new message with the following values shall be supported:
    316      *   - FOLDER_ID
    317      *
    318      * When doing an insert on this table, the actual content of the message (subject,
    319      * date etc) written through file-i/o takes precedence over the inserted values and should
    320      * overwrite them.
    321      */
    322     public interface MessageColumns {
    323 
    324         /**
    325          * The unique ID for a row.
    326          * <P>Type: INTEGER (long)</P>
    327          */
    328         public static final String _ID = "_id";
    329 
    330         /**
    331          * The date the message was received as a unix timestamp
    332          * (miliseconds since 00:00:00 UTC 1/1-1970).
    333          *
    334          * <P>Type: INTEGER (long)</P>
    335          * read-only
    336          */
    337         public static final String DATE = "date";
    338 
    339         /**
    340          * Message subject.
    341          * <P>Type: TEXT</P>
    342          * read-only.
    343          */
    344         public static final String SUBJECT = "subject";
    345 
    346         /**
    347          * Message Read flag
    348          * <P>Type: INTEGER (boolean) unread = 0, read = 1</P>
    349          *  read/write
    350          */
    351         public static final String FLAG_READ = "flag_read";
    352 
    353         /**
    354          * Message Priority flag
    355          * <P>Type: INTEGER (boolean) normal priority = 0, high priority = 1</P>
    356          * read-only
    357          */
    358         public static final String FLAG_HIGH_PRIORITY = "high_priority";
    359 
    360         /**
    361          * Reception state - the amount of the message that have been loaded from the server.
    362          * <P>Type: INTEGER see RECEPTION_STATE_ constants below </P>
    363          * read-only
    364          */
    365         public static final String RECEPTION_STATE = "reception_state";
    366 
    367         /** To be able to filter messages with attachments, we need this flag.
    368          * <P>Type: INTEGER (boolean) no attachment = 0, attachment = 1 </P>
    369          * read-only
    370          */
    371         public static final String FLAG_ATTACHMENT = "flag_attachment";
    372 
    373         /** The overall size in bytes of the attachments of the message.
    374          * <P>Type: INTEGER </P>
    375          */
    376         public static final String ATTACHMENT_SIZE = "attachment_size";
    377 
    378         /** The overall size in bytes of the message including any attachments.
    379          * This value is informative only and should be the size an email client
    380          * would display as size for the message.
    381          * <P>Type: INTEGER </P>
    382          * read-only
    383          */
    384         public static final String MESSAGE_SIZE = "message_size";
    385 
    386         /** Indicates that the message or a part of it is protected by a DRM scheme.
    387          * <P>Type: INTEGER (boolean) no DRM = 0, DRM protected = 1 </P>
    388          * read-only
    389          */
    390         public static final String FLAG_PROTECTED = "flag_protected";
    391 
    392         /**
    393          * A comma-delimited list of FROM addresses in RFC2822 format.
    394          * The list must be compatible with Rfc822Tokenizer.tokenize();
    395          * <P>Type: TEXT</P>
    396          * read-only
    397          */
    398         public static final String FROM_LIST = "from_list";
    399 
    400         /**
    401          * A comma-delimited list of TO addresses in RFC2822 format.
    402          * The list must be compatible with Rfc822Tokenizer.tokenize();
    403          * <P>Type: TEXT</P>
    404          * read-only
    405          */
    406         public static final String TO_LIST = "to_list";
    407 
    408         /**
    409          * A comma-delimited list of CC addresses in RFC2822 format.
    410          * The list must be compatible with Rfc822Tokenizer.tokenize();
    411          * <P>Type: TEXT</P>
    412          * read-only
    413          */
    414         public static final String CC_LIST = "cc_list";
    415 
    416         /**
    417          * A comma-delimited list of BCC addresses in RFC2822 format.
    418          * The list must be compatible with Rfc822Tokenizer.tokenize();
    419          * <P>Type: TEXT</P>
    420          * read-only
    421          */
    422         public static final String BCC_LIST = "bcc_list";
    423 
    424         /**
    425          * A comma-delimited list of REPLY-TO addresses in RFC2822 format.
    426          * The list must be compatible with Rfc822Tokenizer.tokenize();
    427          * <P>Type: TEXT</P>
    428          * read-only
    429          */
    430         public static final String REPLY_TO_LIST = "reply_to_List";
    431 
    432         /**
    433          * The unique ID for a row in the folder table in which this message belongs.
    434          * <P>Type: INTEGER (long)</P>
    435          * read/write
    436          */
    437         public static final String FOLDER_ID = "folder_id";
    438 
    439         /**
    440          * The unique ID for a row in the account table which owns this message.
    441          * <P>Type: INTEGER (long)</P>
    442          * read-only
    443          */
    444         public static final String ACCOUNT_ID = "account_id";
    445 
    446         /**
    447          * The ID identify the thread a message belongs to. If no thread id is available,
    448          * set value to "-1"
    449          * <P>Type: INTEGER (long)</P>
    450          * read-only
    451          */
    452         public static final String THREAD_ID = "thread_id";
    453     }
    454 
    455     /**
    456      * Indicates that the message, including any attachments, has been received from the
    457      * server to the device.
    458      */
    459     public static final String RECEPTION_STATE_COMPLETE = "complete";
    460     /**
    461      * Indicates the message is partially received from the email server.
    462      */
    463     public static final String RECEPTION_STATE_FRACTIONED = "fractioned";
    464     /**
    465      * Indicates that only a notification about the message have been received.
    466      */
    467     public static final String RECEPTION_STATE_NOTIFICATION = "notification";
    468 
    469     /**
    470      * Message folder structure
    471      * MAP enforces use of a folder structure with mandatory folders:
    472      *   - inbox, outbox, sent, deleted, draft
    473      * User defined folders are supported.
    474      * The folder table must provide filtering (use of WHERE clauses) of the following entries:
    475      *   - account_id (linking the folder to an e-mail account)
    476      *   - parent_id (linking the folders individually)
    477      * The folder table must have a folder name for each entry, and the mandatory folders
    478      * MUST exist for each account_id. The folders may be empty.
    479      * Use the FOLDER_NAME_xxx constants for the mandatory folders. Their names must
    480      * not be translated into other languages, as the folder browsing is string based, and
    481      * many Bluetooth Message Clients will use these strings to navigate to the folders.
    482      */
    483     public interface FolderColumns {
    484 
    485         /**
    486          * The unique ID for a row.
    487          * <P>Type: INTEGER (long)</P>
    488          * read-only
    489          */
    490         public static final String _ID = "_id";
    491 
    492         /**
    493          * The folder display name to present to the user.
    494          * <P>Type: TEXT</P>
    495          * read-only
    496          */
    497         public static final String NAME = "name";
    498 
    499         /**
    500          * The _id-key to the account this folder refers to.
    501          * <P>Type: INTEGER (long)</P>
    502          * read-only
    503          */
    504         public static final String ACCOUNT_ID = "account_id";
    505 
    506         /**
    507          * The _id-key to the parent folder. -1 for root folders.
    508          * <P>Type: INTEGER (long)</P>
    509          * read-only
    510          */
    511         public static final String PARENT_FOLDER_ID = "parent_id";
    512     }
    513     /**
    514      * A projection of all the columns in the Message table
    515      */
    516     public static final String[] BT_MESSAGE_PROJECTION = new String[] {
    517         MessageColumns._ID,
    518         MessageColumns.DATE,
    519         MessageColumns.SUBJECT,
    520         MessageColumns.FLAG_READ,
    521         MessageColumns.FLAG_ATTACHMENT,
    522         MessageColumns.FOLDER_ID,
    523         MessageColumns.ACCOUNT_ID,
    524         MessageColumns.FROM_LIST,
    525         MessageColumns.TO_LIST,
    526         MessageColumns.CC_LIST,
    527         MessageColumns.BCC_LIST,
    528         MessageColumns.REPLY_TO_LIST,
    529         MessageColumns.FLAG_PROTECTED,
    530         MessageColumns.FLAG_HIGH_PRIORITY,
    531         MessageColumns.MESSAGE_SIZE,
    532         MessageColumns.ATTACHMENT_SIZE,
    533         MessageColumns.RECEPTION_STATE,
    534         MessageColumns.THREAD_ID
    535     };
    536 
    537     /**
    538      * A projection of all the columns in the Account table
    539      */
    540     public static final String[] BT_ACCOUNT_PROJECTION = new String[] {
    541         AccountColumns._ID,
    542         AccountColumns.ACCOUNT_DISPLAY_NAME,
    543         AccountColumns.FLAG_EXPOSE,
    544     };
    545 
    546     /**
    547      * A projection of all the columns in the Folder table
    548      */
    549     public static final String[] BT_FOLDER_PROJECTION = new String[] {
    550         FolderColumns._ID,
    551         FolderColumns.NAME,
    552         FolderColumns.ACCOUNT_ID,
    553         FolderColumns.PARENT_FOLDER_ID
    554     };
    555 
    556 
    557 }
    558