Android User Guide
This verison of the SDK is still in beta and public APIs are subject to change.
Welcome
Audience
VMSDK documentation is designed for people familiar with basic mobile development for Android. The latest generated docs for the Android SDK can be found here.
Supported Platforms
VMSDK supports Android 5.0+ (API 21). Consult your map provider’s documentation for their own supported platforms.
Install and run the reference app
- Make sure you have version Electric Eel (2022.1.1) or later of Android Studio.
- Download our sample app here.
- In the extracted directory, navigate to vmsdk-sampleapp and open it in Android Studio.
- The reference app uses the Google Maps SDK and the MapLibre SDK, so you will need to generate a Google API Key and generate a MapTiler API Key.
- Once you’ve generated a Google Maps API key and a MapTiler API Key, open src/main/res/values/strings.xml and update map_tiler_key and google_maps_key values.
- Build and run the app on the emulator or device.
Using Google Maps with the VMSDK is not supported in some versions of the Android emulator. You will need to use a physical device for this.
Implement
Add the dependencies to your build.gradle
The vmsdk-core
Maven package is required in your build.gradle file to use any features.
implementation 'com.aegirmaps:vmsdk-core:2.1.0-beta.2'
You also need to include a reference to the Maven Central repository if your build.gradle if you don't already have one:
repositories {
mavenCentral()
}
Load the VMD file and display your map
Now you’re ready to write code to load the venue data info from the VMD file. Consult the example in the SDK demo: MapActivity.java.
To get started, create a VMDZipFileCollection
to load the VMD data.
- Java
- Kotlin
new VMDUrlFileCollection(
"https://your_vmd_endpoint.com",
"VENUE_ID",
cacheFolder,
MapProvider.GOOGLE_MAPS,
fileCollection -> {
//start parsing the VMD after files are downloaded (asynchronously)
Map.load(fileCollection, this, callback);
return null;
}
);
VMDUrlFileCollection(
"https://your_vmd_endpoint.com",
"VENUE_ID",
cacheFolder,
MapProvider.GOOGLE_MAPS
) { fileCollection: VMDFileCollection? ->
Map.load(fileCollection, this, callback)
null
}
Implement the com.aegir.vmms.vmd.MapDelegate
interface to be notified when the VMD isfinished loading.
- Java
- Kotlin
/**
* Called when the VMD file is done loading SUCCESSFULLY
* @param vmd a Map object with venue object model and wayfinding data
*/
@Override
public void didFinishLoadingMap(Map vmd, CustomMapInfo customMapInfo)
{
// this is a good place to create your MapView and call the onCreate()
// method of that MapView instance.
this.mapView = new VectorMapView(this);
this.mapView.onCreate(this.savedInstanceState, this);
}
/**
* Called when the VMD file is done loading SUCCESSFULLY
* @param vmd a Map object with venue object model and wayfinding data
*/
override fun didFinishLoadingMap(map: Map?, customMapInfo: CustomMapInfo?) {
// this is a good place to create your MapView and call the onCreate()
// method of that MapView instance.
this.mapView = VectorMapView(this)
this.mapView.onCreate(this.savedInstanceState, this)
}
At this point, you should have a map display of the world with your map tiles superimposed.
Legacy Support
If you need to add support for parsing legacy venue map data files to your application, include the ‘vmsdk-legacy’ dependency in your project's build.gradle file. The SDK will automatically detect if it’s loading a zip file that contains legacy venue map data or new venue map data and process appropriately.
Vector map tiles and wayfinding is not supported for legacy venue maps.
Customizing your map's look and feel
If you use vector map tiles, as opposed to raster map tiles, you have great flexibility in styling your map. For more information, see Vector Map Tile Style Spec.
Global map styling
The easiest way to style your map is to create a Map Style JSON configuration file that follows the Vector Map Tile Style Spec. For a full example, see style_default.json in the demo project.
- Java
- Kotlin
//load your custom style from style_default.json configuration file
VMDAssetFile venueStyleConfig = new VMDAssetFile("style_default.json", getAssets());
VenueStyle venueStyle = new VenueStyle(venueStyleConfig,"venue_map_sample" );
//apply the style to your map
this.mapView.setStyle(venueStyle);
//load your custom style from style_default.json configuration file
val venueStyleConfig = VMDAssetFile("style_default.json", assets)
val venueStyle = VenueStyle(venueStyleConfig, "venue_map_sample")
//apply the style to your map
this.mapView.style = venueStyle
Styling individual map units
You can now add custom styles to individual map elements. This allows you to override the
overall map style defined in your map's VMVenueStyle
configuration for a single unit.
- Java
- Kotlin
//get the map unit you want to style
MapUnit mapUnit = ... //some map unit
MapView mapView = ... // some mapview
//... see class documentation for a full list of styleable attributes
VenueLayerStyle style = new VenueLayerStyle();
style.setFillColor(Color.GREEN);
style.setOutlineColor(Color.RED);
//apply the style to the unit. If the map unit is not visible, it will be
//applied the next time it is shown.
mapView.setStyleForMapUnit(style, mapUnit);
//get the map unit you want to style
val mapUnit = ... // some map Unit
val mapView = ... // some mapview
//... see class documentation for a full list of styleable attributes
val style = VenueLayerStyle()
style.fillColor = Color.GREEN
style.outlineColor = Color.RED
//apply the style to the unit. If the map unit is not visible, it will be
//applied the next time it is shown.
mapView.setStyleForMapUnit(style, mapUnit)
Styling individual buildings
You can now add custom styles to individual buildings. This allows you to override the
global map style defined in your map's VMVenueStyle
configuration for a single building.
- Java
- Kotlin
//get the building you want to style
MapBuilding building = ... //some map building
MapView mapView = ... // some mapview
//... see class documentation for a full list of styleable attributes
VenueLayerStyle style = new VenueLayerStyle();
style.setFillColor(Color.GREEN);
style.setOutlineColor(Color.RED);
//apply the style to the building.
mapView.setStyleForBuilding(style, building);
//get the building you want to style
val building = ... // some building
val mapView = ... // some mapview
//... see class documentation for a full list of styleable attributes
val style = VenueLayerStyle()
style.fillColor = Color.GREEN
style.outlineColor = Color.RED
//apply the style to the buidling.
mapView.setStyleForBuilding(style, building);
Responding to MapView events and callbacks
There are numerous ways to customize the behavior of your map view by responding to the following events:
Map loading will start
Before you can begin configuring your map view with its initial state, you must wait for internal setup to happen first. After that is complete, your app code will be notified in the delegate method below. In this method, you should call MapView.setupMap.
- Java
- Kotlin
/**
* Called when map view will begin loading. You must NOT call MapView.setupMap
before this method has been called.
* @param map the MapView
*/
@Override
public void willStartLoadingMapView(MapView mapView);
/**
* Called when map view will begin loading. You must NOT call MapView.setupMap
before this method has been called.
* @param map the MapView
*/
override fun willStartLoadingMapView(mapView: MapView?)
Map loading complete
In some scenarios, you may want to wait until the map view has completed loading before
proceeding to the next step. You can wait for the didFinishLoadingMapView
callback.
- Java
- Kotlin
/**
* Called when map view has finished loading so you can do any additional setup
* @param map the MapView
*/
@Override
public void didFinishLoadingMapView(MapView mapView);
/**
* Called when map view has finished loading so you can do any additional setup
* @param map the MapView
*/
override fun didFinishLoadingMapView(mapView: MapView?)
Changes in map position
Anytime the map’s position changes, you can act accordingly.
If your map view is overlaid on another provider's map (such as Google Maps), this is a good place to ensure the map positions stay in sync with each other.
- Java
- Kotlin
/**
* @param newLocation the new map location
* @param newZoom the new map zoom
* @param newBearing the new map bearing
* @param newTilt the new map tilt
*/
@Override
public void didChangeCameraPosition(LatLng newLocation, float newZoom, double
newBearing, double newTilt);
/**
* @param newLocation the new map location
* @param newZoom the new map zoom
* @param newBearing the new map bearing
* @param newTilt the new map tilt
*/
override fun didChangeCameraPosition(newLocation: LatLng?, newZoom: Float, newBearing: Double, newTilt: Double) {
Room selection/highlighting
When the user taps the map on a specific point or room, you can respond to those events appropriately. If you return true
to canSelectUnit, the map will also highlight the selected shape using the color defined in your Map Style json for the layer-id of floor_selected_unit_[FLOOR]
.
See Customizing your map's look and feel above for more information.
- Java
- Kotlin
/**
* @param mapUnit The map unit to check.
* @return Boolean indicating whether or not a map unit can be selected.
*/
Boolean canSelectUnit(MapUnit mapUnit);
/**
* Called when a map unit is selected on the map.
* @param mapUnit The map unit that was selected.
*/
void didSelectUnit(MapUnit mapUnit);
/**
* @param mapUnit The map unit to check.
* @return Boolean indicating whether or not a map unit can be selected.
*/
override fun canSelectUnit(mapUnit: MapUnit?): Boolean
/**
* Called when a map unit is selected on the map.
* @param mapUnit The map unit that was selected.
*/
override fun didSelectUnit(mapUnit: MapUnit?)
Building selection
When the user taps the map on a specific building, you can respond to those events appropriately by implementing canSelectBuilding
and didSelectBuilding
delegate methods.
See Customizing your map's look and feel above for more information.
- Java
- Kotlin
/**
* @param building The building to check.
* @return Boolean indicating whether or not a building can be selected.
*/
Boolean canSelectBuilding(BaseMapBuilding building);
/**
* Called when a building is selected on the map.
* @param building The building that was selected.
*/
void didSelectBuilding(BaseMapBuilding building);
/**
* @param building The building to check.
* @return Boolean indicating whether or not a building can be selected.
*/
override fun canSelectBuilding(building: BaseMapBuilding?): Boolean
/**
* Called when a building is selected on the map.
* @param building The building that was selected.
*/
override fun didSelectBuilding(building: BaseMapBuilding?)
Adding your own annotations to the map view
You can programmatically add annotations to the map to suit your needs by creating a new PointAnnotation
object and adding it to the map:
- Java
- Kotlin
Bitmap icon = // custom icon;
PointAnnotation marker = new PointAnnotation();
marker.setFloorId(floor.getId()); //set the floor id to the VMMSBaseFloor
// object's uid that this marker belongs on
marker.setTitle(wp.getId()); //give it a title, which you can use to reference
//in additional callbacks
marker.setFloorNumber(floor.getFloorNumber());
marker.setPosition(target.getLocation()); //set the location you want the
//annotation to appear on the map
//If your MapView has usingDefaultMapProvider == true
marker.setIcon(IconFactory.getInstance(this).fromBitmap(icon));
//If your MapView has usingDefaultMapProvider == false
marker.setHtml(“<div>Some html</div>”);
this.mapView.addMarker(marker);
val icon:Bitmap = // custom icon;
var marker = PointAnnotation()
marker.floorId = floor.id //set the floor id to the VMMSBaseFloor
// object's uid that this marker belongs on
marker.title = //give it a title, which you can use to reference
//in additional callbacks
marker.floorNumber = floor.floorNumber
marker.position = //set the location you want the
//annotation to appear on the map
//If your MapView has usingDefaultMapProvider == true
marker.icon = IconFactory.getInstance(this).fromBitmap(icon)
//If your MapView has usingDefaultMapProvider == false
marker.html = “<div>Some html</div>”;
this.mapView.addMarker(marker);
Custom annotations are implemented differently depending on whether your MapView has usingDefaultMapProvider
set to true
. If it is, then you can create a custom Bitmap to represent your map annotation. Otherwise, you will need to recreate your bitmap using HTML and CSS.
Responding to Errors that occur in the SDK
There are numerous instances where an error could occur within the VMSDK at any of the many steps above. You can be notified of the error by implementing any of the following callbacks:
VMD Parsing errors
If any errors are encountered while parsing your venue map data files, this method will be called within the SDK with more detailed information about the error:
- Java
- Kotlin
/**
* Callback if the VMD file FAILS to load
* @param e the exception that was raised during load
*/
@Override
public void didFailToLoadMapWithError(Exception e)
/**
* Callback if the VMD file FAILS to load
* @param e the exception that was raised during load
*/
override fun didFailToLoadMapWithError(e: Exception?)
Map display errors
If any errors are encountered when your map is loaded and rendered on screen through the MapView
object, this method will be called within the SDK with more detailed information about the error:
- Java
- Kotlin
/**
* Called when the map view fails to load
* @param mapView the MapView that failed to load
* @param ex the error that caused the failure
*/
@Override
public void didFailToLoadMapView(MapView mapView, Exception ex) {
/**
* Called when the map view fails to load
* @param mapView the MapView that failed to load
* @param ex the error that caused the failure
*/
override fun didFailToLoadMapView(mapView: MapView?, ex: Exception?)
Enable Wayfinding
You can add wayfinding capabilities to your map view to enable your application to provide turn-by-turn paths and directions:
If you want the waypath to be rendered on your map view, you'll have to create a VectorWalkingPathOverlay
and add it to your mapview:
::note
You have to wait until didFinishLoadingMapView is called to be able to set this!
- Java
- Kotlin
//Create a new overlay that will display paths and markers for directions
this.walkingPathOverlay = new VectorWalkingPathOverlay(this.mapView);
//Set the delegate so this class can override certain functionality
this.walkingPathOverlay.setDelegate(this);
this.walkingPathOverlay.setMap(this.vmd);
.. and so on
//Create a new overlay that will display paths and markers for directions
this.walkingPathOverlay = VectorWalkingPathOverlay(this.mapView)
//Set the delegate so this class can override certain functionality
this.walkingPathOverlay.delegate = this;
this.walkingPathOverlay.map = this.vmd
.. and so on
Handle Wayfinding events
Implement the com.aegir.vmms.wayfinding.WayfindingDelegate
interface to get notified of any callbacks from the SDK for wayfinding:
- Java
- Kotlin
/**
* Callback after waypath has been determined
* @param path the Waypath that leads from the starting point to the ending point
*/
@Override
public void didFinishFindingWaypath(Waypath path);
/**
* Called after turn by turn directions are done
* @param turnByTurnDirections the list of directions
*/
@Override
public void didFinishCreatingTurnByTurnDirections(List<MapDirectionStep> turnByTurnDirections);
/**
* Callback after waypath has been determined
* @param path the Waypath that leads from the starting point to the ending point
*/
override fun didFinishFindingWaypath(path: Waypath?)
/**
* Called after turn by turn directions are done
* @param turnByTurnDirections the list of directions
*/
override fun didFinishCreatingTurnByTurnDirections(turnByTurnDirections: MutableList<MapDirectionStep>?)
Override auto-generated wayfinding directions and landmark names
This section is experimental
You can use map information from a JSON
file to override the VMD’s auto-generated wayfinding directions and landmark names. See this full example: MapActivity.java.
The data contained in your wayfinding info override file must be in JSON format, according to the following specs:
{
"points": [
{
"id": "node_waypoint_b1_f1_517",
"public-description": "the edge of the Basketball Court"
},
{
"id": "<the ID of the waypoint>",
"public-description": "<the description you want for this
landmark/waypoint>"
}
],
"paths": [
{
"pathID": "node_path_b1_f1_722",
"p1": "node_waypoint_b1_f1_473",
"p2": "node_waypoint_b1_f1_567",
"description-d1": "along the sidewalk",
"description-d2": "along the sidewalk the other direction"
},
{
"pathID": "<the ID of the path>",
"p1": "<the ID of one of the waypoints>",
"p2": "<the ID of the other waypoint>",
"description-d1": "<description for traversing from P1 to P2>, leave
blank to auto-generate",
"description-d2": "<description for traversing from P2 to P1>, leave
blank to auto-generate"
}
]
}
Responding to wayfinding events and callbacks
Changing floors for wayfinding
When you have a waypath that spans multiple floors, the default behavior for MapView is to draw a button on the map that looks like this:
You can provide your own image instead that matches your own branding. Additionally, when the user selects that button, you must implement that behavior as well by specifying what floor to change to, etc. See MapActivity.java
for an example of how to appropriately respond to a
floor change event.
- Java
- Kotlin
/// Called to provide a custom image for the floor change annotation button
/// @param annotation the annotation
/// @return the custom image
@Override
public Bitmap imageForFloorChangeAnnotation(FloorChangePointAnnotation annotation);
/**
* Called when a floor annotation is selected. You should use this to
* update the floor that is visible on your mapview
* @param annotation
*/
@Override
public void didSelectFloorChangeAnnotation(FloorChangePointAnnotation annotation)
/// Called to provide a custom image for the floor change annotation button
/// @param annotation the annotation
/// @return the custom image
override fun imageForFloorChangeAnnotation(annotation: FloorChangePointAnnotation?): Bitmap
/**
* Called when a floor annotation is selected. You should use this to
* update the floor that is visible on your mapview
* @param annotation
*/
override fun didSelectFloorChangeAnnotation(annotation: FloorChangePointAnnotation?)
Responding to errors that occur in wayfinding
Wayfinding errors
Errors may occur during wayfinding, usually if no paths exist between your selected start & end destination. This method will be called within the SDK with more detailed information about the error:
- Java
- Kotlin
/**
* Callback when wayfinding fails
* @param e the exception that was raised
*/
@Override
public void didFailToFindWaypathWithError(Exception e)
/**
* Callback when turn-by-turn fails
* @param e the exception that was raised
*/
@Override
public void didFailToCreateTurnByTurnDirectionsWithError(Exception e)
/**
* Callback when wayfinding fails
* @param e the exception that was raised
*/
override fun didFailToFindWaypathWithError(e: Exception?)
/**
* Callback when turn-by-turn fails
* @param e the exception that was raised
*/
override fun didFailToCreateTurnByTurnDirectionsWithError(e: Exception?)
Customizing wayfinding look and feel
All styling for wayfinding is now done through new styling properties added in v1.1 to the “wayfinding” section of the Vector map tile spec.
Landmark customization
In the turn-by-turn directions provided by the SDK for wayfinding, there are usually points of interest, or landmarks, that are part of each step and refer to actual places on the map. You can add special icons to the map to further highlight your landmarks:
- Java
- Kotlin
/**
* Called to provide a custom image for a landmark annotation
* @param annotation the annotation
* @return the custom image
*/
Bitmap imageForLandmarkAnnotation(LandmarkAnnotation annotation)s
/**
* Called to provide a custom image for a landmark annotation
* @param annotation the annotation
* @return the custom image
*/
override fun imageForLandmarkAnnotation(annotation: LandmarkAnnotation?): Bitmap {
Landmark annotations are not currently supported if your MapView instance has usingDefaultMapProvider
set to false.
More Information
For assistance with the Aegir VMSDK, related questions, or information about other Aegir products and services, visit https://support.aegirmaps.com/ or contact Aegir Support at [email protected].