summaryrefslogtreecommitdiffstats
path: root/docs/html
diff options
context:
space:
mode:
Diffstat (limited to 'docs/html')
-rw-r--r--docs/html/design/building-blocks/buttons.jd1
-rw-r--r--docs/html/design/building-blocks/dialogs.jd1
-rw-r--r--docs/html/design/building-blocks/grid-lists.jd1
-rw-r--r--docs/html/design/building-blocks/lists.jd1
-rw-r--r--docs/html/design/building-blocks/pickers.jd1
-rw-r--r--docs/html/design/building-blocks/progress.jd1
-rw-r--r--docs/html/design/building-blocks/scrolling.jd1
-rw-r--r--docs/html/design/building-blocks/seek-bars.jd1
-rw-r--r--docs/html/design/building-blocks/spinners.jd1
-rw-r--r--docs/html/design/building-blocks/switches.jd1
-rw-r--r--docs/html/design/building-blocks/tabs.jd1
-rw-r--r--docs/html/design/building-blocks/text-fields.jd1
-rw-r--r--docs/html/design/patterns/accessibility.jd1
-rw-r--r--docs/html/design/patterns/actionbar.jd1
-rw-r--r--docs/html/design/patterns/app-structure.jd1
-rw-r--r--docs/html/design/patterns/confirming-acknowledging.jd1
-rw-r--r--docs/html/design/patterns/gestures.jd1
-rw-r--r--docs/html/design/patterns/multi-pane-layouts.jd1
-rw-r--r--docs/html/design/patterns/navigation.jd1
-rw-r--r--docs/html/design/patterns/notifications.jd1
-rw-r--r--docs/html/design/patterns/selection.jd1
-rw-r--r--docs/html/design/patterns/settings.jd1
-rw-r--r--docs/html/design/patterns/swipe-views.jd1
-rw-r--r--docs/html/design/patterns/widgets.jd1
-rw-r--r--docs/html/google/gcm/gcm.jd34
-rw-r--r--docs/html/google/gcm/gs.jd11
-rw-r--r--docs/html/guide/components/activities.jd1
-rw-r--r--docs/html/guide/practices/index.jd4
-rw-r--r--docs/html/guide/topics/manifest/data-element.jd3
-rw-r--r--docs/html/guide/topics/manifest/uses-sdk-element.jd80
-rw-r--r--docs/html/guide/topics/providers/calendar-provider.jd2
-rw-r--r--docs/html/guide/topics/ui/actionbar.jd1
-rw-r--r--docs/html/guide/topics/ui/binding.jd15
-rw-r--r--docs/html/guide/topics/ui/ui-events.jd4
-rw-r--r--docs/html/guide/webapps/webview.jd5
-rw-r--r--docs/html/index.jd5
-rw-r--r--docs/html/sdk/index.jd30
-rw-r--r--docs/html/tools/extras/support-library.jd29
-rw-r--r--docs/html/tools/revisions/platforms.jd19
-rw-r--r--docs/html/tools/sdk/eclipse-adt.jd2
-rw-r--r--docs/html/tools/sdk/ndk/index.jd256
-rw-r--r--docs/html/tools/sdk/tools-notes.jd4
-rw-r--r--docs/html/training/animation/index.jd1
-rw-r--r--docs/html/training/basics/data-storage/databases.jd2
-rw-r--r--docs/html/training/basics/data-storage/files.jd2
-rw-r--r--docs/html/training/basics/data-storage/index.jd1
-rw-r--r--docs/html/training/basics/data-storage/shared-preferences.jd2
-rw-r--r--docs/html/training/basics/fragments/communicating.jd4
-rw-r--r--docs/html/training/basics/fragments/creating.jd6
-rw-r--r--docs/html/training/basics/fragments/fragment-ui.jd6
-rw-r--r--docs/html/training/basics/fragments/index.jd3
-rw-r--r--docs/html/training/basics/fragments/support-lib.jd5
-rw-r--r--docs/html/training/basics/intents/index.jd3
-rw-r--r--docs/html/training/basics/network-ops/index.jd1
-rw-r--r--docs/html/training/basics/supporting-devices/index.jd3
-rw-r--r--docs/html/training/camera/index.jd1
-rw-r--r--docs/html/training/cloudsync/index.jd3
-rw-r--r--docs/html/training/connect-devices-wirelessly/index.jd3
-rw-r--r--docs/html/training/contacts-provider/ContactsList.zipbin0 -> 483676 bytes
-rw-r--r--docs/html/training/contacts-provider/display-contact-badge.jd635
-rw-r--r--docs/html/training/contacts-provider/index.jd97
-rw-r--r--docs/html/training/contacts-provider/modify-data.jd305
-rw-r--r--docs/html/training/contacts-provider/retrieve-details.jd378
-rw-r--r--docs/html/training/contacts-provider/retrieve-names.jd815
-rw-r--r--docs/html/training/displaying-bitmaps/cache-bitmap.jd4
-rw-r--r--docs/html/training/displaying-bitmaps/display-bitmap.jd2
-rw-r--r--docs/html/training/displaying-bitmaps/index.jd8
-rw-r--r--docs/html/training/displaying-bitmaps/load-bitmap.jd4
-rw-r--r--docs/html/training/displaying-bitmaps/manage-memory.jd297
-rw-r--r--docs/html/training/displaying-bitmaps/process-bitmap.jd4
-rw-r--r--docs/html/training/efficient-downloads/index.jd3
-rw-r--r--docs/html/training/gestures/detector.jd8
-rw-r--r--docs/html/training/gestures/index.jd8
-rw-r--r--docs/html/training/gestures/movement.jd8
-rw-r--r--docs/html/training/gestures/multi.jd8
-rw-r--r--docs/html/training/gestures/scale.jd205
-rw-r--r--docs/html/training/gestures/scroll.jd339
-rw-r--r--docs/html/training/gestures/viewgroup.jd9
-rw-r--r--docs/html/training/graphics/opengl/index.jd3
-rw-r--r--docs/html/training/implementing-navigation/lateral.jd3
-rw-r--r--docs/html/training/managing-audio/index.jd3
-rw-r--r--docs/html/training/notify-user/build-notification.jd4
-rw-r--r--docs/html/training/sharing/index.jd3
-rw-r--r--docs/html/training/training_toc.cs38
84 files changed, 3504 insertions, 262 deletions
diff --git a/docs/html/design/building-blocks/buttons.jd b/docs/html/design/building-blocks/buttons.jd
index 82e2477..9e82ed4 100644
--- a/docs/html/design/building-blocks/buttons.jd
+++ b/docs/html/design/building-blocks/buttons.jd
@@ -1,4 +1,5 @@
page.title=Buttons
+page.tags="button"
@jd:body
<p>A button consists of text and/or an image that clearly communicates what action will occur when the
diff --git a/docs/html/design/building-blocks/dialogs.jd b/docs/html/design/building-blocks/dialogs.jd
index a2ece2e..2f6ca27 100644
--- a/docs/html/design/building-blocks/dialogs.jd
+++ b/docs/html/design/building-blocks/dialogs.jd
@@ -1,4 +1,5 @@
page.title=Dialogs
+page.tags="dialog","alert","popup","toast"
@jd:body
<p>Dialogs prompt the user for decisions or additional information required by the app to continue a
diff --git a/docs/html/design/building-blocks/grid-lists.jd b/docs/html/design/building-blocks/grid-lists.jd
index 775ebcc..69a43b1 100644
--- a/docs/html/design/building-blocks/grid-lists.jd
+++ b/docs/html/design/building-blocks/grid-lists.jd
@@ -1,4 +1,5 @@
page.title=Grid Lists
+page.tags="gridview","layout"
@jd:body
<img src="{@docRoot}design/media/gridview_overview.png">
diff --git a/docs/html/design/building-blocks/lists.jd b/docs/html/design/building-blocks/lists.jd
index aaa86b8..16927a6 100644
--- a/docs/html/design/building-blocks/lists.jd
+++ b/docs/html/design/building-blocks/lists.jd
@@ -1,4 +1,5 @@
page.title=Lists
+page.tags="listview","layout"
@jd:body
<p>Lists present multiple line items in a vertical arrangement. They can be used for data selection as
diff --git a/docs/html/design/building-blocks/pickers.jd b/docs/html/design/building-blocks/pickers.jd
index b328df9..47363d0 100644
--- a/docs/html/design/building-blocks/pickers.jd
+++ b/docs/html/design/building-blocks/pickers.jd
@@ -1,4 +1,5 @@
page.title=Pickers
+page.tags="datepicker","timepicker"
@jd:body
<p>Pickers provide a simple way to select a single value from a set. In addition to touching the
diff --git a/docs/html/design/building-blocks/progress.jd b/docs/html/design/building-blocks/progress.jd
index 7342387..96cc1af 100644
--- a/docs/html/design/building-blocks/progress.jd
+++ b/docs/html/design/building-blocks/progress.jd
@@ -1,4 +1,5 @@
page.title=Progress &amp; Activity
+page.tags="progressbar"
@jd:body
<p>Progress bars and activity indicators signal to users that something is happening that will take a moment.</p>
diff --git a/docs/html/design/building-blocks/scrolling.jd b/docs/html/design/building-blocks/scrolling.jd
index 7695157..66999f9 100644
--- a/docs/html/design/building-blocks/scrolling.jd
+++ b/docs/html/design/building-blocks/scrolling.jd
@@ -1,4 +1,5 @@
page.title=Scrolling
+page.tags="scrollview","listview"
@jd:body
<p>Scrolling allows the user to navigate to content in the overflow using a swipe gesture. The
diff --git a/docs/html/design/building-blocks/seek-bars.jd b/docs/html/design/building-blocks/seek-bars.jd
index 3407ddd..9d38e36 100644
--- a/docs/html/design/building-blocks/seek-bars.jd
+++ b/docs/html/design/building-blocks/seek-bars.jd
@@ -1,4 +1,5 @@
page.title=Seek Bars and Sliders
+page.tags="seekbar","progressbar"
@jd:body
<p>Interactive sliders make it possible to select a value from a continuous or discrete range of values
diff --git a/docs/html/design/building-blocks/spinners.jd b/docs/html/design/building-blocks/spinners.jd
index 279565f..8c80b91 100644
--- a/docs/html/design/building-blocks/spinners.jd
+++ b/docs/html/design/building-blocks/spinners.jd
@@ -1,4 +1,5 @@
page.title=Spinners
+page.tags="spinner","drop down"
@jd:body
<p>Spinners provide a quick way to select one value from a set. In the default state, a spinner shows
diff --git a/docs/html/design/building-blocks/switches.jd b/docs/html/design/building-blocks/switches.jd
index d9cfd07..6386bdf 100644
--- a/docs/html/design/building-blocks/switches.jd
+++ b/docs/html/design/building-blocks/switches.jd
@@ -1,4 +1,5 @@
page.title=Switches
+page.tags="switch","checkbox","radiobutton"
@jd:body
<p>Switches allow the user to select options. There are three kinds of switches: checkboxes, radio
diff --git a/docs/html/design/building-blocks/tabs.jd b/docs/html/design/building-blocks/tabs.jd
index 0a0f907..1fe2c62 100644
--- a/docs/html/design/building-blocks/tabs.jd
+++ b/docs/html/design/building-blocks/tabs.jd
@@ -1,4 +1,5 @@
page.title=Tabs
+page.tags="tabs","action bar","navigation"
@jd:body
<img src="{@docRoot}design/media/tabs_overview.png">
diff --git a/docs/html/design/building-blocks/text-fields.jd b/docs/html/design/building-blocks/text-fields.jd
index 563f247..c1bed78 100644
--- a/docs/html/design/building-blocks/text-fields.jd
+++ b/docs/html/design/building-blocks/text-fields.jd
@@ -1,4 +1,5 @@
page.title=Text Fields
+page.tags="text","edittext","input",
@jd:body
<p>Text fields allow the user to type text into your app. They can be either single line or multi-line.
diff --git a/docs/html/design/patterns/accessibility.jd b/docs/html/design/patterns/accessibility.jd
index 2c3333f..edf3843 100644
--- a/docs/html/design/patterns/accessibility.jd
+++ b/docs/html/design/patterns/accessibility.jd
@@ -1,4 +1,5 @@
page.title=Accessibility
+page.tags="accessibility","navigation"
@jd:body
<p>One of Android's missions is to organize the world's information and make it universally accessible and useful. Accessibility is the measure of how successfully a product can be used by people with varying abilities. Our mission applies to all users-including people with disabilities such as visual impairment, color deficiency, hearing loss, and limited dexterity.</p>
diff --git a/docs/html/design/patterns/actionbar.jd b/docs/html/design/patterns/actionbar.jd
index 265ccde..da9c3c3 100644
--- a/docs/html/design/patterns/actionbar.jd
+++ b/docs/html/design/patterns/actionbar.jd
@@ -1,4 +1,5 @@
page.title=Action Bar
+page.tags="actionbar","navigation"
@jd:body
<img src="{@docRoot}design/media/action_bar_pattern_overview.png">
diff --git a/docs/html/design/patterns/app-structure.jd b/docs/html/design/patterns/app-structure.jd
index 04af57b..e1bb819 100644
--- a/docs/html/design/patterns/app-structure.jd
+++ b/docs/html/design/patterns/app-structure.jd
@@ -1,4 +1,5 @@
page.title=Application Structure
+page.tags="navigation","layout"
@jd:body
<p>Apps come in many varieties that address very different needs. For example:</p>
diff --git a/docs/html/design/patterns/confirming-acknowledging.jd b/docs/html/design/patterns/confirming-acknowledging.jd
index ce0631b..f2e88ec 100644
--- a/docs/html/design/patterns/confirming-acknowledging.jd
+++ b/docs/html/design/patterns/confirming-acknowledging.jd
@@ -1,4 +1,5 @@
page.title=Confirming &amp; Acknowledging
+page.tags="dialog","toast"
@jd:body
<p>In some situations, when a user invokes an action in your app, it's a good idea to <em>confirm</em> or <em>acknowledge</em> that action through text.</p>
diff --git a/docs/html/design/patterns/gestures.jd b/docs/html/design/patterns/gestures.jd
index e579cee..3ef133d 100644
--- a/docs/html/design/patterns/gestures.jd
+++ b/docs/html/design/patterns/gestures.jd
@@ -1,4 +1,5 @@
page.title=Gestures
+page.tags="gesture","input"
@jd:body
<p>Gestures allow users to interact with your app by manipulating the screen objects you provide. The
diff --git a/docs/html/design/patterns/multi-pane-layouts.jd b/docs/html/design/patterns/multi-pane-layouts.jd
index e607676..cbf29cb 100644
--- a/docs/html/design/patterns/multi-pane-layouts.jd
+++ b/docs/html/design/patterns/multi-pane-layouts.jd
@@ -1,4 +1,5 @@
page.title=Multi-pane Layouts
+page.tags="tablet","navigation","layout","fragment"
@jd:body
<p>When writing an app for Android, keep in mind that Android devices come in many different screen
diff --git a/docs/html/design/patterns/navigation.jd b/docs/html/design/patterns/navigation.jd
index 656e6e5..36debbe 100644
--- a/docs/html/design/patterns/navigation.jd
+++ b/docs/html/design/patterns/navigation.jd
@@ -1,4 +1,5 @@
page.title=Navigation with Back and Up
+page.tags="navigation","activity"
@jd:body
<p>Consistent navigation is an essential component of the overall user experience. Few things frustrate
diff --git a/docs/html/design/patterns/notifications.jd b/docs/html/design/patterns/notifications.jd
index 0665774..3ae827e 100644
--- a/docs/html/design/patterns/notifications.jd
+++ b/docs/html/design/patterns/notifications.jd
@@ -1,4 +1,5 @@
page.title=Notifications
+page.tags="notification"
@jd:body
<p>The notification system allows your app to keep the user informed about events, such as new chat messages or a calendar event. Think of notifications as a news channel that alerts the user to important events as they happen or a log that chronicles events while the user is not paying attention.</p>
diff --git a/docs/html/design/patterns/selection.jd b/docs/html/design/patterns/selection.jd
index e9d22e6..682ce56 100644
--- a/docs/html/design/patterns/selection.jd
+++ b/docs/html/design/patterns/selection.jd
@@ -1,4 +1,5 @@
page.title=Selection
+page.tags="actionmode","navigation"
@jd:body
<p>Android 3.0 changed the <em>long press</em> gesture&mdash;that is, a touch that's held in the same position for a moment&mdash;to be the global gesture to select data.. This affects the way you should
diff --git a/docs/html/design/patterns/settings.jd b/docs/html/design/patterns/settings.jd
index fef7585..f86cd39 100644
--- a/docs/html/design/patterns/settings.jd
+++ b/docs/html/design/patterns/settings.jd
@@ -1,4 +1,5 @@
page.title=Settings
+page.tags="settings","preferences"
@jd:body
<p>Settings is a place in your app where users indicate their preferences for how your app should
diff --git a/docs/html/design/patterns/swipe-views.jd b/docs/html/design/patterns/swipe-views.jd
index daddd31..b86d990 100644
--- a/docs/html/design/patterns/swipe-views.jd
+++ b/docs/html/design/patterns/swipe-views.jd
@@ -1,4 +1,5 @@
page.title=Swipe Views
+page.tags="viewpager","navigation"
@jd:body
<p>Efficient navigation is one of the cornerstones of a well-designed app. While apps are generally
diff --git a/docs/html/design/patterns/widgets.jd b/docs/html/design/patterns/widgets.jd
index 54726b1..a5979ce 100644
--- a/docs/html/design/patterns/widgets.jd
+++ b/docs/html/design/patterns/widgets.jd
@@ -1,4 +1,5 @@
page.title=Widgets
+page.tags="appwidget"
@jd:body
<p>Widgets are an essential aspect of home screen customization. You can imagine them as "at-a-glance" views of an app's most important data and functionality that is accessible right from the user's home screen. Users can move widgets across their home screen panels, and, if supported, resize them to tailor the amount of information within a widget to their preference.</p>
diff --git a/docs/html/google/gcm/gcm.jd b/docs/html/google/gcm/gcm.jd
index 11b5a6c..fb57a91 100644
--- a/docs/html/google/gcm/gcm.jd
+++ b/docs/html/google/gcm/gcm.jd
@@ -149,7 +149,16 @@ it to receive messages. Once the Android application has the registration ID, it
it to the 3rd-party application server, which uses it to identify each device
that has registered to receive messages for a given Android application. In other words,
a registration ID is tied to a particular Android application running on a particular
-device.</td>
+device.
+<br/>
+<br/>
+<strong>Note:</strong> If you use
+<a href="https://developer.android.com/google/backup/index.html">backup and restore</a>,
+you should explicitly avoid backing up registration IDs. When you back up
+a device, apps back up shared prefs indiscriminately. If you don't explicitly
+exclude the GCM registration ID, it could get reused on a new device,
+which would cause delivery errors.
+</td>
</tr>
<tr>
<td><strong>Google User Account</strong></td>
@@ -295,6 +304,13 @@ include:
</li>
</ul>
+<p class="note"><strong>Note:</strong> This section describes how to
+write an app without using the
+<a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a>.
+For details on writing
+an app that uses the helper libraries (which is the recommended and
+simpler approach), see <a href="gs.html">GCM: Getting Started</a>.
+
<h3 id="manifest">Creating the Manifest</h3>
<p>Every Android application must have an <code>AndroidManifest.xml</code> file (with
@@ -585,6 +601,7 @@ ensures that the Android application cannot be installed in an environment in wh
could not run properly. </li>
</ul>
+
<h2 id="server">Role of the 3rd-party Application Server</h2>
<p>Before you can write client Android applications that use the GCM feature, you must
@@ -758,9 +775,14 @@ sent. Optional. The default value is <code>false</code>, and must be a JSON bool
<pre class="prettyprint">collapse_key=score_update&amp;time_to_live=108&amp;delay_while_idle=1&amp;data.score=4x8&amp;data.time=15:16.2342&amp;registration_id=42
</pre>
- <p class="note"><strong>Note:</strong> If your organization has a firewall that restricts the traffic to or from the Internet, you'll need to configure it to allow connectivity with GCM. 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. It changes IPs frequently. We recommend against using ACLs but if you must use them, take a broad approach such as the method suggested in <a href="http://support.google.com/code/bin/answer.py?hl=en&answer=62464">this support link</a>.
-</p>
+<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.
+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
+contained in the IP blocks listed in Google's ASN of 15169.</p>
+
<h4 id="response">Response format</h4>
@@ -770,7 +792,7 @@ GCM doesn't provide specific IPs. It changes IPs frequently. We recommend agains
<li>The GCM server rejects the request.</li>
</ul>
-<p>When the messge is processed successfully, the HTTP response has a 200 status and the body contains more information about the status of the message (including possible errors). When the request is rejected,
+<p>When the message is processed successfully, the HTTP response has a 200 status and the body contains more information about the status of the message (including possible errors). When the request is rejected,
the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
<p>The following table summarizes the statuses that the HTTP response header might contain. Click the troubleshoot link for advice on how to deal with each type of error.</p>
@@ -825,7 +847,7 @@ the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
<td>Array of objects representing the status of the messages processed. The objects are listed in the same order as the request (i.e., for each registration ID in the request, its result is listed in the same index in the response) and they can have these fields:<br>
<ul>
<li><code>message_id</code>: String representing the message when it was successfully processed.</li>
- <li><code>registration_id</code>: If set, means that GCM processed the message but it has another canonical registration ID for that device, so sender should replace the IDs on future requests (otherwise they might be rejected). This field is never set if there is an error in the request.<br />
+ <li><code>registration_id</code>: If set, means that GCM processed the message but it has another canonical registration ID for that device, so sender should replace the IDs on future requests (otherwise they might be rejected). This field is never set if there is an error in the request.
</li>
<li><code>error</code>: String describing an error that occurred while processing the message for that recipient. The possible values are the same as documented in the above table, plus &quot;Unavailable&quot; (meaning GCM servers were busy and could not process the message for that particular recipient, so it could be retried).</li>
</ul></td>
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index 37ef684..5d34641 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -86,8 +86,15 @@ page.title=GCM: Getting Started
<h2 id="libs">Install the Helper Libraries</h2>
<p>To perform the steps described in the following sections, you must first install the
-<a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a>.
-From the SDK Manager, install <strong>Extras &gt; Google Cloud Messaging for Android Library</strong>. This creates a <code>gcm</code> directory under <code><em>YOUR_SDK_ROOT</em>/extras/google/</code> containing these subdirectories: <code>gcm-client</code>, <code>gcm-server</code>, <code>samples/gcm-demo-client</code>, <code>samples/gcm-demo-server</code>, and <code>samples/gcm-demo-appengine</code>.</p>
+<a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a>. Note that while using the helper libraries is recommended, it is not required. See the <a href="gcm.html#writing_apps">GCM Architectural Overview</a> for a description of how to write apps without using the helper libraries.
+
+<p>To install the helper libraries, choose
+<strong>Extras &gt; Google Cloud Messaging for Android Library</strong>
+from the SDK Manager. This creates a <code>gcm</code> directory under
+<code><em>YOUR_SDK_ROOT</em>/extras/google/</code> containing these
+subdirectories: <code>gcm-client</code>, <code>gcm-server</code>,
+<code>samples/gcm-demo-client</code>, <code>samples/gcm-demo-server</code>,
+and <code>samples/gcm-demo-appengine</code>.</p>
<p class="note"><strong>Note:</strong> If you don't see <strong>Extras &gt; Google Cloud Messaging for Android Library</strong> in the SDK Manager, make sure you are running version 20 or higher. Be sure to restart the SDK Manager after updating it.</p>
diff --git a/docs/html/guide/components/activities.jd b/docs/html/guide/components/activities.jd
index 2897804..1cbaa79 100644
--- a/docs/html/guide/components/activities.jd
+++ b/docs/html/guide/components/activities.jd
@@ -1,4 +1,5 @@
page.title=Activities
+page.tags="activity","intent"
@jd:body
<div id="qv-wrapper">
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 @@ of fueling the impression-install-ranking cycle: improve the product!</p>
<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 @@ make mistakes in the way they interact with the Android system and with other ap
</div>
-</div> \ No newline at end of file
+</div>
diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd
index 8fd91de..766d2d7 100644
--- a/docs/html/guide/topics/manifest/data-element.jd
+++ b/docs/html/guide/topics/manifest/data-element.jd
@@ -85,6 +85,9 @@ host names using lowercase letters.</p>
The subtype can be the asterisk wildcard ({@code *}) to indicate that any
subtype matches.
+<p>It's common for an intent filter to declare a {@code &lt;data>} that includes
+only the {@code android:mimeType} attribute.</p>
+
<p class="note">Note: MIME type matching in the Android framework is
case-sensitive, unlike formal RFC MIME types. As a result, you should always
specify MIME types using lowercase letters.</p>
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index f9e2785..3b3bb8f 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -26,14 +26,14 @@ parent.link=manifest-intro.html
</div>
</div>
-<div class="sidebox-wrapper">
+<div class="sidebox-wrapper">
<div class="sidebox">
- <img src="{@docRoot}assets/images/icon_play.png" style="float:left;margin:0;padding:0;">
- <p style="color:#669999;padding-top:1em;">Google Play Filtering</p>
+ <img src="{@docRoot}assets/images/icon_play.png" style="float:left;margin:0;padding:0;">
+ <p style="color:#669999;padding-top:1em;">Google Play Filtering</p>
<p style="padding-top:1em;">Google Play uses the <code>&lt;uses-sdk&gt;</code>
- attributes declared in your app manifest to filter your app from devices
+ attributes declared in your app manifest to filter your app from devices
that do not meet it's platform version requirements. Before setting these
- attributes, make sure that you understand
+ attributes, make sure that you understand
<a href="{@docRoot}google/play/filters.html">Google Play filters</a>. </p>
</div>
</div>
@@ -41,7 +41,7 @@ parent.link=manifest-intro.html
<dl class="xml">
<dt>syntax:</dt>
<dd><pre>
-&lt;uses-sdk android:<a href="#min">minSdkVersion</a>="<i>integer</i>"
+&lt;uses-sdk android:<a href="#min">minSdkVersion</a>="<i>integer</i>"
android:<a href="#target">targetSdkVersion</a>="<i>integer</i>"
android:<a href="#max">maxSdkVersion</a>="<i>integer</i>" /&gt;</pre></dd>
@@ -55,14 +55,14 @@ API Level of a given Android system, which may vary among different Android devi
</p>
<p>Despite its name, this element is used to specify the API Level, <em>not</em>
-the version number of the SDK (software development kit) or Android platform.
+the version number of the SDK (software development kit) or Android platform.
The API Level is always a single integer. You cannot derive the API Level from
its associated Android version number (for example, it is not the same as the
major version or the sum of the major and minor versions).</p>
<p>Also read the document about
<a href="{@docRoot}tools/publishing/versioning.html">Versioning Your Applications</a>.
-</p></dd>
+</p></dd>
<dt>attributes:</dt>
@@ -117,8 +117,8 @@ the corresponding platform version.</p>
</dd>
<dt><a name="max"></a>{@code android:maxSdkVersion}</dt>
- <dd>An integer designating the maximum API Level on which the application is
- designed to run.
+ <dd>An integer designating the maximum API Level on which the application is
+ designed to run.
<p>In Android 1.5, 1.6, 2.0, and 2.0.1, the system checks the value of this
attribute when installing an application and when re-validating the application
@@ -165,7 +165,7 @@ installation or re-validation. Google Play will continue to use the attribute
as a filter, however, when presenting users with applications available for
download. </div>
</dd>
-
+
</dl></dd>
@@ -217,7 +217,7 @@ modification.</p>
<p>The framework API that an Android platform delivers is specified using an
integer identifier called "API Level". Each Android platform version supports
exactly one API Level, although support is implicit for all earlier API Levels
-(down to API Level 1). The initial release of the Android platform provided
+(down to API Level 1). The initial release of the Android platform provided
API Level 1 and subsequent releases have incremented the API Level.</p>
<p>The table below specifies the API Level supported by each version of the
@@ -227,8 +227,8 @@ Versions dashboards page</a>.</p>
<table>
<tr><th>Platform Version</th><th>API Level</th><th>VERSION_CODE</th><th>Notes</th></tr>
-
- <tr><td><a href="{@docRoot}about/versions/android-4.2.html">Android 4.2</a></td>
+
+ <tr><td><a href="{@docRoot}about/versions/android-4.2.html">Android 4.2, 4.2.2</a></td>
<td><a href="{@docRoot}sdk/api_diff/17/changes.html" title="Diff Report">17</a></td>
<td>{@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}</td>
<td><a href="{@docRoot}about/versions/jelly-bean.html">Platform
@@ -250,70 +250,70 @@ Highlights</a></td></tr>
<td><a href="{@docRoot}sdk/api_diff/14/changes.html" title="Diff Report">14</a></td>
<td>{@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}</td>
</tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-3.2.html">Android 3.2</a></td>
<td><a href="{@docRoot}sdk/api_diff/13/changes.html" title="Diff Report">13</a></td>
<td>{@link android.os.Build.VERSION_CODES#HONEYCOMB_MR2}</td>
<td><!-- <a href="{@docRoot}about/versions/android-3.2-highlights.html">Platform
Highlights</a>--></td></tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-3.1.html">Android 3.1.x</a></td>
<td><a href="{@docRoot}sdk/api_diff/12/changes.html" title="Diff Report">12</a></td>
<td>{@link android.os.Build.VERSION_CODES#HONEYCOMB_MR1}</td>
<td><a href="{@docRoot}about/versions/android-3.1-highlights.html">Platform Highlights</a></td></tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-3.0.html">Android 3.0.x</td>
<td><a href="{@docRoot}sdk/api_diff/11/changes.html" title="Diff Report">11</a></td>
<td>{@link android.os.Build.VERSION_CODES#HONEYCOMB}</td>
<td><a href="{@docRoot}about/versions/android-3.0-highlights.html">Platform Highlights</a></td></tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-2.3.3.html">Android 2.3.4<br>Android 2.3.3</td>
<td><a href="{@docRoot}sdk/api_diff/10/changes.html" title="Diff Report">10</a></td>
<td>{@link android.os.Build.VERSION_CODES#GINGERBREAD_MR1}</td>
<td rowspan="2"><a href="{@docRoot}about/versions/android-2.3-highlights.html">Platform
Highlights</a></td></tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-2.3.html">Android 2.3.2<br>Android 2.3.1<br>Android
2.3</td>
<td><a href="{@docRoot}sdk/api_diff/9/changes.html" title="Diff Report">9</a></td>
<td>{@link android.os.Build.VERSION_CODES#GINGERBREAD}</td>
</tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-2.2.html">Android 2.2.x</td>
<td ><a href="{@docRoot}sdk/api_diff/8/changes.html" title="Diff Report">8</a></td>
<td>{@link android.os.Build.VERSION_CODES#FROYO}</td>
<td><a href="{@docRoot}about/versions/android-2.2-highlights.html">Platform Highlights</a></td></tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-2.1.html">Android 2.1.x</td>
<td><a href="{@docRoot}sdk/api_diff/7/changes.html" title="Diff Report">7</a></td>
<td>{@link android.os.Build.VERSION_CODES#ECLAIR_MR1}</td>
<td rowspan="3" ><a href="{@docRoot}about/versions/android-2.0-highlights.html">Platform
Highlights</a></td></tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-2.0.1.html">Android 2.0.1</td>
<td><a href="{@docRoot}sdk/api_diff/6/changes.html" title="Diff Report">6</a></td>
<td>{@link android.os.Build.VERSION_CODES#ECLAIR_0_1}</td>
</tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-2.0.html">Android 2.0</td>
<td><a href="{@docRoot}sdk/api_diff/5/changes.html" title="Diff Report">5</a></td>
<td>{@link android.os.Build.VERSION_CODES#ECLAIR}</td>
</tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-1.6.html">Android 1.6</td>
<td><a href="{@docRoot}sdk/api_diff/4/changes.html" title="Diff Report">4</a></td>
<td>{@link android.os.Build.VERSION_CODES#DONUT}</td>
<td><a href="{@docRoot}about/versions/android-1.6-highlights.html">Platform Highlights</a></td></tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-1.5.html">Android 1.5</td>
<td><a href="{@docRoot}sdk/api_diff/3/changes.html" title="Diff Report">3</a></td>
<td>{@link android.os.Build.VERSION_CODES#CUPCAKE}</td>
<td><a href="{@docRoot}about/versions/android-1.5-highlights.html">Platform Highlights</a></td></tr>
-
+
<tr><td><a href="{@docRoot}about/versions/android-1.1.html">Android 1.1</td>
<td>2</td>
<td>{@link android.os.Build.VERSION_CODES#BASE_1_1}</td><td></td></tr>
-
+
<tr><td>Android 1.0</td>
<td>1</td>
<td>{@link android.os.Build.VERSION_CODES#BASE}</td>
@@ -324,10 +324,10 @@ Highlights</a></td></tr>
<h2 id="uses">Uses of API Level in Android</h2>
<p>The API Level identifier serves a key role in ensuring the best possible
-experience for users and application developers:
+experience for users and application developers:
<ul>
-<li>It lets the Android platform describe the maximum framework API revision
+<li>It lets the Android platform describe the maximum framework API revision
that it supports</li>
<li>It lets applications describe the framework API revision that they
require</li>
@@ -349,7 +349,7 @@ on which the application is able to run. The default value is "1".</li>
<li><code>android:targetSdkVersion</code> &mdash; Specifies the API Level
on which the application is designed to run. In some cases, this allows the
application to use manifest elements or behaviors defined in the target
-API Level, rather than being restricted to using only those defined
+API Level, rather than being restricted to using only those defined
for the minimum API Level.</li>
<li><code>android:maxSdkVersion</code> &mdash; Specifies the maximum API Level
on which the application is able to run. <strong>Important:</strong> Please read the <a
@@ -375,7 +375,7 @@ installation to begin only if these conditions are met:</p>
must be less than or equal to the system's API Level integer. If not declared,
the system assumes that the application requires API Level 1. </li>
<li>If a <code>android:maxSdkVersion</code> attribute is declared, its value
-must be equal to or greater than the system's API Level integer.
+must be equal to or greater than the system's API Level integer.
If not declared, the system assumes that the application
has no maximum API Level. Please read the <a
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html"><code>&lt;uses-sdk&gt;</code></a>
@@ -470,7 +470,7 @@ might not receive an update for a significant amount of time. </p>
<p>When you are developing your application, you will need to choose
the platform version against which you will compile the application. In
general, you should compile your application against the lowest possible
-version of the platform that your application can support.
+version of the platform that your application can support.
<p>You can determine the lowest possible platform version by compiling the
application against successively lower build targets. After you determine the
@@ -513,7 +513,7 @@ download other platform versions as necessary. </p>
located in the &lt;sdk&gt;/tools directory. You can launch the SDK updater by
executing <code>android sdk</code>. You can
also simply double-click the android.bat (Windows) or android (OS X/Linux) file.
-In ADT, you can also access the updater by selecting
+In ADT, you can also access the updater by selecting
<strong>Window</strong>&nbsp;>&nbsp;<strong>Android SDK
Manager</strong>.</p>
@@ -552,9 +552,9 @@ Level integer.</p>
<h2 id="filtering">Filtering the Reference Documentation by API Level</h2>
<p>Reference documentation pages on the Android Developers site offer a "Filter
-by API Level" control in the top-right area of each page. You can use the
-control to show documentation only for parts of the API that are actually
-accessible to your application, based on the API Level that it specifies in
+by API Level" control in the top-right area of each page. You can use the
+control to show documentation only for parts of the API that are actually
+accessible to your application, based on the API Level that it specifies in
the <code>android:minSdkVersion</code> attribute of its manifest file. </p>
<p>To use filtering, select the checkbox to enable filtering, just below the
@@ -574,10 +574,10 @@ disabled, so that you can view the full framework API, regardless of API Level.
</p>
<p>Also note that the reference documentation for individual API elements
-specifies the API Level at which each element was introduced. The API Level
-for packages and classes is specified as "Since &lt;api level&gt;" at the
-top-right corner of the content area on each documentation page. The API Level
-for class members is specified in their detailed description headers,
+specifies the API Level at which each element was introduced. The API Level
+for packages and classes is specified as "Since &lt;api level&gt;" at the
+top-right corner of the content area on each documentation page. The API Level
+for class members is specified in their detailed description headers,
at the right margin. </p>
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 @@ ContentValues values = new ContentValues();
Uri updateUri = null;
// The new title for the event
values.put(Events.TITLE, &quot;Kickboxing&quot;);
-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, &quot;Rows updated: &quot; + rows); </pre>
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index 3115c8f..678a512 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -1,4 +1,5 @@
page.title=Action Bar
+page.tags="action bar","menu"
parent.title=User Interface
parent.link=index.html
@jd:body
diff --git a/docs/html/guide/topics/ui/binding.jd b/docs/html/guide/topics/ui/binding.jd
index e8b49d5..a4fd25c 100644
--- a/docs/html/guide/topics/ui/binding.jd
+++ b/docs/html/guide/topics/ui/binding.jd
@@ -10,13 +10,6 @@ parent.link=index.html
<li><a href="#FillingTheLayout">Filling the Layout with Data</a></li>
<li><a href="#HandlingUserSelections">Handling User Selections</a></li>
</ol>
-
- <h2>Related tutorials</h2>
- <ol>
- <li><a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Spinner</a></li>
- <li><a href="{@docRoot}resources/tutorials/views/hello-listview.html">List View</a></li>
- <li><a href="{@docRoot}resources/tutorials/views/hello-gridview.html">Grid View</a></li>
- </ol>
</div>
</div>
@@ -81,8 +74,8 @@ mHistoryView.setOnItemClickListener(mMessageClickedHandler);
</pre>
<div class="special">
-<p>For more discussion on how to create different AdapterViews, read the following tutorials:
-<a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Hello Spinner</a>,
-<a href="{@docRoot}resources/tutorials/views/hello-listview.html">Hello ListView</a>, and
-<a href="{@docRoot}resources/tutorials/views/hello-gridview.html">Hello GridView</a>.
+<p>For more discussion on how to create different AdapterViews, read the following guides:
+<a href="{@docRoot}guide/topics/ui/controls/spinner.html">Spinner</a>,
+<a href="{@docRoot}guide/topics/ui/layout/listview.html">List View</a>, and
+<a href="{@docRoot}guide/topics/ui/layout/gridview.html">Grid View</a>.
</div>
diff --git a/docs/html/guide/topics/ui/ui-events.jd b/docs/html/guide/topics/ui/ui-events.jd
index 707d4b1..6d41b15 100644
--- a/docs/html/guide/topics/ui/ui-events.jd
+++ b/docs/html/guide/topics/ui/ui-events.jd
@@ -13,10 +13,6 @@ parent.link=index.html
<li><a href="#HandlingFocus">Handling Focus</a></li>
</ol>
- <h2>Related tutorials</h2>
- <ol>
- <li><a href="{@docRoot}resources/tutorials/views/hello-formstuff.html">Form Stuff</a></li>
- </ol>
</div>
</div>
diff --git a/docs/html/guide/webapps/webview.jd b/docs/html/guide/webapps/webview.jd
index d2b2532..c87be06 100644
--- a/docs/html/guide/webapps/webview.jd
+++ b/docs/html/guide/webapps/webview.jd
@@ -33,11 +33,6 @@ layout</li>
<li>{@link android.webkit.WebViewClient}</li>
</ol>
-<h2>Related tutorials</h2>
-<ol>
- <li><a href="{@docRoot}resources/tutorials/views/hello-webview.html">Web View</a></li>
-</ol>
-
</div>
</div>
diff --git a/docs/html/index.jd b/docs/html/index.jd
index f2df7be..ec0469c 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -19,12 +19,11 @@ page.metaDescription=The official site for Android developers. Provides the Andr
<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.
- Registration opens on March 13, 2013 at 7:00 AM PDT (GMT-7).</p>
+ 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/register" class="button">Register here</a></p>
+ <p><a href="https://developers.google.com/events/io/" class="button">Learn more</a></p>
</div>
</li>
<li class="item carousel-home">
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 6307c69..315c977 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -4,25 +4,25 @@ header.hide=1
page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
-sdk.linux32_bundle_download=adt-bundle-linux-x86.zip
-sdk.linux32_bundle_bytes=418614971
-sdk.linux32_bundle_checksum=24506708af221a887326c2a9ca9625dc
+sdk.linux32_bundle_download=adt-bundle-linux-x86-20130219.zip
+sdk.linux32_bundle_bytes=418664018
+sdk.linux32_bundle_checksum=e56ebb5c8eb84eb3227cf7c255373f4b
-sdk.linux64_bundle_download=adt-bundle-linux-x86_64.zip
-sdk.linux64_bundle_bytes=418889835
-sdk.linux64_bundle_checksum=464c1fbe92ea293d6b2292c27af5066a
+sdk.linux64_bundle_download=adt-bundle-linux-x86_64-20130219.zip
+sdk.linux64_bundle_bytes=418939098
+sdk.linux64_bundle_checksum=90cb420934170787938d0477c1a83a7f
-sdk.mac64_bundle_download=adt-bundle-mac-x86_64.zip
-sdk.mac64_bundle_bytes=390649300
-sdk.mac64_bundle_checksum=f557bc61a4bff466633037839771bffb
+sdk.mac64_bundle_download=adt-bundle-mac-x86_64-20130219.zip
+sdk.mac64_bundle_bytes=390697025
+sdk.mac64_bundle_checksum=b768c28f380c1846479664c4790e9c53
-sdk.win32_bundle_download=adt-bundle-windows-x86.zip
-sdk.win32_bundle_bytes=425429957
-sdk.win32_bundle_checksum=cca97f12904774385a57d542e70a490f
+sdk.win32_bundle_download=adt-bundle-windows-x86-20130219.zip
+sdk.win32_bundle_bytes=425487608
+sdk.win32_bundle_checksum=4a40039f28048e6d7b2440adf55b8321
-sdk.win64_bundle_download=adt-bundle-windows-x86_64.zip
-sdk.win64_bundle_bytes=425553759
-sdk.win64_bundle_checksum=c51679f4517e1c3ddefa1e662bbf17f6
+sdk.win64_bundle_download=adt-bundle-windows-x86_64-20130219.zip
+sdk.win64_bundle_bytes=425611626
+sdk.win64_bundle_checksum=891f79816b4d19042faab26d670f4f77
diff --git a/docs/html/tools/extras/support-library.jd b/docs/html/tools/extras/support-library.jd
index 08ac172..6475e3c 100644
--- a/docs/html/tools/extras/support-library.jd
+++ b/docs/html/tools/extras/support-library.jd
@@ -46,10 +46,33 @@ by the directory name, such as {@code v4/} and {@code v13/}.</p>
<p>The sections below provide notes about successive releases of
the Support Package, as denoted by revision number.</p>
-
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" alt=""
+/>Support Package, revision 12</a> <em>(February 2013)</em>
+ </p>
+ <div class="toggle-content-toggleme">
+ <dl>
+ <dt>Changes for v4 support library:</dt>
+ <dd>
+ <ul>
+ <li>Improved interaction behavior for {@link android.support.v4.view.ViewPager}.</li>
+ <li>Fixed a bug that could cause {@link android.support.v4.view.ViewPager} to select the
+ wrong page.</li>
+ <li>Fixed use of {@link android.support.v4.view.ViewPager#removeView removeView()} method
+ during layout for {@link android.support.v4.view.ViewPager}.</li>
+ <li>Fixed issue with {@link android.support.v4.widget.SearchViewCompat} where using the
+ back button to dismiss does not clear the search text. This fix only applies to
+ host API levels 14 and higher.</li>
+ </ul>
+ </dd>
+ </dl>
+ </div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""
/>Support Package, revision 11</a> <em>(November 2012)</em>
</p>
<div class="toggle-content-toggleme">
@@ -119,7 +142,7 @@ the Support Package, as denoted by revision number.</p>
<dt>Changes for v4 support library:</dt>
<dd>
<ul>
- <li>Added support for notification features introduced in Android 4.1 (API Level 16) with
+ <li>Added support for notification features introduced in Android 4.1 (API level 16) with
additions to {@link android.support.v4.app.NotificationCompat}.</li>
</ul>
</dd>
@@ -210,7 +233,7 @@ isActiveNetworkMetered()} method.</li>
<li>Fixed intent flags for {@link android.app.PendingIntent} objects generated
by {@link android.support.v4.app.TaskStackBuilder}.</li>
<li>Removed unused attributes from the gridlayout library projects to make sure
- the library can be built with API Level 7 and higher.</li>
+ the library can be built with API level 7 and higher.</li>
<li>Added {@code .classpath} and {@code .project} files for the gridlayout
library project.</li>
</ul>
diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd
index c1bc185..31cec0e 100644
--- a/docs/html/tools/revisions/platforms.jd
+++ b/docs/html/tools/revisions/platforms.jd
@@ -44,11 +44,28 @@ version.</p>
SDK tools to revision 20 or later and restart the Android SDK Manager. If you do not,
the Android 4.2 system components will not be available for download.</p>
-
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png"
+class="toggle-content-img" alt="" />Revision 2</a> <em>(February 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <p>Maintenance update. The system version is 4.2.2.</p>
+ <dl>
+ <dt>Dependencies:</dt>
+ <dd>SDK Tools r21 or higher is required.</dd>
+ </dl>
+
+ </div>
+</div>
+
+<div class="toggle-content closed">
+
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png"
class="toggle-content-img" alt="" />Revision 1</a> <em>(November 2012)</em>
</p>
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index 4adb7b2..a3f53bb 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -69,7 +69,7 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues
<li>Java 1.6 or higher is required for ADT 21.1.0.</li>
<li>Eclipse Helios (Version 3.6.2) or higher is required for ADT 21.1.0.</li>
<li>ADT 21.1.0 is designed for use with <a href="{@docRoot}tools/sdk/tools-notes.html">SDK
- Tools r21.1.0</a>. If you haven't already installed SDK Tools r21.1.0 into your SDK, use the
+ Tools r21.1</a>. If you haven't already installed SDK Tools r21.1 into your SDK, use the
Android SDK Manager to do so.</li>
</ul>
</dd>
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index cb4954b..74caaf4 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -1,17 +1,29 @@
ndk=true
page.template=sdk
-ndk.win_download=android-ndk-r8d-windows.zip
-ndk.win_bytes=327014028
-ndk.win_checksum=d78ec3d4ec15ad3b18b9f488a5763c23
+ndk.mac64_download=android-ndk-r8e-darwin-x86_64.tar.bz2
+ndk.mac64_bytes=508419298
+ndk.mac64_checksum=efac96fab20e6ddb1311d6ba5648ce72
-ndk.mac_download=android-ndk-r8d-darwin-x86.tar.bz2
-ndk.mac_bytes=308328942
-ndk.mac_checksum=5cd9ef9fb7e03943ee8c9e147e42e571
+ndk.mac32_download=android-ndk-r8e-darwin-x86.tar.bz2
+ndk.mac32_bytes=496238878
+ndk.mac32_checksum=e17e707464c45c0d5615e4d0ae6a5cf7
-ndk.linux_download=android-ndk-r8d-linux-x86.tar.bz2
-ndk.linux_bytes=254644383
-ndk.linux_checksum=e1fa0379a3feb59f2f0865f1a90bd382
+ndk.linux64_download=android-ndk-r8e-linux-x86_64.tar.bz2
+ndk.linux64_bytes=466853553
+ndk.linux64_checksum=fa812352956067e7a9eefc0274675e9a
+
+ndk.linux32_download=android-ndk-r8e-linux-x86.tar.bz2
+ndk.linux32_bytes=461526099
+ndk.linux32_checksum=26d774b0884bcd98de08eb4de41ab532
+
+ndk.win64_download=android-ndk-r8e-windows-x86_64.zip
+ndk.win64_bytes=461298980
+ndk.win64_checksum=11eb99b3b56fc86d9d231ebff5c41db3
+
+ndk.win32_download=android-ndk-r8e-windows-x86.zip
+ndk.win32_bytes=434701805
+ndk.win32_checksum=fb41ed2bff5610b14a7b6f085ab86213
page.title=Android NDK
@jd:body
@@ -250,6 +262,222 @@ the NDK, as denoted by revision number. </p>
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt="">Android NDK, Revision 8e</a> <em>(March 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+ <dl>
+ <dt>Important changes:</dt>
+ <dd>
+ <ul>
+ <li>Added 64-bit host toolchain set (package name suffix {@code *-x86_64.*}). For more
+ information, see {@code CHANGES.HTML} and {@code NDK-BUILD.html}.</li>
+ <li>Added Clang 3.2 compiler. GCC 4.6 is still the default. For information on using the
+ Clang compiler, see {@code CHANGES.HTML}.</li>
+ <li>Added static code analyzer for Linux/MacOSX hosts. For information on using the
+ analyzer, see {@code CHANGES.HTML}.</li>
+ <li>Added MCLinker for Linux/MacOSX hosts as an experimental feature. The {@code ld.gold}
+ linker is the default where available, so you must explicitly enable it. For more
+ information, see {@code CHANGES.HTML}.</li>
+ <li>Updated ndk-build to use topological sort for module dependencies, which means the
+ build automatically sorts out the order of libraries specified in
+ {@code LOCAL_STATIC_LIBRARIES}, {@code LOCAL_WHOLE_STATIC_LIBRARIES} and
+ {@code LOCAL_SHARED_LIBRARIES}. For more information, see {@code CHANGES.HTML}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=39378">Issue 39378</a>)</li>
+ </ul>
+ </dd>
+
+ <dt>Important bug fixes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed build script to build all toolchains in {@code -O2}. Toolchains in previous
+ releases were incorrectly built without optimization.</li>
+ <li>Fixed build script which unconditionally builds Clang/llvm for MacOSX in 64-bit.</li>
+ <li>Fixed GCC 4.6/4.7 internal compiler error:
+ {@code gen_thumb_movhi_clobber at config/arm/arm.md:5832}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=52732">Issue 52732</a>)</li>
+ <li>Fixed build problem where GCC/ARM 4.6/4.7 fails to link code using 64-bit atomic
+ built-in functions.
+ (<a href="http://code.google.com/p/android/issues/detail?id=41297">Issue 41297</a>)</li>
+ <li>Fixed GCC 4.7 linker DIV usage mismatch errors.
+ (<a href="http://sourceware.org/ml/binutils/2012-12/msg00202.html">Sourceware Issue</a>)
+ <li>Fixed GCC 4.7 internal compiler error {@code build_data_member_initialization, at
+ cp/semantics.c:5790}.</li>
+ <li>Fixed GCC 4.7 internal compiler error {@code redirect_eh_edge_1, at tree-eh.c:2214}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=52909">Issue 52909</a>)</li>
+ <li>Fixed a GCC 4.7 segfault.
+ (<a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55245">GCC Issue</a>)</li>
+ <li>Fixed {@code &lt;chrono&gt;} clock resolution and enabled {@code steady_clock}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=39680">Issue 39680</a>)</li>
+ <li>Fixed toolchain to enable {@code _GLIBCXX_HAS_GTHREADS} for GCC 4.7 libstdc++.
+ (<a href="http://code.google.com/p/android/issues/detail?id=41770">Issue 41770</a>,
+ <a href="http://code.google.com/p/android/issues/detail?id=41859">Issue 41859</a>)</li>
+ <li>Fixed problem with the X86 MXX/SSE code failing to link due to missing
+ {@code posix_memalign}.
+ (<a href="https://android-review.googlesource.com/#/c/51872">Change 51872</a>)</li>
+ <li>Fixed GCC4.7/X86 segmentation fault in {@code i386.c}, function
+ {@code distance_non_agu_define_in_bb()}.
+ (<a href="https://android-review.googlesource.com/#/c/50383">Change 50383</a>)</li>
+ <li>Fixed GCC4.7/X86 to restore earlier {@code cmov} behavior.
+ (<a href="http://gcc.gnu.org/viewcvs?view=revision&revision=193554">GCC Issue</a>)</li>
+ <li>Fixed handling NULL return value of {@code setlocale()} in libstdc++/GCC4.7.
+ (<a href="http://code.google.com/p/android/issues/detail?id=46718">Issue 46718</a>)
+ <li>Fixed {@code ld.gold} runtime undefined reference to {@code __exidx_start} and
+ {@code __exidx_start_end}.
+ (<a href="https://android-review.googlesource.com/#/c/52134">Change 52134</a>)</li>
+ <li>Fixed Clang 3.1 internal compiler error when using Eigen library.
+ (<a href="http://code.google.com/p/android/issues/detail?id=41246">Issue 41246</a>)</li>
+ <li>Fixed Clang 3.1 internal compiler error including {@code &lt;chrono&gt;} in C++11 mode.
+ (<a href="http://code.google.com/p/android/issues/detail?id=39600">Issue 39600</a>)</li>
+ <li>Fixed Clang 3.1 internal compiler error when generating object code for a method
+ call to a uniform initialized {@code rvalue}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=41387">Issue 41387</a>)</li>
+ <li>Fixed Clang 3.1/X86 stack realignment.
+ (<a href="https://android-review.googlesource.com/#/c/52154">Change 52154</a>)</li>
+ <li>Fixed problem with GNU Debugger (GDB) SIGILL when debugging on Android 4.1.2.
+ (<a href="http://code.google.com/p/android/issues/detail?id=40941">Issue 40941</a>)</li>
+ <li>Fixed problem where GDB cannot set {@code source:line} breakpoints when symbols contain
+ long, indirect file paths.
+ (<a href="http://code.google.com/p/android/issues/detail?id=42448">Issue 42448</a>)</li>
+ <li>Fixed GDB {@code read_program_header} for MIPS PIE executables.
+ (<a href="https://android-review.googlesource.com/#/c/49592">Change 49592</a>)</li>
+ <li>Fixed {@code STLport} segmentation fault in {@code uncaught_exception()}.
+ (<a href="https://android-review.googlesource.com/#/c/50236">Change 50236</a>)</li>
+ <li>Fixed {@code STLport} bus error in exception handling due to unaligned access of
+ {@code DW_EH_PE_udata2}, {@code DW_EH_PE_udata4}, and {@code DW_EH_PE_udata8}.</li>
+ <li>Fixed Gabi++ infinite recursion problem with {@code nothrow new[]} operator.
+ (<a href="http://code.google.com/p/android/issues/detail?id=52833">Issue 52833</a>)</li>
+ <li>Fixed Gabi++ wrong offset to exception handler pointer.
+ (<a href="https://android-review.googlesource.com/#/c/53446">Change 53446</a>)</li>
+ <li>Removed Gabi++ redundant free on exception object
+ (<a href="https://android-review.googlesource.com/#/c/53447">Change 53447</a>)</li>
+ </ul>
+ </dd>
+
+ <dt>Other bug fixes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed NDK headers:
+ <ul>
+ <li>Removed redundant definitions of {@code size_t}, {@code ssize_t}, and
+ {@code ptrdiff_t}.</li>
+ <li>Fixed MIPS and ARM {@code fenv.h} header.</li>
+ <li>Fixed {@code stddef.h} to not redefine {@code offsetof} since it already exists
+ in the toolchain.</li>
+ <li>Fixed {@code elf.h} to contain {@code Elf32_auxv_t} and {@code Elf64_auxv_t}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=38441">Issue 38441</a>)
+ </li>
+ <li>Fixed the {@code #ifdef} C++ definitions in the
+ {@code OpenSLES_AndroidConfiguration.h} header file.
+ (<a href="http://code.google.com/p/android/issues/detail?id=53163">Issue 53163</a>)
+ </li>
+ </ul>
+ </li>
+ <li>Fixed {@code STLport} to abort after out of memory error instead of silently exiting.
+ </li>
+ <li>Fixed system and Gabi++ headers to be able to compile with API level 8 and lower.</li>
+ <li>Fixed {@code cpufeatures} to not parse {@code /proc/self/auxv}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=43055">Issue 43055</a>)</li>
+ <li>Fixed {@code ld.gold} to not depend on host libstdc++ and on Windows platforms,
+ to not depend on the {@code libgcc_sjlj_1.dll} library.</li>
+ <li>Fixed Clang 3.1 which emits inconsistent register list in {@code .vsave} and fails
+ assembler.
+ (<a href="https://android-review.googlesource.com/#/c/49930">Change 49930</a>)</li>
+ <li>Fixed Clang 3.1 to be able to compile libgabi++ and pass the {@code test-stlport}
+ tests for MIPS build targets.
+ (<a href="https://android-review.googlesource.com/#/c/51961">Change 51961</a>)</li>
+ <li>Fixed Clang 3.1 to only enable exception by default for C++, not for C.</li>
+ <li>Fixed several issues in Clang 3.1 to pass most GNU exception tests.</li>
+ <li>Fixed scripts {@code clang} and {@code clang++} in standalone NDK compiler to detect
+ {@code -cc1} and to not specify {@code -target} when found.</li>
+ <li>Fixed {@code ndk-build} to observe {@code NDK_APP_OUT} set in {@code Application.mk}.
+ </li>
+ <li>Fixed X86 {@code libc.so} and {@code lib.a} which were missing the {@code sigsetjmp}
+ and {@code siglongjmp} functions already declared in {@code setjmp.h}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=19851">Issue 19851</a>)</li>
+ <li>Patched GCC 4.4.3/4.6/4.7 libstdc++ to work with Clang in C++ 11.
+ (<a href="http://clang.llvm.org/cxx_status.html">Clang Issue</a>)</li>
+ <li>Fixed cygwin path in argument passed to {@code HOST_AWK}.</li>
+ <li>Fixed {@code ndk-build} script warning in windows when running from project's JNI
+ directory.
+ (<a href="http://code.google.com/p/android/issues/detail?id=40192">Issue 40192</a>)</li>
+ <li>Fixed problem where the {@code ndk-build} script does not build if makefile has
+ trailing whitespace in the {@code LOCAL_PATH} definition.
+ (<a href="http://code.google.com/p/android/issues/detail?id=42841">Issue 42841</a>)</li>
+ </ul>
+ </dd>
+
+ <dt>Other changes:</dt>
+ <dd>
+ <ul>
+ <li>Enabled threading support in GCC/MIPS toolchain.</li>
+ <li>Updated GCC exception handling helpers {@code __cxa_begin_cleanup} and
+ {@code __cxa_type_match} to have <em>default</em> visibility from the previous
+ <em>hidden</em> visibility in GNU libstdc++. For more information, see
+ {@code CHANGES.HTML}.</li>
+ <li>Updated build scripts so that Gabi++ and STLport static libraries are now built with
+ hidden visibility except for exception handling helpers.</li>
+ <li>Updated build so that {@code STLport} is built for ARM in Thumb mode.</li>
+ <li>Added support for {@code std::set_new_handler} in Gabi++.
+ (<a href="http://code.google.com/p/android/issues/detail?id=52805">Issue 52805</a>)</li>
+ <li>Enabled {@code FUTEX} system call in GNU libstdc++.</li>
+ <li>Updated {@code ndk-build} so that it no longer copies prebuilt static library to
+ a project's {@code obj/local/&lt;abi&gt;/} directory.
+ (<a href="http://code.google.com/p/android/issues/detail?id=40302">Issue 40302</a>)</li>
+ <li>Removed {@code __ARM_ARCH_5*__} from ARM {@code toolchains/*/setup.mk} script.
+ (<a href="http://code.google.com/p/android/issues/detail?id=21132">Issue 21132</a>)</li>
+ <li>Built additional GNU libstdc++ libraries in thumb for ARM.</li>
+ <li>Enabled MIPS floating-point {@code madd/msub/nmadd/nmsub/recip/rsqrt}
+ instructions with 32-bit FPU.</li>
+ <li>Enabled graphite loop optimizer in GCC 4.6 and 4.7 to allow more optimizations:
+ {@code -fgraphite}, {@code -fgraphite-identity}, {@code -floop-block}, {@code -floop-flatten},
+ {@code -floop-interchange}, {@code -floop-strip-mine}, {@code -floop-parallelize-all},
+ and {@code -ftree-loop-linear}.
+ (<a href="http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html">info</a>)</li>
+ <li>Enabled {@code polly} for Clang 3.1 on Linux and Max OS X 32-bit hosts which analyzes
+ and optimizes memory access. (<a href="http://polly.llvm.org">info</a>)</li>
+ <li>Enabled {@code -flto} in GCC 4.7, 4.6, Clang 3.2 and Clang 3.1 on linux (Clang LTO
+ via LLVMgold.so). MIPS compiler targets are not supported because {@code ld.gold}
+ is not available.</li>
+ <li>Enabled {@code --plugin} and {@code --plugin-opt} for {@code ld.gold} in GCC 4.6/4.7.
+ </li>
+ <li>Enabled {@code --text-reorder} for {@code ld.gold} in GCC 4.7.</li>
+ <li>Configured GNU libstdc++ with {@code _GLIBCXX_USE_C99_MATH} which undefines the
+ {@code isinf} script in the bionic header. For more information, see
+ {@code CHANGES.html}.</li>
+ <li>Added {@code APP_LDFLAGS} to the build scripts. For more information, see
+ {@code ANDROID-MK.html}.</li>
+ <li>Updated build scripts to allow {@code NDK_LOG=0} to disable the {@code NDK_LOG}.</li>
+ <li>Updated build scripts to allow {@code NDK_HOST_32BIT=0} to disable the host developer
+ environment 32-bit toolchain.</li>
+ <li>Changed the default GCC/X86 flags {@code -march=} and {@code -mtune=} from
+ {@code pentiumpro} and {@code generic} to {@code i686} and {@code atom}.</li>
+ <li>Enhanced toolchain build scripts:
+ <ul>
+ <li>Fixed a race condition in {@code build-gcc.sh} for the {@code mingw} build type
+ which was preventing a significant amount of parallel build processing.</li>
+ <li>Updated {@code build-gabi++.sh} and {@code build-stlport.sh} so they can now run
+ from the NDK package.
+ (<a href="http://code.google.com/p/android/issues/detail?id=52835">Issue 52835</a>)
+ </li>
+ <li>Fixed {@code run-tests.sh} in the {@code MSys} utilities collection.</li>
+ <li>Improved 64-bit host toolchain and Canadian Cross build support.</li>
+ <li>Updated {@code build-mingw64-toolchain.sh} script to more recent version.</li>
+ <li>Added option to build {@code libgnustl_static.a} and {@code stlport_static.a}
+ without hidden visibility.</li>
+ </ul>
+ </li>
+ </ul>
+
+ </dd>
+ </dl>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt="">Android NDK, Revision 8d</a> <em>(December 2012)</em>
</p>
@@ -769,7 +997,7 @@ MIPS.</li>
<dd>
<ul>
<li>Added GCC 4.6 toolchain ({@code binutils} 2.21 with {@code gold} and GDB 7.3.x) to
-co-exist with the original GCC 4.4.3 toolchain ({@code binutils} 2.19 and GDB 6.6).</p>
+co-exist with the original GCC 4.4.3 toolchain ({@code binutils} 2.19 and GDB 6.6).
<ul>
<li>GCC 4.6 is now the default toolchain. You may set {@code
NDK_TOOLCHAIN_VERSION=4.4.3} in {@code Application.mk} to select the original one.</li>
@@ -816,8 +1044,9 @@ assembler and {@code -z execstack} for the linker.</li>
following options:
<pre>
LOCAL_DISABLE_NO_EXECUTE=true # disable "--noexecstack" and "-z noexecstack"
-DISABLE_RELRO=true # disable "-z relro" and "-z now"</li>
+DISABLE_RELRO=true # disable "-z relro" and "-z now"
</pre>
+ </li>
</ol>
<p>See {@code docs/ANDROID-MK.html} for more details.</p>
</li>
@@ -826,7 +1055,7 @@ DISABLE_RELRO=true # disable "-z relro" and "-z now"</li>
<li>Added branding for Android executables with the {@code .note.ABI-tag} section (in
{@code crtbegin_static/dynamic.o}) so that debugging tools can act accordingly. The structure
-member and values are defined as follows:</p>
+member and values are defined as follows:
<pre>
static const struct {
int32_t namesz; /* = 4, sizeof ("GNU") */
@@ -1621,10 +1850,11 @@ float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event,
<li>Fixed a bug that caused the build to fail if <code>LOCAL_ARM_NEON</code> was set to
true (typo in <code>build/core/build-binary.mk</code>).</li>
- <li>Fixed a bug that prevented the compilation of </code>.s</code> assembly files
+ <li>Fixed a bug that prevented the compilation of <code>.s</code> assembly files
(<code>.S</code> files were okay).</li>
</ul>
</dd>
+ </dl>
</div>
</div>
diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd
index a5b7eee..7d121844 100644
--- a/docs/html/tools/sdk/tools-notes.jd
+++ b/docs/html/tools/sdk/tools-notes.jd
@@ -28,7 +28,7 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
- alt=""/>SDK Tools, Revision 21.1.0</a> <em>(February 2013)</em>
+ alt=""/>SDK Tools, Revision 21.1</a> <em>(February 2013)</em>
</p>
<div class="toggle-content-toggleme">
@@ -38,7 +38,7 @@ href="http://tools.android.com/knownissues">http://tools.android.com/knownissues
<dd>
<ul>
<li>Android SDK Platform-tools revision 16 or later.</li>
- <li>If you are developing in Eclipse with ADT, note that the SDK Tools r21.1.0 is
+ <li>If you are developing in Eclipse with ADT, note that the SDK Tools r21.1 is
designed for use with ADT 21.1.0 and later. If you haven't already, update your
<a href="{@docRoot}tools/sdk/eclipse-adt.html">ADT Plugin</a> to 21.1.0.</li>
<li>If you are developing outside Eclipse, you must have
diff --git a/docs/html/training/animation/index.jd b/docs/html/training/animation/index.jd
index 9cc7e6c..b2815fc 100644
--- a/docs/html/training/animation/index.jd
+++ b/docs/html/training/animation/index.jd
@@ -1,4 +1,5 @@
page.title=Adding Animations
+page.tags="animation","views","layout","user interface"
trainingnavtop=true
startpage=true
diff --git a/docs/html/training/basics/data-storage/databases.jd b/docs/html/training/basics/data-storage/databases.jd
index 8b11983..9976bb1 100644
--- a/docs/html/training/basics/data-storage/databases.jd
+++ b/docs/html/training/basics/data-storage/databases.jd
@@ -1,6 +1,4 @@
page.title=Saving Data in SQL Databases
-parent.title=Data Storage
-parent.link=index.html
trainingnavtop=true
previous.title=Saving Data in Files
diff --git a/docs/html/training/basics/data-storage/files.jd b/docs/html/training/basics/data-storage/files.jd
index dd081a6..52bea4c 100644
--- a/docs/html/training/basics/data-storage/files.jd
+++ b/docs/html/training/basics/data-storage/files.jd
@@ -1,6 +1,4 @@
page.title=Saving Files
-parent.title=Data Storage
-parent.link=index.html
trainingnavtop=true
diff --git a/docs/html/training/basics/data-storage/index.jd b/docs/html/training/basics/data-storage/index.jd
index 4334936..4ccad75 100644
--- a/docs/html/training/basics/data-storage/index.jd
+++ b/docs/html/training/basics/data-storage/index.jd
@@ -1,4 +1,5 @@
page.title=Saving Data
+page.tags="data storage","files","sql","database","preferences"
trainingnavtop=true
startpage=true
diff --git a/docs/html/training/basics/data-storage/shared-preferences.jd b/docs/html/training/basics/data-storage/shared-preferences.jd
index 099da67..a6717c4 100644
--- a/docs/html/training/basics/data-storage/shared-preferences.jd
+++ b/docs/html/training/basics/data-storage/shared-preferences.jd
@@ -1,6 +1,4 @@
page.title=Saving Key-Value Sets
-parent.title=Data Storage
-parent.link=index.html
trainingnavtop=true
diff --git a/docs/html/training/basics/fragments/communicating.jd b/docs/html/training/basics/fragments/communicating.jd
index eb9b368..b30045d 100644
--- a/docs/html/training/basics/fragments/communicating.jd
+++ b/docs/html/training/basics/fragments/communicating.jd
@@ -1,10 +1,6 @@
page.title=Communicating with Other Fragments
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
trainingnavtop=true
-previous.title=Building a Flexible UI
-previous.link=fragment-ui.html
@jd:body
diff --git a/docs/html/training/basics/fragments/creating.jd b/docs/html/training/basics/fragments/creating.jd
index 0646230..b5df4e1 100644
--- a/docs/html/training/basics/fragments/creating.jd
+++ b/docs/html/training/basics/fragments/creating.jd
@@ -1,12 +1,6 @@
page.title=Creating a Fragment
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
trainingnavtop=true
-previous.title=Using the Android Support Library
-previous.link=support-lib.html
-next.title=Building a Flexible UI
-next.link=fragment-ui.html
@jd:body
diff --git a/docs/html/training/basics/fragments/fragment-ui.jd b/docs/html/training/basics/fragments/fragment-ui.jd
index 4ec4de5..d648938 100644
--- a/docs/html/training/basics/fragments/fragment-ui.jd
+++ b/docs/html/training/basics/fragments/fragment-ui.jd
@@ -1,12 +1,6 @@
page.title=Building a Flexible UI
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
trainingnavtop=true
-previous.title=Create a Fragment
-previous.link=creating.html
-next.title=Communicating with Other Fragments
-next.link=communicating.html
@jd:body
diff --git a/docs/html/training/basics/fragments/index.jd b/docs/html/training/basics/fragments/index.jd
index bc93f43..1b82f2c 100644
--- a/docs/html/training/basics/fragments/index.jd
+++ b/docs/html/training/basics/fragments/index.jd
@@ -1,9 +1,8 @@
page.title=Building a Dynamic UI with Fragments
+page.tags="fragments", "user interface", "support library"
trainingnavtop=true
startpage=true
-next.title=Using the Android Support Library
-next.link=support-lib.html
@jd:body
diff --git a/docs/html/training/basics/fragments/support-lib.jd b/docs/html/training/basics/fragments/support-lib.jd
index cc867d3..b097de1 100644
--- a/docs/html/training/basics/fragments/support-lib.jd
+++ b/docs/html/training/basics/fragments/support-lib.jd
@@ -1,10 +1,7 @@
page.title=Using the Support Library
-parent.title=Building a Dynamic UI with Fragments
-parent.link=index.html
+page.tags="support library"
trainingnavtop=true
-next.title=Creating a Fragment
-next.link=creating.html
@jd:body
diff --git a/docs/html/training/basics/intents/index.jd b/docs/html/training/basics/intents/index.jd
index d94ff01..8876a33 100644
--- a/docs/html/training/basics/intents/index.jd
+++ b/docs/html/training/basics/intents/index.jd
@@ -1,9 +1,8 @@
page.title=Interacting with Other Apps
+page.tags="intents","activity"
trainingnavtop=true
startpage=true
-next.title=Sending the User to Another App
-next.link=sending.html
@jd:body
diff --git a/docs/html/training/basics/network-ops/index.jd b/docs/html/training/basics/network-ops/index.jd
index b213c03..cb3a390 100644
--- a/docs/html/training/basics/network-ops/index.jd
+++ b/docs/html/training/basics/network-ops/index.jd
@@ -1,4 +1,5 @@
page.title=Performing Network Operations
+page.tags="network","wireless"
trainingnavtop=true
startpage=true
diff --git a/docs/html/training/basics/supporting-devices/index.jd b/docs/html/training/basics/supporting-devices/index.jd
index 49ea81d..1e3eb42 100644
--- a/docs/html/training/basics/supporting-devices/index.jd
+++ b/docs/html/training/basics/supporting-devices/index.jd
@@ -1,9 +1,8 @@
page.title=Supporting Different Devices
+page.tags="resources","screens","versions","localization"
trainingnavtop=true
startpage=true
-next.title=Supporting Multiple Languages
-next.link=languages.html
@jd:body
diff --git a/docs/html/training/camera/index.jd b/docs/html/training/camera/index.jd
index 282bed8..fa754a0 100644
--- a/docs/html/training/camera/index.jd
+++ b/docs/html/training/camera/index.jd
@@ -1,4 +1,5 @@
page.title=Capturing Photos
+page.tags="camera","video"
trainingnavtop=true
startpage=true
diff --git a/docs/html/training/cloudsync/index.jd b/docs/html/training/cloudsync/index.jd
index 91885e8..55b275b 100644
--- a/docs/html/training/cloudsync/index.jd
+++ b/docs/html/training/cloudsync/index.jd
@@ -1,9 +1,8 @@
page.title=Syncing to the Cloud
+page.tags="cloud","sync","backup"
trainingnavtop=true
startpage=true
-next.title=Making the Most of Google Cloud Messaging
-next.link=gcm.html
@jd:body
diff --git a/docs/html/training/connect-devices-wirelessly/index.jd b/docs/html/training/connect-devices-wirelessly/index.jd
index 37cf633..f27b9c3 100644
--- a/docs/html/training/connect-devices-wirelessly/index.jd
+++ b/docs/html/training/connect-devices-wirelessly/index.jd
@@ -1,9 +1,8 @@
page.title=Connecting Devices Wirelessly
+page.tags="wifi","network","wireless"
trainingnavtop=true
startpage=true
-next.title=Using Network Service Discovery
-next.link=nsd.html
@jd:body
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>&lt;QuickContactBadge&gt;</code> element in your layout. For example:
+</p>
+<pre>
+&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"&gt;
+...
+ &lt;QuickContactBadge
+ android:id=&#64;+id/quickbadge
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"/&gt;
+ ...
+&lt;/RelativeLayout&gt;
+</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 &gt;= Honeycomb
+ */
+ if (Build.VERSION.SDK_INT &gt;= 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
+ &gt;=
+ 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>
+&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"&gt;
+ &lt;QuickContactBadge
+ android:id="&#64;+id/quickcontact"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="centerCrop"/&gt;
+ &lt;TextView android:id="&#64;+id/displayname"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="&#64;+id/quickcontact"
+ android:gravity="center_vertical"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"/&gt;
+&lt;/RelativeLayout&gt;
+</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;
+ }
+ ..
+ &#64;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;
+ }
+ ...
+ &#64;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&lt;Cursor&gt; {
+...
+ // 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 &gt;=
+ Build.VERSION_CODES.HONEYCOMB) ?
+ Contacts.DISPLAY_NAME_PRIMARY :
+ Contacts.DISPLAY_NAME
+ (Build.VERSION.SDK_INT &gt;=
+ 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 &gt;= 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>
+ &#64;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>
+ &#64;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&lt;Cursor&gt; 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>
+ &#64;Override
+ public void onLoaderReset(Loader&lt;Cursor&gt; 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">
+ &lt;manifest&gt;</a></code> to your manifest file:
+</p>
+<pre>
+ &lt;uses-permission android:name="android.permission.READ_CONTACTS" /&gt;
+</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&lt;Cursor&gt; {
+ ...
+ // 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.
+ */
+ &#64;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>
+ &#64;Override
+ public Loader&lt;Cursor&gt; 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&lt;Cursor&gt; 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>
+ &#64;Override
+ public void onLoaderReset(Loader&lt;Cursor&gt; 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">&lt;uses-permission&gt;</a></code>
+ element to your manifest file as a child element of
+<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>:
+</p>
+<pre>
+ &lt;uses-permission android:name="android.permission.READ_CONTACTS" /&gt;
+</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>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="&#64;android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/&gt;
+</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>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="&#64;android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clickable="true"/&gt;
+</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&lt;Cursor&gt;,
+ 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.
+ */
+ &#64;SuppressLint("InlinedApi")
+ private final static String[] FROM_COLUMNS = {
+ Build.VERSION.SDK_INT
+ &gt;= 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
+ &#64;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>
+...
+&#64;SuppressLint("InlinedApi")
+private static final String[] PROJECTION =
+ {
+ Contacts._ID,
+ Contacts.LOOKUP_KEY,
+ Build.VERSION.SDK_INT
+ &gt;= 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
+ &#64;SuppressLint("InlinedApi")
+ private static final String SELECTION =
+ Build.VERSION.SDK_INT &gt;= 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>
+ &#64;Override
+ public void onItemClick(
+ AdapterView&lt;?&gt; 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&lt;Cursor&gt; {
+ ...
+ // Called just before the Fragment displays its UI
+ &#64;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>
+ ...
+ &#64;Override
+ public Loader&lt;Cursor&gt; 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&lt;Cursor&gt; 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>
+ &#64;Override
+ public void onLoaderReset(Loader&lt;Cursor&gt; 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>
+ &#64;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 &gt;= 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>
+ &#64;Override
+ public Loader&lt;Cursor&gt; 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>
+ &#64;Override
+ public Loader&lt;Cursor&gt; 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/displaying-bitmaps/cache-bitmap.jd b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
index 417ec5b..b1608c3 100644
--- a/docs/html/training/displaying-bitmaps/cache-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
@@ -3,10 +3,6 @@ parent.title=Displaying Bitmaps Efficiently
parent.link=index.html
trainingnavtop=true
-next.title=Displaying Bitmaps in Your UI
-next.link=display-bitmap.html
-previous.title=Processing Bitmaps Off the UI Thread
-previous.link=process-bitmap.html
@jd:body
diff --git a/docs/html/training/displaying-bitmaps/display-bitmap.jd b/docs/html/training/displaying-bitmaps/display-bitmap.jd
index 4572c42..ed1836c 100644
--- a/docs/html/training/displaying-bitmaps/display-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/display-bitmap.jd
@@ -3,8 +3,6 @@ parent.title=Displaying Bitmaps Efficiently
parent.link=index.html
trainingnavtop=true
-previous.title=Caching Bitmaps
-previous.link=cache-bitmap.html
@jd:body
diff --git a/docs/html/training/displaying-bitmaps/index.jd b/docs/html/training/displaying-bitmaps/index.jd
index b91172b..857edee 100644
--- a/docs/html/training/displaying-bitmaps/index.jd
+++ b/docs/html/training/displaying-bitmaps/index.jd
@@ -1,9 +1,8 @@
page.title=Displaying Bitmaps Efficiently
+page.tags="bitmaps","images","graphics"
trainingnavtop=true
startpage=true
-next.title=Loading Large Bitmaps Efficiently
-next.link=load-bitmap.html
@jd:body
@@ -26,7 +25,7 @@ next.link=load-bitmap.html
</div>
</div>
-<p>This class covers some common techniques for processing and loading {@link
+<p>Learn how to use common techniques to process and load {@link
android.graphics.Bitmap} objects in a way that keeps your user interface (UI) components responsive
and avoids exceeding your application memory limit. If you're not careful, bitmaps can quickly
consume your available memory budget leading to an application crash due to the dreaded
@@ -70,6 +69,9 @@ exception:<br />{@code java.lang.OutofMemoryError: bitmap size exceeds VM budget
<dd>This lesson walks you through using a memory and disk bitmap cache to improve the
responsiveness and fluidity of your UI when loading multiple bitmaps.</dd>
+ <dt><b><a href="manage-memory.html">Managing Bitmap Memory</a></b></dt>
+ <dd>This lesson explains how to manage bitmap memory to maximize your app's performance.</dd>
+
<dt><b><a href="display-bitmap.html">Displaying Bitmaps in Your UI</a></b></dt>
<dd>This lesson brings everything together, showing you how to load multiple bitmaps into
components like {@link android.support.v4.view.ViewPager} and {@link android.widget.GridView}
diff --git a/docs/html/training/displaying-bitmaps/load-bitmap.jd b/docs/html/training/displaying-bitmaps/load-bitmap.jd
index 283f272..633ffd2 100644
--- a/docs/html/training/displaying-bitmaps/load-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/load-bitmap.jd
@@ -3,8 +3,6 @@ parent.title=Displaying Bitmaps Efficiently
parent.link=index.html
trainingnavtop=true
-next.title=Processing Bitmaps Off the UI Thread
-next.link=process-bitmap.html
@jd:body
@@ -167,4 +165,4 @@ mImageView.setImageBitmap(
<p>You can follow a similar process to decode bitmaps from other sources, by substituting the
appropriate {@link
android.graphics.BitmapFactory#decodeByteArray(byte[],int,int,android.graphics.BitmapFactory.Options)
-BitmapFactory.decode*} method as needed.</p> \ No newline at end of file
+BitmapFactory.decode*} method as needed.</p>
diff --git a/docs/html/training/displaying-bitmaps/manage-memory.jd b/docs/html/training/displaying-bitmaps/manage-memory.jd
new file mode 100644
index 0000000..60ac2e6
--- /dev/null
+++ b/docs/html/training/displaying-bitmaps/manage-memory.jd
@@ -0,0 +1,297 @@
+page.title=Managing Bitmap Memory
+parent.title=Displaying Bitmaps Efficiently
+parent.link=index.html
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#recycle">Manage Memory on Android 2.3.3 and Lower</a></li>
+ <li><a href="#inBitmap">Manage Memory on Android 3.0 and Higher</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+ <li><a href="http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html">Memory Analysis for Android Applications</a> blog post</li>
+ <li><a href="http://www.google.com/events/io/2011/sessions/memory-management-for-android-apps.html">Memory management for Android Apps</a> Google I/O presentation</li>
+ <li><a href="{@docRoot}design/patterns/swipe-views.html">Android Design: Swipe Views</a></li>
+ <li><a href="{@docRoot}design/building-blocks/grid-lists.html">Android Design: Grid Lists</a></li>
+</ul>
+
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/BitmapFun.zip" class="button">Download the sample</a>
+ <p class="filename">BitmapFun.zip</p>
+</div>
+
+</div>
+</div>
+
+<p>In addition to the steps described in <a href="cache-bitmap.html">Caching Bitmaps</a>,
+there are specific things you can do to facilitate garbage collection
+and bitmap reuse. The recommended strategy depends on which version(s)
+of Android you are targeting. The {@code BitmapFun} sample app included with
+this class shows you how to design your app to work efficiently across
+different versions of Android.</p>
+
+<p>To set the stage for this lesson, here is how Android's management of
+bitmap memory has evolved:</p>
+<ul>
+ <li>
+On Android Android 2.2 (API level 8) and lower, when garbage
+collection occurs, your app's threads get stopped. This causes a lag that
+can degrade performance.
+<strong>Android 2.3 adds concurrent garbage collection, which means that
+the memory is reclaimed soon after a bitmap is no longer referenced.</strong>
+</li>
+
+ <li>On Android 2.3.3 (API level 10) and lower, the backing pixel data for a
+bitmap is stored in native memory. It is separate from the bitmap itself,
+which is stored in the Dalvik heap. The pixel data in native memory is
+not released in a predictable manner, potentially causing an application
+to briefly exceed its memory limits and crash.
+<strong>As of Android 3.0 (API Level 11), the pixel data is stored on the
+Dalvik heap along with the associated bitmap.</strong></li>
+
+</ul>
+
+<p>The following sections describe how to optimize bitmap memory
+management for different Android versions.</p>
+
+<h2 id="recycle">Manage Memory on Android 2.3.3 and Lower</h2>
+
+<p>On Android 2.3.3 (API level 10) and lower, using
+{@link android.graphics.Bitmap#recycle recycle()}
+is recommended. If you're displaying large amounts of bitmap data in your app,
+you're likely to run into
+{@link java.lang.OutOfMemoryError} errors. The
+{@link android.graphics.Bitmap#recycle recycle()} method allows an app
+to reclaim memory as soon as possible.</p>
+
+<p class="note"><strong>Caution:</strong> You should use
+{@link android.graphics.Bitmap#recycle recycle()} only when you are sure that the
+bitmap is no longer being used. If you call {@link android.graphics.Bitmap#recycle recycle()}
+and later attempt to draw the bitmap, you will get the error:
+{@code &quot;Canvas: trying to use a recycled bitmap&quot;}.</p>
+
+<p>The following code snippet gives an example of calling
+{@link android.graphics.Bitmap#recycle recycle()}. It uses reference counting
+(in the variables {@code mDisplayRefCount} and {@code mCacheRefCount}) to track
+whether a bitmap is currently being displayed or in the cache. The
+code recycles the bitmap when these conditions are met:</p>
+
+<ul>
+<li>The reference count for both {@code mDisplayRefCount} and
+{@code mCacheRefCount} is 0.</li>
+<li>The bitmap is not {@code null}, and it hasn't been recycled yet.</li>
+</ul>
+
+<pre>private int mCacheRefCount = 0;
+private int mDisplayRefCount = 0;
+...
+// Notify the drawable that the displayed state has changed.
+// Keep a count to determine when the drawable is no longer displayed.
+public void setIsDisplayed(boolean isDisplayed) {
+ synchronized (this) {
+ if (isDisplayed) {
+ mDisplayRefCount++;
+ mHasBeenDisplayed = true;
+ } else {
+ mDisplayRefCount--;
+ }
+ }
+ // Check to see if recycle() can be called.
+ checkState();
+}
+
+// Notify the drawable that the cache state has changed.
+// Keep a count to determine when the drawable is no longer being cached.
+public void setIsCached(boolean isCached) {
+ synchronized (this) {
+ if (isCached) {
+ mCacheRefCount++;
+ } else {
+ mCacheRefCount--;
+ }
+ }
+ // Check to see if recycle() can be called.
+ checkState();
+}
+
+private synchronized void checkState() {
+ // If the drawable cache and display ref counts = 0, and this drawable
+ // has been displayed, then recycle.
+ if (mCacheRefCount <= 0 && mDisplayRefCount <= 0 && mHasBeenDisplayed
+ && hasValidBitmap()) {
+ getBitmap().recycle();
+ }
+}
+
+private synchronized boolean hasValidBitmap() {
+ Bitmap bitmap = getBitmap();
+ return bitmap != null && !bitmap.isRecycled();
+}</pre>
+
+<h2 id="inBitmap">Manage Memory on Android 3.0 and Higher</h2>
+
+<p>Android 3.0 (API Level 11) introduces the
+{@link android.graphics.BitmapFactory.Options#inBitmap BitmapFactory.Options.inBitmap}
+field. If this option is set, decode methods that take the
+{@link android.graphics.BitmapFactory.Options Options} object
+will attempt to reuse an existing bitmap when loading content. This means
+that the bitmap's memory is reused, resulting in improved performance, and
+removing both memory allocation and de-allocation. There are some caveats in using
+{@link android.graphics.BitmapFactory.Options#inBitmap}:</p>
+<ul>
+ <li>The reused bitmap must be of the same size as the source content (to make
+sure that the same amount of memory is used), and in JPEG or PNG format
+(whether as a resource or as a stream).</li>
+
+
+<li>The {@link android.graphics.Bitmap.Config configuration} of the reused bitmap
+overrides the setting of
+{@link android.graphics.BitmapFactory.Options#inPreferredConfig}, if set. </li>
+
+ <li>You should always use the returned bitmap of the decode method,
+because you can't assume that reusing the bitmap worked (for example, if there is
+a size mismatch).</li>
+
+<h3>Save a bitmap for later use</h3>
+
+<p>The following snippet demonstrates how an existing bitmap is stored for possible
+later use in the sample app. When an app is running on Android 3.0 or higher and
+a bitmap is evicted from the {@link android.util.LruCache},
+a soft reference to the bitmap is placed
+in a {@link java.util.HashSet}, for possible reuse later with
+{@link android.graphics.BitmapFactory.Options#inBitmap}:
+
+<pre>HashSet&lt;SoftReference&lt;Bitmap&gt;&gt; mReusableBitmaps;
+private LruCache&lt;String, BitmapDrawable&gt; mMemoryCache;
+
+// If you're running on Honeycomb or newer, create
+// a HashSet of references to reusable bitmaps.
+if (Utils.hasHoneycomb()) {
+ mReusableBitmaps = new HashSet&lt;SoftReference&lt;Bitmap&gt;&gt;();
+}
+
+mMemoryCache = new LruCache&lt;String, BitmapDrawable&gt;(mCacheParams.memCacheSize) {
+
+ // Notify the removed entry that is no longer being cached.
+ &#64;Override
+ protected void entryRemoved(boolean evicted, String key,
+ BitmapDrawable oldValue, BitmapDrawable newValue) {
+ if (RecyclingBitmapDrawable.class.isInstance(oldValue)) {
+ // The removed entry is a recycling drawable, so notify it
+ // that it has been removed from the memory cache.
+ ((RecyclingBitmapDrawable) oldValue).setIsCached(false);
+ } else {
+ // The removed entry is a standard BitmapDrawable.
+ if (Utils.hasHoneycomb()) {
+ // We're running on Honeycomb or later, so add the bitmap
+ // to a SoftReference set for possible use with inBitmap later.
+ mReusableBitmaps.add
+ (new SoftReference&lt;Bitmap&gt;(oldValue.getBitmap()));
+ }
+ }
+ }
+....
+}</pre>
+
+
+<h3>Use an existing bitmap</h3>
+<p>In the running app, decoder methods check to see if there is an existing
+bitmap they can use. For example:</p>
+
+<pre>public static Bitmap decodeSampledBitmapFromFile(String filename,
+ int reqWidth, int reqHeight, ImageCache cache) {
+
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ ...
+ BitmapFactory.decodeFile(filename, options);
+ ...
+
+ // If we're running on Honeycomb or newer, try to use inBitmap.
+ if (Utils.hasHoneycomb()) {
+ addInBitmapOptions(options, cache);
+ }
+ ...
+ return BitmapFactory.decodeFile(filename, options);
+}</pre
+
+<p>The next snippet shows the {@code addInBitmapOptions()} method that is called in the
+above snippet. It looks for an existing bitmap to set as the value for
+{@link android.graphics.BitmapFactory.Options#inBitmap}. Note that this
+method only sets a value for {@link android.graphics.BitmapFactory.Options#inBitmap}
+if it finds a suitable match (your code should never assume that a match will be found):</p>
+
+<pre>private static void addInBitmapOptions(BitmapFactory.Options options,
+ ImageCache cache) {
+ // inBitmap only works with mutable bitmaps, so force the decoder to
+ // return mutable bitmaps.
+ options.inMutable = true;
+
+ if (cache != null) {
+ // Try to find a bitmap to use for inBitmap.
+ Bitmap inBitmap = cache.getBitmapFromReusableSet(options);
+
+ if (inBitmap != null) {
+ // If a suitable bitmap has been found, set it as the value of
+ // inBitmap.
+ options.inBitmap = inBitmap;
+ }
+ }
+}
+
+// This method iterates through the reusable bitmaps, looking for one
+// to use for inBitmap:
+protected Bitmap getBitmapFromReusableSet(BitmapFactory.Options options) {
+ Bitmap bitmap = null;
+
+ if (mReusableBitmaps != null && !mReusableBitmaps.isEmpty()) {
+ final Iterator&lt;SoftReference&lt;Bitmap&gt;&gt; iterator
+ = mReusableBitmaps.iterator();
+ Bitmap item;
+
+ while (iterator.hasNext()) {
+ item = iterator.next().get();
+
+ if (null != item && item.isMutable()) {
+ // Check to see it the item can be used for inBitmap.
+ if (canUseForInBitmap(item, options)) {
+ bitmap = item;
+
+ // Remove from reusable set so it can't be used again.
+ iterator.remove();
+ break;
+ }
+ } else {
+ // Remove from the set if the reference has been cleared.
+ iterator.remove();
+ }
+ }
+ }
+ return bitmap;
+}</pre>
+
+<p>Finally, this method determines whether a candidate bitmap
+satisfies the size criteria to be used for
+{@link android.graphics.BitmapFactory.Options#inBitmap}:</p>
+
+<pre>private static boolean canUseForInBitmap(
+ Bitmap candidate, BitmapFactory.Options targetOptions) {
+ int width = targetOptions.outWidth / targetOptions.inSampleSize;
+ int height = targetOptions.outHeight / targetOptions.inSampleSize;
+
+ // Returns true if "candidate" can be used for inBitmap re-use with
+ // "targetOptions".
+ return candidate.getWidth() == width && candidate.getHeight() == height;
+}</pre>
+
+</body>
+</html>
diff --git a/docs/html/training/displaying-bitmaps/process-bitmap.jd b/docs/html/training/displaying-bitmaps/process-bitmap.jd
index d4fcff3..272b8bc 100644
--- a/docs/html/training/displaying-bitmaps/process-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/process-bitmap.jd
@@ -3,10 +3,6 @@ parent.title=Displaying Bitmaps Efficiently
parent.link=index.html
trainingnavtop=true
-next.title=Caching Bitmaps
-next.link=cache-bitmap.html
-previous.title=Loading Large Bitmaps Efficiently
-previous.link=load-bitmap.html
@jd:body
diff --git a/docs/html/training/efficient-downloads/index.jd b/docs/html/training/efficient-downloads/index.jd
index a29be91..2ab93ae 100644
--- a/docs/html/training/efficient-downloads/index.jd
+++ b/docs/html/training/efficient-downloads/index.jd
@@ -1,9 +1,8 @@
page.title=Transferring Data Without Draining the Battery
+page.tags="battery","network","wireless"
trainingnavtop=true
startpage=true
-next.title=Optimizing Downloads for Efficient Network Access
-next.link=efficient-network-access.html
@jd:body
diff --git a/docs/html/training/gestures/detector.jd b/docs/html/training/gestures/detector.jd
index 06d0e98..65ddb1b 100644
--- a/docs/html/training/gestures/detector.jd
+++ b/docs/html/training/gestures/detector.jd
@@ -25,12 +25,18 @@ next.link=movement.html
<li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
</li>
<li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
- <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
<li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
<li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
<li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
</ul>
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
</div>
</div>
diff --git a/docs/html/training/gestures/index.jd b/docs/html/training/gestures/index.jd
index 0191450..16ca7b0 100644
--- a/docs/html/training/gestures/index.jd
+++ b/docs/html/training/gestures/index.jd
@@ -20,12 +20,18 @@ next.link=detector.html
<li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
</li>
<li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
- <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
<li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
<li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
<li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
</ul>
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
</div>
</div>
diff --git a/docs/html/training/gestures/movement.jd b/docs/html/training/gestures/movement.jd
index f2c49d7..fdc1ea4 100644
--- a/docs/html/training/gestures/movement.jd
+++ b/docs/html/training/gestures/movement.jd
@@ -24,12 +24,18 @@ next.link=scroll.html
<li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
</li>
<li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
- <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
<li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
<li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
<li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
</ul>
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
</div>
</div>
diff --git a/docs/html/training/gestures/multi.jd b/docs/html/training/gestures/multi.jd
index d4c5b1d..6a0df11 100644
--- a/docs/html/training/gestures/multi.jd
+++ b/docs/html/training/gestures/multi.jd
@@ -25,12 +25,18 @@ next.link=scale.html
<li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
</li>
<li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
- <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
<li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
<li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
<li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
</ul>
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
</div>
</div>
diff --git a/docs/html/training/gestures/scale.jd b/docs/html/training/gestures/scale.jd
index 17e4085..f2e4eb8 100644
--- a/docs/html/training/gestures/scale.jd
+++ b/docs/html/training/gestures/scale.jd
@@ -15,6 +15,7 @@ next.link=viewgroup.html
<h2>This lesson teaches you to</h2>
<ol>
<li><a href="#drag">Drag an Object</a></li>
+ <li><a href="#pan">Drag to Pan</a></li>
<li><a href="#scale">Use Touch to Perform Scaling</a></li>
</ol>
@@ -25,20 +26,25 @@ next.link=viewgroup.html
<li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
</li>
<li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
- <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
<li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
<li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
<li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
</ul>
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
</div>
</div>
+
<p>This lesson describes how to use touch gestures to drag and scale on-screen
objects, using {@link android.view.View#onTouchEvent onTouchEvent()} to intercept
-touch events. Here is the original <a
-href="http://code.google.com/p/android-touchexample/">source code</a>
-for the examples used in this lesson.
+touch events.
</p>
<h2 id="drag">Drag an Object</h2>
@@ -128,17 +134,15 @@ public boolean onTouchEvent(MotionEvent ev) {
final float x = MotionEventCompat.getX(ev, pointerIndex);
final float y = MotionEventCompat.getY(ev, pointerIndex);
- // Only move if the ScaleGestureDetector isn't processing a gesture.
- if (!mScaleDetector.isInProgress()) {
- // Calculate the distance moved
- final float dx = x - mLastTouchX;
- final float dy = y - mLastTouchY;
+ // Calculate the distance moved
+ final float dx = x - mLastTouchX;
+ final float dy = y - mLastTouchY;
- mPosX += dx;
- mPosY += dy;
+ mPosX += dx;
+ mPosY += dy;
+
+ invalidate();
- invalidate();
- }
// Remember this touch position for the next move event
mLastTouchX = x;
mLastTouchY = y;
@@ -175,6 +179,88 @@ public boolean onTouchEvent(MotionEvent ev) {
return true;
}</pre>
+<h2 id="pan">Drag to Pan</h2>
+
+<p>The previous section showed an example of dragging an object around the screen. Another
+common scenario is <em>panning</em>, which is when a user's dragging motion causes scrolling
+in both the x and y axes. The above snippet directly intercepted the {@link android.view.MotionEvent}
+actions to implement dragging. The snippet in this section takes advantage of the platform's
+built-in support for common gestures. It overrides
+{@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} in
+{@link android.view.GestureDetector.SimpleOnGestureListener}.</p>
+
+<p>To provide a little more context, {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()}
+is called when a user is dragging his finger to pan the content.
+{@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} is only called when
+a finger is down; as soon as the finger is lifted from the screen, the gesture either ends,
+or a fling gesture is started (if the finger was moving with some speed just before it was lifted).
+For more discussion of scrolling vs. flinging, see <a href="scroll.html">Animating a Scroll Gesture</a>.</p>
+
+<p>Here is the snippet for {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()}:
+
+
+<pre>// The current viewport. This rectangle represents the currently visible
+// chart domain and range.
+private RectF mCurrentViewport =
+ new RectF(AXIS_X_MIN, AXIS_Y_MIN, AXIS_X_MAX, AXIS_Y_MAX);
+
+// The current destination rectangle (in pixel coordinates) into which the
+// chart data should be drawn.
+private Rect mContentRect;
+
+private final GestureDetector.SimpleOnGestureListener mGestureListener
+ = new GestureDetector.SimpleOnGestureListener() {
+...
+
+&#64;Override
+public boolean onScroll(MotionEvent e1, MotionEvent e2,
+ float distanceX, float distanceY) {
+ // Scrolling uses math based on the viewport (as opposed to math using pixels).
+
+ // Pixel offset is the offset in screen pixels, while viewport offset is the
+ // offset within the current viewport.
+ float viewportOffsetX = distanceX * mCurrentViewport.width()
+ / mContentRect.width();
+ float viewportOffsetY = -distanceY * mCurrentViewport.height()
+ / mContentRect.height();
+ ...
+ // Updates the viewport, refreshes the display.
+ setViewportBottomLeft(
+ mCurrentViewport.left + viewportOffsetX,
+ mCurrentViewport.bottom + viewportOffsetY);
+ ...
+ return true;
+}</pre>
+
+<p>The implementation of {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()}
+scrolls the viewport in response to the touch gesture:</p>
+
+<pre>
+/**
+ * Sets the current viewport (defined by mCurrentViewport) to the given
+ * X and Y positions. Note that the Y value represents the topmost pixel position,
+ * and thus the bottom of the mCurrentViewport rectangle.
+ */
+private void setViewportBottomLeft(float x, float y) {
+ /*
+ * Constrains within the scroll range. The scroll range is simply the viewport
+ * extremes (AXIS_X_MAX, etc.) minus the viewport size. For example, if the
+ * extremes were 0 and 10, and the viewport size was 2, the scroll range would
+ * be 0 to 8.
+ */
+
+ float curWidth = mCurrentViewport.width();
+ float curHeight = mCurrentViewport.height();
+ x = Math.max(AXIS_X_MIN, Math.min(x, AXIS_X_MAX - curWidth));
+ y = Math.max(AXIS_Y_MIN + curHeight, Math.min(y, AXIS_Y_MAX));
+
+ mCurrentViewport.set(x, y - curHeight, x + curWidth, y);
+
+ // Invalidates the View to update the display.
+ ViewCompat.postInvalidateOnAnimation(this);
+}
+</pre>
+
<h2 id="scale">Use Touch to Perform Scaling</h2>
<p>As discussed in <a href="detector.html">Detecting Common Gestures</a>,
@@ -191,10 +277,10 @@ Android provides
{@link android.view.ScaleGestureDetector.SimpleOnScaleGestureListener}
as a helper class that you can extend if you don’t care about all of the reported events.</p>
-<p>Here is a snippet that gives you the basic idea of how to perform scaling.
-Here is the original <a
-href="http://code.google.com/p/android-touchexample/">source code</a>
-for the examples.</p>
+
+<h3>Basic scaling example</h3>
+
+<p>Here is a snippet that illustrates the basic ingredients involved in scaling.</p>
<pre>private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1.f;
@@ -238,3 +324,88 @@ private class ScaleListener
return true;
}
}</pre>
+
+
+
+
+<h3>More complex scaling example</h3>
+<p>Here is a more complex example from the {@code InteractiveChart} sample provided with this class.
+The {@code InteractiveChart} sample supports both scrolling (panning) and scaling with multiple fingers,
+using the {@link android.view.ScaleGestureDetector} "span"
+({@link android.view.ScaleGestureDetector#getCurrentSpanX getCurrentSpanX/Y}) and
+"focus" ({@link android.view.ScaleGestureDetector#getFocusX getFocusX/Y}) features:</p>
+
+<pre>&#64;Override
+private RectF mCurrentViewport =
+ new RectF(AXIS_X_MIN, AXIS_Y_MIN, AXIS_X_MAX, AXIS_Y_MAX);
+private Rect mContentRect;
+private ScaleGestureDetector mScaleGestureDetector;
+...
+public boolean onTouchEvent(MotionEvent event) {
+ boolean retVal = mScaleGestureDetector.onTouchEvent(event);
+ retVal = mGestureDetector.onTouchEvent(event) || retVal;
+ return retVal || super.onTouchEvent(event);
+}
+
+/**
+ * The scale listener, used for handling multi-finger scale gestures.
+ */
+private final ScaleGestureDetector.OnScaleGestureListener mScaleGestureListener
+ = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
+ /**
+ * This is the active focal point in terms of the viewport. Could be a local
+ * variable but kept here to minimize per-frame allocations.
+ */
+ private PointF viewportFocus = new PointF();
+ private float lastSpanX;
+ private float lastSpanY;
+
+ // Detects that new pointers are going down.
+ &#64;Override
+ public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
+ lastSpanX = ScaleGestureDetectorCompat.
+ getCurrentSpanX(scaleGestureDetector);
+ lastSpanY = ScaleGestureDetectorCompat.
+ getCurrentSpanY(scaleGestureDetector);
+ return true;
+ }
+
+ &#64;Override
+ public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
+
+ float spanX = ScaleGestureDetectorCompat.
+ getCurrentSpanX(scaleGestureDetector);
+ float spanY = ScaleGestureDetectorCompat.
+ getCurrentSpanY(scaleGestureDetector);
+
+ float newWidth = lastSpanX / spanX * mCurrentViewport.width();
+ float newHeight = lastSpanY / spanY * mCurrentViewport.height();
+
+ float focusX = scaleGestureDetector.getFocusX();
+ float focusY = scaleGestureDetector.getFocusY();
+ // Makes sure that the chart point is within the chart region.
+ // See the sample for the implementation of hitTest().
+ hitTest(scaleGestureDetector.getFocusX(),
+ scaleGestureDetector.getFocusY(),
+ viewportFocus);
+
+ mCurrentViewport.set(
+ viewportFocus.x
+ - newWidth * (focusX - mContentRect.left)
+ / mContentRect.width(),
+ viewportFocus.y
+ - newHeight * (mContentRect.bottom - focusY)
+ / mContentRect.height(),
+ 0,
+ 0);
+ mCurrentViewport.right = mCurrentViewport.left + newWidth;
+ mCurrentViewport.bottom = mCurrentViewport.top + newHeight;
+ ...
+ // Invalidates the View to update the display.
+ ViewCompat.postInvalidateOnAnimation(InteractiveLineGraphView.this);
+
+ lastSpanX = spanX;
+ lastSpanY = spanY;
+ return true;
+ }
+};</pre>
diff --git a/docs/html/training/gestures/scroll.jd b/docs/html/training/gestures/scroll.jd
index 8576948..bd1537a 100644
--- a/docs/html/training/gestures/scroll.jd
+++ b/docs/html/training/gestures/scroll.jd
@@ -14,6 +14,7 @@ next.link=multi.html
<!-- table of contents -->
<h2>This lesson teaches you to</h2>
<ol>
+ <li><a href="#term">Understand Scrolling Terminology</a></li>
<li><a href="#scroll">Implement Touch-Based Scrolling</a></li>
</ol>
@@ -24,12 +25,18 @@ next.link=multi.html
<li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
</li>
<li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
- <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
<li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
<li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
<li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
</ul>
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
</div>
</div>
@@ -45,7 +52,26 @@ a scrolling effect in response to touch gestures using <em>scrollers</em>.
<p>You can use scrollers ({@link android.widget.Scroller} or {@link
android.widget.OverScroller}) to collect the data you need to produce a
-scrolling animation in response to a touch event.</p>
+scrolling animation in response to a touch event. They are similar, but
+{@link android.widget.OverScroller}
+includes methods for indicating to users that they've reached the content edges
+after a pan or fling gesture. The {@code InteractiveChart} sample
+uses the the {@link android.widget.EdgeEffect} class
+(actually the {@link android.support.v4.widget.EdgeEffectCompat} class)
+to display a "glow" effect when users reach the content edges.</p>
+
+<p class="note"><strong>Note:</strong> We recommend that you
+use {@link android.widget.OverScroller} rather than {@link
+android.widget.Scroller} for scrolling animations.
+{@link android.widget.OverScroller} provides the best backward
+compatibility with older devices.
+<br />
+Also note that you generally only need to use scrollers
+when implementing scrolling yourself. {@link android.widget.ScrollView} and
+{@link android.widget.HorizontalScrollView} do all of this for you if you nest your
+layout within them.
+</p>
+
<p>A scroller is used to animate scrolling over time, using platform-standard
scrolling physics (friction, velocity, etc.). The scroller itself doesn't
@@ -54,101 +80,280 @@ they don't automatically apply those positions to your view. It's your
responsibility to get and apply new coordinates at a rate that will make the
scrolling animation look smooth.</p>
-<p class="note"><strong>Note:</strong> You generally only need to use scrollers
-when implementing scrolling yourself. {@link android.widget.ScrollView} and
-{@link android.widget.HorizontalScrollView} do all this for you do all of this for you if you nest your layout within them.</p>
-<h2 id = "scroll">Implement Touch-Based Scrolling</h2>
+<h2 id="term">Understand Scrolling Terminology</h2>
-<p>This snippet illustrates the basics of using a scroller. It uses a
-{@link android.view.GestureDetector}, and overrides the
-{@link android.view.GestureDetector.SimpleOnGestureListener} methods
-{@link android.view.GestureDetector.OnGestureListener#onDown onDown()} and
-{@link android.view.GestureDetector.OnGestureListener#onFling onFling()}. It also
-overrides {@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()}
-to return {@code false} since you don't need to animate a scroll.</p>
+<p>"Scrolling" is a word that can take on different meanings in Android, depending on the context.</p>
+
+<p><strong>Scrolling</strong> is the general process of moving the viewport (that is, the 'window'
+of content you're looking at). When scrolling is in both the x and y axes, it's called
+<em>panning</em>. The sample application provided with this class, {@code InteractiveChart}, illustrates
+two different types of scrolling, dragging and flinging:</p>
+<ul>
+ <li><strong>Dragging</strong> is the type of scrolling that occurs when a user drags her
+finger across the touch screen. Simple dragging is often implemented by overriding
+{@link android.view.GestureDetector.OnGestureListener#onScroll onScroll()} in
+{@link android.view.GestureDetector.OnGestureListener}. For more discussion of dragging, see
+<a href="dragging.jd">Dragging and Scaling</a>.</li>
+ <li><strong>Flinging</strong> is the type of scrolling that occurs when a user
+drags and lifts her finger quickly. After the user lifts her finger, you generally
+want to keep scrolling (moving the viewport), but decelerate until the viewport stops moving.
+Flinging can be implemented by overriding
+{@link android.view.GestureDetector.OnGestureListener#onFling onFling()}
+in {@link android.view.GestureDetector.OnGestureListener}, and by using
+a scroller object. This is the use
+case that is the topic of this lesson.</li>
+</ul>
-<p>It's common to use scrollers in conjunction with a fling gesture, but they
+<p>It's common to use scroller objects
+in conjunction with a fling gesture, but they
can be used in pretty much any context where you want the UI to display
-scrolling in response to a touch event. For example, you could override {@link
-android.view.View#onTouchEvent onTouchEvent()} to process touch events directly,
-and produce a scrolling effect in response to those touch events.</p>
+scrolling in response to a touch event. For example, you could override
+{@link android.view.View#onTouchEvent onTouchEvent()} to process touch
+events directly, and produce a scrolling effect or a "snapping to page" animation
+in response to those touch events.</p>
+
+
+<h2 id="#scroll">Implement Touch-Based Scrolling</h2>
+
+<p>This section describes how to use a scroller.
+The snippet shown below comes from the {@code InteractiveChart} sample
+provided with this class.
+It uses a
+{@link android.view.GestureDetector}, and overrides the
+{@link android.view.GestureDetector.SimpleOnGestureListener} method
+{@link android.view.GestureDetector.OnGestureListener#onFling onFling()}.
+It uses {@link android.widget.OverScroller} to track the fling gesture.
+If the user reaches the content edges
+after the fling gesture, the app displays a "glow" effect.
+</p>
-<pre>
-private OverScroller mScroller = new OverScroller(context);
+<p class="note"><strong>Note:</strong> The {@code InteractiveChart} sample app displays a
+chart that you can zoom, pan, scroll, and so on. In the following snippet,
+{@code mContentRect} represents the rectangle coordinates within the view that the chart
+will be drawn into. At any given time, a subset of the total chart domain and range are drawn
+into this rectangular area.
+{@code mCurrentViewport} represents the portion of the chart that is currently
+visible in the screen. Because pixel offsets are generally treated as integers,
+{@code mContentRect} is of the type {@link android.graphics.Rect}. Because the
+graph domain and range are decimal/float values, {@code mCurrentViewport} is of
+the type {@link android.graphics.RectF}.</p>
-private GestureDetector.SimpleOnGestureListener mGestureListener
+<p>The first part of the snippet shows the implementation of
+{@link android.view.GestureDetector.OnGestureListener#onFling onFling()}:</p>
+
+<pre>// The current viewport. This rectangle represents the currently visible
+// chart domain and range. The viewport is the part of the app that the
+// user manipulates via touch gestures.
+private RectF mCurrentViewport =
+ new RectF(AXIS_X_MIN, AXIS_Y_MIN, AXIS_X_MAX, AXIS_Y_MAX);
+
+// The current destination rectangle (in pixel coordinates) into which the
+// chart data should be drawn.
+private Rect mContentRect;
+
+private OverScroller mScroller;
+private RectF mScrollerStartViewport;
+...
+private final GestureDetector.SimpleOnGestureListener mGestureListener
= new GestureDetector.SimpleOnGestureListener() {
&#64;Override
public boolean onDown(MotionEvent e) {
- // Abort any active scroll animations and invalidate.
+ // Initiates the decay phase of any active edge effects.
+ releaseEdgeEffects();
+ mScrollerStartViewport.set(mCurrentViewport);
+ // Aborts any active scroll animations and invalidates.
mScroller.forceFinished(true);
- // There is also a compatibility version:
- // ViewCompat.postInvalidateOnAnimation
- postInvalidateOnAnimation();
+ ViewCompat.postInvalidateOnAnimation(InteractiveLineGraphView.this);
return true;
}
-
- &#64;Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- // You don't use a scroller in onScroll because you don't need to animate
- // a scroll. The scroll occurs instantly in response to touch feedback.
- return false;
- }
-
+ ...
&#64;Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
- // Before flinging, abort the current animation.
- mScroller.forceFinished(true);
- // Begin the scroll animation
- mScroller.fling(
- // Current scroll position
- startX,
- startY,
- // Velocities, negated for natural touch response
- (int) -velocityX,
- (int) -velocityY,
- // Minimum and maximum scroll positions. The minimum scroll
- // position is generally zero and the maximum scroll position
- // is generally the content size less the screen size. So if the
- // content width is 1000 pixels and the screen width is 200
- // pixels, the maximum scroll offset should be 800 pixels.
- minX, maxX,
- minY, maxY,
- // The maximum overscroll bounds. This is useful when using
- // the EdgeEffect class to draw overscroll "glow" overlays.
- mContentRect.width() / 2,
- mContentRect.height() / 2);
- // Invalidate to trigger computeScroll()
- postInvalidateOnAnimation();
+ fling((int) -velocityX, (int) -velocityY);
return true;
}
};
+private void fling(int velocityX, int velocityY) {
+ // Initiates the decay phase of any active edge effects.
+ releaseEdgeEffects();
+ // Flings use math in pixels (as opposed to math based on the viewport).
+ Point surfaceSize = computeScrollSurfaceSize();
+ mScrollerStartViewport.set(mCurrentViewport);
+ int startX = (int) (surfaceSize.x * (mScrollerStartViewport.left -
+ AXIS_X_MIN) / (
+ AXIS_X_MAX - AXIS_X_MIN));
+ int startY = (int) (surfaceSize.y * (AXIS_Y_MAX -
+ mScrollerStartViewport.bottom) / (
+ AXIS_Y_MAX - AXIS_Y_MIN));
+ // Before flinging, aborts the current animation.
+ mScroller.forceFinished(true);
+ // Begins the animation
+ mScroller.fling(
+ // Current scroll position
+ startX,
+ startY,
+ velocityX,
+ velocityY,
+ /*
+ * Minimum and maximum scroll positions. The minimum scroll
+ * position is generally zero and the maximum scroll position
+ * is generally the content size less the screen size. So if the
+ * content width is 1000 pixels and the screen width is 200
+ * pixels, the maximum scroll offset should be 800 pixels.
+ */
+ 0, surfaceSize.x - mContentRect.width(),
+ 0, surfaceSize.y - mContentRect.height(),
+ // The edges of the content. This comes into play when using
+ // the EdgeEffect class to draw "glow" overlays.
+ mContentRect.width() / 2,
+ mContentRect.height() / 2);
+ // Invalidates to trigger computeScroll()
+ ViewCompat.postInvalidateOnAnimation(this);
+}</pre>
+
+<p>When {@link android.view.GestureDetector.OnGestureListener#onFling onFling()} calls
+{@link android.support.v4.view.ViewCompat#postInvalidateOnAnimation postInvalidateOnAnimation()},
+it triggers
+{@link android.view.View#computeScroll computeScroll()} to update the values for x and y.
+This is typically be done when a view child is animating a scroll using a scroller object, as in this example. </p>
+
+<p>Most views pass the scroller object's x and y position directly to
+{@link android.view.View#scrollTo scrollTo()}.
+The following implementation of {@link android.view.View#computeScroll computeScroll()}
+takes a different approach&mdash;it calls
+{@link android.widget.OverScroller#computeScrollOffset computeScrollOffset()} to get the current
+location of x and y. When the criteria for displaying an overscroll "glow" edge effect are met
+(the display is zoomed in, x or y is out of bounds, and the app isn't already showing an overscroll),
+the code sets up the overscroll glow effect and calls
+{@link android.support.v4.view.ViewCompat#postInvalidateOnAnimation postInvalidateOnAnimation()}
+to trigger an invalidate on the view:</p>
+
+<pre>// Edge effect / overscroll tracking objects.
+private EdgeEffectCompat mEdgeEffectTop;
+private EdgeEffectCompat mEdgeEffectBottom;
+private EdgeEffectCompat mEdgeEffectLeft;
+private EdgeEffectCompat mEdgeEffectRight;
+
+private boolean mEdgeEffectTopActive;
+private boolean mEdgeEffectBottomActive;
+private boolean mEdgeEffectLeftActive;
+private boolean mEdgeEffectRightActive;
+
&#64;Override
public void computeScroll() {
super.computeScroll();
- // Compute the current scroll offsets. If this returns true, then the
- // scroll has not yet finished.
+ boolean needsInvalidate = false;
+
+ // The scroller isn't finished, meaning a fling or programmatic pan
+ // operation is currently active.
if (mScroller.computeScrollOffset()) {
+ Point surfaceSize = computeScrollSurfaceSize();
int currX = mScroller.getCurrX();
int currY = mScroller.getCurrY();
- // Actually render the scrolled viewport, or actually scroll the
- // view using View.scrollTo.
+ boolean canScrollX = (mCurrentViewport.left > AXIS_X_MIN
+ || mCurrentViewport.right < AXIS_X_MAX);
+ boolean canScrollY = (mCurrentViewport.top > AXIS_Y_MIN
+ || mCurrentViewport.bottom < AXIS_Y_MAX);
- // If currX or currY are outside the bounds, render the overscroll
- // glow using EdgeEffect.
+ /*
+ * If you are zoomed in and currX or currY is
+ * outside of bounds and you're not already
+ * showing overscroll, then render the overscroll
+ * glow edge effect.
+ */
+ if (canScrollX
+ && currX < 0
+ && mEdgeEffectLeft.isFinished()
+ && !mEdgeEffectLeftActive) {
+ mEdgeEffectLeft.onAbsorb((int)
+ OverScrollerCompat.getCurrVelocity(mScroller));
+ mEdgeEffectLeftActive = true;
+ needsInvalidate = true;
+ } else if (canScrollX
+ && currX > (surfaceSize.x - mContentRect.width())
+ && mEdgeEffectRight.isFinished()
+ && !mEdgeEffectRightActive) {
+ mEdgeEffectRight.onAbsorb((int)
+ OverScrollerCompat.getCurrVelocity(mScroller));
+ mEdgeEffectRightActive = true;
+ needsInvalidate = true;
+ }
- } else {
- // The scroll has finished.
- }
+ if (canScrollY
+ && currY < 0
+ && mEdgeEffectTop.isFinished()
+ && !mEdgeEffectTopActive) {
+ mEdgeEffectTop.onAbsorb((int)
+ OverScrollerCompat.getCurrVelocity(mScroller));
+ mEdgeEffectTopActive = true;
+ needsInvalidate = true;
+ } else if (canScrollY
+ && currY > (surfaceSize.y - mContentRect.height())
+ && mEdgeEffectBottom.isFinished()
+ && !mEdgeEffectBottomActive) {
+ mEdgeEffectBottom.onAbsorb((int)
+ OverScrollerCompat.getCurrVelocity(mScroller));
+ mEdgeEffectBottomActive = true;
+ needsInvalidate = true;
+ }
+ ...
+ }</pre>
+
+<p>Here is the section of the code that performs the actual zoom:</p>
+
+<pre>// Custom object that is functionally similar to Scroller
+Zoomer mZoomer;
+private PointF mZoomFocalPoint = new PointF();
+...
+
+// If a zoom is in progress (either programmatically or via double
+// touch), performs the zoom.
+if (mZoomer.computeZoom()) {
+ float newWidth = (1f - mZoomer.getCurrZoom()) *
+ mScrollerStartViewport.width();
+ float newHeight = (1f - mZoomer.getCurrZoom()) *
+ mScrollerStartViewport.height();
+ float pointWithinViewportX = (mZoomFocalPoint.x -
+ mScrollerStartViewport.left)
+ / mScrollerStartViewport.width();
+ float pointWithinViewportY = (mZoomFocalPoint.y -
+ mScrollerStartViewport.top)
+ / mScrollerStartViewport.height();
+ mCurrentViewport.set(
+ mZoomFocalPoint.x - newWidth * pointWithinViewportX,
+ mZoomFocalPoint.y - newHeight * pointWithinViewportY,
+ mZoomFocalPoint.x + newWidth * (1 - pointWithinViewportX),
+ mZoomFocalPoint.y + newHeight * (1 - pointWithinViewportY));
+ constrainViewport();
+ needsInvalidate = true;
+}
+if (needsInvalidate) {
+ ViewCompat.postInvalidateOnAnimation(this);
+}
+</pre>
+
+<p>This is the {@code computeScrollSurfaceSize()} method that's called in the above snippet. It
+computes the current scrollable surface size, in pixels. For example, if the entire chart area is visible,
+this is simply the current size of {@code mContentRect}. If the chart is zoomed in 200% in both directions,
+the returned size will be twice as large horizontally and vertically.</p>
+
+<pre>private Point computeScrollSurfaceSize() {
+ return new Point(
+ (int) (mContentRect.width() * (AXIS_X_MAX - AXIS_X_MIN)
+ / mCurrentViewport.width()),
+ (int) (mContentRect.height() * (AXIS_Y_MAX - AXIS_Y_MIN)
+ / mCurrentViewport.height()));
}</pre>
-<p>For another example of scroller usage, see the <a href="http://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/view/ViewPager.java">source code</a> for the
-{@link android.support.v4.view.ViewPager} class.</p>
+<p>For another example of scroller usage, see the
+<a href="http://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/view/ViewPager.java">source code</a> for the
+{@link android.support.v4.view.ViewPager} class. It scrolls in response to flings,
+and uses scrolling to implement the "snapping to page" animation.</p>
+
diff --git a/docs/html/training/gestures/viewgroup.jd b/docs/html/training/gestures/viewgroup.jd
index 257a5d8..5b32300 100644
--- a/docs/html/training/gestures/viewgroup.jd
+++ b/docs/html/training/gestures/viewgroup.jd
@@ -26,12 +26,19 @@ next.link=
<li><a href="http://developer.android.com/guide/topics/ui/ui-events.html">Input Events</a> API Guide
</li>
<li><a href="{@docRoot}guide/topics/sensors/sensors_overview.html">Sensors Overview</a></li>
- <li><a href="http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html">Making Sense of Multitouch</a> blog post</li>
<li><a href="{@docRoot}training/custom-views/making-interactive.html">Making the View Interactive</a> </li>
<li>Design Guide for <a href="{@docRoot}design/patterns/gestures.html">Gestures</a></li>
<li>Design Guide for <a href="{@docRoot}design/style/touch-feedback.html">Touch Feedback</a></li>
</ul>
+<h2>Try it out</h2>
+
+<div class="download-box">
+ <a href="{@docRoot}shareables/training/InteractiveChart.zip"
+class="button">Download the sample</a>
+ <p class="filename">InteractiveChart.zip</p>
+</div>
+
</div>
</div>
diff --git a/docs/html/training/graphics/opengl/index.jd b/docs/html/training/graphics/opengl/index.jd
index 23a734a..cf33d80 100644
--- a/docs/html/training/graphics/opengl/index.jd
+++ b/docs/html/training/graphics/opengl/index.jd
@@ -1,7 +1,6 @@
page.title=Displaying Graphics with OpenGL ES
+page=tags="open gl","graphics"
trainingnavtop=true
-next.title=Building an OpenGL ES Environment
-next.link=environment.html
@jd:body
diff --git a/docs/html/training/implementing-navigation/lateral.jd b/docs/html/training/implementing-navigation/lateral.jd
index 9a31d7a..c8f57a2 100644
--- a/docs/html/training/implementing-navigation/lateral.jd
+++ b/docs/html/training/implementing-navigation/lateral.jd
@@ -43,7 +43,8 @@ next.link=ancestral.html
<p>Tabs allow the user to navigate between sibling screens by selecting the appropriate tab indicator available at the top of the display. In Android 3.0 and later, tabs are implemented using the {@link android.app.ActionBar} class, and are generally set up in {@link android.app.Activity#onCreate Activity.onCreate()}. In some cases, such as when horizontal space is limited and/or the number of tabs is large, an appropriate alternate presentation for tabs is a dropdown list (sometimes implemented using a {@link android.widget.Spinner}).</p>
-<p>In previous versions of Android, tabs could be implemented using a {@link android.widget.TabWidget} and {@link android.widget.TabHost}. For details, see the <a href="{@docRoot}resources/tutorials/views/hello-tabwidget.html">Hello, Views</a> tutorial.</p>
+<p>In previous versions of Android, tabs could be implemented using a
+{@link android.widget.TabWidget} and {@link android.widget.TabHost}.</p>
<p>As of Android 3.0, however, you should use either {@link android.app.ActionBar#NAVIGATION_MODE_TABS} or {@link android.app.ActionBar#NAVIGATION_MODE_LIST} along with the {@link android.app.ActionBar} class.</p>
diff --git a/docs/html/training/managing-audio/index.jd b/docs/html/training/managing-audio/index.jd
index 0f7bbfd..3e3bcf0 100644
--- a/docs/html/training/managing-audio/index.jd
+++ b/docs/html/training/managing-audio/index.jd
@@ -1,9 +1,8 @@
page.title=Managing Audio Playback
+page.tags="audio","media"
trainingnavtop=true
startpage=true
-next.title=Controlling Your App's Volume and Playback
-next.link=volume-playback.html
@jd:body
diff --git a/docs/html/training/notify-user/build-notification.jd b/docs/html/training/notify-user/build-notification.jd
index ba66028..80f2cd5 100644
--- a/docs/html/training/notify-user/build-notification.jd
+++ b/docs/html/training/notify-user/build-notification.jd
@@ -149,12 +149,14 @@ specifications.</li>
<p>For example:</p>
<pre>
+NotificationCompat.Builder mBuilder;
+...
// Sets an ID for the notification
int mNotificationId = 001;
// Gets an instance of the NotificationManager service
NotificationManager mNotifyMgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Builds the notification and issues it.
-mNotifyMgr.notify(mNotificationId, builder.build());
+mNotifyMgr.notify(mNotificationId, mBuilder.build());
</pre>
diff --git a/docs/html/training/sharing/index.jd b/docs/html/training/sharing/index.jd
index c2e8dbc..2aa22b6 100644
--- a/docs/html/training/sharing/index.jd
+++ b/docs/html/training/sharing/index.jd
@@ -1,9 +1,8 @@
page.title=Sharing Content
+page.tags="intents","share"
trainingnavtop=true
startpage=true
-next.title=Sending Content to Other Apps
-next.link=send.html
@jd:body
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 79980be..7a3f2ca 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -287,6 +287,10 @@
Caching Bitmaps
</a>
</li>
+ <li><a href="<?cs var:toroot ?>training/displaying-bitmaps/manage-memory.html">
+ Managing Bitmap Memory
+ </a>
+ </li>
<li><a href="<?cs var:toroot ?>training/displaying-bitmaps/display-bitmap.html">
Displaying Bitmaps in Your UI
</a></li>
@@ -480,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"
@@ -875,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">