| page.title=Contacts Provider |
| @jd:body |
| <div id="qv-wrapper"> |
| <div id="qv"> |
| <h2>Quickview</h2> |
| <ul> |
| <li>Android's repository of information about people.</li> |
| <li> |
| Syncs with the web. |
| </li> |
| <li> |
| Integrates social stream data. |
| </li> |
| </ul> |
| <h2>In this document</h2> |
| <ol> |
| <li> |
| <a href="#InformationTypes">Contacts Provider Organization</a> |
| </li> |
| <li> |
| <a href="#RawContactBasics">Raw contacts</a> |
| </li> |
| <li> |
| <a href="#DataBasics">Data</a> |
| </li> |
| <li> |
| <a href="#ContactBasics">Contacts</a> |
| </li> |
| <li> |
| <a href="#Sources">Data From Sync Adapters</a> |
| </li> |
| <li> |
| <a href="#Permissions">Required Permissions</a> |
| </li> |
| <li> |
| <a href="#UserProfile">The User Profile</a> |
| </li> |
| <li> |
| <a href="#ContactsProviderMetadata">Contacts Provider Metadata</a> |
| </li> |
| <li> |
| <a href="#Access">Contacts Provider Access</a> |
| <li> |
| </li> |
| <li> |
| <a href="#SyncAdapters">Contacts Provider Sync Adapters</a> |
| </li> |
| <li> |
| <a href="#SocialStream">Social Stream Data</a> |
| </li> |
| <li> |
| <a href="#AdditionalFeatures">Additional Contacts Provider Features</a> |
| </li> |
| </ol> |
| <h2>Key classes</h2> |
| <ol> |
| <li>{@link android.provider.ContactsContract.Contacts}</li> |
| <li>{@link android.provider.ContactsContract.RawContacts}</li> |
| <li>{@link android.provider.ContactsContract.Data}</li> |
| <li>android.provider.ContactsContract.StreamItems</li> |
| </ol> |
| <h2>Related Samples</h2> |
| <ol> |
| <li> |
| <a href="{@docRoot}resources/samples/ContactManager/index.html"> |
| Contact Manager |
| </a> |
| </li> |
| <li> |
| <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html"> |
| Sample Sync Adapter</a> |
| </li> |
| </ol> |
| <h2>See Also</h2> |
| <ol> |
| <li> |
| <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> |
| Content Provider Basics |
| </a> |
| </li> |
| </ol> |
| </div> |
| </div> |
| <p> |
| The Contacts Provider is a powerful and flexible Android component that manages the |
| device's central repository of data about people. The Contacts Provider is the source of data |
| you see in the device's contacts application, and you can also access its data in your own |
| application and transfer data between the device and online services. The provider accommodates |
| a wide range of data sources and tries to manage as much data as possible for each person, with |
| the result that its organization is complex. Because of this, the provider's API includes an |
| extensive set of contract classes and interfaces that facilitate both data retrieval and |
| modification. |
| </p> |
| <p> |
| This guide describes the following: |
| </p> |
| <ul> |
| <li> |
| The basic provider structure. |
| </li> |
| <li> |
| How to retrieve data from the provider. |
| </li> |
| <li> |
| How to modify data in the provider. |
| </li> |
| <li> |
| How to write a sync adapter for synchronizing data from your server to the |
| Contacts Provider. |
| </li> |
| </ul> |
| <p> |
| This guide assumes that you know the basics of Android content providers. To learn more |
| about Android content providers, read the |
| <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> |
| Content Provider Basics</a> guide. The |
| <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">Sample Sync Adapter</a> |
| sample app is an example of using a sync adapter to transfer data between the Contacts |
| Provider and a sample application hosted by Google Web Services. |
| </p> |
| <h2 id="InformationTypes">Contacts Provider Organization</h2> |
| <p> |
| The Contacts Provider is an Android content provider component. It maintains three types of |
| data about a person, each of which corresponds to a table offered by the provider, as |
| illustrated in figure 1: |
| </p> |
| <img src="{@docRoot}images/providers/contacts_structure.png" alt="" |
| height="364" id="figure1" /> |
| <p class="img-caption"> |
| <strong>Figure 1.</strong> Contacts Provider table structure. |
| </p> |
| <p> |
| The three tables are commonly referred to by the names of their contract classes. The classes |
| define constants for content URIs, column names, and column values used by the tables: |
| </p> |
| <dl> |
| <dt> |
| {@link android.provider.ContactsContract.Contacts} table |
| </dt> |
| <dd> |
| Rows representing different people, based on aggregations of raw contact rows. |
| </dd> |
| <dt> |
| {@link android.provider.ContactsContract.RawContacts} table |
| </dt> |
| <dd> |
| Rows containing a summary of a person's data, specific to a user account and type. |
| </dd> |
| <dt> |
| {@link android.provider.ContactsContract.Data} table |
| </dt> |
| <dd> |
| Rows containing the details for raw contact, such as email addresses or phone numbers. |
| </dd> |
| </dl> |
| <p> |
| The other tables represented by contract classes in {@link android.provider.ContactsContract} |
| are auxiliary tables that the Contacts Provider uses to manage its operations or support |
| specific functions in the device's contacts or telephony applications. |
| </p> |
| <h2 id="RawContactBasics">Raw contacts</h2> |
| <p> |
| A raw contact represents a person's data coming from a single account type and account |
| name. Because the Contacts Provider allows more than one online service as the source of |
| data for a person, the Contacts Provider allows multiple raw contacts for the same person. |
| Multiple raw contacts also allow a user to combine a person's data from more than one account |
| from the same account type. |
| </p> |
| <p> |
| Most of the data for a raw contact isn't stored in the |
| {@link android.provider.ContactsContract.RawContacts} table. Instead, it's stored in one or more |
| rows in the {@link android.provider.ContactsContract.Data} table. Each data row has a column |
| {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID Data.RAW_CONTACT_ID} that |
| contains the {@link android.provider.BaseColumns#_ID RawContacts._ID} value of its |
| parent {@link android.provider.ContactsContract.RawContacts} row. |
| </p> |
| <h3 id="RawContactsColumns">Important raw contact columns</h3> |
| <p> |
| The important columns in the {@link android.provider.ContactsContract.RawContacts} table are |
| listed in table 1. Please read the notes that follow after the table: |
| </p> |
| <p class="table-caption" id="table1"> |
| <strong>Table 1.</strong> Important raw contact columns. |
| </p> |
| <table> |
| <tr> |
| <th scope="col">Column name</th> |
| <th scope="col">Use</th> |
| <th scope="col">Notes</th> |
| </tr> |
| <tr> |
| <td> |
| {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_NAME} |
| </td> |
| <td> |
| The account name for the account type that's the source of this raw contact. |
| For example, the account name of a Google account is one of the device owner's Gmail |
| addresses. See the next entry for |
| {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} for more |
| information. |
| </td> |
| <td> |
| The format of this name is specific to its account type. It is not |
| necessarily an email address. |
| </td> |
| </tr> |
| <tr> |
| <td> |
| {@link android.provider.ContactsContract.SyncColumns#ACCOUNT_TYPE} |
| </td> |
| <td> |
| The account type that's the source of this raw contact. For example, the account |
| type of a Google account is <code>com.google</code>. Always qualify your account type |
| with a domain identifier for a domain you own or control. This will ensure that your |
| account type is unique. |
| </td> |
| <td> |
| An account type that offers contacts data usually has an associated sync adapter that |
| synchronizes with the Contacts Provider. |
| </tr> |
| <tr> |
| <td> |
| {@link android.provider.ContactsContract.RawContactsColumns#DELETED} |
| </td> |
| <td> |
| The "deleted" flag for a raw contact. |
| </td> |
| <td> |
| This flag allows the Contacts Provider to maintain the row internally until sync |
| adapters are able to delete the row from their servers and then finally delete the row |
| from the repository. |
| </td> |
| </tr> |
| </table> |
| <h4>Notes</h4> |
| <p> |
| The following are important notes about the |
| {@link android.provider.ContactsContract.RawContacts} table: |
| </p> |
| <ul> |
| <li> |
| A raw contact's name is not stored in its row in |
| {@link android.provider.ContactsContract.RawContacts}. Instead, it's stored in |
| the {@link android.provider.ContactsContract.Data} table, in a |
| {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} row. A raw contact |
| has only one row of this type in the {@link android.provider.ContactsContract.Data} table. |
| </li> |
| <li> |
| <strong>Caution:</strong> To use your own account data in a raw contact row, it must |
| first be registered with the {@link android.accounts.AccountManager}. To do this, prompt |
| users to add the account type and their account name to the list of accounts. If you don't |
| do this, the Contacts Provider will automatically delete your raw contact row. |
| <p> |
| For example, if you want your app to maintain contacts data for your web-based service |
| with the domain {@code com.example.dataservice}, and the user's account for your service |
| is {@code becky.sharp@dataservice.example.com}, the user must first add the account |
| "type" ({@code com.example.dataservice}) and account "name" |
| ({@code becky.smart@dataservice.example.com}) before your app can add raw contact rows. |
| You can explain this requirement to the user in documentation, or you can prompt the |
| user to add the type and name, or both. Account types and account names |
| are described in more detail in the next section. |
| </li> |
| </ul> |
| <h3 id="RawContactsExample">Sources of raw contacts data</h3> |
| <p> |
| To understand how raw contacts work, consider the user "Emily Dickinson" who has the following |
| three user accounts defined on her device: |
| </p> |
| <ul> |
| <li><code>emily.dickinson@gmail.com</code></li> |
| <li><code>emilyd@gmail.com</code></li> |
| <li>Twitter account "belle_of_amherst"</li> |
| </ul> |
| <p> |
| This user has enabled <em>Sync Contacts</em> for all three of these accounts in the |
| <em>Accounts</em> settings. |
| </p> |
| <p> |
| Suppose Emily Dickinson opens a browser window, logs into Gmail as |
| <code>emily.dickinson@gmail.com</code>, opens |
| Contacts, and adds "Thomas Higginson". Later on, she logs into Gmail as |
| <code>emilyd@gmail.com</code> and sends an email to "Thomas Higginson", which automatically |
| adds him as a contact. She also follows "colonel_tom" (Thomas Higginson's Twitter ID) on |
| Twitter. |
| </p> |
| <p> |
| The Contacts Provider creates three raw contacts as a result of this work: |
| </p> |
| <ol> |
| <li> |
| A raw contact for "Thomas Higginson" associated with <code>emily.dickinson@gmail.com</code>. |
| The user account type is Google. |
| </li> |
| <li> |
| A second raw contact for "Thomas Higginson" associated with <code>emilyd@gmail.com</code>. |
| The user account type is also Google. There is a second raw contact even |
| though the name is identical to a previous name, because the person was added for a |
| different user account. |
| </li> |
| <li> |
| A third raw contact for "Thomas Higginson" associated with "belle_of_amherst". The user |
| account type is Twitter. |
| </li> |
| </ol> |
| <h2 id="DataBasics">Data</h2> |
| <p> |
| As noted previously, the data for a raw contact is stored in a |
| {@link android.provider.ContactsContract.Data} row that is linked to the raw contact's |
| <code>_ID</code> value. This allows a single raw contact to have multiple instances of the same |
| type of data such as email addresses or phone numbers. For example, if |
| "Thomas Higginson" for {@code emilyd@gmail.com} (the raw contact row for Thomas Higginson |
| associated with the Google account <code>emilyd@gmail.com</code>) has a home email address of |
| <code>thigg@gmail.com</code> and a work email address of |
| <code>thomas.higginson@gmail.com</code>, the Contacts Provider stores the two email address |
| rows and links them both to the raw contact. |
| </p> |
| <p> |
| Notice that different types of data are stored in this single table. Display name, |
| phone number, email, postal address, photo, and website detail rows are all found in the |
| {@link android.provider.ContactsContract.Data} table. To help manage this, the |
| {@link android.provider.ContactsContract.Data} table has some columns with descriptive names, |
| and others with generic names. The contents of a descriptive-name column have the same meaning |
| regardless of the type of data in the row, while the contents of a generic-name column have |
| different meanings depending on the type of data. |
| </p> |
| <h3 id="DescriptiveColumns">Descriptive column names</h3> |
| <p> |
| Some examples of descriptive column names are: |
| </p> |
| <dl> |
| <dt> |
| {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} |
| </dt> |
| <dd> |
| The value of the <code>_ID</code> column of the raw contact for this data. |
| </dd> |
| <dt> |
| {@link android.provider.ContactsContract.DataColumns#MIMETYPE} |
| </dt> |
| <dd> |
| The type of data stored in this row, expressed as a custom MIME type. The Contacts Provider |
| uses the MIME types defined in the subclasses of |
| {@link android.provider.ContactsContract.CommonDataKinds}. These MIME types are open source, |
| and can be used by any application or sync adapter that works with the Contacts Provider. |
| </dd> |
| <dt> |
| {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} |
| </dt> |
| <dd> |
| If this type of data row can occur more than once for a raw contact, the |
| {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} column flags |
| the data row that contains the primary data for the type. For example, if |
| the user long-presses a phone number for a contact and selects <strong>Set default</strong>, |
| then the {@link android.provider.ContactsContract.Data} row containing that number |
| has its {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} column set to a |
| non-zero value. |
| </dd> |
| </dl> |
| <h3 id="GenericColumns">Generic column names</h3> |
| <p> |
| There are 15 generic columns named <code>DATA1</code> through |
| <code>DATA15</code> that are generally available and an additional four generic |
| columns <code>SYNC1</code> through <code>SYNC4</code> that should only be used by sync |
| adapters. The generic column name constants always work, regardless of the type of |
| data the row contains. |
| </p> |
| <p> |
| The <code>DATA1</code> column is indexed. The Contacts Provider always uses this column for |
| the data that the provider expects will be the most frequent target of a query. For example, |
| in an email row, this column contains the actual email address. |
| </p> |
| <p> |
| By convention, the column <code>DATA15</code> is reserved for storing Binary Large Object |
| (BLOB) data such as photo thumbnails. |
| </p> |
| <h3 id="TypeSpecificNames">Type-specific column names</h3> |
| <p> |
| To facilitate working with the columns for a particular type of row, the Contacts Provider |
| also provides type-specific column name constants, defined in subclasses of |
| {@link android.provider.ContactsContract.CommonDataKinds}. The constants simply give a |
| different constant name to the same column name, which helps you access data in a row of a |
| particular type. |
| </p> |
| <p> |
| For example, the {@link android.provider.ContactsContract.CommonDataKinds.Email} class defines |
| type-specific column name constants for a {@link android.provider.ContactsContract.Data} row |
| that has the MIME type |
| {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE |
| Email.CONTENT_ITEM_TYPE}. The class contains the constant |
| {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} for the email address |
| column. The actual value of |
| {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS} is "data1", which is |
| the same as the column's generic name. |
| </p> |
| <p class="caution"> |
| <strong>Caution:</strong> Don't add your own custom data to the |
| {@link android.provider.ContactsContract.Data} table using a row that has one of the |
| provider's pre-defined MIME types. If you do, you may lose the data or cause the provider to |
| malfunction. For example, you should not add a row with the MIME type |
| {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE |
| Email.CONTENT_ITEM_TYPE} that contains a user name instead of an email address in the |
| column <code>DATA1</code>. If you use your own custom MIME type for the row, then you are free |
| to define your own type-specific column names and use the columns however you wish. |
| </p> |
| <p> |
| Figure 2 shows how descriptive columns and data columns appear in a |
| {@link android.provider.ContactsContract.Data} row, and how type-specific column names "overlay" |
| the generic column names |
| </p> |
| <img src="{@docRoot}images/providers/data_columns.png" |
| alt="How type-specific column names map to generic column names" |
| height="311" id="figure2" /> |
| <p class="img-caption"> |
| <strong>Figure 2.</strong> Type-specific column names and generic column names. |
| </p> |
| <h3 id="ColumnMaps">Type-specific column name classes</h3> |
| <p> |
| Table 2 lists the most commonly-used type-specific column name classes: |
| </p> |
| <p class="table-caption" id="table2"> |
| <strong>Table 2.</strong> Type-specific column name classes</p> |
| <table> |
| <tr> |
| <th scope="col">Mapping class</th> |
| <th scope="col">Type of data</th> |
| <th scope="col">Notes</th> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredName}</td> |
| <td>The name data for the raw contact associated with this data row.</td> |
| <td>A raw contact has only one of these rows.</td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.CommonDataKinds.Photo}</td> |
| <td>The main photo for the raw contact associated with this data row.</td> |
| <td>A raw contact has only one of these rows.</td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.CommonDataKinds.Email}</td> |
| <td>An email address for the raw contact associated with this data row.</td> |
| <td>A raw contact can have multiple email addresses.</td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal}</td> |
| <td>A postal address for the raw contact associated with this data row.</td> |
| <td>A raw contact can have multiple postal addresses.</td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.CommonDataKinds.GroupMembership}</td> |
| <td>An identifier that links the raw contact to one of the groups in the Contacts Provider.</td> |
| <td> |
| Groups are an optional feature of an account type and account name. They're described in |
| more detail in the section <a href="#Groups">Contact groups</a>. |
| </td> |
| </tr> |
| </table> |
| <h3 id="ContactBasics">Contacts</h3> |
| <p> |
| The Contacts Provider combines the raw contact rows across all account types and account names |
| to form a <strong>contact</strong>. This facilitates displaying and modifying all the data a |
| user has collected for a person. The Contacts Provider manages the creation of new contact |
| rows, and the aggregation of raw contacts with an existing contact row. Neither applications nor |
| sync adapters are allowed to add contacts, and some columns in a contact row are read-only. |
| </p> |
| <p class="note"> |
| <strong>Note:</strong> If you try to add a contact to the Contacts Provider with an |
| {@link android.content.ContentResolver#insert(Uri,ContentValues) insert()}, you'll get |
| an {@link java.lang.UnsupportedOperationException} exception. If you try to update a column |
| that's listed as "read-only," the update is ignored. |
| </p> |
| <p> |
| The Contacts Provider creates a new contact in response to the addition of a new raw contact |
| that doesn't match any existing contacts. The provider also does this if an existing raw |
| contact's data changes in such a way that it no longer matches the contact to which it was |
| previously attached. If an application or sync adapter creates a new raw contact that |
| <em>does</em> match an existing contact, the new raw contact is aggregated to the existing |
| contact. |
| </p> |
| <p> |
| The Contacts Provider links a contact row to its raw contact rows with the contact row's |
| <code>_ID</code> column in the {@link android.provider.ContactsContract.Contacts Contacts} |
| table. The <code>CONTACT_ID</code> column of the raw contacts table |
| {@link android.provider.ContactsContract.RawContacts} contains <code>_ID</code> values for |
| the contacts row associated with each raw contacts row. |
| </p> |
| <p> |
| The {@link android.provider.ContactsContract.Contacts} table also has the column |
| {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} that is a |
| "permanent" link to the contact row. Because the Contacts Provider maintains contacts |
| automatically, it may change a contact row's {@link android.provider.BaseColumns#_ID} value |
| in response to an aggregation or sync. Even If this happens, the content URI |
| {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} combined with |
| contact's {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} will still |
| point to the contact row, so you can use |
| {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} |
| to maintain links to "favorite" contacts, and so forth. This column has its own format that is |
| unrelated to the format of the {@link android.provider.BaseColumns#_ID} column. |
| </p> |
| <p> |
| Figure 3 shows how the three main tables relate to each other. |
| </p> |
| <img src="{@docRoot}images/providers/contacts_tables.png" alt="Contacts provider main tables" |
| height="514" id="figure4" /> |
| <p class="img-caption"> |
| <strong>Figure 3.</strong> Contacts, Raw Contacts, and Details table relationships. |
| </p> |
| <h2 id="Sources">Data From Sync Adapters</h2> |
| <p> |
| Users enter contacts data directly into the device, but data also flows into the Contacts |
| Provider from web services via <strong>sync adapters</strong>, which automate |
| the transfer of data between the device and services. Sync adapters run in the background |
| under the control of the system, and they call {@link android.content.ContentResolver} methods |
| to manage data. |
| </p> |
| <p> |
| In Android, the web service that a sync adapter works with is identified by an account type. |
| Each sync adapter works with one account type, but it can support multiple account names for |
| that type. Account types and account names are described briefly in the section |
| <a href="#RawContactsExample">Sources of raw contacts data</a>. The following definitions offer |
| more detail, and describe how account type and name relate to sync adapters and services. |
| </p> |
| <dl> |
| <dt> |
| Account type |
| </dt> |
| <dd> |
| Identifies a service in which the user has stored data. Most of the time, the user has to |
| authenticate with the service. For example, Google Contacts is an account type, identified |
| by the code <code>google.com</code>. This value corresponds to the account type used by |
| {@link android.accounts.AccountManager}. |
| </dd> |
| <dt> |
| Account name |
| </dt> |
| <dd> |
| Identifies a particular account or login for an account type. Google Contacts accounts |
| are the same as Google accounts, which have an email address as an account name. |
| Other services may use a single-word username or numeric id. |
| </dd> |
| </dl> |
| <p> |
| Account types don't have to be unique. A user can configure multiple Google Contacts accounts |
| and download their data to the Contacts Provider; this may happen if the user has one set of |
| personal contacts for a personal account name, and another set for work. Account names are |
| usually unique. Together, they identify a specific data flow between the Contacts Provider and |
| an external service. |
| </p> |
| <p> |
| If you want to transfer your service's data to the Contacts Provider, you need to write your |
| own sync adapter. This is described in more detail in the section |
| <a href="#SyncAdapters">Contacts Provider Sync Adapters</a>. |
| </p> |
| <p> |
| Figure 4 shows how the Contacts Provider fits into the flow of data |
| about people. In the box marked "sync adapters," each adapter is labeled by its account type. |
| </p> |
| <img src="{@docRoot}images/providers/ContactsDataFlow.png" alt="Flow of data about people" |
| height="252" id="figure5" /> |
| <p class="img-caption"> |
| <strong>Figure 4.</strong> The Contacts Provider flow of data. |
| </p> |
| <h2 id="Permissions">Required Permissions</h2> |
| <p> |
| Applications that want to access the Contacts Provider must request the following |
| permissions: |
| </p> |
| <dl> |
| <dt>Read access to one or more tables</dt> |
| <dd> |
| {@link android.Manifest.permission#READ_CONTACTS}, specified in |
| <code>AndroidManifest.xml</code> with the |
| <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"> |
| <uses-permission></a></code> element as |
| <code><uses-permission android:name="android.permission.READ_CONTACTS"></code>. |
| </dd> |
| <dt>Write access to one or more tables</dt> |
| <dd> |
| {@link android.Manifest.permission#WRITE_CONTACTS}, specified in |
| <code>AndroidManifest.xml</code> with the |
| <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"> |
| <uses-permission></a></code> element as |
| <code><uses-permission android:name="android.permission.WRITE_CONTACTS"></code>. |
| </dd> |
| </dl> |
| <p> |
| These permissions do not extend to the user profile data. The user profile and its |
| required permissions are discussed in the following section, |
| <a href="#UserProfile">The User Profile</a>. |
| </p> |
| <p> |
| Remember that the user's contacts data is personal and sensitive. Users are concerned about |
| their privacy, so they don't want applications collecting data about them or their contacts. |
| If it's not obvious why you need permission to access their contacts data, they may give |
| your application low ratings or simply refuse to install it. |
| </p> |
| <h2 id="UserProfile">The User Profile</h2> |
| <p> |
| The {@link android.provider.ContactsContract.Contacts} table has a single row containing |
| profile data for the device's user. This data describes the device's <code>user</code> rather |
| than one of the user's contacts. The profile contacts row is linked to a raw |
| contacts row for each system that uses a profile. |
| Each profile raw contact row can have multiple data rows. Constants for accessing the user |
| profile are available in the {@link android.provider.ContactsContract.Profile} class. |
| </p> |
| <p> |
| Access to the user profile requires special permissions. In addition to the |
| {@link android.Manifest.permission#READ_CONTACTS} and |
| {@link android.Manifest.permission#WRITE_CONTACTS} permissions needed to read and write, access |
| to the user profile requires the android.Manifest.permission#READ_PROFILE and |
| android.Manifest.permission#WRITE_PROFILE permissions for read and write access, |
| respectively. |
| </p> |
| <p> |
| Remember that you should consider a user's profile to be sensitive. The permission |
| android.Manifest.permission#READ_PROFILE allows you to access the device user's |
| personally-identifying data. Make sure to tell the user why |
| you need user profile access permissions in the description of your application. |
| </p> |
| <p> |
| To retrieve the contact row that contains the user's profile, |
| call {@link android.content.ContentResolver#query(Uri,String[], String, String[], String) |
| ContentResolver.query()}. Set the content URI to |
| {@link android.provider.ContactsContract.Profile#CONTENT_URI} and don't provide any |
| selection criteria. You can also use this content URI as the base URI for retrieving raw |
| contacts or data for the profile. For example, this snippet retrieves data for the profile: |
| </p> |
| <pre> |
| // Sets the columns to retrieve for the user profile |
| mProjection = new String[] |
| { |
| Profile._ID, |
| Profile.DISPLAY_NAME_PRIMARY, |
| Profile.LOOKUP_KEY, |
| Profile.PHOTO_THUMBNAIL_URI |
| }; |
| |
| // Retrieves the profile from the Contacts Provider |
| mProfileCursor = |
| getContentResolver().query( |
| Profile.CONTENT_URI, |
| mProjection , |
| null, |
| null, |
| null); |
| </pre> |
| <p class="note"> |
| <strong>Note:</strong> If you retrieve multiple contact rows, and you want to determine if one of them |
| is the user profile, test the row's |
| {@link android.provider.ContactsContract.ContactsColumns#IS_USER_PROFILE} column. This column |
| is set to "1" if the contact is the user profile. |
| </p> |
| <h2 id="ContactsProviderMetadata">Contacts Provider Metadata</h2> |
| <p> |
| The Contacts Provider manages data that keeps track of the state of contacts data in the |
| repository. This metadata about the repository is stored in various places, including the |
| Raw Contacts, Data, and Contacts table rows, the |
| {@link android.provider.ContactsContract.Settings} table, and the |
| {@link android.provider.ContactsContract.SyncState} table. The following table shows the |
| effect of each of these pieces of metadata: |
| </p> |
| <p class="table-caption" id="table3"> |
| <strong>Table 3.</strong> Metadata in the Contacts Provider</p> |
| <table> |
| <tr> |
| <th scope="col">Table</th> |
| <th scope="col">Column</th> |
| <th scope="col">Values</th> |
| <th scope="col">Meaning</th> |
| </tr> |
| <tr> |
| <td rowspan="2">{@link android.provider.ContactsContract.RawContacts}</td> |
| <td rowspan="2">{@link android.provider.ContactsContract.SyncColumns#DIRTY}</td> |
| <td>"0" - not changed since the last sync.</td> |
| <td rowspan="2"> |
| Marks raw contacts that were changed on the device and have to be synced back to the |
| server. The value is set automatically by the Contacts Provider when Android |
| applications update a row. |
| <p> |
| Sync adapters that modify the raw contact or data tables should always append the |
| string {@link android.provider.ContactsContract#CALLER_IS_SYNCADAPTER} to the |
| content URI they use. This prevents the provider from marking rows as dirty. |
| Otherwise, sync adapter modifications appear to be local modifications and are |
| sent to the server, even though the server was the source of the modification. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td>"1" - changed since last sync, needs to be synced back to the server.</td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.RawContacts}</td> |
| <td>{@link android.provider.ContactsContract.SyncColumns#VERSION}</td> |
| <td>The version number of this row.</td> |
| <td> |
| The Contacts Provider automatically increments this value whenever the row or |
| its related data changes. |
| </td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.Data}</td> |
| <td>{@link android.provider.ContactsContract.DataColumns#DATA_VERSION}</td> |
| <td>The version number of this row.</td> |
| <td> |
| The Contacts Provider automatically increments this value whenever the data row |
| is changed. |
| </td> |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.RawContacts}</td> |
| <td>{@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}</td> |
| <td> |
| A string value that uniquely identifies this raw contact to the account in |
| which it was created. |
| </td> |
| <td> |
| When a sync adapter creates a new raw contact, this column should be set to the |
| server's unique ID for the raw contact. When an Android application creates a new |
| raw contact, the application should leave this column empty. This signals the sync |
| adapter that it should create a new raw contact on the server, and get a |
| value for the {@link android.provider.ContactsContract.SyncColumns#SOURCE_ID}. |
| <p> |
| In particular, the source id must be <strong>unique</strong> for each account |
| type and should be stable across syncs: |
| </p> |
| <ul> |
| <li> |
| Unique: Each raw contact for an account must have its own source id. If you |
| don't enforce this, you'll cause problems in the contacts application. |
| Notice that two raw contacts for the same account <em>type</em> may have |
| the same source id. For example, the raw contact "Thomas Higginson" for the |
| account {@code emily.dickinson@gmail.com} is allowed to have the same source |
| id as the raw contact "Thomas Higginson" for the account |
| {@code emilyd@gmail.com}. |
| </li> |
| <li> |
| Stable: Source ids are a permanent part of the online service's data for |
| the raw contact. For example, if the user clears Contacts Storage from the |
| Apps settings and re-syncs, the restored raw contacts should have the same |
| source ids as before. If you don't enforce this, shortcuts will stop |
| working. |
| </li> |
| </ul> |
| </td> |
| </tr> |
| <tr> |
| <td rowspan="2">{@link android.provider.ContactsContract.Groups}</td> |
| <td rowspan="2">{@link android.provider.ContactsContract.GroupsColumns#GROUP_VISIBLE}</td> |
| <td>"0" - Contacts in this group should not be visible in Android application UIs.</td> |
| <td> |
| This column is for compatibility with servers that allow a user to hide contacts in |
| certain groups. |
| </td> |
| </tr> |
| <tr> |
| <td>"1" - Contacts in this group are allowed to be visible in application UIs.</td> |
| </tr> |
| <tr> |
| <td rowspan="2">{@link android.provider.ContactsContract.Settings}</td> |
| <td rowspan="2"> |
| {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE}</td> |
| <td> |
| "0" - For this account and account type, contacts that don't belong to a group are |
| invisible to Android application UIs. |
| </td> |
| <td rowspan="2"> |
| By default, contacts are invisible if none of their raw contacts belongs to a group |
| (Group membership for a raw contact is indicated by one or more |
| {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} rows |
| in the {@link android.provider.ContactsContract.Data} table). |
| By setting this flag in the {@link android.provider.ContactsContract.Settings} table row |
| for an account type and account, you can force contacts without groups to be visible. |
| One use of this flag is to show contacts from servers that don't use groups. |
| </td> |
| </tr> |
| <tr> |
| <td> |
| "1" - For this account and account type, contacts that don't belong to a group are |
| visible to application UIs. |
| </td> |
| |
| </tr> |
| <tr> |
| <td>{@link android.provider.ContactsContract.SyncState}</td> |
| <td>(all)</td> |
| <td> |
| Use this table to store metadata for your sync adapter. |
| </td> |
| <td> |
| With this table you can store sync state and other sync-related data persistently on |
| the device. |
| </td> |
| </tr> |
| </table> |
| <h2 id="Access">Contacts Provider Access</h2> |
| <p> |
| This section describes guidelines for accessing data from the Contacts Provider, focusing on |
| the following: |
| </p> |
| <ul> |
| <li> |
| Entity queries. |
| </li> |
| <li> |
| Batch modification. |
| </li> |
| <li> |
| Retrieval and modification with intents. |
| </li> |
| <li> |
| Data integrity. |
| </li> |
| </ul> |
| <p> |
| Making modifications from a sync adapter is also covered in more detail in the section |
| <a href="#SyncAdapters">Contacts Provider Sync Adapters</a>. |
| </p> |
| <h3 id="Entities">Querying entities</h3> |
| <p> |
| Because the Contacts Provider tables are organized in a hierarchy, it's often useful to |
| retrieve a row and all of the "child" rows that are linked to it. For example, to display |
| all the information for a person, you may want to retrieve all the |
| {@link android.provider.ContactsContract.RawContacts} rows for a single |
| {@link android.provider.ContactsContract.Contacts} row, or all the |
| {@link android.provider.ContactsContract.CommonDataKinds.Email} rows for a single |
| {@link android.provider.ContactsContract.RawContacts} row. To facilitate this, the Contacts |
| Provider offers <strong>entity</strong> constructs, which act like database joins between |
| tables. |
| </p> |
| <p> |
| An entity is like a table composed of selected columns from a parent table and its child table. |
| When you query an entity, you supply a projection and search criteria based on the columns |
| available from the entity. The result is a {@link android.database.Cursor} that contains |
| contains one row for each child table row that was retrieved. For example, if you query |
| {@link android.provider.ContactsContract.Contacts.Entity} for a contact name |
| and all the {@link android.provider.ContactsContract.CommonDataKinds.Email} rows for all the |
| raw contacts for that name, you get back a {@link android.database.Cursor} containing one row |
| for each {@link android.provider.ContactsContract.CommonDataKinds.Email} row. |
| </p> |
| <p> |
| Entities simplify queries. Using an entity, you can retrieve all of the contacts data for a |
| contact or raw contact at once, instead of having to query the parent table first to get an |
| ID, and then having to query the child table with that ID. Also, the Contacts Provider processes |
| a query against an entity in a single transaction, which ensures that the retrieved data is |
| internally consistent. |
| </p> |
| <p class="note"> |
| <strong>Note:</strong> An entity usually doesn't contain all the columns of the parent and |
| child table. If you attempt to work with a column name that isn't in the list of column name |
| constants for the entity, you'll get an {@link java.lang.Exception}. |
| </p> |
| <p> |
| The following snippet shows how to retrieve all the raw contact rows for a contact. The snippet |
| is part of a larger application that has two activities, "main" and "detail". The main activity |
| shows a list of contact rows; when the user select one, the activity sends its ID to the detail |
| activity. The detail activity uses the {@link android.provider.ContactsContract.Contacts.Entity} |
| to display all of the data rows from all of the raw contacts associated with the selected |
| contact. |
| </p> |
| <p> |
| This snippet is taken from the "detail" activity: |
| </p> |
| <pre> |
| ... |
| /* |
| * Appends the entity path to the URI. In the case of the Contacts Provider, the |
| * expected URI is content://com.google.contacts/#/entity (# is the ID value). |
| */ |
| mContactUri = Uri.withAppendedPath( |
| mContactUri, |
| ContactsContract.Contacts.Entity.CONTENT_DIRECTORY); |
| |
| // Initializes the loader identified by LOADER_ID. |
| getLoaderManager().initLoader( |
| LOADER_ID, // The identifier of the loader to initialize |
| null, // Arguments for the loader (in this case, none) |
| this); // The context of the activity |
| |
| // Creates a new cursor adapter to attach to the list view |
| mCursorAdapter = new SimpleCursorAdapter( |
| this, // the context of the activity |
| R.layout.detail_list_item, // the view item containing the detail widgets |
| mCursor, // the backing cursor |
| mFromColumns, // the columns in the cursor that provide the data |
| mToViews, // the views in the view item that display the data |
| 0); // flags |
| |
| // Sets the ListView's backing adapter. |
| mRawContactList.setAdapter(mCursorAdapter); |
| ... |
| @Override |
| public Loader<Cursor> onCreateLoader(int id, Bundle args) { |
| |
| /* |
| * Sets the columns to retrieve. |
| * RAW_CONTACT_ID is included to identify the raw contact associated with the data row. |
| * DATA1 contains the first column in the data row (usually the most important one). |
| * MIMETYPE indicates the type of data in the data row. |
| */ |
| String[] projection = |
| { |
| ContactsContract.Contacts.Entity.RAW_CONTACT_ID, |
| ContactsContract.Contacts.Entity.DATA1, |
| ContactsContract.Contacts.Entity.MIMETYPE |
| }; |
| |
| /* |
| * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw |
| * contact collated together. |
| */ |
| String sortOrder = |
| ContactsContract.Contacts.Entity.RAW_CONTACT_ID + |
| " ASC"; |
| |
| /* |
| * Returns a new CursorLoader. The arguments are similar to |
| * ContentResolver.query(), except for the Context argument, which supplies the location of |
| * the ContentResolver to use. |
| */ |
| return new CursorLoader( |
| getApplicationContext(), // The activity's context |
| mContactUri, // The entity content URI for a single contact |
| projection, // The columns to retrieve |
| null, // Retrieve all the raw contacts and their data rows. |
| null, // |
| sortOrder); // Sort by the raw contact ID. |
| } |
| </pre> |
| <p> |
| When the load is finished, {@link android.app.LoaderManager} invokes a callback to |
| {@link android.app.LoaderManager.LoaderCallbacks#onLoadFinished(Loader, D) |
| onLoadFinished()}. One of the incoming arguments to this method is a |
| {@link android.database.Cursor} with the results of the query. In your own app, you can get the |
| data from this {@link android.database.Cursor} to display it or work with it further. |
| </p> |
| <h3 id="Transactions">Batch modification</h3> |
| <p> |
| Whenever possible, you should insert, update, and delete data in the Contacts Provider in |
| "batch mode", by creating an {@link java.util.ArrayList} of |
| {@link android.content.ContentProviderOperation} objects and calling |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Because |
| the Contacts Provider performs all of the operations in an |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} in a single |
| transaction, your modifications will never leave the contacts repository in an inconsistent |
| state. A batch modification also facilitates inserting a raw contact and its detail data at |
| the same time. |
| </p> |
| <p class="note"> |
| <strong>Note:</strong> To modify a <em>single</em> raw contact, consider sending an intent to |
| the device's contacts application rather than handling the modification in your app. |
| Doing this is described in more detail in the section |
| <a href="#Intents">Retrieval and modification with intents</a>. |
| </p> |
| <h4>Yield points</h4> |
| <p> |
| A batch modification containing a large number of operations can block other processes, |
| resulting in a bad overall user experience. To organize all the modifications you want to |
| perform in as few separate lists as possible, and at the same time prevent them from |
| blocking the system, you should set <strong>yield points</strong> for one or more operations. |
| A yield point is a {@link android.content.ContentProviderOperation} object that has its |
| {@link android.content.ContentProviderOperation#isYieldAllowed()} value set to |
| <code>true</code>. When the Contacts Provider encounters a yield point, it pauses its work to |
| let other processes run and closes the current transaction. When the provider starts again, it |
| continues with the next operation in the {@link java.util.ArrayList} and starts a new |
| transaction. |
| </p> |
| <p> |
| Yield points do result in more than one transaction per call to |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. Because of |
| this, you should set a yield point for the last operation for a set of related rows. |
| For example, you should set a yield point for the last operation in a set that adds a |
| raw contact rows and its associated data rows, or the last operation for a set of rows related |
| to a single contact. |
| </p> |
| <p> |
| Yield points are also a unit of atomic operation. All accesses between two yield points will |
| either succeed or fail as a single unit. If you don't set any yield points, the smallest |
| atomic operation is the entire batch of operations. If you do use yield points, you prevent |
| operations from degrading system performance, while at the same time ensuring that a subset of |
| operations is atomic. |
| </p> |
| <h4>Modification back references</h4> |
| <p> |
| When you're inserting a new raw contact row and its associated data rows as a set of |
| {@link android.content.ContentProviderOperation} objects, you have to link the data rows to |
| the raw contact row by inserting the raw contact's |
| {@link android.provider.BaseColumns#_ID} value as the |
| {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} value. However, this |
| value isn't available when you're creating the {@link android.content.ContentProviderOperation} |
| for the data row, because you haven't yet applied the |
| {@link android.content.ContentProviderOperation} for the raw contact row. To work around this, |
| the {@link android.content.ContentProviderOperation.Builder} class has the method |
| {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()}. |
| This method allows you to insert or modify a column with the |
| result of a previous operation. |
| </p> |
| <p> |
| The {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} |
| method has two arguments: |
| </p> |
| <dl> |
| <dt> |
| <code>key</code> |
| </dt> |
| <dd> |
| The key of a key-value pair. The value of this argument should be the name of a column |
| in the table that you're modifying. |
| </dd> |
| <dt> |
| <code>previousResult</code> |
| </dt> |
| <dd> |
| The 0-based index of a value in the array of |
| {@link android.content.ContentProviderResult} objects from |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. As |
| the batch operations are applied, the result of each operation is stored in an |
| intermediate array of results. The <code>previousResult</code> value is the index |
| of one of these results, which is retrieved and stored with the <code>key</code> |
| value. This allows you to insert a new raw contact record and get back its |
| {@link android.provider.BaseColumns#_ID} value, then make a "back reference" to the |
| value when you add a {@link android.provider.ContactsContract.Data} row. |
| <p> |
| The entire result array is created when you first call |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}, |
| with a size equal to the size of the {@link java.util.ArrayList} of |
| {@link android.content.ContentProviderOperation} objects you provide. However, all |
| the elements in the result array are set to <code>null</code>, and if you try |
| to do a back reference to a result for an operation that hasn't yet been applied, |
| {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} |
| throws an {@link java.lang.Exception}. |
| |
| </p> |
| </dd> |
| </dl> |
| <p> |
| The following snippets show how to insert a new raw contact and data in batch. They |
| includes code that establishes a yield point and uses a back reference. The snippets are an |
| expanded version of the <code>createContacEntry()</code> method, which is part of the |
| <code>ContactAdder</code> class in the |
| <code><a href="{@docRoot}resources/samples/ContactManager/index.html"> |
| Contact Manager</a></code> sample application. |
| </p> |
| <p> |
| The first snippet retrieves contact data from the UI. At this point, the user has already |
| selected the account for which the new raw contact should be added. |
| </p> |
| <pre> |
| // Creates a contact entry from the current UI values, using the currently-selected account. |
| protected void createContactEntry() { |
| /* |
| * Gets values from the UI |
| */ |
| String name = mContactNameEditText.getText().toString(); |
| String phone = mContactPhoneEditText.getText().toString(); |
| String email = mContactEmailEditText.getText().toString(); |
| |
| int phoneType = mContactPhoneTypes.get( |
| mContactPhoneTypeSpinner.getSelectedItemPosition()); |
| |
| int emailType = mContactEmailTypes.get( |
| mContactEmailTypeSpinner.getSelectedItemPosition()); |
| </pre> |
| <p> |
| The next snippet creates an operation to insert the raw contact row into the |
| {@link android.provider.ContactsContract.RawContacts} table: |
| </p> |
| <pre> |
| /* |
| * Prepares the batch operation for inserting a new raw contact and its data. Even if |
| * the Contacts Provider does not have any data for this person, you can't add a Contact, |
| * only a raw contact. The Contacts Provider will then add a Contact automatically. |
| */ |
| |
| // Creates a new array of ContentProviderOperation objects. |
| ArrayList<ContentProviderOperation> ops = |
| new ArrayList<ContentProviderOperation>(); |
| |
| /* |
| * Creates a new raw contact with its account type (server type) and account name |
| * (user's account). Remember that the display name is not stored in this row, but in a |
| * StructuredName data row. No other data is required. |
| */ |
| ContentProviderOperation.Builder op = |
| ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) |
| .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType()) |
| .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName()); |
| |
| // Builds the operation and adds it to the array of operations |
| ops.add(op.build()); |
| </pre> |
| <p> |
| Next, the code creates data rows for the display name, phone, and email rows. |
| </p> |
| <p> |
| Each operation builder object uses |
| {@link android.content.ContentProviderOperation.Builder#withValueBackReference(String, int) withValueBackReference()} |
| to get the |
| {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID}. The reference points |
| back to the {@link android.content.ContentProviderResult} object from the first operation, |
| which adds the raw contact row and returns its new {@link android.provider.BaseColumns#_ID} |
| value. As a result, each data row is automatically linked by its |
| {@link android.provider.ContactsContract.DataColumns#RAW_CONTACT_ID} |
| to the new {@link android.provider.ContactsContract.RawContacts} row to which it belongs. |
| </p> |
| <p> |
| The {@link android.content.ContentProviderOperation.Builder} object that adds the email row is |
| flagged with {@link android.content.ContentProviderOperation.Builder#withYieldAllowed(boolean) |
| withYieldAllowed()}, which sets a yield point: |
| </p> |
| <pre> |
| // Creates the display name for the new raw contact, as a StructuredName data row. |
| op = |
| ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) |
| /* |
| * withValueBackReference sets the value of the first argument to the value of |
| * the ContentProviderResult indexed by the second argument. In this particular |
| * call, the raw contact ID column of the StructuredName data row is set to the |
| * value of the result returned by the first operation, which is the one that |
| * actually adds the raw contact row. |
| */ |
| .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) |
| |
| // Sets the data row's MIME type to StructuredName |
| .withValue(ContactsContract.Data.MIMETYPE, |
| ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) |
| |
| // Sets the data row's display name to the name in the UI. |
| .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name); |
| |
| // Builds the operation and adds it to the array of operations |
| ops.add(op.build()); |
| |
| // Inserts the specified phone number and type as a Phone data row |
| op = |
| ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) |
| /* |
| * Sets the value of the raw contact id column to the new raw contact ID returned |
| * by the first operation in the batch. |
| */ |
| .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) |
| |
| // Sets the data row's MIME type to Phone |
| .withValue(ContactsContract.Data.MIMETYPE, |
| ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) |
| |
| // Sets the phone number and type |
| .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone) |
| .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType); |
| |
| // Builds the operation and adds it to the array of operations |
| ops.add(op.build()); |
| |
| // Inserts the specified email and type as a Phone data row |
| op = |
| ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) |
| /* |
| * Sets the value of the raw contact id column to the new raw contact ID returned |
| * by the first operation in the batch. |
| */ |
| .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) |
| |
| // Sets the data row's MIME type to Email |
| .withValue(ContactsContract.Data.MIMETYPE, |
| ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE) |
| |
| // Sets the email address and type |
| .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email) |
| .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType); |
| |
| /* |
| * Demonstrates a yield point. At the end of this insert, the batch operation's thread |
| * will yield priority to other threads. Use after every set of operations that affect a |
| * single contact, to avoid degrading performance. |
| */ |
| op.withYieldAllowed(true); |
| |
| // Builds the operation and adds it to the array of operations |
| ops.add(op.build()); |
| </pre> |
| <p> |
| The last snippet shows the call to |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()} that |
| inserts the new raw contact and data rows. |
| </p> |
| <pre> |
| // Ask the Contacts Provider to create a new contact |
| Log.d(TAG,"Selected account: " + mSelectedAccount.getName() + " (" + |
| mSelectedAccount.getType() + ")"); |
| Log.d(TAG,"Creating contact: " + name); |
| |
| /* |
| * Applies the array of ContentProviderOperation objects in batch. The results are |
| * discarded. |
| */ |
| try { |
| |
| getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); |
| } catch (Exception e) { |
| |
| // Display a warning |
| Context ctx = getApplicationContext(); |
| |
| CharSequence txt = getString(R.string.contactCreationFailure); |
| int duration = Toast.LENGTH_SHORT; |
| Toast toast = Toast.makeText(ctx, txt, duration); |
| toast.show(); |
| |
| // Log exception |
| Log.e(TAG, "Exception encountered while inserting contact: " + e); |
| } |
| } |
| </pre> |
| <p> |
| Batch operations also allow you to implement <strong>optimistic concurrency control</strong>, |
| a method of applying modification transactions without having to lock the underlying repository. |
| To use this method, you apply the transaction and then check for other modifications that |
| may have been made at the same time. If you find an inconsistent modification has occurred, you |
| roll back your transaction and retry it. |
| </p> |
| <p> |
| Optimistic concurrency control is useful for a mobile device, where there's only one user at |
| a time, and simultaneous accesses to a data repository are rare. Because locking isn't used, |
| no time is wasted on setting locks or waiting for other transactions to release their locks. |
| </p> |
| <p> |
| To use optimistic concurrency control while updating a single |
| {@link android.provider.ContactsContract.RawContacts} row, follow these steps: |
| </p> |
| <ol> |
| <li> |
| Retrieve the raw contact's {@link android.provider.ContactsContract.SyncColumns#VERSION} |
| column along with the other data you retrieve. |
| </li> |
| <li> |
| Create a {@link android.content.ContentProviderOperation.Builder} object suitable for |
| enforcing a constraint, using the method |
| {@link android.content.ContentProviderOperation#newAssertQuery(Uri)}. For the content URI, |
| use {@link android.provider.ContactsContract.RawContacts#CONTENT_URI |
| RawContacts.CONTENT_URI} |
| with the raw contact's {@link android.provider.BaseColumns#_ID} appended to it. |
| </li> |
| <li> |
| For the {@link android.content.ContentProviderOperation.Builder} object, call |
| {@link android.content.ContentProviderOperation.Builder#withValue(String, Object) |
| withValue()} to compare the {@link android.provider.ContactsContract.SyncColumns#VERSION} |
| column to the version number you just retrieved. |
| </li> |
| <li> |
| For the same {@link android.content.ContentProviderOperation.Builder}, call |
| {@link android.content.ContentProviderOperation.Builder#withExpectedCount(int) |
| withExpectedCount()} to ensure that only one row is tested by this assertion. |
| </li> |
| <li> |
| Call {@link android.content.ContentProviderOperation.Builder#build()} to create the |
| {@link android.content.ContentProviderOperation} object, then add this object as the |
| first object in the {@link java.util.ArrayList} that you pass to |
| {@link android.content.ContentResolver#applyBatch(String, ArrayList) applyBatch()}. |
| </li> |
| <li> |
| Apply the batch transaction. |
| </li> |
| </ol> |
| <p> |
| If the raw contact row is updated by another operation between the time you read the row and |
| the time you attempt to modify it, the "assert" {@link android.content.ContentProviderOperation} |
| will fail, and the entire batch of operations will be backed out. You can then choose to retry |
| the batch or take some other action. |
| </p> |
| <p> |
| The following snippet demonstrates how to create an "assert" |
| {@link android.content.ContentProviderOperation} after querying for a single raw contact using |
| a {@link android.content.CursorLoader}: |
| </p> |
| <pre> |
| /* |
| * The application uses CursorLoader to query the raw contacts table. The system calls this method |
| * when the load is finished. |
| */ |
| public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { |
| |
| // Gets the raw contact's _ID and VERSION values |
| mRawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)); |
| mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)); |
| } |
| |
| ... |
| |
| // Sets up a Uri for the assert operation |
| Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactID); |
| |
| // Creates a builder for the assert operation |
| ContentProviderOperation.Builder assertOp = ContentProviderOperation.netAssertQuery(rawContactUri); |
| |
| // Adds the assertions to the assert operation: checks the version and count of rows tested |
| assertOp.withValue(SyncColumns.VERSION, mVersion); |
| assertOp.withExpectedCount(1); |
| |
| // Creates an ArrayList to hold the ContentProviderOperation objects |
| ArrayList ops = new ArrayList<ContentProviderOperationg>; |
| |
| ops.add(assertOp.build()); |
| |
| // You would add the rest of your batch operations to "ops" here |
| |
| ... |
| |
| // Applies the batch. If the assert fails, an Exception is thrown |
| try |
| { |
| ContentProviderResult[] results = |
| getContentResolver().applyBatch(AUTHORITY, ops); |
| |
| } catch (OperationApplicationException e) { |
| |
| // Actions you want to take if the assert operation fails go here |
| } |
| </pre> |
| <h3 id="Intents">Retrieval and modification with intents</h3> |
| <p> |
| Sending an intent to the device's contacts application allows you to access the Contacts |
| Provider indirectly. The intent starts the device's contacts application UI, in which users can |
| do contacts-related work. With this type of access, users can: |
| <ul> |
| <li>Pick a contact from a list and have it returned to your app for further work.</li> |
| <li>Edit an existing contact's data.</li> |
| <li>Insert a new raw contact for any of their accounts.</li> |
| <li>Delete a contact or contacts data.</li> |
| </ul> |
| <p> |
| If the user is inserting or updating data, you can collect the data first and send it as |
| part of the intent. |
| </p> |
| <p> |
| When you use intents to access the Contacts Provider via the device's contacts application, you |
| don't have to write your own UI or code for accessing the provider. You also don't have to |
| request permission to read or write to the provider. The device's contacts application can |
| delegate read permission for a contact to you, and because you're making modifications to the |
| provider through another application, you don't have to have write permissions. |
| </p> |
| <p> |
| The general process of sending an intent to access a provider is described in detail in the |
| <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> |
| Content Provider Basics</a> guide in the section "Data access via intents." The action, |
| MIME type, and data values you use for the available tasks are summarized in Table 4, while the |
| extras values you can use with |
| {@link android.content.Intent#putExtra(String, String) putExtra()} are listed in the |
| reference documentation for {@link android.provider.ContactsContract.Intents.Insert}: |
| </p> |
| <p class="table-caption" id="table4"> |
| <strong>Table 4.</strong> Contacts Provider Intents. |
| </p> |
| <table style="width:75%"> |
| <tr> |
| <th scope="col" style="width:10%">Task</th> |
| <th scope="col" style="width:5%">Action</th> |
| <th scope="col" style="width:10%">Data</th> |
| <th scope="col" style="width:10%">MIME type</th> |
| <th scope="col" style="width:25%">Notes</th> |
| </tr> |
| <tr> |
| <td><strong>Pick a contact from a list</strong></td> |
| <td>{@link android.content.Intent#ACTION_PICK}</td> |
| <td> |
| One of: |
| <ul> |
| <li> |
| {@link android.provider.ContactsContract.Contacts#CONTENT_URI Contacts.CONTENT_URI}, |
| which displays a list of contacts. |
| </li> |
| <li> |
| {@link android.provider.ContactsContract.CommonDataKinds.Phone#CONTENT_URI Phone.CONTENT_URI}, |
| which displays a list of phone numbers for a raw contact. |
| </li> |
| <li> |
| {@link android.provider.ContactsContract.CommonDataKinds.StructuredPostal#CONTENT_URI |
| StructuredPostal.CONTENT_URI}, |
| which displays a list of postal addresses for a raw contact. |
| </li> |
| <li> |
| {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_URI Email.CONTENT_URI}, |
| which displays a list of email addresses for a raw contact. |
| </li> |
| </ul> |
| </td> |
| <td> |
| Not used |
| </td> |
| <td> |
| Displays a list of raw contacts or a list of data from a raw contact, depending on the |
| content URI type you supply. |
| <p> |
| Call |
| {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()}, |
| which returns the content URI of the selected row. The form of the URI is the |
| table's content URI with the row's <code>LOOKUP_ID</code> appended to it. |
| The device's contacts app delegates read and write permissions to this content URI |
| for the life of your activity. See the |
| <a href="{@docRoot}guide/topics/providers/content-provider-basics.html"> |
| Content Provider Basics</a> guide for more details. |
| </p> |
| </td> |
| </tr> |
| <tr> |
| <td><strong>Insert a new raw contact</strong></td> |
| <td>{@link android.provider.ContactsContract.Intents.Insert#ACTION Insert.ACTION}</td> |
| <td>N/A</td> |
| <td> |
| {@link android.provider.ContactsContract.RawContacts#CONTENT_TYPE |
| RawContacts.CONTENT_TYPE}, MIME type for a set of raw contacts. |
| </td> |
| <td> |
| Displays the device's contacts application's <strong>Add Contact</strong> screen. The |
| extras values you add to the intent are displayed. If sent with |
| {@link android.app.Activity#startActivityForResult(Intent, int) startActivityForResult()}, |
| the content URI of the newly-added raw contact is passed back to your activity's |
| {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()} |
| callback method in the {@link android.content.Intent} argument, in the |
| "data" field. To get the value, call {@link android.content.Intent#getData()}. |
| </td> |
| </tr> |
| <tr> |
| <td><strong>Edit a contact</strong></td> |
| <td>{@link android.content.Intent#ACTION_EDIT}</td> |
| <td> |
| {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} for |
| the contact. The editor activity will allow the user to edit any of the data associated |
| with this contact. |
| </td> |
| <td> |
| {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE |
| Contacts.CONTENT_ITEM_TYPE}, a single contact.</td> |
| <td> |
| Displays the Edit Contact screen in the contacts application. The extras values you add |
| to the intent are displayed. When the user clicks <strong>Done</strong> to save the |
| edits, your activity returns to the foreground. |
| </td> |
| </tr> |
| <tr> |
| <td><strong>Display a picker that can also add data.</strong></td> |
| <td>{@link android.content.Intent#ACTION_INSERT_OR_EDIT}</td> |
| <td> |
| N/A |
| </td> |
| <td> |
| {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE} |
| </td> |
| <td> |
| This intent always displays the contacts app's picker screen. The user can either |
| pick a contact to edit, or add a new contact. Either the edit or the add screen |
| appears, depending on the user's choice, and the extras data you pass in the intent |
| is displayed. If your app displays contact data such as an email or phone number, use |
| this intent to allow the user to add the data to an existing contact. |
| contact, |
| <p class="note"> |
| <strong>Note:</strong> There's no need to send a name value in this intent's extras, |
| because the user always picks an existing name or adds a new one. Moreover, |
| if you send a name, and the user chooses to do an edit, the contacts app will |
| display the name you send, overwriting the previous value. If the user doesn't |
| notice this and saves the edit, the old value is lost. |
| </p> |
| </td> |
| </tr> |
| </table> |
| <p> |
| The device's contacts app doesn't allow you to delete a raw contact or any of its data with an |
| intent. Instead, to delete a raw contact, use |
| {@link android.content.ContentResolver#delete(Uri, String, String[]) ContentResolver.delete()} |
| or {@link android.content.ContentProviderOperation#newDelete(Uri) |
| ContentProviderOperation.newDelete()}. |
| </p> |
| <p> |
| The following snippet shows how to construct and send an intent that inserts a new raw |
| contact and data: |
| </p> |
| <pre> |
| // Gets values from the UI |
| String name = mContactNameEditText.getText().toString(); |
| String phone = mContactPhoneEditText.getText().toString(); |
| String email = mContactEmailEditText.getText().toString(); |
| |
| String company = mCompanyName.getText().toString(); |
| String jobtitle = mJobTitle.getText().toString(); |
| |
| // Creates a new intent for sending to the device's contacts application |
| Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION); |
| |
| // Sets the MIME type to the one expected by the insertion activity |
| insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE); |
| |
| // Sets the new contact name |
| insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name); |
| |
| // Sets the new company and job title |
| insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company); |
| insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle); |
| |
| /* |
| * Demonstrates adding data rows as an array list associated with the DATA key |
| */ |
| |
| // Defines an array list to contain the ContentValues objects for each row |
| ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); |
| |
| |
| /* |
| * Defines the raw contact row |
| */ |
| |
| // Sets up the row as a ContentValues object |
| ContentValues rawContactRow = new ContentValues(); |
| |
| // Adds the account type and name to the row |
| rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType()); |
| rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName()); |
| |
| // Adds the row to the array |
| contactData.add(rawContactRow); |
| |
| /* |
| * Sets up the phone number data row |
| */ |
| |
| // Sets up the row as a ContentValues object |
| ContentValues phoneRow = new ContentValues(); |
| |
| // Specifies the MIME type for this data row (all data rows must be marked by their type) |
| phoneRow.put( |
| ContactsContract.Data.MIMETYPE, |
| ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE |
| ); |
| |
| // Adds the phone number and its type to the row |
| phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone); |
| |
| // Adds the row to the array |
| contactData.add(phoneRow); |
| |
| /* |
| * Sets up the email data row |
| */ |
| |
| // Sets up the row as a ContentValues object |
| ContentValues emailRow = new ContentValues(); |
| |
| // Specifies the MIME type for this data row (all data rows must be marked by their type) |
| emailRow.put( |
| ContactsContract.Data.MIMETYPE, |
| ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE |
| ); |
| |
| // Adds the email address and its type to the row |
| emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email); |
| |
| // Adds the row to the array |
| contactData.add(emailRow); |
| |
| /* |
| * Adds the array to the intent's extras. It must be a parcelable object in order to |
| * travel between processes. The device's contacts app expects its key to be |
| * Intents.Insert.DATA |
| */ |
| insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData); |
| |
| // Send out the intent to start the device's contacts app in its add contact activity. |
| startActivity(insertIntent); |
| </pre> |
| <h3 id="DataIntegrity">Data integrity</h3> |
| <p> |
| Because the contacts repository contains important and sensitive data that users expect to be |
| correct and up-to-date, the Contacts Provider has well-defined rules for data integrity. It's |
| your responsibility to conform to these rules when you modify contacts data. The important |
| rules are listed here: |
| </p> |
| <dl> |
| <dt> |
| Always add a {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} row |
| for every {@link android.provider.ContactsContract.RawContacts} row you add. |
| </dt> |
| <dd> |
| A {@link android.provider.ContactsContract.RawContacts} row without a |
| {@link android.provider.ContactsContract.CommonDataKinds.StructuredName} row in the |
| {@link android.provider.ContactsContract.Data} table may cause problems during |
| aggregation. |
| </dd> |
| <dt> |
| Always link new {@link android.provider.ContactsContract.Data} rows to their parent |
| {@link android.provider.ContactsContract.RawContacts} row. |
| </dt> |
| <dd> |
| A {@link android.provider.ContactsContract.Data} row that isn't linked to a |
| {@link android.provider.ContactsContract.RawContacts} won't be visible in the device's |
| contacts application, and it might cause problems with sync adapters. |
| </dd> |
| <dt> |
| Change data only for those raw contacts that you own. |
| </dt> |
| <dd> |
| Remember that the Contacts Provider is usually managing data from several different |
| account types/online services. You need to ensure that your application only modifies |
| or deletes data for rows that belong to you, and that it only inserts data with an |
| account type and name that you control. |
| </dd> |
| <dt> |
| Always use the constants defined in {@link android.provider.ContactsContract} and its |
| subclasses for authorities, content URIs, URI paths, column names, MIME types, and |
| {@link android.provider.ContactsContract.CommonDataKinds.CommonColumns#TYPE} values. |
| </dt> |
| <dd> |
| Using these constants helps you to avoid errors. You'll also be notified with compiler |
| warnings if any of the constants is deprecated. |
| </dd> |
| </dl> |
| <h3 id="CustomData">Custom data rows</h3> |
| <p> |
| By creating and using your own custom MIME types, you can insert, edit, delete, and retrieve |
| your own data rows in the {@link android.provider.ContactsContract.Data} table. Your rows |
| are limited to using the column defined in |
| {@link android.provider.ContactsContract.DataColumns}, although you can map your own |
| type-specific column names to the default column names. In the device's contacts application, |
| the data for your rows is displayed but can't be edited or deleted, and users can't add |
| additional data. To allow users to modify your custom data rows, you must provide an editor |
| activity in your own application. |
| </p> |
| <p> |
| To display your custom data, provide a <code>contacts.xml</code> file containing a |
| <code><ContactsAccountType></code> element and one or more of its |
| <code><ContactsDataKind></code> child elements. This is described in more detail in the |
| section <a href="#SocialStreamDataKind"><code><ContactsDataKind> element</code></a>. |
| </p> |
| <p> |
| To learn more about custom MIME types, read the |
| <a href="{@docRoot}guide/topics/providers/content-provider-creating.html"> |
| Creating a Content Provider</a> guide. |
| </p> |
| <h2 id="SyncAdapters">Contacts Provider Sync Adapters</h2> |
| <p> |
| The Contacts Provider is specifically designed for handling <strong>synchronization</strong> |
| of contacts data between a device and an online service. This allows users to download |
| existing data to a new device and upload existing data to a new account. |
| Synchronization also ensures that users have the latest data at hand, regardless |
| of the source of additions and changes. Another advantage of synchronization is that it makes |
| contacts data available even when the device is not connected to the network. |
| </p> |
| <p> |
| Although you can implement synchronization in a variety of ways, the Android system provides |
| a plug-in synchronization framework that automates the following tasks: |
| <ul> |
| |
| <li> |
| Checking network availability. |
| </li> |
| <li> |
| Scheduling and executing synchronization, based on user preferences. |
| </li> |
| <li> |
| Restarting synchronizations that have stopped. |
| </li> |
| </ul> |
| <p> |
| To use this framework, you supply a sync adapter plug-in. Each sync adapter is unique to a |
| service and content provider, but can handle multiple account names for the same service. The |
| framework also allows multiple sync adapters for the same service and provider. |
| </p> |
| <h3 id="SyncClassesFiles">Sync adapter classes and files</h3> |
| <p> |
| You implement a sync adapter as a subclass of |
| {@link android.content.AbstractThreadedSyncAdapter} and install it as part of an Android |
| application. The system learns about the sync adapter from elements in your application |
| manifest, and from a special XML file pointed to by the manifest. The XML file defines the |
| account type for the online service and the authority for the content provider, which together |
| uniquely identify the adapter. The sync adapter does not become active until the user adds an |
| account for the sync adapter's account type and enables synchronization for the content |
| provider the sync adapter syncs with. At that point, the system starts managing the adapter, |
| calling it as necessary to synchronize between the content provider and the server. |
| </p> |
| <p class="note"> |
| <strong>Note:</strong> Using an account type as part of the sync adapter's identification allows |
| the system to detect and group together sync adapters that access different services from the |
| same organization. For example, sync adapters for Google online services all have the same |
| account type <code>com.google</code>. When users add a Google account to their devices, all |
| of the installed sync adapters for Google services are listed together; each sync adapter |
| listed syncs with a different content provider on the device. |
| </p> |
| <p> |
| Because most services require users to verify their identity before accessing |
| data, the Android system offers an authentication framework that is similar to, and often |
| used in conjunction with, the sync adapter framework. The authentication framework uses |
| plug-in authenticators that are subclasses of |
| {@link android.accounts.AbstractAccountAuthenticator}. An authenticator verifies |
| the user's identity in the following steps: |
| <ol> |
| <li> |
| Collects the user's name, password or similar information (the user's |
| <strong>credentials</strong>). |
| </li> |
| <li> |
| Sends the credentials to the service |
| </li> |
| <li> |
| Examines the service's reply. |
| </li> |
| </ol> |
| <p> |
| If the service accepts the credentials, the authenticator can |
| store the credentials for later use. Because of the plug-in authenticator framework, the |
| {@link android.accounts.AccountManager} can provide access to any authtokens an authenticator |
| supports and chooses to expose, such as OAuth2 authtokens. |
| </p> |
| <p> |
| Although authentication is not required, most contacts services use it. |
| However, you're not required to use the Android authentication framework to do authentication. |
| </p> |
| <h3 id="SyncAdapterImplementing">Sync adapter implementation</h3> |
| <p> |
| To implement a sync adapter for the Contacts Provider, you start by creating an |
| Android application that contains the following: |
| </p> |
| <dl> |
| <dt> |
| A {@link android.app.Service} component that responds to requests from the system to |
| bind to the sync adapter. |
| </dt> |
| <dd> |
| When the system wants to run a synchronization, it calls the service's |
| {@link android.app.Service#onBind(Intent) onBind()} method to get an |
| {@link android.os.IBinder} for the sync adapter. This allows the system to do |
| cross-process calls to the adapter's methods. |
| <p> |
| In the <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html"> |
| Sample Sync Adapter</a> sample app, the class name of this service is |
| <code>com.example.android.samplesync.syncadapter.SyncService</code>. |
| </p> |
| </dd> |
| <dt> |
| The actual sync adapter, implemented as a concrete subclass of |
| {@link android.content.AbstractThreadedSyncAdapter}. |
| </dt> |
| <dd> |
| This class does the work of downloading data from the server, uploading data from the |
| device, and resolving conflicts. The main work of the adapter is |
| done in the method {@link android.content.AbstractThreadedSyncAdapter#onPerformSync( |
| Account, Bundle, String, ContentProviderClient, SyncResult) |
| onPerformSync()}. This class must be instantiated as a singleton. |
| <p> |
| In the <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html"> |
| Sample Sync Adapter</a> sample app, the sync adapter is defined in the class |
| <code>com.example.android.samplesync.syncadapter.SyncAdapter</code>. |
| </p> |
| </dd> |
| <dt> |
| A subclass of {@link android.app.Application}. |
| </dt> |
| <dd> |
| This class acts as a factory for the sync adapter singleton. Use the |
| {@link android.app.Application#onCreate()} method to instantiate the sync adapter, and |
| provide a static "getter" method to return the singleton to the |
| {@link android.app.Service#onBind(Intent) onBind()} method of the sync adapter's |
| service. |
| </dd> |
| <dt> |
| <strong>Optional:</strong> A {@link android.app.Service} component that responds to |
| requests from the system for user authentication. |
| </dt> |
| <dd> |
| {@link android.accounts.AccountManager} starts this service to begin the authentication |
| process. The service's {@link android.app.Service#onCreate()} method instantiates an |
| authenticator object. When the system wants to authenticate a user account for the |
| application's sync adapter, it calls the service's |
| {@link android.app.Service#onBind(Intent) onBind()} method to get an |
| {@link android.os.IBinder} for the authenticator. This allows the system to do |
| cross-process calls to the authenticator's methods.. |
| <p> |
| In the <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html"> |
| Sample Sync Adapter</a> sample app, the class name of this service is |
| <code>com.example.android.samplesync.authenticator.AuthenticationService</code>. |
| </p> |
| </dd> |
| <dt> |
| <strong>Optional:</strong> A concrete subclass of |
| {@link android.accounts.AbstractAccountAuthenticator} that handles requests for |
| authentication. |
| </dt> |
| <dd> |
| This class provides methods that the {@link android.accounts.AccountManager} invokes |
| to authenticate the user's credentials with the server. The details of the |
| authentication process vary widely, based on the server technology in use. You should |
| refer to the documentation for your server software to learn more about authentication. |
| <p> |
| In the <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html"> |
| Sample Sync Adapter</a> sample app, the authenticator is defined in the class |
| <code>com.example.android.samplesync.authenticator.Authenticator</code>. |
| </p> |
| </dd> |
| <dt> |
| XML files that define the sync adapter and authenticator to the system. |
| </dt> |
| <dd> |
| The sync adapter and authenticator service components described previously are |
| defined in |
| <code><<a href="{@docRoot}guide/topics/manifest/service-element.html">service</a>></code> |
| elements in the application manifest. These elements |
| contain |
| <code><<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>></code> |
| child elements that provide specific data to the |
| system: |
| <ul> |
| <li> |
| The |
| <code><<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>></code> |
| element for the sync adapter service points to the |
| XML file <code>res/xml/syncadapter.xml</code>. In turn, this file specifies |
| a URI for the web service that will be synchronized with the Contacts Provider, |
| and an account type for the web service. |
| </li> |
| <li> |
| <strong>Optional:</strong> The |
| <code><<a href="{@docRoot}guide/topics/manifest/meta-data-element.html">meta-data</a>></code> |
| element for the authenticator points to the XML file |
| <code>res/xml/authenticator.xml</code>. In turn, this file specifies the |
| account type that this authenticator supports, as well as UI resources that |
| appear during the authentication process. The account type specified in this |
| element must be the same as the account type specified for the sync |
| adapter. |
| </li> |
| </ul> |
| </dd> |
| </dl> |
| <h2 id="SocialStream">Social Stream Data</h2> |
| <p> |
| The android.provider.ContactsContract.StreamItems and |
| android.provider.ContactsContract.StreamItemPhotos tables |
| manage incoming data from social networks. You can write a sync adapter that adds stream data |
| from your own network to these tables, or you can read stream data from these tables and |
| display it in your own application, or both. With these features, your social networking |
| services and applications can be integrated into Android's social networking experience. |
| </p> |
| <h3 id="StreamText">Social stream text</h3> |
| <p> |
| Stream items are always associated with a raw contact. The |
| android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID links to the |
| <code>_ID</code> value for the raw contact. The account type and account name of the raw |
| contact are also stored in the stream item row. |
| </p> |
| <p> |
| Store the data from your stream in the following columns: |
| </p> |
| <dl> |
| <dt> |
| android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_TYPE |
| </dt> |
| <dd> |
| <strong>Required.</strong> The user's account type for the raw contact associated with this |
| stream item. Remember to set this value when you insert a stream item. |
| </dd> |
| <dt> |
| android.provider.ContactsContract.StreamItemsColumns#ACCOUNT_NAME |
| </dt> |
| <dd> |
| <strong>Required.</strong> The user's account name for the raw contact associated with this |
| stream item. Remember to set this value when you insert a stream item. |
| </dd> |
| <dt> |
| Identifier columns |
| </dt> |
| <dd> |
| <strong>Required.</strong> You must insert the following identifier columns when you |
| insert a stream item: |
| <ul> |
| <li> |
| android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID: The |
| android.provider.BaseColumns#_ID value of the contact that this stream |
| item is associated with. |
| </li> |
| <li> |
| android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY: The |
| android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY value of the |
| contact this stream item is associated with. |
| </li> |
| <li> |
| android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID: The |
| android.provider.BaseColumns#_ID value of the raw contact that this stream |
| item is associated with. |
| </li> |
| </ul> |
| </dd> |
| <dt> |
| android.provider.ContactsContract.StreamItemsColumns#COMMENTS |
| </dt> |
| <dd> |
| Optional. Stores summary information that you can display at the beginning of a stream item. |
| </dd> |
| <dt> |
| android.provider.ContactsContract.StreamItemsColumns#TEXT |
| </dt> |
| <dd> |
| The text of the stream item, either the content that was posted by the source of the item, |
| or a description of some action that generated the stream item. This column can contain |
| any formatting and embedded resource images that can be rendered by |
| {@link android.text.Html#fromHtml(String) fromHtml()}. The provider may truncate or |
| ellipsize long content, but it will try to avoid breaking tags. |
| </dd> |
| <dt> |
| android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP |
| </dt> |
| <dd> |
| A text string containing the time the stream item was inserted or updated, in the form |
| of <em>milliseconds</em> since epoch. Applications that insert or update stream items are |
| responsible for maintaining this column; it is not automatically maintained by the |
| Contacts Provider. |
| </dd> |
| </dl> |
| <p> |
| To display identifying information for your stream items, use the |
| android.provider.ContactsContract.StreamItemsColumns#RES_ICON, |
| android.provider.ContactsContract.StreamItemsColumns#RES_LABEL, and |
| android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE to link to resources |
| in your application. |
| </p> |
| <p> |
| The android.provider.ContactsContract.StreamItems table also contains the columns |
| android.provider.ContactsContract.StreamItemsColumns#SYNC1 through |
| android.provider.ContactsContract.StreamItemsColumns#SYNC4 for the exclusive use of |
| sync adapters. |
| </p> |
| <h3 id="StreamPhotos">Social stream photos</h3> |
| <p> |
| The android.provider.ContactsContract.StreamItemPhotos table stores photos associated |
| with a stream item. The table's |
| android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID column |
| links to values in the {@link android.provider.BaseColumns#_ID} column of |
| android.provider.ContactsContract.StreamItems table. Photo references are stored in the |
| table in these columns: |
| </p> |
| <dl> |
| <dt> |
| android.provider.ContactsContract.StreamItemPhotos#PHOTO column (a BLOB). |
| </dt> |
| <dd> |
| A binary representation of the photo, resized by the provider for storage and display. |
| This column is available for backwards compatibility with previous versions of the Contacts |
| Provider that used it for storing photos. However, in the current version |
| you should not use this column to store photos. Instead, use |
| either android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID or |
| android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI (both of |
| which are described in the following points) to store photos in a file. This column now |
| contains a thumbnail of the photo, which is available for reading. |
| </dd> |
| <dt> |
| android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID |
| </dt> |
| <dd> |
| A numeric identifier of a photo for a raw contact. Append this value to the constant |
| {@link android.provider.ContactsContract.DisplayPhoto#CONTENT_URI DisplayPhoto.CONTENT_URI} |
| to get a content URI pointing to a single photo file, and then call |
| {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String) |
| openAssetFileDescriptor()} to get a handle to the photo file. |
| </dd> |
| <dt> |
| android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_URI |
| </dt> |
| <dd> |
| A content URI pointing directly to the photo file for the photo represented by this row. |
| Call {@link android.content.ContentResolver#openAssetFileDescriptor(Uri, String) |
| openAssetFileDescriptor()} with this URI to get a handle to the photo file. |
| </dd> |
| </dl> |
| <h3 id="SocialStreamTables">Using the social stream tables</h3> |
| <p> |
| These tables work the same as the other main tables in the Contacts Provider, except that: |
| </p> |
| <ul> |
| <li> |
| These tables require additional access permissions. To read from them, your application |
| must have the permission android.Manifest.permission#READ_SOCIAL_STREAM. To |
| modify them, your application must have the permission |
| android.Manifest.permission#WRITE_SOCIAL_STREAM. |
| </li> |
| <li> |
| For the android.provider.ContactsContract.StreamItems table, the number of rows |
| stored for each raw contact is limited. Once this limit is reached, |
| the Contacts Provider makes space for new stream item rows by automatically deleting |
| the rows having the oldest |
| android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP. To get the |
| limit, issue a query to the content URI |
| android.provider.ContactsContract.StreamItems#CONTENT_LIMIT_URI. You can leave |
| all the arguments other than the content URI set to <code>null</code>. The query |
| returns a Cursor containing a single row, with the single column |
| android.provider.ContactsContract.StreamItems#MAX_ITEMS. |
| </li> |
| </ul> |
| |
| <p> |
| The class android.provider.ContactsContract.StreamItems.StreamItemPhotos defines a |
| sub-table of android.provider.ContactsContract.StreamItemPhotos containing the photo |
| rows for a single stream item. |
| </p> |
| <h3 id="SocialStreamInteraction">Social stream interactions</h3> |
| <p> |
| The social stream data managed by the Contacts Provider, in conjunction with the |
| device's contacts application, offers a powerful way to connect your social networking system |
| with existing contacts. The following features are available: |
| </p> |
| <ul> |
| <li> |
| By syncing your social networking service to the Contacts Provider with a sync |
| adapter, you can retrieve recent activity for a user's contacts and store it in |
| the android.provider.ContactsContract.StreamItems and |
| android.provider.ContactsContract.StreamItemPhotos tables for later use. |
| </li> |
| <li> |
| Besides regular synchronization, you can trigger your sync adapter to retrieve |
| additional data when the user selects a contact to view. This allows your sync adapter |
| to retrieve high-resolution photos and the most recent stream items for the contact. |
| </li> |
| <li> |
| By registering a notification with the device's contacts application and the Contacts |
| Provider, you can <em>receive</em> an intent when a contact is viewed, and at that point |
| update the contact's status from your service. This approach may be faster and use less |
| bandwidth than doing a full sync with a sync adapter. |
| </li> |
| <li> |
| Users can add a contact to your social networking service while looking at the contact |
| in the device's contacts application. You enable this with the "invite contact" feature, |
| which you enable with a combination of an activity that adds an existing contact to your |
| network, and an XML file that provides the device's contacts application and the |
| Contacts Provider with the details of your application. |
| </li> |
| </ul> |
| <p> |
| Regular synchronization of stream items with the Contacts Provider is the same as |
| other synchronizations. To learn more about synchronization, see the section |
| <a href="#SyncAdapters">Contacts Provider Sync Adapters</a>. Registering notifications and |
| inviting contacts are covered in the next two sections. |
| </p> |
| <h4>Registering to handle social networking views</h4> |
| <p> |
| To register your sync adapter to receive notifications when the user views a contact that's |
| managed by your sync adapter: |
| </p> |
| <ol> |
| <li> |
| Create a file named <code>contacts.xml</code> in your project's <code>res/xml/</code> |
| directory. If you already have this file, you can skip this step. |
| </li> |
| <li> |
| In this file, add the element |
| <code><ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"></code>. |
| If this element already exists, you can skip this step. |
| </li> |
| <li> |
| To register a service that is notified when the user opens a contact's detail page in |
| the device's contacts application, add the attribute |
| <code>viewContactNotifyService="<em>serviceclass</em>"</code> to the element, where |
| <code><em>serviceclass</em></code> is the fully-qualified classname of the service |
| that should receive the intent from the device's contacts application. For the notifier |
| service, use a class that extends {@link android.app.IntentService}, to allow the service to |
| receive intents. The data in the incoming intent contains the content URI of the raw |
| contact the user clicked. From the notifier service, you can bind to and then call your |
| sync adapter to update the data for the raw contact. |
| </li> |
| </ol> |
| <p> |
| To register an activity to be called when the user clicks on a stream item or photo or both: |
| </p> |
| <ol> |
| <li> |
| Create a file named <code>contacts.xml</code> in your project's <code>res/xml/</code> |
| directory. If you already have this file, you can skip this step. |
| </li> |
| <li> |
| In this file, add the element |
| <code><ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"></code>. |
| If this element already exists, you can skip this step. |
| </li> |
| <li> |
| To register one of your activities to handle the user clicking on a stream item in the |
| device's contacts application, add the attribute |
| <code>viewStreamItemActivity="<em>activityclass</em>"</code> to the element, where |
| <code><em>activityclass</em></code> is the fully-qualified classname of the activity |
| that should receive the intent from the device's contacts application. |
| </li> |
| <li> |
| To register one of your activities to handle the user clicking on a stream photo in the |
| device's contacts application, add the attribute |
| <code>viewStreamItemPhotoActivity="<em>activityclass</em>"</code> to the element, where |
| <code><em>activityclass</em></code> is the fully-qualified classname of the activity |
| that should receive the intent from the device's contacts application. |
| </li> |
| </ol> |
| <p> |
| The <code><ContactsAccountType></code> element is described in more detail in the |
| section <a href="#SocialStreamAcctType"><ContactsAccountType> element</a>. |
| </p> |
| <p> |
| The incoming intent contains the content URI of the item or photo that the user clicked. |
| To have separate activities for text items and for photos, use both attributes in the same file. |
| </p> |
| <h4>Interacting with your social networking service</h4> |
| <p> |
| Users don't have to leave the device's contacts application to invite a contact to your social |
| networking site. Instead, you can have the device's contacts app send an intent for inviting the |
| contact to one of your activities. To set this up: |
| </p> |
| <ol> |
| <li> |
| Create a file named <code>contacts.xml</code> in your project's <code>res/xml/</code> |
| directory. If you already have this file, you can skip this step. |
| </li> |
| <li> |
| In this file, add the element |
| <code><ContactsAccountType xmlns:android="http://schemas.android.com/apk/res/android"></code>. |
| If this element already exists, you can skip this step. |
| </li> |
| <li> |
| Add the following attributes: |
| <ul> |
| <li><code>inviteContactActivity="<em>activityclass</em>"</code></li> |
| <li> |
| <code>inviteContactActionLabel="@string/<em>invite_action_label</em>"</code> |
| </li> |
| </ul> |
| The <code><em>activityclass</em></code> value is the fully-qualified classname of the |
| activity that should receive the intent. The <code><em>invite_action_label</em></code> |
| value is a text string that's displayed in the <strong>Add Connection</strong> menu in the |
| device's contacts application. |
| </li> |
| </ol> |
| <p class="note"> |
| <strong>Note:</strong> <code>ContactsSource</code> is a deprecated tag name for |
| <code>ContactsAccountType</code>. |
| </p> |
| <h3 id="ContactsFile">contacts.xml reference</h3> |
| <p> |
| The file <code>contacts.xml</code> contains XML elements that control the interaction of your |
| sync adapter and application with the contacts application and the Contacts Provider. These |
| elements are described in the following sections. |
| </p> |
| <h4 id="SocialStreamAcctType"><ContactsAccountType> element</h4> |
| <p> |
| The <code><ContactsAccountType></code> element controls the interaction of your |
| application with the contacts application. It has the following syntax: |
| </p> |
| <pre> |
| <ContactsAccountType |
| xmlns:android="http://schemas.android.com/apk/res/android" |
| inviteContactActivity="<em>activity_name</em>" |
| inviteContactActionLabel="<em>invite_command_text</em>" |
| viewContactNotifyService="<em>view_notify_service</em>" |
| viewGroupActivity="<em>group_view_activity</em>" |
| viewGroupActionLabel="<em>group_action_text</em>" |
| viewStreamItemActivity="<em>viewstream_activity_name</em>" |
| viewStreamItemPhotoActivity="<em>viewphotostream_activity_name</em>"> |
| </pre> |
| <p> |
| <strong>contained in:</strong> |
| </p> |
| <p> |
| <code>res/xml/contacts.xml</code> |
| </p> |
| <p> |
| <strong>can contain:</strong> |
| </p> |
| <p> |
| <strong><code><ContactsDataKind></code></strong> |
| </p> |
| <p> |
| <strong>Description:</strong> |
| </p> |
| <p> |
| Declares Android components and UI labels that allow users to invite one of their contacts to |
| a social network, notify users when one of their social networking streams is updated, and |
| so forth. |
| </p> |
| <p> |
| Notice that the attribute prefix <code>android:</code> is not necessary for the attributes |
| of <code><ContactsAccountType></code>. |
| </p> |
| <p> |
| <strong>Attributes:</strong> |
| </p> |
| <dl> |
| <dt>{@code inviteContactActivity}</dt> |
| <dd> |
| The fully-qualified class name of the activity in your application that you want to |
| activate when the user selects <strong>Add connection</strong> from the device's |
| contacts application. |
| </dd> |
| <dt>{@code inviteContactActionLabel}</dt> |
| <dd> |
| A text string that is displayed for the activity specified in |
| {@code inviteContactActivity}, in the <strong>Add connection</strong> menu. |
| For example, you can use the string "Follow in my network". You can use a string resource |
| identifier for this label. |
| </dd> |
| <dt>{@code viewContactNotifyService}</dt> |
| <dd> |
| The fully-qualified class name of a service in your application that should receive |
| notifications when the user views a contact. This notification is sent by the device's |
| contacts application; it allows your application to postpone data-intensive operations |
| until they're needed. For example, your application can respond to this notification |
| by reading in and displaying the contact's high-resolution photo and most recent |
| social stream items. This feature is described in more detail in the section |
| <a href="#SocialStreamInteraction">Social stream interactions</a>. You can see an |
| example of the notification service in the <code>NotifierService.java</code> file in the |
| <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">SampleSyncAdapter</a> |
| sample app. |
| </dd> |
| <dt>{@code viewGroupActivity}</dt> |
| <dd> |
| The fully-qualified class name of an activity in your application that can display |
| group information. When the user clicks the group label in the device's contacts |
| application, the UI for this activity is displayed. |
| </dd> |
| <dt>{@code viewGroupActionLabel}</dt> |
| <dd> |
| The label that the contacts application displays for a UI control that allows |
| the user to look at groups in your application. |
| <p> |
| For example, if you install the Google+ application on your device and you sync |
| Google+ with the contacts application, you'll see Google+ circles listed as groups |
| in your contacts application's <strong>Groups</strong> tab. If you click on a |
| Google+ circle, you'll see people in that circle listed as a "group". At the top of |
| the display, you'll see a Google+ icon; if you click it, control switches to the |
| Google+ app. The contacts application does this with the |
| {@code viewGroupActivity}, using the Google+ icon as the value of |
| {@code viewGroupActionLabel}. |
| </p> |
| <p> |
| A string resource identifier is allowed for this attribute. |
| </p> |
| </dd> |
| <dt>{@code viewStreamItemActivity}</dt> |
| <dd> |
| The fully-qualified class name of an activity in your application that the device's |
| contacts application launches when the user clicks a stream item for a raw contact. |
| </dd> |
| <dt>{@code viewStreamItemPhotoActivity}</dt> |
| <dd> |
| The fully-qualified class name of an activity in your application that the device's |
| contacts application launches when the user clicks a photo in the stream item |
| for a raw contact. |
| </dd> |
| </dl> |
| <h4 id="SocialStreamDataKind"><ContactsDataKind> element</h4> |
| <p> |
| The <code><ContactsDataKind></code> element controls the display of your application's |
| custom data rows in the contacts application's UI. It has the following syntax: |
| </p> |
| <pre> |
| <ContactsDataKind |
| android:mimeType="<em>MIMEtype</em>" |
| android:icon="<em>icon_resources</em>" |
| android:summaryColumn="<em>column_name</em>" |
| android:detailColumn="<em>column_name</em>"> |
| </pre> |
| <p> |
| <strong>contained in:</strong> |
| </p> |
| <code><ContactsAccountType></code> |
| <p> |
| <strong>Description:</strong> |
| </p> |
| <p> |
| Use this element to have the contacts application display the contents of a custom data row as |
| part of the details of a raw contact. Each <code><ContactsDataKind></code> child element |
| of <code><ContactsAccountType></code> represents a type of custom data row that your sync |
| adapter adds to the {@link android.provider.ContactsContract.Data} table. Add one |
| <code><ContactsDataKind></code> element for each custom MIME type you use. You don't have |
| to add the element if you have a custom data row for which you don't want to display data. |
| </p> |
| <p> |
| <strong>Attributes:</strong> |
| </p> |
| <dl> |
| <dt>{@code android:mimeType}</dt> |
| <dd> |
| The custom MIME type you've defined for one of your custom data row types in the |
| {@link android.provider.ContactsContract.Data} table. For example, the value |
| <code>vnd.android.cursor.item/vnd.example.locationstatus</code> could be a custom |
| MIME type for a data row that records a contact's last known location. |
| </dd> |
| <dt>{@code android:icon}</dt> |
| <dd> |
| An Android |
| <a href="{@docRoot}guide/topics/resources/drawable-resource.html">drawable resource</a> |
| that the contacts application displays next to your data. Use this to indicate to the |
| user that the data comes from your service. |
| </dd> |
| <dt>{@code android:summaryColumn}</dt> |
| <dd> |
| The column name for the first of two values retrieved from the data row. The |
| value is displayed as the first line of the entry for this data row. The first line is |
| intended to be used as a summary of the data, but that is optional. See also |
| <a href="#detailColumn">android:detailColumn</a>. |
| </dd> |
| <dt>{@code android:detailColumn}</dt> |
| <dd> |
| The column name for the second of two values retrieved from the data row. The value is |
| displayed as the second line of the entry for this data row. See also |
| {@code android:summaryColumn}. |
| </dd> |
| </dl> |
| <h2 id="AdditionalFeatures">Additional Contacts Provider Features</h2> |
| <p> |
| Besides the main features described in previous sections, the Contacts Provider offers |
| these useful features for working with contacts data: |
| </p> |
| <ul> |
| <li>Contact groups</li> |
| <li>Photo features</li> |
| </ul> |
| <h3 id="Groups">Contact groups</h3> |
| <p> |
| The Contacts Provider can optionally label collections of related contacts with |
| <strong>group</strong> data. If the server associated with a user account |
| wants to maintain groups, the sync adapter for the account's account type should transfer |
| groups data between the Contacts Provider and the server. When users add a new contact to the |
| server and then put this contact in a new group, the sync adapter must add the new group |
| to the {@link android.provider.ContactsContract.Groups} table. The group or groups a raw |
| contact belongs to are stored in the {@link android.provider.ContactsContract.Data} table, using |
| the {@link android.provider.ContactsContract.CommonDataKinds.GroupMembership} MIME type. |
| </p> |
| <p> |
| If you're designing a sync adapter that will add raw contact data from |
| server to the Contacts Provider, and you aren't using groups, then you need to tell the |
| Provider to make your data visible. In the code that is executed when a user adds an account |
| to the device, update the {@link android.provider.ContactsContract.Settings} |
| row that the Contacts Provider adds for the account. In this row, set the value of the |
| {@link android.provider.ContactsContract.SettingsColumns#UNGROUPED_VISIBLE |
| Settings.UNGROUPED_VISIBLE} column to 1. When you do this, the Contacts Provider will always |
| make your contacts data visible, even if you don't use groups. |
| </p> |
| <h3 id="Photos">Contact photos</h3> |
| <p> |
| The {@link android.provider.ContactsContract.Data} table stores photos as rows with MIME type |
| {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE |
| Photo.CONTENT_ITEM_TYPE}. The row's |
| {@link android.provider.ContactsContract.RawContactsColumns#CONTACT_ID} column is linked to the |
| {@link android.provider.BaseColumns#_ID} column of the raw contact to which it belongs. |
| The class {@link android.provider.ContactsContract.Contacts.Photo} defines a sub-table of |
| {@link android.provider.ContactsContract.Contacts} containing photo information for a contact's |
| primary photo, which is the primary photo of the contact's primary raw contact. Similarly, |
| the class {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} defines a sub-table |
| of {@link android.provider.ContactsContract.RawContacts} containing photo information for a |
| raw contact's primary photo. |
| </p> |
| <p> |
| The reference documentation for {@link android.provider.ContactsContract.Contacts.Photo} and |
| {@link android.provider.ContactsContract.RawContacts.DisplayPhoto} contain examples of |
| retrieving photo information. There is no convenience class for retrieving the primary |
| thumbnail for a raw contact, but you can send a query to the |
| {@link android.provider.ContactsContract.Data} table, selecting on the raw contact's |
| {@link android.provider.BaseColumns#_ID}, the |
| {@link android.provider.ContactsContract.CommonDataKinds.Photo#CONTENT_ITEM_TYPE |
| Photo.CONTENT_ITEM_TYPE}, and the {@link android.provider.ContactsContract.DataColumns#IS_PRIMARY} |
| column to find the raw contact's primary photo row. |
| </p> |
| <p> |
| Social stream data for a person may also include photos. These are stored in the |
| android.provider.ContactsContract.StreamItemPhotos table, which is described in more |
| detail in the section <a href="#StreamPhotos">Social stream photos</a>. |
| </p> |