Location Services

Introduction to Location Services and the Fused Location Provider

PDF for offline use
Sample Code:
Related SDKs:

Let us know how you feel about this

Translation Quality


0/250

last updated: 2017-10

This guide introduces location-awareness in Android applications, and illustrates how to get the user's location using the Android Location Service API, as well as the Fused Location Provider available with the Google Location Services API.

Overview

Android provides access to various location technologies such as cell tower location, Wi-Fi, and GPS. The details of each location technology are abstracted through location providers, allowing applications to obtain a location in the same way regardless of the provider used. In this guide, we introduce the Android Location Service API, and show how to communicate with the system location Service using a LocationManager. In the second part of the guide, we explore the Google Location Services API, which changes location providers dynamically using the Fused Location Provider from Google Play Services.

Location Fundamentals

Several concepts are the same in Android regardless of what API you choose for working with location data. This section introduces Location Providers and location-related permissions.

Location Providers

Several technologies are used internally to pinpoint the user's location. The hardware used depends on the type of location provider selected for the job of collecting data. Android uses three location providers:

  • GPS Provider – GPS gives the most accurate location, uses the most power, and works best outdoors. This provider uses a combination of GPS and assisted GPS (aGPS), which returns GPS data collected by cellular towers.

  • Network Provider – Providers a combination of WiFi and Cellular data, including aGPS data collected by cell towers. It uses less power than the GPS Provider, but returns location data of varying accuracy.

  • Passive Provider – A "piggyback" option using providers requested by other applications or Services to generate location data in an application. This is a less reliable but power-saving option ideal for applications that don't require constant location updates to work.

Location providers aren't always available. For example, we might want to use GPS for our application, but GPS might be turned off in Settings, or the device might not have GPS at all. If a specific provider is not available, choosing that provider may return null.

Location Permissions

A location-aware application needs access a device's hardware sensors in order to receive GPS, Wi-Fi, and cellular data. Access is controlled through appropriate permissions in the application's Android Manifest. There are two permissions available - depending on your application's requirements and your choice of API, you will want to allow one:

  • ACCESS_FINE_LOCATION – Allows an application access to GPS. Required for the GPS Provider and Passive Provider options (Passive Provider needs permission to access GPS data collected by another application or Service). Optional permission for the Network Provider.

  • ACCESS_COARSE_LOCATION – Allows an application access to Cellular and Wi-Fi location. Required for Network Provider if ACCESS_FINE_LOCATION is not set.

For apps that target API version 21 (Android 5.0 Lollipop) or higher, you can enable ACCESS_FINE_LOCATION and still run on devices that do not have GPS hardware. If your app requires GPS hardware, you should explicitly add an android.hardware.location.gps uses-feature element to the Android Manifest. For more information, see the Android uses-feature element reference.

To set the permissions, expand the Properties folder in the Solution Pad and double-click AndroidManifest.xml. The permissions will be listed under Required Permissions:

Screenshot of the Android Manifest Required Permissions settings

Setting either of these permissions tells Android that your application needs access to the location provider for the given location technology.

Note: Setting ACCESS_FINE_LOCATION implies access to both coarse and fine location data. You should never have to set both permissions, only the minimal permission your app requires to work.

Get Location with Android Location Service

The Android Location Service is the standard API for using location information on Android. Location data is collected by hardware sensors and collected by a system Service, which is accessed in the application with a LocationManager class and a ILocationListener.

To obtain the user's location using Android Location Service, we need to:

  1. Get a reference to the LocationManager class.
  2. Use the LocationManager to request location updates for a specified provider.
  3. Implement the ILocationListener interface and handle events when the location changes.
  4. Stop location updates when application enters the background.

Location Service

The Location Service is a special type of Service managed by the System. A System Service interacts with the device hardware, and is always running. To tap into location updates in our application, we will subscribe to location updates from the system Location Service using a LocationManager and a RequestLocationUpdates call.

Location Manager

We can access the system location service with an instance of the LocationManager class. LocationManager is a special class that lets us interact with the system location Service and call methods on it. An application can get a reference to the LocationManager by calling GetSystemService and passing in a Service type, as shown below:

LocationManager locMgr;
...
locMgr = GetSystemService (Context.LocationService) as LocationManager;

OnCreate is a good place to get a reference to the LocationManager. It's a good idea to keep the LocationManager as a class variable, so we can call it at various points in the Activity lifecycle.

Request Location Updates

Once our application has a reference to the LocationManager, it needs to tell the LocationManager what type of location information we're interested in, and how often we want to receive updates. We can do this by calling RequestionLocationUpdates on the LocationManager object, and passing in some criteria for updates.

The RequestionLocationUpdates method tells the system location Service that your application would like to start receiving location updates. This method allows you to specify the provider, as well as time and distance thresholds to control update frequency. For example, the code below requests location updates every 2000 milliseconds, and only when the location changes more than 1 metre:

protected override void OnResume ()
{
    base.OnResume ();
    string Provider = LocationManager.GpsProvider;

    if(locMgr.IsProviderEnabled(Provider))
    {
      locMgr.RequestLocationUpdates (Provider, 2000, 1, this);
    }
    else
    {
      Log.Info(tag, Provider + " is not available. Does the device have location services enabled?");
    }
}

An application should request location updates only as often as required for the application to perform well. This preserves battery life and creates a better experience for the user.

Subscribe to Location Updates

Once an application has requested updates from the LocationManager, it can receive information from the Service by implementing the ILocationListener interface. This interface provides methods for listening to the location Service and the location provider.

The following code sample implements ILocationListener in the MainActivity:

public class MainActivity : Activity, ILocationListener
{
  ...

  public void OnProviderEnabled (string provider)
  {
    ...
  }
  public void OnProviderDisabled (string provider)
  {
    ...
  }
  public void OnStatusChanged (string provider, Availability status, Bundle extras)
  {
    ...
  }
  public void OnLocationChanged (Android.Locations.Location location)
  {
    ...
  }
}

This interface lets us subscribe to four system events to check the status of the provider and get location information:

  • OnProviderEnabled and OnProviderDisabled - Complementary methods that notify the application when the user has enabled or disabled the provider (for example, a user may disable GPS to conserve battery).

  • OnStatusChanged - Notifies the application when the provider's availability changes, and provides the accompanying status (for example, GPS availability may change when a user walks indoors).

  • OnLocationChanged - The System will call OnLocationChanged when the user's location changes enough to qualify as a location change according to the Criteria we set when requesting location updates.

The following code example illustrates how an Activity might implement the OnLocationChanged method to receive location updates and print them to the screen:

TextView latitude;
TextView longitude;

public void OnLocationChanged (Location location)
{
  latitude.Text = "Latitude: " + location.Latitude;
  longitude.Text = "Longitude: " + location.Longitude;
}

Stop Location Updates

The RemoveUpdates method tells the system location Service to stop sending updates to our application. By calling this in OnPause, we are able to conserve power if an application doesn't need location updates while its Activity is not on the screen:

protected override void OnPause ()
{
  base.OnPause ();
  locMgr.RemoveUpdates (this);
}

If your application needs to get location updates while in the background, you'll want to create a custom Service that subscribes to the system Location Service. Refer to the Backgrounding with Android Services guide for more information.

GetBestProvider

The application above sets GPS as the location provider. However, GPS may not be available in all cases, such as if the device is indoors or does not have a GPS receiver. If this is the case, we will get a null return for the Provider.

If we want our app to work when GPS is not available, we can use the GetBestProvider method to ask for the best available (device-supported and user-enabled) location provider at application launch. Instead of passing in a specific provider, we can tell GetBestProvider our requirements for the provider - such as accuracy and power - with a Criteria object. GetBestProvider returns the best provider for the given Criteria.

The following code shows how to get the best available provider and use it when requesting location updates:

Criteria locationCriteria = new Criteria();

locationCriteria.Accuracy = Accuracy.Coarse;
locationCriteria.PowerRequirement = Power.Medium;

locationProvider = locMgr.GetBestProvider(locationCriteria, true);

if(locationProvider != null)
{
  locMgr.RequestLocationUpdates (locationProvider, 2000, 1, this);
}
else
{
  Log.Info(tag, "No location providers available");
}
ℹ️

Note: If the user has disabled all location providers, GetBestProvider will return null. To see how this code works on a real device, be sure to enable GPS, Wi-Fi, and cellular networks under Google Settings > Location > Mode as shown in this screenshot:

Settings Location Mode screen on an Android phone

The screenshot below demonstrates the location application running using GetBestProvider:

GetBestProvider app displaying latitude, longitude, and provider

Keep in mind that GetBestProvider does not change the provider dynamically. Rather, it determines the best available provider once during the Activity lifecycle. If the provider status changes after it has been set, the application will require additional code in the ILocationListener methods - OnProviderEnabled, OnProviderDisabled, and OnStatusChanged - to handle every possibility related to the provider switch.

To make this common scenario simpler and less code-intensive, Google introduced the FusedLocationProvider to handle changing providers for us. FusedLocationProvider is part of the Google Location Services API shipped with Google Play Services. We'll cover it next.

Get Location with Google Location Services and the Fused Location Provider

The Fused Location Provider is an optional alternative to the standard Android Location Service that automatically handles changes in provider status inside the application. The Fused Location Provider is part of Google Play Services, which includes the new Google Location Services APIs. Google Play Services must be installed and configured properly in the application for the Fused Location Provider API to work.

An application using the Fused Location Provider switches dynamically between providers to select the best provider available at any given moment. For example, a user walking around outdoors gets the best location reading with GPS. If the user then walks into a bar, where GPS works poorly (if at all), the provider automatically switches to WiFi, which works better indoors.

The Fused Location Provider API provides a variety of other tools to empower location-aware applications, including geofencing and activity monitoring. In this section, we are going to focus on the basics of setting up the LocationClient, establishing providers, and getting the user's location.

To get the user's location using the Fused Location Provider, we need to:

  1. Add the Google Play Services component, and configure the application to use it.

  2. Define a LocationClient and implement the required interfaces to interact with the Client.

  3. For continuous updates, define a LocationRequest with requirements for location updates, and provide an instance of ILocationListener to listen for location changes.

  4. Stop location updates when application enters the background.

Google Play Services

The Fused Location Provider and other Google Location Services APIs require the Google Play Services SDK. You'll need to take extra steps to bind the Google Play Services client library in your app, and ensure that the user's device has Google Play Services installed as well.

For a detailed description of how to add the the Google Play Services Component to an application, refer to this blog post.

Location Client

The LocationClient is conceptually similar to a LocationManager - it lets the application interact with already-running location services, and request location data for the application to use. In this example we're going to wire up a LocationClient to get the device location in two ways: first with a call to get the user's last known coordinates, and then with a request to get continuous updates on the user's position using a instance of Android.Locations.ILocationListener.

The Location Client works by establishing a connection to Google Location Services, and listening for location data from the Service. Before we can use a Location Client, we need to implement two interfaces to monitor connection status. IGooglePlayServicesClientConnectionCallbacks listens for client connection status with the OnConnected and OnDisconnected methods; IGooglePlayServicesClientOnConnectionFailedListener lets us troubleshoot problems with the connection with OnConnectionFailed.

Here is what our MainActivity looks like implementing the two interfaces:

public class MainActivity : Activity, IGooglePlayServicesClientConnectionCallbacks, IGooglePlayServicesClientOnConnectionFailedListener
{
  ...
  public void OnConnected (Bundle bundle)
  {
    ...
  }
  public void OnDisconnected (Bundle bundle)
  {
    ...
  }
  public void OnConnectionFailed (Bundle bundle)
  {
    ...
  }
}

Next, we need to instantiate a LocationClient instance. This requires a Context, an IGooglePlayServicesClientConnectionCallbacks, and an IGooglePlayServicesClientOnConnectionFailedListener. We'll establish a connection by calling Connect on the Client:

LocationClient locClient = new LocationClient (this, this, this);
locClient.Connect();

Once the Client is connected, we can begin working with location data. We can do this directly in OnConnected, as illustrated below:

public void OnConnected (Bundle bundle)
{
  if(locClient.LastLocation != null)
  {
    Location location = locClient.LastLocation;
    latitude.Text = "Latitude: " + location.Latitude.ToString();
    longitude.Text = "Longitude: " + location.Longitude.ToString();
  }
}

When we're done receiving location information, we can disconnect from the Client:

protected override void OnPause ()
{
  base.OnPause ();

  if (locClient.IsConnected) {
    locClient.Disconnect ();
  }
}

In the example above we used the Location Client's LastLocation property to get the user's last known location. LastLocation gives a one-time reading useful for apps that can work with rough location coordinates - for example, weather apps. However, LastLocation doesn't track the user's movement over time. If our app needs to monitor movement, we will want to subscribe to continuous location updates from the Location Client. The next section shows how to request continuous location updates from the Client.

ℹ️

Note: When using the Location Client outside of the OnConnected method, always perform a check to ensure the Client is connected. You can check if the Client is connected with the IsConnected property.

Request Location Updates

If we want to receive continuous location updates from the Google Location Service, we need to implement the ILocationListener interface. This resembles the ILocationListener interface we implemented for the Android Location Service, but in this case the listener is provided by the Google Location Services API. In fact, we have to specify the full namespace of the Android.Gms.Location.ILocationListener in order to avoid confusion with Android's ILocationListener (Android.Locations.ILocationListener). Unlike the Android ILocationListener, the Location Listener from Google Play Services only provides one method for listening to the location Service, OnLocationChanged.

The following code snippet shows how to implement the ILocationListener in an Activity:

public class MainActivity : Activity, IGooglePlayServicesClientConnectionCallbacks, IGooglePlayServicesClientOnConnectionFailedListener, Android.Gms.Location.ILocationListener
{
  ...
  public void OnLocationChanged (Location location)
  {
    ...
  }
}

Requesting location updates with the Fused Location Provider is similar to calling GetBestProvider in the Android Location Service. Instead of specifying a Provider, we specify the requirements for our location data, and we can do that with a LocationRequest object. The LocationRequest contains everything we expect from the location updates returned by the Service - how often we want updates to appear, the minimum displacement between updates, how many updates we want, and our Priority for the updates - whether we want to prioritize accuracy, power, or a balanced approach. The LocationRequest class is analogous to the Criteria object in the Android Location Service, and in fact the APIs are very similar.

To set the Priority, we pass in a constant (status code) for one of the following settings:

  1. Balanced Power/Accuracy (102) - The balanced approach takes a coarse accuracy of about 100 meters, and a medium draw on power. This is the default setting.

  2. High Accuracy (100) - This setting draws on battery life to return the most accurate location information available.

  3. Low Power (104) - This priority returns location data with a coarse accuracy of about 10 kilometers, and attempts to conserve power.

  4. No Power (105) - A no-power setting works similarly to a Passive Provider, conserving power by only providing location updates when they are requested by other applications.

Keep in mind that the provider used to satisfy each priority is greatly influenced by other settings and situations. For example, GPS will only be used for high accuracy updates if the ACCESS_FINE_LOCATION permission is set in the Android Manifest. The no power option may use GPS updates if another application is requesting them.

In the example below, we set a high accuracy priority, and specify updates every second (1000 milliseconds), with a minimum wait of 500 milliseconds between updates. Then, we call RequestLocationUpdates on the Location Client, passing in our Request and a Location Listener:

public void OnConnected (Bundle bundle)
{
  LocationRequest locRequest = new LocationRequest ();

  locRequest.SetPriority(100);
  locRequest.SetFastestInterval(500);
  locRequest.SetInterval(1000);

  locClient.RequestLocationUpdates (locRequest, this);
}

Again, ensure the Client is connected before requesting location updates outside the OnConnected method.

ℹ️

Note: The Client will attempt to update the location once every Interval, but no faster than the FastestInterval - the minimal time between updates. The default FastestInterval for updates is 1 minute. If you want to receive location updates more than once a minute, you will need to change both the Interval and the FastestInterval values to reflect this.

Receive Location Updates

In the code example below, we listen to location updates in OnLocationChanged and print the user's latitude and longitude:

public void OnLocationChanged (Location location)
{
  latitude.Text = "Latitude: " + location.Latitude.ToString();
  longitude.Text = "Longitude: " + location.Longitude.ToString();
}

Stop Location Updates

To stop location updates, call RemoveLocationUpdates on the LocationClient, passing in the ILocationListener instance that should stop listening for updates:

protected override void OnPause ()
{
  base.OnPause ();

  if (locClient.IsConnected) {
    locClient.RemoveLocationUpdates (this);
    locClient.Disconnect ();
  }
}

We can check the provider by getting the value of Location.Provider on any Location value returned by the Service. For Google Location Services, the provider will always be "fused":

Screenshot of the FusedLocationProvider app displaying latitude, longitude, and provider

Summary

In this guide, we obtained the user's location using both the Android Location Service and the Fused Location Provider from Google Location Services API.

Xamarin Workbook

If it's not already installed, install the Xamarin Workbooks app first. The workbook file should download automatically, but if it doesn't, just click to start the workbook download manually.