Merge "docs: Added details about key/signature for IAB/Licensing docs. Bugs: 8338447" into jb-mr1.1-docs
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index bcb35d5..f490e79 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -1853,7 +1853,7 @@
* <p>
* The most common case is to call this with one account type, e.g.:
* <p>
- * <pre> newChooseAccountsIntent(null, null, new String[]{"com.google"}, false, null,
+ * <pre> newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null,
* null, null, null);</pre>
* @param selectedAccount if specified, indicates that the {@link Account} is the currently
* selected one, according to the caller's definition of selected.
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 02cf3aa..4fbca73 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -666,7 +666,9 @@
/**
* Print the Service's state into the given stream. This gets invoked if
- * you run "adb shell dumpsys activity service <yourservicename>".
+ * you run "adb shell dumpsys activity service <yourservicename>"
+ * (note that for this command to work, the service must be running, and
+ * you must specify a fully-qualified service name).
* This is distinct from "dumpsys <servicename>", which only works for
* named system services and which invokes the {@link IBinder#dump} method
* on the {@link IBinder} interface registered with ServiceManager.
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 9ad33a5..0e835ed 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -440,21 +440,31 @@
basePath = getCacheDir().getCanonicalPath();
} else {
// Not a supported location
- Log.i(TAG, "Data restored from non-app domain " + domain + ", ignoring");
+ Log.i(TAG, "Unrecognized domain " + domain);
}
// Now that we've figured out where the data goes, send it on its way
if (basePath != null) {
+ // Canonicalize the nominal path and verify that it lies within the stated domain
File outFile = new File(basePath, path);
- if (DEBUG) Log.i(TAG, "[" + domain + " : " + path + "] mapped to " + outFile.getPath());
- onRestoreFile(data, size, outFile, type, mode, mtime);
- } else {
- // Not a supported output location? We need to consume the data
- // anyway, so just use the default "copy the data out" implementation
- // with a null destination.
- if (DEBUG) Log.i(TAG, "[ skipping data from unsupported domain " + domain + "]");
- FullBackup.restoreFile(data, size, type, mode, mtime, null);
+ String outPath = outFile.getCanonicalPath();
+ if (outPath.startsWith(basePath + File.separatorChar)) {
+ if (DEBUG) Log.i(TAG, "[" + domain + " : " + path + "] mapped to " + outPath);
+ onRestoreFile(data, size, outFile, type, mode, mtime);
+ return;
+ } else {
+ // Attempt to restore to a path outside the file's nominal domain.
+ if (DEBUG) {
+ Log.e(TAG, "Cross-domain restore attempt: " + outPath);
+ }
+ }
}
+
+ // Not a supported output location, or bad path: we need to consume the data
+ // anyway, so just use the default "copy the data out" implementation
+ // with a null destination.
+ if (DEBUG) Log.i(TAG, "[ skipping file " + path + "]");
+ FullBackup.restoreFile(data, size, type, mode, mtime, null);
}
// ----- Core implementation -----
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 8ba1988..2c31ea0 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -45,7 +45,7 @@
/**
* This exception is thrown when a given package, application, or component
- * name can not be found.
+ * name cannot be found.
*/
public static class NameNotFoundException extends AndroidException {
public NameNotFoundException() {
@@ -259,7 +259,7 @@
* user has explicitly disabled the application, regardless of what it has
* specified in its manifest. Because this is due to the user's request,
* they may re-enable it if desired through the appropriate system UI. This
- * option currently <strong>can not</strong> be used with
+ * option currently <strong>cannot</strong> be used with
* {@link #setComponentEnabledSetting(ComponentName, int, int)}.
*/
public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3;
@@ -1210,9 +1210,9 @@
* package. If flag GET_UNINSTALLED_PACKAGES is set and if the
* package is not found in the list of installed applications, the
* package information is retrieved from the list of uninstalled
- * applications(which includes installed applications as well as
- * applications with data directory ie applications which had been
- * deleted with DONT_DELTE_DATA flag set).
+ * applications (which includes installed applications as well as
+ * applications with data directory i.e. applications which had been
+ * deleted with {@code DONT_DELETE_DATA} flag set).
* @see #GET_ACTIVITIES
* @see #GET_GIDS
* @see #GET_CONFIGURATIONS
@@ -1253,7 +1253,7 @@
* null if neither are found.
*
* <p>Throws {@link NameNotFoundException} if a package with the given
- * name can not be found on the system.
+ * name cannot be found on the system.
*
* @param packageName The name of the package to inspect.
*
@@ -1268,7 +1268,7 @@
* assigned to a package.
*
* <p>Throws {@link NameNotFoundException} if a package with the given
- * name can not be found on the system.
+ * name cannot be found on the system.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
@@ -1283,7 +1283,7 @@
* Retrieve all of the information we know about a particular permission.
*
* <p>Throws {@link NameNotFoundException} if a permission with the given
- * name can not be found on the system.
+ * name cannot be found on the system.
*
* @param name The fully qualified name (i.e. com.google.permission.LOGIN)
* of the permission you are interested in.
@@ -1319,7 +1319,7 @@
* permissions.
*
* <p>Throws {@link NameNotFoundException} if a permission group with the given
- * name can not be found on the system.
+ * name cannot be found on the system.
*
* @param name The fully qualified name (i.e. com.google.permission_group.APPS)
* of the permission you are interested in.
@@ -1348,7 +1348,7 @@
* package/application.
*
* <p>Throws {@link NameNotFoundException} if an application with the given
- * package name can not be found on the system.
+ * package name cannot be found on the system.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of an
* application.
@@ -1364,7 +1364,7 @@
* list of uninstalled applications(which includes
* installed applications as well as applications
* with data directory ie applications which had been
- * deleted with DONT_DELTE_DATA flag set).
+ * deleted with {@code DONT_DELETE_DATA} flag set).
*
* @see #GET_META_DATA
* @see #GET_SHARED_LIBRARY_FILES
@@ -1378,7 +1378,7 @@
* class.
*
* <p>Throws {@link NameNotFoundException} if an activity with the given
- * class name can not be found on the system.
+ * class name cannot be found on the system.
*
* @param component The full component name (i.e.
* com.google.apps.contacts/com.google.apps.contacts.ContactsList) of an Activity
@@ -1401,7 +1401,7 @@
* class.
*
* <p>Throws {@link NameNotFoundException} if a receiver with the given
- * class name can not be found on the system.
+ * class name cannot be found on the system.
*
* @param component The full component name (i.e.
* com.google.apps.calendar/com.google.apps.calendar.CalendarAlarm) of a Receiver
@@ -1424,7 +1424,7 @@
* class.
*
* <p>Throws {@link NameNotFoundException} if a service with the given
- * class name can not be found on the system.
+ * class name cannot be found on the system.
*
* @param component The full component name (i.e.
* com.google.apps.media/com.google.apps.media.BackgroundPlayback) of a Service
@@ -1446,7 +1446,7 @@
* provider class.
*
* <p>Throws {@link NameNotFoundException} if a provider with the given
- * class name can not be found on the system.
+ * class name cannot be found on the system.
*
* @param component The full component name (i.e.
* com.google.providers.media/com.google.providers.media.MediaProvider) of a
@@ -1483,7 +1483,7 @@
* installed on the device. In the unlikely case of there being no
* installed packages, an empty list is returned.
* If flag GET_UNINSTALLED_PACKAGES is set, a list of all
- * applications including those deleted with DONT_DELETE_DATA
+ * applications including those deleted with {@code DONT_DELETE_DATA}
* (partially installed apps with data directory) will be returned.
*
* @see #GET_ACTIVITIES
@@ -1521,7 +1521,7 @@
* installed on the device. In the unlikely case of there being no
* installed packages, an empty list is returned.
* If flag GET_UNINSTALLED_PACKAGES is set, a list of all
- * applications including those deleted with DONT_DELETE_DATA
+ * applications including those deleted with {@code DONT_DELETE_DATA}
* (partially installed apps with data directory) will be returned.
*
* @see #GET_ACTIVITIES
@@ -1726,7 +1726,7 @@
/**
* Return a List of all application packages that are installed on the
* device. If flag GET_UNINSTALLED_PACKAGES has been set, a list of all
- * applications including those deleted with DONT_DELETE_DATA(partially
+ * applications including those deleted with {@code DONT_DELETE_DATA} (partially
* installed apps with data directory) will be returned.
*
* @param flags Additional option flags. Use any combination of
@@ -1737,7 +1737,7 @@
* is installed on the device. In the unlikely case of there being
* no installed applications, an empty list is returned.
* If flag GET_UNINSTALLED_PACKAGES is set, a list of all
- * applications including those deleted with DONT_DELETE_DATA
+ * applications including those deleted with {@code DONT_DELETE_DATA}
* (partially installed apps with data directory) will be returned.
*
* @see #GET_META_DATA
@@ -2043,7 +2043,7 @@
* instrumentation class.
*
* <p>Throws {@link NameNotFoundException} if instrumentation with the
- * given class name can not be found on the system.
+ * given class name cannot be found on the system.
*
* @param className The full name (i.e.
* com.google.apps.contacts.InstrumentList) of an
@@ -2080,8 +2080,8 @@
* icon.
*
* @param packageName The name of the package that this icon is coming from.
- * Can not be null.
- * @param resid The resource identifier of the desired image. Can not be 0.
+ * Cannot be null.
+ * @param resid The resource identifier of the desired image. Cannot be 0.
* @param appInfo Overall information about <var>packageName</var>. This
* may be null, in which case the application information will be retrieved
* for you if needed; if you already have this information around, it can
@@ -2097,7 +2097,7 @@
* Retrieve the icon associated with an activity. Given the full name of
* an activity, retrieves the information about it and calls
* {@link ComponentInfo#loadIcon ComponentInfo.loadIcon()} to return its icon.
- * If the activity can not be found, NameNotFoundException is thrown.
+ * If the activity cannot be found, NameNotFoundException is thrown.
*
* @param activityName Name of the activity whose icon is to be retrieved.
*
@@ -2116,7 +2116,7 @@
* set, this simply returns the result of
* getActivityIcon(intent.getClassName()). Otherwise it resolves the intent's
* component and returns the icon associated with the resolved component.
- * If intent.getClassName() can not be found or the Intent can not be resolved
+ * If intent.getClassName() cannot be found or the Intent cannot be resolved
* to a component, NameNotFoundException is thrown.
*
* @param intent The intent for which you would like to retrieve an icon.
@@ -2155,7 +2155,7 @@
/**
* Retrieve the icon associated with an application. Given the name of the
* application's package, retrieves the information about it and calls
- * getApplicationIcon() to return its icon. If the application can not be
+ * getApplicationIcon() to return its icon. If the application cannot be
* found, NameNotFoundException is thrown.
*
* @param packageName Name of the package whose application icon is to be
@@ -2175,7 +2175,7 @@
* Retrieve the logo associated with an activity. Given the full name of
* an activity, retrieves the information about it and calls
* {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its logo.
- * If the activity can not be found, NameNotFoundException is thrown.
+ * If the activity cannot be found, NameNotFoundException is thrown.
*
* @param activityName Name of the activity whose logo is to be retrieved.
*
@@ -2195,7 +2195,7 @@
* set, this simply returns the result of
* getActivityLogo(intent.getClassName()). Otherwise it resolves the intent's
* component and returns the logo associated with the resolved component.
- * If intent.getClassName() can not be found or the Intent can not be resolved
+ * If intent.getClassName() cannot be found or the Intent cannot be resolved
* to a component, NameNotFoundException is thrown.
*
* @param intent The intent for which you would like to retrieve a logo.
@@ -2227,7 +2227,7 @@
/**
* Retrieve the logo associated with an application. Given the name of the
* application's package, retrieves the information about it and calls
- * getApplicationLogo() to return its logo. If the application can not be
+ * getApplicationLogo() to return its logo. If the application cannot be
* found, NameNotFoundException is thrown.
*
* @param packageName Name of the package whose application logo is to be
@@ -2251,8 +2251,8 @@
* labels and other text.
*
* @param packageName The name of the package that this text is coming from.
- * Can not be null.
- * @param resid The resource identifier of the desired text. Can not be 0.
+ * Cannot be null.
+ * @param resid The resource identifier of the desired text. Cannot be 0.
* @param appInfo Overall information about <var>packageName</var>. This
* may be null, in which case the application information will be retrieved
* for you if needed; if you already have this information around, it can
@@ -2269,8 +2269,8 @@
* retrieve XML meta data.
*
* @param packageName The name of the package that this xml is coming from.
- * Can not be null.
- * @param resid The resource identifier of the desired xml. Can not be 0.
+ * Cannot be null.
+ * @param resid The resource identifier of the desired xml. Cannot be 0.
* @param appInfo Overall information about <var>packageName</var>. This
* may be null, in which case the application information will be retrieved
* for you if needed; if you already have this information around, it can
@@ -2288,7 +2288,7 @@
*
* @return Returns the label associated with this application, or null if
* it could not be found for any reason.
- * @param info The application to get the label of
+ * @param info The application to get the label of.
*/
public abstract CharSequence getApplicationLabel(ApplicationInfo info);
@@ -2296,7 +2296,7 @@
* Retrieve the resources associated with an activity. Given the full
* name of an activity, retrieves the information about it and calls
* getResources() to return its application's resources. If the activity
- * can not be found, NameNotFoundException is thrown.
+ * cannot be found, NameNotFoundException is thrown.
*
* @param activityName Name of the activity whose resources are to be
* retrieved.
@@ -2327,7 +2327,7 @@
* Retrieve the resources associated with an application. Given the full
* package name of an application, retrieves the information about it and
* calls getResources() to return its application's resources. If the
- * appPackageName can not be found, NameNotFoundException is thrown.
+ * appPackageName cannot be found, NameNotFoundException is thrown.
*
* @param appPackageName Package name of the application whose resources
* are to be retrieved.
@@ -2496,7 +2496,7 @@
* {@link PackageManager#VERIFICATION_REJECT}.
*
* @param id pending package identifier as passed via the
- * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra
+ * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
* @param verificationCode either {@link PackageManager#VERIFICATION_ALLOW}
* or {@link PackageManager#VERIFICATION_REJECT}.
* @throws SecurityException if the caller does not have the
@@ -2517,7 +2517,7 @@
* will have no effect.
*
* @param id pending package identifier as passed via the
- * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra
+ * {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
* @param verificationCodeAtTimeout either
* {@link PackageManager#VERIFICATION_ALLOW} or
* {@link PackageManager#VERIFICATION_REJECT}. If
@@ -2701,16 +2701,16 @@
/**
* @deprecated This function no longer does anything; it was an old
- * approach to managing preferred activities, which has been superceeded
- * (and conflicts with) the modern activity-based preferences.
+ * approach to managing preferred activities, which has been superseded
+ * by (and conflicts with) the modern activity-based preferences.
*/
@Deprecated
public abstract void addPackageToPreferred(String packageName);
/**
* @deprecated This function no longer does anything; it was an old
- * approach to managing preferred activities, which has been superceeded
- * (and conflicts with) the modern activity-based preferences.
+ * approach to managing preferred activities, which has been superseded
+ * by (and conflicts with) the modern activity-based preferences.
*/
@Deprecated
public abstract void removePackageFromPreferred(String packageName);
@@ -2749,7 +2749,7 @@
/**
* @deprecated This is a protected API that should not have been available
* to third party applications. It is the platform's responsibility for
- * assigning preferred activities and this can not be directly modified.
+ * assigning preferred activities and this cannot be directly modified.
*
* Add a new preferred activity mapping to the system. This will be used
* to automatically select the given activity component when
@@ -2783,7 +2783,7 @@
/**
* @deprecated This is a protected API that should not have been available
* to third party applications. It is the platform's responsibility for
- * assigning preferred activities and this can not be directly modified.
+ * assigning preferred activities and this cannot be directly modified.
*
* Replaces an existing preferred activity mapping to the system, and if that were not present
* adds a new preferred activity. This will be used
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index b8ad818..08fba29 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -572,7 +572,10 @@
* are received faster. The value must be one of
* {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
* {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}
- * or, the desired delay between events in microsecond.
+ * or, the desired delay between events in microseconds.
+ * Specifying the delay in microseconds only works from Android
+ * 2.3 (API level 9) onwards. For earlier releases, you must use
+ * one of the {@code SENSOR_DELAY_*} constants.
*
* @return <code>true</code> if the sensor is supported and successfully
* enabled.
@@ -604,7 +607,10 @@
* are received faster. The value must be one of
* {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI},
* {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
- * or, the desired delay between events in microsecond.
+ * or, the desired delay between events in microseconds.
+ * Specifying the delay in microseconds only works from Android
+ * 2.3 (API level 9) onwards. For earlier releases, you must use
+ * one of the {@code SENSOR_DELAY_*} constants.
*
* @param handler
* The {@link android.os.Handler Handler} the
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 8f54a38..965d38d 100755
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1359,7 +1359,7 @@
* 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>
+ * updated on a regular basis.</td>
* </tr>
* <tr>
* <td>String</td>
@@ -4131,7 +4131,7 @@
* 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.
+ * updated on a regular basis.
* </td>
* </tr>
* <tr>
diff --git a/core/java/android/util/AttributeSet.java b/core/java/android/util/AttributeSet.java
index 470526c..74942ba 100644
--- a/core/java/android/util/AttributeSet.java
+++ b/core/java/android/util/AttributeSet.java
@@ -151,7 +151,7 @@
* Return the value of 'attribute' as a resource identifier.
*
* <p>Note that this is different than {@link #getAttributeNameResource}
- * in that it returns a the value contained in this attribute as a
+ * in that it returns the value contained in this attribute as a
* resource identifier (i.e., a value originally of the form
* "@package:type/resource"); the other method returns a resource
* identifier that identifies the name of the attribute.
@@ -230,7 +230,7 @@
* Return the value of attribute at 'index' as a resource identifier.
*
* <p>Note that this is different than {@link #getAttributeNameResource}
- * in that it returns a the value contained in this attribute as a
+ * in that it returns the value contained in this attribute as a
* resource identifier (i.e., a value originally of the form
* "@package:type/resource"); the other method returns a resource
* identifier that identifies the name of the attribute.
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8e66a77..05130a1 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2082,11 +2082,11 @@
<!-- Don't use a layer. -->
<enum name="none" value="0" />
<!-- Use a software layer. Refer to
- {@link android.view.View#setLayerType(int, android.graphics.Paint) for
+ {@link android.view.View#setLayerType(int, android.graphics.Paint)} for
more information. -->
<enum name="software" value="1" />
<!-- Use a hardware layer. Refer to
- {@link android.view.View#setLayerType(int, android.graphics.Paint) for
+ {@link android.view.View#setLayerType(int, android.graphics.Paint)} for
more information. -->
<enum name="hardware" value="2" />
</attr>
diff --git a/docs/html/google/gcm/gcm.jd b/docs/html/google/gcm/gcm.jd
index fb57a91..26fc49a 100644
--- a/docs/html/google/gcm/gcm.jd
+++ b/docs/html/google/gcm/gcm.jd
@@ -777,10 +777,11 @@
<p class="note"><strong>Note:</strong> If your organization has a firewall
that restricts the traffic to or
-from the Internet, you need to configure it to allow connectivity with GCM.
+from the Internet, you need to configure it to allow connectivity with GCM in order for
+your Android devices to receive messages.
The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but
it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should
-allow your server to accept incoming connections from all IP addresses
+allow your firewall to accept incoming connections from all IP addresses
contained in the IP blocks listed in Google's ASN of 15169.</p>
diff --git a/docs/html/guide/practices/index.jd b/docs/html/guide/practices/index.jd
index 04a43c5..48a849a 100644
--- a/docs/html/guide/practices/index.jd
+++ b/docs/html/guide/practices/index.jd
@@ -19,7 +19,7 @@
<a href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">
<h4>Say Goodbye to the Menu Button</h4>
- <p>As Ice Cream Sandwich rolls out to more devices, it?s important that you begin to migrate
+ <p>As Ice Cream Sandwich rolls out to more devices, it's important that you begin to migrate
your designs to the action bar in order to promote a consistent Android user experience.</p>
</a>
@@ -49,4 +49,4 @@
</div>
-</div>
\ No newline at end of file
+</div>
diff --git a/docs/html/guide/topics/providers/calendar-provider.jd b/docs/html/guide/topics/providers/calendar-provider.jd
index f53b062..5adc68c 100644
--- a/docs/html/guide/topics/providers/calendar-provider.jd
+++ b/docs/html/guide/topics/providers/calendar-provider.jd
@@ -605,7 +605,7 @@
Uri updateUri = null;
// The new title for the event
values.put(Events.TITLE, "Kickboxing");
-myUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
+updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
int rows = getContentResolver().update(updateUri, values, null, null);
Log.i(DEBUG_TAG, "Rows updated: " + rows); </pre>
diff --git a/docs/html/images/home/io-extended-2013.png b/docs/html/images/home/io-extended-2013.png
new file mode 100644
index 0000000..93989d4
--- /dev/null
+++ b/docs/html/images/home/io-extended-2013.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index ec0469c..29d6a8f 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -14,16 +14,16 @@
<ul>
<li class="item carousel-home">
<div class="content-left col-10">
- <img src="{@docRoot}images/home/io-logo-2013.png" style="margin:40px 0 0">
+ <img src="{@docRoot}images/home/io-extended-2013.png" style="margin:90px 0 0">
</div>
<div class="content-right col-5">
- <h1>Google I/O 2013</h1>
- <p>Android will be at Google I/O on May 15-17, 2013, with sessions covering a variety of topics
- such as design, performance, and how to extend your app with the latest Android features.</p>
- <p>For more information about event details and planned sessions,
- stay tuned to <a
- href="http://google.com/+GoogleDevelopers">+Google Developers</a>.</p>
- <p><a href="https://developers.google.com/events/io/" class="button">Learn more</a></p>
+ <h1>Google I/O Extended</h1>
+ <p>Android will be at Google I/O on May 15-17, 2013, with sessions covering topics
+ such as design, performance, and how to enhance your app with the latest Android features.</p>
+ <p>Even if you can't make it there, you can experience the excitement and innovation of
+ Google I/O remotely with Google I/O Extended.</p>
+ <p><a href="https://developers.google.com/events/io/io-extended/?utm_source=site&utm_medium=emb&utm_campaign=extended-android-site"
+ >Organize or attend an event near you »</a></p>
</div>
</li>
<li class="item carousel-home">
diff --git a/docs/html/tools/devices/emulator.jd b/docs/html/tools/devices/emulator.jd
index cee6473..bae3985 100644
--- a/docs/html/tools/devices/emulator.jd
+++ b/docs/html/tools/devices/emulator.jd
@@ -1254,7 +1254,7 @@
<td> </td>
</tr>
<tr>
- <td><code>power health <percent></code></td>
+ <td><code>capacity <percent></code></td>
<td>Set remaining battery capacity state (0-100).</td>
<td> </td>
</tr>
diff --git a/docs/html/tools/testing/testing_otheride.jd b/docs/html/tools/testing/testing_otheride.jd
index 0678f52..9484158 100644
--- a/docs/html/tools/testing/testing_otheride.jd
+++ b/docs/html/tools/testing/testing_otheride.jd
@@ -75,9 +75,9 @@
<p>
You use the <code>android</code> tool to create test projects.
You also use <code>android</code> to convert existing test code into an Android test project,
- or to add the <code>run-tests</code> Ant target to an existing Android test project.
+ or to add the <code>test</code> Ant target to an existing Android test project.
These operations are described in more detail in the section <a href="#UpdateTestProject">
- Updating a test project</a>. The <code>run-tests</code> target is described in
+ Updating a test project</a>. The <code>test</code> target is described in
<a href="#RunTestsAnt">Quick build and run with Ant</a>.
</p>
<h3 id="CreateTestProject">Creating a test project</h3>
@@ -300,7 +300,7 @@
<h3 id="RunTestsAnt">Quick build and run with Ant</h3>
<p>
You can use Ant to run all the tests in your test project, using the target
- <code>run-tests</code>, which is created automatically when you create a test project with
+ <code>test</code>, which is created automatically when you create a test project with
the <code>android</code> tool.
</p>
<p>
diff --git a/docs/html/training/basics/data-storage/databases.jd b/docs/html/training/basics/data-storage/databases.jd
index 9976bb1..61fb758 100644
--- a/docs/html/training/basics/data-storage/databases.jd
+++ b/docs/html/training/basics/data-storage/databases.jd
@@ -284,7 +284,7 @@
// Define 'where' part of query.
String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
// Specify arguments in placeholder order.
-String[] selelectionArgs = { String.valueOf(rowId) };
+String[] selectionArgs = { String.valueOf(rowId) };
// Issue SQL statement.
db.delete(table_name, selection, selectionArgs);
</pre>
@@ -309,7 +309,7 @@
// Which row to update, based on the ID
String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
-String[] selelectionArgs = { String.valueOf(rowId) };
+String[] selectionArgs = { String.valueOf(rowId) };
int count = db.update(
FeedReaderDbHelper.FeedEntry.TABLE_NAME,
diff --git a/docs/html/training/basics/intents/result.jd b/docs/html/training/basics/intents/result.jd
index 0086913..24ecc46 100644
--- a/docs/html/training/basics/intents/result.jd
+++ b/docs/html/training/basics/intents/result.jd
@@ -62,7 +62,7 @@
static final int PICK_CONTACT_REQUEST = 1; // The request code
...
private void pickContact() {
- Intent pickContactIntent = new Intent(Intent.ACTION_PICK, new Uri("content://contacts"));
+ Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));
pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}
diff --git a/docs/html/training/contacts-provider/ContactsList.zip b/docs/html/training/contacts-provider/ContactsList.zip
new file mode 100644
index 0000000..d2a5cfb
--- /dev/null
+++ b/docs/html/training/contacts-provider/ContactsList.zip
Binary files differ
diff --git a/docs/html/training/contacts-provider/display-contact-badge.jd b/docs/html/training/contacts-provider/display-contact-badge.jd
new file mode 100644
index 0000000..f08935d
--- /dev/null
+++ b/docs/html/training/contacts-provider/display-contact-badge.jd
@@ -0,0 +1,635 @@
+page.title=Displaying the Quick Contact Badge
+
+trainingnavtop=true
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li>
+ <a href="#AddView">Add a QuickContactBadge View</a>
+ </li>
+ <li>
+ <a href="#SetURIThumbnail">Set the Contact URI and Thumbnail</a>
+ </li>
+ <li>
+ <a href="#ListView">
+ Add a QuickContactBadge to a ListView
+ </a>
+ </li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+ Content Provider Basics
+ </a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/contacts-provider.html">
+ Contacts Provider
+ </a>
+ </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/ContactsList.zip" class="button">
+ Download the sample
+ </a>
+ <p class="filename">ContactsList.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+ This lesson shows you how to add a {@link android.widget.QuickContactBadge} to your UI
+ and how to bind data to it. A {@link android.widget.QuickContactBadge} is a widget that
+ initially appears as a thumbnail image. Although you can use any {@link android.graphics.Bitmap}
+ for the thumbnail image, you usually use a {@link android.graphics.Bitmap} decoded from the
+ contact's photo thumbnail image.
+</p>
+<p>
+ The small image acts as a control; when users click on the image, the
+ {@link android.widget.QuickContactBadge} expands into a dialog containing the following:
+</p>
+<dl>
+ <dt>A large image</dt>
+ <dd>
+ The large image associated with the contact, or no image is available, a placeholder
+ graphic.
+ </dd>
+ <dt>
+ App icons
+ </dt>
+ <dd>
+ An app icon for each piece of detail data that can be handled by a built-in app. For
+ example, if the contact's details include one or more email addresses, an email icon
+ appears. When users click the icon, all of the contact's email addresses appear. When users
+ click one of the addresses, the email app displays a screen for composing a message to the
+ selected email address.
+ </dd>
+</dl>
+<p>
+ The {@link android.widget.QuickContactBadge} view provides instant access to a contact's
+ details, as well as a fast way of communicating with the contact. Users don't have to look up
+ a contact, find and copy information, and then paste it into the appropriate app. Instead, they
+ can click on the {@link android.widget.QuickContactBadge}, choose the communication method they
+ want to use, and send the information for that method directly to the appropriate app.
+</p>
+<h2 id="AddView">Add a QuickContactBadge View</h2>
+<p>
+ To add a {@link android.widget.QuickContactBadge}, insert a
+ <code><QuickContactBadge></code> element in your layout. For example:
+</p>
+<pre>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+...
+ <QuickContactBadge
+ android:id=@+id/quickbadge
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"/>
+ ...
+</RelativeLayout>
+</pre>
+<h2 id="">Retrieve provider data</h2>
+<p>
+ To display a contact in the {@link android.widget.QuickContactBadge}, you need a content URI
+ for the contact and a {@link android.graphics.Bitmap} for the small image. You generate
+ both the content URI and the {@link android.graphics.Bitmap} from columns retrieved from the
+ Contacts Provider. Specify these columns as part of the projection you use to load data into
+ your {@link android.database.Cursor}.
+</p>
+<p>
+ For Android 3.0 (API level 11) and later, include the following columns in your projection:</p>
+<ul>
+ <li>{@link android.provider.ContactsContract.Contacts#_ID Contacts._ID}</li>
+ <li>{@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
+ <li>
+ {@link android.provider.ContactsContract.Contacts#PHOTO_THUMBNAIL_URI
+ Contacts.PHOTO_THUMBNAIL_URI}
+ </li>
+</ul>
+<p>
+ For Android 2.3.3 (API level 10) and earlier, use the following columns:
+</p>
+<ul>
+ <li>{@link android.provider.ContactsContract.Contacts#_ID Contacts._ID}</li>
+ <li>{@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY}</li>
+</ul>
+<p>
+ The remainder of this lesson assumes that you've already loaded a
+ {@link android.database.Cursor} that contains these columns as well as others you may have
+ chosen. To learn how to retrieve this columns in a {@link android.database.Cursor}, read the
+ lesson <a href="retrieve-names.html">Retrieving a List of Contacts</a>.
+</p>
+<h2 id="SetURIThumbnail">Set the Contact URI and Thumbnail</h2>
+<p>
+ Once you have the necessary columns, you can bind data to the
+ {@link android.widget.QuickContactBadge}.
+</p>
+<h3>Set the Contact URI</h3>
+<p>
+ To set the content URI for the contact, call
+ {@link android.provider.ContactsContract.Contacts#getLookupUri getLookupUri(id,lookupKey)} to
+ get a {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}, then
+ call {@link android.widget.QuickContactBadge#assignContactUri assignContactUri()} to set the
+ contact. For example:
+</p>
+<pre>
+ // The Cursor that contains contact rows
+ Cursor mCursor;
+ // The index of the _ID column in the Cursor
+ int mIdColumn;
+ // The index of the LOOKUP_KEY column in the Cursor
+ int mLookupKeyColumn;
+ // A content URI for the desired contact
+ Uri mContactUri;
+ // A handle to the QuickContactBadge view
+ QuickContactBadge mBadge;
+ ...
+ mBadge = (QuickContactBadge) findViewById(R.id.quickbadge);
+ /*
+ * Insert code here to move to the desired cursor row
+ */
+ // Gets the _ID column index
+ mIdColumn = mCursor.getColumnIndex(Contacts._ID);
+ // Gets the LOOKUP_KEY index
+ mLookupKeyColumn = mCursor.getColumnIndex(Contacts.LOOKUP_KEY);
+ // Gets a content URI for the contact
+ mContactUri =
+ Contacts.getLookupUri(
+ Cursor.getLong(mIdColumn),
+ Cursor.getString(mLookupKeyColumn)
+ );
+ mBadge.assignContactUri(mContactUri);
+</pre>
+<p>
+ When users click the {@link android.widget.QuickContactBadge} icon, the contact's
+ details automatically appear in the dialog.
+</p>
+<h3>Set the photo thumbnail</h3>
+<p>
+ Setting the contact URI for the {@link android.widget.QuickContactBadge} does not automatically
+ load the contact's thumbnail photo. To load the photo, get a URI for the photo from the
+ contact's {@link android.database.Cursor} row, use it to open the file containing the compressed
+ thumbnail photo, and read the file into a {@link android.graphics.Bitmap}.
+</p>
+<p class="note">
+ <strong>Note:</strong> The
+ {@link android.provider.ContactsContract.Contacts#PHOTO_THUMBNAIL_URI} column isn't available
+ in platform versions prior to 3.0. For those versions, you must retrieve the URI
+ from the {@link android.provider.ContactsContract.Contacts.Photo Contacts.Photo} subtable.
+</p>
+<p>
+ First, set up variables for accessing the {@link android.database.Cursor} containing the
+ {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
+ {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} columns, as
+ described previously:
+</p>
+<pre>
+ // The column in which to find the thumbnail ID
+ int mThumbnailColumn;
+ /*
+ * The thumbnail URI, expressed as a String.
+ * Contacts Provider stores URIs as String values.
+ */
+ String mThumbnailUri;
+ ...
+ /*
+ * Gets the photo thumbnail column index if
+ * platform version >= Honeycomb
+ */
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ mThumbnailColumn =
+ mCursor.getColumnIndex(Contacts.PHOTO_THUMBNAIL_URI);
+ // Otherwise, sets the thumbnail column to the _ID column
+ } else {
+ mThumbnailColumn = mIdColumn;
+ }
+ /*
+ * Assuming the current Cursor position is the contact you want,
+ * gets the thumbnail ID
+ */
+ mThumbnailUri = Cursor.getString(mThumbnailColumn);
+ ...
+</pre>
+<p>
+ Define a method that takes photo-related data for the contact and dimensions for the
+ destination view, and returns the properly-sized thumbnail in a
+ {@link android.graphics.Bitmap}. Start by constructing a URI that points to the
+ thumbnail:
+<p>
+<pre>
+ /**
+ * Load a contact photo thumbnail and return it as a Bitmap,
+ * resizing the image to the provided image dimensions as needed.
+ * @param photoData photo ID Prior to Honeycomb, the contact's _ID value.
+ * For Honeycomb and later, the value of PHOTO_THUMBNAIL_URI.
+ * @return A thumbnail Bitmap, sized to the provided width and height.
+ * Returns null if the thumbnail is not found.
+ */
+ private Bitmap loadContactPhotoThumbnail(String photoData) {
+ // Creates an asset file descriptor for the thumbnail file.
+ AssetFileDescriptor afd = null;
+ // try-catch block for file not found
+ try {
+ // Creates a holder for the URI.
+ Uri thumbUri;
+ // If Android 3.0 or later
+ if (Build.VERSION.SDK_INT
+ >=
+ Build.VERSION_CODES.HONEYCOMB) {
+ // Sets the URI from the incoming PHOTO_THUMBNAIL_URI
+ thumbUri = Uri.parse(photoData);
+ } else {
+ // Prior to Android 3.0, constructs a photo Uri using _ID
+ /*
+ * Creates a contact URI from the Contacts content URI
+ * incoming photoData (_ID)
+ */
+ final Uri contactUri = Uri.withAppendedPath(
+ Contacts.CONTENT_URI, photoData);
+ /*
+ * Creates a photo URI by appending the content URI of
+ * Contacts.Photo.
+ */
+ thumbUri =
+ Uri.withAppendedPath(
+ contactUri, Photo.CONTENT_DIRECTORY);
+ }
+
+ /*
+ * Retrieves an AssetFileDescriptor object for the thumbnail
+ * URI
+ * using ContentResolver.openAssetFileDescriptor
+ */
+ afd = getActivity().getContentResolver().
+ openAssetFileDescriptor(thumbUri, "r");
+ /*
+ * Gets a file descriptor from the asset file descriptor.
+ * This object can be used across processes.
+ */
+ FileDescriptor fileDescriptor = afd.getFileDescriptor();
+ // Decode the photo file and return the result as a Bitmap
+ // If the file descriptor is valid
+ if (fileDescriptor != null) {
+ // Decodes the bitmap
+ return BitmapFactory.decodeFileDescriptor(
+ fileDescriptor, null, null);
+ }
+ // If the file isn't found
+ } catch (FileNotFoundException e) {
+ /*
+ * Handle file not found errors
+ */
+ }
+ // In all cases, close the asset file descriptor
+ } finally {
+ if (afd != null) {
+ try {
+ afd.close();
+ } catch (IOException e) {}
+ }
+ }
+ return null;
+ }
+</pre>
+<p>
+ Call the <code>loadContactPhotoThumbnail()</code> method in your code to get the
+ thumbnail {@link android.graphics.Bitmap}, and use the result to set the photo thumbnail in
+ your {@link android.widget.QuickContactBadge}:
+</p>
+<pre>
+ ...
+ /*
+ * Decodes the thumbnail file to a Bitmap.
+ */
+ Bitmap mThumbnail =
+ loadContactPhotoThumbnail(mThumbnailUri);
+ /*
+ * Sets the image in the QuickContactBadge
+ * QuickContactBadge inherits from ImageView, so
+ */
+ mBadge.setImageBitmap(mThumbnail);
+</pre>
+<h2 id="ListView">Add a QuickContactBadge to a ListView</h2>
+<p>
+ A {@link android.widget.QuickContactBadge} is a useful addition to a
+ {@link android.widget.ListView} that displays a list of contacts. Use the
+ {@link android.widget.QuickContactBadge} to display a thumbnail photo for each contact; when
+ users click the thumbnail, the {@link android.widget.QuickContactBadge} dialog appears.
+</p>
+<h3>Add the QuickContactBadge element</h3>
+<p>
+ To start, add a {@link android.widget.QuickContactBadge} view element to your item layout
+ For example, if you want to display a {@link android.widget.QuickContactBadge} and a name for
+ each contact you retrieve, put the following XML into a layout file:
+</p>
+<pre>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <QuickContactBadge
+ android:id="@+id/quickcontact"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"/>
+ <TextView android:id="@+id/displayname"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@+id/quickcontact"
+ android:gravity="center_vertical"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"/>
+</RelativeLayout>
+</pre>
+<p>
+ In the following sections, this file is referred to as <code>contact_item_layout.xml</code>.
+</p>
+<h3>Set up a custom CursorAdapter</h3>
+<p>
+ To bind a {@link android.support.v4.widget.CursorAdapter} to a {@link android.widget.ListView}
+ containing a {@link android.widget.QuickContactBadge}, define a custom adapter that
+ extends {@link android.support.v4.widget.CursorAdapter}. This approach allows you to process the
+ data in the {@link android.database.Cursor} before you bind it to the
+ {@link android.widget.QuickContactBadge}. This approach also allows you to bind multiple
+ {@link android.database.Cursor} columns to the {@link android.widget.QuickContactBadge}. Neither
+ of these operations is possible in a regular {@link android.support.v4.widget.CursorAdapter}.
+</p>
+<p>
+ The subclass of {@link android.support.v4.widget.CursorAdapter} that you define must
+ override the following methods:
+</p>
+<dl>
+ <dt>{@link android.support.v4.widget.CursorAdapter#newView CursorAdapter.newView()}</dt>
+ <dd>
+ Inflates a new {@link android.view.View} object to hold the item layout. In the override
+ of this method, store handles to the child {@link android.view.View} objects of the layout,
+ including the child {@link android.widget.QuickContactBadge}. By taking this approach, you
+ avoid having to get handles to the child {@link android.view.View} objects each time you
+ inflate a new layout.
+ <p>
+ You must override this method so you can get handles to the individual child
+ {@link android.view.View} objects. This technique allows you to control their binding in
+ {@link android.support.v4.widget.CursorAdapter#bindView CursorAdapter.bindView()}.
+ </p>
+ </dd>
+ <dt>{@link android.support.v4.widget.CursorAdapter#bindView CursorAdapter.bindView()}</dt>
+ <dd>
+ Moves data from the current {@link android.database.Cursor} row to the child
+ {@link android.view.View} objects of the item layout. You must override this method so
+ you can bind both the contact's URI and thumbnail to the
+ {@link android.widget.QuickContactBadge}. The default implementation only allows a 1-to-1
+ mapping between a column and a {@link android.view.View}
+ </dd>
+</dl>
+<p>
+ The following code snippet contains an example of a custom subclass of
+ {@link android.support.v4.widget.CursorAdapter}:
+</p>
+<h3>Define the custom list adapter</h3>
+<p>
+ Define the subclass of {@link android.support.v4.widget.CursorAdapter} including its
+ constructor, and override
+ {@link android.support.v4.widget.CursorAdapter#newView newView()} and
+ {@link android.support.v4.widget.CursorAdapter#bindView bindView()}:
+</p>
+<pre>
+ /**
+ *
+ *
+ */
+ private class ContactsAdapter extends CursorAdapter {
+ private LayoutInflater mInflater;
+ ...
+ public ContactsAdapter(Context context) {
+ super(context, null, 0);
+
+ /*
+ * Gets an inflater that can instantiate
+ * the ListView layout from the file.
+ */
+ mInflater = LayoutInflater.from(context);
+ ...
+ }
+ ...
+ /**
+ * Defines a class that hold resource IDs of each item layout
+ * row to prevent having to look them up each time data is
+ * bound to a row.
+ */
+ private class ViewHolder {
+ TextView displayname;
+ QuickContactBadge quickcontact;
+ }
+ ..
+ @Override
+ public View newView(
+ Context context,
+ Cursor cursor,
+ ViewGroup viewGroup) {
+ /* Inflates the item layout. Stores resource IDs in a
+ * in a ViewHolder class to prevent having to look
+ * them up each time bindView() is called.
+ */
+ final View itemView =
+ mInflater.inflate(
+ R.layout.contact_list_layout,
+ viewGroup,
+ false
+ );
+ final ViewHolder holder = new ViewHolder();
+ holder.displayname =
+ (TextView) view.findViewById(R.id.displayname);
+ holder.quickcontact =
+ (QuickContactBadge)
+ view.findViewById(R.id.quickcontact);
+ view.setTag(holder);
+ return view;
+ }
+ ...
+ @Override
+ public void bindView(
+ View view,
+ Context context,
+ Cursor cursor) {
+ final ViewHolder holder = (ViewHolder) view.getTag();
+ final String photoData =
+ cursor.getString(mPhotoDataIndex);
+ final String displayName =
+ cursor.getString(mDisplayNameIndex);
+ ...
+ // Sets the display name in the layout
+ holder.displayname = cursor.getString(mDisplayNameIndex);
+ ...
+ /*
+ * Generates a contact URI for the QuickContactBadge.
+ */
+ final Uri contactUri = Contacts.getLookupUri(
+ cursor.getLong(mIdIndex),
+ cursor.getString(mLookupKeyIndex));
+ holder.quickcontact.assignContactUri(contactUri);
+ String photoData = cursor.getString(mPhotoDataIndex);
+ /*
+ * Decodes the thumbnail file to a Bitmap.
+ * The method loadContactPhotoThumbnail() is defined
+ * in the section "Set the Contact URI and Thumbnail"
+ */
+ Bitmap thumbnailBitmap =
+ loadContactPhotoThumbnail(photoData);
+ /*
+ * Sets the image in the QuickContactBadge
+ * QuickContactBadge inherits from ImageView
+ */
+ holder.quickcontact.setImageBitmap(thumbnailBitmap);
+ }
+</pre>
+
+<h3>Set up variables</h3>
+<p>
+ In your code, set up variables, including a {@link android.database.Cursor} projection that
+ includes the necessary columns.
+</p>
+<p class="note">
+ <strong>Note:</strong> The following code snippets use the method
+ <code>loadContactPhotoThumbnail()</code>, which is defined in the section
+ <a href="#SetURIThumbnail">Set the Contact URI and Thumbnail</a>
+</p>
+<p>
+ For example:
+</p>
+<pre>
+public class ContactsFragment extends Fragment implements
+ LoaderManager.LoaderCallbacks<Cursor> {
+...
+ // Defines a ListView
+ private ListView mListView;
+ // Defines a ContactsAdapter
+ private ContactsAdapter mAdapter;
+ ...
+ // Defines a Cursor to contain the retrieved data
+ private Cursor mCursor;
+ /*
+ * Defines a projection based on platform version. This ensures
+ * that you retrieve the correct columns.
+ */
+ private static final String[] PROJECTION =
+ {
+ Contacts._ID,
+ Contacts.LOOKUP_KEY,
+ (Build.VERSION.SDK_INT >=
+ Build.VERSION_CODES.HONEYCOMB) ?
+ Contacts.DISPLAY_NAME_PRIMARY :
+ Contacts.DISPLAY_NAME
+ (Build.VERSION.SDK_INT >=
+ Build.VERSION_CODES.HONEYCOMB) ?
+ Contacts.PHOTO_THUMBNAIL_ID :
+ /*
+ * Although it's not necessary to include the
+ * column twice, this keeps the number of
+ * columns the same regardless of version
+ */
+ Contacts_ID
+ ...
+ };
+ /*
+ * As a shortcut, defines constants for the
+ * column indexes in the Cursor. The index is
+ * 0-based and always matches the column order
+ * in the projection.
+ */
+ // Column index of the _ID column
+ private int mIdIndex = 0;
+ // Column index of the LOOKUP_KEY column
+ private int mLookupKeyIndex = 1;
+ // Column index of the display name column
+ private int mDisplayNameIndex = 3;
+ /*
+ * Column index of the photo data column.
+ * It's PHOTO_THUMBNAIL_URI for Honeycomb and later,
+ * and _ID for previous versions.
+ */
+ private int mPhotoDataIndex =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
+ 3 :
+ 0;
+ ...
+</pre>
+<h3>Set up the ListView</h3>
+<p>
+ In {@link android.support.v4.app.Fragment#onCreate Fragment.onCreate()}, instantiate the custom
+ cursor adapter and get a handle to the {@link android.widget.ListView}:
+</p>
+<pre>
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ ...
+ /*
+ * Instantiates the subclass of
+ * CursorAdapter
+ */
+ ContactsAdapter mContactsAdapter =
+ new ContactsAdapter(getActivity());
+ /*
+ * Gets a handle to the ListView in the file
+ * contact_list_layout.xml
+ */
+ mListView = (ListView) findViewById(R.layout.contact_list_layout);
+ ...
+ }
+ ...
+</pre>
+<p>
+ In {@link android.support.v4.app.Fragment#onActivityCreated onActivityCreated()}, bind the
+ <code>ContactsAdapter</code> to the {@link android.widget.ListView}:
+</p>
+<pre>
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ ...
+ // Sets up the adapter for the ListView
+ mListView.setAdapter(mAdapter);
+ ...
+ }
+ ...
+</pre>
+<p>
+ When you get back a {@link android.database.Cursor} containing the contacts data, usually in
+ {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()},
+ call {@link android.support.v4.widget.CursorAdapter#swapCursor swapCursor()} to move the
+ {@link android.database.Cursor} data to the {@link android.widget.ListView}. This displays the
+ {@link android.widget.QuickContactBadge} for each entry in the list of contacts:
+</p>
+<pre>
+ public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
+ // When the loader has completed, swap the cursor into the adapter.
+ mContactsAdapter.swapCursor(cursor);
+ }
+</pre>
+<p>
+ When you bind a {@link android.database.Cursor} to a
+ {@link android.widget.ListView} with a {@link android.support.v4.widget.CursorAdapter}
+ (or subclass), and you use a {@link android.support.v4.content.CursorLoader} to load the
+ {@link android.database.Cursor}, always clear references to the {@link android.database.Cursor}
+ in your implementation of
+ {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset onLoaderReset()}.
+ For example:
+</p>
+<pre>
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ // Removes remaining reference to the previous Cursor
+ mContactsAdapter.swapCursor(null);
+ }
+</pre>
diff --git a/docs/html/training/contacts-provider/index.jd b/docs/html/training/contacts-provider/index.jd
new file mode 100644
index 0000000..f380d95
--- /dev/null
+++ b/docs/html/training/contacts-provider/index.jd
@@ -0,0 +1,97 @@
+page.title=Accessing Contacts Data
+
+trainingnavtop=true
+startpage=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
+<h2>Dependencies and prerequisites</h2>
+<ul>
+ <li>Android 2.0 (API Level 5) or higher</li>
+ <li>Experience in using {@link android.content.Intent} objects</li>
+ <li>Experience in using content providers</li>
+</ul>
+
+<!-- related docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+ Content Provider Basics</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/contacts-provider.html">
+ Contacts Provider</a>
+ </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/ContactsList.zip" class="button">
+ Download the sample
+ </a>
+ <p class="filename">ContactsList.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>
+ The <a href="{@docRoot}guide/topics/providers/contacts-provider.html">Contacts Provider</a> is
+ the central repository of the user's contacts information, including data from contacts apps and
+ social networking apps. In your apps, you can access Contacts Provider information directly by
+ calling {@link android.content.ContentResolver} methods or by sending intents to a contacts app.
+</p>
+<p>
+ This class focuses on retrieving lists of contacts, displaying the details for a particular
+ contact, and modifying contacts using intents. The basic techniques described
+ here can be extended to perform more complex tasks. In addition, this class helps you
+ understand the overall structure and operation of the
+ <a href="{@docRoot}guide/topics/providers/contacts-provider.html">Contacts Provider</a>.
+</p>
+<h2>Lessons</h2>
+
+<dl>
+ <dt>
+ <b><a href="retrieve-names.html">Retrieving a List of Contacts</a></b>
+ </dt>
+ <dd>
+ Learn how to retrieve a list of contacts for which the data matches all or part of a search
+ string, using the following techniques:
+ <ul>
+ <li>Match by contact name</li>
+ <li>Match any type of contact data</li>
+ <li>Match a specific type of contact data, such as a phone number</li>
+ </ul>
+ </dd>
+ <dt>
+ <b><a href="retrieve-details.html">Retrieving Details for a Contact</a></b>
+ </dt>
+ <dd>
+ Learn how to retrieve the details for a single contact. A contact's details are data
+ such as phone numbers and email addresses. You can retrieve all details, or you can
+ retrieve details of a specific type, such as all email addresses.
+ </dd>
+ <dt>
+ <b><a href="modify-data.html">Modifying Contacts Using Intents</a></b>
+ </dt>
+ <dd>
+ Learn how to modify a contact by sending an intent to the People app.
+ </dd>
+ <dt>
+ <b>
+ <a href="display-contact-badge.html">Displaying the Quick Contact Badge</a>
+ </b>
+ </dt>
+ <dd>
+ Learn how to display the {@link android.widget.QuickContactBadge} widget. When the user
+ clicks the contact badge widget, a dialog opens that displays the contact's details and
+ action buttons for apps that can handle the details. For example, if the contact has an
+ email address, the dialog displays an action button for the default email app.
+ </dd>
+</dl>
diff --git a/docs/html/training/contacts-provider/modify-data.jd b/docs/html/training/contacts-provider/modify-data.jd
new file mode 100644
index 0000000..64853ef
--- /dev/null
+++ b/docs/html/training/contacts-provider/modify-data.jd
@@ -0,0 +1,305 @@
+page.title=Modifying Contacts Using Intents
+trainingnavtop=true
+@jd:body
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#InsertContact">Insert a New Contact Using an Intent</a></li>
+ <li><a href="#EditContact">Edit an Existing Contact Using an Intent</a></li>
+ <li><a href="#InsertEdit">Let Users Choose to Insert or Edit Using an Intent</a>
+</ol>
+<h2>You should also read</h2>
+<ul>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+ Content Provider Basics
+ </a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/contacts-provider.html">
+ Contacts Provider
+ </a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/components/intents-filters.html">Intents and Intent Filters</a>
+ </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/ContactsList.zip" class="button">
+ Download the sample
+ </a>
+ <p class="filename">ContactsList.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+ This lesson shows you how to use an {@link android.content.Intent} to insert a new contact or
+ modify a contact's data. Instead of accessing the Contacts Provider directly, an
+ {@link android.content.Intent} starts the contacts app, which runs the appropriate
+ {@link android.app.Activity}. For the modification actions described in this lesson,
+ if you send extended data in the {@link android.content.Intent} it's entered into the UI of the
+ {@link android.app.Activity} that is started.
+</p>
+<p>
+ Using an {@link android.content.Intent} to insert or update a single contact is the preferred
+ way of modifying the Contacts Provider, for the following reasons:
+</p>
+<ul>
+ <li>It saves you the time and and effort of developing your own UI and code.</li>
+ <li>
+ It avoids introducing errors caused by modifications that don't follow the
+ Contacts Provider's rules.
+ </li>
+ <li>
+ It reduces the number of permissions you need to request. Your app doesn't need permission
+ to write to the Contacts Provider, because it delegates modifications to the contacts app,
+ which already has that permission.
+ </li>
+</ul>
+<h2 id="InsertContact">Insert a New Contact Using an Intent</h2>
+<p>
+ You often want to allow the user to insert a new contact when your app receives new data. For
+ example, a restaurant review app can allow users to add the restaurant as a contact as they're
+ reviewing it. To do this using an intent, create the intent using as much data as you have
+ available, and then send the intent to the contacts app.
+</p>
+<p>
+ Inserting a contact using the contacts app inserts a new <em>raw</em> contact into the Contacts
+ Provider's {@link android.provider.ContactsContract.RawContacts} table. If necessary,
+ the contacts app prompts users for the account type and account to use when creating the raw
+ contact. The contacts app also notifies users if the raw contact already exists. Users then have
+ option of canceling the insertion, in which case no contact is created. To learn
+ more about raw contacts, see the
+ <a href="{@docRoot}guide/topics/providers/contacts-provider.html">Contacts Provider</a>
+ API guide.
+</p>
+
+<h3>Create an Intent</h3>
+<p>
+ To start, create a new {@link android.content.Intent} object with the action
+ {@link android.provider.ContactsContract.Intents.Insert#ACTION Intents.Insert.ACTION}.
+ Set the MIME type to {@link android.provider.ContactsContract.RawContacts#CONTENT_TYPE
+ RawContacts.CONTENT_TYPE}. For example:
+</p>
+<pre>
+...
+// Creates a new Intent to insert a contact
+Intent intent = new Intent(Intents.Insert.ACTION);
+// Sets the MIME type to match the Contacts Provider
+intent.setType(ContactsContract.RawContacts.CONTENT_TYPE);
+</pre>
+<p>
+ If you already have details for the contact, such as a phone number or email address, you can
+ insert them into the intent as extended data. For a key value, use the appropriate constant from
+ {@link android.provider.ContactsContract.Intents.Insert Intents.Insert}. The contacts app
+ displays the data in its insert screen, allowing users to make further edits and additions.
+</p>
+<pre>
+/* Assumes EditText fields in your UI contain an email address
+ * and a phone number.
+ *
+ */
+private EditText mEmailAddress = (EditText) findViewById(R.id.email);
+private EditText mPhoneNumber = (EditText) findViewById(R.id.phone);
+...
+/*
+ * Inserts new data into the Intent. This data is passed to the
+ * contacts app's Insert screen
+ */
+// Inserts an email address
+intent.putExtra(Intents.Insert.EMAIL, mEmailAddress.getText())
+/*
+ * In this example, sets the email type to be a work email.
+ * You can set other email types as necessary.
+ */
+ .putExtra(Intents.Insert.EMAIL_TYPE, CommonDataKinds.Email.TYPE_WORK)
+// Inserts a phone number
+ .putExtra(Intents.Insert.PHONE, mPhoneNumber.getText())
+/*
+ * In this example, sets the phone type to be a work phone.
+ * You can set other phone types as necessary.
+ */
+ .putExtra(Intents.Insert.PHONE_TYPE, Phone.TYPE_WORK);
+
+</pre>
+<p>
+ Once you've created the {@link android.content.Intent}, send it by calling
+ {@link android.support.v4.app.Fragment#startActivity startActivity()}.
+</p>
+<pre>
+ /* Sends the Intent
+ */
+ startActivity(intent);
+</pre>
+<p>
+ This call opens a screen in the contacts app that allows users to enter a new contact. The
+ account type and account name for the contact is listed at the top of the screen. Once users
+ enter the data and click <i>Done</i>, the contacts app's contact list appears. Users return to
+ your app by clicking <i>Back</i>.
+</p>
+<h2 id="EditContact">Edit an Existing Contact Using an Intent</h2>
+<p>
+ Editing an existing contact using an {@link android.content.Intent} is useful if the user
+ has already chosen a contact of interest. For example, an app that finds contacts that have
+ postal addresses but lack a postal code could give users the option of looking up the code and
+ then adding it to the contact.
+</p>
+<p>
+ To edit an existing contact using an intent, use a procedure similar to
+ inserting a contact. Create an intent as described in the section
+ <a href="#InsertContact">Insert a New Contact Using an Intent</a>, but add the contact's
+ {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI
+ Contacts.CONTENT_LOOKUP_URI} and the MIME type
+ {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE
+ Contacts.CONTENT_ITEM_TYPE} to the intent. If you want to edit the contact with details you
+ already have, you can put them in the intent's extended data. Notice that some
+ name columns can't be edited using an intent; these columns are listed in the summary
+ section of the API reference for the class {@link android.provider.ContactsContract.Contacts}
+ under the heading "Update".
+</p>
+<p>
+ Finally, send the intent. In response, the contacts app displays an edit screen. When the user
+ finishes editing and saves the edits, the contacts app displays a contact list. When the user
+ clicks <i>Back</i>, your app is displayed.
+</p>
+<div class="sidebox-wrapper">
+<div class="sidebox">
+ <h2>Contacts Lookup Key</h2>
+ <p>
+ A contact's {@link android.provider.ContactsContract.ContactsColumns#LOOKUP_KEY} value is
+ the identifier that you should use to retrieve a contact. It remains constant,
+ even if the provider changes the contact's row ID to handle internal operations.
+ </p>
+</div>
+</div>
+<h3>Create the Intent</h3>
+<p>
+ To edit a contact, call {@link android.content.Intent#Intent Intent(action)} to
+ create an intent with the action {@link android.content.Intent#ACTION_EDIT}. Call
+ {@link android.content.Intent#setDataAndType setDataAndType()} to set the data value for the
+ intent to the contact's {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI
+ Contacts.CONTENT_LOOKUP_URI} and the MIME type to
+ {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE
+ Contacts.CONTENT_ITEM_TYPE} MIME type; because a call to
+ {@link android.content.Intent#setType setType()} overwrites the current data value for the
+ {@link android.content.Intent}, you must set the data and the MIME type at the same time.
+</p>
+<p>
+ To get a contact's {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI
+ Contacts.CONTENT_LOOKUP_URI}, call
+ {@link android.provider.ContactsContract.Contacts#getLookupUri
+ Contacts.getLookupUri(id, lookupkey)} with the contact's
+ {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
+ {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} values as
+ arguments.
+</p>
+<p>
+ The following snippet shows you how to create an intent:
+</p>
+<pre>
+ // The Cursor that contains the Contact row
+ public Cursor mCursor;
+ // The index of the lookup key column in the cursor
+ public int mLookupKeyIndex;
+ // The index of the contact's _ID value
+ public int mIdIndex;
+ // The lookup key from the Cursor
+ public String mCurrentLookupKey;
+ // The _ID value from the Cursor
+ public long mCurrentId;
+ // A content URI pointing to the contact
+ Uri mSelectedContactUri;
+ ...
+ /*
+ * Once the user has selected a contact to edit,
+ * this gets the contact's lookup key and _ID values from the
+ * cursor and creates the necessary URI.
+ */
+ // Gets the lookup key column index
+ mLookupKeyIndex = mCursor.getColumnIndex(Contacts.LOOKUP_KEY);
+ // Gets the lookup key value
+ mCurrentLookupKey = mCursor.getString(mLookupKeyIndex);
+ // Gets the _ID column index
+ mIdIndex = mCursor.getColumnIndex(Contacts._ID);
+ mCurrentId = mCursor.getLong(mIdIndex);
+ mSelectedContactUri =
+ Contacts.getLookupUri(mCurrentId, mCurrentLookupKey);
+ ...
+ // Creates a new Intent to edit a contact
+ Intent editIntent = new Intent(Intent.ACTION_EDIT);
+ /*
+ * Sets the contact URI to edit, and the data type that the
+ * Intent must match
+ */
+ editIntent.setDataAndType(mSelectedContactUri,Contacts.CONTENT_ITEM_TYPE);
+</pre>
+<h3>Add the navigation flag</h3>
+<p>
+ In Android 4.0 (API version 14) and later, a problem in the contacts app causes incorrect
+ navigation. When your app sends an edit intent to the contacts app, and users edit and save a
+ contact, when they click <i>Back</i> they see the contacts list screen. To navigate back to
+ your app, they have to click <i>Recents</i> and choose your app.
+</p>
+<p>
+ To work around this problem in Android 4.0.3 (API version 15) and later, add the extended
+ data key {@code finishActivityOnSaveCompleted} to the intent, with a value of {@code true}.
+ Android versions prior to Android 4.0 accept this key, but it has no effect. To set the
+ extended data, do the following:
+</p>
+<pre>
+ // Sets the special extended data for navigation
+ editIntent.putExtra("finishActivityOnSaveCompleted", true);
+</pre>
+<h3>Add other extended data</h3>
+<p>
+ To add additional extended data to the {@link android.content.Intent}, call
+ {@link android.content.Intent#putExtra putExtra()} as desired.
+ You can add extended data for common contact fields by using the key values specified in
+ {@link android.provider.ContactsContract.Intents.Insert Intents.Insert}. Remember that some
+ columns in the {@link android.provider.ContactsContract.Contacts} table can't be modified.
+ These columns are listed in the summary section of the API reference for the class
+ {@link android.provider.ContactsContract.Contacts} under the heading "Update".
+</p>
+
+<h3>Send the Intent</h3>
+<p>
+ Finally, send the intent you've constructed. For example:
+</p>
+<pre>
+ // Sends the Intent
+ startActivity(editIntent);
+</pre>
+<h2 id="InsertEdit">Let Users Choose to Insert or Edit Using an Intent</h2>
+<p>
+ You can allow users to choose whether to insert a contact or edit an existing one by sending
+ an {@link android.content.Intent} with the action
+ {@link android.content.Intent#ACTION_INSERT_OR_EDIT}. For example, an email client app could
+ allow users to add an incoming email address to a new contact, or add it as an additional
+ address for an existing contact. Set the MIME type for this intent to
+ {@link android.provider.ContactsContract.Contacts#CONTENT_ITEM_TYPE Contacts.CONTENT_ITEM_TYPE},
+ but don't set the data URI.
+</p>
+<p>
+ When you send this intent, the contacts app displays a list of contacts.
+ Users can either insert a new contact or pick an existing contact and edit it.
+ Any extended data fields you add to the intent populates the screen that appears. You can use
+ any of the key values specified in {@link android.provider.ContactsContract.Intents.Insert
+ Intents.Insert}. The following code snippet shows how to construct and send the intent:
+</p>
+<pre>
+ // Creates a new Intent to insert or edit a contact
+ Intent intentInsertEdit = new Intent(Intent.ACTION_INSERT_OR_EDIT);
+ // Sets the MIME type
+ intentInsertEdit.setType(Contacts.CONTENT_ITEM_TYPE);
+ // Add code here to insert extended data, if desired
+ ...
+ // Sends the Intent with an request ID
+ startActivity(intentInsertEdit);
+</pre>
diff --git a/docs/html/training/contacts-provider/retrieve-details.jd b/docs/html/training/contacts-provider/retrieve-details.jd
new file mode 100644
index 0000000..0de3b67
--- /dev/null
+++ b/docs/html/training/contacts-provider/retrieve-details.jd
@@ -0,0 +1,378 @@
+page.title=Retrieving Details for a Contact
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#RetrieveAll">Retrieve All Details for a Contact</a></li>
+ <li><a href="#RetrieveSpecific">Retrieve Specific Details for a Contact</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+ Content Provider Basics</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/contacts-provider.html">
+ Contacts Provider</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/components/loaders.html">Loaders</a>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/ContactsList.zip" class="button">
+ Download the sample
+ </a>
+ <p class="filename">ContactsList.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+ This lesson shows how to retrieve detail data for a contact, such as email addresses, phone
+ numbers, and so forth. It's the details that users are looking for when they retrieve a contact.
+ You can give them all the details for a contact, or only display details of a particular type,
+ such as email addresses.
+</p>
+<p>
+ The steps in this lesson assume that you already have a
+ {@link android.provider.ContactsContract.Contacts} row for a contact the user has picked.
+ The <a href="retrieve-names.html">Retrieving Contact Names</a> lesson shows how to
+ retrieve a list of contacts.
+</p>
+<h2 id="RetrieveAll">Retrieve All Details for a Contact</h2>
+<p>
+ To retrieve all the details for a contact, search the
+ {@link android.provider.ContactsContract.Data} table for any rows that contain the contact's
+ {@link android.provider.ContactsContract.Data#LOOKUP_KEY}. This column is available in
+ the {@link android.provider.ContactsContract.Data} table, because the Contacts
+ Provider makes an implicit join between the {@link android.provider.ContactsContract.Contacts}
+ table and the {@link android.provider.ContactsContract.Data} table. The
+ {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} column is described
+ in more detail in the <a href="retrieve-names.html">Retrieving Contact Names</a> lesson.
+</p>
+<p class="note">
+ <strong>Note:</strong> Retrieving all the details for a contact reduces the performance of a
+ device, because it needs to retrieve all of the columns in the
+ {@link android.provider.ContactsContract.Data} table. Consider the performance impact before
+ you use this technique.
+</p>
+<h3>Request permissions</h3>
+<p>
+ To read from the Contacts Provider, your app must have
+ {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission.
+ To request this permission, add the following child element of
+ <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">
+ <manifest></a></code> to your manifest file:
+</p>
+<pre>
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+</pre>
+<h3>Set up a projection</h3>
+<p>
+ Depending on the data type a row contains, it may use only a few columns or many. In addition,
+ the data is in different columns depending on the data type.
+ To ensure you get all the possible columns for all possible data types, you need to add all the
+ column names to your projection. Always retrieve
+ {@link android.provider.ContactsContract.Data#_ID Data._ID} if you're binding the result
+ {@link android.database.Cursor} to a {@link android.widget.ListView}; otherwise, the binding
+ won't work. Also retrieve {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}
+ so you can identify the data type of each row you retrieve. For example:
+</p>
+<pre>
+ private static final String PROJECTION =
+ {
+ Data._ID,
+ Data.MIMETYPE,
+ Data.DATA1,
+ Data.DATA2,
+ Data.DATA3,
+ Data.DATA4,
+ Data.DATA5,
+ Data.DATA6,
+ Data.DATA7,
+ Data.DATA8,
+ Data.DATA9,
+ Data.DATA10,
+ Data.DATA11,
+ Data.DATA12,
+ Data.DATA13,
+ Data.DATA14,
+ Data.DATA15
+ };
+</pre>
+<p>
+ This projection retrieves all the columns for a row in the
+ {@link android.provider.ContactsContract.Data} table, using the column names defined in
+ the {@link android.provider.ContactsContract.Data} class.
+</p>
+<p>
+ Optionally, you can also use any other column constants defined in or inherited by the
+ {@link android.provider.ContactsContract.Data} class. Notice, however, that the columns
+ {@link android.provider.ContactsContract.DataColumns#SYNC1} through
+ {@link android.provider.ContactsContract.DataColumns#SYNC4} are meant to be used by sync
+ adapters, so their data is not useful.
+</p>
+<h3>Define the selection criteria</h3>
+<p>
+ Define a constant for your selection clause, an array to hold selection arguments, and a
+ variable to hold the selection value. Use
+ the {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY Contacts.LOOKUP_KEY} column to
+ find the contact. For example:
+</p>
+<pre>
+ // Defines the selection clause
+ private static final String SELECTION = Data.LOOKUP_KEY + " = ?";
+ // Defines the array to hold the search criteria
+ private String[] mSelectionArgs = { "" };
+ /*
+ * Defines a variable to contain the selection value. Once you
+ * have the Cursor from the Contacts table, and you've selected
+ * the desired row, move the row's LOOKUP_KEY value into this
+ * variable.
+ */
+ private String mLookupKey;
+</pre>
+<p>
+ Using "?" as a placeholder in your selection text expression ensures that the resulting search
+ is generated by binding rather than SQL compilation. This approach eliminates the
+ possibility of malicious SQL injection.
+</p>
+<h3>Define the sort order</h3>
+<p>
+ Define the sort order you want in the resulting {@link android.database.Cursor}. To
+ keep all rows for a particular data type together, sort by
+ {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}. This query argument
+ groups all email rows together, all phone rows together, and so forth. For example:
+</p>
+<pre>
+ /*
+ * Defines a string that specifies a sort order of MIME type
+ */
+ private static final String SORT_ORDER = Data.MIMETYPE;
+</pre>
+<p class="note">
+ <strong>Note:</strong> Some data types don't use a subtype, so you can't sort on subtype.
+ Instead, you have to iterate through the returned {@link android.database.Cursor},
+ determine the data type of the current row, and store data for rows that use a subtype. When
+ you finish reading the cursor, you can then sort each data type by subtype and display the
+ results.
+</p>
+<h3>Initialize the Loader</h3>
+<p>
+ Always do retrievals from the Contacts Provider (and all other content providers) in a
+ background thread. Use the Loader framework defined by the
+ {@link android.support.v4.app.LoaderManager} class and the
+ {@link android.support.v4.app.LoaderManager.LoaderCallbacks} interface to do background
+ retrievals.
+</p>
+<p>
+ When you're ready to retrieve the rows, initialize the loader framework by
+ calling {@link android.support.v4.app.LoaderManager#initLoader initLoader()}. Pass an
+ integer identifier to the method; this identifier is passed to
+ {@link android.support.v4.app.LoaderManager.LoaderCallbacks} methods. The identifier helps you
+ use multiple loaders in an app by allowing you to differentiate between them.
+</p>
+<p>
+ The following snippet shows how to initialize the loader framework:
+</p>
+<pre>
+public class DetailsFragment extends Fragment implements
+ LoaderManager.LoaderCallbacks<Cursor> {
+ ...
+ // Defines a constant that identifies the loader
+ DETAILS_QUERY_ID = 0;
+ ...
+ /*
+ * Invoked when the parent Activity is instantiated
+ * and the Fragment's UI is ready. Put final initialization
+ * steps here.
+ */
+ @Override
+ onActivityCreated(Bundle savedInstanceState) {
+ ...
+ // Initializes the loader framework
+ getLoaderManager().initLoader(DETAILS_QUERY_ID, null, this);
+</pre>
+<h3>Implement onCreateLoader()</h3>
+<p>
+ Implement the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader
+ onCreateLoader()} method, which is called by the loader framework immediately after you call
+ {@link android.support.v4.app.LoaderManager#initLoader initLoader()}. Return a
+ {@link android.support.v4.content.CursorLoader} from this method. Since you're searching
+ the {@link android.provider.ContactsContract.Data} table, use the constant
+ {@link android.provider.ContactsContract.Data#CONTENT_URI Data.CONTENT_URI} as the content URI.
+ For example:
+</p>
+<pre>
+ @Override
+ public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
+ // Choose the proper action
+ switch (loaderId) {
+ case DETAILS_QUERY_ID:
+ // Assigns the selection parameter
+ mSelectionArgs[0] = mLookupKey;
+ // Starts the query
+ CursorLoader mLoader =
+ new CursorLoader(
+ getActivity(),
+ Data.CONTENT_URI,
+ PROJECTION,
+ SELECTION,
+ mSelectionArgs,
+ SORT_ORDER
+ );
+ ...
+ }
+</pre>
+<h3>Implement onLoadFinished() and onLoaderReset()</h3>
+<p>
+ Implement the
+ {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
+ method. The loader framework calls
+ {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
+ when the Contacts Provider returns the results of the query. For example:
+</p>
+<pre>
+ public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
+ switch (loader.getId()) {
+ case DETAILS_QUERY_ID:
+ /*
+ * Process the resulting Cursor here.
+ */
+ }
+ break;
+ ...
+ }
+ }
+</pre>
+<p>
+<p>
+ The method {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset
+ onLoaderReset()} is invoked when the loader framework detects that the data backing the result
+ {@link android.database.Cursor} has changed. At this point, remove any existing references
+ to the {@link android.database.Cursor} by setting them to null. If you don't, the loader
+ framework won't destroy the old {@link android.database.Cursor}, and you'll get a memory
+ leak. For example:
+<pre>
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ switch (loader.getId()) {
+ case DETAILS_QUERY_ID:
+ /*
+ * If you have current references to the Cursor,
+ * remove them here.
+ */
+ }
+ break;
+ }
+</pre>
+<h2 id="RetrieveSpecific">Retrieve Specific Details for a Contact</h2>
+<p>
+ Retrieving a specific data type for a contact, such as all the emails, follows the same pattern
+ as retrieving all details. These are the only changes you need to make to the code
+ listed in <a href="#RetrieveAll">Retrieve All Details for a Contact</a>:
+</p>
+<dl>
+ <dt>
+ Projection
+ </dt>
+ <dd>
+ Modify your projection to retrieve the columns that are specific to the
+ data type. Also modify the projection to use the column name constants defined in the
+ {@link android.provider.ContactsContract.CommonDataKinds} subclass corresponding to the
+ data type.
+ </dd>
+ <dt>
+ Selection
+ </dt>
+ <dd>
+ Modify the selection text to search for the
+ {@link android.provider.ContactsContract.Data#MIMETYPE MIMETYPE} value that's specific to
+ your data type.
+ </dd>
+ <dt>
+ Sort order
+ </dt>
+ <dd>
+ Since you're only selecting a single detail type, don't group the returned
+ {@link android.database.Cursor} by {@link android.provider.ContactsContract.Data#MIMETYPE
+ Data.MIMETYPE}.
+ </dd>
+</dl>
+<p>
+ These modifications are described in the following sections.
+</p>
+<h3>Define a projection</h3>
+<p>
+ Define the columns you want to retrieve, using the column name constants in the subclass
+ of {@link android.provider.ContactsContract.CommonDataKinds} for the data type.
+ If you plan to bind your {@link android.database.Cursor} to a {@link android.widget.ListView},
+ be sure to retrieve the <code>_ID</code> column. For example, to retrieve email data, define the
+ following projection:
+</p>
+<pre>
+ private static final String[] PROJECTION =
+ {
+ Email._ID,
+ Email.ADDRESS,
+ Email.TYPE,
+ Email.LABEL
+ };
+</pre>
+<p>
+ Notice that this projection uses the column names defined in the class
+ {@link android.provider.ContactsContract.CommonDataKinds.Email}, instead of the column names
+ defined in the class {@link android.provider.ContactsContract.Data}. Using the email-specific
+ column names makes the code more readable.
+</p>
+<p>
+ In the projection, you can also use any of the other columns defined in the
+ {@link android.provider.ContactsContract.CommonDataKinds} subclass.
+</p>
+<h3>Define selection criteria</h3>
+<p>
+ Define a search text expression that retrieves rows for a specific contact's
+ {@link android.provider.ContactsContract.Data#LOOKUP_KEY} and the
+ {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE} of the details you
+ want. Enclose the {@link android.provider.ContactsContract.Data#MIMETYPE MIMETYPE} value in
+ single quotes by concatenating a "<code>'</code>" (single-quote) character to the start and end
+ of the constant; otherwise, the provider interprets the constant as a variable name rather
+ than as a string value. You don't need to use a placeholder for this value, because you're
+ using a constant rather than a user-supplied value. For example:
+</p>
+<pre>
+ /*
+ * Defines the selection clause. Search for a lookup key
+ * and the Email MIME type
+ */
+ private static final String SELECTION =
+ Data.LOOKUP_KEY + " = ?" +
+ " AND " +
+ Data.MIMETYPE + " = " +
+ "'" + Email.CONTENT_ITEM_TYPE + "'";
+ // Defines the array to hold the search criteria
+ private String[] mSelectionArgs = { "" };
+</pre>
+<h3>Define a sort order</h3>
+<p>
+ Define a sort order for the returned {@link android.database.Cursor}. Since you're retrieving a
+ specific data type, omit the sort on {@link android.provider.ContactsContract.Data#MIMETYPE}.
+ Instead, if the type of detail data you're searching includes a subtype, sort on it.
+ For example, for email data you can sort on
+ {@link android.provider.ContactsContract.CommonDataKinds.Email#TYPE Email.TYPE}:
+</p>
+<pre>
+ private static final String SORT_ORDER = Email.TYPE + " ASC ";
+</pre>
diff --git a/docs/html/training/contacts-provider/retrieve-names.jd b/docs/html/training/contacts-provider/retrieve-names.jd
new file mode 100644
index 0000000..b034a6a
--- /dev/null
+++ b/docs/html/training/contacts-provider/retrieve-names.jd
@@ -0,0 +1,815 @@
+page.title=Retrieving a List of Contacts
+
+trainingnavtop=true
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#Permissions">Request Permission to Read the Provider</a>
+ <li><a href="#NameMatch">Match a Contact by Name and List the Results</a></li>
+ <li><a href="#TypeMatch">Match a Contact By a Specific Type of Data</a></li>
+ <li><a href="#GeneralMatch">Match a Contact By Any Type of Data</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+ Content Provider Basics</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/contacts-provider.html">
+ Contacts Provider</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/components/loaders.html">Loaders</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>
+ </li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="http://developer.android.com/shareables/training/ContactsList.zip" class="button">
+ Download the sample
+ </a>
+ <p class="filename">ContactsList.zip</p>
+</div>
+
+</div>
+</div>
+<p>
+ This lesson shows you how to retrieve a list of contacts whose data matches all or part of a
+ search string, using the following techniques:
+</p>
+<dl>
+ <dt>Match contact names</dt>
+ <dd>
+ Retrieve a list of contacts by matching the search string to all or part of the contact
+ name data. The Contacts Provider allows multiple instances of the same name, so this
+ technique can return a list of matches.
+ </dd>
+ <dt>Match a specific type of data, such as a phone number</dt>
+ <dd>
+ Retrieve a list of contacts by matching the search string to a particular type of detail
+ data such as an email address. For example, this technique allows you to list all of the
+ contacts whose email address matches the search string.
+ </dd>
+ <dt>Match any type of data</dt>
+ <dd>
+ Retrieve a list of contacts by matching the search string to any type of detail data,
+ including name, phone number, street address, email address, and so forth. For example,
+ this technique allows you to accept any type of data for a search string and then list the
+ contacts for which the data matches the string.
+ </dd>
+</dl>
+<p class="note">
+ <strong>Note:</strong> All the examples in this lesson use a
+ {@link android.support.v4.content.CursorLoader} to retrieve data from the Contacts
+ Provider. A {@link android.support.v4.content.CursorLoader} runs its query on a
+ thread that's separate from the UI thread. This ensures that the query doesn't slow down UI
+ response times and cause a poor user experience. For more information, see the Android
+ training class <a href="{@docRoot}training/load-data-background/index.html">
+ Loading Data in the Background</a>.
+</p>
+<h2 id="Permissions">Request Permission to Read the Provider</h2>
+<p>
+ To do any type of search of the Contacts Provider, your app must have
+ {@link android.Manifest.permission#READ_CONTACTS READ_CONTACTS} permission.
+ To request this, add this
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a></code>
+ element to your manifest file as a child element of
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code>:
+</p>
+<pre>
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+</pre>
+<h2 id="NameMatch">Match a Contact by Name and List the Results</h2>
+<p>
+ This technique tries to match a search string to the name of a contact or contacts in the
+ Contact Provider's {@link android.provider.ContactsContract.Contacts} table. You usually want
+ to display the results in a {@link android.widget.ListView}, to allow the user to choose among
+ the matched contacts.
+</p>
+<h3 id="DefineListView">Define ListView and item layouts</h3>
+<p>
+ To display the search results in a {@link android.widget.ListView}, you need a main layout file
+ that defines the entire UI including the {@link android.widget.ListView}, and an item layout
+ file that defines one line of the {@link android.widget.ListView}. For example, you can define
+ the main layout file <code>res/layout/contacts_list_view.xml</code> that contains the
+ following XML:
+</p>
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</pre>
+<p>
+ This XML uses the built-in Android {@link android.widget.ListView} widget
+ {@link android.R.id#list android:id/list}.
+</p>
+<p>
+ Define the item layout file <code>contacts_list_item.xml</code> with the following XML:
+</p>
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clickable="true"/>
+</pre>
+<p>
+ This XML uses the built-in Android {@link android.widget.TextView} widget
+ {@link android.R.id#text1 android:text1}.
+</p>
+<p class="note">
+ <strong>Note:</strong> This lesson doesn't describe the UI for getting a search string from the
+ user, because you may want to get the string indirectly. For example, you can give the user
+ an option to search for contacts whose name matches a string in an incoming text message.
+</p>
+<p>
+ The two layout files you've written define a user interface that shows a
+ {@link android.widget.ListView}. The next step is to write code that uses this UI to display a
+ list of contacts.
+</p>
+<h3 id="Fragment">Define a Fragment that displays the list of contacts</h3>
+<p>
+ To display the list of contacts, start by defining a {@link android.support.v4.app.Fragment}
+ that's loaded by an {@link android.app.Activity}. Using a
+ {@link android.support.v4.app.Fragment} is a more flexible technique, because you can use
+ one {@link android.support.v4.app.Fragment} to display the list and a second
+ {@link android.support.v4.app.Fragment} to display the details for a contact that the user
+ chooses from the list. Using this approach, you can combine one of the techniques presented in
+ this lesson with one from the lesson <a href="retrieve-details.html">
+ Retrieving Details for a Contact</a>.
+</p>
+<p>
+ To learn how to use one or more {@link android.support.v4.app.Fragment} objects from an
+ an {@link android.app.Activity}, read the training class
+ <a href="{@docRoot}training/basics/fragments/index.html">
+ Building a Dynamic UI with Fragments</a>.
+</p>
+<p>
+ To help you write queries against the Contacts Provider, the Android framework provides a
+ contracts class called {@link android.provider.ContactsContract}, which defines useful
+ constants and methods for accessing the provider. When you use this class, you don't have to
+ define your own constants for content URIs, table names, or columns. To use this class,
+ include the following statement:
+</p>
+<pre>
+import android.provider.ContactsContract;
+</pre>
+<p>
+ Since the code uses a {@link android.support.v4.content.CursorLoader} to retrieve data
+ from the provider, you must specify that it implements the loader interface
+ {@link android.support.v4.app.LoaderManager.LoaderCallbacks}. Also, to help detect which contact
+ the user selects from the list of search results, implement the adapter interface
+ {@link android.widget.AdapterView.OnItemClickListener}. For example:
+</p>
+<pre>
+...
+import android.support.v4.app.Fragment;
+import android.support.v4.app.LoaderManager.LoaderCallbacks;
+import android.widget.AdapterView;
+...
+public class ContactsFragment extends Fragment implements
+ LoaderManager.LoaderCallbacks<Cursor>,
+ AdapterView.OnItemClickListener {
+</pre>
+<h3 id="DefineVariables">Define global variables</h3>
+<p>
+ Define global variables that are used in other parts of the code:
+</p>
+<pre>
+ ...
+ /*
+ * Defines an array that contains column names to move from
+ * the Cursor to the ListView.
+ */
+ @SuppressLint("InlinedApi")
+ private final static String[] FROM_COLUMNS = {
+ Build.VERSION.SDK_INT
+ >= Build.VERSION_CODES.HONEYCOMB ?
+ Contacts.DISPLAY_NAME_PRIMARY :
+ Contacts.DISPLAY_NAME
+ };
+ /*
+ * Defines an array that contains resource ids for the layout views
+ * that get the Cursor column contents. The id is pre-defined in
+ * the Android framework, so it is prefaced with "android.R.id"
+ */
+ private final static int[] TO_IDS = {
+ android.R.id.text1
+ };
+ // Define global mutable variables
+ // Define a ListView object
+ ListView mContactsList;
+ // Define variables for the contact the user selects
+ // The contact's _ID value
+ long mContactId;
+ // The contact's LOOKUP_KEY
+ String mContactKey;
+ // A content URI for the selected contact
+ Uri mContactUri;
+ // An adapter that binds the result Cursor to the ListView
+ private SimpleCursorAdapter mCursorAdapter;
+ ...
+</pre>
+<p class="note">
+ <strong>Note:</strong> Since
+ {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
+ Contacts.DISPLAY_NAME_PRIMARY} requires Android 3.0 (API version 11) or later, setting your
+ app's <code>minSdkVersion</code> to 10 or below generates an Android Lint warning in
+ Eclipse with ADK. To turn off this warning, add the annotation
+ <code>@SuppressLint("InlinedApi")</code> before the definition of <code>FROM_COLUMNS</code>.
+</p>
+<h3 id="InitializeFragment">Initialize the Fragment</h3>
+<p>
+
+ Initialize the {@link android.support.v4.app.Fragment}. Add the empty, public constructor
+ required by the Android system, and inflate the {@link android.support.v4.app.Fragment} object's
+ UI in the callback method {@link android.support.v4.app.Fragment#onCreateView onCreateView()}.
+ For example:
+</p>
+<pre>
+ // Empty public constructor, required by the system
+ public ContactsFragment() {}
+
+ // A UI Fragment must inflate its View
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the fragment layout
+ return inflater.inflate(R.layout.contacts_list_layout, container, false);
+ }
+</pre>
+<h3 id="DefineAdapter">Set up the CursorAdapter for the ListView</h3>
+<p>
+ Set up the {@link android.support.v4.widget.SimpleCursorAdapter} that binds the results of the
+ search to the {@link android.widget.ListView}. To get the {@link android.widget.ListView} object
+ that displays the contacts, you need to call {@link android.app.Activity#findViewById
+ Activity.findViewById()} using the parent activity of the
+ {@link android.support.v4.app.Fragment}. Use the {@link android.content.Context} of the
+ parent activity when you call {@link android.widget.ListView#setAdapter setAdapter()}.
+ For example:
+</p>
+<pre>
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ ...
+ // Gets the ListView from the View list of the parent activity
+ mContactsList = (ListView) getActivity().findViewById(R.layout.contact_list_view);
+ // Gets a CursorAdapter
+ mCursorAdapter = new SimpleCursorAdapter(
+ getActivity(),
+ R.layout.contact_list_item,
+ null,
+ FROM_COLUMNS, TO_IDS,
+ 0);
+ // Sets the adapter for the ListView
+ mContactsList.setAdapter(mCursorAdapter);
+ }
+</pre>
+<h3 id="SetListener">Set the selected contact listener</h3>
+<p>
+ When you display the results of a search, you usually want to allow the user to select a
+ single contact for further processing. For example, when the user clicks a contact you can
+ display the contact's address on a map. To provide this feature, you first defined the current
+ {@link android.support.v4.app.Fragment} as the click listener by specifying that the class
+ implements {@link android.widget.AdapterView.OnItemClickListener}, as shown in the section
+ <a href="#Fragment">Define a Fragment that displays the list of contacts</a>.
+</p>
+<p>
+ To continue setting up the listener, bind it to the {@link android.widget.ListView} by
+ calling the method {@link android.widget.ListView#setOnItemClickListener
+ setOnItemClickListener()} in {@link android.support.v4.app.Fragment#onActivityCreated
+ onActivityCreated()}. For example:
+</p>
+<pre>
+ public void onActivityCreated(Bundle savedInstanceState) {
+ ...
+ // Set the item click listener to be the current fragment.
+ mContactsList.setOnItemClickListener(this);
+ ...
+ }
+</pre>
+<p>
+ Since you specified that the current {@link android.support.v4.app.Fragment} is the
+ {@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} for the
+ {@link android.widget.ListView}, you now need to implement its required method
+ {@link android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()}, which
+ handles the click event. This is described in a succeeding section.
+</p>
+<h3 id="DefineProjection">Define a projection</h3>
+<p>
+ Define a constant that contains the columns you want to return from your query. Each item in
+ the {@link android.widget.ListView} displays the contact's display name,
+ which contains the main form of the contact's name. In Android 3.0 (API version 11) and later,
+ the name of this column is
+ {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME_PRIMARY
+ Contacts.DISPLAY_NAME_PRIMARY}; in versions previous to that, its name is
+ {@link android.provider.ContactsContract.Contacts#DISPLAY_NAME Contacts.DISPLAY_NAME}.
+</p>
+<p>
+ The column {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} is used by the
+ {@link android.support.v4.widget.SimpleCursorAdapter} binding process.
+ {@link android.provider.ContactsContract.Contacts#_ID Contacts._ID} and
+ {@link android.provider.ContactsContract.Contacts#LOOKUP_KEY} are used together to
+ construct a content URI for the contact the user selects.
+</p>
+<pre>
+...
+@SuppressLint("InlinedApi")
+private static final String[] PROJECTION =
+ {
+ Contacts._ID,
+ Contacts.LOOKUP_KEY,
+ Build.VERSION.SDK_INT
+ >= Build.VERSION_CODES.HONEYCOMB ?
+ Contacts.DISPLAY_NAME_PRIMARY :
+ Contacts.DISPLAY_NAME
+
+ };
+</pre>
+<h3 id="DefineConstants">Define constants for the Cursor column indexes</h3>
+<p>
+ To get data from an individual column in a {@link android.database.Cursor}, you need
+ the column's index within the {@link android.database.Cursor}. You can define constants
+ for the indexes of the {@link android.database.Cursor} columns, because the indexes are
+ the same as the order of the column names in your projection. For example:
+</p>
+<pre>
+// The column index for the _ID column
+private static final int CONTACT_ID_INDEX = 0;
+// The column index for the LOOKUP_KEY column
+private static final int LOOKUP_KEY_INDEX = 1;
+</pre>
+<h3 id="SelectionCriteria">Specify the selection criteria</h3>
+<p>
+ To specify the data you want, create a combination of text expressions and variables
+ that tell the provider the data columns to search and the values to find.
+</p>
+<p>
+ For the text expression, define a constant that lists the search columns. Although this
+ expression can contain values as well, the preferred practice is to represent the values with
+ a "?" placeholder. During retrieval, the placeholder is replaced with values from an
+ array. Using "?" as a placeholder ensures that the search specification is generated by binding
+ rather than by SQL compilation. This practice eliminates the possibility of malicious SQL
+ injection. For example:
+</p>
+<pre>
+ // Defines the text expression
+ @SuppressLint("InlinedApi")
+ private static final String SELECTION =
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
+ Contacts.DISPLAY_NAME_PRIMARY + " LIKE ?" :
+ Contacts.DISPLAY_NAME + " LIKE ?";
+ // Defines a variable for the search string
+ private String mSearchString;
+ // Defines the array to hold values that replace the ?
+ private String[] mSelectionArgs = { mSearchString };
+</pre>
+<h3 id="OnItemClick">Define the onItemClick() method</h3>
+<p>
+ In a previous section, you set the item click listener for the {@link android.widget.ListView}.
+ Now implement the action for the listener by defining the method
+ {@link android.widget.AdapterView.OnItemClickListener#onItemClick
+ AdapterView.OnItemClickListener.onItemClick()}:
+</p>
+<pre>
+ @Override
+ public void onItemClick(
+ AdapterView<?> parent, View item, int position, long rowID) {
+ // Get the Cursor
+ Cursor cursor = parent.getAdapter().getCursor();
+ // Move to the selected contact
+ cursor.moveToPosition(position);
+ // Get the _ID value
+ mContactId = getLong(CONTACT_ID_INDEX);
+ // Get the selected LOOKUP KEY
+ mContactKey = getString(CONTACT_KEY_INDEX);
+ // Create the contact's content Uri
+ mContactUri = Contacts.getLookupUri(mContactId, mContactKey);
+ /*
+ * You can use mContactUri as the content URI for retrieving
+ * the details for a contact.
+ */
+ }
+</pre>
+<h3 id="InitializeLoader">Initialize the loader</h3>
+<p>
+ Since you're using a {@link android.support.v4.content.CursorLoader} to retrieve data,
+ you must initialize the background thread and other variables that control asynchronous
+ retrieval. Do the initialization in
+ {@link android.support.v4.app.Fragment#onActivityCreated onActivityCreated()}, which
+ is invoked immediately before the {@link android.support.v4.app.Fragment} UI appears, as
+ shown in the following example:
+</p>
+<pre>
+public class ContactsFragment extends Fragment implements
+ LoaderManager.LoaderCallbacks<Cursor> {
+ ...
+ // Called just before the Fragment displays its UI
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ // Always call the super method first
+ super.onActivityCreated(savedInstanceState);
+ ...
+ // Initializes the loader
+ getLoaderManager().initLoader(0, null, this);
+</pre>
+<h3 id="OnCreateLoader">Implement onCreateLoader()</h3>
+<p>
+ Implement the method
+ {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()},
+ which is called by the loader framework immediately after you call
+ {@link android.support.v4.app.LoaderManager#initLoader initLoader()}.
+<p>
+ In {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader onCreateLoader()},
+ set up the search string pattern. To make a string into a pattern, insert "%"
+ (percent) characters to represent a sequence of zero or more characters, or "_" (underscore)
+ characters to represent a single character, or both. For example, the pattern "%Jefferson%"
+ would match both "Thomas Jefferson" and "Jefferson Davis".
+</p>
+<p>
+ Return a new {@link android.support.v4.content.CursorLoader} from the method. For the content
+ URI, use {@link android.provider.ContactsContract.Contacts#CONTENT_URI Contacts.CONTENT_URI}.
+ This URI refers to the entire table, as shown in the following example:
+</p>
+<pre>
+ ...
+ @Override
+ public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
+ /*
+ * Makes search string into pattern and
+ * stores it in the selection array
+ */
+ mSelectionArgs[0] = "%" + mSearchString + "%";
+ // Starts the query
+ return new CursorLoader(
+ getActivity(),
+ Contacts.CONTENT_URI,
+ PROJECTION,
+ SELECTION,
+ mSelectionArgs,
+ null
+ );
+ }
+</pre>
+<h3 id="FinishedReset">Implement onLoadFinished() and onLoaderReset()</h3>
+<p>
+ Implement the
+ {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
+ method. The loader framework calls
+ {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoadFinished onLoadFinished()}
+ when the Contacts Provider returns the results of the query. In this method, put the
+ result {@link android.database.Cursor} in the
+ {@link android.support.v4.widget.SimpleCursorAdapter}. This automatically updates the
+ {@link android.widget.ListView} with the search results:
+</p>
+<pre>
+ public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
+ // Put the result Cursor in the adapter for the ListView
+ mCursorAdapter.swapCursor(cursor);
+ }
+</pre>
+<p>
+ The method {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onLoaderReset
+ onLoaderReset()} is invoked when the loader framework detects that the
+ result {@link android.database.Cursor} contains stale data. Delete the
+ {@link android.support.v4.widget.SimpleCursorAdapter} reference to the existing
+ {@link android.database.Cursor}. If you don't, the loader framework will not
+ recycle the {@link android.database.Cursor}, which causes a memory leak. For example:
+</p>
+<pre>
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ // Delete the reference to the existing Cursor
+ mCursorAdapter.swapCursor(null);
+
+ }
+</pre>
+
+<p>
+ You now have the key pieces of an app that matches a search string to contact names and returns
+ the result in a {@link android.widget.ListView}. The user can click a contact name to select it.
+ This triggers a listener, in which you can work further with the contact's data. For example,
+ you can retrieve the contact's details. To learn how to do this, continue with the next
+ lesson, <a href="#retrieve-details.html">Retrieving Details for a Contact</a>.
+</p>
+<p>
+ To learn more about search user interfaces, read the API guide
+ <a href="{@docRoot}guide/topics/search/search-dialog.html">Creating a Search Interface</a>.
+</p>
+<p>
+ The remaining sections in this lesson demonstrate other ways of finding contacts in the
+ Contacts Provider.
+</p>
+<h2 id="TypeMatch">Match a Contact By a Specific Type of Data</h2>
+<p>
+ This technique allows you to specify the type of data you want to match. Retrieving
+ by name is a specific example of this type of query, but you can also do it for any of the types
+ of detail data associated with a contact. For example, you can retrieve contacts that have a
+ specific postal code; in this case, the search string has to match data stored in a postal code
+ row.
+</p>
+<p>
+ To implement this type of retrieval, first implement the following code, as listed in
+ previous sections:
+</p>
+<ul>
+ <li>
+ Request Permission to Read the Provider.
+ </li>
+ <li>
+ Define ListView and item layouts.
+ </li>
+ <li>
+ Define a Fragment that displays the list of contacts.
+ </li>
+ <li>
+ Define global variables.
+ </li>
+ <li>
+ Initialize the Fragment.
+ </li>
+ <li>
+ Set up the CursorAdapter for the ListView.
+ </li>
+ <li>
+ Set the selected contact listener.
+ </li>
+ <li>
+ Define constants for the Cursor column indexes.
+ <p>
+ Although you're retrieving data from a different table, the order of the columns in
+ the projection is the same, so you can use the same indexes for the Cursor.
+ </p>
+ </li>
+ <li>
+ Define the onItemClick() method.
+ </li>
+ <li>
+ Initialize the loader.
+ </li>
+ <li>
+
+ Implement onLoadFinished() and onLoaderReset().
+ </li>
+</ul>
+<p>
+ The following steps show you the additional code you need to match a search string to
+ a particular type of detail data and display the results.
+</p>
+<h3>Choose the data type and table</h3>
+<p>
+ To search for a particular type of detail data, you have to know the custom MIME type value
+ for the data type. Each data type has a unique MIME type
+ value defined by a constant <code>CONTENT_ITEM_TYPE</code> in the subclass of
+ {@link android.provider.ContactsContract.CommonDataKinds} associated with the data type.
+ The subclasses have names that indicate their data type; for example, the subclass for email
+ data is {@link android.provider.ContactsContract.CommonDataKinds.Email}, and the custom MIME
+ type for email data is defined by the constant
+ {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
+ Email.CONTENT_ITEM_TYPE}.
+</p>
+<p>
+ Use the {@link android.provider.ContactsContract.Data} table for your search. All of the
+ constants you need for your projection, selection clause, and sort order are defined in or
+ inherited by this table.
+</p>
+<h3 id="SpecificProjection">Define a projection</h3>
+<p>
+ To define a projection, choose one or more of the columns defined in
+ {@link android.provider.ContactsContract.Data} or the classes from which it inherits. The
+ Contacts Provider does an implicit join between {@link android.provider.ContactsContract.Data}
+ and other tables before it returns rows. For example:
+</p>
+<pre>
+ @SuppressLint("InlinedApi")
+ private static final String[] PROJECTION =
+ {
+ /*
+ * The detail data row ID. To make a ListView work,
+ * this column is required.
+ */
+ Data._ID,
+ // The primary display name
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
+ Data.DISPLAY_NAME_PRIMARY :
+ Data.DISPLAY_NAME,
+ // The contact's _ID, to construct a content URI
+ Data.CONTACT_ID
+ // The contact's LOOKUP_KEY, to construct a content URI
+ Data.LOOKUP_KEY (a permanent link to the contact
+ };
+</pre>
+<h3 id="SpecificCriteria">Define search criteria</h3>
+<p>
+ To search for a string within a particular type of data, construct a selection clause from
+ the following:
+</p>
+<ul>
+ <li>
+ The name of the column that contains your search string. This name varies by data type,
+ so you need to find the subclass of
+ {@link android.provider.ContactsContract.CommonDataKinds} that corresponds to the data type
+ and then choose the column name from that subclass. For example, to search for
+ email addresses, use the column
+ {@link android.provider.ContactsContract.CommonDataKinds.Email#ADDRESS Email.ADDRESS}.
+ </li>
+ <li>
+ The search string itself, represented as the "?" character in the selection clause.
+ </li>
+ <li>
+ The name of the column that contains the custom MIME type value. This name is always
+ {@link android.provider.ContactsContract.Data#MIMETYPE Data.MIMETYPE}.
+ </li>
+ <li>
+ The custom MIME type value for the data type. As described previously, this is the constant
+ <code>CONTENT_ITEM_TYPE</code> in the
+ {@link android.provider.ContactsContract.CommonDataKinds} subclass. For example, the MIME
+ type value for email data is
+ {@link android.provider.ContactsContract.CommonDataKinds.Email#CONTENT_ITEM_TYPE
+ Email.CONTENT_ITEM_TYPE}. Enclose the value in single quotes by concatenating a
+ "<code>'</code>" (single quote) character to the start and end of the constant; otherwise,
+ the provider interprets the value as a variable name rather than as a string value.
+ You don't need to use a placeholder for this value, because you're using a constant
+ rather than a user-supplied value.
+ </li>
+</ul>
+<p>
+ For example:
+</p>
+<pre>
+ /*
+ * Constructs search criteria from the search string
+ * and email MIME type
+ */
+ private static final String SELECTION =
+ /*
+ * Searches for an email address
+ * that matches the search string
+ */
+ Email.ADDRESS + " LIKE ? " + "AND " +
+ /*
+ * Searches for a MIME type that matches
+ * the value of the constant
+ * Email.CONTENT_ITEM_TYPE. Note the
+ * single quotes surrounding Email.CONTENT_ITEM_TYPE.
+ */
+ Data.MIMETYPE + " = '" + Email.CONTENT_ITEM_TYPE + "'";
+</pre>
+<p>
+ Next, define variables to contain the selection argument:
+</p>
+<pre>
+ String mSearchString;
+ String[] mSelectionArgs = { "" };
+</pre>
+<h3 id="SpecificLoader">Implement onCreateLoader()</h3>
+<p>
+ Now that you've specified the data you want and how to find it, define a query in your
+ implementation of {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader
+ onCreateLoader()}. Return a new {@link android.support.v4.content.CursorLoader} from this
+ method, using your projection, selection text expression, and selection array as
+ arguments. For a content URI, use
+ {@link android.provider.ContactsContract.Data#CONTENT_URI Data.CONTENT_URI}. For example:
+</p>
+<pre>
+ @Override
+ public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
+ // OPTIONAL: Makes search string into pattern
+ mSearchString = "%" + mSearchString + "%";
+ // Puts the search string into the selection criteria
+ mSelectionArgs[0] = mSearchString;
+ // Starts the query
+ return new CursorLoader(
+ getActivity(),
+ Data.CONTENT_URI,
+ PROJECTION,
+ SELECTION,
+ mSelectionArgs,
+ null
+ );
+ }
+</pre>
+<p>
+ These code snippets are the basis of a simple reverse lookup based on a specific type of detail
+ data. This is the best technique to use if your app focuses on a particular type of data, such
+ as emails, and you want allow users to get the names associated with a piece of data.
+</p>
+<h2 id="GeneralMatch">Match a Contact By Any Type of Data</h2>
+<p>
+ Retrieving a contact based on any type of data returns contacts if any of their data matches a
+ the search string, including name, email address, postal address, phone number, and so forth.
+ This results in a broad set of search results. For example, if the search string
+ is "Doe", then searching for any data type returns the contact "John Doe"; it also returns
+ contacts who live on "Doe Street".
+</p>
+<p>
+ To implement this type of retrieval, first implement the following code, as listed in
+ previous sections:
+</p>
+<ul>
+ <li>
+ Request Permission to Read the Provider.
+ </li>
+ <li>
+ Define ListView and item layouts.
+ </li>
+ <li>
+ <li>
+ Define a Fragment that displays the list of contacts.
+ </li>
+ <li>
+ Define global variables.
+ </li>
+ <li>
+ Initialize the Fragment.
+ </li>
+ <li>
+ Set up the CursorAdapter for the ListView.
+ </li>
+ <li>
+ Set the selected contact listener.
+ </li>
+ <li>
+ Define a projection.
+ </li>
+ <li>
+ Define constants for the Cursor column indexes.
+ <p>
+ For this type of retrieval, you're using the same table you used in the section
+ <a href="#NameMatch">Match a Contact by Name and List the Results</a>. Use the
+ same column indexes as well.
+ </p>
+ </li>
+ <li>
+ Define the onItemClick() method.
+ </li>
+ <li>
+ Initialize the loader.
+ </li>
+ <li>
+
+ Implement onLoadFinished() and onLoaderReset().
+ </li>
+</ul>
+<p>
+ The following steps show you the additional code you need to match a search string to
+ any type of data and display the results.
+</p>
+<h3 id="NoSelection">Remove selection criteria</h3>
+<p>
+ Don't define the <code>SELECTION</code> constants or the <code>mSelectionArgs</code> variable.
+ These aren't used in this type of retrieval.
+</p>
+<h3 id="CreateLoaderAny">Implement onCreateLoader()</h3>
+<p>
+ Implement the {@link android.support.v4.app.LoaderManager.LoaderCallbacks#onCreateLoader
+ onCreateLoader()} method, returning a new {@link android.support.v4.content.CursorLoader}.
+ You don't need to convert the search string into a pattern, because the Contacts Provider does
+ that automatically. Use
+ {@link android.provider.ContactsContract.Contacts#CONTENT_FILTER_URI
+ Contacts.CONTENT_FILTER_URI} as the base URI, and append your search string to it by calling
+ {@link android.net.Uri#withAppendedPath Uri.withAppendedPath()}. Using this URI
+ automatically triggers searching for any data type, as shown in the following example:
+</p>
+<pre>
+ @Override
+ public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) {
+ /*
+ * Appends the search string to the base URI. Always
+ * encode search strings to ensure they're in proper
+ * format.
+ */
+ Uri contentUri = Uri.withAppendedPath(
+ Contacts.CONTENT_FILTER_URI,
+ Uri.encode(mSearchString));
+ // Starts the query
+ return new CursorLoader(
+ getActivity(),
+ contentUri,
+ PROJECTION,
+ null,
+ null,
+ null
+ );
+ }
+</pre>
+<p>
+ These code snippets are the basis of an app that does a broad search of the Contacts Provider.
+ The technique is useful for apps that want to implement functionality similar to the
+ People app's contact list screen.
+</p>
diff --git a/docs/html/training/in-app-billing/purchase-iab-products.jd b/docs/html/training/in-app-billing/purchase-iab-products.jd
index 7fa77d3..4e6e035 100644
--- a/docs/html/training/in-app-billing/purchase-iab-products.jd
+++ b/docs/html/training/in-app-billing/purchase-iab-products.jd
@@ -104,7 +104,7 @@
</pre>
<h2 id="Consume">Consume a Purchase</h2>
-<p>You can use the In-app Billing Version 3 API to track the ownership of purchased items in Google Play. Once an item is purchased, it is considered to be "owned" and cannot be purchased again from Google Play while in that state. You must send a consumption request for the item before Google Play makes it available for purchase again. All managed in-app products are consumable. How you use the consumption mechanism in your app is up to you. Typically, you would implement consumption for products with temporary benefits that users may want to purchase multiple times (for example, in-game currency or replensihable game tokens). You would typically not want to implement consumption for products that are purchased once and provide a permanent effect (for example, a premium upgrade).</p>
+<p>You can use the In-app Billing Version 3 API to track the ownership of purchased items in Google Play. Once an item is purchased, it is considered to be "owned" and cannot be purchased again from Google Play while in that state. You must send a consumption request for the item before Google Play makes it available for purchase again. All managed in-app products are consumable. How you use the consumption mechanism in your app is up to you. Typically, you would implement consumption for products with temporary benefits that users may want to purchase multiple times (for example, in-game currency or replenishable game tokens). You would typically not want to implement consumption for products that are purchased once and provide a permanent effect (for example, a premium upgrade).</p>
<p>It's your responsibility to control and track how the in-app product is provisioned to the user. For example, if the user purchased in-game currency, you should update the player's inventory with the amount of currency purchased.</p>
<p class="note"><strong>Security Recommendation:</strong> You must send a consumption request before provisioning the benefit of the consumable in-app purchase to the user. Make sure that you have received a successful consumption response from Google Play before you provision the item.</p>
<p>To record a purchase consumption, call {@code consumeAsync(Purchase, OnConsumeFinishedListener)} on your {@code IabHelper} instance. The first argument that the method takes is the {@code Purchase} object representing the item to consume. The second argument is a {@code OnConsumeFinishedListener} that is notified when the consumption operation has completed and handles the consumption response from Google Play. It is safe to make this call fom your main thread.</p>
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 985fc44..7a3f2ca 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -484,7 +484,37 @@
</a>
</div>
<ul>
-
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>training/contacts-provider/index.html"
+ description=
+ "How to use Android's central address book, the Contacts Provider, to
+ display contacts and their details and modify contact information.">
+ Accessing Contacts Data</a>
+ </div>
+ <ul>
+ <li>
+ <a href="<?cs var:toroot ?>training/contacts-provider/retrieve-names.html">
+ Retrieving a List of Contacts
+ </a>
+ </li>
+ <li>
+ <a href="<?cs var:toroot ?>training/contacts-provider/retrieve-details.html">
+ Retrieving Details for a Contact
+ </a>
+ </li>
+ <li>
+ <a href="<?cs var:toroot ?>training/contacts-provider/modify-data.html">
+ Modifying Contacts Using Intents
+ </a>
+ </li>
+ <li>
+ <a href="<?cs var:toroot ?>training/contacts-provider/display-contact-badge.html">
+ Displaying the Quick Contact Badge
+ </a>
+ </li>
+ </ul>
+ </li>
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/id-auth/index.html"
@@ -879,7 +909,7 @@
</ul>
</li>
</ul>
- </li> <!-- end of User Input -->
+ </li> <!-- end of User Input -->
<li class="nav-section">
<div class="nav-section-header">
diff --git a/graphics/java/android/graphics/DashPathEffect.java b/graphics/java/android/graphics/DashPathEffect.java
index 4f16dc4..2bdecce 100644
--- a/graphics/java/android/graphics/DashPathEffect.java
+++ b/graphics/java/android/graphics/DashPathEffect.java
@@ -26,7 +26,7 @@
* controls the length of the dashes. The paint's strokeWidth controls the
* thickness of the dashes.
* Note: this patheffect only affects drawing with the paint's style is set
- * to STROKE or STROKE_AND_FILL. It is ignored if the drawing is done with
+ * to STROKE or FILL_AND_STROKE. It is ignored if the drawing is done with
* style == FILL.
* @param intervals array of ON and OFF distances
* @param phase offset into the intervals array
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index ef0da3a..7c547ec 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -328,8 +328,8 @@
* the state. Calling this method in an invalid state transfers the
* object to the <em>Error</em> state. </p></td></tr>
* <tr><td>pause </p></td>
- * <td>{Started, Paused}</p></td>
- * <td>{Idle, Initialized, Prepared, Stopped, PlaybackCompleted, Error}</p></td>
+ * <td>{Started, Paused, PlaybackCompleted}</p></td>
+ * <td>{Idle, Initialized, Prepared, Stopped, Error}</p></td>
* <td>Successful invoke of this method in a valid state transfers the
* object to the <em>Paused</em> state. Calling this method in an
* invalid state transfers the object to the <em>Error</em> state.</p></td></tr>