Merge "add new sensor types for handling gyro data and device orientation more efficiently." into gingerbread
diff --git a/Android.mk b/Android.mk
index 62c7679..c1324c9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -371,8 +371,6 @@
 # (see development/build/sdk.atree)
 web_docs_sample_code_flags := \
 		-hdf android.hasSamples 1 \
-		-samplecode $(sample_dir)/AccessibilityService \
-		            resources/samples/AccessibilityService "Accessibility Service" \
 		-samplecode $(sample_dir)/ApiDemos \
 		            resources/samples/ApiDemos "API Demos" \
 		-samplecode $(sample_dir)/BackupRestore \
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index c0a546d..ec7d927 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -21,8 +21,9 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
-import android.graphics.Shader;
 import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.drawable.Animatable;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ClipDrawable;
@@ -30,11 +31,14 @@
 import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.StateListDrawable;
-import android.graphics.drawable.Animatable;
 import android.graphics.drawable.shapes.RoundRectShape;
 import android.graphics.drawable.shapes.Shape;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.view.Gravity;
+import android.view.RemotableViewMethod;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.animation.AlphaAnimation;
@@ -44,9 +48,6 @@
 import android.view.animation.LinearInterpolator;
 import android.view.animation.Transformation;
 import android.widget.RemoteViews.RemoteView;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
 
 import com.android.internal.R;
 
@@ -762,6 +763,7 @@
     }
 
     @Override
+    @RemotableViewMethod
     public void setVisibility(int v) {
         if (getVisibility() != v) {
             super.setVisibility(v);
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index d0318cf..35ce17e 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -220,9 +220,16 @@
             <li><a style="color:gray;">Accelerometer</a></li>
           </ul>
       </li> -->
-      <li><a href="<?cs var:toroot ?>guide/topics/location/index.html">
-            <span class="en">Location and Maps</span>
-          </a></li>
+      <li class="toggle-list">
+        <div><a href="<?cs var:toroot ?>guide/topics/location/index.html">
+               <span class="en">Location and Maps</span>
+             </a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>guide/topics/location/obtaining-user-location.html">
+                <span class="en">Obtaining User Location</span>
+              </a> <span class="new">new!</span></li>
+        </ul>
+      </li>
   <!--<li class="toggle-list">
         <div><a style="color:gray;">Wireless Controls</a></div>
           <ul>
diff --git a/docs/html/guide/topics/location/index.jd b/docs/html/guide/topics/location/index.jd
index e988ecb..5f98902 100644
--- a/docs/html/guide/topics/location/index.jd
+++ b/docs/html/guide/topics/location/index.jd
@@ -4,94 +4,63 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-  <h2>Location and Maps quickview</h2>
+  <h2>Quickview</h2>
   <ul>
-    <li>Android provides a location framework that your application can use to determine the device's location and bearing and register for updates.</li>
-    <li>A Google Maps external library is available that lets you display and manage Maps data.</li>
+    <li>Android provides a location framework that your application can use to determine the
+device's location and bearing and register for updates</li>
+    <li>A Google Maps external library is available that lets you display and manage Maps data</li>
   </ul>
-  <h2>In this document</h2>
+
+  <h2>Topics</h2>
   <ol>
-    <li><a href="#location">Location Services</a></li>
-    <li><a href="#maps">Google Maps External Library</a></li>
+    <li><a href="{@docRoot}guide/topics/location/obtaining-user-location.html">Obtaining User
+Location</a></li>
   </ol>
+  
   <h2>See Also</h2>
   <ol>
-    <li><a href="http://code.google.com/android/add-ons/google-apis/index.html">Google APIs add-on download&raquo;</a></li>
+    <li><a
+href="http://code.google.com/android/add-ons/google-apis/maps-overview.html">Google
+Maps External Library &raquo;</a></li>
   </ol>
 </div>
 </div>
 
-<p>Location- and maps-based applications and services are compelling for mobile device users. You can build these capabilities into your applications using the classes of the {@link android.location} package and the Google Maps external library. The sections below provide details. </p>
+<p>Location and maps-based applications are compelling for mobile device users. You
+can build these capabilities into your applications using the classes of the {@link
+android.location} package and the Google Maps external library. The sections below provide details.
+</p>
 
 <h2 id="location">Location Services</h2>
 
 <p>Android gives your applications access to the location services supported by
-the device through the classes in the <code>android.location</code> package. The
+the device through the classes in the {@code android.location} package. The
 central component of the location framework is the 
-{@link android.location.LocationManager} system service, which provides an API to
-determine location and bearing if the underlying device (if it supports location
-capabilities). </p>
+{@link android.location.LocationManager} system service, which provides APIs to
+determine location and bearing of the underlying device (if available). </p>
 
-<p>As with other system services, you do not instantiate a LocationManager directly. 
-Rather, you request an LocationManager instance from the system by calling 
-{@link android.content.Context#getSystemService(String) getSystemService(Context.LOCATION_SERVICE)}. 
-The method returns a handle to a new LocationManager instance.</p>
+<p>As with other system services, you do not instantiate a {@link android.location.LocationManager}
+directly. Rather, you request an instance from the system by calling
+{@link android.content.Context#getSystemService(String)
+getSystemService(Context.LOCATION_SERVICE)}. The method returns a handle to a new {@link
+android.location.LocationManager} instance.</p>
 
-<p>Once your application has a handle to a LocationManager instance, your application 
-will be able to do three things:</p>
+<p>Once your application has a {@link android.location.LocationManager}, your application
+is able to do three things:</p>
 
 <ul>
-    <li>Query for the list of all LocationProviders known to the
-    LocationManager for its last known location.</li>
-    <li>Register/unregister for periodic updates of current location from a
-    LocationProvider (specified either by Criteria or name).</li>
-    <li>Register/unregister for a given Intent to be fired if the device comes
-    within a given proximity (specified by radius in meters) of a given
-    lat/long.</li>
+    <li>Query for the list of all {@link android.location.LocationProvider}s for the last known
+user location.</li>
+    <li>Register/unregister for periodic updates of the user's current location from a
+    location provider (specified either by criteria or name).</li>
+    <li>Register/unregister for a given {@link android.content.Intent} to be fired if the device
+comes within a given proximity (specified by radius in meters) of a given lat/long.</li>
 </ul>
 
-<p>However, during initial development in the emulator, you may not have access to real 
-data from a real location provider (Network or GPS). In that case, it may be necessary to
-spoof some data for your application using a mock location provider.</p>
+<p>For more information, read the guide to <a
+href="{@docRoot}guide/topics/location/obtaining-user-location.html">Obtaining User
+Location</a>.</p>
 
-<p class="note"><strong>Note:</strong> If you've used mock LocationProviders in
-previous versions of the SDK, you can no longer provide canned LocationProviders
-in the /system/etc/location directory. These directories will be wiped during boot-up.
-Please follow the new procedures outlined below.</p>
-
-<h3>Providing Mock Location Data</h3>
-
-<p>When testing your application on the Android emulator, there are a couple different
-ways to send it some mock location data: you can use the DDMS tool or the "geo" command 
-option in the emulator console.</p>
-
-<h4 id="ddms">Using DDMS</h4>
-<p>With the DDMS tool, you can simulate location data a few different ways:</p>
-<ul>
-    <li>Manually send individual longitude/latitude coordinates to the device.</li>
-    <li>Use a GPX file describing a route for playback to the device.</li>
-    <li>Use a KML file describing individual placemarks for sequenced playback to the device.</li>
-</ul>
-<p>For more information on using DDMS to spoof location data, see the 
-<a href="{@docRoot}guide/developing/tools/ddms.html#emulator-control">Using DDMS guide</a>.
-
-<h4 id="geo">Using the "geo" command in the emulator console</h4>
-<p>Launch your application in the Android emulator and open a terminal/console in
-your SDK's <code>/tools</code> directory. Connect to the emulator console. Now you can use:</p>
-<ul><li><code>geo fix</code> to send a fixed geo-location.
-	<p>This command accepts a longitude and latitude in decimal degrees, and
-	an optional altitude in meters. For example:</p>
-	<pre>geo fix -121.45356 46.51119 4392</pre>
-    </li>
-    <li><code>geo nmea</code> to send an NMEA 0183 sentence.
-	<p>This command accepts a single NMEA sentence of type '$GPGGA' (fix data) or '$GPRMC' (transit data).
-	For example:</p>
-	<pre>geo nmea $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62</pre>
-    </li>
-</ul>
-
-<p>For information about how to connect to the emulator console, see 
-<a href="{@docRoot}guide/developing/tools/emulator.html#console">Using the Emulator Console</a>.</p>
 
 <h2 id="maps">Google Maps External Library</h2>
 
@@ -128,9 +97,9 @@
 <p style="margin-left:2em;"><a
 href="http://code.google.com/android/add-ons/google-apis">http://code.google.com/android/add-ons/google-apis</a></p>
 
-<p>For your convenience, the Google APIs add-on is also included in the Android
-SDK. <!-- To learn now to use the Maps external library in your application, see
-[[Using External Libraries]].--></p>
+<p>For your convenience, the Google APIs add-on is also available as a downloadable component from
+the Android SDK and AVD Manager (see <a href="{@docRoot}sdk/adding-components.html">Adding SDK
+Components</a>).</p>
 
 <p class="note"><strong>Note:</strong> In order to display Google Maps data in a
 MapView, you must register with the Google Maps service and obtain a Maps API
diff --git a/docs/html/guide/topics/location/obtaining-user-location.jd b/docs/html/guide/topics/location/obtaining-user-location.jd
new file mode 100644
index 0000000..bc782d2
--- /dev/null
+++ b/docs/html/guide/topics/location/obtaining-user-location.jd
@@ -0,0 +1,454 @@
+page.title=Obtaining User Location
+parent.title=Location and Maps
+parent.link=index.html
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+  <h2>Quickview</h2>
+  <ul>
+    <li>The Network Location Provider provides good location data without using GPS</li>
+    <li>Obtaining user location can consume a lot of battery, so be careful how
+long you listen for updates</li>
+  </ul>
+  <h2>In this document</h2>
+  <ol>
+    <li><a href="#Challenges">Challenges in Determining User Location</a></li>
+    <li><a href="#Updates">Requesting Location Updates</a>
+      <ol>
+        <li><a href="#Permission">Requesting User Permissions</a></li>
+      </ol>
+    </li>
+    <li><a href="#BestPerformance">Defining a Model for the Best Performance</a>
+      <ol>
+        <li><a href="#Flow">Flow for obtaining user location</a></li>
+        <li><a href="#StartListening">Deciding when to start listening for updates</a></li>
+        <li><a href="#FastFix">Getting a fast fix with the last known location</a></li>
+        <li><a href="#StopListening">Deciding when to stop listening for updates</a></li>
+        <li><a href="#BestEstimate">Maintaining a current best estimate</a></li>
+        <li><a href="#Adjusting">Adjusting the model to save battery and data exchange</a></li>
+      </ol>
+    </li>
+    <li><a href="#MockData">Providing Mock Location Data</a></li>
+  </ol>
+  <h2>Key classes</h2>
+  <ol>
+    <li>{@link android.location.LocationManager}</li>
+    <li>{@link android.location.LocationListener}</li>
+  </ol>
+</div>
+</div>
+
+  <p>Knowing where the user is allows your application to be smarter and deliver
+better information to the user. When developing a location-aware application for Android, you can
+utilize GPS and Android's Network Location Provider to acquire the user location. Although
+GPS is most accurate, it only works outdoors, it quickly consumes battery power, and doesn't return
+the location as quickly as users want. Android's Network Location Provider determines user location
+using cell tower and Wi-Fi signals, providing location information in a way that
+works indoors and outdoors, responds faster, and uses less battery power. To obtain the user
+location in your application, you can use both GPS and the Network Location Provider, or just
+one.</p>
+
+
+<h2 id="Challenges">Challenges in Determining User Location</h2>
+
+<p>Obtaining user location from a mobile device can be complicated. There are several reasons
+why a location reading (regardless of the source) can contain errors and be inaccurate.
+Some sources of error in the user location include:</p>
+
+<ul>
+  <li><b>Multitude of location sources</b>
+    <p>GPS, Cell-ID, and Wi-Fi can each provide a clue to users location. Determining which to use
+and trust is a matter of trade-offs in accuracy, speed, and battery-efficiency.</p>
+  </li>
+  <li><b>User movement</b>
+    <p>Because the user location changes, you must account for movement by re-estimating user
+location every so often.</p>
+  </li>
+  <li><b>Varying accuracy</b>
+    <p>Location estimates coming from each location source are not consistent in their
+accuracy. A location obtained 10 seconds ago from one source might be more accurate than the newest
+location from another or same source.</p>
+  </li>
+</ul>
+
+  <p>These problems can make it difficult to obtain a reliable user location reading. This
+document provides information to help you meet these challenges to obtain a reliable location
+reading. It also provides ideas that you can use in your
+application to provide the user with an accurate and responsive geo-location experience.</p>
+
+
+<h2 id="Updates">Requesting Location Updates</h2>
+
+  <p>Before addressing some of the location errors described above, here is an introduction to
+how you can obtain user location on Android.</p>
+
+  <p>Getting user location in Android works by means of callback. You indicate that you'd
+like to receive location updates from the {@link android.location.LocationManager} ("Location
+Manager") by calling {@link android.location.LocationManager#requestLocationUpdates
+requestLocationUpdates()}, passing it a
+{@link android.location.LocationListener}. Your {@link android.location.LocationListener} must
+implement several callback methods that the Location Manager calls when the user location
+changes or when the status of the service changes.</p>
+
+<p>For example, the following code shows how to define a {@link android.location.LocationListener}
+and request location updates:
+  </p>
+
+<pre>
+// Acquire a reference to the system Location Manager
+LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
+
+// Define a listener that responds to location updates
+LocationListener locationListener = new LocationListener() {
+    public void onLocationChanged(Location location) {
+      // Called when a new location is found by the network location provider.
+      makeUseOfNewLocation(location);
+    }
+
+    public void onStatusChanged(String provider, int status, Bundle extras) {}
+
+    public void onProviderEnabled(String provider) {}
+
+    public void onProviderDisabled(String provider) {}
+  };
+
+// Register the listener with the Location Manager to receive location updates
+locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
+</pre>
+
+  <p>The first parameter in {@link
+android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} is the type of
+location provider to use (in this case, the Network Location Provider for cell tower and Wi-Fi
+based location). You can control the frequency at which your listener receives updates
+with the second and third parameter&mdash;the second is the minimum time interval between
+notifications and the third is the minimum change in distance between notifications&mdash;setting
+both to zero requests location notifications as frequently as possible. The last parameter is your
+{@link android.location.LocationListener}, which receives callbacks for location updates.</p>
+
+<p>To request location updates from the GPS provider,
+substitute <code>GPS_PROVIDER</code> for <code>NETWORK_PROVIDER</code>. You can also request
+location updates from both the GPS and the Network Location Provider by calling {@link
+android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} twice&mdash;once
+for <code>NETWORK_PROVIDER</code> and once for <code>GPS_PROVIDER</code>.</p>
+
+
+<h3 id="Permission">Requesting User Permissions</h3>
+
+<p>In order to receive location updates from <code>NETWORK_PROVIDER</code> or
+<code>GPS_PROVIDER</code>, you must request user permission by declaring either the {@code
+ACCESS_COARSE_LOCATION} or {@code ACCESS_FINE_LOCATION} permission, respectively, in your Android
+manifest file. For example:</p>
+
+<pre>
+&lt;manifest ... &gt;
+    &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
+    ...
+&lt;/manifest&gt;
+</pre>
+
+<p>Without these permissions, your application will fail at runtime when requesting
+location updates.</p>
+
+<p class="note"><strong>Note:</strong> If you are using both <code>NETWORK_PROVIDER</code> and
+<code>GPS_PROVIDER</code>, then you need to request only the {@code ACCESS_FINE_LOCATION}
+permission, because it includes permission for both providers. (Permission for {@code
+ACCESS_COARSE_LOCATION} includes permission only for <code>NETWORK_PROVIDER</code>.)</p>
+
+
+<h2 id="BestPerformance">Defining a Model for the Best Performance</h2>
+
+  <p>Location-based applications are now commonplace, but due to the less than optimal
+accuracy, user movement, the multitude of methods to obtain the location, and the desire to conserve
+battery, getting user location is complicated. To overcome the obstacles of obtaining a good user
+location while preserving battery power, you must define a consistent model that specifies how your
+application obtains the user location. This model includes when you start and stop listening for
+updates and when to use cached location data.</p>
+
+
+  <h3 id="Flow">Flow for obtaining user location</h3>
+
+  <p>Here's the typical flow of procedures for obtaining the user location:</p>
+
+  <ol>
+    <li>Start application.</li>
+    <li>Sometime later, start listening for updates from desired location providers.</li>
+    <li>Maintain a "current best estimate" of location by filtering out new, but less accurate
+fixes.</li>
+    <li>Stop listening for location updates.</li>
+    <li>Take advantage of the last best location estimate.</li>
+  </ol>
+
+  <p>Figure 1 demonstrates this model in a timeline that visualizes the period in which an
+application is listening for location updates and the events that occur during that time.</p>
+
+<img src="{@docRoot}images/location/getting-location.png" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> A timeline representing the window in which an
+application listens for location updates.</p>
+    
+  <p>This model of a window&mdash;during which location updates are received&mdash;frames many of
+the decisions you need to make when adding location-based services to your application.</p>
+
+
+  <h3 id="StartListening">Deciding when to start listening for updates</h3>
+
+  <p>You might want to start listening for location updates as soon as your application starts, or
+only after users activate a certain feature. Be aware that long windows of listening for location
+fixes can consume a lot of battery power, but short periods might not allow for sufficient
+accuracy.</p>
+
+  <p>As demonstrated above, you can begin listening for updates by calling {@link
+android.location.LocationManager#requestLocationUpdates requestLocationUpdates()}:</p>
+
+<pre>
+LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
+// Or, use GPS location data:
+// LocationProvider locationProvider = LocationManager.GPS_PROVIDER;
+
+locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);
+</pre>
+
+
+  <h3 id="FastFix">Getting a fast fix with the last known location</h3>
+  
+  <p>The time it takes for your location listener to receive the first location fix is often too
+long for users wait. Until a more accurate location is provided to your location listener, you
+should utilize a cached location by calling {@link
+android.location.LocationManager#getLastKnownLocation}:</p>
+<pre>
+LocationProvider locationProvider = LocationManager.NETWORK_PROVIDER;
+// Or use LocationManager.GPS_PROVIDER
+
+Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
+</pre>
+
+
+  <h3 id="StopListening">Deciding when to stop listening for updates</h3>
+  
+  <p>The logic of deciding when new fixes are no longer necessary might range from very simple to
+very complex depending on your application. A short gap between when the location is acquired and
+when the location is used, improves the accuracy of the estimate. Always beware that listening for a
+long time consumes a lot of battery power, so as soon as you have the information you need, you
+should stop
+listening for updates by calling {@link android.location.LocationManager#removeUpdates}:</p>
+<pre>
+// Remove the listener you previously added
+locationManager.removeUpdates(locationListener);
+</pre>
+
+
+  <h3 id="BestEstimate">Maintaining a current best estimate</h3>
+
+  <p>You might expect that the most recent location fix is the most accurate.
+However, because the accuracy of a location fix varies, the most recent fix is not always the best.
+You should include logic for choosing location fixes based on several criteria. The criteria also
+varies depending on the use-cases of the application and field testing.</p>
+
+  <p>Here are a few steps you can take to validate the accuracy of a location fix:</p>
+  <ul>
+    <li>Check if the location retrieved is significantly newer than the previous estimate.</li>
+    <li>Check if the accuracy claimed by the location is better or worse than the previous
+estimate.</li>
+    <li>Check which provider the new location is from and determine if you trust it more.</li>
+  </ul>
+  
+  <p>An elaborate example of this logic can look something like this:</p>
+
+<pre>
+private static final int TWO_MINUTES = 1000 * 60 * 2;
+
+/** Determines whether one Location reading is better than the current Location fix
+  * @param location  The new Location that you want to evaluate
+  * @param currentBestLocation  The current Location fix, to which you want to compare the new one
+  */
+protected boolean isBetterLocation(Location location, Location currentBestLocation) {
+    if (currentBestLocation == null) {
+        // A new location is always better than no location
+        return true;
+    }
+
+    // Check whether the new location fix is newer or older
+    long timeDelta = location.getTime() - currentBestLocation.getTime();
+    boolean isSignificantlyNewer = timeDelta &gt; TWO_MINUTES;
+    boolean isSignificantlyOlder = timeDelta &lt; -TWO_MINUTES;
+    boolean isNewer = timeDelta > 0;
+
+    // If it's been more than two minutes since the current location, use the new location
+    // because the user has likely moved
+    if (isSignificantlyNewer) {
+        return true;
+    // If the new location is more than two minutes older, it must be worse
+    } else if (isSignificantlyOlder) {
+        return false;
+    }
+
+    // Check whether the new location fix is more or less accurate
+    int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
+    boolean isLessAccurate = accuracyDelta &gt; 0;
+    boolean isMoreAccurate = accuracyDelta &lt; 0;
+    boolean isSignificantlyLessAccurate = accuracyDelta &gt; 200;
+
+    // Check if the old and new location are from the same provider
+    boolean isFromSameProvider = isSameProvider(location.getProvider(),
+            currentBestLocation.getProvider());
+
+    // Determine location quality using a combination of timeliness and accuracy
+    if (isMoreAccurate) {
+        return true;
+    } else if (isNewer &amp;&amp; !isLessAccurate) {
+        return true;
+    } else if (isNewer &amp;&amp; !isSignificantlyLessAccurate &amp;&amp; isFromSameProvider) {
+        return true;
+    }
+    return false;
+}
+
+/** Checks whether two providers are the same */
+private boolean isSameProvider(String provider1, String provider2) {
+    if (provider1 == null) {
+      return provider2 == null;
+    }
+    return provider1.equals(provider2);
+}
+</pre>
+
+
+  <h3 id="Adjusting">Adjusting the model to save battery and data exchange</h3>
+
+  <p>As you test your application, you might find that your model for providing good location and
+good performance needs some adjustment. Here are some things you might change to find a good
+balance between the two.</p>
+
+  <h4>Reduce the size of the window</h4>
+  
+  <p>A smaller window in which you listen for location updates means less interaction with GPS and
+network location services, thus, preserving battery life. But it also allows for fewer locations
+from which to choose a best estimate.</p>
+
+  <h4>Set the location providers to return updates less frequently</h4>
+  
+  <p>Reducing the rate at which new updates appear during the window can also improve battery
+efficiency, but at the cost of accuracy. The value of the trade-off depends on how your
+application is used. You can reduce the rate of updates by increasing the parameters in {@link
+android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} that specify the
+interval time and minimum distance change.</p>
+
+  <h4>Restrict a set of providers</h4>
+  
+  <p>Depending on the environment where your application is used or the desired level of accuracy,
+you might choose to use only the Network Location Provider or only GPS, instead of both. Interacting
+with only one of the services reduces battery usage at a potential cost of accuracy.</p>
+
+
+  <h2>Common application cases</h2>
+  
+  <p>There are many reasons you might want to obtain the user location in your application. Below
+are a couple scenarios in which you can use the user location to enrich your application. Each
+scenario also describes good practices for when you should start and stop listening for the
+location, in order to get a good reading and help preserve battery life.</p>
+
+
+  <h3>Tagging user-created content with a location</h3>
+  
+  <p>You might be creating an application where user-created content is tagged with a location.
+Think of users sharing their local experiences, posting a review for a restaurant, or recording some
+content that can be augmented with their current location. A model of how this
+interaction might happen, with respect to the location services, is visualized in figure 2.</p>
+
+  <img src="{@docRoot}images/location/content-tagging.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> A timeline representing the window in which
+the user location is obtained and listening stops when the user consumes the current location.</p>
+  
+  <p>This lines up with the previous model of how user location is obtained in code (figure 1). For
+best location accuracy, you might choose to start listening for location updates when users begin
+creating
+the content or even when the application starts, then stop listening for updates when content is
+ready to be posted or recorded. You might need to consider how long a typical task of creating the
+content takes and judge if this duration allows for efficient collection of a location estimate.</p>
+
+
+  <h3>Helping the user decide on where to go</h3>
+  
+  <p>You might be creating an application that attempts to provide users with a set
+of options about where to go. For example, you're looking to provide a list of nearby restaurants,
+stores, and entertainment and the order of recommendations changes depending on the user
+location.</p>
+
+  <p>To accommodate such a flow, you might choose to:</p>
+  <ul>
+    <li>Rearrange recommendations when a new best estimate is obtained</li>
+    <li>Stop listening for updates if the order of recommendations has stabilized</li>
+  </ul>
+
+  <p>This kind of model is visualized in figure 3.</p>
+  
+  <img src="{@docRoot}images/location/where-to-go.png" alt="" />
+<p class="img-caption"><strong>Figure 3.</strong> A timeline representing the window in which a
+dynamic set of data is updated each time the user location updates.</p>
+
+
+
+
+<h2 id="MockData">Providing Mock Location Data</h2>
+
+<p>As you develop your application, you'll certainly need to test how well your model for obtaining
+user location works. This is most easily done using a real Android-powered device. If, however, you
+don't have a device, you can still test your location-based features by mocking location data in
+the Android emulator. There are three different ways to send your application mock location
+data: using Eclipse, DDMS, or the "geo" command in the emulator console.</p>
+
+<p class="note"><strong>Note:</strong> Providing mock location data is injected as GPS location
+data, so you must request location updates from <code>GPS_PROVIDER</code> in order for mock location
+data to work.</p>
+
+<h3 id="MockEclipse">Using Eclipse</h3>
+
+<p>Select <b>Window</b> &gt; <b>Show View</b> &gt; <b>Other</b> &gt; <b>Emulator Control</b>.</p>
+
+<p>In the Emulator Control panel, enter GPS coordinates under Location Controls as individual
+lat/long coordinates, with a GPX file for route playback, or a KML file for multiple place marks.
+(Be sure that you have a device selected in the Devices panel&mdash;available from <b>Window</b>
+&gt; <b>Show View</b> &gt; <b>Other</b> &gt; <b>Devices</b>.)</p>
+
+
+<h3 id="MockDdms">Using DDMS</h3>
+
+<p>With the DDMS tool, you can simulate location data a few different ways:</p>
+<ul>
+    <li>Manually send individual longitude/latitude coordinates to the device.</li>
+    <li>Use a GPX file describing a route for playback to the device.</li>
+    <li>Use a KML file describing individual place marks for sequenced playback to the device.</li>
+</ul>
+
+<p>For more information on using DDMS to spoof location data, see the
+<a href="{@docRoot}guide/developing/tools/ddms.html#emulator-control">Using DDMS guide</a>.
+
+
+<h3 id="MockGeo">Using the "geo" command in the emulator console</h3>
+
+<p>To send mock location data from the command line:</p>
+
+<ol>
+  <li>Launch your application in the Android emulator and open a terminal/console in your SDK's
+<code>/tools</code> directory.</li>
+  <li>Connect to the emulator console:
+<pre>telnet localhost <em>&lt;console-port&gt;</em></pre></li>
+  <li>Send the location data:</p>
+    <ul><li><code>geo fix</code> to send a fixed geo-location.
+    <p>This command accepts a longitude and latitude in decimal degrees, and
+    an optional altitude in meters. For example:</p>
+    <pre>geo fix -121.45356 46.51119 4392</pre>
+      </li>
+      <li><code>geo nmea</code> to send an NMEA 0183 sentence.
+    <p>This command accepts a single NMEA sentence of type '$GPGGA' (fix data) or '$GPRMC' (transit
+  data).
+    For example:</p>
+    <pre>geo nmea $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62</pre>
+      </li>
+    </ul>
+  </li>
+</ol>
+
+<p>For information about how to connect to the emulator console, see
+<a href="{@docRoot}guide/developing/tools/emulator.html#console">Using the Emulator Console</a>.</p>
diff --git a/docs/html/images/location/content-tagging.png b/docs/html/images/location/content-tagging.png
new file mode 100644
index 0000000..d58bfee
--- /dev/null
+++ b/docs/html/images/location/content-tagging.png
Binary files differ
diff --git a/docs/html/images/location/getting-location.png b/docs/html/images/location/getting-location.png
new file mode 100644
index 0000000..a5905ec
--- /dev/null
+++ b/docs/html/images/location/getting-location.png
Binary files differ
diff --git a/docs/html/images/location/where-to-go.png b/docs/html/images/location/where-to-go.png
new file mode 100644
index 0000000..59f5983
--- /dev/null
+++ b/docs/html/images/location/where-to-go.png
Binary files differ
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 00860ae..7ca3741 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1002,7 +1002,6 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            mRecycled = true;
             nativeDestructor(mNativeBitmap);
         } finally {
             super.finalize();
diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h
index 5d51de8..b8746c2 100644
--- a/include/media/Visualizer.h
+++ b/include/media/Visualizer.h
@@ -151,7 +151,6 @@
     void *mCaptureCbkUser;
     sp<CaptureThread> mCaptureThread;
     uint32_t mCaptureFlags;
-    void *mFftTable;
 };
 
 
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index de82b38..2412f6a 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -40,6 +40,7 @@
     virtual status_t stop();
     virtual status_t pause();
     virtual bool reachedEOS();
+    virtual status_t dump(int fd, const Vector<String16>& args);
 
     void beginBox(const char *fourcc);
     void writeInt8(int8_t x);
diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h
index 151bf16..5cc8dcf 100644
--- a/include/media/stagefright/MediaWriter.h
+++ b/include/media/stagefright/MediaWriter.h
@@ -44,6 +44,10 @@
         mListener = listener;
     }
 
+    virtual status_t dump(int fd, const Vector<String16>& args) {
+        return OK;
+    }
+
 protected:
     virtual ~MediaWriter() {}
     int64_t mMaxFileSizeLimitBytes;
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 977e6be..b4d01f5 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -31,7 +31,8 @@
     IEffect.cpp \
     IEffectClient.cpp \
     AudioEffect.cpp \
-    Visualizer.cpp
+    Visualizer.cpp \
+    fixedfft.cpp.arm
 
 LOCAL_SHARED_LIBRARIES := \
 	libui libcutils libutils libbinder libsonivox libicuuc libexpat libsurfaceflinger_client libcamera_client
@@ -50,11 +51,7 @@
     $(JNI_H_INCLUDE) \
     $(call include-path-for, graphics corecg) \
     $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
-    external/speex/include \
-    external/speex/libspeex \
     external/icu4c/common \
     external/expat/lib
 
-LOCAL_STATIC_LIBRARIES := libspeex
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index 32cdb49..39552b6 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -26,10 +26,7 @@
 
 #include <media/Visualizer.h>
 
-extern "C" {
-#define FLOATING_POINT 1
-#include "fftwrap.h"
-}
+extern void fixed_fft_real(int n, int32_t *v);
 
 namespace android {
 
@@ -47,18 +44,10 @@
         mCaptureCbkUser(NULL)
 {
     initCaptureSize();
-    if (mCaptureSize != 0) {
-        mFftTable = spx_fft_init(mCaptureSize);
-    } else {
-        mFftTable = NULL;
-    }
 }
 
 Visualizer::~Visualizer()
 {
-    if (mFftTable != NULL) {
-        spx_fft_destroy(mFftTable);
-    }
 }
 
 status_t Visualizer::setEnabled(bool enabled)
@@ -163,11 +152,6 @@
     }
     if (status == NO_ERROR) {
         mCaptureSize = size;
-        if (mFftTable != NULL) {
-            spx_fft_destroy(mFftTable);
-        }
-        mFftTable = spx_fft_init(mCaptureSize);
-        LOGV("setCaptureSize size %d mFftTable %p", mCaptureSize, mFftTable);
     }
 
     return status;
@@ -219,19 +203,24 @@
 
 status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
 {
-    if (mFftTable == NULL) {
-        return NO_INIT;
+    int32_t workspace[mCaptureSize >> 1];
+    int32_t nonzero = 0;
+
+    for (uint32_t i = 0; i < mCaptureSize; i += 2) {
+        workspace[i >> 1] = (waveform[i] ^ 0x80) << 23;
+        workspace[i >> 1] |= (waveform[i + 1] ^ 0x80) << 7;
+        nonzero |= workspace[i >> 1];
     }
 
-    float fsrc[mCaptureSize];
-    for (uint32_t i = 0; i < mCaptureSize; i++) {
-        fsrc[i] = (int16_t)(waveform[i] ^ 0x80) << 8;
+    if (nonzero) {
+        fixed_fft_real(mCaptureSize >> 1, workspace);
     }
-    float fdst[mCaptureSize];
-    spx_fft_float(mFftTable, fsrc, fdst);
-    for (uint32_t i = 0; i < mCaptureSize; i++) {
-        fft[i] = (uint8_t)((int32_t)fdst[i] >> 8);
+
+    for (uint32_t i = 0; i < mCaptureSize; i += 2) {
+        fft[i] = workspace[i >> 1] >> 23;
+        fft[i + 1] = workspace[i >> 1] >> 7;
     }
+
     return NO_ERROR;
 }
 
diff --git a/media/libmedia/fixedfft.cpp b/media/libmedia/fixedfft.cpp
new file mode 100644
index 0000000..28eb05a
--- /dev/null
+++ b/media/libmedia/fixedfft.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* A Fixed point implementation of Fast Fourier Transform (FFT). Complex numbers
+ * are represented by 32-bit integers, where higher 16 bits are real part and
+ * lower ones are imaginary part. Few compromises are made between efficiency,
+ * accuracy, and maintainability. To make it fast, arithmetic shifts are used
+ * instead of divisions, and bitwise inverses are used instead of negates. To
+ * keep it small, only radix-2 Cooley-Tukey algorithm is implemented, and only
+ * half of the twiddle factors are stored. Although there are still ways to make
+ * it even faster or smaller, it costs too much on one of the aspects.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <machine/cpu-features.h>
+
+#define LOG_FFT_SIZE 10
+#define MAX_FFT_SIZE (1 << LOG_FFT_SIZE)
+
+static const int32_t twiddle[MAX_FFT_SIZE / 4] = {
+    0x00008000, 0xff378001, 0xfe6e8002, 0xfda58006, 0xfcdc800a, 0xfc13800f,
+    0xfb4a8016, 0xfa81801e, 0xf9b88027, 0xf8ef8032, 0xf827803e, 0xf75e804b,
+    0xf6958059, 0xf5cd8068, 0xf5058079, 0xf43c808b, 0xf374809e, 0xf2ac80b2,
+    0xf1e480c8, 0xf11c80de, 0xf05580f6, 0xef8d8110, 0xeec6812a, 0xedff8146,
+    0xed388163, 0xec718181, 0xebab81a0, 0xeae481c1, 0xea1e81e2, 0xe9588205,
+    0xe892822a, 0xe7cd824f, 0xe7078276, 0xe642829d, 0xe57d82c6, 0xe4b982f1,
+    0xe3f4831c, 0xe3308349, 0xe26d8377, 0xe1a983a6, 0xe0e683d6, 0xe0238407,
+    0xdf61843a, 0xde9e846e, 0xdddc84a3, 0xdd1b84d9, 0xdc598511, 0xdb998549,
+    0xdad88583, 0xda1885be, 0xd95885fa, 0xd8988637, 0xd7d98676, 0xd71b86b6,
+    0xd65c86f6, 0xd59e8738, 0xd4e1877b, 0xd42487c0, 0xd3678805, 0xd2ab884c,
+    0xd1ef8894, 0xd13488dd, 0xd0798927, 0xcfbe8972, 0xcf0489be, 0xce4b8a0c,
+    0xcd928a5a, 0xccd98aaa, 0xcc218afb, 0xcb698b4d, 0xcab28ba0, 0xc9fc8bf5,
+    0xc9468c4a, 0xc8908ca1, 0xc7db8cf8, 0xc7278d51, 0xc6738dab, 0xc5c08e06,
+    0xc50d8e62, 0xc45b8ebf, 0xc3a98f1d, 0xc2f88f7d, 0xc2488fdd, 0xc198903e,
+    0xc0e990a1, 0xc03a9105, 0xbf8c9169, 0xbedf91cf, 0xbe329236, 0xbd86929e,
+    0xbcda9307, 0xbc2f9371, 0xbb8593dc, 0xbadc9448, 0xba3394b5, 0xb98b9523,
+    0xb8e39592, 0xb83c9603, 0xb7969674, 0xb6f196e6, 0xb64c9759, 0xb5a897ce,
+    0xb5059843, 0xb46298b9, 0xb3c09930, 0xb31f99a9, 0xb27f9a22, 0xb1df9a9c,
+    0xb1409b17, 0xb0a29b94, 0xb0059c11, 0xaf689c8f, 0xaecc9d0e, 0xae319d8e,
+    0xad979e0f, 0xacfd9e91, 0xac659f14, 0xabcd9f98, 0xab36a01c, 0xaaa0a0a2,
+    0xaa0aa129, 0xa976a1b0, 0xa8e2a238, 0xa84fa2c2, 0xa7bda34c, 0xa72ca3d7,
+    0xa69ca463, 0xa60ca4f0, 0xa57ea57e, 0xa4f0a60c, 0xa463a69c, 0xa3d7a72c,
+    0xa34ca7bd, 0xa2c2a84f, 0xa238a8e2, 0xa1b0a976, 0xa129aa0a, 0xa0a2aaa0,
+    0xa01cab36, 0x9f98abcd, 0x9f14ac65, 0x9e91acfd, 0x9e0fad97, 0x9d8eae31,
+    0x9d0eaecc, 0x9c8faf68, 0x9c11b005, 0x9b94b0a2, 0x9b17b140, 0x9a9cb1df,
+    0x9a22b27f, 0x99a9b31f, 0x9930b3c0, 0x98b9b462, 0x9843b505, 0x97ceb5a8,
+    0x9759b64c, 0x96e6b6f1, 0x9674b796, 0x9603b83c, 0x9592b8e3, 0x9523b98b,
+    0x94b5ba33, 0x9448badc, 0x93dcbb85, 0x9371bc2f, 0x9307bcda, 0x929ebd86,
+    0x9236be32, 0x91cfbedf, 0x9169bf8c, 0x9105c03a, 0x90a1c0e9, 0x903ec198,
+    0x8fddc248, 0x8f7dc2f8, 0x8f1dc3a9, 0x8ebfc45b, 0x8e62c50d, 0x8e06c5c0,
+    0x8dabc673, 0x8d51c727, 0x8cf8c7db, 0x8ca1c890, 0x8c4ac946, 0x8bf5c9fc,
+    0x8ba0cab2, 0x8b4dcb69, 0x8afbcc21, 0x8aaaccd9, 0x8a5acd92, 0x8a0cce4b,
+    0x89becf04, 0x8972cfbe, 0x8927d079, 0x88ddd134, 0x8894d1ef, 0x884cd2ab,
+    0x8805d367, 0x87c0d424, 0x877bd4e1, 0x8738d59e, 0x86f6d65c, 0x86b6d71b,
+    0x8676d7d9, 0x8637d898, 0x85fad958, 0x85beda18, 0x8583dad8, 0x8549db99,
+    0x8511dc59, 0x84d9dd1b, 0x84a3dddc, 0x846ede9e, 0x843adf61, 0x8407e023,
+    0x83d6e0e6, 0x83a6e1a9, 0x8377e26d, 0x8349e330, 0x831ce3f4, 0x82f1e4b9,
+    0x82c6e57d, 0x829de642, 0x8276e707, 0x824fe7cd, 0x822ae892, 0x8205e958,
+    0x81e2ea1e, 0x81c1eae4, 0x81a0ebab, 0x8181ec71, 0x8163ed38, 0x8146edff,
+    0x812aeec6, 0x8110ef8d, 0x80f6f055, 0x80def11c, 0x80c8f1e4, 0x80b2f2ac,
+    0x809ef374, 0x808bf43c, 0x8079f505, 0x8068f5cd, 0x8059f695, 0x804bf75e,
+    0x803ef827, 0x8032f8ef, 0x8027f9b8, 0x801efa81, 0x8016fb4a, 0x800ffc13,
+    0x800afcdc, 0x8006fda5, 0x8002fe6e, 0x8001ff37,
+};
+
+/* Returns the multiplication of \conj{a} and {b}. */
+static inline int32_t mult(int32_t a, int32_t b)
+{
+#if __ARM_ARCH__ >= 6
+    int32_t t = b;
+    __asm__("smuad  %0, %0, %1"          : "+r" (t) : "r" (a));
+    __asm__("smusdx %0, %0, %1"          : "+r" (b) : "r" (a));
+    __asm__("pkhtb  %0, %0, %1, ASR #16" : "+r" (t) : "r" (b));
+    return t;
+#else
+    return (((a >> 16) * (b >> 16) + (int16_t)a * (int16_t)b) & ~0xFFFF) |
+        ((((a >> 16) * (int16_t)b - (int16_t)a * (b >> 16)) >> 16) & 0xFFFF);
+#endif
+}
+
+static inline int32_t half(int32_t a)
+{
+#if __ARM_ARCH__ >= 6
+    __asm__("shadd16 %0, %0, %1" : "+r" (a) : "r" (0));
+    return a;
+#else
+    return ((a >> 1) & ~0x8000) | (a & 0x8000);
+#endif
+}
+
+void fixed_fft(int n, int32_t *v)
+{
+    int scale = LOG_FFT_SIZE, i, p, r;
+
+    for (r = 0, i = 1; i < n; ++i) {
+        for (p = n; !(p & r); p >>= 1, r ^= p);
+        if (i < r) {
+            int32_t t = v[i];
+            v[i] = v[r];
+            v[r] = t;
+        }
+    }
+
+    for (p = 1; p < n; p <<= 1) {
+        --scale;
+
+        for (i = 0; i < n; i += p << 1) {
+            int32_t x = half(v[i]);
+            int32_t y = half(v[i + p]);
+            v[i] = x + y;
+            v[i + p] = x - y;
+        }
+
+        for (r = 1; r < p; ++r) {
+            int32_t w = MAX_FFT_SIZE / 4 - (r << scale);
+            i = w >> 31;
+            w = twiddle[(w ^ i) - i] ^ (i << 16);
+            for (i = r; i < n; i += p << 1) {
+                int32_t x = half(v[i]);
+                int32_t y = mult(w, v[i + p]);
+                v[i] = x - y;
+                v[i + p] = x + y;
+            }
+        }
+    }
+}
+
+void fixed_fft_real(int n, int32_t *v)
+{
+    int scale = LOG_FFT_SIZE, m = n >> 1, i;
+
+    fixed_fft(n, v);
+    for (i = 1; i <= n; i <<= 1, --scale);
+    v[0] = mult(~v[0], 0x80008000);
+    v[m] = half(v[m]);
+
+    for (i = 1; i < n >> 1; ++i) {
+        int32_t x = half(v[i]);
+        int32_t z = half(v[n - i]);
+        int32_t y = z - (x ^ 0xFFFF);
+        x = half(x + (z ^ 0xFFFF));
+        y = mult(y, twiddle[i << scale]);
+        v[i] = x - y;
+        v[n - i] = (x + y) ^ 0xFFFF;
+    }
+}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 796731b..cf01ff6 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1162,11 +1162,19 @@
     return OK;
 }
 
-status_t StagefrightRecorder::dump(int fd, const Vector<String16>& args) const {
+status_t StagefrightRecorder::dump(
+        int fd, const Vector<String16>& args) const {
+    LOGV("dump");
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
-    snprintf(buffer, SIZE, "   Recorder: %p", this);
+    if (mWriter != 0) {
+        mWriter->dump(fd, args);
+    } else {
+        snprintf(buffer, SIZE, "   No file writer\n");
+        result.append(buffer);
+    }
+    snprintf(buffer, SIZE, "   Recorder: %p\n", this);
     snprintf(buffer, SIZE, "   Output file (fd %d):\n", mOutputFd);
     result.append(buffer);
     snprintf(buffer, SIZE, "     File format: %d\n", mOutputFormat);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 568037e..e36d9fe 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -60,6 +60,7 @@
     bool isAudio() const { return mIsAudio; }
     bool isMPEG4() const { return mIsMPEG4; }
     void addChunkOffset(off_t offset) { mChunkOffsets.push_back(offset); }
+    status_t dump(int fd, const Vector<String16>& args) const;
 
 private:
     MPEG4Writer *mOwner;
@@ -217,6 +218,37 @@
     mTracks.clear();
 }
 
+status_t MPEG4Writer::dump(
+        int fd, const Vector<String16>& args) {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
+    result.append(buffer);
+    snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    for (List<Track *>::iterator it = mTracks.begin();
+         it != mTracks.end(); ++it) {
+        (*it)->dump(fd, args);
+    }
+    return OK;
+}
+
+status_t MPEG4Writer::Track::dump(
+        int fd, const Vector<String16>& args) const {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+    snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "       reached EOS: %s\n",
+            mReachedEOS? "true": "false");
+    result.append(buffer);
+    ::write(fd, result.string(), result.size());
+    return OK;
+}
+
 status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
     Track *track = new Track(this, source);
     mTracks.push_back(track);
diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h
index 55efd41..2542e4e 100644
--- a/media/libstagefright/include/ARTSPController.h
+++ b/media/libstagefright/include/ARTSPController.h
@@ -19,6 +19,7 @@
 #define A_RTSP_CONTROLLER_H_
 
 #include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
 #include <media/stagefright/MediaExtractor.h>
 
 namespace android {
@@ -38,12 +39,32 @@
     virtual sp<MetaData> getTrackMetaData(
             size_t index, uint32_t flags);
 
+    void onMessageReceived(const sp<AMessage> &msg);
+
 protected:
     virtual ~ARTSPController();
 
 private:
+    enum {
+        kWhatConnectDone    = 'cdon',
+        kWhatDisconnectDone = 'ddon',
+    };
+
+    enum State {
+        DISCONNECTED,
+        CONNECTED,
+        CONNECTING,
+    };
+
+    Mutex mLock;
+    Condition mCondition;
+
+    State mState;
+    status_t mConnectionResult;
+
     sp<ALooper> mLooper;
     sp<MyHandler> mHandler;
+    sp<AHandlerReflector<ARTSPController> > mReflector;
 
     DISALLOW_EVIL_CONSTRUCTORS(ARTSPController);
 };
diff --git a/media/libstagefright/rtsp/ARTSPController.cpp b/media/libstagefright/rtsp/ARTSPController.cpp
index 195323e..ceae3a6 100644
--- a/media/libstagefright/rtsp/ARTSPController.cpp
+++ b/media/libstagefright/rtsp/ARTSPController.cpp
@@ -26,31 +26,57 @@
 namespace android {
 
 ARTSPController::ARTSPController(const sp<ALooper> &looper)
-    : mLooper(looper) {
+    : mState(DISCONNECTED),
+      mLooper(looper) {
+    mReflector = new AHandlerReflector<ARTSPController>(this);
+    looper->registerHandler(mReflector);
 }
 
 ARTSPController::~ARTSPController() {
+    disconnect();
+    mLooper->unregisterHandler(mReflector->id());
 }
 
 status_t ARTSPController::connect(const char *url) {
-    if (mHandler != NULL) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mState != DISCONNECTED) {
         return ERROR_ALREADY_CONNECTED;
     }
 
+    sp<AMessage> msg = new AMessage(kWhatConnectDone, mReflector->id());
+
     mHandler = new MyHandler(url, mLooper);
-    mHandler->connect();
 
-    sleep(10);
+    mState = CONNECTING;
 
-    return OK;
+    mHandler->connect(msg);
+
+    while (mState == CONNECTING) {
+        mCondition.wait(mLock);
+    }
+
+    if (mState != CONNECTED) {
+        mHandler.clear();
+    }
+
+    return mConnectionResult;
 }
 
 void ARTSPController::disconnect() {
-    if (mHandler == NULL) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mState != CONNECTED) {
         return;
     }
 
-    mHandler->disconnect();
+    sp<AMessage> msg = new AMessage(kWhatDisconnectDone, mReflector->id());
+    mHandler->disconnect(msg);
+
+    while (mState == CONNECTED) {
+        mCondition.wait(mLock);
+    }
+
     mHandler.clear();
 }
 
@@ -75,4 +101,31 @@
     return mHandler->getPacketSource(index)->getFormat();
 }
 
+void ARTSPController::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+        case kWhatConnectDone:
+        {
+            Mutex::Autolock autoLock(mLock);
+
+            CHECK(msg->findInt32("result", &mConnectionResult));
+            mState = (mConnectionResult == OK) ? CONNECTED : DISCONNECTED;
+
+            mCondition.signal();
+            break;
+        }
+
+        case kWhatDisconnectDone:
+        {
+            Mutex::Autolock autoLock(mLock);
+            mState = DISCONNECTED;
+            mCondition.signal();
+            break;
+        }
+
+        default:
+            TRESPASS();
+            break;
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index b19ad48..90070c9 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -45,18 +45,21 @@
                           PRIORITY_HIGHEST);
     }
 
-    void connect() {
+    void connect(const sp<AMessage> &doneMsg) {
+        mDoneMsg = doneMsg;
+
         mLooper->registerHandler(this);
         mLooper->registerHandler(mConn);
         (1 ? mNetLooper : mLooper)->registerHandler(mRTPConn);
-        sp<AMessage> reply = new AMessage('conn', id());
 
+        sp<AMessage> reply = new AMessage('conn', id());
         mConn->connect(mSessionURL.c_str(), reply);
     }
 
-    void disconnect() {
-        sp<AMessage> reply = new AMessage('disc', id());
-        mConn->disconnect(reply);
+    void disconnect(const sp<AMessage> &doneMsg) {
+        mDoneMsg = doneMsg;
+
+        (new AMessage('abor', id()))->post();
     }
 
     virtual void onMessageReceived(const sp<AMessage> &msg) {
@@ -250,8 +253,9 @@
 
                     CHECK_EQ(response->mStatusCode, 200u);
 
-                    sp<AMessage> msg = new AMessage('abor', id());
-                    msg->post(60000000ll);
+                    mDoneMsg->setInt32("result", OK);
+                    mDoneMsg->post();
+                    mDoneMsg = NULL;
                 } else {
                     sp<AMessage> reply = new AMessage('disc', id());
                     mConn->disconnect(reply);
@@ -301,6 +305,11 @@
 
             case 'quit':
             {
+                if (mDoneMsg != NULL) {
+                    mDoneMsg->setInt32("result", UNKNOWN_ERROR);
+                    mDoneMsg->post();
+                    mDoneMsg = NULL;
+                }
                 break;
             }
 
@@ -380,6 +389,8 @@
     };
     Vector<TrackInfo> mTracks;
 
+    sp<AMessage> mDoneMsg;
+
     void setupTrack(size_t index) {
         sp<APacketSource> source =
             new APacketSource(mSessionDesc, index);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index af4d7e4..0eca082 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -171,6 +171,7 @@
     private static final int MESSAGE_START_ACCESS_POINT = 6;
     private static final int MESSAGE_STOP_ACCESS_POINT  = 7;
     private static final int MESSAGE_SET_CHANNELS       = 8;
+    private static final int MESSAGE_ENABLE_NETWORKS    = 9;
 
 
     private final  WifiHandler mWifiHandler;
@@ -1663,6 +1664,12 @@
                 mDeviceIdle = false;
                 mScreenOff = false;
                 mWifiStateTracker.enableRssiPolling(true);
+                /* DHCP or other temporary failures in the past can prevent
+                 * a disabled network from being connected to, enable on screen on
+                 */
+                if (mWifiStateTracker.isAnyNetworkDisabled()) {
+                    sendEnableNetworksMessage();
+                }
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 Slog.d(TAG, "ACTION_SCREEN_OFF");
                 mScreenOff = true;
@@ -1794,6 +1801,10 @@
                 uid, 0, wifiConfig).sendToTarget();
     }
 
+    private void sendEnableNetworksMessage() {
+        Message.obtain(mWifiHandler, MESSAGE_ENABLE_NETWORKS).sendToTarget();
+    }
+
     private void updateWifiState() {
         // send a message so it's all serialized
         Message.obtain(mWifiHandler, MESSAGE_UPDATE_STATE, 0, 0).sendToTarget();
@@ -1956,6 +1967,10 @@
                     setNumAllowedChannelsBlocking(msg.arg1, msg.arg2 == 1);
                     break;
 
+                case MESSAGE_ENABLE_NETWORKS:
+                    mWifiStateTracker.enableAllNetworks(getConfiguredNetworks());
+                    break;
+
             }
         }
     }
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 0cc1f46..22dbda3 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -59,6 +59,7 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Track the state of Wifi connectivity. All event handling is done here,
@@ -216,6 +217,9 @@
     private boolean mUseStaticIp = false;
     private int mReconnectCount;
 
+    /* Tracks if any network in the configuration is disabled */
+    private AtomicBoolean mIsAnyNetworkDisabled = new AtomicBoolean(false);
+
     // used to store the (non-persisted) num determined during device boot 
     // (from mcc or other phone info) before the driver is started.
     private int mNumAllowedChannels = 0;
@@ -814,6 +818,7 @@
                 mTornDownByConnMgr = false;
                 mLastBssid = null;
                 mLastSsid = null;
+                mIsAnyNetworkDisabled.set(false);
                 requestConnectionInfo();
                 SupplicantState supplState = mWifiInfo.getSupplicantState();
                 /**
@@ -1585,6 +1590,10 @@
         mWifiState.set(wifiState);
     }
 
+    public boolean isAnyNetworkDisabled() {
+        return mIsAnyNetworkDisabled.get();
+    }
+
    /**
      * The WifiNative interface functions are listed below.
      * The only native call that is not synchronized on
@@ -1785,10 +1794,28 @@
         if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
+        if (disableOthers) mIsAnyNetworkDisabled.set(true);
         return WifiNative.enableNetworkCommand(netId, disableOthers);
     }
 
     /**
+     * Enable all networks
+     *
+     * @param networks list of configured networks
+     */
+    public synchronized void enableAllNetworks(List<WifiConfiguration> networks) {
+        if (mWifiState.get() != WIFI_STATE_ENABLED) {
+            return;
+        }
+        mIsAnyNetworkDisabled.set(false);
+        for (WifiConfiguration config : networks) {
+            if (config.status == WifiConfiguration.Status.DISABLED) {
+                WifiNative.enableNetworkCommand(config.networkId, false);
+            }
+        }
+    }
+
+    /**
      * Disable a network
      *
      * @param netId network id of the network
@@ -1798,6 +1825,7 @@
         if (mWifiState.get() != WIFI_STATE_ENABLED) {
             return false;
         }
+        mIsAnyNetworkDisabled.set(true);
         return WifiNative.disableNetworkCommand(netId);
     }