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 that some Android devices do not have a GPS sensor and may fallback to Wi-Fi positioning using a NETWORK_PROVIDER.

The HERE SDK smoothly works together with any proprietary positioning solution. In the future, a comprehensive HERE positioning solution is planned with more advanced features. 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 burdening task to request the user's permission. Please refer to the Get Started section for more information.

As a next step, 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.

Apparently, 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);

Then you can start locating and hook in a listener:

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

And 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, new Date());
    location.bearingInDegrees = (double) nativeLocation.getBearing();
    location.speedInMetersPerSecond = (double) nativeLocation.getSpeed();
    location.horizontalAccuracyInMeters = (double) nativeLocation.getAccuracy();

    return location;
}

A practical example for this class can be seen in the Navigation example app, which is available for the Navigate Edition of the HERE SDK from here.

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

results matching ""

    No results matching ""