2362 lines
110 KiB
Plaintext
2362 lines
110 KiB
Plaintext
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>{@link 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.Data#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.Data#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 {@link android.Manifest.permission#READ_PROFILE} and
|
|
{@link 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
|
|
{@link 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 {@link android.provider.ContactsContract.StreamItems} and
|
|
{@link 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
|
|
{@link 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>
|
|
{@link 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>
|
|
{@link 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>
|
|
{@link android.provider.ContactsContract.StreamItemsColumns#CONTACT_ID}: The
|
|
{@link android.provider.BaseColumns#_ID} value of the contact that this stream
|
|
item is associated with.
|
|
</li>
|
|
<li>
|
|
{@link android.provider.ContactsContract.StreamItemsColumns#CONTACT_LOOKUP_KEY}: The
|
|
{@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} value of the
|
|
contact this stream item is associated with.
|
|
</li>
|
|
<li>
|
|
{@link android.provider.ContactsContract.StreamItemsColumns#RAW_CONTACT_ID}: The
|
|
{@link android.provider.BaseColumns#_ID} value of the raw contact that this stream
|
|
item is associated with.
|
|
</li>
|
|
</ul>
|
|
</dd>
|
|
<dt>
|
|
{@link android.provider.ContactsContract.StreamItemsColumns#COMMENTS}
|
|
</dt>
|
|
<dd>
|
|
Optional. Stores summary information that you can display at the beginning of a stream item.
|
|
</dd>
|
|
<dt>
|
|
{@link 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>
|
|
{@link 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
|
|
{@link android.provider.ContactsContract.StreamItemsColumns#RES_ICON},
|
|
{@link android.provider.ContactsContract.StreamItemsColumns#RES_LABEL}, and
|
|
{@link android.provider.ContactsContract.StreamItemsColumns#RES_PACKAGE} to link to resources
|
|
in your application.
|
|
</p>
|
|
<p>
|
|
The {@link android.provider.ContactsContract.StreamItems} table also contains the columns
|
|
{@link android.provider.ContactsContract.StreamItemsColumns#SYNC1} through
|
|
{@link android.provider.ContactsContract.StreamItemsColumns#SYNC4} for the exclusive use of
|
|
sync adapters.
|
|
</p>
|
|
<h3 id="StreamPhotos">Social stream photos</h3>
|
|
<p>
|
|
The {@link android.provider.ContactsContract.StreamItemPhotos} table stores photos associated
|
|
with a stream item. The table's
|
|
{@link android.provider.ContactsContract.StreamItemPhotosColumns#STREAM_ITEM_ID} column
|
|
links to values in the {@link android.provider.BaseColumns#_ID} column of
|
|
{@link android.provider.ContactsContract.StreamItems} table. Photo references are stored in the
|
|
table in these columns:
|
|
</p>
|
|
<dl>
|
|
<dt>
|
|
{@link 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 {@link android.provider.ContactsContract.StreamItemPhotosColumns#PHOTO_FILE_ID} or
|
|
{@link 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>
|
|
{@link 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>
|
|
{@link 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 {@link android.Manifest.permission#READ_SOCIAL_STREAM}. To
|
|
modify them, your application must have the permission
|
|
{@link android.Manifest.permission#WRITE_SOCIAL_STREAM}.
|
|
</li>
|
|
<li>
|
|
For the {@link 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
|
|
{@link android.provider.ContactsContract.StreamItemsColumns#TIMESTAMP}. To get the
|
|
limit, issue a query to the content URI
|
|
{@link 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
|
|
{@link android.provider.ContactsContract.StreamItems#MAX_ITEMS}.
|
|
</li>
|
|
</ul>
|
|
|
|
<p>
|
|
The class {@link android.provider.ContactsContract.StreamItems.StreamItemPhotos} defines a
|
|
sub-table of {@link 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 {@link android.provider.ContactsContract.StreamItems} and
|
|
{@link 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.Data#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
|
|
{@link android.provider.ContactsContract.StreamItemPhotos} table, which is described in more
|
|
detail in the section <a href="#StreamPhotos">Social stream photos</a>.
|
|
</p>
|