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.