SDK for Android Developer's Guide

Custom Location Extension 2

Custom Location Extension 2 (CLE2) allows you to easily distribute custom geospatial information in your mobile applications. Through CLE2 you can programatically insert spatial content to the local database and upload them to the server for data-sharing purposes. You can also perform online or offline searches. These features effectively turn the SDK for Android into a lightweight spatial storage solution that enables insertion and queries for geospatial information using optimized algorithms.

The classes that support this feature are located under com.here.android.mpa.customlocation2. Instead of having specific interfaces for location and geometry requests, CLE2 unifies all use cases in one flexible approach: the returned value always contains one of the geometry types (such as CLE2PointGeometry) along with a set of 0 to N user-defined attributes that can represent any information. There is no implied structure in these attributes. These attributes are made available as a Map of key and attribute values.

Some examples of how you can use these CLE2 features include:

  • Show all users' custom Points of Interest (POIs) within a 2km radius.
  • Online or offline search for all customer offices within Germany using an area defined by a polygon, then display the office's reception phone numbers, employee counts, and other details.
  • Edit geometry shapes in real time or in offline mode and perform queries against them to get notifications when such shapes intersect with other existing fixed shapes and other basic Geofencing solutions. For example, this can be a ‘moving platform’, such as ships near ship docks where locations are relative to GPS movements.
  • Sharing Points of Interest that are not officially available as a part of HERE map data such as city's facilities and outdoor basketball courts.
  • Persist GPS data that is tied to arbitrary data such as hiking trails with speed, even during offline mode.
  • Search for specific types of objects that are near a given route.

Layers and Filtering

All data is organized in the form of layers. When uploading, storing or search for information, a layer name string is specified and can be used to better filter relevant information.

Further filtering is possible by checking the geometry's attributes. These attributes are user-defined fields that are linked to a geometry, such as CLE2PointGeometry, and can be text or number fields.

Note: CLE2 search is restricted per layer by app credentials. To manage the access restriction of a Custom Location layer, contact your Custom Location administrator. If you do not have one, see Service Support to contact us for more details .

Inserting and Uploading Data

To upload data to the CLE2 servers, you can use the web interface or REST APIs. Refer to the following User Guide for more details: https://developer.here.com/documentation .

It is also possible to insert data locally and to the server via SDK for Android. HERE SDK makes it straightforward to generate any location-referenced data even while storing it locally offline and sequentially sharing that information to other devices when a connection is established.

Performing Spatial Searches

To perform search, choose one of the search types as shown below. A common input parameter to all requests is the layer name.

Table 1. Search Classes
Search Type Description Class Name
Proximity Retrieve geometries that are within a given radius from a center. CLE2ProximityRequest
Corridor Retrieve geometries along a route specified by a sequence of coordinates. CLE2CorridorRequest
Bounding box Retrieve geometries within a specified rectangular geographic area. CLE2BoundingBoxRequest
Quadkey Retrieve geometries that fall within a specified QuadKey. CLE2QuadkeyRequest
Attribute Retrieve all geometries that match a specified query. This type of search is only available online. CLE2AttributeRequest

Each of the search request types supports some common parameters as listed below.

Table 2. Common CLE2Request Members
Setter Method Description Example Values
setGeometry(CLE2GeometryType) Specifies the geometry type to be given as a result (online only), see details below on "Understanding the search results".
  • CLE2GeometryType.FULL
  • CLE2GeometryType.LOCAL
  • CLE2GeometryType.NONE
setCachingEnabled(boolean) Default is false. If enabled, geometries received from such online search request will be stored locally.  
setQuery(String) Currently available for online requests only. This variable allows a query filter to be specified on the user's geometry attributes so that only geometries that pass the filter are returned. Free form text with simple equality and comparison operators.  

Once you have a search request object created and set up according to your needs, call its execute(CLE2ResultListener) method. The result of the search will be delivered to the provided listener. You can get the geometries that matched search criteria from a CLE2Result object by calling getGeometries(). This list of geometry results may contain objects of the following types:

Table 3. Geometry Return Types
Class Geometry Description Relevant Getter Methods
CLE2Geometry Base class for all other geometry return values containing user-defined attributes. Map<String, String> getAttributes()
CLE2PointGeometry Represents a point in coordinates. Relates to a Point in WKT. GeoCoordinate getPoint()
CLE2MultiPointGeometry Represents a multi-point as a coordinates array. Relates to a MultiPoint in WKT. List<GeoCoordinate> getMultiPoint()
CLE2PolylineGeometry Represents a polyline as a GeoPolyline. Relates to a WKT LineString object. GeoPolyline getPolyline()
CLE2MultiPolylineGeometry Represents a multi-polyline as an array of GeoPolyline. Relates to a WKT MultiLineString object. List<GeoPolyline> getPolylines()
CLE2PolygonGeometry Represents a polygon with a GeoPolygon for the outer ring and an array of GeoPolygon for inner holes. Relates to a WKT polygon object containing all rings of this geometry. GeoPolygon getOuterRing(), List<GeoPolygon> getInnerRings()
CLE2MultiPolygonGeometry Represents a multi-polygon as an array of CLE2GeometryPolygon. Relates to a MultiPolygon object in WKT. List<CLE2PolygonGeometry> getPolygons()

In the OpenGIS (the implementation standard for Geographic Information) and WKT representation formats the concept of a polygon is defined by one outer ring polygon plus zero or more inner hole polygons. This is the reason why CLE2PolygonGeometry class contains a GeoPolygon and a secondary GeoPolygon array.

Proximity Search Request Example

To perform a custom location search, you need to create a CLE2ProximityRequest using the CLE2ProximityRequest(String layerId, GeoCoordinate center, int radius) or CLE2ProximityRequest(List<String> layerIds, GeoCoordinate center, int radius) constructor methods.

A proximity search returns a list of custom locations that fall within a specified radius of a GeoCoordinate location. For example, the following code shows how to perform a search for all locations in the previously-mentioned stores layer that exists within an 8 kilometer radius of Frankfurt Central Station:

String layerId = "HERE_SITES";
int radius = 8000; // 8 km
GeoCoordinate location = new GeoCoordinate(49.196261, -123.004773);
CLE2ProximityRequest req = new CLE2ProximityRequest(layerId, location, radius);
req.execute(new CLE2Request.CLE2ResultListener() {
  @Override
  public void onCompleted(CLE2Result result, String error)
  {
    // if CLE2Error.NONE.equals(error) is true, the request was successful
    if (error.equals(CLE2Error.NONE)) {
      List<CLE2Geometry> gemetry = result.getGeometries();
      for (CLE2Geometry geo : gemetry) {
        java.util.Map<String, String> attributeMap = geo.getAttributes();
        String name = attributeMap.get("NAME1");
        double distance = geo.getDistance();
      }
    }
  }
});

The layerId parameter represents a set of custom locations. For example, layerID="HERE_SITES" represents an example layer that contains HERE locations in Germany. You can also perform a proximity search on different layers at the same time:


List<String> layerIds = new ArrayList<String>();
layerIds.add("LAYER_1");
layerIds.add("LAYER_2");
int radius = 500; // 500 meters
GeoCoordinate location = new GeoCoordinate(50.113905,8.677608);
CLE2ProximityRequest req = new CLE2ProximityRequest(layerIds, location, radius);
req.execute(new CLE2Request.CLE2ResultListener() {
  @Override
  public void onCompleted(CLE2Result result, String error)
  {
    // if CLE2Error.NONE.equals(error) is true, the request was successful
    if (error.equals(CLE2Error.NONE)) {
      List<CLE2Geometry> gemetry = result.getGeometries();
      for (CLE2Geometry geo : gemetry) {
        java.util.Map<String, String> attributeMap = geo.getAttributes();
        String name = attributeMap.get("NAME1");
        double distance = geo.getDistance();
      }
    }
  }
});

After creating a request object you can call execute(ResultListener) method to launch the search request and listen for search results.

You can also add a filter to the request. A filter is a JavaScript-like expression that is evaluated for each location-matching search query. When specified, only locations where the expression evaluates to true are returned. For example, if you want to filter for location results that have the custom location parameter of rating greater than 3 and the name "MyPlace23", perform the following:


String layerId = "HERE_SITES";
int radius = 8000; // 8 km
GeoCoordinate location = new GeoCoordinate(49.196261, -123.004773);
CLE2ProximityRequest req = new CLE2ProximityRequest(layerId, location, radius);
String filter = "CITY == 'Burnaby' && NAME1 != 'MyPlace'";
req.setQuery(filter);
req.execute(new CLE2Request.CLE2ResultListener() {
  @Override
  public void onCompleted(CLE2Result result, String error)
  {
    // if CLE2Error.NONE.equals(error) is true, the request was successful
    if (error.equals(CLE2Error.NONE)) {
      List<CLE2Geometry> gemetry = result.getGeometries();
      for (CLE2Geometry geo : gemetry) {
        java.util.Map<String, String> attributeMap = geo.getAttributes();
        String name = attributeMap.get("NAME1");
        double distance = geo.getDistance();
      }
    }
  }
});

Iterating Over Results

The CLE2Result object contains a list of geometries that are the result of the search and makes them available with getGeometries() method. Since different types of geometry can be returned, it is recommended to test for the type before using it. For example, you can use CLE2ResultListener in a similar manner as in the following example:


CLE2ResultListener resultListener = new CLE2Request.CLE2ResultListener() {
  @Override
  public void onCompleted(CLE2Result result, String error) {
    if (!error.equals(CLE2Request.CLE2Error.NONE)) {
      // process search results
      for (CLE2Geometry geometry : result.getGeometries()) {
        if (geometry instanceof CLE2PointGeometry) {
          CLE2PointGeometry point = (CLE2PointGeometry) geometry;
          // work with point geometry data
        }
      }
    } else {
      // handle error
    }
  }
};