Merge "Doc change: add MR1 API summary and updated highlights." into ics-mr1
diff --git a/docs/html/images/training/hierarchy-layouttimes.png b/docs/html/images/training/hierarchy-layouttimes.png
new file mode 100644
index 0000000..423f1af
--- /dev/null
+++ b/docs/html/images/training/hierarchy-layouttimes.png
Binary files differ
diff --git a/docs/html/images/training/hierarchy-linearlayout.png b/docs/html/images/training/hierarchy-linearlayout.png
new file mode 100644
index 0000000..cac4cae
--- /dev/null
+++ b/docs/html/images/training/hierarchy-linearlayout.png
Binary files differ
diff --git a/docs/html/images/training/hierarchy-relativelayout.png b/docs/html/images/training/hierarchy-relativelayout.png
new file mode 100644
index 0000000..b3408e5
--- /dev/null
+++ b/docs/html/images/training/hierarchy-relativelayout.png
Binary files differ
diff --git a/docs/html/images/training/import-progress.png b/docs/html/images/training/import-progress.png
new file mode 100644
index 0000000..bbb689b
--- /dev/null
+++ b/docs/html/images/training/import-progress.png
Binary files differ
diff --git a/docs/html/images/training/layout-listitem.png b/docs/html/images/training/layout-listitem.png
new file mode 100644
index 0000000..9cb241d
--- /dev/null
+++ b/docs/html/images/training/layout-listitem.png
Binary files differ
diff --git a/docs/html/images/training/sharing/share-text-screenshot.png b/docs/html/images/training/sharing/share-text-screenshot.png
new file mode 100644
index 0000000..089221c
--- /dev/null
+++ b/docs/html/images/training/sharing/share-text-screenshot.png
Binary files differ
diff --git a/docs/html/training/improving-layouts/index.jd b/docs/html/training/improving-layouts/index.jd
new file mode 100644
index 0000000..4cc6963
--- /dev/null
+++ b/docs/html/training/improving-layouts/index.jd
@@ -0,0 +1,58 @@
+page.title=Improving Performance of Layouts
+
+trainingnavtop=true
+startpage=true
+next.title=Optimizing Layout
+next.link=optimizing-layout.html
+
+@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 1.5 (API Level 3) or higher</li>
+</ul>
+
+<!-- related docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a></li>
+</ul>
+
+</div>
+</div>
+
+
+
+<p>Layouts are a key part of Android applications that directly affect the user experience. If
+implemented poorly, your layout can lead to a memory hungry application with slow UIs. The Android
+SDK includes tools to help you identify problems in your layout performance, which when combined the
+lessons here, you will be able to implement smooth scrolling interfaces with a minimum memory
+footprint.</p>
+
+
+
+<h2>Lessons</h2>
+
+<dl>
+  <dt><b><a href="optimizing-layout.html">Optimizing Layout Hierarchies</a></b></dt>
+    <dd>In the same way a complex web page can slow down load time, your layout hierarchy
+if too complex can also cause performance problems. This lesson shows how you can use SDK tools
+to inspect your layout and discover performance bottlenecks.</dd>
+  <dt><b><a href="reusing-layouts.html">Re-using Layouts with &lt;include/&gt;</a></b></dt>
+    <dd>If your application UI repeats certain layout constructs in multiple places, this lesson
+shows you how to create efficient, re-usable layout constructs, then include them in the appropriate
+UI layouts.</dd>
+  <dt><b><a href="loading-ondemand.html">Loading Views On Demand</a></b></dt>
+    <dd>Beyond simply including one layout component within another layout, you might want to
+make the included layout visible only when it's needed, sometime after the activity is running.
+This lesson shows how you can improve your layout's initialization performance by loading
+portions of your layout on demand.</dd>
+  <dt><b><a href="smooth-scrolling.html">Making ListView Scrolling Smooth</a></b></dt>
+    <dd>If you've built an instance of {@link android.widget.ListView} that contains complex or
+data-heavy content in each list item, the scroll performance of the list might suffer. This
+lesson provides some tips about how you can make your scrolling performance more smooth.</dd>
+</dl>
\ No newline at end of file
diff --git a/docs/html/training/improving-layouts/loading-ondemand.jd b/docs/html/training/improving-layouts/loading-ondemand.jd
new file mode 100644
index 0000000..659b1ec3
--- /dev/null
+++ b/docs/html/training/improving-layouts/loading-ondemand.jd
@@ -0,0 +1,86 @@
+page.title=Loading Views On Demand
+parent.title=Improving Performance of Layouts
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Re-using Layouts with &lt;include/&gt;
+previous.link=reusing-layouts.html
+next.title=Making ListView Scrolling Smooth
+next.link=smooth-scrolling.html
+
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#ViewStub">Define a ViewStub</a></li>
+  <li><a href="#Load">Load the ViewStub Layout</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}resources/articles/layout-tricks-stubs.html">Using ViewStubs</a></li>
+</ul>
+
+</div>
+</div>
+
+
+<p>Sometimes your layout might require complex views that are rarely used. Whether
+they are item details, progress indicators, or undo messages, you can reduce memory usage and speed
+up rendering by loading the views only when they are needed.</p>
+
+
+<h2 id="ViewStub">Define a ViewStub</h2>
+
+<p>{@link android.view.ViewStub} is a lightweight view with no dimension and doesn’t draw anything
+or participate in the layout. As such, it's cheap to inflate and cheap to leave in a view hierarchy.
+Each {@link android.view.ViewStub} simply needs to include the {@code android:layout} attribute to
+specify the layout to inflate.</p>
+
+<p>The following {@link android.view.ViewStub} is for a translucent progress bar overlay. It should
+be visible only when new items are being imported into the application.</p>
+
+<pre>
+&lt;ViewStub
+    android:id="@+id/stub_import"
+    android:inflatedId="@+id/panel_import"
+    android:layout="@layout/progress_overlay"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="bottom" /&gt;
+</pre>
+
+
+<h2 id="Load">Load the ViewStub Layout</h2>
+
+<p>When you want to load the layout specified by the {@link android.view.ViewStub}, either set it
+visible by calling {@link android.view.View#setVisibility setVisibility(View.VISIBLE)} or call
+{@link android.view.ViewStub#inflate()}.</p>
+
+<pre>
+((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
+// or
+View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
+</pre>
+
+<p class="note"><strong>Note:</strong> The {@link android.view.ViewStub#inflate()} method returns
+the inflated {@link android.view.View} once complete. so you don't need to call {@link
+android.app.Activity#findViewById findViewById()} if you need to interact with the layout.</p>
+
+<p>Once visible/inflated, the {@link android.view.ViewStub} element is no longer part of the view
+hierarchy. It is replaced by the inflated layout and the ID for the root view of that layout is
+the one specified by the {@code android:inflatedId} attribute of the ViewStub. (The ID {@code
+android:id} specified for the {@link android.view.ViewStub} is valid only until the {@link
+android.view.ViewStub} layout is visible/inflated.)</p>
+
+<p class="note"><strong>Note:</strong> One drawback of {@link android.view.ViewStub} is that it
+doesn’t currently support the {@code &lt;merge/&gt;} tag in the layouts to be inflated.</p>
+
+
+
diff --git a/docs/html/training/improving-layouts/optimizing-layout.jd b/docs/html/training/improving-layouts/optimizing-layout.jd
new file mode 100644
index 0000000..3237780
--- /dev/null
+++ b/docs/html/training/improving-layouts/optimizing-layout.jd
@@ -0,0 +1,156 @@
+page.title=Optimizing Layout Hierarchies
+parent.title=Improving Performance of Layouts
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Re-using Layouts with &lt;include/&gt;
+next.link=reusing-layouts.html
+
+@jd:body
+
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#Inspect">Inspect Your Layout</a></li>
+  <li><a href="#Revise">Revise Your Layout</a></li>
+  <li><a href="#Layoutopt">Use Layoutopt</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a></li>
+  <li><a
+href="{@docRoot}guide/topics/resources/layout-resource.html#include- element">Layout
+Resource</a></li>
+</ul>
+
+</div>
+</div>
+
+
+<p>It is a common misconception that using the basic layout structures leads to the most efficient
+layouts. However, each widget and layout you add to your application requires initialization,
+layout, and drawing. For example, using nested instances of {@link android.widget.LinearLayout} can
+lead to an excessively deep view hierarchy. Furthermore, nesting several instances of {@link
+android.widget.LinearLayout} that use the {@code layout_weight} parameter can be especially
+expensive as each child needs to be measured twice. This is particularly important when the layout
+is inflated repeatedly, such as when used in a {@link android.widget.ListView} or {@link
+android.widget.GridView}.</p>
+
+<p>In this lesson you'll learn to use <a
+href="{@docRoot}guide/developing/tools/hierarchy-viewer.html">Heirachy Viewer</a> and <a
+href="{@docRoot}guide/developing/tools/layoutopt.html">Layoutopt</a> to examine and optimize your
+layout.</p>
+
+
+
+<h2 id="Inspect">Inspect Your Layout</h2>
+
+<p>The Android SDK tools include a tool called <a
+href="{@docRoot}guide/developing/tools/hierarchy-viewer.html">Heirachy Viewer</a> that allows
+you to analyze your layout while your application is running. Using this tool helps you discover
+bottlenecks in the layout performance.</p>
+
+<p>Hierarchy Viewer works by allowing you to select running processes on a connected device or
+emulator, then display the layout tree. The traffic lights on each block represent its Measure,
+Layout and Draw performance, helping you identify potential issues.</p>
+
+<p>For example, figure 1 shows a layout that's used as an item in a {@link
+android.widget.ListView}. This layout shows a small bitmap image on the left and two stacked items
+of text on the right. It is especially important that layouts that will be inflated multiple
+times&mdash;such as this one&mdash;are optimized as the performance
+benefits will be multiplied.</p>
+
+<img src="{@docRoot}images/training/layout-listitem.png" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> Conceptual layout for an item in a {@link
+android.widget.ListView}.</p>
+
+<p>The {@code hierarchyviewer} tool is available in  {@code &lt;sdk&gt;/tools/}. When opened,
+the Hierarchy Viewer shows a list of available devices and its running components. Click
+<strong>Load View Hierarchy</strong> to view the layout hierarchy of the selected component. For
+example, figure 2 shows the layout for the list item illustrated by figure 1.</p>
+
+<div style="float:left;width:455px">
+<img src="{@docRoot}images/training/hierarchy-linearlayout.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> Layout hierarchy for the layout in figure 1,
+using nested instances of {@link android.widget.LinearLayout}.</p>
+</div>
+
+<div style="float:left;width:155px;margin-left:2em">
+<img src="{@docRoot}images/training/hierarchy-layouttimes.png" alt="" />
+<p class="img-caption"><strong>Figure 3.</strong> Clicking a hierarchy node shows its
+performance times.</p>
+</div>
+
+<p style="clear:left">In figure 2, you can see there is a 3-level hierarchy with some problems
+laying out the text items. Clicking on the items shows the time taken for each stage of the process
+(figure 3). It becomes clear which items are taking the longest to measure, layout, and render, and
+where you should spend time optimizing.</p>
+
+<p>The timings for rendering a complete list item using this layout are:</p>
+<ul>
+  <li>Measure: 0.977ms</li>
+  <li>Layout: 0.167ms</li>
+  <li>Draw: 2.717ms</li>
+</ul>
+
+
+<h2 id="Revise">Revise Your Layout</h2>
+
+<p>Because the layout performance above slows down due to a nested {@link
+android.widget.LinearLayout}, the performance might improve by flattening the layout&mdash;make
+the layout shallow and wide, rather than narrow and deep. A {@link android.widget.RelativeLayout} as
+the root node allows for such layouts. So, when this design is converted to use {@link
+android.widget.RelativeLayout}, you can see that the layout becomes a 2-level hierarchy. Inspection
+of the new layout looks like this:</p>
+
+<img src="{@docRoot}images/training/hierarchy-relativelayout.png" alt="" />
+<p class="img-caption"><strong>Figure 4.</strong> Layout hierarchy for the layout in figure 1,
+using {@link android.widget.RelativeLayout}.</p>
+
+<p>Now rendering a list item takes:</p>
+<ul>
+  <li>Measure: 0.598ms</li>
+  <li>Layout: 0.110ms</li>
+  <li>Draw: 2.146ms</li>
+</ul>
+
+<p>Might seem like a small improvement, but this time is multiplied several times because this
+layout is used for every item in a list.</p>
+
+<p>Most of this time difference is due to the use of {@code layout_weight} in the {@link
+android.widget.LinearLayout} design, which can slow down the speed of measurement. It is just one
+example of how each layout has appropriate uses and you should carefully consider whether using 
+layout weight is necessary.</p>
+
+
+<h2 id="Layoutopt">Use Layoutopt</h2>
+
+<p>It is always good practice to also run the <a
+href="{@docRoot}guide/developing/tools/layoutopt.html">layoutopt</a> tool on your final layout files
+to search for places in your view hierarchy that may be optimized. Layoutopt is also in your SDK
+{@code tools/} directory and takes a layout directory name or a space-separated list of layout files
+that you'd like to inspect.</p>
+
+<p>When you run {@code layoutopt} on a layout file, it prints a line number for each issue found, a
+description of the issue, and for some types of issues it also suggests a resolution. For
+example:</p>
+
+<pre class="no-pretty-print classic">
+$ layoutopt samples/
+samples/compound.xml
+   7:23 The root-level &lt;FrameLayout/&gt; can be replaced with &lt;merge/&gt;
+   11:21 This LinearLayout layout or its FrameLayout parent is useless
+samples/simple.xml
+   7:7 The root-level &lt;FrameLayout/&gt; can be replaced with &lt;merge/&gt;
+</pre>
+
+<p>After you apply the suggested layout optimizations, run Hierarchy Viewer again to inspect the
+performance changes.</p>
+
diff --git a/docs/html/training/improving-layouts/reusing-layouts.jd b/docs/html/training/improving-layouts/reusing-layouts.jd
new file mode 100644
index 0000000..8f9729a
--- /dev/null
+++ b/docs/html/training/improving-layouts/reusing-layouts.jd
@@ -0,0 +1,150 @@
+page.title=Re-using Layouts with &lt;include/&gt;
+parent.title=Improving Performance of Layouts
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Optimizing Layout Hierarchies
+previous.link=optimizing-layout.html
+next.title=Loading Views On Demand
+next.link=loading-ondemand.html
+
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#Create">Create a Re-usable Layout</a></li>
+  <li><a href="#Include">Use the &lt;include&gt; Tag</a></li>
+  <li><a href="#Merge">Use the &lt;merge&gt; Tag</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}resources/articles/layout-tricks-reuse.html">Creating Reusable UI
+Components</a></li>
+  <li><a href="{@docRoot}resources/articles/layout-tricks-merge.html">Merging Layouts</a></li>
+  <li><a
+href="{@docRoot}guide/topics/resources/layout-resource.html#include-element">Layout
+Resource</a></li>
+</ul>
+
+</div>
+</div>
+
+
+
+<p>Although Android offers a variety of widgets to provide small and re-usable interactive elements,
+you might also need to re-use larger components that require a special layout. To efficiently
+re-use complete layouts, you can use the {@code &lt;include/&gt;} and {@code &lt;merge/&gt;} tags
+to embed another layout inside the current layout.</p>
+
+<p>Reusing layouts is particularly powerful as it allows you create reusable complex layouts. For
+example, a yes/no button panel, or custom progress bar with description text.
+It also means that any elements of your application that are common across multiple layouts can be
+extracted, managed separately, then included in each layout. So while 
+you can create individual UI components by writing a custom {@link android.view.View}, you can
+do it even more easily by re-using a layout file.</p>
+
+
+<h2 id="Create">Create a Re-usable Layout</h2>
+
+<p>If you already know the layout that you want to re-use, create a new XML file and define the
+layout. For example, here's a layout from the G-Kenya codelab that defines a title bar to be
+included in each activity (<code>titlebar.xml</code>):</p>
+
+<pre>
+&lt;FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width=”match_parent”
+    android:layout_height="wrap_content"
+    android:background="&#64;color/titlebar_bg">
+
+    &lt;ImageView android:layout_width="wrap_content"
+               android:layout_height="wrap_content" 
+               android:src="&#64;drawable/gafricalogo" />
+&lt;/FrameLayout>
+</pre>
+
+<p>The root {@link android.view.View} should be exactly how you'd like it to appear in each
+layout to which you add this layout.</p>
+
+
+<h2 id="Include">Use the &lt;include&gt; Tag</h2>
+
+<p>Inside the layout to which you want to add the re-usable component, add the {@code
+&lt;include/&gt;} tag. For example, here's a layout from the
+G-Kenya codelab that includes the title bar from above:</p>
+
+<p>Here's the layout file:</p>
+
+<pre>
+&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical" 
+    android:layout_width=”match_parent”
+    android:layout_height=”match_parent”
+    android:background="&#64;color/app_bg"
+    android:gravity="center_horizontal">
+
+    <strong>&lt;include layout="&#64;layout/titlebar"/></strong>
+
+    &lt;TextView android:layout_width=”match_parent”
+              android:layout_height="wrap_content"
+              android:text="&#64;string/hello"
+              android:padding="10dp" />
+
+    ...
+
+&lt;/LinearLayout>
+</pre>
+
+<p>You can also override all the layout parameters (any {@code android:layout_*} attributes) of the
+included layout's root view by specifying them in the {@code &lt;include/&gt;} tag. For
+example:</p>
+
+<pre>
+&lt;include android:id=”&#64;+id/news_title”
+         android:layout_width=”match_parent”
+         android:layout_height=”match_parent”
+         layout=”@layout/title”/>
+</pre>
+
+
+
+<h2 id="Merge">Use the &lt;merge&gt; Tag</h2>
+
+<p>The {@code &lt;merge />} tag helps eliminate redundant view groups in your view hierarchy
+when including one layout within another. For example, if your main layout is a vertical {@link
+android.widget.LinearLayout} in which two consecutive views can be
+re-used in multiple layouts, then the re-usable layout in which you place the two views requires its
+own root view. However, using another {@link android.widget.LinearLayout} as the root for the
+re-usable layout would result in a vertical {@link android.widget.LinearLayout} inside a
+vertical {@link android.widget.LinearLayout}. The nested {@link android.widget.LinearLayout}
+serves no real purpose other than to slow down your UI performance.</p>
+
+<p>To avoid including such a redundant view group, you can instead use the
+{@code &lt;merge&gt;} element as the root view for the re-usable layout. For example:</p>
+
+<pre>
+&lt;merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    &lt;Button
+        android:layout_width="fill_parent" 
+        android:layout_height="wrap_content"
+        android:text="@string/add"/>
+
+    &lt;Button
+        android:layout_width="fill_parent" 
+        android:layout_height="wrap_content"
+        android:text="@string/delete"/>
+
+&lt;/merge>
+</pre>
+
+<p>Now, when you include this layout in another layout (using the {@code &lt;include/&gt;} tag), the
+system ignores the {@code &lt;merge&gt;} element and places the two buttons directly in the
+layout, in place of the {@code &lt;include/&gt;} tag.</p>
+
diff --git a/docs/html/training/improving-layouts/smooth-scrolling.jd b/docs/html/training/improving-layouts/smooth-scrolling.jd
new file mode 100644
index 0000000..bc90dd2
--- /dev/null
+++ b/docs/html/training/improving-layouts/smooth-scrolling.jd
@@ -0,0 +1,124 @@
+page.title=Making ListView Scrolling Smooth
+parent.title=Optimizing Performance of Layouts
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Loading Views On Demand
+previous.link=loading-ondemand.html
+
+@jd:body
+
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#AsyncTask">Use a Background Thread</a></li>
+  <li><a href="#ViewHolder">Hold View Objects in a View Holder</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}resources/articles/listview-backgrounds.html">ListView
+Backgrounds: An Optimization</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>The key to a smoothly scrolling {@link android.widget.ListView} is to keep the application’s main
+thread (the UI thread) free from heavy processing. Ensure you do any disk access, network access, or
+SQL access in a separate thread. To test the status of your app, you can enable {@link
+android.os.StrictMode}.</p>
+
+
+<h2 id="AsyncTask">Use a Background Thread</h2>
+
+<p>Using a background thread ("worker thread") removes strain from the main thread so it can focus
+on drawing the UI. In many cases, using {@link android.os.AsyncTask} provides a simple way to
+perform your work outside the main thread. {@link android.os.AsyncTask} automatically queues up all
+the {@link android.os.AsyncTask#execute execute()} requests and performs them serially. This
+behavior is global to a particular process and means you don’t need to worry about creating your
+own thread pool.</p>
+
+<p>In the sample code below, an {@link android.os.AsyncTask} is used to load
+images in a background thread, then apply them to the UI once finished. It also shows a
+progress spinner in place of the images while they are loading.</p>
+
+<pre>
+// Using an AsyncTask to load the slow images in a background thread
+new AsyncTask&lt;ViewHolder, Void, Bitmap>() {
+    private ViewHolder v;
+
+    &#64;Override
+    protected Bitmap doInBackground(ViewHolder... params) {
+        v = params[0];
+        return mFakeImageLoader.getImage();
+    }
+
+    &#64;Override
+    protected void onPostExecute(Bitmap result) {
+        super.onPostExecute(result);
+        if (v.position == position) {
+            // If this item hasn't been recycled already, hide the
+            // progress and set and show the image
+            v.progress.setVisibility(View.GONE);
+            v.icon.setVisibility(View.VISIBLE);
+            v.icon.setImageBitmap(result);
+        }
+    }
+}.execute(holder);
+</pre>
+
+<p>Beginning with Android 3.0 (API level 11), an extra feature is available in {@link
+android.os.AsyncTask} so you can enable it to run across multiple processor cores. Instead of
+calling {@link android.os.AsyncTask#execute execute()} you can specify {@link
+android.os.AsyncTask#executeOnExecutor executeOnExecutor()} and multiple requests can be executed at
+the same time depending on the number of cores available.</p>
+
+
+<h2 id="ViewHolder">Hold View Objects in a View Holder</h2>
+
+<p>Your code might call {@link android.app.Activity#findViewById findViewById()} frequently
+during the scrolling of {@link android.widget.ListView}, which can slow down performance. Even when
+the {@link
+android.widget.Adapter} returns an inflated view for recycling, you still need to look up the
+elements
+and update them. A way around repeated use of {@link android.app.Activity#findViewById
+findViewById()} is to use the "view holder" design pattern.</p>
+
+<p>A {@code ViewHolder} object stores each of the component views inside the tag field of the
+Layout, so you can immediately access them without the need to look them up repeatedly. First, you
+need to create a class to hold your exact set of views. For example:</p>
+
+<pre>
+static class ViewHolder {
+  TextView text;
+  TextView timestamp;
+  ImageView icon;
+  ProgressBar progress;
+  int position;
+}
+</pre>
+
+<p>Then populate the {@code ViewHolder} and store it inside the layout.</p>
+
+<pre>
+ViewHolder holder = new ViewHolder();
+holder.icon = (ImageView) convertView.findViewById(R.id.listitem_image);
+holder.text = (TextView) convertView.findViewById(R.id.listitem_text);
+holder.timestamp = (TextView) convertView.findViewById(R.id.listitem_timestamp);
+holder.progress = (ProgressBar) convertView.findViewById(R.id.progress_spinner);
+convertView.setTag(holder);
+</pre>
+
+<p>Now you can easily access each view without the need for the look-up, saving valuable processor
+cycles.</p>
+
+
+
+
+
diff --git a/docs/html/training/managing-audio/audio-focus.jd b/docs/html/training/managing-audio/audio-focus.jd
new file mode 100644
index 0000000..07a4465
--- /dev/null
+++ b/docs/html/training/managing-audio/audio-focus.jd
@@ -0,0 +1,183 @@
+page.title=Managing Audio Focus
+parent.title=Managing Audio Playback and Focus
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Controlling Your App's Volume and Playback
+previous.link=volume-playback.html
+next.title=Dealing with Audio Output Hardware
+next.link=audio-output.html
+
+@jd:body
+
+
+<div id="tb-wrapper"> 
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#RequestFocus">Request the Audio Focus</a></li>
+  <li><a href="#HandleFocusLoss">Handle the Loss of Audio Focus</a></li>
+  <li><a href="#DUCK">Duck!</a></li>
+</ol>
+
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a></li>
+</ul>
+
+</div> 
+</div>
+ 
+
+<p>With multiple apps potentially playing audio it's important to think about how they should
+interact. To avoid every music app playing at the same time, Android uses audio focus to moderate
+audio playback&mdash;only apps that hold the audio focus should play audio.</p>
+
+<p>Before your app starts playing audio it should request&mdash;and receive&mdash;the audio focus. 
+Likewise, it should know how to listen for a loss of audio focus and respond appropriately when that
+happens.</p>
+
+ 
+<h2 id="RequestFocus">Request the Audio Focus</h2> 
+ 
+<p>Before your app starts playing any audio, it should hold the audio focus for the stream
+it will be using. This is done with a call to {@link android.media.AudioManager#requestAudioFocus
+requestAudioFocus()} which returns
+{@link android.media.AudioManager#AUDIOFOCUS_REQUEST_GRANTED} if your request is successful.</p>
+
+<p>You must specify which stream you're using and whether you expect to require transient or
+permanent audio focus. Request transient focus when you expect to play audio for only a short time
+(for example when playing navigation instructions). Request permanent audio focus when you
+plan to play audio for the foreseeable future (for example, when playing music).</p>
+
+<p>The following snippet requests permanent audio focus on the music audio stream. You should
+request the audio focus immediately before you begin playback, such as when the user presses
+play or the background music for the next game level begins.</p>
+  
+<pre>
+AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
+...
+
+// Request audio focus for playback
+int result = am.requestAudioFocus(afChangeListener,
+                                 // Use the music stream.
+                                 AudioManager.STREAM_MUSIC,
+                                 // Request permanent focus.
+                                 AudioManager.AUDIOFOCUS_GAIN);
+   
+if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+    am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
+    // Start playback.
+}
+</pre>
+
+<p>Once you've finished playback be sure to call {@link
+android.media.AudioManager#abandonAudioFocus abandonAudioFocus()}. This notifies
+the system that you no longer require focus and unregisters the associated {@link
+android.media.AudioManager.OnAudioFocusChangeListener}. In the case of abandoning transient focus,
+this allows any interupted app to continue playback.</p>
+
+<pre>
+// Abandon audio focus when playback complete    
+am.abandonAudioFocus(afChangeListener);
+</pre>
+
+<p>When requesting transient audio focus you have an additional option: whether or not you want to
+enable "ducking." Normally, when a well-behaved audio app loses audio focus it immediately
+silences its playback. By requesting a transient audio focus that allows ducking you tell other
+audio apps that it’s acceptable for them to keep playing, provided they lower their volume until the
+focus returns to them.</p>
+
+<pre>
+// Request audio focus for playback
+int result = am.requestAudioFocus(afChangeListener,
+                             // Use the music stream.
+                             AudioManager.STREAM_MUSIC,
+                             // Request permanent focus.
+                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+   
+if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+    // Start playback.
+}
+</pre>
+
+<p>Ducking is particularly suitable for apps that use the audio stream intermittently, such as for
+audible driving directions.</p>
+
+<p>Whenever another app requests audio focus as described above, its choice between permanent and
+transient (with or without support for ducking) audio focus is received by the listener you
+registered when requesting focus.</p>
+
+
+<h2 id="HandleFocusLoss">Handle the Loss of Audio Focus</h2> 
+
+<p>If your app can request audio focus, it follows that it will in turn lose that focus when another
+app requests it. How your app responds to a loss of audio focus depends on the manner of that
+loss.</p>
+
+<p>The {@link android.media.AudioManager.OnAudioFocusChangeListener#onAudioFocusChange
+onAudioFocusChange()} callback method of they audio focus change listener you registered when
+requesting audio focus receives a parameter that describes the focus change event. Specifically,
+the possible focus loss events mirror the focus request types from the previous
+section&mdash;permanent loss, transient loss, and transient with ducking permitted.</p>
+
+<p>Generally speaking, a transient (temporary) loss of audio focus should result in your app
+silencing it’s audio stream, but otherwise maintaining the same state. You should continue to
+monitor changes in audio focus and be prepared to resume playback where it was paused once you’ve
+regained the focus.</p>
+
+<p>If the audio focus loss is permanent, it’s assumed that another application is now being used to
+listen to audio and your app should effectively end itself. In practical terms, that means stopping
+playback, removing media button listeners&mdash;allowing the new audio player to exclusively handle
+those events&mdash;and abandoning your audio focus. At that point, you would expect a user action
+(pressing play in your app) to be required before you resume playing audio.</p>
+
+<p>In the following code snippet, we pause the playback or our media player object if the audio
+loss is transien and resume it when we have regained the focus. If the loss is permanent, it
+unregisters our media button event receiver and stops monitoring audio focus changes.<p>
+
+<pre>
+OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
+    public void onAudioFocusChange(int focusChange) {
+        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
+            // Pause playback
+        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
+            // Resume playback 
+        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
+            am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
+            am.abandonAudioFocus(afChangeListener);
+            // Stop playback
+        }
+    }
+};
+</pre>
+ 
+<p>In the case of a transient loss of audio focus where ducking is permitted, rather than pausing
+playback, you can "duck" instead.</p>
+
+
+<h2 id="DUCK">Duck!</h2> 
+
+<p>Ducking is the process of lowering your audio stream output volume to make transient audio from
+another app easier to hear without totally disrupting the audio from your own application.</p>
+
+<p>In the following code snippet lowers the volume on our media player object when we temporarily
+lose focus, then returns it to its previous level when we regain focus.</p>
+
+<pre>
+OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
+    public void onAudioFocusChange(int focusChange) {
+        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
+            // Lower the volume
+        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
+            // Raise it back to normal
+        }
+    }
+};
+</pre>
+
+<p>A loss of audio focus is the most important broadcast to react to, but not the only one. The
+system broadcasts a number of intents to alert you to changes in user’s audio experience.
+The next lesson demonstrates how to monitor them to improve the user’s overall experience.</p>
diff --git a/docs/html/training/managing-audio/audio-output.jd b/docs/html/training/managing-audio/audio-output.jd
new file mode 100644
index 0000000..d5d7e4b
--- /dev/null
+++ b/docs/html/training/managing-audio/audio-output.jd
@@ -0,0 +1,88 @@
+page.title=Dealing with Audio Output Hardware
+parent.title=Managing Audio Playback and Focus
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Managing Audio Focus
+previous.link=audio-focus.html
+
+@jd:body
+
+ 
+<div id="tb-wrapper"> 
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#CheckHardware">Check What Hardware is Being Used</a></li>
+  <li><a href="#HandleChanges">Handle Changes in the Audio Output Hardware</a></li>
+</ol>
+
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a></li>
+</ul>
+
+
+</div> 
+</div>
+
+<p>Users have a number of alternatives when it comes to enjoying the audio from their Android
+devices. Most devices have a built-in speaker, headphone jacks for wired headsets, and many also
+feature Bluetooth connectivity and support for A2DP audio. </p>
+
+ 
+<h2 id="CheckHardware">Check What Hardware is Being Used</h2> 
+ 
+<p>How your app behaves might be affected by which hardware its output is being routed to.</p>
+
+<p>You can query the {@link android.media.AudioManager} to determine if the audio is currently
+being routed to the device speaker, wired headset, or attached Bluetooth device as shown in the
+following snippet:</p>
+
+<pre>
+if (isBluetoothA2dpOn()) {
+    // Adjust output for Bluetooth.
+} else if (isSpeakerphoneOn()) {
+    // Adjust output for Speakerphone.
+} else if (isWiredHeadsetOn()) {
+    // Adjust output for headsets
+} else { 
+    // If audio plays and noone can hear it, is it still playing?
+}
+</pre>
+
+
+<h2 id="HandleChanges">Handle Changes in the Audio Output Hardware</h2> 
+
+<p>When a headset is unplugged, or a Bluetooth device disconnected, the audio stream
+automatically reroutes to the built in speaker. If you listen to your music at as high a volume as I
+do, that can be a noisy surprise.</p>
+
+<p>Luckily the system broadcasts an {@link android.media.AudioManager#ACTION_AUDIO_BECOMING_NOISY}
+intent when this happens. It’s good practice to register a {@link android.content.BroadcastReceiver}
+that listens for this intent whenever you’re playing audio. In the case of music players, users
+typically expect the playback to be paused&mdash;while for games you may choose to significantly
+lower the volume.</p>
+ 
+<pre>
+private class NoisyAudioStreamReceiver extends BroadcastReceiver {
+    &#64;Override
+    public void onReceive(Context context, Intent intent) {
+        if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
+            // Pause the playback
+        }
+    }
+}
+
+private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+
+private void startPlayback() {
+    registerReceiver(myNoisyAudioStreamReceiver(), intentFilter);
+}
+
+private void stopPlayback() {
+    unregisterReceiver(myNoisyAudioStreamReceiver);
+}
+</pre>
diff --git a/docs/html/training/managing-audio/index.jd b/docs/html/training/managing-audio/index.jd
new file mode 100644
index 0000000..c7df39b
--- /dev/null
+++ b/docs/html/training/managing-audio/index.jd
@@ -0,0 +1,62 @@
+page.title=Managing Audio Playback and Focus
+
+trainingnavtop=true
+startpage=true
+next.title=Controlling Your App's Volume and Playback
+next.link=volume-playback.html
+
+@jd:body
+
+<div id="tb-wrapper"> 
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2> 
+<ul>
+  <li>Android 2.0 (API level 5) or higher</li>
+  <li>Experience with <a href="{@docRoot}guide/topics/media/mediaplayer.html">Media
+Playback</a></li>
+</ul>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a></li>
+</ul>
+
+</div> 
+</div>
+
+
+<p>If your app plays audio, it’s important that your users can control the audio in a predictable
+manner. To ensure a great user experience, it’s also important that your app manages the audio focus
+to ensure multiple apps aren’t playing audio at the same time.</p> 
+
+<p>After this class, you will be able to build apps that respond to hardware audio key presses, 
+which request audio focus when playing audio, and which respond appropriately to changes in audio
+focus caused by the system or other applications.</p> 
+
+
+
+
+<h2>Lessons</h2> 
+ 
+<!-- Create a list of the lessons in this class along with a short description of each lesson.
+These should be short and to the point. It should be clear from reading the summary whether someone
+will want to jump to a lesson or not.--> 
+ 
+<dl>
+  <dt><b><a href="volume-playback.html">Controlling Your App’s Volume and
+Playback</a></b></dt>
+  <dd>Learn how to ensure your users can control the volume of your app using the hardware or
+software volume controls and where available the play, stop, pause, skip, and previous media
+playback keys.</dd> 
+ 
+  <dt><b><a href="audio-focus.html">Managing Audio Focus</a></b></dt>
+  <dd>With multiple apps potentially playing audio it's important to think about how they should
+interact. To avoid every music app playing at the same time, Android uses audio focus to moderate
+audio playback. Learn how to request the audio focus, listen for a loss of audio focus, and how to
+respond when that happens.</dd> 
+ 
+  <dt><b><a href="audio-output.html">Dealing with Audio Output Hardware</a></b></dt>
+  <dd>Audio can be played from a number of sources. Learn how to find out where the audio is being
+played and how to handle a headset being disconnected during playback.</dd> 
+ </dl> 
\ No newline at end of file
diff --git a/docs/html/training/managing-audio/volume-playback.jd b/docs/html/training/managing-audio/volume-playback.jd
new file mode 100644
index 0000000..7038ddf
--- /dev/null
+++ b/docs/html/training/managing-audio/volume-playback.jd
@@ -0,0 +1,156 @@
+page.title=Controlling Your App’s Volume and Playback
+parent.title=Managing Audio Playback and Focus
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Managing Audio Focus
+next.link=audio-focus.html
+
+@jd:body
+
+ 
+<div id="tb-wrapper"> 
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#IdentifyStream">Identify Which Audio Stream to Use</a></li>
+  <li><a href="#HardwareVolumeKeys">Use Hardware Volume Keys to Control Your App’s Audio
+Volume</a></li>
+  <li><a href="#PlaybackControls">Use Hardware Playback Control Keys to Control Your App’s Audio
+Playback</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a></li>
+</ul>
+
+</div> 
+</div>
+
+
+ 
+<p>A good user experience is a predictable one. If your app plays media it’s important that your
+users can control the volume of your app using the hardware or software volume controls of their
+device, bluetooth headset, or headphones.</p>
+
+<p>Similarly, where appropriate and available, the play, stop, pause, skip, and previous media
+playback keys should perform their respective actions on the audio stream used by your app.</p>
+
+ 
+<h2 id="IdentifyStream">Identify Which Audio Stream to Use</h2> 
+ 
+<p>The first step to creating a predictable audio experience is understanding which audio stream
+your app will use.</p>
+
+<p>Android maintains a separate audio stream for playing music, alarms, notifications, the incoming
+call ringer, system sounds, in-call volume, and DTMF tones. This is done primarily to allow users to
+control the volume of each stream independently.</p>
+
+<p>Most of these streams are restricted to system events, so unless your app is a replacement alarm
+clock, you’ll almost certainly be playing your audio using the {@link
+android.media.AudioManager#STREAM_MUSIC} stream.</p>
+
+
+<h2 id="HardwareVolumeKeys">Use Hardware Volume Keys to Control Your App’s Audio Volume</h2> 
+
+<p>By default, pressing the volume controls modify the volume of the active audio stream. If your
+app isn't currently playing anything, hitting the volume keys adjusts the ringer volume.<p>
+    
+<p>If you've got a game or music app, then chances are good that when the user hits the volume keys
+they want to control the volume of the game or music, even if they’re currently between songs or
+there’s no music in the current game location.</p>
+
+<p>You may be tempted to try and listen for volume key presses and modify the volume of your
+audio stream that way. Resist the urge. Android provides the handy {@link
+android.app.Activity#setVolumeControlStream setVolumeControlStream()} method to direct volume key
+presses to the audio stream you specify.<p> 
+  
+<p>Having identified the audio stream your application
+will be using, you should set it as the volume stream target. You should make this call early in
+your app’s lifecycle&mdash;because you only need to call it once during the activity lifecycle, you
+should typically call it within the {@code onCreate()} method (of the {@link
+android.app.Activity} or {@link android.app.Fragment} that controls
+your media). This ensures that whenever your app is visible, the
+volume controls function as the user expects.<p>
+
+<pre>
+setVolumeControlStream(AudioManager.STREAM_MUSIC);
+</pre>
+
+
+<p>From this point onwards, pressing the volume keys on the device affect the audio stream you
+specify (in this case “music”) whenever the target activity or fragment is visible.</p>
+
+
+<h2 id="PlaybackControls">Use Hardware Playback Control Keys to Control Your App’s Audio
+Playback</h2> 
+
+<p>Media playback buttons such as play, pause, stop, skip, and previous are available on some
+handsets and many connected or wireless headsets. Whenever a user presses one of these hardware
+keys, the system broadcasts an intent with the {@link android.content.Intent#ACTION_MEDIA_BUTTON}
+action.</p>
+
+<p>To respond to media button clicks, you need to register a {@link
+android.content.BroadcastReceiver} in your manifest that listens for this action broadcast as shown
+below.</p>
+
+<pre>
+&lt;receiver android:name=".RemoteControlReceiver">
+    &lt;intent-filter>
+        &lt;action android:name="android.intent.action.MEDIA_BUTTON" />
+    &lt;/intent-filter>
+&lt;/receiver>
+</pre>
+
+<p>The receiver implementation itself needs to extract which key was pressed to cause the broadcast.
+The {@link android.content.Intent} includes this under the {@link
+android.content.Intent#EXTRA_KEY_EVENT} key, while the {@link android.view.KeyEvent} class includes
+a list {@code KEYCODE_MEDIA_*} static constants that represents each of the possible media
+buttons, such as {@link android.view.KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE} and {@link
+android.view.KeyEvent#KEYCODE_MEDIA_NEXT}.</p>
+
+<p>The following snippet shows how to extract the media button pressed and affects the media playback accordingly.</p>
+
+<pre>
+public class RemoteControlReceiver extends BroadcastReceiver {
+    &#64;Override
+    public void onReceive(Context context, Intent intent) {
+        if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
+            KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+            if (KeyEvent.KEYCODE_MEDIA_PLAY == event.getKeyCode()) {
+                // Handle key press.
+            }
+        }
+    }
+}
+</pre>
+
+<p>Because multiple applications might want to listen for media button presses, you must
+also programmatically control when your app should receive media button press events.</p>
+
+<p>The following code can be used within your app to register and de-register your media button
+event receiver using the {@link android.media.AudioManager}. When registered, your broadcast
+receiver is the exclusive receiver of all media button broadcasts.<p>
+
+<pre>
+AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
+...
+
+// Start listening for button presses
+am.registerMediaButtonEventReceiver(RemoteControlReceiver);
+...
+
+// Stop listening for button presses
+am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
+</pre>
+
+<p>Typically, apps should unregister most of their receivers whenever they become inactive or
+invisible (such as during the {@link android.app.Activity#onStop onStop()} callback). However, it’s
+not that simple for media playback apps&mdash;in fact, responding to media playback buttons is most
+important when your application isn’t visible and therefore can’t be controlled by the on-screen
+UI.</p>
+
+<p>A better approach is to register and unregister the media button event receiver when your
+application gains and losses the audio focus. This is covered in detail in the next lesson.</p>
diff --git a/docs/html/training/monitoring-device-state/battery-monitoring.jd b/docs/html/training/monitoring-device-state/battery-monitoring.jd
new file mode 100644
index 0000000..a442140
--- /dev/null
+++ b/docs/html/training/monitoring-device-state/battery-monitoring.jd
@@ -0,0 +1,156 @@
+page.title=Monitoring the Battery Level and Charging State
+parent.title=Monitoring Device State to Optimize Battery Life
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Determining and Monitoring the Docking State and Type
+next.link=docking-monitoring.html
+
+@jd:body
+ 
+<div id="tb-wrapper"> 
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#DetermineChargeState">Determine the Current Charging State</a></li>
+  <li><a href="#MonitorChargeState">Monitor Changes in Charging State</a></li>
+  <li><a href="#CurrentLevel">Determine the Current Battery Level</a></li>
+  <li><a href="#MonitorLevel">Monitor Significant Changes in Battery Level</a></li>
+</ol>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>
+</ul>
+
+</div> 
+</div>
+ 
+<p>When you're altering the frequency of your background updates to reduce the effect of those
+updates on battery life, checking the current battery level and charging state is a good place to
+start.</p>
+
+<p>The battery-life impact of performing application updates depends on the battery level and
+charging state of the device. The impact of performing updates while the device is charging over AC
+is negligible, so in most cases you can maximize your refresh rate whenever the device is connected
+to a wall charger. Conversely, if the device is discharging, reducing your update rate helps
+prolong the battery life.</p>
+
+<p>Similarly, you can check the battery charge level, potentially reducing the frequency of&mdash;or
+even stopping&mdash;your updates when the battery charge is nearly exhausted.</p>
+
+
+<h2 id="DetermineChargeState">Determine the Current Charging State</h2> 
+ 
+<p>Start by determining the current charge status. The {@link android.os.BatteryManager}
+broadcasts all battery and charging details in a sticky {@link android.content.Intent} that includes
+the charging status.</p>
+
+<p>Because it's a sticky intent, you don't need to register a {@link
+android.content.BroadcastReceiver}&mdash;by simply calling {@code registerReceiver} passing in
+{@code null} as the receiver as shown in the next snippet, the current battery status intent is
+returned. You could pass in an actual {@link android.content.BroadcastReceiver} object here, but
+we'll be handling updates in a later section so it's not necessary.</p>
+
+<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+Intent batteryStatus = context.registerReceiver(null, ifilter);</pre>
+
+<p>You can extract both the current charging status and, if the device is being charged, whether
+it's charging via USB or AC charger:<p>
+
+<pre>// Are we charging / charged?
+int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
+                     status == BatteryManager.BATTERY_STATUS_FULL;
+
+// How are we charging?
+int chargePlug = battery.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB;
+boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;</pre>
+
+<p>Typically you should maximize the rate of your background updates in the case where the device is
+connected to an AC charger, reduce the rate if the charge is over USB, and lower it
+further if the battery is discharging.</p>
+
+
+<h2 id="MonitorChargeState">Monitor Changes in Charging State</h2> 
+
+<p>The charging status can change as easily as a device can be plugged in, so it's important to
+monitor the charging state for changes and alter your refresh rate accordingly.</p>
+
+<p>The {@link android.os.BatteryManager} broadcasts an action whenever the device is connected or
+disconnected from power. It's important to to receive these events even while your app isn't
+running&mdash;particularly as these events should impact how often you start your app in order to
+initiate a background update&mdash;so you should register a {@link
+android.content.BroadcastReceiver} in your manifest to listen for both events by defining the
+{@link android.content.Intent#ACTION_POWER_CONNECTED} and {@link
+android.content.Intent#ACTION_POWER_DISCONNECTED} within an intent filter.</p>
+
+<pre>&lt;receiver android:name=".PowerConnectionReceiver">
+  &lt;intent-filter>
+    &lt;action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
+    &lt;action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
+  &lt;/intent-filter>
+&lt;/receiver></pre>
+
+<p>Within the associated {@link android.content.BroadcastReceiver} implementation, you can extract
+the current charging state and method as described in the previous step.</p>
+
+<pre>public class PowerConnectionReceiver extends BroadcastReceiver {
+    &#64;Override
+    public void onReceive(Context context, Intent intent) { 
+        int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+        boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
+                            status == BatteryManager.BATTERY_STATUS_FULL;
+    
+        int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+        boolean usbCharge = chargePlug == BATTERY_PLUGGED_USB;
+        boolean acCharge = chargePlug == BATTERY_PLUGGED_AC;
+    }
+}</pre>
+
+
+<h2 id="CurrentLevel">Determine the Current Battery Level</h2> 
+
+<p>In some cases it's also useful to determine the current battery level. You may choose to reduce
+the rate of your background updates if the battery charge is below a certain level.</p>
+
+<p>You can find the current battery charge by extracting the current battery level and scale from
+the battery status intent as shown here:</p>
+
+<pre>int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+int scale = battery.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+
+float batteryPct = level / (float)scale;</pre>
+
+
+<h2 id="MonitorLevel">Monitor Significant Changes in Battery Level</h2> 
+
+<p>You can't easily continually monitor the battery state, but you don't need to.</p>
+
+<p>Generally speaking, the impact of constantly monitoring the battery level has a greater
+impact on the battery than your app's normal behavior, so it's good practice to only monitor
+significant changes in battery level&mdash;specifically when the device enters or exits a low
+battery state.</p>
+
+<p>The manifest snippet below is extracted from the intent filter element within a broadcast
+receiver. The receiver is triggered whenever the device battery becomes low or exits the low
+condition by listening for {@link android.content.Intent#ACTION_BATTERY_LOW} and {@link
+android.content.Intent#ACTION_BATTERY_OKAY}.</p>
+
+<pre>&lt;receiver android:name=".BatteryLevelReceiver">
+&lt;intent-filter>
+  &lt;action android:name="android.intent.action.ACTION_BATTERY_LOW"/>
+  &lt;action android:name="android.intent.action.ACTION_BATTERY_OKAY"/>
+  &lt;/intent-filter>
+&lt;/receiver></pre>
+
+<p>It is generally good practice to disable all your background updates when the battery is
+critically low. It doesn't matter how fresh your data is if the phone turns itself off before you
+can make use of it.</p>
+
+<p>In many cases, the act of charging a device is coincident with putting it into a dock. The next
+lesson shows you how to determine the current dock state and monitor for changes in device
+docking.</p>
+
diff --git a/docs/html/training/monitoring-device-state/connectivity-monitoring.jd b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
new file mode 100644
index 0000000..4c71279
--- /dev/null
+++ b/docs/html/training/monitoring-device-state/connectivity-monitoring.jd
@@ -0,0 +1,90 @@
+page.title=Determining and Monitoring the Connectivity Status
+parent.title=Monitoring Device State to Optimize Battery Life
+parent.link=index.html
+
+trainingnavtop=true
+
+previous.title=Determining and Monitoring the Docking State and Type
+previous.link=docking-monitoring.html
+next.title=Manipulating Broadcast Receivers On Demand
+next.link=manifest-receivers.html
+
+@jd:body
+
+<div id="tb-wrapper"> 
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#DetermineConnection">Determine if you Have an Internet Connection</a></li>
+  <li><a href="#DetermineType">Determine the Type of your Internet Connection</a></li>
+  <li><a href="#MonitorChanges">Monitor for Changes in Connectivity</a></li>
+</ol>
+
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>
+</ul>
+
+</div> 
+</div>
+
+<p>Some of the most common uses for repeating alarms and background services is to schedule regular
+updates of application data from Internet resources, cache data, or execute long running downloads.
+But if you aren't connected to the Internet, or the connection is too slow to complete your
+download, why both waking the device to schedule the update at all?</p>
+
+<p>You can use the {@link android.net.ConnectivityManager} to check that you're actually
+connected to the Internet, and if so, what type of connection is in place.</p>
+
+
+<h2 id="DetermineConnection">Determine if You Have an Internet Connection</h2> 
+ 
+<p>There's no need to schedule an update based on an Internet resource if you aren't connected to
+the Internet. The following snippet shows how to use the {@link android.net.ConnectivityManager} 
+to query the active network and determine if it has Internet connectivity.</p>
+
+<pre>ConnectivityManager cm =
+        (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ 
+NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
+boolean isConnected = activeNetwork.isConnectedOrConnecting();</pre>
+
+
+<h2 id="DetermineType">Determine the Type of your Internet Connection</h2> 
+
+<p>It's also possible to determine the type of Internet connection currently available.</p>
+
+<p>Device connectivity can be provided by mobile data, WiMAX, Wi-Fi, and ethernet connections. By
+querying the type of the active network, as shown below, you can alter your refresh rate based on
+the bandwidth available.</p>
+
+<pre>boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;</pre>
+
+<p>Mobile data costs tend to be significantly higher than Wi-Fi, so in most cases, your app's update
+rate should be lower when on mobile connections. Similarly, downloads of significant size should be
+suspended until you have a Wi-Fi connection.</p>
+
+<p>Having disabled your updates, it's important that you listen for changes in connectivity in order
+to resume them once an Internet connection has been established.</p>
+
+
+<h2 id="MonitorChanges">Monitor for Changes in Connectivity</h2> 
+
+<p>The {@link android.net.ConnectivityManager} broadcasts the {@link
+android.net.ConnectivityManager#CONNECTIVITY_ACTION} ({@code
+"android.net.conn.CONNECTIVITY_CHANGE"}) action whenever the connectivity details have changed. You
+can register a broadcast receiver in your manifest to listen for these changes and resume (or
+suspend) your background updates accordingly.</p>
+
+<pre>&lt;action android:name="android.net.conn.CONNECTIVITY_CHANGE"/></pre>
+
+<p>Changes to a device's connectivity can be very frequent&mdash;this broadcast is triggered
+every time you move between mobile data and Wi-Fi. As a result, it's good practice to monitor
+this broadcast only when you've previously suspended updates or downloads in order to resume them.
+It's generally sufficient to simply check for Internet connectivity before beginning an update and,
+should there be none, suspend further updates until connectivity is restored.</p>
+
+<p>This technique requires toggling broadcast receivers you've declard in the manifest, which is
+described in the next lesson.</p>
diff --git a/docs/html/training/monitoring-device-state/docking-monitoring.jd b/docs/html/training/monitoring-device-state/docking-monitoring.jd
new file mode 100644
index 0000000..6a4a9a8
--- /dev/null
+++ b/docs/html/training/monitoring-device-state/docking-monitoring.jd
@@ -0,0 +1,90 @@
+page.title=Determining and Monitoring the Docking State and Type
+parent.title=Monitoring Device State to Optimize Battery Life
+parent.link=index.html
+
+trainingnavtop=true
+previous.title= Monitoring the Battery Level and Charging State
+previous.link=battery-monitoring.html
+next.title= Determining and Monitoring the Connectivity Status
+next.link=connectivity-monitoring.html
+
+@jd:body
+
+<div id="tb-wrapper"> 
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#CurrentDockState">Request the Audio Focus</a></li>
+  <li><a href="#DockType">Determine the Current Dock Type</a></li>
+  <li><a href="#MonitorDockState">Monitor for Changes in the Dock State or Type</a></li>
+</ol>
+
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>
+</ul>
+
+</div> 
+</div>
+
+<p>Android devices can be docked into several different kinds of docks. These include car or home
+docks and digital versus analog docks. The dock-state is typically closely linked to the charging
+state as many docks provide power to docked devices.</p>
+
+<p>How the dock-state of the phone affects your update rate depends on your app. You may choose
+to increase the update frequency of a sports center app when it's in the desktop dock, or disable
+your updates completely if the device is car docked. Conversely, you may choose to maximize your
+updates while car docked if your background service is updating traffic conditions.</p>
+
+<p>The dock state is also broadcast as a sticky {@link android.content.Intent}, allowing you to
+query if the device is docked or not, and if so, in which kind of dock.</p>
+
+
+<h2 id="CurrentDockState">Determine the Current Docking State</h2> 
+ 
+<p>The dock-state details are included as an extra in a sticky broadcast of the {@link
+android.content.Intent#ACTION_DOCK_EVENT} action. Because it's sticky, you don't need to register a
+{@link android.content.BroadcastReceiver}. You can simply call {@link
+android.content.Context#registerReceiver registerReceiver()} passing in {@code null} as the
+broadcast receiver as shown in the next snippet.</p>
+
+<pre>IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
+Intent dockStatus = context.registerReceiver(null, ifilter);</pre>
+
+<p>You can extract the current docking status from the {@code EXTRA_DOCK_STATE} extra:<p>
+
+<pre>int dockState = battery.getIntExtra(EXTRA_DOCK_STATE, -1);
+boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;</pre>
+
+
+<h2 id="DockType">Determine the Current Dock Type</h2> 
+
+<p>If a device is docked, it can be docked in any one of four different type of dock: 
+<ul><li>Car</li>
+<li>Desk</li>
+<li>Low-End (Analog) Desk</li>
+<li>High-End (Digital) Desk</li></ul></p>
+
+<p>Note that the latter two options were only introduced to Android in API level 11, so it's good
+practice to check for all three where you are only interested in the type of dock rather than it
+being digital or analog specifically:</p>
+
+<pre>boolean isCar = dockState == EXTRA_DOCK_STATE_CAR;
+boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK || 
+                 dockState == EXTRA_DOCK_STATE_LE_DESK ||
+                 dockState == EXTRA_DOCK_STATE_HE_DESK;</pre>
+
+
+<h2 id="MonitorDockState">Monitor for Changes in the Dock State or Type</h2> 
+
+<p>Whenever the the device is docked or undocked, the {@link
+android.content.Intent#ACTION_DOCK_EVENT} action is broadcast. To monitor changes in the
+device's dock-state, simply register a broadcast receiver in your application manifest as shown in
+the snippet below:</p>
+
+<pre>&lt;action android:name="android.intent.action.ACTION_DOCK_EVENT"/></pre>
+
+<p>You can extract the dock type and state within the receiver implementation using the same
+techniques described in the previous step.</p>
diff --git a/docs/html/training/monitoring-device-state/index.jd b/docs/html/training/monitoring-device-state/index.jd
new file mode 100644
index 0000000..e92e1e8
--- /dev/null
+++ b/docs/html/training/monitoring-device-state/index.jd
@@ -0,0 +1,63 @@
+page.title=Monitoring Device State to Optimize Battery Life
+
+trainingnavtop=true
+startpage=true
+next.title=Monitoring the Battery Level and Charging State
+next.link=battery-monitoring.html
+
+@jd:body
+
+<div id="tb-wrapper"> 
+<div id="tb">
+
+<h2>Dependencies and prerequisites</h2> 
+<ul>
+  <li>Android 2.0 (API level 5) or higher</li>
+  <li>Experience with <a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a></li>
+</ul>
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a>
+</ul>
+
+</div> 
+</div>
+
+<p>For your app to be a good citizen, it should seek to limit its impact on the battery life of its
+host device. After this class you will be able to build apps that monitor modify their functionality
+and behavior based on the state of the host device.</p>
+
+<p>By taking steps such as disabling background service updates when you lose connectivity, or
+reducing the rate of such updates when the battery level is low, you can ensure that the impact of
+your app on battery life is minimized, without compromising the user experience.</p>
+
+<h2>Lessons</h2> 
+ 
+<!-- Create a list of the lessons in this class along with a short description of each lesson.
+These should be short and to the point. It should be clear from reading the summary whether someone
+will want to jump to a lesson or not.--> 
+ 
+<dl>
+  <dt><b><a href="battery-monitoring.html">Monitoring the Battery Level and Charging State</a></b></dt>
+  <dd>Learn how to alter your app's update rate by determining, and monitoring, the current battery
+level and changes in charging state.</dd>
+
+  <dt><b><a href="docking-monitoring.html">Determining and Monitoring the Docking State and
+Type</a></b></dt>
+  <dd>Optimal refresh rates can vary based on how the host device is being used. Learn how to
+determine, and monitor, the docking state and type of dock being used to affect your app's
+behavior.</dd>
+
+  <dt><b><a href="connectivity-monitoring.html">Determining and Monitoring the Connectivity
+Status</a></b></dt>
+  <dd>Without Internet connectivity you can't update your app from an online source. Learn how to  
+check the connectivity status to alter your background update rate. You'll also learn to check for
+Wi-Fi or mobile connectivity before beginning high-bandwidth operations.</dd>
+
+  <dt><b><a href="manifest-receivers.html">Manipulating Broadcast Receivers On Demand</a></b></dt>
+  <dd>Broadcast receivers that you've declared in the manifest can be toggled at runtime to disable
+those that aren't necessary due to the current device state. Learn to improve
+efficiency by toggling and cascading state change receivers and delay actions until the device is in
+a specific state.</dd>
+</dl> 
\ No newline at end of file
diff --git a/docs/html/training/monitoring-device-state/manifest-receivers.jd b/docs/html/training/monitoring-device-state/manifest-receivers.jd
new file mode 100644
index 0000000..bf5462a
--- /dev/null
+++ b/docs/html/training/monitoring-device-state/manifest-receivers.jd
@@ -0,0 +1,64 @@
+page.title=Manipulating Broadcast Receivers On Demand
+parent.title=Monitoring Device State to Optimize Battery Life
+parent.link=index.html
+
+trainingnavtop=true
+
+previous.title=Determining and Monitoring the Connectivity Status
+previous.link=connectivity-monitoring.html
+
+@jd:body
+
+<div id="tb-wrapper"> 
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="ToggleReceivers">Toggle and Cascade State Change Receivers to Improve
+Efficiency</a></li>
+</ol>
+
+
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>
+</ul>
+
+</div> 
+</div>
+
+<p>The simplest way to monitor device state changes is to create a {@link
+android.content.BroadcastReceiver} for each state you're monitoring and register each of them in
+your application manifest. Then within each of these receivers you simply reschedule your recurring
+alarms based on the current device state.</p>
+
+<p>A side-effect of this approach is that your app will wake the device each time any of these
+receivers is triggered&mdash;potentially much more frequently than required.</p>
+
+<p>A better approach is to disable or enable the broadcast receivers at runtime. That way you can
+use the receivers you declared in the manifest as passive alarms that are triggered by system events
+only when necessary.</p>
+ 
+
+<h2 id="ToggleReceivers">Toggle and Cascade State Change Receivers to Improve Efficiency </h2> 
+ 
+<p>Use can use the {@link android.content.pm.PackageManager} to toggle the enabled state on any
+component defined in the manifest, including whichever broadcast receivers you wish to enable or
+disable as shown in the snippet below:</p>
+
+<pre>ComponentName receiver = new ComponentName(context, myReceiver.class);
+
+PackageManager pm = context.getPackageManager();
+
+pm.setComponentEnabledSetting(receiver,
+        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+        PackageManager.DONT_KILL_APP)</pre>
+
+<p>Using this technique, if you determine that connectivity has been lost, you can disable all of
+your receivers except the connectivity-change receiver. Conversely, once you are connected you can
+stop listening for connectivity changes and simply check to see if you're online immediately before
+performing an update and rescheduling a recurring update alarm.</p>
+
+<p>You can use the same technique to delay a download that requires higher bandwidth to complete.  
+Simply enable a broadcast receiver that listens for connectivity changes and initiates the
+download only after you are connected to Wi-Fi.</p>
diff --git a/docs/html/training/sharing/index.jd b/docs/html/training/sharing/index.jd
new file mode 100644
index 0000000..cb133c3
--- /dev/null
+++ b/docs/html/training/sharing/index.jd
@@ -0,0 +1,46 @@
+page.title=Sharing Content
+
+trainingnavtop=true
+startpage=true
+next.title=Sending Content to Other Apps
+next.link=send.html
+
+@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 1.0 or higher (greater requirements where noted)</li>
+  <li>Experience with <a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and
+Intent Filters</a></li>
+</ul>
+
+</div>
+</div>
+
+ 
+<p>One of the great things about Android applications is their ability to communicate and
+integrate with each other. Why reinvent functionality that isn't core to your application when it
+already exists in another application?</p> 
+
+<p>This class shows some common ways you can send and receive content between
+applications using {@link android.content.Intent} APIs and the {@link
+android.view.ActionProvider}.</p>
+
+
+<h2>Lessons</h2>
+ 
+<dl> 
+  <dt><b><a href="send.html">Sending Content to Other Apps</a></b></dt> 
+    <dd>Learn how to set up your application to be able to send text and binary data to other
+applications with intents.</dd> 
+ 
+  <dt><b><a href="receive.html">Receiving Content from Other Apps</a></b></dt> 
+    <dd>Learn how to set up your application to receive text and binary data from intents.</dd> 
+                                    
+  <dt><b><a href="shareaction.html">Adding an Easy Share Action</a></b></dt> 
+    <dd>Learn how to add a "share" action item to your action bar.</dd> 
+</dl> 
diff --git a/docs/html/training/sharing/receive.jd b/docs/html/training/sharing/receive.jd
new file mode 100644
index 0000000..b2cac30
--- /dev/null
+++ b/docs/html/training/sharing/receive.jd
@@ -0,0 +1,149 @@
+page.title=Receiving Content from Other Apps
+parent.title=Sharing Content
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Sending Content to Other Apps
+previous.link=send.html
+next.title=Adding an Easy Share Action
+next.link=shareaction.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#update-manifest">Update Your Manifest</a></li>
+  <li><a href="#handling-content">Handle the Incoming Content</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and
+Intent Filters</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>Just as your application can send data to other applications, so too can it easily receive data 
+from applications. Think about how users interact with your application, and what data types you 
+want to receive from other applications. For example, a social networking application would likely 
+be interested in receiving text content, like an interesting web URL, from another app. The 
+<a href="https://market.android.com/details?id=com.google.android.apps.plus">Google+ Android
+application</a> 
+accepts both text <em>and</em> single or multiple images. With this app, a user can easily start a 
+new Google+ post with photos from the Android Gallery app.</p>
+
+
+<h2 id="update-manifest">Update Your Manifest</h2>
+
+<p>Intent filters inform the system what intents an application component is willing to accept. 
+Just as you constructed an intent with action {@link android.content.Intent#ACTION_SEND} in the 
+<a href="{@docRoot}training/sharing/send.html">Send Content to Other Apps Using Intents</a> 
+lesson, you create intent filters in order to be able to receive intents with this action. You 
+define an intent filter in your manifest, using the 
+<code><a
+href="{@docRoot}guide/topics/intents/intents-filters.html#ifs">&lt;intent-filter&gt;</a></code> 
+element. For example, if your application handles receiving text content, a single image of any 
+type, or multiple images of any type, your manifest would look like:</p>
+
+<pre>
+&lt;activity android:name=&quot;.ui.MyActivity&quot; &gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name=&quot;android.intent.action.SEND&quot; /&gt;
+        &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
+        &lt;data android:mimeType=&quot;image/*&quot; /&gt;
+    &lt;/intent-filter&gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name=&quot;android.intent.action.SEND&quot; /&gt;
+        &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
+        &lt;data android:mimeType=&quot;text/plain&quot; /&gt;
+    &lt;/intent-filter&gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name=&quot;android.intent.action.SEND_MULTIPLE&quot; /&gt;
+        &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
+        &lt;data android:mimeType=&quot;image/*&quot; /&gt;
+    &lt;/intent-filter&gt;
+&lt;/activity&gt;
+</pre>
+
+<p class="note"><strong>Note:</strong> For more information on intent filters and intent resolution 
+please read <a href="{@docRoot}guide/topics/intents/intents-filters.html#ifs">Intents and Intent
+Filters</a></p>
+
+<p>When another application tries to share any of these things by constructing an intent and passing
+it to {@link android.content.Context#startActivity(android.content.Intent) startActivity()}, your
+application will be listed as an option in the intent chooser (see figure 1). If the user selects
+your application, the corresponding activity (<code>.ui.MyActivity</code> in the example above) will
+be started. It is then up to you to handle the content appropriately within your code and UI.</p>
+
+
+<h2 id="handling-content">Handle the Incoming Content</h2>
+
+<p>To handle the content delivered by an {@link android.content.Intent}, start by calling {@link
+android.content.Intent#getIntent(String) getIntent()} 
+to get {@link android.content.Intent} object. Once you have the object, you can examine its 
+contents to determine what to do next. Keep in mind that if this activity can be started from other 
+parts of the system, such as the launcher, then you will need to take this into consideration when 
+examining the intent.</p>
+
+<pre>
+void onCreate (Bundle savedInstanceState) {
+    ...
+    // Get intent, action and MIME type
+    Intent intent = getIntent();
+    String action = intent.getAction();
+    String type = intent.getType();
+
+    if (Intent.ACTION_SEND.equals(action) &amp;&amp; type != null) {
+        if (&quot;text/plain&quot;.equals(type)) {
+            handleSendText(intent); // Handle text being sent
+        } else if (type.startsWith(&quot;image/&quot;)) {
+            handleSendImage(intent); // Handle single image being sent
+        }
+    } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) &amp;&amp; type != null) {
+        if (type.startsWith(&quot;image/&quot;)) {
+            handleSendMultipleImages(intent); // Handle multiple images being sent
+        }
+    } else {
+        // Handle other intents, such as being started from the home screen
+    }
+    ...
+}
+
+void handleSendText(Intent intent) {
+    String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
+    if (sharedText != null) {
+        // Update UI to reflect text being shared
+    }
+}
+
+void handleSendImage(Intent intent) {
+    Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
+    if (imageUri != null) {
+        // Update UI to reflect image being shared
+    }
+}
+
+void handleSendMultipleImages(Intent intent) {
+    ArrayList&lt;Uri&gt; imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+    if (imageUris != null) {
+        // Update UI to reflect multiple images being shared
+    }
+}
+</pre>
+
+<p class="caution"><strong>Caution:</strong> Take extra care to check the incoming data, you never
+know what some other application may send you. For example, the wrong MIME type might be set, or the
+image being sent might be extremely large. Also, remember to process binary data in a separate
+thread rather than the main ("UI") thread.</p>
+
+<p>Updating the UI can be as simple as populating an {@link android.widget.EditText}, or it can 
+be more complicated like applying an interesting photo filter to an image. It's really specific 
+to your application what happens next.</p>
+
diff --git a/docs/html/training/sharing/send.jd b/docs/html/training/sharing/send.jd
new file mode 100644
index 0000000..d151ed0
--- /dev/null
+++ b/docs/html/training/sharing/send.jd
@@ -0,0 +1,194 @@
+page.title=Sending Content to Other Apps
+parent.title=Sharing Content
+parent.link=index.html
+
+trainingnavtop=true
+next.title=Receiving Content from Other Apps
+next.link=receive.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#send-text-content">Send Text Content</a></li>
+  <li><a href="#send-binary-content">Send Binary Content</a></li>
+  <li><a href="#send-multiple-content">Send Multiple Pieces of Content</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and
+Intent Filters</a></li>
+</ul>
+
+</div>
+</div>
+
+<p>When you construct an intent, you must specify the action you want the intent to "trigger." 
+Android defines several actions, including {@link android.content.Intent#ACTION_SEND} which, as 
+you can probably guess, indicates that the intent is sending data from one activity to another, 
+even across process boundaries. To send data to another activity, all you need to do is speicify 
+the data and its type, the system will identify compatible receiving activities and display them 
+to the user (if there are multiple options) or immediately start the activity (if there is only 
+one option). Similarly, you can advertise the data types that your activities support receiving 
+from other applications by specifying them in your manifest.</p>
+
+<p>Sending and receiving data between applications with intents is most commonly used for social 
+sharing of content. Intents allow users to share information quickly and easily, using their 
+favorite social applications.</p>
+
+<p><strong>Note:</strong> The best way to add a share action item to an 
+{@link android.app.ActionBar} is to use {@link android.widget.ShareActionProvider}, which became 
+available in API level 14. {@link android.widget.ShareActionProvider} is discussed in the lesson 
+about <a href="shareaction.html">Adding an Easy Share Action</a>.</p>
+
+
+<h2 id="send-text-content">Send Text Content</h2>
+
+<div class="figure" style="width:220px">
+<img src="{@docRoot}images/training/sharing/share-text-screenshot.png" alt="" id="figure1" />
+<p class="img-caption">
+  <strong>Figure 1.</strong> Screenshot of {@link android.content.Intent#ACTION_SEND} intent chooser
+on a handset.
+</p>
+</div>
+
+<p>The most straightforward and common use of the {@link android.content.Intent#ACTION_SEND} 
+action is sending text content from one activity to another. For example, the built-in Browser 
+app can share the URL of the currently-displayed page as text with any application. This is useful 
+for sharing an article or website with friends via email or social networking. Here is the code to 
+implement this type of sharing:</p>
+
+<pre>
+Intent sendIntent = new Intent();
+sendIntent.setAction(Intent.ACTION_SEND);
+sendIntent.putExtra(Intent.EXTRA_TEXT, &quot;This is my text to send.&quot;);
+sendIntent.setType(&quot;text/plain&quot;);
+startActivity(sendIntent);
+</pre>
+
+<p>If there's an installed application with a filter that matches 
+{@link android.content.Intent#ACTION_SEND} and MIME type text/plain, the Android system will run 
+it; if more than one application matches, the system displays a disambiguation dialog (a "chooser") 
+that allows the user to choose an app. If you call 
+{@link android.content.Intent#createChooser(android.content.Intent, CharSequence)
+Intent.createChooser()} 
+for the intent, Android will <strong>always</strong> display the chooser. This has some
+advantages:</p>
+
+<ul>
+  <li>Even if the user has previously selected a default action for this intent, the chooser will
+still be displayed.</li>
+  <li>If no applications match, Android displays a system message.</li>
+  <li>You can specify a title for the chooser dialog.</li>
+</ul>
+
+<p>Here's the updated code:</p>
+
+<pre>
+Intent sendIntent = new Intent();
+sendIntent.setAction(Intent.ACTION_SEND);
+sendIntent.putExtra(Intent.EXTRA_TEXT, &quot;This is my text to send.&quot;);
+sendIntent.setType(&quot;text/plain&quot;);
+startActivity(<strong>Intent.createChooser(sendIntent, getResources().getText(R.string.send_to)</strong>);
+</pre>
+
+<p>The resulting dialog is shown in figure 1.</p>
+
+<p>Optionally, you can set some standard extras for the intent: 
+{@link android.content.Intent#EXTRA_EMAIL}, {@link android.content.Intent#EXTRA_CC}, 
+{@link android.content.Intent#EXTRA_BCC}, {@link android.content.Intent#EXTRA_SUBJECT}. However, 
+if the receiving application is not designed to use them, nothing will happen. You can use 
+custom extras as well, but there's no effect unless the receiving application understands them. 
+Typically, you'd use custom extras defined by the receiving application itself.</p>
+
+<p class="note"><strong>Note:</strong> Some e-mail applications, such as Gmail, expect a 
+{@link java.lang.String String[]} for extras like {@link android.content.Intent#EXTRA_EMAIL} and 
+{@link android.content.Intent#EXTRA_CC}, use 
+{@link android.content.Intent#putExtra(String,String[]) putExtra(String, String[])} to add these 
+to your intent.</p>
+
+
+<h2 id="send-binary-content">Send Binary Content</h2>
+
+<p>Binary data is shared using the {@link android.content.Intent#ACTION_SEND} action combined with
+setting the appropriate MIME type and placing the URI to the data in an extra named {@link
+android.content.Intent#EXTRA_STREAM}. This is commonly used to share an image but can be used to
+share any type of binary content:</p>
+
+<pre>
+Intent shareIntent = new Intent();
+shareIntent.setAction(Intent.ACTION_SEND);
+shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);
+shareIntent.setType(&quot;image/jpeg&quot;);
+startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)));
+</pre>
+
+<p>Note the following:</p>
+<ul>
+  <li>You can use a MIME type of {@code "*/*"}, but this will only match activities that are able to
+handle generic data streams.</li>
+  <li>The receiving application needs permission to access the data the {@link android.net.Uri}
+points to. There are a number of ways to handle this:
+  <ul>
+    <li>Write the data to a file on external/shared storage (such as the SD card), which all apps
+can read. Use {@link android.net.Uri#fromFile(java.io.File) Uri.fromFile()} to create the
+{@link android.net.Uri} that can be passed to the share intent. However, keep in mind that not
+all applications process a {@code file://} style {@link android.net.Uri}.</li>
+    <li>Write the data to a file in your own application directory using {@link
+android.content.Context#openFileOutput(java.lang.String, int) openFileOutput()} with mode {@link
+android.content.Context#MODE_WORLD_READABLE} after which {@link
+android.content.Context#getFileStreamPath(java.lang.String) getFileStreamPath()} can be used to
+return a {@link java.io.File}. As with the previous option, {@link
+android.net.Uri#fromFile(java.io.File) Uri.fromFile()} will create a {@code file://} style {@link
+android.net.Uri} for your share intent.</li>
+    <li>Media files like images, videos and audio can be scanned and added to the system {@link
+android.provider.MediaStore} using {@link
+android.media.MediaScannerConnection#scanFile(android.content.Context, java.lang.String[],
+java.lang.String[], android.media.MediaScannerConnection.OnScanCompletedListener) scanFile()}. The
+{@link
+android.media.MediaScannerConnection.OnScanCompletedListener#onScanCompleted(java.lang.String,
+android.net.Uri) onScanCompleted()} callback returns a {@code content://} style {@link
+android.net.Uri} suitable for including in your share intent.</li>
+    <li>Images can be inserted into the system {@link android.provider.MediaStore} using {@link
+android.provider.MediaStore.Images.Media#insertImage(android.content.ContentResolver,
+android.graphics.Bitmap, java.lang.String, java.lang.String) insertImage()} which will return a
+{@code content://} style {@link android.net.Uri} suitable for including in a share intent.</li>
+    <li>Store the data in your own {@link android.content.ContentProvider}, make sure that other
+apps have the correct permission to access your provider (or use <a
+href="{@docRoot}guide/topics/security/security.html#uri">per-URI permissions</a>).</li>
+  </ul>
+  </li>
+</ul>
+
+
+<h2 id="send-multiple-content">Send Multiple Pieces of Content</h2>
+
+<p>To share multiple pieces of content, use the {@link android.content.Intent#ACTION_SEND_MULTIPLE}
+action together with a list of URIs pointing to the content. The MIME type varies according to the
+mix of content you're sharing. For example, if you share 3 JPEG images, the type is still {@code
+"image/jpeg"}. For a mixture of image types, it should be {@code "image/*"} to match an activity
+that handles any type of image. You should only use {@code "*/*"} if you're sharing out a wide
+variety of types. As previously stated, it's up to the receiving application to parse and process
+your data. Here's an example:</p>
+
+<pre>
+ArrayList&lt;Uri&gt; imageUris = new ArrayList&lt;Uri&gt;();
+imageUris.add(imageUri1); // Add your image URIs here
+imageUris.add(imageUri2);
+
+Intent shareIntent = new Intent();
+shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
+shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);
+shareIntent.setType(&quot;image/*&quot;);
+startActivity(Intent.createChooser(shareIntent, &quot;Share images to..&quot;));
+</pre>
+
+<p>As before, make sure the provided {@link android.net.Uri URIs} point to data that a receiving
+application can access.</p>
+
diff --git a/docs/html/training/sharing/shareaction.jd b/docs/html/training/sharing/shareaction.jd
new file mode 100644
index 0000000..f6be745
--- /dev/null
+++ b/docs/html/training/sharing/shareaction.jd
@@ -0,0 +1,115 @@
+page.title=Adding an Easy Share Action
+parent.title=Sharing Content
+parent.link=index.html
+
+trainingnavtop=true
+previous.title=Receiving Content from Other Apps
+previous.link=receive.html
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<!-- table of contents -->
+<h2>This lesson teaches you to</h2>
+<ol>
+  <li><a href="#update-menus">Update Menu Declarations</a></li>
+  <li><a href="#set-share-intent">Set the Share Intent</a></li>
+</ol>
+
+<!-- other docs (NOT javadocs) -->
+<h2>You should also read</h2>
+<ul>
+  <li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li>
+</ul>
+
+</div>
+</div>
+
+
+<p>Implementing an effective and user friendly share action in your {@link android.app.ActionBar} 
+is made even easier with the introduction of {@link  android.view.ActionProvider} in Android 4.0
+(API Level 14). An {@link android.view.ActionProvider}, once attached to a menu item in the action
+bar, handles both the appearance and behavior of that item. In the case of {@link
+android.widget.ShareActionProvider}, you provide a share intent and it does the rest.</p>
+
+<p class="note"><strong>Note:&nbsp;</strong> {@link android.widget.ShareActionProvider} is available
+starting with API Level 14 and higher.</p>
+
+
+<div class="figure" style="width:200px">
+<img src="{@docRoot}images/ui/actionbar-shareaction.png" alt="" id="figure1" />
+<p class="img-caption">
+  <strong>Figure 1.</strong> The {@link android.widget.ShareActionProvider} in the Gallery app.
+</p>
+</div>
+
+<h2 id="update-menus">Update Menu Declarations</h2>
+
+<p>To get started with {@link android.widget.ShareActionProvider ShareActionProviders}, define the <code>android:actionProviderClass</code> attribute for the corresponding <code>&lt;item&gt;</code> in your <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a> file:</p>
+
+<pre>
+&lt;menu xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
+    &lt;item android:id=&quot;@+id/menu_item_share&quot;
+        android:showAsAction=&quot;ifRoom&quot;
+        android:title=&quot;Share&quot;
+        <strong>android:actionProviderClass=&quot;android.widget.ShareActionProvider&quot;</strong> /&gt;
+    ...
+&lt;/menu&gt;
+</pre>
+
+<p>This delegates responsibility for the item's appearance and function to 
+{@link android.widget.ShareActionProvider}. However, you will need to tell the provider what you 
+would like to share.</p>
+
+
+<h2 id="set-share-intent">Set the Share Intent</h2>
+
+<p>In order for {@link android.widget.ShareActionProvider} to function, you must provide it a share
+intent. This share intent should be the same as described in the <a
+href="{@docRoot}training/sharing/send.html">Sending Content to Other Apps</a>
+lesson, with action {@link android.content.Intent#ACTION_SEND} and additional data set via extras
+like {@link android.content.Intent#EXTRA_TEXT} and {@link android.content.Intent#EXTRA_STREAM}. To
+assign a share intent, first find the corresponding {@link android.view.MenuItem} while inflating
+your menu resource in your {@link android.app.Activity} or {@link android.app.Fragment}. Next, call
+{@link android.view.MenuItem#getActionProvider() MenuItem.getActionProvider()} to retreive an
+instance of {@link android.widget.ShareActionProvider}. Use {@link
+android.widget.ShareActionProvider#setShareIntent(android.content.Intent) setShareIntent()} to
+update the share intent associated with that action item. Here's an example:</p>
+
+<pre>
+private ShareActionProvider mShareActionProvider;
+...
+
+&#64;Override
+public boolean onCreateOptionsMenu(Menu menu) {
+    // Inflate menu resource file.
+    getMenuInflater().inflate(R.menu.share_menu, menu);
+
+    // Locate MenuItem with ShareActionProvider
+    MenuItem item = menu.findItem(R.id.menu_item_share);
+
+    // Fetch and store ShareActionProvider
+    mShareActionProvider = (ShareActionProvider) item.getActionProvider();
+
+    // Return true to display menu
+    return true;
+}
+
+// Call to update the share intent
+private void setShareIntent(Intent shareIntent) {
+    if (mShareActionProvider != null) {
+        mShareActionProvider.setShareIntent(shareIntent);
+    }
+}
+</pre>
+
+<p>You may only need to set the share intent once during the creation of your menus, or you may 
+want to set it and then update it as the UI changes. For example, when you view photos full screen 
+in the Gallery app, the sharing intent changes as you flip between photos.</p>
+
+<p>For further discussion about the {@link android.widget.ShareActionProvider}, see the <a
+href="{@docRoot}guide/topics/ui/actionbar.html#ActionProvider">Action Bar</a> guide.</p>
+
+
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index eaf884d..b2fa053 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -99,12 +99,11 @@
 
 status_t DrmManager::loadPlugIns() {
 
-    String8 pluginDirPath("/system/lib/drm");
-    loadPlugIns(pluginDirPath);
-
     String8 vendorPluginDirPath("/vendor/lib/drm");
     loadPlugIns(vendorPluginDirPath);
 
+    String8 pluginDirPath("/system/lib/drm");
+    loadPlugIns(pluginDirPath);
     return DRM_NO_ERROR;
 
 }
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index ba6ff10..50c264e 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -335,13 +335,11 @@
         return UNKNOWN_ERROR;
     }
 
-    if (extractor->getDrmFlag()) {
-        dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
-        if (mDecryptHandle != NULL) {
-            CHECK(mDrmManagerClient);
-            if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
-                notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
-            }
+    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
+    if (mDecryptHandle != NULL) {
+        CHECK(mDrmManagerClient);
+        if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
+            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
         }
     }
 
@@ -2093,7 +2091,7 @@
         String8 mimeType;
         float confidence;
         sp<AMessage> dummy;
-        bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
+        bool success = SniffDRM(dataSource, &mimeType, &confidence, &dummy);
 
         if (!success
                 || strcasecmp(
@@ -2101,11 +2099,8 @@
             return ERROR_UNSUPPORTED;
         }
 
-        dataSource->DrmInitialization();
-
         mWVMExtractor = new WVMExtractor(dataSource);
         mWVMExtractor->setAdaptiveStreamingMode(true);
-        mWVMExtractor->setDrmFlag(true);
         extractor = mWVMExtractor;
     } else {
         extractor = MediaExtractor::Create(
@@ -2116,14 +2111,12 @@
         }
     }
 
-    if (extractor->getDrmFlag()) {
-        dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
+    dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
 
-        if (mDecryptHandle != NULL) {
-            CHECK(mDrmManagerClient);
-            if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
-                notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
-            }
+    if (mDecryptHandle != NULL) {
+        CHECK(mDrmManagerClient);
+        if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
+            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE);
         }
     }
 
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index afc4a80..1f3d581 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -282,13 +282,13 @@
     if (decryptHandle != NULL) {
         if (decryptHandle->decryptApiType == DecryptApiType::CONTAINER_BASED) {
             *mimeType = String8("drm+container_based+") + decryptHandle->mimeType;
-            *confidence = 10.0f;
         } else if (decryptHandle->decryptApiType == DecryptApiType::ELEMENTARY_STREAM_BASED) {
             *mimeType = String8("drm+es_based+") + decryptHandle->mimeType;
-            *confidence = 10.0f;
-        } else {
-            return false;
+        } else if (decryptHandle->decryptApiType == DecryptApiType::WV_BASED) {
+            *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM;
+            LOGW("SniffWVM: found match\n");
         }
+        *confidence = 10.0f;
 
         return true;
     }
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 6134344..43539bb 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -26,7 +26,6 @@
 #include "include/DRMExtractor.h"
 #include "include/FLACExtractor.h"
 #include "include/AACExtractor.h"
-#include "include/WVMExtractor.h"
 
 #include "matroska/MatroskaExtractor.h"
 
@@ -114,7 +113,6 @@
     RegisterSniffer(SniffMP3);
     RegisterSniffer(SniffAAC);
     RegisterSniffer(SniffMPEG2PS);
-    RegisterSniffer(SniffWVM);
 
     char value[PROPERTY_VALUE_MAX];
     if (property_get("drm.service.enabled", value, NULL)
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 9eee6aa..374ecf7 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -111,9 +111,6 @@
         ret = new MPEG2TSExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
         ret = new WVMExtractor(source);
-        if (ret != NULL) {
-            isDrm = true;
-        }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
         ret = new AACExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 79dedca..26eda0c 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -45,12 +45,17 @@
 static Mutex gWVMutex;
 
 WVMExtractor::WVMExtractor(const sp<DataSource> &source)
-    : mDataSource(source)
-{
-    Mutex::Autolock autoLock(gWVMutex);
+    : mDataSource(source) {
+    {
+        Mutex::Autolock autoLock(gWVMutex);
+        if (gVendorLibHandle == NULL) {
+            gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
+        }
 
-    if (!getVendorLibHandle()) {
-        return;
+        if (gVendorLibHandle == NULL) {
+            LOGE("Failed to open libwvm.so");
+            return;
+        }
     }
 
     typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>);
@@ -66,19 +71,6 @@
     }
 }
 
-bool WVMExtractor::getVendorLibHandle()
-{
-    if (gVendorLibHandle == NULL) {
-        gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
-    }
-
-    if (gVendorLibHandle == NULL) {
-        LOGE("Failed to open libwvm.so");
-    }
-
-    return gVendorLibHandle != NULL;
-}
-
 WVMExtractor::~WVMExtractor() {
 }
 
@@ -121,33 +113,5 @@
     }
 }
 
-bool SniffWVM(
-    const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *) {
-
-    Mutex::Autolock autoLock(gWVMutex);
-
-    if (!WVMExtractor::getVendorLibHandle()) {
-        return false;
-    }
-
-    typedef WVMLoadableExtractor *(*SnifferFunc)(sp<DataSource>);
-    SnifferFunc snifferFunc =
-        (SnifferFunc) dlsym(gVendorLibHandle,
-                            "_ZN7android15IsWidevineMediaENS_2spINS_10DataSourceEEE");
-
-    if (snifferFunc) {
-        if ((*snifferFunc)(source)) {
-            *mimeType = MEDIA_MIMETYPE_CONTAINER_WVM;
-            *confidence = 10.0f;
-            return true;
-        }
-    } else {
-        LOGE("IsWidevineMedia not found in libwvm.so");
-    }
-
-    return false;
-}
-
 } //namespace android
 
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index 9f763f9..deecd25 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -23,8 +23,6 @@
 
 namespace android {
 
-struct AMessage;
-class String8;
 class DataSource;
 
 class WVMLoadableExtractor : public MediaExtractor {
@@ -60,8 +58,6 @@
     // is used.
     void setAdaptiveStreamingMode(bool adaptive);
 
-    static bool getVendorLibHandle();
-
 protected:
     virtual ~WVMExtractor();
 
@@ -73,10 +69,6 @@
     WVMExtractor &operator=(const WVMExtractor &);
 };
 
-bool SniffWVM(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *);
-
 }  // namespace android
 
 #endif  // DRM_EXTRACTOR_H_