Hands On

Positions to Addresses with Gesture Events and HERE in Android

By Nic Raboy | 18 December 2018

I’ve been writing a few tutorials on using the HERE Location Services (HLS) platform with Android. These tutorials have included showing a map, dropping markers, and geocoding address information to latitude and longitude position information. This time around we’re going to take things to the next level by converting latitude and longitude position information to address information within an Android application.

To be specific in what we plan to accomplish, take a look at the following animated image.

android-reverse-geocoder-click

As you can see, we are able to place a marker on the map at any given touch location. After tapping the marker, an address is displayed in the form of a Toast notification. From a technical perspective, all this is accomplished by finding the latitude and longitude position from a gesture listener and that coordinate is converted to an address with the HERE Reverse Geocoder API for Android.

So let’s take a look at how we can actually accomplish this.

Getting the Latitude and Longitude Coordinates of a Touch Event Listener

To get the latitude and longitude coordinates from a HERE map based on a tap event, we need to create a gesture listener. A gesture listener can track any kind of gesture on our map, not limited to tap, long tap, and double tap events.

Assuming you’ve got HERE configured within your Android application, you could add the following after the initialization of the map engine has completed:

mapFragment.getMapGesture().addOnGestureListener(new MapGesture.OnGestureListener.OnGestureListenerAdapter() {
    @Override
    public boolean onTapEvent(PointF p) {
        GeoCoordinate position = map.pixelToGeo(p);
        return false;
    }

    @Override
    public boolean onLongPressEvent(PointF p) {
        GeoCoordinate position = map.pixelToGeo(p);
        return false;
    }
});

In the above example, mapFragment is the variable that is actually connected to our Fragment defined in the XML. Only two of the many possible events are overridden, and in our example so far, they accomplish the same thing, which is taking the point on the map and converting it to the latitude and longitude position equivalent.

For clarity, both mapFragment and map should have been defined somewhere within your Activity like follows:

private Map map;
private MapFragment mapFragment;

If you need help configuring HERE in your Android application and setting up the initial map, you might want to check out my previous tutorial titled, Getting Started with HERE Maps in an Android Application.

Since we have our listener in place, we probably want a way to visually display our touch events, rather than spitting out log data. The simplest thing to do beyond log data is to drop a marker on the map. You can create a method called dropMarker that contains the following:

public void dropMarker(GeoCoordinate position) {
    if(marker != null) {
        map.removeMapObject(marker);
    }
    marker = new MapMarker();
    marker.setCoordinate(position);
    map.addMapObject(marker);
}

If the above code looks familiar, it is because I had written about it in my tutorial titled, Placing Markers on a Map in Android with HERE. Essentially, we’d want to call the dropMarker function after we have the position from the touch event.

Now that we have markers and a gesture event listener registered, we can focus on converting our positions to addresses.

Reverse Geocoding Latitude and Longitude Positions to Addresses

The concept behind a reverse geocoder is that we are providing a latitude and longitude and it is searching for a selection of addresses where the first result is the nearest match. With the address information, we’ll have access to a concatenated string of all information as well as separated pieces of information such as the city, state, street, etc.

Take the following reverseGeocode method:

public void reverseGeocode(GeoCoordinate position) {
    ReverseGeocodeRequest request = new ReverseGeocodeRequest(position);
    request.execute(new ResultListener<Address>() {
        @Override
        public void onCompleted(Address data, ErrorCode error) {
            if (error != ErrorCode.NONE) {
                Log.e("HERE", error.toString());
            } else {
                Toast.makeText(getApplicationContext(), data.getText(), Toast.LENGTH_LONG).show();
            }
        }
    });
}

When the reverse geocoding is complete, a Toast notification is displayed with the concatenated string of data. To clear up any loose ends, we can revisit the gesture listener and make it look like the following:

mapFragment.getMapGesture().addOnGestureListener(new MapGesture.OnGestureListener.OnGestureListenerAdapter() {
    @Override
    public boolean onTapEvent(PointF p) {
        ArrayList<ViewObject> viewObjectList = (ArrayList<ViewObject>) map.getSelectedObjects(p);
        for (ViewObject viewObject : viewObjectList) {
            if (viewObject.getBaseType() == ViewObject.Type.USER_OBJECT) {
                MapObject mapObject = (MapObject) viewObject;
                if (mapObject.getType() == MapObject.Type.MARKER) {
                    MapMarker selectedMarker = ((MapMarker) mapObject);
                    reverseGeocode(selectedMarker.getCoordinate());
                }
            }
        }
        return false;
    }

    @Override
    public boolean onLongPressEvent(PointF p) {
        GeoCoordinate position = map.pixelToGeo(p);
        dropMarker(position);
        return false;
    }
});

When a long press is done, the latitude and longitude position is found and a marker is placed at that position with the dropMarker method. When a tap is done, we find all the objects on the map at that given set of pixels. These objects include markers and everything else that may be placed. Once we have that list, we can loop through them and figure out if they are a marker. If we are dealing with a marker that was tapped, we can reverse geocode the coordinate.

To give credit where credit is due, I actually pulled the code for getting the selected map objects from Stack Overflow.

Conclusion

You just saw how to override gestures on a HERE map, place markers at a position based on a tap event, and reverse geocode latitude and longitude coordinates to addresses within an Android mobile application. As previously mentioned, this is just the next part in my series of tutorials in regards to using HERE within Android.

If you’re curious on getting configured to use HERE with Android, I recommend you check out my previous tutorial. I also have a tutorial for converting addresses to coordinates in a tutorial titled, Geocoding Addresses with HERE in an Android Mobile Application.