Find your location

When building location-aware applications, one of the most common tasks is to show the current location of the user on a map. For this, there are many different solutions available. One possible way is to use the android.location.LocationManager to get locations from the device's built-in GPS sensors.

Note

  • Note that some Android devices do not have a GPS sensor and may fallback to Wi-Fi positioning using a NETWORK_PROVIDER.
  • If GPS is available, some Android devices allow to improve the location accuracy. For this, go to Settings -> Location Services -> Google Location Accuracy - or similar.

The HERE SDK works smoothly with any proprietary or platform positioning solution. Note that a comprehensive HERE positioning solution is available as part of the Navigate Edition. A possible platform dependent implementation is shown below.

Before accessing the device's sensors, you need to ask the user for permission. Add the following permissions to your AndroidManifest file:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

For all example apps accompanying this user guide, we use a convenience class called PermissionsRequestor which takes care of the task to request the user's permission. Please refer to the Get Started section for more information.

Next, get an instance of the LocationManager from the Android platform and request location updates depending on the capabilities of the device:

locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);

if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) &&
        context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)) {
    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, LOCATION_UPDATE_INTERVAL_IN_MS, 1,this);
} else if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, LOCATION_UPDATE_INTERVAL_IN_MS, 1,this);
} else {
    Log.d(LOG_TAG, "Positioning not possible.");
    // ...
}

If GPS is not available or disabled by the user, we fallback to Wi-Fi positioning which will be much less accurate. If even that is turned off, we give up.

As you can see from above, we set the calling class as the listener, so we need to implement the LocationListener interface to start getting events:

@Override
public void onLocationChanged(android.location.Location location) {
    if (platformLocationListener != null) {
        platformLocationListener.onLocationUpdated(location);
    }
}

// ...

platformLocationListener is an interface we have defined to enable another class to easily get notified.

This is just an example of how to integrate a LocationManager that provides access to the Android location services. Feel free to adapt it to your own needs.

Below you can find the complete class:

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.util.Log;

import static android.content.Context.LOCATION_SERVICE;

// A simple Android based positioning implementation.
public class PlatformPositioningProvider implements LocationListener {

    public static final String LOG_TAG = PlatformPositioningProvider.class.getName();
    public static final int LOCATION_UPDATE_INTERVAL_IN_MS = 100;

    private Context context;
    private LocationManager locationManager;
    @Nullable
    private PlatformLocationListener platformLocationListener;

    public interface PlatformLocationListener {
        void onLocationUpdated(Location location);
    }

    public PlatformPositioningProvider(Context context) {
        this.context = context;
    }

    @Override
    public void onLocationChanged(android.location.Location location) {
        if (platformLocationListener != null) {
            platformLocationListener.onLocationUpdated(location);
        }
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        switch(status){
            case LocationProvider.AVAILABLE:
                Log.d(LOG_TAG, "PlatformPositioningProvider status: AVAILABLE");
                break;
            case LocationProvider.OUT_OF_SERVICE:
                Log.d(LOG_TAG, "PlatformPositioningProvider status: OUT_OF_SERVICE");
                break;
            case LocationProvider.TEMPORARILY_UNAVAILABLE:
                Log.d(LOG_TAG, "PlatformPositioningProvider status: TEMPORARILY_UNAVAILABLE");
                break;
            default:
                Log.d(LOG_TAG, "PlatformPositioningProvider status: UNKNOWN");
        }
    }

    @Override
    public void onProviderEnabled(String provider) {
        Log.d(LOG_TAG, "PlatformPositioningProvider enabled.");
    }

    @Override
    public void onProviderDisabled(String provider) {
        Log.d(LOG_TAG, "PlatformPositioningProvider disabled.");
    }

    public void startLocating(PlatformLocationListener locationCallback) {
        if (this.platformLocationListener != null) {
            throw new RuntimeException("Please stop locating before starting again.");
        }

        if (ActivityCompat.checkSelfPermission(context,
                Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ActivityCompat.checkSelfPermission(context,
                        Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            Log.d(LOG_TAG, "Positioning permissions denied.");
            return;
        }

        this.platformLocationListener = locationCallback;
        locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);

        if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) &&
                context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)) {
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, LOCATION_UPDATE_INTERVAL_IN_MS, 1,this);
        } else if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
            locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, LOCATION_UPDATE_INTERVAL_IN_MS, 1,this);
        } else {
            Log.d(LOG_TAG, "Positioning not possible.");
            stopLocating();
        }
    }

    public void stopLocating() {
        if (locationManager == null) {
            return;
        }

        locationManager.removeUpdates(this);
        platformLocationListener = null;
    }
}

To integrate this class in your own app, create a new instance:

platformPositioningProvider = new PlatformPositioningProvider(context);

You can then start locating and hook in a listener:

platformPositioningProvider.startLocating(new PlatformPositioningProvider.PlatformLocationListener() {
    @Override
    public void onLocationUpdated(android.location.Location location) {
        // ...
    }
});

To stop listening, call:

platformPositioningProvider.stopLocating();

Note that our class receives android.location.Location events. Use the following method to convert them to the Location class used by the HERE SDK to cover the most common fields:

private Location convertLocation(android.location.Location nativeLocation) {
    GeoCoordinates geoCoordinates = new GeoCoordinates(
            nativeLocation.getLatitude(),
            nativeLocation.getLongitude(),
            nativeLocation.getAltitude());

    Location location = new Location(geoCoordinates);

    if (nativeLocation.hasBearing()) {
        location.bearingInDegrees = (double) nativeLocation.getBearing();
    }

    if (nativeLocation.hasSpeed()) {
        location.speedInMetersPerSecond = (double) nativeLocation.getSpeed();
    }

    if (nativeLocation.hasAccuracy()) {
        location.horizontalAccuracyInMeters = (double) nativeLocation.getAccuracy();
    }

    return location;
}

For more information on the LocationManager and how to utilize other platform positioning features, please refer to the official Android documentation.

Note

A more comprehensive tutorial that shows how to build an app with HERE Positioning and GPX tracking features can be found here.

results matching ""

    No results matching ""