Integrate indoor maps

HERE Indoor Map provides functionality to load, show, and interact with private venues on a map. For more information on HERE Indoor Map, see the HERE Indoor Map Guide.

Note

If you are a venue owner and are interested in leveraging HERE Indoor Map with the HERE SDK, contact us at

venues.support@here.com.

An airport venue with a customized floor switcher.

Currently, the HERE SDK only supports private venues, therefore your venue data will only be shown in your app. By default, no venues are visible on the map. Each of your venues receives a unique venue ID that is tied to your HERE SDK credentials.

Initialize the VenueEngine

Before you can begin using the HERE Indoor Map API, the VenueEngine instance must be created and started. This can be done after a map initialization, however The best time to create the VenueEngine is after the map loads a scene:

private void loadMapScene() {
    // Load a scene from the HERE SDK to render the map with a map scheme.
    mapView.getMapScene().loadScene(MapScheme.NORMAL_DAY, mapError -> {
        if (mapError == null) {
            // Hide extruded buildings layer, so it will not overlaps with venues.
            List<String> mapFeatures = new ArrayList<>();
            mapFeatures.add(MapFeatures.EXTRUDED_BUILDINGS);
            mapView.getMapScene().disableFeatures(mapFeatures);        

            // Create a venue engine object. Once an initialization is done, the callback
            // will be called.
            try {
                venueEngine = new VenueEngine(this ::onVenueEngineInitCompleted);
            } catch (InstantiationErrorException e) {
                Log.e(TAG, "SDK Engine instantiation failed");
                e.printStackTrace();
            }
        } else {
            Log.d(TAG, "Loading map failed: mapError: " + mapError.name());
        }
    });
}

Once the VenueEngine is initialized, a callback is called. From this point on, there is access to both the VenueService and the VenueMap. A VenueService is used to load venues, and a VenueMap controls the venues on the map. Inside the callback, all required listeners can be added, and then the VenueEngine must be started. The platform map catalog HRN can be set once the VenueEngine is started if user does not want to use default collection HRN.

Note

Setting HRN is optional. If a user does not set HRN, default collection HRN is automatically selected. If a user want to use any other collection, respective HRN can be set. An error log is generated that indicates missing or invalid HRN values. For more information on how you can receive a valid HRN string for your project, see the HERE Indoor Map Guide.

private void onVenueEngineInitCompleted() {
    // Get VenueService and VenueMap objects.
    VenueService service = venueEngine.getVenueService();
    VenueMap venueMap = venueEngine.getVenueMap();

    // Add needed listeners.
    service.add(serviceListener);
    service.add(venueListener);
    venueMap.add(venueSelectionListener);

    // Start VenueEngine. Once authentication is done, the authentication callback
    // will be triggered. Afterwards, VenueEngine will start VenueService. Once VenueService
    // is initialized, VenueServiceListener.onInitializationCompleted method will be called.
    venueEngine.start((authenticationError, authenticationData) -> {
        if (authenticationError != null) {
            Log.e(TAG, "Failed to authenticate, reason: " + authenticationError.value);
        }
    });

    if(HRN != "") {
        // Set platform catalog HRN
        service.setHrn(HRN);
    }
}

Once the VenueEngine is started, it authenticates using the current credentials, and then starts the VenueService. Once the VenueService is initialized, the VenueServiceListener.onInitializationCompleted() method is called:

// Listener for the VenueService event.
private final VenueServiceListener serviceListener = new VenueServiceListener() {
    @Override
    public void onInitializationCompleted(@NonNull VenueServiceInitStatus result) {
        if (result == VenueServiceInitStatus.ONLINE_SUCCESS) {
            Log.d(TAG, "VenueService initialization is successful.");
        } else {
            Log.e(TAG, "Failed to initialize venue service.");
        }
    }

    @Override
    public void onVenueServiceStopped() {}
};

Start the VenueEngine using a token

The VenueEngine can be started using a valid HERE Indoor Platform project token. For additional information on the HERE platform project management and project workflows refer to HERE Platform Project management

private void onVenueEngineInitCompleted() {
    // Get VenueService and VenueMap objects.
    VenueService service = venueEngine.getVenueService();
    VenueMap venueMap = venueEngine.getVenueMap();

    // Add needed listeners.
    service.add(serviceListener);
    service.add(venueListener);
    venueMap.add(venueSelectionListener);

    // Start VenueEngine by replacing TOKEN_GOES_HERE with token you have in String data type.
    // Afterwards, VenueEngine will start VenueService. Once VenueService
    // is initialized, VenueServiceListener.onInitializationCompleted method will be called.
    venueEngine.start("TOKEN_GOES_HERE");
}

List all indoor maps

The HERE Indoor Maps API allows you to list all private venues that are accessible for your account and the selected collection. VenueMap contains a list which holds VenueInfo elements containing venue Identifier, venue ID and venue Name.

List<VenueInfo> venueInfo = venueEngine.getVenueMap().getVenueInfoList();
for (int i = 0; i< venueInfo.size(); i++) {
    Log.d(TAG, "Venue Identifier: " + venueInfo.get(i).getVenueIdentifier() + " Venue Id: "+venueInfo.get(i).getVenueId() + " Venue Name: "+venueInfo.get(i).getVenueName());
}

Load and show a venue

The HERE Indoor Map API allows you to load and visualize venues by ID. You must know the venue's ID for the current set of credentials. There are several ways to load and visualize the venues. In the VenueService, there is a method to start a new venues loading queue:

venueEngine.getVenueService().startLoading(/*VENUE_ID_LIST*/);

You can also add a venue ID to the existing loading queue:

venueEngine.getVenueService().addVenueToLoad(/*VENUE_ID*/);

A VenueMap has two methods to add a venue to the map: selectVenueAsync() and addVenueAsync(). Both methods use getVenueService().addVenueToLoad() to load the venue by ID and then add it to the map. The method selectVenueAsync() also selects the venue:

venueEngine.getVenueMap().selectVenueAsync(/*VENUE_ID*/);
venueEngine.getVenueMap().addVenueAsync(/*VENUE_ID*/);

Once the venue is loaded, the VenueService calls the VenueListener.onGetVenueCompleted() method:

// Listener for the venue loading event
private final VenueListener venueListener = (venueId, venueModel, online, venueStyle) -> {
    if (venueModel == null) {
        Log.e(TAG, "Failed to load the venue: " + venueId);
    }
};

Once the venue is loaded successfully, if you are using the addVenueAsync() method, only the VenueLifecycleListener.onVenueAdded() method will be triggered. If you are using the selectVenueAsync() method, the VenueSelectionListener.onSelectedVenueChanged() method will also be triggered:

// Listener for the venue selection event.
private final VenueSelectionListener venueSelectionListener =
    (deselectedVenue, selectedVenue) -> {
        if (selectedVenue != null) {
            // Move camera to the selected venue.
            GeoCoordinates venueCenter = selectedVenue.getVenueModel().getCenter();
            final double distanceInMeters = 500;
            MapMeasure mapMeasureZoom = new MapMeasure(MapMeasure.Kind.DISTANCE, distanceInMeters);
            mapView.getCamera().lookAt(
                    new GeoCoordinates(venueCenter.latitude, venueCenter.longitude),
                    mapMeasureZoom);
        }
    };

A Venue can also be removed from the VenueMap, which triggers the VenueLifecycleListener.onVenueRemoved() method:

venueEngine.getVenueMap().removeVenue(venue);

Label text preference

You can override the default label text preference for a venue.

Once the VenueEngine is initialized, a callback is called. From this point on, there is access to the VenueService. The optional method setLabeltextPreference() can be called to set the label text preference during rendering. Overriding the default style label text preference provides an opportunity to set the following options as a list where the order defines the preference:

  • "OCCUPANT_NAMES"
  • "SPACE_NAME"
  • "INTERNAL_ADDRESS"
  • "SPACE_TYPE_NAME"
  • "SPACE_CATEGORY_NAME"

These can be set in any desired order. For example, if the label text preference does not contain "OCCUPANT_NAMES" then it will switch to "SPACE_NAME" and so on, based on the order of the list. Nothing is displayed if no preference is found.

private void onVenueEngineInitCompleted() {
    // Get VenueService and VenueMap objects.
    VenueService service = venueEngine.getVenueService();
    VenueMap venueMap = venueEngine.getVenueMap();

    // Add needed listeners.
    service.add(serviceListener);
    service.add(venueListener);
    venueMap.add(venueSelectionListener);

    // Start VenueEngine. Once authentication is done, the authentication callback
    // will be triggered. After, VenueEngine will start VenueService. Once VenueService
    // is initialized, VenueServiceListener.onInitializationCompleted method will be called.
    venueEngine.start((authenticationError, authenticationData) -> {
        if (authenticationError != null) {
            Log.e(TAG, "Failed to authenticate, reason: " + authenticationError.value);
        }
    });

    if(HRN != "") {
        // Set platform catalog HRN
        service.setHrn(HRN);
    }

    // Set label text preference
    service.setLabeltextPreference(LabelPref);
}

Select venue drawings and levels

A Venue object allows you to control the state of the venue.

The methods getSelectedDrawing() and setSelectedDrawing() allow you to get and set a drawing which is visible on the map. When a new drawing is selected, the VenueDrawingSelectionListener.onDrawingSelected() method is triggered.

The following provides an example of how to select a drawing when an item is clicked in a ListView:

@Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
    VenueModel venueModel = venue.getVenueModel();
    // Set the selected drawing when a user clicks on the item in the list.
    venue.setSelectedDrawing(venueModel.getDrawings().get(position));
}

The methods getSelectedLevelIndex() and setSelectedLevelIndex() allow you to get and set a level based on the location within the list of levels. When a new level is selected, the VenueLevelSelectionListener.onLevelSelected() method is triggered.

The following provides an example of how to select a level based on a reversed levels list from ListView:

listView.setOnItemClickListener((parent, view, position, id) -> {
    if (venueMap.getSelectedVenue() != null) {
        // Revers an index, as levels in LevelSwitcher appear in a different order
        venueMap.getSelectedVenue().setSelectedLevelIndex(maxLevelIndex - position);
    }
});

A full example of the UI switchers to control drawings and levels is available in the IndoorMap example app, available on GitHub.

Customize the style of a venue

You can change the visual style of VenueGeometry objects. Geometry style and/or label style objects must be created and provided to the Venue.setCustomStyle() method:

private final VenueGeometryStyle geometryStyle = new VenueGeometryStyle(
        SELECTED_COLOR, SELECTED_OUTLINE_COLOR, 1);
private final VenueLabelStyle labelStyle = new VenueLabelStyle(
        SELECTED_TEXT_COLOR, SELECTED_TEXT_OUTLINE_COLOR, 1, 28);
ArrayList<VenueGeometry> geometries =
        new ArrayList<>(Collections.singletonList(geometry));
venue.setCustomStyle(geometries, geometryStyle, labelStyle);

Select space by identifier

The ID of spaces, levels and drawings can be extracted using getIdentifier(), e.g. for spaces call: spaces.getIdentifier(). Then, for using those id values, a specific space can be searched in a level or a drawing with getGeometryById(String id).

ArrayList<String> geometriesID;
ArrayList<VenueGeometry> geometries;
for(String id : geometriesID)
{
    VenueGeometry geometry = selectVenue.getSelectedDrawing().getGeometryById(id);
    geometries.add(geometry);
}
private final VenueGeometryStyle geometryStyle = new VenueGeometryStyle(
        SELECTED_COLOR, SELECTED_OUTLINE_COLOR, 1);
private final VenueLabelStyle labelStyle = new VenueLabelStyle(
        SELECTED_TEXT_COLOR, SELECTED_TEXT_OUTLINE_COLOR, 1, 28);
selectVenue.setCustomStyle(geometries, geometryStyle, labelStyle);

Handle tap gestures on a venue

You can select a venue object by tapping it. First, set the tap listener:

mapView.getGestures().setTapListener(tapListener);

Inside the tap listener, you can use the tapped geographic coordinates as parameter for the VenueMap.getGeometry() and VenueMap.getVenue() methods:

private final TapListener tapListener = origin -> {
    deselectGeometry();

    // Get geo position of the tap.
    GeoCoordinates position = mapView.viewToGeoCoordinates(origin);
    if (position == null) {
        return;
    }

    VenueMap venueMap = venueEngine.getVenueMap();
    // Get VenueGeometry under the tapped position.
    VenueGeometry geometry = venueMap.getGeometry(position);

    if (geometry != null) {
        // If there is a geometry, put a marker on top of it.
        marker = new MapMarker(position, markerImage, new Anchor2D(0.5f, 1f));
        mapView.getMapScene().addMapMarker(marker);
    } else {
        // If no geometry was tapped, check if there is a not-selected venue under
        // the tapped position. If there is one, select it.
        Venue venue = venueMap.getVenue(position);
        if (venue != null) {
            venueMap.setSelectedVenue(venue);
        }
    }
};

private void deselectGeometry() {
    // If marker is already on the screen, remove it.
    if (marker != null) {
        mapView.getMapScene().removeMapMarker(marker);
    }
}

HERE recommends that you deselect the tapped geometry when the selected venue, drawing, or level has changed:

private final VenueSelectionListener venueSelectionListener =
        (deselectedController, selectedController) -> deselectGeometry();

private final VenueDrawingSelectionListener drawingSelectionListener =
        (venue, deselectedController, selectedController) -> deselectGeometry();

private final VenueLevelSelectionListener levelChangeListener =
        (venue, drawing, oldLevel, newLevel) -> deselectGeometry();

void setVenueMap(VenueMap venueMap) {
    if (this.venueMap == venueMap) {
        return;
    }

    // Remove old venue map listeners.
    removeListeners();
    this.venueMap = venueMap;

    if (this.venueMap != null) {
        this.venueMap.add(venueSelectionListener);
        this.venueMap.add(drawingSelectionListener);
        this.venueMap.add(levelChangeListener);
        deselectGeometry();
    }
}

private void removeListeners() {

    if (this.venueMap != null) {
        this.venueMap.remove(venueSelectionListener);
        this.venueMap.remove(drawingSelectionListener);
        this.venueMap.remove(levelChangeListener);
    }
}

A full example showing usage of the map tap event with venues is available in the IndoorMap example app, available on GitHub.

results matching ""

    No results matching ""