Integrating On-Street Parking API via HERE SDK

This guide demonstrates the integration of the On-Street Parking API using the HERE SDK. The solution retrieves and visualizes on-street parking segments on the map, utilizing HERE's search and parking APIs. The logic provided here is generic and can be adapted to other applications using the HERE SDK.

Overview
--------

The solution involves:

1. Using HERE SDK's Search API to reverse-geocode a location and fetch nearby places.
2. Calling the On-Street Parking API to retrieve parking segment data for a bounding box around a selected location.
3. Visualizing the parking segments as polylines on the HERE map.

---

Steps for Integration
---------------------

### 1. Setting Up the HERE SDK

Ensure the HERE SDK is initialized in your app. Refer to HERE SDK documentation for initialization steps.

---

### 2. Making the On-Street Parking API Request

#### Search Integration

Use the HERE SDK Search API to get a place or location details for reverse-geocoding.

<br />private final SearchCallback addressSearchCallback = new SearchCallback() { @Override public void onSearchCompleted(@Nullable SearchError searchError, @Nullable List list) { if (searchError != null) { showDialog("Reverse Geocoding", "Error: " + searchError.toString()); return; } // If error is null, the list is guaranteed to be non-empty. Place place = list.get(0); addPoiMapMarker(place.getGeoCoordinates(), null); // Add a marker for the place. getOnStreetParkingData(mapView, place); // Fetch parking data. }}`;<br />

#### On-Street Parking API Call

Once a place is identified, its bounding box is used to fetch parking segments via the On-Street Parking API.

<br />private void getOnStreetParkingData(MapView mapView, Place placeData) { SDKNativeEngine sdkNativeEngine = SDKNativeEngine.getSharedInstance(); Authentication.authenticate(sdkNativeEngine, (authenticationError, authenticationData) -> { if (authenticationError != null) { Log.e("Authentication", "Failed: " + authenticationError.toString()); return; } // Use the bounding box to fetch parking data if (placeData.getBoundingBox() != null) { String bbox = placeData.getBoundingBox().northEastCorner.latitude + "," + placeData.getBoundingBox().northEastCorner.longitude + "," + placeData.getBoundingBox().southWestCorner.latitude + "," + placeData.getBoundingBox().southWestCorner.longitude; String geometryType = "segmentAnchor"; // Retrofit call to fetch parking data Call call = RetrofitClient.getInstance().getMyApi().getOnStreetParking( bbox, geometryType, "Bearer " + authenticationData.token); call.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { if (response.isSuccessful() && response.body() != null) { List segments = response.body().getParkingSegments(); drawSegmentsOnMap(mapView, segments); // Visualize parking data on the map. } else { Log.e("API Response", "Empty or Error Response"); } } @Override public void onFailure(Call call, Throwable t) { Log.e("API Error", t.getMessage()); } }); } });}<br />

### 3. Visualizing Parking Segments

The parking segments are drawn as polylines on the map using HERE SDK's MapPolyline class.

<br />private void drawSegmentsOnMap(MapView mapView, List segmentsItems) { List mapPolylines = new ArrayList<>(); for (ParkingSegmentsItem segment : segmentsItems) { List orientedSegmentRefs = segment.getSegmentAnchor().getOrientedSegmentRef(); for (OrientedSegmentRefItem ref : orientedSegmentRefs) { GeoPolyline geoPolyline = getSegmentGeometry(ref); // Retrieve the segment geometry. if (geoPolyline != null) { MapPolyline polyline = createPolyline(geoPolyline); if (polyline != null) { mapPolylines.add(polyline); } } } } mapView.getMapScene().addMapPolylines(mapPolylines); // Add all polylines to the map.}<br />

#### Getting Segment Geometry

The segment geometry is retrieved using HERE's SegmentReferenceConverter and SegmentDataLoader.

<br />public GeoPolyline getSegmentGeometry(OrientedSegmentRefItem orientedSegmentRefBean) { try { SegmentReference segmentReference = SegmentReference.fromString(orientedSegmentRefBean.getSegmentRef().getIdentifier()); segmentReference.tilePartitionId = Integer.parseInt(orientedSegmentRefBean.getSegmentRef().getPartitionName()); segmentReference.travelDirection = orientedSegmentRefBean.isInverted() ? TravelDirection.NEGATIVE : TravelDirection.POSITIVE; SegmentReferenceConverter converter = new SegmentReferenceConverter(SDKNativeEngine.getSharedInstance()); DirectedOCMSegmentId ocmSegmentId = converter.getOCMSegmentId(segmentReference); SegmentDataLoader segmentDataLoader = new SegmentDataLoader(SDKNativeEngine.getSharedInstance()); SegmentData segmentData = segmentDataLoader.loadData(ocmSegmentId.id, new SegmentDataLoaderOptions()); return segmentData != null ? segmentData.getPolyline() : null; } catch (Exception e) { Log.e("Segment Geometry Error", e.getMessage()); return null; }}`<br />

#### Creating Polylines

Polylines are styled and added to the map.

<br />private MapPolyline createPolyline(GeoPolyline geoPolyline) { try { float widthInPixels = 20; com.here.sdk.core.Color lineColor = com.here.sdk.core.Color.valueOf(ContextCompat.getColor(context, R.color.design_default_color_secondary_variant)); return new MapPolyline(geoPolyline, new MapPolyline.SolidRepresentation( new MapMeasureDependentRenderSize(RenderSize.Unit.PIXELS, widthInPixels), lineColor, LineCap.ROUND)); } catch (Exception e) { Log.e("Polyline Error", e.getMessage()); return null; }}`<br />

### 4. Highlighting Polylines

To achieve this functionality, we dynamically adjust the width and color of the selected polyline and revert any previously selected polylines to their original appearance.

#### Define State for Selected Polylines

Use a List to keep track of the currently selected polyline(s).

<br />private List selectedParkingPolylines = new ArrayList<>();<br />

#### Handle Click Events

The onClickPolyline() method processes the user's interaction. It adjusts the visual properties of both the previously selected and newly selected polylines.

<br />@Overridepublic void onClickPolyLine(List place) { int selectedWidthInPixels = 30; // Width for the selected polyline int unSelectedWidthInPixels = 20; // Width for the unselected polyline // Colors for unselected and selected states com.here.sdk.core.Color lineColor = com.here.sdk.core.Color.valueOf(ContextCompat.getColor(this, R.color.design_default_color_secondary_variant)); com.here.sdk.core.Color selectedLineColor = com.here.sdk.core.Color.valueOf(ContextCompat.getColor(this, R.color.selectedRouteColor)); // Reset previously selected polylines if (!selectedParkingPolylines.isEmpty()) { mapView.getMapScene().removeMapPolylines(selectedParkingPolylines); // Remove current polylines try { MapPolyline.Representation representation = new MapPolyline.SolidRepresentation( new MapMeasureDependentRenderSize(RenderSize.Unit.PIXELS, unSelectedWidthInPixels), lineColor, LineCap.ROUND); selectedParkingPolylines.forEach(mapPolyline -> mapPolyline.setRepresentation(representation)); // Revert appearance } catch (Exception e) { Log.e(TAG, "onClickPolyLine: " + e.getLocalizedMessage()); } mapView.getMapScene().addMapPolylines(selectedParkingPolylines); // Re-add with default style } // Highlight the newly selected polyline(s) mapView.getMapScene().removeMapPolylines(place); try { MapPolyline.Representation representation = new MapPolyline.SolidRepresentation( new MapMeasureDependentRenderSize(RenderSize.Unit.PIXELS, selectedWidthInPixels), selectedLineColor, LineCap.ROUND); place.forEach(mapPolyline -> mapPolyline.setRepresentation(representation)); // Apply selected style } catch (Exception e) { Log.e(TAG, "onClickPolyLine: " + e.getLocalizedMessage()); } mapView.getMapScene().addMapPolylines(place); // Add the selected polyline(s) to the map // Update the selected state selectedParkingPolylines = place;}<br />

### 5. API Definition

#### Retrofit Interface

Defines the endpoint for fetching on-street parking data.

<br />public interface Api { String ON_STREET_PARKING_BASE_URL = "https://osp.cc.api.here.com/"; @GET("parking/segments") Call getOnStreetParking(@Query("bbox") String bbox, @Query("geometryType") String geometryType, @Header("Authorization") String token);}<br />

#### Retrofit Client

Singleton pattern for Retrofit client initialization.

<br />public class RetrofitClient { private static RetrofitClient instance = null; private Api myApi; private RetrofitClient() { Retrofit retrofit = new Retrofit.Builder() .baseUrl(Api.ON_STREET_PARKING_BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); myApi = retrofit.create(Api.class); } public static synchronized RetrofitClient getInstance() { if (instance == null) { instance = new RetrofitClient(); } return instance; } public Api getMyApi() { return myApi; }}`<br />

### 6. Dependencies

Add the following dependencies to build.gradle(:app):

<br />implementation 'com.squareup.retrofit2:retrofit:2.7.2'implementation 'com.squareup.retrofit2:converter-gson:2.7.2'<br />

Please download the full sample integration from this link.

Please note: Kindly get in touch with your Account Executive(AE) or HERE sales representative to get your whitelisted credentials in order to access HERE Parking API with HERE SDK.


Did this page help you?