Merge "Improve ContractsContract.RawContacts documentation"
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 7fb9daf..0e7e86b 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -55,19 +55,21 @@
  * </p>
  * <ul>
  * <li>
- * 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.
+ * A row in the {@link Data} table can store any kind of personal data, such
+ * as a phone number or email addresses.  The set 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.
  * </li>
  * <li>
- * A row in the {@link RawContacts} table represents a set of Data describing a
- * person and associated with a single account (for example, a single Gmail
- * account).
+ * A row in the {@link RawContacts} table represents a set of data describing a
+ * person and associated with a single account (for example, one of the user's
+ * Gmail accounts).
  * </li>
  * <li>
  * A row in the {@link Contacts} table represents an aggregate of one or more
- * RawContacts presumably describing the same person.
+ * RawContacts presumably describing the same person.  When data in or associated with
+ * the RawContacts table is changed, the affected aggregate contacts are updated as
+ * necessary.
  * </li>
  * </ul>
  * <p>
@@ -75,7 +77,8 @@
  * </p>
  * <ul>
  * <li>
- * {@link Groups}, which contains information about raw contact groups - the
+ * {@link Groups}, which contains information about raw contact groups
+ * such as Gmail contact groups.  The
  * current API does not support the notion of groups spanning multiple accounts.
  * </li>
  * <li>
@@ -106,11 +109,15 @@
     public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
 
     /**
-     * An optional insert, update or delete URI parameter that allows the caller
+     * An optional URI parameter for insert, update, or delete queries
+     * that allows the caller
      * to specify that it is a sync adapter. The default value is false. If true
-     * the dirty flag is not automatically set and the "syncToNetwork" parameter
-     * is set to false when calling
-     * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}.
+     * {@link RawContacts#DIRTY} is not automatically set and the
+     * "syncToNetwork" parameter is set to false when calling
+     * {@link
+     * ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}.
+     * This prevents an unnecessary extra synchronization, see the discussion of
+     * the delete operation in {@link RawContacts}.
      */
     public static final String CALLER_IS_SYNCADAPTER = "caller_is_syncadapter";
 
@@ -459,19 +466,23 @@
     protected interface ContactNameColumns {
 
         /**
-         * The kind of data that is used as the display name for the contact, see
-         * DisplayNameSources.
+         * The kind of data that is used as the display name for the contact, such as
+         * structured name or email address.  See DisplayNameSources.
+         *
+         * TODO: convert DisplayNameSources to a link after it is un-hidden
          */
         public static final String DISPLAY_NAME_SOURCE = "display_name_source";
 
         /**
          * The default text shown as the contact's display name.  It is based on
          * available data, see {@link #DISPLAY_NAME_SOURCE}.
+         *
+         * @see ContactsContract.ContactNameColumns#DISPLAY_NAME_ALTERNATIVE
          */
         public static final String DISPLAY_NAME_PRIMARY = "display_name";
 
         /**
-         * Alternative representation of the display name.  If display name is
+         * An alternative representation of the display name.  If display name is
          * based on the structured name and the structured name follows
          * the Western full name style, then this field contains the "family name first"
          * version of the full name.  Otherwise, it is the same as DISPLAY_NAME_PRIMARY.
@@ -479,27 +490,42 @@
         public static final String DISPLAY_NAME_ALTERNATIVE = "display_name_alt";
 
         /**
-         * The type of alphabet used to capture the phonetic name.  See
+         * The phonetic alphabet used to represent the {@link #PHONETIC_NAME}.  See
          * PhoneticNameStyle.
+         *
+         * TODO: convert PhoneticNameStyle to a link after it is un-hidden
          */
         public static final String PHONETIC_NAME_STYLE = "phonetic_name_style";
 
         /**
-         * Pronunciation of the full name. See PhoneticNameStyle.
+         * <p>
+         * Pronunciation of the full name in the phonetic alphabet specified by
+         * {@link #PHONETIC_NAME_STYLE}.
+         * </p>
+         * <p>
+         * The value may be set manually by the user.
+         * This capability is is of interest only in countries
+         * with commonly used phonetic
+         * alphabets, such as Japan and Korea.  See PhoneticNameStyle.
+         * </p>
+         *
+         * TODO: convert PhoneticNameStyle to a link after it is un-hidden
          */
         public static final String PHONETIC_NAME = "phonetic_name";
 
         /**
          * Sort key that takes into account locale-based traditions for sorting
-         * names in address books.  More specifically, for Chinese names
-         * the sort key is the name's Pinyin spelling; for Japanese names
+         * names in address books.  The default
+         * sort key is {@link #DISPLAY_NAME_PRIMARY}.  For Chinese names
+         * the sort key is the name's Pinyin spelling, and for Japanese names
          * it is the Hiragana version of the phonetic name.
          */
         public static final String SORT_KEY_PRIMARY = "sort_key";
 
         /**
          * Sort key based on the alternative representation of the full name,
-         * specifically the one using the 'family name first' format for
+         * {@link #DISPLAY_NAME_ALTERNATIVE}.  Thus for Western names,
+         * it is the one using the "family name first" format for
          * Western names.
          */
         public static final String SORT_KEY_ALTERNATIVE = "sort_key_alt";
@@ -808,7 +834,10 @@
         }
 
         /**
-         * Mark a contact as having been contacted.
+         * Mark a contact as having been contacted.  This updates the
+         * {@link #TIMES_CONTACTED} and {@link #LAST_TIME_CONTACTED} for the
+         * contact, plus the corresponding values of any associated raw
+         * contacts.
          *
          * @param resolver the ContentResolver to use
          * @param contactId the person who was contacted
@@ -1050,15 +1079,37 @@
     }
 
     /**
-     * Constants for the raw contacts table, which contains the base contact
-     * information per sync source. Sync adapters and contact management apps
+     * Constants for the raw contacts table, which contains one row of contact
+     * information for each person in each synced account. Sync adapters and
+     * contact management apps
      * are the primary consumers of this API.
+     *
+     * <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. The
+     * aggregation is reflected in the {@link RawContacts} table by the change of the
+     * {@link #CONTACT_ID} field, which is the reference to the aggregate contact.
+     * </p>
+     * <p>
+     * Changes to the structured name, organization, phone number, email address,
+     * or nickname trigger a re-aggregation.
+     * </p>
+     * <p>
+     * See also {@link AggregationExceptions} for a mechanism to control
+     * aggregation programmatically.
+     * </p>
+     *
      * <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:
+     * <dd>
+     * <p>
+     * Raw contacts can be inserted incrementally or in a batch.
+     * The incremental method is more traditional but less efficient.
+     * It should be used
+     * only if no {@link Data} values are available at the time the raw contact is created:
      * <pre>
      * ContentValues values = new ContentValues();
      * values.put(RawContacts.ACCOUNT_TYPE, accountType);
@@ -1066,9 +1117,10 @@
      * Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values);
      * long rawContactId = ContentUris.parseId(rawContactUri);
      * </pre>
+     * </p>
      * <p>
-     * Once data rows are available, insert those.  For example, here's how you would insert
-     * a name:
+     * Once {@link Data} values become available, insert those.
+     * For example, here's how you would insert a name:
      *
      * <pre>
      * values.clear();
@@ -1084,6 +1136,7 @@
      * and causes at most one aggregation pass.
      * <pre>
      * ArrayList&lt;ContentProviderOperation&gt; ops = Lists.newArrayList();
+     * ...
      * int rawContactInsertIndex = ops.size();
      * ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
      *          .withValue(RawContacts.ACCOUNT_TYPE, accountType)
@@ -1100,21 +1153,27 @@
      * </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.
+     * Note the use of {@link ContentProviderOperation.Builder#withValueBackReference(String, int)}
+     * to refer to the as-yet-unknown index value of the raw contact inserted in the
+     * first operation.
      * </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>
+     * <dd><p>
+     * Raw contacts can be updated incrementally or in a batch.
+     * Batch mode should be used whenever possible.
+     * The procedures and considerations are analogous to those documented above for inserts.
+     * </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.
+     * contacts associated with a {@link Contacts} row are deleted, the {@link Contacts} row
+     * 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
+     * The invocation of {@code resolver.delete(...)}, does not immediately delete
+     * a raw contacts row.
+     * Instead, 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(...)}
@@ -1124,10 +1183,11 @@
      * 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:
+     * It is easy to find all raw contacts in a Contact:
      * <pre>
      * Cursor c = getContentResolver().query(RawContacts.CONTENT_URI,
      *          new String[]{RawContacts._ID},
@@ -1136,7 +1196,7 @@
      * </pre>
      * </p>
      * <p>
-     * There are two ways to find raw contacts within a specific account,
+     * 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:
@@ -1178,19 +1238,11 @@
      * </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>
+     * TODO: include {@link #DISPLAY_NAME_PRIMARY}, {@link #DISPLAY_NAME_ALTERNATIVE},
+     * {@link #DISPLAY_NAME_SOURCE}, {@link #PHONETIC_NAME}, {@link #PHONETIC_NAME_STYLE},
+     * {@link #SORT_KEY_PRIMARY}, {@link #SORT_KEY_ALTERNATIVE}?
+     *
      * <table class="jd-sumtable">
      * <tr>
      * <th colspan='4'>RawContacts</th>
@@ -1199,15 +1251,16 @@
      * <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>
+     * <td>Row ID. Sync adapters should try to preserve row IDs during updates. In other words,
+     * it is much better for a sync adapter to update a raw contact rather than to delete and
+     * re-insert it.</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
+     * <td>The ID of the row in the {@link ContactsContract.Contacts} table
+     * 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>
@@ -1238,7 +1291,8 @@
      * <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>
+     * After that, this value is typically updated via
+     * {@link ContactsContract.Contacts#markAsContacted}.</td>
      * </tr>
      * <tr>
      * <td>long</td>
@@ -1247,14 +1301,16 @@
      * <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>
+     * After that, this value is typically updated via
+     * {@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:
+     * Changing this field immediately affects the corresponding aggregate contact:
      * if any raw contacts in that aggregate contact are starred, then the contact
      * itself is marked as starred.</td>
      * </tr>
@@ -1267,7 +1323,8 @@
      * {@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}
+     * ringtone on a contact, use the field {@link ContactsContract.Contacts#CUSTOM_RINGTONE
+     * Contacts.CUSTOM_RINGTONE}
      * instead.</td>
      * </tr>
      * <tr>
@@ -1284,16 +1341,27 @@
      * <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
+     * {@link #ACCOUNT_TYPE} identifies a specific account.
+     * For example, this will be the Gmail address if it is a Google 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>
+     * <td>
+     * <p>
+     * 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.
+     * </p>
+     * <p>
+     * To ensure uniqueness, new account types should be chosen according to the
+     * Java package naming convention.  Thus a Google account is of type "com.google".
+     * </p>
+     * </td>
      * </tr>
      * <tr>
      * <td>String</td>
@@ -1302,8 +1370,8 @@
      * <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
+     * will have an account name and type, but no source id. This
+     * indicates 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>
@@ -1335,7 +1403,8 @@
      * <td>String</td>
      * <td>{@link #SYNC1}</td>
      * <td>read/write</td>
-     * <td>Generic column for use by sync adapters. Content provider
+     * <td>Generic column provided for arbitrary use by sync adapters.
+     * The content provider
      * stores this information on behalf of the sync adapter but does not
      * interpret it in any way.
      * </td>
@@ -1372,46 +1441,70 @@
         }
 
         /**
-         * The content:// style URI for this table
+         * The content:// style URI for this table, which requests a directory of
+         * raw contact rows matching the selection criteria.
          */
         public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "raw_contacts");
 
         /**
-         * The MIME type of {@link #CONTENT_URI} providing a directory of
-         * people.
+         * The MIME type of the results from {@link #CONTENT_URI} when a specific
+         * ID value is not provided, and multiple raw contacts may be returned.
          */
         public static final String CONTENT_TYPE = "vnd.android.cursor.dir/raw_contact";
 
         /**
-         * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
-         * person.
+         * The MIME type of the results when a raw contact ID is appended to {@link #CONTENT_URI},
+         * yielding a subdirectory of a single person.
          */
         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/raw_contact";
 
         /**
-         * Aggregation mode: aggregate asynchronously.
+         * Aggregation mode: aggregate immediately after insert or update operation(s) are complete.
          */
         public static final int AGGREGATION_MODE_DEFAULT = 0;
 
         /**
-         * Aggregation mode: aggregate at the time the raw contact is inserted/updated.
-         * TODO: deprecate. Aggregation is now synchronous, this value is a no-op
+         * Do not use.
+         *
+         * @deprecated in favor of {@link #AGGREGATION_MODE_DEFAULT}
          */
+        @Deprecated
         public static final int AGGREGATION_MODE_IMMEDIATE = 1;
 
         /**
-         * If {@link #AGGREGATION_MODE} is {@link #AGGREGATION_MODE_SUSPENDED}, changes
-         * to the raw contact do not cause its aggregation to be revisited. Note that changing
+         * <p>
+         * Aggregation mode: aggregation suspended temporarily, and is likely to be resumed later.
+         * Changes to the raw contact will update the associated aggregate contact but will not
+         * result in any change in how the contact is aggregated. Similar to
+         * {@link #AGGREGATION_MODE_DISABLED}, but maintains a link to the corresponding
+         * {@link Contacts} aggregate.
+         * </p>
+         * <p>
+         * This can be used to postpone aggregation until after a series of updates, for better
+         * performance and/or user experience.
+         * </p>
+         * <p>
+         * Note that changing
          * {@link #AGGREGATION_MODE} from {@link #AGGREGATION_MODE_SUSPENDED} to
-         * {@link #AGGREGATION_MODE_DEFAULT} does not trigger an aggregation pass. Any subsequent
+         * {@link #AGGREGATION_MODE_DEFAULT} does not trigger an aggregation pass, but any
+         * subsequent
          * change to the raw contact's data will.
+         * </p>
          */
         public static final int AGGREGATION_MODE_SUSPENDED = 2;
 
         /**
-         * Aggregation mode: never aggregate this raw contact (note that the raw contact will not
-         * have a corresponding Aggregate and therefore will not be included in Aggregates
-         * query results.)
+         * <p>
+         * Aggregation mode: never aggregate this raw contact.  The raw contact will not
+         * have a corresponding {@link Contacts} aggregate and therefore will not be included in
+         * {@link Contacts} query results.
+         * </p>
+         * <p>
+         * For example, this mode can be used for a raw contact that is marked for deletion while
+         * waiting for the deletion to occur on the server side.
+         * </p>
+         *
+         * @see #AGGREGATION_MODE_SUSPENDED
          */
         public static final int AGGREGATION_MODE_DISABLED = 3;
 
@@ -1441,10 +1534,13 @@
         }
 
         /**
-         * A sub-directory of a single raw contact that contains all of their
+         * A sub-directory of a single raw contact that contains all of its
          * {@link ContactsContract.Data} rows. To access this directory
          * append {@link Data#CONTENT_DIRECTORY} to the contact URI.
+         *
+         * @deprecated in favor of {@link RawContacts.Entity}.
          */
+        @Deprecated
         public static final class Data implements BaseColumns, DataColumns {
             /**
              * no public constructor since this is a utility class
@@ -1460,26 +1556,24 @@
 
         /**
          * <p>
-         * A sub-directory of a single raw contact that contains all of their
+         * A sub-directory of a single raw contact that contains all of its
          * {@link ContactsContract.Data} rows. To access this directory append
          * {@link #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
+         * Entity has two ID fields: {@link #_ID} for the raw contact
+         * and {@link #DATA_ID} for the data rows.
+         * 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.
+         * null.
+         * </p>
+         * <p>
+         * Entity reads all
+         * data for a raw contact in one transaction, to guarantee
+         * consistency.
+         * </p>
          */
         public static final class Entity implements BaseColumns, DataColumns {
             /**
@@ -1501,6 +1595,11 @@
             public static final String DATA_ID = "data_id";
         }
 
+        /**
+         * TODO: javadoc
+         * @param cursor
+         * @return
+         */
         public static EntityIterator newEntityIterator(Cursor cursor) {
             return new EntityIteratorImpl(cursor);
         }
@@ -1839,7 +1938,12 @@
      * By convention, {@link #DATA15} is used for storing BLOBs (binary data).
      * </p>
      * <p>
-     * Typically you should refrain from introducing new kinds of data for an other
+     * The sync adapter for a given account type must correctly handle every data type
+     * used in the corresponding raw contacts.  Otherwise it could result in lost or
+     * corrupted data.
+     * </p>
+     * <p>
+     * Similarly, you should refrain from introducing new kinds of data for an other
      * party's 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