The Mapwize Android SDK is built as a plugin on top of Mapbox GL native for Android.
The Mapbox map is used as base map to display the outdoor. It is an amazingly powerful SDK allowing you to do a lot of cool stuff with the map. If you want to move the map, rotate it, overlay your own data or more, you can do it directly by controlling the Mapbox map. Adding Mapwize does not remove any capability from Mapbox, it just adds more. Have a look at the Mapbox documentation to see all features.
This Mapwize plugin is adding the possibility of getting inside buildings. As you zoom on the map, you will automatically enter in buildings, see the different floors and be able to navigate inside. If you want to change floors, see different universes (views) of the building, draw directions inside or display the user's indoor location, then you'll interact with the Mapwize plugin.
The Mapwize app available on Google Play store is a feature-rich app, built with this SDK, allowing you to browse any building (private buildings require an access key), search for points of interest and get directions.
The full code of the application is available under the MIT license on our Github.
Feel free to fork it, change the branding, add the API key to your building and publish it.
MapwizeForMapbox is compatible with Android api 21 and above.
A very simple app integrating Mapwize is available on our Github. It contains the minimum code to display the map.
In your main gradle app, add the following maven repositories
repositories {
repositories {
...
maven { url "https://jitpack.io" }
maven { url "https://maven.mapwize.io"}
}
}
In the gradle file of your application, add the Mapwize dependency.
dependencies {
implementation ("io.mapwize.indoormaps:MapwizeForMapbox:{lib-version}") {
transitive = true
}
}
As mapbox is now compatible with java 8, you have to add those lines to the build.gradle in order to avoid error at start.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
You'll need a Mapwize API key to load the plugin and allow API requests. To get your own Mapwize API key, sign up for a free account at mapwize.io. Then within the Mapwize Studio, navigate to "API Keys" on the side menu.
In your main Application class, initialize the AccountManager in the onCreate method.
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
AccountManager.start(this, "YourApiKey");
}
}
Your main Application class needs to be defined in your Manifest.xml
<application
...
android:name=".MyApplication">
...
</application>
Mapwize demo keys are available for testing in the demo projects. Please note they cannot be used in production.
MapwizePlugin is using Mapbox for the outdoor map. There are 2 options regarding the outdoor:
To use the default Mapwize outdoor map:
http://outdoor.mapwize.io/styles/mapwize/style.json?key=<YOUR_MAPWIZE_API_KEY>
pk.mapwize
as Mapbox access tokenIf you want to use your custom Mapbox style, get your Mapbox API key by sign up at mapbox.com
Instanciate a Mapbox map, either through layout or through code. See details here
You can instantiate Mapwize as soon as you get a Mapbox.MapView with one of the following constructors:
public static MapwizePlugin create(@NonNull final MapView mapView, @NonNull final MapOptions mapOptions)
public static MapwizePlugin create(@NonNull final MapView mapView, @NonNull final MapOptions mapOptions, @NonNull final UISettings uiSettings)
Like for example
MapOptions opts = new MapOptions.Builder()
.build();
mapwizePlugin = MapwizePluginFactory.create(mapView, opts);
mapwizePlugin.setOnDidLoadListener(new MapwizePlugin.OnDidLoadListener() {
@Override
public void didLoad(MapwizePlugin plugin) {
// Mapwize plugin is loaded and ready to use.
}
});
Take a look at the simple app for details.
As the loading of the map can take some time, especially when large venues need to be loaded, it is advised to keep the map active in the activity in case of rotation and resize, instead of detroying and recreating it. To do so, the attribute android:configChanges="orientation|sreenSize"
can be added to the activity.
<activity
android:name=".MapActivity"
android:configChanges="orientation|screenSize">
...
</activity>
If you are using a custom instance of Mapwize server you have to set the api URL. This is done at the initialization of Account manager using :
public static AccountManager start(@NonNull Application app, @NonNull String mapwizeApiKey, String serverScheme, String serverHost, String serverApiPath)
The default parameters are :
serverScheme = "https";
serverHost = "api.mapwize.io";
serverApiPath = "v1/";
The plugin can be loaded with the following options available in the MapOptions class:
floor
to set the default floor when entering a venue. Floors are Double and can be decimal values.language
to set the default language for venues. It is a string with the 2 letter code for the language. Example: "fr" or "en".universeId
to set the default universe for the displayed venue.restrictContentToVenueId
to show only the related venue on the map.restrictContentToOrganizationId
to show only the venues of that organization on the map.centerOnPlace
to center on a place at start.centerOnVenue
to center on a venue at start.It is also possible to specify a main color to tint all the controls on the map. To do so, add mapwize_main_color
in value/colors in your app.
showUserPositionControl
If set to false, the button to center the map on the user position is not displayed. Displayed by default.showFloorControl
If set to false, the floor selector control is not displayed. Displayed by default.logoEnabled
If set to false, Mapwize logo will be disabled. You should not do this unless you get written authorization from Mapwize. If you disable Mapwize logo, you have to display an UI Component on or next to the map to show attributions for Mapbox, openstreetmap and openmaptiles. Default is true.mapwizeCompassEnabled
If false, Mapwize won't handle the compass for you. If true, the compass will be managed by the Mapwize plugin. Default is true.MapwizePlugin needs access to the Mapbox map listeners to work properly.
For some listeners like MapboxMap.OnCameraMoveListener, MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnFlingListener or MapboxMap.OnMapClickListener.
Adds a callback that's invoked when the user clicks on the map view. Mapbox supports multiple listeners on Android so you can add yours next to the ones added by MapwizePlugin. Please note that if you would manually remove all listeners from the Mapbox map, Mapwize plugin would stop working.
For some other listeners like onMarkerClickListener, onPolygonClickListener and onPolylineClickListener, Mapbox only supports a single listener that is used exclusively by MapwizePlugin. To use those listeners, use the related setters provided by MapwizePlugin.
Listeners are provided for the following events:
public void setOnDidLoadListener(OnDidLoadListener listener);
public void addOnVenueExitListener(OnVenueExitListener listener);
public void addOnVenueEnterListener(OnVenueEnterListener listener);
public void addOnClickListener(OnClickListener listener)
public void addOnLongClickListener(OnLongClickListener listener)
public void addOnMarkerClickListener(OnMarkerClickListener listener);
public void addOnFloorChangeListener(OnFloorChangeListener listener);
public void addOnFloorsChangeListener(OnFloorsChangeListener listener);
public void addOnFollowUserModeChangeListener(OnFollowUserModeChange listener);
public void addMapboxMarkerClickListener(MapboxMap.OnMarkerClickListener mapboxMarkerClickListener);
public void addMapboxPolygonClickListener(MapboxMap.OnPolygonClickListener mapboxPolygonClickListener);
public void addMapboxPolylineClickListener(MapboxMap.OnPolylineClickListener mapboxPolylineClickListener);
In order to react to click events on the map, Mapwize provides an object that helps you know on which object the user clicked. It can be a venue, a place or nothing.
It is represented with 3 event types :
public final static int MAP_CLICK = 0; // The user clicked on the map
public final static int PLACE_CLICK = 1;// The user clicked on a place
public final static int VENUE_CLICK = 2;// The user clicked on a venue
The following attributes can be retrieved :
int eventType; // Enum, see above
LatLngFloor latLngFloor; // The latLngFloor at which the click was made. The latitude and longitudes are always set, but the floor can be null. Available for all event types.
Place place; // Not null if eventType == PLACE_CLICK
Venue venue; // Not null if eventType == VENUE_CLICK
A typical way to handle those event :]
mapwizePlugin.setOnClickListener(event -> {
switch (event.getEventType()) {
case ClickEvent.MAP_CLICK:
LatLngFloor llf = event.getLatLngFloor()
// Do something with LatLngFloor
break;
case ClickEvent.PLACE_CLICK:
Place place = event.getPlace()
// Do something with place
break;
case ClickEvent.VENUE_CLICK:
Venue venue = event.getVenue())
// Do something with venue
break;
}
});
Displaying the user's location on the map is done by connecting an IndoorLocationProvider to Mapwize.
There are a lot of IndoorLocation providers already freely available as part of the IndoorLocation open-source framework.
If you are missing your provider, contact us at support@mapwize.io or build your own starting from the base classes.
To set the IndoorLocationProvider on the MapwizePlugin:
java
public void setLocationProvider(IndoorLocationProvider provider);
If you want to manually set the user location, you can use the ManualIndoorLocationProvider
You can retrieve the current user position on the map using IndoorLocation getUserPosition()
and the user heading using Double getUserHeading()
`
There is no listener to be notified of any new user location. Subscribe to the IndoorLocationProvider's listener instead.
The user's heading is also displayed on the map as an arrow from the user position. The heading is retrieved directly from the device. It is not possible to manually set the user heading at this point.
You can use the follow user mode feature to automatically move the map as the user location changes.
3 modes are provided by FollowUserMode enum class :
FollowUserMode.NONE
the map does not move if the location changesFollowUserMode.FOLLOW_USER
the map moves laterally in order to keep the user position at the center. Zoom and rotation do not change.FollowUserMode.FOLLOW_USER_AND_HEADING
the map moves and rotates in order to keep the user position in the center and the heading towards the top of the device.You can retrieve the current mode using the int getFollowUserMode()
method and you can set it using
public void setFollowUserMode(int followMode)
The FollowUserMode is automatically set to NONE
when the user manually moves the map or changes floor.
Indoor maps are defined inside venues. The map will automatically enter in a venue when the zoom is sufficient, and exit the venue when the map is moved away. Only one venue can be open at a time.
The currently displayed venue can be retrieved using the getVenue method
public Venue getVenue();
The method returns null if no venue is displayed on the map. Listeners are available to listen to enter and exit of venues.
Venues can have multiple universes. Universes are like views. In Mapwize Studio, it is possible to define which elements are displayed in each universe and define security policies for each of them.
When a venue is displayed, the method Universe getUniverse()
will return the currently displayed universe for that venue.
You can set and get the universe for each venue using
public void setUniverse(Universe universe);
public void setUniverseForVenue(Universe universe, Venue venue);
public Universe getUniverseForVenue(Venue venue);
Venues usually have multiple floors. Floors are identified by a Double and can be decimal.
When a venue is displayed, the method Double getFloor()
will return the currently displayed floor for that venue and List<Double> getFloors()
will return the list of active floors for that venue. A floor is considered active if the geometry of one layer of that floor is intersecting with the visible region on the screen.
You can change floor using
public void setFloorForVenue(Double floor, Venue venue);
public void setFloor(Double floor);
The OnFloorChange
event is fired when the floor changes.
The OnFloorsChange
event is fired when the list of active floors changes, which may or may not happen at venue enter, venue exit, universe change or camera move.
The title of the places that are displayed on the map can be translated in multiple languages and you can control what language is used.
Firstly, you can set the preferered language of the user. By default, titles will be displayed in the preferred language if available in the venue. Otherwise, the main language of the venue is used.
public void setPreferredLanguage(String language);
public String getPreferredLanguage();
It is also possible to specify what language to use for a specific venue and get the language displayed for the current venue.
public void setLanguageForVenue(String language, Venue venue);
public String getLanguage();
Markers is a convenient way to add simple pins on the map.
Mapwize Markers are positioned on a specific floor and therefore only displayed if that floor is selected. However, they are not attached to a specific venue and will be displayed even if the venue is not visible.
If you want to add more complex annotations on the map, you have all the power of Mapbox at your disposal. Have a look at their documentation
By default, the image used for the pin is the standard Mapwize pin. However, you can specify your own using a Mapbox Icon.
public Marker addMarker(LatLngFloor latLngFloor);
public Marker addMarker(LatLngFloor latLngFloor, Icon icon);
public Marker addMarker(Place place);
public Marker addMarker(Place place, Icon icon);
public List<Marker> addMarkers(PlaceList placelist);
public List<Marker> addMarkers(PlaceList placelist, Icon icon);
public void removeMarker(Marker marker);
public void removeMarkers();
The title of places are displayed based on the zoom level. The objective is to display as many as possible without having collisions. By default, the order specified in Mapwize Studio is used to define which place is displayed first.
However, there are situations where you would like to change dynamically the order. For example, if the user clicks on a place and you display informations about it, you might want to make sure that the title of that place is displayed. Basically, you want to promote that place to the first position.
Promoting places make them come first on the rendering. Of course, the collision mechanism still apply so if 2 promoted places collide, then only the first in the promotion list comes first. Also, promoted places only show on their floor when their venue are visible.
public void addPromotedPlace(Place place);
public void addPromotedPlaces(List<Place> places);
public void removePromotedPlace(Place place);
public void removePromotedPlaces(List<Place> places);
public void removePromotedPlacesForVenue(Venue venue);
To display directions on the map, the first step is to compute them. For that, you'll need to use the API methods to get a Direction object as described in the API section.
When you have a Direction object, you can display it on the map using
public void setDirection(Direction direction);
public void setDirection(Direction direction, DirectionOptions options);
The first method will use defaut DirectionOptions.
Here is the list of options with their default value:
Icon endMarkerIcon = null;
boolean displayEndMarker = true;
boolean centerOnStart = true;
boolean setToStartingFloor = true;
If endMarkerIcon is null and displayEndMarker is true, default Mapwize marker will be used.
You can retrieve the displayed direction using
public Direction getDirection();
And you can remove the direction by setting it to null or use
java
public void removeDirection();
Navigation is used as direction is. The difference is that navigation show the evolution of the user on the direction line.
The navigation should be used only if the starting point of the direction is the user position and if you have a IndoorLocation system working in your venue.
In order to provide an understandable visualization, Mapwize recompute the IndoorLocation to put the user position dot at the most realistic position on the direction path. Below, you will read how to use this information to recompute direction if needed.
public void startNavigation(@Nullable Direction direction, @NonNull DirectionOptions options, @Nullable OnNavigationUpdateListener onNavigationUpdateListener)
public void stopNavigation()
NavigationInfo contains 3 parameters :
Do you want to show if a meeting room is available or not, or color the prefered shops of the user? Then dynamic styling of places is what you are looking for.
You can overwrite the style of any place at any time using the setPlaceStyle
function. Set the style to nil to return to the default style.
public void setPlaceStyle(final Place place, final Style style);
The available attributes for the style are
markerUrl
the url to an image to use for the marker (String)fillColor
the color of the inside of the polygon. Only used if the place is a polygon. (String with format "#000000")strokeColor
the color of the border of the polygon. Only used if the place is a polygon. (String with format "#000000")fillOpacity
the opacity of the inside of the polygon. Only used if the place is a polygon. (Double between 0 and 1)strokeOpacity
the opacity of the border of the polygon. Only used if the place is a polygon. (Double between 0 and 1)strokeWidth
the width of the border of the polygon. Only used if the place is a polygon. (Double positive)isMarkerDisplay
defines if the marker of the place is displayed or not. (Boolean default true)isShapeDisplay
defines if the shape of the place is displayed or not. (Boolean default true)When developing an app around a map, it is advised not to resize the map at every user interaction. However, it might be interesting to overlay elements on top of the map. Since MapwizePlugin is adding controls on the map like the user position control or the floor control, padding can be used to free the sides of the map to make space for overlay.
public void setBottomPadding(int pad);
public void setRightPadding(int pad);
public void setTopPadding(int pad);
public void setLeftPadding(int pad);
A complete set of functions are available to query raw Mapwize objects.
Mapwize objects are cached as much as possible in the SDK to reduce network traffic. However, full offline support is not available yet, but will be in a near future.
private final String venueId;
private final String universeId;
private final Boolean isVisible;
private final String alias;
private final String name;
private final Double floor;
private final String organizationId;
private final Double latitudeMin;
private final Double latitudeMax;
private final Double longitudeMin;
private final Double longitudeMax;
private String query;
private String venueId;
private String organizationId;
private String universeId;
private String[] objectClass;
Access can be granted at runtime by calling the Api
directly :
java
public static void getAccess(String accessKey, final ApiCallback<Boolean> callback);
Using this, you have to refresh the MapwizePlugin manually using MapwizePlugin.refresh(OnAsyncTaskReady callback);
You can also call the grantAccess method on the MapwizePlugin
. This method handle the Api call and the refresh.
java
public static void grantAccess(String accessKey, final ApiCallback<Boolean> callback);
public static void getVenue(String id, final ApiCallback<Venue> callback);
public static void getVenueWithAlias(String alias, final ApiCallback<Venue> callback);
public static void getVenueWithName(String name, final ApiCallback<Venue> callback);
public static void getVenues(ApiFilter apiFilter, final ApiCallback<List<Venue>> callback);
public static void getPlace(String id, final ApiCallback<Place> callback);
public static void getPlaceWithAlias(String alias, Venue venue, final ApiCallback<Place> callback);
public static void getPlaceWithName(String name, Venue venue, final ApiCallback<Place> callback);
public static void getPlaces(ApiFilter apiFilter, final ApiCallback<List<Place>> callback);
public static void getConnectorPlaces(ApiFilter apiFilter, final ApiCallback<List<ConnectorPlace>> callback);
public static void getConnectorPlaceWithAlias(String alias, Venue venue, final ApiCallback<ConnectorPlace> callback);
public static void getConnectorPlaceWithName(String name, Venue venue, final ApiCallback<ConnectorPlace> callback);
public static void getConnectorPlace(String id, final ApiCallback<ConnectorPlace> callback);
public static void getPlaceList(String id, final ApiCallback<Place> callback);
public static void getPlaceListWithAlias(String alias, Venue venue, final ApiCallback<Place> callback);
public static void getPlaceListWithName(String name, Venue venue, final ApiCallback<Place> callback);
public static void getPlaceLists(ApiFilter apiFilter, final ApiCallback<List<Place>> callback);
public static void getMainFromForVenue(String venueId, final ApiCallback<List<Place>> callback);
public static void getMainSearchesForVenue(String venueId, final ApiCallback<List<MapwizeObject>> callback)
public static void getLayer(String id, final ApiCallback<Layer> callback);
public static void getLayerWithAlias(String alias, Venue venue, final ApiCallback<Layer> callback);
public static void getLayerWithName(String name, Venue venue, final ApiCallback<Layer> callback);
public static void getLayers(ApiFilter apiFilter, final ApiCallback<List<Layer>> callback);
public static void getStyleSheet(String id, final ApiCallback<StyleSheet> callback);
public static void getUniverses(ApiFilter apiFilter, final ApiCallback<List<Universe>> callback);
public static void getUniverse(String id, final ApiCallback<Universe> callback);
public static void getAccessibleUniverseForVenue(String venueId, final ApiCallback<List<Universe>> callback);
public static void getDirection(DirectionPoint from, List<? extends DirectionPoint> to, List<? extends DirectionPoint> waypoints, boolean isAccessible, boolean waypointOptimize, final ApiCallback<Direction> callback);
public static void getDirection(DirectionPoint from, DirectionPoint to, List<? extends DirectionPoint> waypoints, boolean isAccessible, boolean waypointOptimize, final ApiCallback<Direction> callback);
public static void getDirection(DirectionPoint from, List<? extends DirectionPoint> to, boolean isAccessible, final ApiCallback<Direction> callback);
public static void getDirection(DirectionPoint from, DirectionPoint to, boolean isAccessible, final ApiCallback<Direction> callback);
You can get a list of distance between a 'from' point to a list of 'to' points using :
public static void getDistances(DirectionPoint from, List<DirectionPoint> to, boolean isAccessible, boolean sortByTraveltime, final ApiCallback<DistanceResponse> callback)
public static void search(SearchParams params, final ApiCallback<List<MapwizeObject>> callback)
The SDK is evolving quickly. If you wish you had an extra function or if you have any remark, don't hesitate to contact us. Updates can be pushed quickly for critical matters.
For any question, contact us at support@mapwize.io