diff options
| -rw-r--r-- | core/java/android/provider/ContactsContract.java | 2489 |
1 files changed, 2422 insertions, 67 deletions
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java index 79044018fcf8..c3b0f1c91faa 100644 --- a/core/java/android/provider/ContactsContract.java +++ b/core/java/android/provider/ContactsContract.java @@ -29,6 +29,7 @@ import android.database.Cursor; import android.graphics.Rect; import android.net.Uri; import android.os.RemoteException; +import android.provider.ContactsContract.CommonDataKinds.Email; import android.text.TextUtils; import android.util.Pair; import android.view.View; @@ -37,8 +38,59 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; /** - * The contract between the contacts provider and applications. Contains definitions - * for the supported URIs and columns. These APIs supersede {@link Contacts}. + * <p> + * The contract between the contacts provider and applications. Contains + * definitions for the supported URIs and columns. These APIs supersede + * {@link Contacts}. + * </p> + * <h3>Overview</h3> + * <p> + * ContactsContract defines an extensible database of contact-related + * information. Contact information is stored in a three-tier data model: + * </p> + * <blockquote> + * <p> + * The {@link Data} table contains all kinds of personal data: phone numbers, + * email addresses etc. The list of data kinds that can be stored in this table + * is open-ended. There is a predefined set of common kinds, but any application + * can add its own data kinds. + * </p> + * <p> + * A row in the {@link RawContacts} table represents a set of Data describing a + * person and associated with a single account. + * </p> + * <p> + * A row in the {@link Contacts} table represents an aggregate of one or more + * RawContacts presumably describing the same person. + * </p> + * </blockquote> + * <p> + * Other tables include: + * </p> + * <blockquote> + * <p> + * {@link Groups}, which contains information about raw contact groups - the + * current API does not support the notion of groups spanning multiple accounts. + * </p> + * <p> + * {@link StatusUpdates}, which contains social status updates including IM + * availability. + * </p> + * <p> + * {@link AggregationExceptions}, which is used for manual aggregation and + * disaggregation of raw contacts + * </p> + * <p> + * {@link Settings}, which contains visibility and sync settings for accounts + * and groups. + * </p> + * <p> + * {@link SyncState}, which contains free-form data maintained on behalf of sync + * adapters + * </p> + * <p> + * {@link PhoneLookup}, which is used for quick caller-ID lookup</id> + * </blockquote> */ @SuppressWarnings("unused") public final class ContactsContract { @@ -128,6 +180,9 @@ public final class ContactsContract { * Generic columns for use by sync adapters. The specific functions of * these columns are private to the sync adapter. Other clients of the API * should not attempt to either read or write this column. + * + * @see RawContacts + * @see Groups */ protected interface BaseSyncColumns { @@ -144,6 +199,9 @@ public final class ContactsContract { /** * Columns that appear when each row of a table belongs to a specific * account, including sync information that an account may need. + * + * @see RawContacts + * @see Groups */ protected interface SyncColumns extends BaseSyncColumns { /** @@ -181,6 +239,13 @@ public final class ContactsContract { public static final String DIRTY = "dirty"; } + /** + * @see Contacts + * @see RawContacts + * @see ContactsContract.Data + * @see PhoneLookup + * @see ContactsContract.Contacts.AggregationSuggestions + */ protected interface ContactOptionsColumns { /** * The number of times a contact has been contacted @@ -214,6 +279,12 @@ public final class ContactsContract { public static final String SEND_TO_VOICEMAIL = "send_to_voicemail"; } + /** + * @see Contacts + * @see ContactsContract.Data + * @see PhoneLookup + * @see ContactsContract.Contacts.AggregationSuggestions + */ protected interface ContactsColumns { /** * The display name for the contact. @@ -247,6 +318,9 @@ public final class ContactsContract { public static final String LOOKUP_KEY = "lookup"; } + /** + * @see Contacts + */ protected interface ContactStatusColumns { /** * Contact presence status. See {@link StatusUpdates} for individual status @@ -270,7 +344,7 @@ public final class ContactsContract { /** * The package containing resources for this status: label and icon. - * <p>Type: NUMBER</p> + * <p>Type: TEXT</p> */ public static final String CONTACT_STATUS_RES_PACKAGE = "contact_status_res_package"; @@ -291,8 +365,194 @@ public final class ContactsContract { } /** - * Constants for the contacts table, which contains a record per group + * Constants for the contacts table, which contains a record per aggregate * of raw contacts representing the same person. + * <h3>Operations</h3> + * <dl> + * <dt><b>Insert</b></dt> + * <dd>A Contact cannot be created explicitly. When a raw contact is + * inserted, the provider will first try to find a Contact representing the + * same person. If one is found, the raw contact's + * {@link RawContacts#CONTACT_ID} column gets the _ID of the aggregate + * Contact. If no match is found, the provider automatically inserts a new + * Contact and puts its _ID into the {@link RawContacts#CONTACT_ID} column + * of the newly inserted raw contact.</dd> + * <dt><b>Update</b></dt> + * <dd>Only certain columns of Contact are modifiable: + * {@link #TIMES_CONTACTED}, {@link #LAST_TIME_CONTACTED}, {@link #STARRED}, + * {@link #CUSTOM_RINGTONE}, {@link #SEND_TO_VOICEMAIL}. Changing any of + * these columns on the Contact also changes them on all constituent raw + * contacts.</dd> + * <dt><b>Delete</b></dt> + * <dd>Be careful with deleting Contacts! Deleting an aggregate contact + * deletes all constituent raw contacts. The corresponding sync adapters + * will notice the deletions of their respective raw contacts and remove + * them from their back end storage.</dd> + * <dt><b>Query</b></dt> + * <dd> + * <ul> + * <li>If you need to read an individual contact, consider using + * {@link #CONTENT_LOOKUP_URI} instead of {@link #CONTENT_URI}.</li> + * <li>If you need to look up a contact by the phone number, use + * {@link PhoneLookup#CONTENT_FILTER_URI PhoneLookup.CONTENT_FILTER_URI}, + * which is optimized for this purpose.</li> + * <li>If you need to look up a contact by partial name, e.g. to produce + * filter-as-you-type suggestions, use the {@link #CONTENT_FILTER_URI} URI. + * <li>If you need to look up a contact by some data element like email + * address, nickname, etc, use a query against the {@link ContactsContract.Data} table. + * The result will contain contact ID, name etc. + * </ul> + * </dd> + * </dl> + * <h2>Columns</h2> + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>Contacts</th> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #_ID}</td> + * <td>read-only</td> + * <td>Row ID. Consider using {@link #LOOKUP_KEY} instead.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LOOKUP_KEY}</td> + * <td>read-only</td> + * <td>An opaque value that contains hints on how to find the contact if its + * row id changed as a result of a sync or aggregation.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #DISPLAY_NAME}</td> + * <td>read-only</td> + * <td>The display name for the contact. During aggregation display name is + * computed from display names of constituent raw contacts using a + * heuristic: a longer name or a name with more diacritic marks or more + * upper case characters is chosen.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #PHOTO_ID}</td> + * <td>read-only</td> + * <td>Reference to the row in the {@link ContactsContract.Data} table holding the photo. + * That row has the mime type + * {@link CommonDataKinds.Photo#CONTENT_ITEM_TYPE}. The value of this field + * is computed automatically based on the + * {@link CommonDataKinds.Photo#IS_SUPER_PRIMARY} field of the data rows of + * that mime type.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #IN_VISIBLE_GROUP}</td> + * <td>read-only</td> + * <td>An indicator of whether this contact is supposed to be visible in the + * UI. "1" if the contact has at least one raw contact that belongs to a + * visible group; "0" otherwise.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #HAS_PHONE_NUMBER}</td> + * <td>read-only</td> + * <td>An indicator of whether this contact has at least one phone number. + * "1" if there is at least one phone number, "0" otherwise.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TIMES_CONTACTED}</td> + * <td>read/write</td> + * <td>The number of times the contact has been contacted. See + * {@link #markAsContacted}. When raw contacts are aggregated, this field is + * computed automatically as the maximum number of times contacted among all + * constituent raw contacts. Setting this field automatically changes the + * corresponding field on all constituent raw contacts.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #LAST_TIME_CONTACTED}</td> + * <td>read/write</td> + * <td>The timestamp of the last time the contact was contacted. See + * {@link #markAsContacted}. Setting this field also automatically + * increments {@link #TIMES_CONTACTED}. When raw contacts are aggregated, + * this field is computed automatically as the latest time contacted of all + * constituent raw contacts. Setting this field automatically changes the + * corresponding field on all constituent raw contacts.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #STARRED}</td> + * <td>read/write</td> + * <td>An indicator for favorite contacts: '1' if favorite, '0' otherwise. + * When raw contacts are aggregated, this field is automatically computed: + * if any constituent raw contacts are starred, then this field is set to + * '1'. Setting this field automatically changes the corresponding field on + * all constituent raw contacts.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #CUSTOM_RINGTONE}</td> + * <td>read/write</td> + * <td>A custom ringtone associated with a contact. Typically this is the + * URI returned by an activity launched with the + * {@link android.media.RingtoneManager#ACTION_RINGTONE_PICKER} intent.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #SEND_TO_VOICEMAIL}</td> + * <td>read/write</td> + * <td>An indicator of whether calls from this contact should be forwarded + * directly to voice mail ('1') or not ('0'). When raw contacts are + * aggregated, this field is automatically computed: if <i>all</i> + * constituent raw contacts have SEND_TO_VOICEMAIL=1, then this field is set + * to '1'. Setting this field automatically changes the corresponding field + * on all constituent raw contacts.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #CONTACT_PRESENCE}</td> + * <td>read-only</td> + * <td>Contact IM presence status. See {@link StatusUpdates} for individual + * status definitions. Automatically computed as the highest presence of all + * constituent raw contacts. The provider may choose not to store this value + * in persistent storage. The expectation is that presence status will be + * updated on a regular basic.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #CONTACT_STATUS}</td> + * <td>read-only</td> + * <td>Contact's latest status update. Automatically computed as the latest + * of all constituent raw contacts' status updates.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #CONTACT_STATUS_TIMESTAMP}</td> + * <td>read-only</td> + * <td>The absolute time in milliseconds when the latest status was + * inserted/updated.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #CONTACT_STATUS_RES_PACKAGE}</td> + * <td>read-only</td> + * <td> The package containing resources for this status: label and icon.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #CONTACT_STATUS_LABEL}</td> + * <td>read-only</td> + * <td>The resource ID of the label describing the source of contact status, + * e.g. "Google Talk". This resource is scoped by the + * {@link #CONTACT_STATUS_RES_PACKAGE}.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #CONTACT_STATUS_ICON}</td> + * <td>read-only</td> + * <td>The resource ID of the icon for the source of contact status. This + * resource is scoped by the {@link #CONTACT_STATUS_RES_PACKAGE}.</td> + * </tr> + * </table> */ public static class Contacts implements BaseColumns, ContactsColumns, ContactOptionsColumns, ContactStatusColumns { @@ -365,7 +625,7 @@ public final class ContactsContract { /** * Build a {@link #CONTENT_LOOKUP_URI} lookup {@link Uri} using the - * given {@link android.provider.ContactsContract.Contacts#_ID} and {@link #LOOKUP_KEY}. + * given {@link ContactsContract.Contacts#_ID} and {@link #LOOKUP_KEY}. */ public static Uri getLookupUri(long contactId, String lookupKey) { return ContentUris.withAppendedId(Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, @@ -423,7 +683,7 @@ public final class ContactsContract { /** * The content:// style URI for this table joined with useful data from - * {@link Data}, filtered to include only starred contacts + * {@link ContactsContract.Data}, filtered to include only starred contacts * and the most frequently contacted contacts. */ public static final Uri CONTENT_STREQUENT_URI = Uri.withAppendedPath( @@ -461,7 +721,7 @@ public final class ContactsContract { /** * A sub-directory of a single contact that contains all of the constituent raw contact - * {@link Data} rows. + * {@link ContactsContract.Data} rows. */ public static final class Data implements BaseColumns, DataColumns { /** @@ -476,10 +736,33 @@ public final class ContactsContract { } /** - * A sub-directory of a single contact aggregate that contains all aggregation suggestions - * (other contacts). The aggregation suggestions are computed based on approximate - * data matches with this contact. + * <p> + * A <i>read-only</i> sub-directory of a single contact aggregate that + * contains all aggregation suggestions (other contacts). The + * aggregation suggestions are computed based on approximate data + * matches with this contact. + * </p> + * <p> + * <i>Note: this query may be expensive! If you need to use it in bulk, + * make sure the user experience is acceptable when the query runs for a + * long time.</i> + * <p> + * Usage example: + * + * <pre> + * Uri uri = Contacts.CONTENT_URI.buildUpon() + * .appendEncodedPath(String.valueOf(contactId)) + * .appendPath(Contacts.AggregationSuggestions.CONTENT_DIRECTORY) + * .appendQueryParameter("limit", "3") + * .build() + * Cursor cursor = getContentResolver().query(suggestionsUri, + * new String[] {Contacts.DISPLAY_NAME, Contacts._ID, Contacts.LOOKUP_KEY}, + * null, null, null); + * </pre> + * + * </p> */ + // TODO: add ContactOptionsColumns, ContactStatusColumns public static final class AggregationSuggestions implements BaseColumns, ContactsColumns { /** * No public constructor since this is a utility class @@ -495,8 +778,40 @@ public final class ContactsContract { } /** - * A sub-directory of a single contact that contains the contact's primary photo. + * A <i>read-only</i> sub-directory of a single contact that contains + * the contact's primary photo. + * <p> + * Usage example: + * + * <pre> + * public InputStream openPhoto(long contactId) { + * Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); + * Uri photoUri = Uri.withAppendedPath(contactUri, Contacts.Photo.CONTENT_DIRECTORY); + * Cursor cursor = getContentResolver().query(photoUri, + * new String[] {Contacts.Photo.PHOTO}, null, null, null); + * if (cursor == null) { + * return null; + * } + * try { + * if (cursor.moveToFirst()) { + * byte[] data = cursor.getBlob(0); + * if (data != null) { + * return new ByteArrayInputStream(data); + * } + * } + * } finally { + * cursor.close(); + * } + * return null; + * } + * </pre> + * + * </p> + * <p>You should also consider using the convenience method + * {@link ContactsContract.Contacts#openContactPhotoInputStream(ContentResolver, Uri)} + * </p> */ + // TODO: change DataColumns to DataColumnsWithJoins public static final class Photo implements BaseColumns, DataColumns { /** * no public constructor since this is a utility class @@ -507,6 +822,15 @@ public final class ContactsContract { * The directory twig for this sub-table */ public static final String CONTENT_DIRECTORY = "photo"; + + /** + * Thumbnail photo of the raw contact. This is the raw bytes of an image + * that could be inflated using {@link android.graphics.BitmapFactory}. + * <p> + * Type: BLOB + * @hide TODO: Unhide in a separate CL + */ + public static final String PHOTO = DATA15; } /** @@ -542,7 +866,7 @@ public final class ContactsContract { protected interface RawContactsColumns { /** - * A reference to the {@link android.provider.ContactsContract.Contacts#_ID} that this + * A reference to the {@link ContactsContract.Contacts#_ID} that this * data belongs to. * <P>Type: INTEGER</P> */ @@ -580,6 +904,315 @@ public final class ContactsContract { * Constants for the raw contacts table, which contains the base contact * information per sync source. Sync adapters and contact management apps * are the primary consumers of this API. + * <h3>Operations</h3> + * <dl> + * <dt><b>Insert</b></dt> + * <dd>There are two mechanisms that can be used to insert a raw contact: incremental and + * batch. The incremental method is more traditional but less efficient. It should be used + * only if the constituent data rows are unavailable at the time the raw contact is created: + * <pre> + * ContentValues values = new ContentValues(); + * values.put(RawContacts.ACCOUNT_TYPE, accountType); + * values.put(RawContacts.ACCOUNT_NAME, accountName); + * Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values); + * long rawContactId = ContentUris.parseId(rawContactUri); + * </pre> + * <p> + * Once data rows are available, insert those. For example, here's how you would insert + * a name: + * + * <pre> + * values.clear(); + * values.put(Data.RAW_CONTACT_ID, rawContactId); + * values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); + * values.put(StructuredName.DISPLAY_NAME, "Mike Sullivan"); + * getContentResolver().insert(Data.CONTENT_URI, values); + * </pre> + * </p> + * <p> + * The batch method is by far preferred. It inserts the raw contact and its + * constituent data rows in a single database transaction + * and causes at most one aggregation pass. + * <pre> + * ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); + * int rawContactInsertIndex = ops.size(); + * ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) + * .withValue(RawContacts.ACCOUNT_TYPE, accountType) + * .withValue(RawContacts.ACCOUNT_NAME, accountName) + * .build()); + * + * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI) + * .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex) + * .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) + * .withValue(StructuredName.DISPLAY_NAME, "Mike Sullivan") + * .build()); + * + * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); + * </pre> + * </p> + * <p> + * Please note the use of back reference in the construction of the + * {@link ContentProviderOperation}. It allows an operation to use the result of + * a previous operation by referring to it by its index in the batch. + * </p> + * <dt><b>Update</b></dt> + * <dd><p>Just as with insert, the update can be done incrementally or as a batch, the + * batch mode being the preferred method.</p></dd> + * <dt><b>Delete</b></dt> + * <dd><p>When a raw contact is deleted, all of its Data rows as well as StatusUpdates, + * AggregationExceptions, PhoneLookup rows are deleted automatically. When all raw + * contacts in a Contact are deleted, the Contact itself is also deleted automatically. + * </p> + * <p> + * The invocation of {@code resolver.delete(...)}, does not physically delete + * a raw contacts row. It sets the {@link #DELETED} flag on the raw contact and + * removes the raw contact from its aggregate contact. + * The sync adapter then deletes the raw contact from the server and + * finalizes phone-side deletion by calling {@code resolver.delete(...)} + * again and passing the {@link #CALLER_IS_SYNCADAPTER} query parameter.<p> + * <p>Some sync adapters are read-only, meaning that they only sync server-side + * changes to the phone, but not the reverse. If one of those raw contacts + * is marked for deletion, it will remain on the phone. However it will be + * effectively invisible, because it will not be part of any aggregate contact. + * </dd> + * <dt><b>Query</b></dt> + * <dd> + * <p> + * Finding all raw contacts in a Contact is easy: + * <pre> + * Cursor c = getContentResolver().query(RawContacts.CONTENT_URI, + * new String[]{RawContacts._ID}, + * RawContacts.CONTACT_ID + "=?", + * new String[]{String.valueOf(contactId)}, null); + * </pre> + * </p> + * <p> + * There are two ways to find raw contacts within a specific account, + * you can either put the account name and type in the selection or pass them as query + * parameters. The latter approach is preferable, especially when you can reuse the + * URI: + * <pre> + * Uri rawContactUri = RawContacts.URI.buildUpon() + * .appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName) + * .appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType) + * .build(); + * Cursor c1 = getContentResolver().query(rawContactUri, + * RawContacts.STARRED + "<>0", null, null, null); + * ... + * Cursor c2 = getContentResolver().query(rawContactUri, + * RawContacts.DELETED + "<>0", null, null, null); + * </pre> + * </p> + * <p>The best way to read a raw contact along with all the data associated with it is + * by using the {@link Entity} directory. If the raw contact has data rows, + * the Entity cursor will contain a row for each data row. If the raw contact has no + * data rows, the cursor will still contain one row with the raw contact-level information. + * <pre> + * Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); + * Uri entityUri = Uri.withAppendedPath(rawContactUri, Entity.CONTENT_DIRECTORY); + * Cursor c = getContentResolver().query(entityUri, + * new String[]{RawContacts.SOURCE_ID, Entity.DATA_ID, Entity.MIMETYPE, Entity.DATA1}, + * null, null, null); + * try { + * while (c.moveToNext()) { + * String sourceId = c.getString(0); + * if (!c.isNull(1)) { + * String mimeType = c.getString(2); + * String data = c.getString(3); + * ... + * } + * } + * } finally { + * c.close(); + * } + * </pre> + * </p> + * </dd> + * </dl> + * <h3>Aggregation</h3> + * <p> + * As soon as a raw contact is inserted or whenever its constituent data + * changes, the provider will check if the raw contact matches other + * existing raw contacts and if so will aggregate it with those. From the + * data standpoint, aggregation is reflected in the change of the + * {@link #CONTACT_ID} field, which is the reference to the aggregate contact. + * </p> + * <p> + * See also {@link AggregationExceptions} for a mechanism to control + * aggregation programmatically. + * </p> + * <h2>Columns</h2> + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>RawContacts</th> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #_ID}</td> + * <td>read-only</td> + * <td>Row ID. Sync adapter should try to preserve row IDs during updates. In other words, + * it would be a really bad idea to delete and reinsert a raw contact. A sync adapter should + * always do an update instead.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #CONTACT_ID}</td> + * <td>read-only</td> + * <td>A reference to the {@link ContactsContract.Contacts#_ID} that this raw contact belongs + * to. Raw contacts are linked to contacts by the aggregation process, which can be controlled + * by the {@link #AGGREGATION_MODE} field and {@link AggregationExceptions}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #AGGREGATION_MODE}</td> + * <td>read/write</td> + * <td>A mechanism that allows programmatic control of the aggregation process. The allowed + * values are {@link #AGGREGATION_MODE_DEFAULT}, {@link #AGGREGATION_MODE_DISABLED} + * and {@link #AGGREGATION_MODE_SUSPENDED}. See also {@link AggregationExceptions}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #DELETED}</td> + * <td>read/write</td> + * <td>The "deleted" flag: "0" by default, "1" if the row has been marked + * for deletion. When {@link android.content.ContentResolver#delete} is + * called on a raw contact, it is marked for deletion and removed from its + * aggregate contact. The sync adaptor deletes the raw contact on the server and + * then calls ContactResolver.delete once more, this time passing the + * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize + * the data removal.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TIMES_CONTACTED}</td> + * <td>read/write</td> + * <td>The number of times the contact has been contacted. To have an effect + * on the corresponding value of the aggregate contact, this field + * should be set at the time the raw contact is inserted. + * See {@link ContactsContract.Contacts#markAsContacted}.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #LAST_TIME_CONTACTED}</td> + * <td>read/write</td> + * <td>The timestamp of the last time the contact was contacted. To have an effect + * on the corresponding value of the aggregate contact, this field + * should be set at the time the raw contact is inserted. + * See {@link ContactsContract.Contacts#markAsContacted}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #STARRED}</td> + * <td>read/write</td> + * <td>An indicator for favorite contacts: '1' if favorite, '0' otherwise. + * Changing this field immediately effects the corresponding aggregate contact: + * if any raw contacts in that aggregate contact are starred, then the contact + * itself is marked as starred.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #CUSTOM_RINGTONE}</td> + * <td>read/write</td> + * <td>A custom ringtone associated with a raw contact. Typically this is the + * URI returned by an activity launched with the + * {@link android.media.RingtoneManager#ACTION_RINGTONE_PICKER} intent. + * To have an effect on the corresponding value of the aggregate contact, this field + * should be set at the time the raw contact is inserted. To set a custom + * ringtone on a contact, use the field {@link ContactsContract.Contacts#CUSTOM_RINGTONE} + * instead.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #SEND_TO_VOICEMAIL}</td> + * <td>read/write</td> + * <td>An indicator of whether calls from this raw contact should be forwarded + * directly to voice mail ('1') or not ('0'). To have an effect + * on the corresponding value of the aggregate contact, this field + * should be set at the time the raw contact is inserted.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #ACCOUNT_NAME}</td> + * <td>read/write-once</td> + * <td>The name of the account instance to which this row belongs, which when paired with + * {@link #ACCOUNT_TYPE} identifies a specific account. It should be set at the time + * the raw contact is inserted and never changed afterwards.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #ACCOUNT_TYPE}</td> + * <td>read/write-once</td> + * <td>The type of account to which this row belongs, which when paired with + * {@link #ACCOUNT_NAME} identifies a specific account. It should be set at the time + * the raw contact is inserted and never changed afterwards.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #SOURCE_ID}</td> + * <td>read/write</td> + * <td>String that uniquely identifies this row to its source account. + * Typically it is set at the time the raw contact is inserted and never + * changed afterwards. The one notable exception is a new raw contact: it + * will have an account name and type, but no source id. This should + * indicated to the sync adapter that a new contact needs to be created + * server-side and its ID stored in the corresponding SOURCE_ID field on + * the phone. + * </td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #VERSION}</td> + * <td>read-only</td> + * <td>Version number that is updated whenever this row or its related data + * changes. This field can be used for optimistic locking of a raw contact. + * </td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #DIRTY}</td> + * <td>read/write</td> + * <td>Flag indicating that {@link #VERSION} has changed, and this row needs + * to be synchronized by its owning account. The value is set to "1" automatically + * whenever the raw contact changes, unless the URI has the + * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter specified. + * The sync adapter should always supply this query parameter to prevent + * unnecessary synchronization: user changes some data on the server, + * the sync adapter updates the contact on the phone (without the + * CALLER_IS_SYNCADAPTER flag) flag, which sets the DIRTY flag, + * which triggers a sync to bring the changes to the server. + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #SYNC1}</td> + * <td>read/write</td> + * <td>Generic column for use by sync adapters. Content provider + * stores this information on behalf of the sync adapter but does not + * interpret it in any way. + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #SYNC2}</td> + * <td>read/write</td> + * <td>Generic column for use by sync adapters. + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #SYNC3}</td> + * <td>read/write</td> + * <td>Generic column for use by sync adapters. + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #SYNC4}</td> + * <td>read/write</td> + * <td>Generic column for use by sync adapters. + * </td> + * </tr> + * </table> */ public static final class RawContacts implements BaseColumns, RawContactsColumns, ContactOptionsColumns, SyncColumns { @@ -613,6 +1246,7 @@ public final class ContactsContract { /** * Aggregation mode: aggregate at the time the raw contact is inserted/updated. + * TODO: deprecate. Aggregation is now synchronous, this value is a no-op */ public static final int AGGREGATION_MODE_IMMEDIATE = 1; @@ -658,8 +1292,9 @@ public final class ContactsContract { } /** - * A sub-directory of a single raw contact that contains all of their {@link Data} rows. - * To access this directory append {@link Data#CONTENT_DIRECTORY} to the contact URI. + * A sub-directory of a single raw contact that contains all of their + * {@link ContactsContract.Data} rows. To access this directory + * append {@link Data#CONTENT_DIRECTORY} to the contact URI. */ public static final class Data implements BaseColumns, DataColumns { /** @@ -675,8 +1310,27 @@ public final class ContactsContract { } /** - * A sub-directory of a single raw contact that contains all of their {@link Data} rows. - * To access this directory append {@link Entity#CONTENT_DIRECTORY} to the contact URI. + * <p> + * A sub-directory of a single raw contact that contains all of their + * {@link ContactsContract.Data} rows. To access this directory append + * {@link Entity#CONTENT_DIRECTORY} to the contact URI. See + * {@link RawContactsEntity} for a stand-alone table containing the same + * data. + * </p> + * <p> + * The Entity directory is similar to the {@link RawContacts.Data} + * directory but with two important differences: + * <ul> + * <li>Entity has different ID fields: {@link #_ID} for the raw contact + * and {@link #DATA_ID} for the data rows.</li> + * <li>Entity always contains at least one row, even if there are no + * actual data rows. In this case the {@link #DATA_ID} field will be + * null.</li> + * </ul> + * Using Entity should preferred to using two separate queries: + * RawContacts followed by Data. The reason is that Entity reads all + * data for a raw contact in one transaction, so there is no possibility + * of the data changing between the two queries. */ public static final class Entity implements BaseColumns, DataColumns { /** @@ -699,6 +1353,12 @@ public final class ContactsContract { } } + /** + * Social status update columns. + * + * @see StatusUpdates + * @see ContactsContract.Data + */ protected interface StatusColumns extends Im.CommonPresenceColumns { /** * Contact's latest presence level. @@ -739,6 +1399,11 @@ public final class ContactsContract { public static final String STATUS_ICON = "status_icon"; } + /** + * Columns in the Data table. + * + * @see ContactsContract.Data + */ protected interface DataColumns { /** * The package name to use when creating {@link Resources} objects for @@ -824,7 +1489,9 @@ public final class ContactsContract { } /** - * Combines all columns returned by {@link Data} table queries. + * Combines all columns returned by {@link ContactsContract.Data} table queries. + * + * @see ContactsContract.Data */ protected interface DataColumnsWithJoins extends BaseColumns, DataColumns, StatusColumns, RawContactsColumns, ContactsColumns, ContactOptionsColumns, ContactStatusColumns { @@ -832,10 +1499,468 @@ public final class ContactsContract { } /** - * Constants for the data table, which contains data points tied to a raw contact. - * For example, a phone number or email address. Each row in this table contains a type - * definition and some generic columns. Each data type can define the meaning for each of - * the generic columns. + * <p> + * Constants for the data table, which contains data points tied to a raw + * contact. For example, a phone number or email address. + * </p> + * <h3>Data kinds</h3> + * <p> + * Data is a generic table that can hold all kinds of data. Sync adapters + * and applications can introduce their own data kinds. The kind of data + * stored in a particular row is determined by the mime type in the row. + * Fields from {@link #DATA1} through {@link #DATA15} are generic columns + * whose specific use is determined by the kind of data stored in the row. + * For example, if the data kind is + * {@link CommonDataKinds.Phone Phone.CONTENT_ITEM_TYPE}, then DATA1 stores the + * phone number, but if the data kind is + * {@link CommonDataKinds.Email Email.CONTENT_ITEM_TYPE}, then DATA1 stores the + * email address. + * </p> + * <p> + * ContactsContract defines a small number of common data kinds, e.g. + * {@link CommonDataKinds.Phone}, {@link CommonDataKinds.Email} etc. As a + * convenience, these classes define data kind specific aliases for DATA1 etc. + * For example, {@link CommonDataKinds.Phone Phone.NUMBER} is the same as + * {@link ContactsContract.Data Data.DATA1}. + * </p> + * <p> + * {@link #DATA1} is an indexed column and should be used for the data element that is + * expected to be most frequently used in query selections. For example, in the + * case of a row representing email addresses {@link #DATA1} should probably + * be used for the email address itself, while {@link #DATA2} etc can be + * used for auxiliary information like type of email address. + * <p> + * <p> + * By convention, {@link #DATA15} is used for storing BLOBs (binary data). + * </p> + * <p> + * Typically you should refrain from introducing new kinds of data for 3rd + * party account types. For example, if you add a data row for + * "favorite song" to a raw contact owned by a Google account, it will not + * get synced to the server, because the Google sync adapter does not know + * how to handle this data kind. Thus new data kinds are typically + * introduced along with new account types, i.e. new sync adapters. + * </p> + * <h3>Batch operations</h3> + * <p> + * Data rows can be inserted/updated/deleted using the traditional + * {@link ContentResolver#insert}, {@link ContentResolver#update} and + * {@link ContentResolver#delete} methods, however the newer mechanism based + * on a batch of {@link ContentProviderOperation} will prove to be a better + * choice in almost all cases. All operations in a batch are executed in a + * single transaction, which ensures that the phone-side and server-side + * state of a raw contact are always consistent. Also, the batch-based + * approach is far more efficient: not only are the database operations + * faster when executed in a single transaction, but also sending a batch of + * commands to the content provider saves a lot of time on context switching + * between your process and the process in which the content provider runs. + * </p> + * <p> + * The flip side of using batched operations is that a large batch may lock + * up the database for a long time preventing other applications from + * accessing data and potentially causing ANRs ("Application Not Responding" + * dialogs.) + * </p> + * <p> + * To avoid such lockups of the database, make sure to insert "yield points" + * in the batch. A yield point indicates to the content provider that before + * executing the next operation it can commit the changes that have already + * been made, yield to other requests, open another transaction and continue + * processing operations. A yield point will not automatically commit the + * transaction, but only if there is another request waiting on the + * database. Normally a sync adapter should insert a yield point at the + * beginning of each raw contact operation sequence in the batch. See + * {@link ContentProviderOperation.Builder#withYieldAllowed(boolean)}. + * </p> + * <h3>Operations</h3> + * <dl> + * <dt><b>Insert</b></dt> + * <dd> + * <p> + * An individual data row can be inserted using the traditional + * {@link ContentResolver#insert(Uri, ContentValues)} method. Multiple rows + * should always be inserted as a batch. + * </p> + * <p> + * An example of a traditional insert: + * <pre> + * ContentValues values = new ContentValues(); + * values.put(Data.RAW_CONTACT_ID, rawContactId); + * values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); + * values.put(Phone.NUMBER, "1-800-GOOG-411"); + * values.put(Phone.TYPE, Phone.TYPE_CUSTOM); + * values.put(Phone.LABEL, "free directory assistance"); + * Uri dataUri = getContentResolver().insert(Data.CONTENT_URI, values); + * </pre> + * <p> + * The same done using ContentProviderOperations: + * <pre> + * ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); + * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI) + * .withValue(Data.RAW_CONTACT_ID, rawContactId) + * .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE) + * .withValue(Phone.NUMBER, "1-800-GOOG-411") + * .withValue(Phone.TYPE, Phone.TYPE_CUSTOM) + * .withValue(Phone.LABEL, "free directory assistance") + * .build()); + * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); + * </pre> + * </p> + * <dt><b>Update</b></dt> + * <dd> + * <p> + * Just as with insert, update can be done incrementally or as a batch, + * the batch mode being the preferred method: + * <pre> + * ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); + * ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI) + * .withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)}) + * .withValue(Email.DATA, "somebody@android.com") + * .build()); + * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); + * </pre> + * </p> + * </dd> + * <dt><b>Delete</b></dt> + * <dd> + * <p> + * Just as with insert and update, deletion can be done either using the + * {@link ContentResolver#delete} method or using a ContentProviderOperation: + * <pre> + * ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); + * ops.add(ContentProviderOperation.newDelete(Data.CONTENT_URI) + * .withSelection(Data._ID + "=?", new String[]{String.valueOf(dataId)}) + * .build()); + * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); + * </pre> + * </p> + * </dd> + * <dt><b>Query</b></dt> + * <dd> + * <p> + * <dl> + * <dt>Finding all Data of a given type for a given contact</dt> + * <dd> + * <pre> + * Cursor c = getContentResolver().query(Data.CONTENT_URI, + * new String[] {Data._ID, Phone.NUMBER, Phone.TYPE, Phone.LABEL}, + * Data.CONTACT_ID + "=?" + " AND " + * + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'", + * new String[] {String.valueOf(contactId)}, null); + * </pre> + * </p> + * <p> + * </dd> + * <dt>Finding all Data of a given type for a given raw contact</dt> + * <dd> + * <pre> + * Cursor c = getContentResolver().query(Data.CONTENT_URI, + * new String[] {Data._ID, Phone.NUMBER, Phone.TYPE, Phone.LABEL}, + * Data.RAW_CONTACT_ID + "=?" + " AND " + * + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'", + * new String[] {String.valueOf(rawContactId)}, null); + * </pre> + * </dd> + * <dt>Finding all Data for a given raw contact</dt> + * <dd> + * Most sync adapters will want to read all data rows for a raw contact + * along with the raw contact itself. For that you should use the + * {@link RawContactsEntity}. See also {@link RawContacts}. + * </dd> + * </dl> + * </p> + * </dd> + * </dl> + * <h2>Columns</h2> + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>Data</th> + * </tr> + * <tr> + * <td style="width: 7em;">long</td> + * <td style="width: 20em;">{@link #_ID}</td> + * <td style="width: 5em;">read-only</td> + * <td>Row ID. Sync adapter should try to preserve row IDs during updates. In other words, + * it would be a bad idea to delete and reinsert a data rows. A sync adapter should + * always do an update instead.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #MIMETYPE}</td> + * <td>read/write-once</td> + * <td> + * <p>The MIME type of the item represented by this row. Examples of common + * MIME types are: + * <ul> + * <li>{@link CommonDataKinds.StructuredName StructuredName.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.Phone Phone.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.Email Email.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.Photo Photo.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.Organization Organization.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.Im Im.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.Nickname Nickname.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.Note Note.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.StructuredPostal StructuredPostal.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.GroupMembership GroupMembership.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.Website Website.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.Event Event.CONTENT_ITEM_TYPE}</li> + * <li>{@link CommonDataKinds.Relation Relation.CONTENT_ITEM_TYPE}</li> + * </ul> + * </p> + * </td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #RAW_CONTACT_ID}</td> + * <td>read/write-once</td> + * <td>A reference to the {@link RawContacts#_ID} that this data belongs to.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #CONTACT_ID}</td> + * <td>read-only</td> + * <td>A reference to the {@link ContactsContract.Contacts#_ID} that this data row belongs + * to. It is obtained through a join with RawContacts.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #IS_PRIMARY}</td> + * <td>read/write</td> + * <td>Whether this is the primary entry of its kind for the raw contact it belongs to. + * "1" if true, "0" if false.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #IS_SUPER_PRIMARY}</td> + * <td>read/write</td> + * <td>Whether this is the primary entry of its kind for the aggregate + * contact it belongs to. Any data record that is "super primary" must + * also be "primary".</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #DATA_VERSION}</td> + * <td>read-only</td> + * <td>The version of this data record. Whenever the data row changes + * the version goes up. This value is monotonically increasing.</td> + * </tr> + * <tr> + * <td>Any type</td> + * <td> + * {@link #DATA1}<br> + * {@link #DATA2}<br> + * {@link #DATA3}<br> + * {@link #DATA4}<br> + * {@link #DATA5}<br> + * {@link #DATA6}<br> + * {@link #DATA7}<br> + * {@link #DATA8}<br> + * {@link #DATA9}<br> + * {@link #DATA10}<br> + * {@link #DATA11}<br> + * {@link #DATA12}<br> + * {@link #DATA13}<br> + * {@link #DATA14}<br> + * {@link #DATA15} + * </td> + * <td>read/write</td> + * <td>Generic data columns, the meaning is {@link #MIMETYPE} specific.</td> + * </tr> + * <tr> + * <td>Any type</td> + * <td> + * {@link #SYNC1}<br> + * {@link #SYNC2}<br> + * {@link #SYNC3}<br> + * {@link #SYNC4} + * </td> + * <td>read/write</td> + * <td>Generic columns for use by sync adapters. For example, a Photo row + * may store the image URL in SYNC1, a status (not loaded, loading, loaded, error) + * in SYNC2, server-side version number in SYNC3 and error code in SYNC4.</td> + * </tr> + * </table> + * + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>Join with {@link StatusUpdates}</th> + * </tr> + * <tr> + * <td style="width: 7em;">int</td> + * <td style="width: 20em;">{@link #PRESENCE}</td> + * <td style="width: 5em;">read-only</td> + * <td>IM presence status linked to this data row. Compare with + * {@link #CONTACT_PRESENCE}, which contains the contact's presence across + * all IM rows. See {@link StatusUpdates} for individual status definitions. + * The provider may choose not to store this value + * in persistent storage. The expectation is that presence status will be + * updated on a regular basic. + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #STATUS}</td> + * <td>read-only</td> + * <td>Latest status update linked with this data row.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #STATUS_TIMESTAMP}</td> + * <td>read-only</td> + * <td>The absolute time in milliseconds when the latest status was + * inserted/updated for this data row.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #STATUS_RES_PACKAGE}</td> + * <td>read-only</td> + * <td>The package containing resources for this status: label and icon.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #STATUS_LABEL}</td> + * <td>read-only</td> + * <td>The resource ID of the label describing the source of status update linked + * to this data row. This resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #STATUS_ICON}</td> + * <td>read-only</td> + * <td>The resource ID of the icon for the source of the status update linked + * to this data row. This resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td> + * </tr> + * </table> + * + * <p> + * Columns from the associated raw contact are also available through an + * implicit join. + * </p> + * + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>Join with {@link RawContacts}</th> + * </tr> + * <tr> + * <td style="width: 7em;">int</td> + * <td style="width: 20em;">{@link #AGGREGATION_MODE}</td> + * <td style="width: 5em;">read-only</td> + * <td>See {@link RawContacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #DELETED}</td> + * <td>read-only</td> + * <td>See {@link RawContacts}.</td> + * </tr> + * </table> + * + * <p> + * Columns from the associated aggregated contact are also available through an + * implicit join. + * </p> + * + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>Join with {@link Contacts}</th> + * </tr> + * <tr> + * <td style="width: 7em;">String</td> + * <td style="width: 20em;">{@link #LOOKUP_KEY}</td> + * <td style="width: 5em;">read-only</td> + * <td>See {@link ContactsContract.Contacts}</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #DISPLAY_NAME}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #PHOTO_ID}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #IN_VISIBLE_GROUP}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #HAS_PHONE_NUMBER}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TIMES_CONTACTED}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #LAST_TIME_CONTACTED}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #STARRED}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #CUSTOM_RINGTONE}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #SEND_TO_VOICEMAIL}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #CONTACT_PRESENCE}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #CONTACT_STATUS}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #CONTACT_STATUS_TIMESTAMP}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #CONTACT_STATUS_RES_PACKAGE}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #CONTACT_STATUS_LABEL}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #CONTACT_STATUS_ICON}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * </table> */ public final static class Data implements DataColumnsWithJoins { /** @@ -859,7 +1984,7 @@ public final class ContactsContract { * * This flag is useful (currently) only for vCard exporter in Contacts app, which * needs to exclude "un-exportable" data from available data to export, while - * Contacts app itself has priviledge to access all data including "un-expotable" + * Contacts app itself has priviledge to access all data including "un-exportable" * ones and providers return all of them regardless of the callers' intention. * <P>Type: INTEGER</p> * @@ -872,7 +1997,7 @@ public final class ContactsContract { /** * Build a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI} * style {@link Uri} for the parent {@link android.provider.ContactsContract.Contacts} - * entry of the given {@link Data} entry. + * entry of the given {@link ContactsContract.Data} entry. */ public static Uri getContactLookupUri(ContentResolver resolver, Uri dataUri) { final Cursor cursor = resolver.query(dataUri, new String[] { @@ -894,8 +2019,141 @@ public final class ContactsContract { } /** - * Constants for the raw contacts entities table, which can be though of as an outer join - * of the raw_contacts table with the data table. + * <p> + * Constants for the raw contacts entities table, which can be though of as + * an outer join of the raw_contacts table with the data table. It is a strictly + * read-only table. + * </p> + * <p> + * If a raw contact has data rows, the RawContactsEntity cursor will contain + * a one row for each data row. If the raw contact has no data rows, the + * cursor will still contain one row with the raw contact-level information + * and nulls for data columns. + * + * <pre> + * Uri entityUri = ContentUris.withAppendedId(RawContactsEntity.CONTENT_URI, rawContactId); + * Cursor c = getContentResolver().query(entityUri, + * new String[]{ + * RawContactsEntity.SOURCE_ID, + * RawContactsEntity.DATA_ID, + * RawContactsEntity.MIMETYPE, + * RawContactsEntity.DATA1 + * }, null, null, null); + * try { + * while (c.moveToNext()) { + * String sourceId = c.getString(0); + * if (!c.isNull(1)) { + * String mimeType = c.getString(2); + * String data = c.getString(3); + * ... + * } + * } + * } finally { + * c.close(); + * } + * </pre> + * + * <h3>Columns</h3> + * RawContactsEntity has a combination of RawContact and Data columns. + * + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>RawContacts</th> + * </tr> + * <tr> + * <td style="width: 7em;">long</td> + * <td style="width: 20em;">{@link #_ID}</td> + * <td style="width: 5em;">read-only</td> + * <td>Raw contact row ID. See {@link RawContacts}.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #CONTACT_ID}</td> + * <td>read-only</td> + * <td>See {@link RawContacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #AGGREGATION_MODE}</td> + * <td>read-only</td> + * <td>See {@link RawContacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #DELETED}</td> + * <td>read-only</td> + * <td>See {@link RawContacts}.</td> + * </tr> + * </table> + * + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>Data</th> + * </tr> + * <tr> + * <td style="width: 7em;">long</td> + * <td style="width: 20em;">{@link #DATA_ID}</td> + * <td style="width: 5em;">read-only</td> + * <td>Data row ID. It will be null if the raw contact has no data rows.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #MIMETYPE}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Data}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #IS_PRIMARY}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Data}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #IS_SUPER_PRIMARY}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Data}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #DATA_VERSION}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Data}.</td> + * </tr> + * <tr> + * <td>Any type</td> + * <td> + * {@link #DATA1}<br> + * {@link #DATA2}<br> + * {@link #DATA3}<br> + * {@link #DATA4}<br> + * {@link #DATA5}<br> + * {@link #DATA6}<br> + * {@link #DATA7}<br> + * {@link #DATA8}<br> + * {@link #DATA9}<br> + * {@link #DATA10}<br> + * {@link #DATA11}<br> + * {@link #DATA12}<br> + * {@link #DATA13}<br> + * {@link #DATA14}<br> + * {@link #DATA15} + * </td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Data}.</td> + * </tr> + * <tr> + * <td>Any type</td> + * <td> + * {@link #SYNC1}<br> + * {@link #SYNC2}<br> + * {@link #SYNC3}<br> + * {@link #SYNC4} + * </td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Data}.</td> + * </tr> + * </table> */ public final static class RawContactsEntity implements BaseColumns, DataColumns, RawContactsColumns { @@ -938,6 +2196,9 @@ public final class ContactsContract { public static final String DATA_ID = "data_id"; } + /** + * @see PhoneLookup + */ protected interface PhoneLookupColumns { /** * The phone number as the user entered it. @@ -961,7 +2222,112 @@ public final class ContactsContract { /** * A table that represents the result of looking up a phone number, for * example for caller ID. To perform a lookup you must append the number you - * want to find to {@link #CONTENT_FILTER_URI}. + * want to find to {@link #CONTENT_FILTER_URI}. This query is highly + * optimized. + * <pre> + * Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber)); + * resolver.query(uri, new String[]{PhoneLookup.DISPLAY_NAME,... + * </pre> + * + * <h3>Columns</h3> + * + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>PhoneLookup</th> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #_ID}</td> + * <td>read-only</td> + * <td>Data row ID.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #NUMBER}</td> + * <td>read-only</td> + * <td>Phone number.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #TYPE}</td> + * <td>read-only</td> + * <td>Phone number type. See {@link CommonDataKinds.Phone}.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LABEL}</td> + * <td>read-only</td> + * <td>Custom label for the phone number. See {@link CommonDataKinds.Phone}.</td> + * </tr> + * </table> + * <p> + * Columns from the Contacts table are also available through a join. + * </p> + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>Join with {@link Contacts}</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LOOKUP_KEY}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #DISPLAY_NAME}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #PHOTO_ID}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #IN_VISIBLE_GROUP}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #HAS_PHONE_NUMBER}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TIMES_CONTACTED}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #LAST_TIME_CONTACTED}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #STARRED}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #CUSTOM_RINGTONE}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #SEND_TO_VOICEMAIL}</td> + * <td>read-only</td> + * <td>See {@link ContactsContract.Contacts}.</td> + * </tr> + * </table> */ public static final class PhoneLookup implements BaseColumns, PhoneLookupColumns, ContactsColumns, ContactOptionsColumns { @@ -973,10 +2339,9 @@ public final class ContactsContract { /** * The content:// style URI for this table. Append the phone number you want to lookup * to this URI and query it to perform a lookup. For example: - * - * {@code - * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_URI, phoneNumber); - * } + * <pre> + * Uri lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_URI, Uri.encode(phoneNumber)); + * </pre> */ public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(AUTHORITY_URI, "phone_lookup"); @@ -985,6 +2350,8 @@ public final class ContactsContract { /** * Additional data mixed in with {@link StatusColumns} to link * back to specific {@link ContactsContract.Data#_ID} entries. + * + * @see StatusUpdates */ protected interface PresenceColumns { @@ -995,6 +2362,7 @@ public final class ContactsContract { public static final String DATA_ID = "presence_data_id"; /** + * See {@link CommonDataKinds.Im} for a list of defined protocol constants. * <p>Type: NUMBER</p> */ public static final String PROTOCOL = "protocol"; @@ -1024,11 +2392,132 @@ public final class ContactsContract { } /** - * A status update is linked to a {@link Data} row and captures the user's latest status - * update via the corresponding source, e.g. "Having lunch" via "Google Talk". + * <p> + * A status update is linked to a {@link ContactsContract.Data} row and captures + * the user's latest status update via the corresponding source, e.g. + * "Having lunch" via "Google Talk". + * </p> + * <p> + * There are two ways a status update can be inserted: by explicitly linking + * it to a Data row using {@link #DATA_ID} or indirectly linking it to a data row + * using a combination of {@link #PROTOCOL} (or {@link #CUSTOM_PROTOCOL}) and + * {@link #IM_HANDLE}. There is no difference between insert and update, you can use + * either. + * </p> + * <p> + * You cannot use {@link ContentResolver#update} to change a status, but + * {@link ContentResolver#insert} will replace the latests status if it already + * exists. + * </p> + * <p> + * Use {@link ContentResolver#bulkInsert(Uri, ContentValues[])} to insert/update statuses + * for multiple contacts at once. + * </p> + * + * <h3>Columns</h3> + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>StatusUpdates</th> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #DATA_ID}</td> + * <td>read/write</td> + * <td>Reference to the {@link Data#_ID} entry that owns this presence. If this + * field is <i>not</i> specified, the provider will attempt to find a data row + * that matches the {@link #PROTOCOL} (or {@link #CUSTOM_PROTOCOL}) and + * {@link #IM_HANDLE} columns. + * </td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #PROTOCOL}</td> + * <td>read/write</td> + * <td>See {@link CommonDataKinds.Im} for a list of defined protocol constants.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #CUSTOM_PROTOCOL}</td> + * <td>read/write</td> + * <td>Name of the custom protocol. Should be supplied along with the {@link #PROTOCOL} value + * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}. Should be null or + * omitted if {@link #PROTOCOL} value is not + * {@link ContactsContract.CommonDataKinds.Im#PROTOCOL_CUSTOM}.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #IM_HANDLE}</td> + * <td>read/write</td> + * <td> The IM handle the presence item is for. The handle is scoped to + * {@link #PROTOCOL}.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #IM_ACCOUNT}</td> + * <td>read/write</td> + * <td>The IM account for the local user that the presence data came from.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #PRESENCE}</td> + * <td>read/write</td> + * <td>Contact IM presence status. The allowed values are: + * <p> + * <ul> + * <li>{@link #OFFLINE}</li> + * <li>{@link #INVISIBLE}</li> + * <li>{@link #AWAY}</li> + * <li>{@link #IDLE}</li> + * <li>{@link #DO_NOT_DISTURB}</li> + * <li>{@link #AVAILABLE}</li> + * </ul> + * </p> + * <p> + * Since presence status is inherently volatile, the content provider + * may choose not to store this field in long-term storage. + * </p> + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #STATUS}</td> + * <td>read/write</td> + * <td>Contact's latest status update, e.g. "having toast for breakfast"</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #STATUS_TIMESTAMP}</td> + * <td>read/write</td> + * <td>The absolute time in milliseconds when the status was + * entered by the user. If this value is not provided, the provider will follow + * this logic: if there was no prior status update, the value will be left as null. + * If there was a prior status update, the provider will default this field + * to the current time.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #STATUS_RES_PACKAGE}</td> + * <td>read/write</td> + * <td> The package containing resources for this status: label and icon.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #STATUS_LABEL}</td> + * <td>read/write</td> + * <td>The resource ID of the label describing the source of contact status, + * e.g. "Google Talk". This resource is scoped by the + * {@link #STATUS_RES_PACKAGE}.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #STATUS_ICON}</td> + * <td>read/write</td> + * <td>The resource ID of the icon for the source of contact status. This + * resource is scoped by the {@link #STATUS_RES_PACKAGE}.</td> + * </tr> + * </table> */ - // TODO make final as soon as Presence is removed - public static /*final*/ class StatusUpdates implements StatusColumns, PresenceColumns { + public static class StatusUpdates implements StatusColumns, PresenceColumns { /** * This utility class cannot be instantiated @@ -1088,13 +2577,17 @@ public final class ContactsContract { public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/status-update"; } + /** + * @deprecated This old name was never meant to be made public. Do not use. + */ @Deprecated public static final class Presence extends StatusUpdates { } /** - * Container for definitions of common data types stored in the {@link Data} table. + * Container for definitions of common data types stored in the {@link ContactsContract.Data} + * table. */ public static final class CommonDataKinds { /** @@ -1144,7 +2637,69 @@ public final class ContactsContract { } /** - * Parts of the name. + * A data kind representing the contact's proper name. You can use all + * columns defined for {@link ContactsContract.Data} as well as the following aliases. + * + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th><th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #DISPLAY_NAME}</td> + * <td>{@link #DATA1}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #GIVEN_NAME}</td> + * <td>{@link #DATA2}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #FAMILY_NAME}</td> + * <td>{@link #DATA3}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #PREFIX}</td> + * <td>{@link #DATA4}</td> + * <td>Common prefixes in English names are "Mr", "Ms", "Dr" etc.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #MIDDLE_NAME}</td> + * <td>{@link #DATA5}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #SUFFIX}</td> + * <td>{@link #DATA6}</td> + * <td>Common suffixes in English names are "Sr", "Jr", "III" etc.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #PHONETIC_GIVEN_NAME}</td> + * <td>{@link #DATA7}</td> + * <td>Used for phonetic spelling of the name, e.g. Pinyin, Katakana, Hiragana</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #PHONETIC_MIDDLE_NAME}</td> + * <td>{@link #DATA8}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #PHONETIC_FAMILY_NAME}</td> + * <td>{@link #DATA9}</td> + * <td></td> + * </tr> + * </table> */ public static final class StructuredName implements DataColumnsWithJoins { /** @@ -1213,7 +2768,68 @@ public final class ContactsContract { } /** - * A nickname. + * <p>A data kind representing the contact's nickname. For example, for + * Bob Parr ("Mr. Incredible"): + * <pre> + * ArrayList<ContentProviderOperation> ops = Lists.newArrayList(); + * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI) + * .withValue(Data.RAW_CONTACT_ID, rawContactId) + * .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) + * .withValue(StructuredName.DISPLAY_NAME, "Bob Parr") + * .build()); + * + * ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI) + * .withValue(Data.RAW_CONTACT_ID, rawContactId) + * .withValue(Data.MIMETYPE, Nickname.CONTENT_ITEM_TYPE) + * .withValue(Nickname.NAME, "Mr. Incredible") + * .withValue(Nickname.TYPE, Nickname.TYPE_CUSTOM) + * .withValue(Nickname.LABEL, "Superhero") + * .build()); + * + * getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops); + * </pre> + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as well as the + * following aliases. + * </p> + * + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th><th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #NAME}</td> + * <td>{@link #DATA1}</td> + * <td></td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TYPE}</td> + * <td>{@link #DATA2}</td> + * <td> + * Allowed values are: + * <p> + * <ul> + * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li> + * <li>{@link #TYPE_DEFAULT}</li> + * <li>{@link #TYPE_OTHER_NAME}</li> + * <li>{@link #TYPE_MAINDEN_NAME}</li> + * <li>{@link #TYPE_SHORT_NAME}</li> + * <li>{@link #TYPE_INITIALS}</li> + * </ul> + * </p> + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LABEL}</td> + * <td>{@link #DATA3}</td> + * <td></td> + * </tr> + * </table> */ public static final class Nickname implements DataColumnsWithJoins, CommonColumns { /** @@ -1237,7 +2853,64 @@ public final class ContactsContract { } /** - * Common data definition for telephone numbers. + * <p> + * A data kind representing a telephone number. + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as + * well as the following aliases. + * </p> + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th> + * <th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #NUMBER}</td> + * <td>{@link #DATA1}</td> + * <td></td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TYPE}</td> + * <td>{@link #DATA2}</td> + * <td>Allowed values are: + * <p> + * <ul> + * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li> + * <li>{@link #TYPE_HOME}</li> + * <li>{@link #TYPE_MOBILE}</li> + * <li>{@link #TYPE_WORK}</li> + * <li>{@link #TYPE_FAX_WORK}</li> + * <li>{@link #TYPE_FAX_HOME}</li> + * <li>{@link #TYPE_PAGER}</li> + * <li>{@link #TYPE_OTHER}</li> + * <li>{@link #TYPE_CALLBACK}</li> + * <li>{@link #TYPE_CAR}</li> + * <li>{@link #TYPE_COMPANY_MAIN}</li> + * <li>{@link #TYPE_ISDN}</li> + * <li>{@link #TYPE_MAIN}</li> + * <li>{@link #TYPE_OTHER_FAX}</li> + * <li>{@link #TYPE_RADIO}</li> + * <li>{@link #TYPE_TELEX}</li> + * <li>{@link #TYPE_TTY_TDD}</li> + * <li>{@link #TYPE_WORK_MOBILE}</li> + * <li>{@link #TYPE_WORK_PAGER}</li> + * <li>{@link #TYPE_ASSISTANT}</li> + * <li>{@link #TYPE_MMS}</li> + * </ul> + * </p> + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LABEL}</td> + * <td>{@link #DATA3}</td> + * <td></td> + * </tr> + * </table> */ public static final class Phone implements DataColumnsWithJoins, CommonColumns { /** @@ -1365,7 +3038,48 @@ public final class ContactsContract { } /** - * Common data definition for email addresses. + * <p> + * A data kind representing an email address. + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as + * well as the following aliases. + * </p> + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th> + * <th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #DATA}</td> + * <td>{@link #DATA1}</td> + * <td>Email address itself.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TYPE}</td> + * <td>{@link #DATA2}</td> + * <td>Allowed values are: + * <p> + * <ul> + * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li> + * <li>{@link #TYPE_HOME}</li> + * <li>{@link #TYPE_WORK}</li> + * <li>{@link #TYPE_OTHER}</li> + * <li>{@link #TYPE_MOBILE}</li> + * </ul> + * </p> + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LABEL}</td> + * <td>{@link #DATA3}</td> + * <td></td> + * </tr> + * </table> */ public static final class Email implements DataColumnsWithJoins, CommonColumns { /** @@ -1390,22 +3104,50 @@ public final class ContactsContract { "emails"); /** + * <p> * The content:// style URL for looking up data rows by email address. The * lookup argument, an email address, should be passed as an additional path segment * after this URI. + * </p> + * <p>Example: + * <pre> + * Uri uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(email)); + * Cursor c = getContentResolver().query(uri, + * new String[]{Email.CONTACT_ID, Email.DISPLAY_NAME, Email.DATA}, + * null, null, null); + * </pre> + * </p> */ public static final Uri CONTENT_LOOKUP_URI = Uri.withAppendedPath(CONTENT_URI, "lookup"); /** + * <p> * The content:// style URL for email lookup using a filter. The filter returns * records of MIME type {@link #CONTENT_ITEM_TYPE}. The filter is applied * to display names as well as email addresses. The filter argument should be passed * as an additional path segment after this URI. + * </p> + * <p>The query in the following example will return "Robert Parr (bob@incredibles.com)" + * as well as "Bob Parr (incredible@android.com)". + * <pre> + * Uri uri = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode("bob")); + * Cursor c = getContentResolver().query(uri, + * new String[]{Email.DISPLAY_NAME, Email.DATA}, + * null, null, null); + * </pre> + * </p> */ public static final Uri CONTENT_FILTER_URI = Uri.withAppendedPath(CONTENT_URI, "filter"); + /** + * The email address. + * <P>Type: TEXT</P> + * @hide TODO: Unhide in a separate CL + */ + public static final String ADDRESS = DATA1; + public static final int TYPE_HOME = 1; public static final int TYPE_WORK = 2; public static final int TYPE_OTHER = 3; @@ -1448,7 +3190,89 @@ public final class ContactsContract { } /** - * Common data definition for postal addresses. + * <p> + * A data kind representing a postal addresses. + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as + * well as the following aliases. + * </p> + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th> + * <th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #FORMATTED_ADDRESS}</td> + * <td>{@link #DATA1}</td> + * <td></td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TYPE}</td> + * <td>{@link #DATA2}</td> + * <td>Allowed values are: + * <p> + * <ul> + * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li> + * <li>{@link #TYPE_HOME}</li> + * <li>{@link #TYPE_WORK}</li> + * <li>{@link #TYPE_OTHER}</li> + * </ul> + * </p> + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LABEL}</td> + * <td>{@link #DATA3}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #STREET}</td> + * <td>{@link #DATA4}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #POBOX}</td> + * <td>{@link #DATA5}</td> + * <td>Post Office Box number</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #NEIGHBORHOOD}</td> + * <td>{@link #DATA6}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #CITY}</td> + * <td>{@link #DATA7}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #REGION}</td> + * <td>{@link #DATA8}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #POSTCODE}</td> + * <td>{@link #DATA9}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #COUNTRY}</td> + * <td>{@link #DATA10}</td> + * <td></td> + * </tr> + * </table> */ public static final class StructuredPostal implements DataColumnsWithJoins, CommonColumns { /** @@ -1573,7 +3397,76 @@ public final class ContactsContract { } /** - * Common data definition for IM addresses. + * <p> + * A data kind representing an IM address + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as + * well as the following aliases. + * </p> + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th> + * <th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #DATA}</td> + * <td>{@link #DATA1}</td> + * <td></td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TYPE}</td> + * <td>{@link #DATA2}</td> + * <td>Allowed values are: + * <p> + * <ul> + * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li> + * <li>{@link #TYPE_HOME}</li> + * <li>{@link #TYPE_WORK}</li> + * <li>{@link #TYPE_OTHER}</li> + * </ul> + * </p> + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LABEL}</td> + * <td>{@link #DATA3}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #PROTOCOL}</td> + * <td>{@link #DATA5}</td> + * <td> + * <p> + * Allowed values: + * <ul> + * <li>{@link #PROTOCOL_CUSTOM}. Also provide the actual protocol name + * as {@link #CUSTOM_PROTOCOL}.</li> + * <li>{@link #PROTOCOL_AIM}</li> + * <li>{@link #PROTOCOL_MSN}</li> + * <li>{@link #PROTOCOL_YAHOO}</li> + * <li>{@link #PROTOCOL_SKYPE}</li> + * <li>{@link #PROTOCOL_QQ}</li> + * <li>{@link #PROTOCOL_GOOGLE_TALK}</li> + * <li>{@link #PROTOCOL_ICQ}</li> + * <li>{@link #PROTOCOL_JABBER}</li> + * <li>{@link #PROTOCOL_NETMEETING}</li> + * </ul> + * </p> + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #CUSTOM_PROTOCOL}</td> + * <td>{@link #DATA6}</td> + * <td></td> + * </tr> + * </table> */ public static final class Im implements DataColumnsWithJoins, CommonColumns { /** @@ -1676,7 +3569,82 @@ public final class ContactsContract { } /** - * Common data definition for organizations. + * <p> + * A data kind representing an organization. + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as + * well as the following aliases. + * </p> + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th> + * <th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #COMPANY}</td> + * <td>{@link #DATA1}</td> + * <td></td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TYPE}</td> + * <td>{@link #DATA2}</td> + * <td>Allowed values are: + * <p> + * <ul> + * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li> + * <li>{@link #TYPE_WORK}</li> + * <li>{@link #TYPE_OTHER}</li> + * </ul> + * </p> + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LABEL}</td> + * <td>{@link #DATA3}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #TITLE}</td> + * <td>{@link #DATA4}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #DEPARTMENT}</td> + * <td>{@link #DATA5}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #JOB_DESCRIPTION}</td> + * <td>{@link #DATA6}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #SYMBOL}</td> + * <td>{@link #DATA7}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #PHONETIC_NAME}</td> + * <td>{@link #DATA8}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #OFFICE_LOCATION}</td> + * <td>{@link #DATA9}</td> + * <td></td> + * </tr> + * </table> */ public static final class Organization implements DataColumnsWithJoins, CommonColumns { /** @@ -1761,7 +3729,58 @@ public final class ContactsContract { } /** - * Common data definition for relations. + * <p> + * A data kind representing a relation. + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as + * well as the following aliases. + * </p> + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th> + * <th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #NAME}</td> + * <td>{@link #DATA1}</td> + * <td></td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TYPE}</td> + * <td>{@link #DATA2}</td> + * <td>Allowed values are: + * <p> + * <ul> + * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li> + * <li>{@link #TYPE_ASSISTANT}</li> + * <li>{@link #TYPE_BROTHER}</li> + * <li>{@link #TYPE_CHILD}</li> + * <li>{@link #TYPE_DOMESTIC_PARTNER}</li> + * <li>{@link #TYPE_FATHER}</li> + * <li>{@link #TYPE_FRIEND}</li> + * <li>{@link #TYPE_MANAGER}</li> + * <li>{@link #TYPE_MOTHER}</li> + * <li>{@link #TYPE_PARENT}</li> + * <li>{@link #TYPE_PARTNER}</li> + * <li>{@link #TYPE_REFERRED_BY}</li> + * <li>{@link #TYPE_RELATIVE}</li> + * <li>{@link #TYPE_SISTER}</li> + * <li>{@link #TYPE_SPOUSE}</li> + * </ul> + * </p> + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LABEL}</td> + * <td>{@link #DATA3}</td> + * <td></td> + * </tr> + * </table> */ public static final class Relation implements DataColumnsWithJoins, CommonColumns { /** @@ -1795,7 +3814,47 @@ public final class ContactsContract { } /** - * Common data definition for events. + * <p> + * A data kind representing an event. + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as + * well as the following aliases. + * </p> + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th> + * <th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #START_DATE}</td> + * <td>{@link #DATA1}</td> + * <td></td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TYPE}</td> + * <td>{@link #DATA2}</td> + * <td>Allowed values are: + * <p> + * <ul> + * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li> + * <li>{@link #TYPE_ANNIVERSARY}</li> + * <li>{@link #TYPE_OTHER}</li> + * <li>{@link #TYPE_BIRTHDAY}</li> + * </ul> + * </p> + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LABEL}</td> + * <td>{@link #DATA3}</td> + * <td></td> + * </tr> + * </table> */ public static final class Event implements DataColumnsWithJoins, CommonColumns { /** @@ -1835,7 +3894,33 @@ public final class ContactsContract { } /** - * Photo of the contact. + * <p> + * A data kind representing an photo for the contact. + * </p> + * <p> + * Some sync adapters will choose to download photos in a separate + * pass. A common pattern is to use columns {@link ContactsContract.Data#SYNC1} + * through {@link ContactsContract.Data#SYNC4} to store temporary + * data, e.g. the image URL or ID, state of download, server-side version + * of the image. It is allowed for the {@link #PHOTO} to be null. + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as + * well as the following aliases. + * </p> + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th> + * <th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>BLOB</td> + * <td>{@link #PHOTO}</td> + * <td>{@link #DATA15}</td> + * <td>By convention, binary data is stored in DATA15.</td> + * </tr> + * </table> */ public static final class Photo implements DataColumnsWithJoins { /** @@ -1856,7 +3941,26 @@ public final class ContactsContract { } /** + * <p> * Notes about the contact. + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as + * well as the following aliases. + * </p> + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th> + * <th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #NOTE}</td> + * <td>{@link #DATA1}</td> + * <td></td> + * </tr> + * </table> */ public static final class Note implements DataColumnsWithJoins { /** @@ -1875,7 +3979,43 @@ public final class ContactsContract { } /** + * <p> * Group Membership. + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as + * well as the following aliases. + * </p> + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th> + * <th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #GROUP_ROW_ID}</td> + * <td>{@link #DATA1}</td> + * <td></td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #GROUP_SOURCE_ID}</td> + * <td>none</td> + * <td> + * <p> + * The sourceid of the group that this group membership refers to. + * Exactly one of this or {@link #GROUP_ROW_ID} must be set when + * inserting a row. + * </p> + * <p> + * If this field is specified, the provider will first try to + * look up a group with this {@link Groups Groups.SOURCE_ID}. If such a group + * is found, it will use the corresponding row id. If the group is not + * found, it will create one. + * </td> + * </tr> + * </table> */ public static final class GroupMembership implements DataColumnsWithJoins { /** @@ -1903,7 +4043,51 @@ public final class ContactsContract { } /** - * Website related to the contact. + * <p> + * A data kind representing a website related to the contact. + * </p> + * <p> + * You can use all columns defined for {@link ContactsContract.Data} as + * well as the following aliases. + * </p> + * <h2>Column aliases</h2> + * <table class="jd-sumtable"> + * <tr> + * <th>Type</th> + * <th>Alias</th><th colspan='2'>Data column</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #URL}</td> + * <td>{@link #DATA1}</td> + * <td></td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TYPE}</td> + * <td>{@link #DATA2}</td> + * <td>Allowed values are: + * <p> + * <ul> + * <li>{@link #TYPE_CUSTOM}. Put the actual type in {@link #LABEL}.</li> + * <li>{@link #TYPE_HOMEPAGE}</li> + * <li>{@link #TYPE_BLOG}</li> + * <li>{@link #TYPE_PROFILE}</li> + * <li>{@link #TYPE_HOME}</li> + * <li>{@link #TYPE_WORK}</li> + * <li>{@link #TYPE_FTP}</li> + * <li>{@link #TYPE_OTHER}</li> + * </ul> + * </p> + * </td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #LABEL}</td> + * <td>{@link #DATA3}</td> + * <td></td> + * </tr> + * </table> */ public static final class Website implements DataColumnsWithJoins, CommonColumns { /** @@ -1930,6 +4114,9 @@ public final class ContactsContract { } } + /** + * @see Groups + */ protected interface GroupsColumns { /** * The display title of this group. @@ -2000,11 +4187,11 @@ public final class ContactsContract { /** * The "deleted" flag: "0" by default, "1" if the row has been marked * for deletion. When {@link android.content.ContentResolver#delete} is - * called on a raw contact, it is marked for deletion and removed from its - * aggregate contact. The sync adaptor deletes the raw contact on the server and - * then calls ContactResolver.delete once more, this time setting the the - * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize - * the data removal. + * called on a group, it is marked for deletion. The sync adaptor + * deletes the group on the server and then calls ContactResolver.delete + * once more, this time setting the the + * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to + * finalize the data removal. * <P>Type: INTEGER</P> */ public static final String DELETED = "deleted"; @@ -2019,7 +4206,82 @@ public final class ContactsContract { } /** - * Constants for the groups table. + * Constants for the groups table. Only per-account groups are supported. + * <h2>Columns</h2> + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>Groups</th> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #_ID}</td> + * <td>read-only</td> + * <td>Row ID. Sync adapter should try to preserve row IDs during updates. + * In other words, it would be a really bad idea to delete and reinsert a + * group. A sync adapter should always do an update instead.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #TITLE}</td> + * <td>read/write</td> + * <td>The display title of this group.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #NOTES}</td> + * <td>read/write</td> + * <td>Notes about the group.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #SYSTEM_ID}</td> + * <td>read/write</td> + * <td>The ID of this group if it is a System Group, i.e. a group that has a + * special meaning to the sync adapter, null otherwise.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #SUMMARY_COUNT}</td> + * <td>read-only</td> + * <td>The total number of {@link Contacts} that have + * {@link CommonDataKinds.GroupMembership} in this group. Read-only value + * that is only present when querying {@link Groups#CONTENT_SUMMARY_URI}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #SUMMARY_WITH_PHONES}</td> + * <td>read-only</td> + * <td>The total number of {@link Contacts} that have both + * {@link CommonDataKinds.GroupMembership} in this group, and also have + * phone numbers. Read-only value that is only present when querying + * {@link Groups#CONTENT_SUMMARY_URI}.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #GROUP_VISIBLE}</td> + * <td>read-only</td> + * <td>Flag indicating if the contacts belonging to this group should be + * visible in any user interface. Allowed values: 0 and 1.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #DELETED}</td> + * <td>read/write</td> + * <td>The "deleted" flag: "0" by default, "1" if the row has been marked + * for deletion. When {@link android.content.ContentResolver#delete} is + * called on a group, it is marked for deletion. The sync adaptor deletes + * the group on the server and then calls ContactResolver.delete once more, + * this time setting the the {@link ContactsContract#CALLER_IS_SYNCADAPTER} + * query parameter to finalize the data removal.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #SHOULD_SYNC}</td> + * <td>read/write</td> + * <td>Whether this group should be synced if the SYNC_EVERYTHING settings + * is false for this group's account.</td> + * </tr> + * </table> */ public static final class Groups implements BaseColumns, GroupsColumns, SyncColumns { /** @@ -2035,7 +4297,7 @@ public final class ContactsContract { /** * The content:// style URI for this table joined with details data from - * {@link Data}. + * {@link ContactsContract.Data}. */ public static final Uri CONTENT_SUMMARY_URI = Uri.withAppendedPath(AUTHORITY_URI, "groups_summary"); @@ -2052,9 +4314,39 @@ public final class ContactsContract { } /** + * <p> * Constants for the contact aggregation exceptions table, which contains - * aggregation rules overriding those used by automatic aggregation. This type only - * supports query and update. Neither insert nor delete are supported. + * aggregation rules overriding those used by automatic aggregation. This + * type only supports query and update. Neither insert nor delete are + * supported. + * </p> + * <h2>Columns</h2> + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>AggregationExceptions</th> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #TYPE}</td> + * <td>read/write</td> + * <td>The type of exception: {@link #TYPE_KEEP_TOGETHER}, + * {@link #TYPE_KEEP_SEPARATE} or {@link #TYPE_AUTOMATIC}.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #RAW_CONTACT_ID1}</td> + * <td>read/write</td> + * <td>A reference to the {@link RawContacts#_ID} of the raw contact that + * the rule applies to.</td> + * </tr> + * <tr> + * <td>long</td> + * <td>{@link #RAW_CONTACT_ID2}</td> + * <td>read/write</td> + * <td>A reference to the other {@link RawContacts#_ID} of the raw contact + * that the rule applies to.</td> + * </tr> + * </table> */ public static final class AggregationExceptions implements BaseColumns { /** @@ -2117,6 +4409,9 @@ public final class ContactsContract { public static final String RAW_CONTACT_ID2 = "raw_contact_id2"; } + /** + * @see Settings + */ protected interface SettingsColumns { /** * The name of the account instance to which this row belongs. @@ -2172,8 +4467,68 @@ public final class ContactsContract { } /** - * Contacts-specific settings for various {@link Account}. + * <p> + * Contacts-specific settings for various {@link Account}'s. + * </p> + * <h2>Columns</h2> + * <table class="jd-sumtable"> + * <tr> + * <th colspan='4'>Settings</th> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #ACCOUNT_NAME}</td> + * <td>read/write-once</td> + * <td>The name of the account instance to which this row belongs.</td> + * </tr> + * <tr> + * <td>String</td> + * <td>{@link #ACCOUNT_TYPE}</td> + * <td>read/write-once</td> + * <td>The type of account to which this row belongs, which when paired with + * {@link #ACCOUNT_NAME} identifies a specific account.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #SHOULD_SYNC}</td> + * <td>read/write</td> + * <td>Depending on the mode defined by the sync-adapter, this flag controls + * the top-level sync behavior for this data source.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #UNGROUPED_VISIBLE}</td> + * <td>read/write</td> + * <td>Flag indicating if contacts without any + * {@link CommonDataKinds.GroupMembership} entries should be visible in any + * user interface.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #ANY_UNSYNCED}</td> + * <td>read-only</td> + * <td>Read-only flag indicating if this {@link #SHOULD_SYNC} or any + * {@link Groups#SHOULD_SYNC} under this account have been marked as + * unsynced.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #UNGROUPED_COUNT}</td> + * <td>read-only</td> + * <td>Read-only count of {@link Contacts} from a specific source that have + * no {@link CommonDataKinds.GroupMembership} entries.</td> + * </tr> + * <tr> + * <td>int</td> + * <td>{@link #UNGROUPED_WITH_PHONES}</td> + * <td>read-only</td> + * <td>Read-only count of {@link Contacts} from a specific source that have + * no {@link CommonDataKinds.GroupMembership} entries, and also have phone + * numbers.</td> + * </tr> + * </table> */ + public static final class Settings implements SettingsColumns { /** * This utility class cannot be instantiated @@ -2252,8 +4607,8 @@ public final class ContactsContract { /** * Trigger a dialog that lists the various methods of interacting with * the requested {@link Contacts} entry. This may be based on available - * {@link Data} rows under that contact, and may also include social - * status and presence details. + * {@link ContactsContract.Data} rows under that contact, and may also + * include social status and presence details. * * @param context The parent {@link Context} that may be used as the * parent for this dialog. @@ -2291,8 +4646,8 @@ public final class ContactsContract { /** * Trigger a dialog that lists the various methods of interacting with * the requested {@link Contacts} entry. This may be based on available - * {@link Data} rows under that contact, and may also include social - * status and presence details. + * {@link ContactsContract.Data} rows under that contact, and may also + * include social status and presence details. * * @param context The parent {@link Context} that may be used as the * parent for this dialog. @@ -2593,7 +4948,7 @@ public final class ContactsContract { /** * The extra field for the contact phone number type. * <P>Type: Either an integer value from - * {@link android.provider.Contacts.PhonesColumns PhonesColumns}, + * {@link CommonDataKinds.Phone}, * or a string specifying a custom label.</P> */ public static final String PHONE_TYPE = "phone_type"; @@ -2613,7 +4968,7 @@ public final class ContactsContract { /** * The extra field for an optional second contact phone number type. * <P>Type: Either an integer value from - * {@link android.provider.Contacts.PhonesColumns PhonesColumns}, + * {@link CommonDataKinds.Phone}, * or a string specifying a custom label.</P> */ public static final String SECONDARY_PHONE_TYPE = "secondary_phone_type"; @@ -2627,7 +4982,7 @@ public final class ContactsContract { /** * The extra field for an optional third contact phone number type. * <P>Type: Either an integer value from - * {@link android.provider.Contacts.PhonesColumns PhonesColumns}, + * {@link CommonDataKinds.Phone}, * or a string specifying a custom label.</P> */ public static final String TERTIARY_PHONE_TYPE = "tertiary_phone_type"; @@ -2641,7 +4996,7 @@ public final class ContactsContract { /** * The extra field for the contact email type. * <P>Type: Either an integer value from - * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} + * {@link CommonDataKinds.Email} * or a string specifying a custom label.</P> */ public static final String EMAIL_TYPE = "email_type"; @@ -2661,7 +5016,7 @@ public final class ContactsContract { /** * The extra field for an optional second contact email type. * <P>Type: Either an integer value from - * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} + * {@link CommonDataKinds.Email} * or a string specifying a custom label.</P> */ public static final String SECONDARY_EMAIL_TYPE = "secondary_email_type"; @@ -2675,7 +5030,7 @@ public final class ContactsContract { /** * The extra field for an optional third contact email type. * <P>Type: Either an integer value from - * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} + * {@link CommonDataKinds.Email} * or a string specifying a custom label.</P> */ public static final String TERTIARY_EMAIL_TYPE = "tertiary_email_type"; @@ -2689,7 +5044,7 @@ public final class ContactsContract { /** * The extra field for the contact postal address type. * <P>Type: Either an integer value from - * {@link android.provider.Contacts.ContactMethodsColumns ContactMethodsColumns} + * {@link CommonDataKinds.StructuredPostal} * or a string specifying a custom label.</P> */ public static final String POSTAL_TYPE = "postal_type"; |