Home | History | Annotate | Download | only in location
      1 page.title=Location Strategies
      2 excludeFromSuggestions=true
      3 @jd:body
      4 
      5 <div id="tb-wrapper">
      6 <div id="tb">
      7   <h2>In this document</h2>
      8   <ol>
      9     <li><a href="#Challenges">Challenges in Determining User Location</a></li>
     10     <li><a href="#Updates">Requesting Location Updates</a>
     11       <ol>
     12         <li><a href="#Permission">Requesting User Permissions</a></li>
     13       </ol>
     14     </li>
     15     <li><a href="#BestPerformance">Defining a Model for the Best Performance</a>
     16       <ol>
     17         <li><a href="#Flow">Flow for obtaining user location</a></li>
     18         <li><a href="#StartListening">Deciding when to start listening for updates</a></li>
     19         <li><a href="#FastFix">Getting a fast fix with the last known location</a></li>
     20         <li><a href="#StopListening">Deciding when to stop listening for updates</a></li>
     21         <li><a href="#BestEstimate">Maintaining a current best estimate</a></li>
     22         <li><a href="#Adjusting">Adjusting the model to save battery and data exchange</a></li>
     23       </ol>
     24     </li>
     25     <li><a href="#MockData">Providing Mock Location Data</a></li>
     26   </ol>
     27   <h2>Key classes</h2>
     28   <ol>
     29     <li>{@link android.location.LocationManager}</li>
     30     <li>{@link android.location.LocationListener}</li>
     31   </ol>
     32 </div>
     33 </div>
     34 <div class="note">
     35 <p>
     36     <strong>Note:</strong> The strategies described in this guide apply to the platform location
     37     API in {@link android.location}. The Google Location Services API, part of Google Play
     38     Services, provides a more powerful, high-level framework that automatically handles location
     39     providers, user movement, and location accuracy. It also handles
     40     location update scheduling based on power consumption parameters you provide. In most cases,
     41     you'll get better battery performance, as well as more appropriate accuracy, by using the
     42     Location Services API.
     43 </p>
     44 <p>
     45     To learn more about the Location Services API, see
     46     <a href="{@docRoot}google/play-services/location.html">Google Location Services for Android</a>.
     47 </p>
     48 </div>
     49   <p>Knowing where the user is allows your application to be smarter and deliver
     50 better information to the user. When developing a location-aware application for Android, you can
     51 utilize GPS and Android's Network Location Provider to acquire the user location. Although
     52 GPS is most accurate, it only works outdoors, it quickly consumes battery power, and doesn't return
     53 the location as quickly as users want. Android's Network Location Provider determines user location
     54 using cell tower and Wi-Fi signals, providing location information in a way that
     55 works indoors and outdoors, responds faster, and uses less battery power. To obtain the user
     56 location in your application, you can use both GPS and the Network Location Provider, or just
     57 one.</p>
     58 
     59 
     60 <h2 id="Challenges">Challenges in Determining User Location</h2>
     61 
     62 <p>Obtaining user location from a mobile device can be complicated. There are several reasons
     63 why a location reading (regardless of the source) can contain errors and be inaccurate.
     64 Some sources of error in the user location include:</p>
     65 
     66 <ul>
     67   <li><b>Multitude of location sources</b>
     68     <p>GPS, Cell-ID, and Wi-Fi can each provide a clue to users location. Determining which to use
     69 and trust is a matter of trade-offs in accuracy, speed, and battery-efficiency.</p>
     70   </li>
     71   <li><b>User movement</b>
     72     <p>Because the user location changes, you must account for movement by re-estimating user
     73 location every so often.</p>
     74   </li>
     75   <li><b>Varying accuracy</b>
     76     <p>Location estimates coming from each location source are not consistent in their
     77 accuracy. A location obtained 10 seconds ago from one source might be more accurate than the newest
     78 location from another or same source.</p>
     79   </li>
     80 </ul>
     81 
     82   <p>These problems can make it difficult to obtain a reliable user location reading. This
     83 document provides information to help you meet these challenges to obtain a reliable location
     84 reading. It also provides ideas that you can use in your
     85 application to provide the user with an accurate and responsive geo-location experience.</p>
     86 
     87 
     88 <h2 id="Updates">Requesting Location Updates</h2>
     89 
     90   <p>Before addressing some of the location errors described above, here is an introduction to
     91 how you can obtain user location on Android.</p>
     92 
     93   <p>Getting user location in Android works by means of callback. You indicate that you'd
     94 like to receive location updates from the {@link android.location.LocationManager} ("Location
     95 Manager") by calling {@link android.location.LocationManager#requestLocationUpdates
     96 requestLocationUpdates()}, passing it a
     97 {@link android.location.LocationListener}. Your {@link android.location.LocationListener} must
     98 implement several callback methods that the Location Manager calls when the user location
     99 changes or when the status of the service changes.</p>
    100 
    101 <p>For example, the following code shows how to define a {@link android.location.LocationListener}
    102 and request location updates:
    103   </p>
    104 
    105 <pre>
    106 // Acquire a reference to the system Location Manager
    107 LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
    108 
    109 // Define a listener that responds to location updates
    110 LocationListener locationListener = new LocationListener() {
    111     public void onLocationChanged(Location location) {
    112       // Called when a new location is found by the network location provider.
    113       makeUseOfNewLocation(location);
    114     }
    115 
    116     public void onStatusChanged(String provider, int status, Bundle extras) {}
    117 
    118     public void onProviderEnabled(String provider) {}
    119 
    120     public void onProviderDisabled(String provider) {}
    121   };
    122 
    123 // Register the listener with the Location Manager to receive location updates
    124 locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
    125 </pre>
    126 
    127   <p>The first parameter in {@link
    128 android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} is the type of
    129 location provider to use (in this case, the Network Location Provider for cell tower and Wi-Fi
    130 based location). You can control the frequency at which your listener receives updates
    131 with the second and third parameter&mdash;the second is the minimum time interval between
    132 notifications and the third is the minimum change in distance between notifications&mdash;setting
    133 both to zero requests location notifications as frequently as possible. The last parameter is your
    134 {@link android.location.LocationListener}, which receives callbacks for location updates.</p>
    135 
    136 <p>To request location updates from the GPS provider,
    137 substitute <code>GPS_PROVIDER</code> for <code>NETWORK_PROVIDER</code>. You can also request
    138 location updates from both the GPS and the Network Location Provider by calling {@link
    139 android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} twice&mdash;once
    140 for <code>NETWORK_PROVIDER</code> and once for <code>GPS_PROVIDER</code>.</p>
    141 
    142 
    143 <h3 id="Permission">Requesting User Permissions</h3>
    144 
    145 <p>In order to receive location updates from <code>NETWORK_PROVIDER</code> or
    146 <code>GPS_PROVIDER</code>, you must request user permission by declaring either the {@code
    147 ACCESS_COARSE_LOCATION} or {@code ACCESS_FINE_LOCATION} permission, respectively, in your Android
    148 manifest file. For example:</p>
    149 
    150 <pre>
    151 &lt;manifest ... &gt;
    152     &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
    153     ...
    154 &lt;/manifest&gt;
    155 </pre>
    156 
    157 <p>Without these permissions, your application will fail at runtime when requesting
    158 location updates.</p>
    159 
    160 <p class="note"><strong>Note:</strong> If you are using both <code>NETWORK_PROVIDER</code> and
    161 <code>GPS_PROVIDER</code>, then you need to request only the {@code ACCESS_FINE_LOCATION}
    162 permission, because it includes permission for both providers. (Permission for {@code
    163 ACCESS_COARSE_LOCATION} includes permission only for <code>NETWORK_PROVIDER</code>.)</p>
    164 
    165 
    166 <h2 id="BestPerformance">Defining a Model for the Best Performance</h2>
    167 
    168   <p>Location-based applications are now commonplace, but due to the less than optimal
    169 accuracy, user movement, the multitude of methods to obtain the location, and the desire to conserve
    170 battery, getting user location is complicated. To overcome the obstacles of obtaining a good user
    171 location while preserving battery power, you must define a consistent model that specifies how your
    172 application obtains the user location. This model includes when you start and stop listening for
    173 updates and when to use cached location data.</p>
    174 
    175 
    176   <h3 id="Flow">Flow for obtaining user location</h3>
    177 
    178   <p>Here's the typical flow of procedures for obtaining the user location:</p>
    179 
    180   <ol>
    181     <li>Start application.</li>
    182     <li>Sometime later, start listening for updates from desired location providers.</li>
    183     <li>Maintain a "current best estimate" of location by filtering out new, but less accurate
    184 fixes.</li>
    185     <li>Stop listening for location updates.</li>
    186     <li>Take advantage of the last best location estimate.</li>
    187   </ol>
    188 
    189   <p>Figure 1 demonstrates this model in a timeline that visualizes the period in which an
    190 application is listening for location updates and the events that occur during that time.</p>
    191 
    192 <img src="{@docRoot}images/location/getting-location.png" alt="" />
    193 <p class="img-caption"><strong>Figure 1.</strong> A timeline representing the window in which an
    194 application listens for location updates.</p>
    195 
    196   <p>This model of a window&mdash;during which location updates are received&mdash;frames many of
    197 the decisions you need to make when adding location-based services to your application.</p>
    198 
    199 
    200   <h3 id="StartListening">Deciding when to start listening for updates</h3>
    201 
    202   <p>You might want to start listening for location updates as soon as your application starts, or
    203 only after users activate a certain feature. Be aware that long windows of listening for location
    204 fixes can consume a lot of battery power, but short periods might not allow for sufficient
    205 accuracy.</p>
    206 
    207   <p>As demonstrated above, you can begin listening for updates by calling {@link
    208 android.location.LocationManager#requestLocationUpdates requestLocationUpdates()}:</p>
    209 
    210 <pre>
    211 String locationProvider = LocationManager.NETWORK_PROVIDER;
    212 // Or, use GPS location data:
    213 // String locationProvider = LocationManager.GPS_PROVIDER;
    214 
    215 locationManager.requestLocationUpdates(locationProvider, 0, 0, locationListener);
    216 </pre>
    217 
    218 
    219   <h3 id="FastFix">Getting a fast fix with the last known location</h3>
    220 
    221   <p>The time it takes for your location listener to receive the first location fix is often too
    222 long for users wait. Until a more accurate location is provided to your location listener, you
    223 should utilize a cached location by calling {@link
    224 android.location.LocationManager#getLastKnownLocation}:</p>
    225 <pre>
    226 String locationProvider = LocationManager.NETWORK_PROVIDER;
    227 // Or use LocationManager.GPS_PROVIDER
    228 
    229 Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider);
    230 </pre>
    231 
    232 
    233   <h3 id="StopListening">Deciding when to stop listening for updates</h3>
    234 
    235   <p>The logic of deciding when new fixes are no longer necessary might range from very simple to
    236 very complex depending on your application. A short gap between when the location is acquired and
    237 when the location is used, improves the accuracy of the estimate. Always beware that listening for a
    238 long time consumes a lot of battery power, so as soon as you have the information you need, you
    239 should stop
    240 listening for updates by calling {@link android.location.LocationManager#removeUpdates}:</p>
    241 <pre>
    242 // Remove the listener you previously added
    243 locationManager.removeUpdates(locationListener);
    244 </pre>
    245 
    246 
    247   <h3 id="BestEstimate">Maintaining a current best estimate</h3>
    248 
    249   <p>You might expect that the most recent location fix is the most accurate.
    250 However, because the accuracy of a location fix varies, the most recent fix is not always the best.
    251 You should include logic for choosing location fixes based on several criteria. The criteria also
    252 varies depending on the use-cases of the application and field testing.</p>
    253 
    254   <p>Here are a few steps you can take to validate the accuracy of a location fix:</p>
    255   <ul>
    256     <li>Check if the location retrieved is significantly newer than the previous estimate.</li>
    257     <li>Check if the accuracy claimed by the location is better or worse than the previous
    258 estimate.</li>
    259     <li>Check which provider the new location is from and determine if you trust it more.</li>
    260   </ul>
    261 
    262   <p>An elaborate example of this logic can look something like this:</p>
    263 
    264 <pre>
    265 private static final int TWO_MINUTES = 1000 * 60 * 2;
    266 
    267 /** Determines whether one Location reading is better than the current Location fix
    268   * @param location  The new Location that you want to evaluate
    269   * @param currentBestLocation  The current Location fix, to which you want to compare the new one
    270   */
    271 protected boolean isBetterLocation(Location location, Location currentBestLocation) {
    272     if (currentBestLocation == null) {
    273         // A new location is always better than no location
    274         return true;
    275     }
    276 
    277     // Check whether the new location fix is newer or older
    278     long timeDelta = location.getTime() - currentBestLocation.getTime();
    279     boolean isSignificantlyNewer = timeDelta &gt; TWO_MINUTES;
    280     boolean isSignificantlyOlder = timeDelta &lt; -TWO_MINUTES;
    281     boolean isNewer = timeDelta > 0;
    282 
    283     // If it's been more than two minutes since the current location, use the new location
    284     // because the user has likely moved
    285     if (isSignificantlyNewer) {
    286         return true;
    287     // If the new location is more than two minutes older, it must be worse
    288     } else if (isSignificantlyOlder) {
    289         return false;
    290     }
    291 
    292     // Check whether the new location fix is more or less accurate
    293     int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
    294     boolean isLessAccurate = accuracyDelta &gt; 0;
    295     boolean isMoreAccurate = accuracyDelta &lt; 0;
    296     boolean isSignificantlyLessAccurate = accuracyDelta &gt; 200;
    297 
    298     // Check if the old and new location are from the same provider
    299     boolean isFromSameProvider = isSameProvider(location.getProvider(),
    300             currentBestLocation.getProvider());
    301 
    302     // Determine location quality using a combination of timeliness and accuracy
    303     if (isMoreAccurate) {
    304         return true;
    305     } else if (isNewer &amp;&amp; !isLessAccurate) {
    306         return true;
    307     } else if (isNewer &amp;&amp; !isSignificantlyLessAccurate &amp;&amp; isFromSameProvider) {
    308         return true;
    309     }
    310     return false;
    311 }
    312 
    313 /** Checks whether two providers are the same */
    314 private boolean isSameProvider(String provider1, String provider2) {
    315     if (provider1 == null) {
    316       return provider2 == null;
    317     }
    318     return provider1.equals(provider2);
    319 }
    320 </pre>
    321 
    322 
    323   <h3 id="Adjusting">Adjusting the model to save battery and data exchange</h3>
    324 
    325   <p>As you test your application, you might find that your model for providing good location and
    326 good performance needs some adjustment. Here are some things you might change to find a good
    327 balance between the two.</p>
    328 
    329   <h4>Reduce the size of the window</h4>
    330 
    331   <p>A smaller window in which you listen for location updates means less interaction with GPS and
    332 network location services, thus, preserving battery life. But it also allows for fewer locations
    333 from which to choose a best estimate.</p>
    334 
    335   <h4>Set the location providers to return updates less frequently</h4>
    336 
    337   <p>Reducing the rate at which new updates appear during the window can also improve battery
    338 efficiency, but at the cost of accuracy. The value of the trade-off depends on how your
    339 application is used. You can reduce the rate of updates by increasing the parameters in {@link
    340 android.location.LocationManager#requestLocationUpdates requestLocationUpdates()} that specify the
    341 interval time and minimum distance change.</p>
    342 
    343   <h4>Restrict a set of providers</h4>
    344 
    345   <p>Depending on the environment where your application is used or the desired level of accuracy,
    346 you might choose to use only the Network Location Provider or only GPS, instead of both. Interacting
    347 with only one of the services reduces battery usage at a potential cost of accuracy.</p>
    348 
    349 
    350   <h2>Common application cases</h2>
    351 
    352   <p>There are many reasons you might want to obtain the user location in your application. Below
    353 are a couple scenarios in which you can use the user location to enrich your application. Each
    354 scenario also describes good practices for when you should start and stop listening for the
    355 location, in order to get a good reading and help preserve battery life.</p>
    356 
    357 
    358   <h3>Tagging user-created content with a location</h3>
    359 
    360   <p>You might be creating an application where user-created content is tagged with a location.
    361 Think of users sharing their local experiences, posting a review for a restaurant, or recording some
    362 content that can be augmented with their current location. A model of how this
    363 interaction might happen, with respect to the location services, is visualized in figure 2.</p>
    364 
    365   <img src="{@docRoot}images/location/content-tagging.png" alt="" />
    366 <p class="img-caption"><strong>Figure 2.</strong> A timeline representing the window in which
    367 the user location is obtained and listening stops when the user consumes the current location.</p>
    368 
    369   <p>This lines up with the previous model of how user location is obtained in code (figure 1). For
    370 best location accuracy, you might choose to start listening for location updates when users begin
    371 creating
    372 the content or even when the application starts, then stop listening for updates when content is
    373 ready to be posted or recorded. You might need to consider how long a typical task of creating the
    374 content takes and judge if this duration allows for efficient collection of a location estimate.</p>
    375 
    376 
    377   <h3>Helping the user decide on where to go</h3>
    378 
    379   <p>You might be creating an application that attempts to provide users with a set
    380 of options about where to go. For example, you're looking to provide a list of nearby restaurants,
    381 stores, and entertainment and the order of recommendations changes depending on the user
    382 location.</p>
    383 
    384   <p>To accommodate such a flow, you might choose to:</p>
    385   <ul>
    386     <li>Rearrange recommendations when a new best estimate is obtained</li>
    387     <li>Stop listening for updates if the order of recommendations has stabilized</li>
    388   </ul>
    389 
    390   <p>This kind of model is visualized in figure 3.</p>
    391 
    392   <img src="{@docRoot}images/location/where-to-go.png" alt="" />
    393 <p class="img-caption"><strong>Figure 3.</strong> A timeline representing the window in which a
    394 dynamic set of data is updated each time the user location updates.</p>
    395 
    396 
    397 
    398 
    399 <h2 id="MockData">Providing Mock Location Data</h2>
    400 
    401 <p>As you develop your application, you'll certainly need to test how well your model for obtaining
    402 user location works. This is most easily done using a real Android-powered device. If, however, you
    403 don't have a device, you can still test your location-based features by mocking location data in
    404 the Android emulator. There are three different ways to send your application mock location
    405 data: using Android Studio, DDMS, or the "geo" command in the emulator console.</p>
    406 
    407 <p class="note"><strong>Note:</strong> Providing mock location data is injected as GPS location
    408 data, so you must request location updates from <code>GPS_PROVIDER</code> in order for mock location
    409 data to work.</p>
    410 
    411 <h3 id="MockAVD">Using Android Studio</h3>
    412 
    413 <p>Select <b>Tools</b> &gt; <b>Android</b> &gt; <b>AVD Manager</b>. In the Android Virtual
    414 Device Manager window, choose your AVD and launch it in the emulator by selecting the green
    415 play arrow in the Actions column.</p>
    416 
    417 <p>Then, select <b>Tools</b> &gt; <b>Android</b> &gt; <b>Android Device Monitor</b>.
    418 Select the Emulator Control tab in the Android Device Monitor window, and enter GPS coordinates
    419 under Location Controls as individual lat/long coordinates, with a GPX file for route playback,
    420 or a KML file for multiple place marks.
    421 </p>
    422 
    423 
    424 <h3 id="MockDdms">Using DDMS</h3>
    425 
    426 <p>With the DDMS tool, you can simulate location data a few different ways:</p>
    427 <ul>
    428     <li>Manually send individual longitude/latitude coordinates to the device.</li>
    429     <li>Use a GPX file describing a route for playback to the device.</li>
    430     <li>Use a KML file describing individual place marks for sequenced playback to the device.</li>
    431 </ul>
    432 
    433 <p>For more information on using DDMS to spoof location data, see
    434 <a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.
    435 
    436 
    437 <h3 id="MockGeo">Using the "geo" command in the emulator console</h3>
    438 
    439 <p>To send mock location data from the command line:</p>
    440 
    441 <ol>
    442   <li>Launch your application in the Android emulator and open a terminal/console in your SDK's
    443 <code>/tools</code> directory.</li>
    444   <li>Connect to the emulator console:
    445 <pre>telnet localhost <em>&lt;console-port&gt;</em></pre></li>
    446   <li>Send the location data:</p>
    447     <ul><li><code>geo fix</code> to send a fixed geo-location.
    448     <p>This command accepts a longitude and latitude in decimal degrees, and
    449     an optional altitude in meters. For example:</p>
    450     <pre>geo fix -121.45356 46.51119 4392</pre>
    451       </li>
    452       <li><code>geo nmea</code> to send an NMEA 0183 sentence.
    453     <p>This command accepts a single NMEA sentence of type '$GPGGA' (fix data) or '$GPRMC' (transit
    454   data).
    455     For example:</p>
    456     <pre>geo nmea $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62</pre>
    457       </li>
    458     </ul>
    459   </li>
    460 </ol>
    461 
    462 <p>For information about how to connect to the emulator console, see
    463 <a href="{@docRoot}tools/devices/emulator.html#console">Using the Emulator Console</a>.</p>
    464