Getting started (3)Create a simple map viewDynamically build a map viewSupport map fragmentDynamic styling (30)HillshadingAdd a vector tile sourceAdd a new layer below labelsAnimate marker positionAdjust a layer's opacityShow time lapseAnimated image source (GIF)Icon update based on API responseChange a layer's colorChange a map's languageColor dependent on zoom levelClick to add photoIndoor MapMarker following routeStyle with missing iconSymbol layer iconsPicture in picturePulsing layer opacityAdd a WMS sourceText anchor positionButton interaction stylingOpacity fadeShow and hide layersSymbolLayer iconsAdjust text labelsMultiple text formatsTransparent render surfaceUse an image sourceAnimated icon movementVariable label placementExtrusions (5)Adjust light location and colorDisplay 3D building height based on vector dataExtrude polygons for 3D indoor mappingRotate and tilt with 3D buildingsUse GeoJSON data to set extrusion heightCamera (5)Animate the map cameraFit camera in bounding boxRestrict map panningRotating cameraZoom to show a cluster's leavesData visualization (33)Baseball spray chartDisplay water depthBiometric fingerprintCalendar integrationCircle icon toggleCircleLayer clustersCircle radiusCircle to icon transitionCreate a line layerCreate hotspots from pointsData time lapseShow heatmap dataDraw a GeoJSON lineDraw a polygon with holesDraw a polygonDraw multiple geometriesJoin local JSON data with vector tile geometriesLine gradientLine behind moving iconMultiple expressionsIcon setting based on Feature propertyOutlined polygon holeSatellite land selectShared preferencesSpinning iconStyle circles categoricallyStyle lines using an identity property functionToggle collision detectionSymbolLayer clusteringSymbol layer info windowZoom-based icon switchUpdate a choropleth layer by zoom levelStyling heatmapsOffline (3)Cache managementA simple offline mapOffline managerQuerying the map (3)Building outlineQuery a map featureSelect a buildingMap style (4)Style attributionLocal style or custom raster styleDefault stylesMapbox Studio styleUser interaction (12)Click on single layerFeature countDrawing search areaHighlighted lineSymbol layer icon size changeInset mapLocation pickerBackground fogRecyclerView DirectionsSearch again in an areaSnaking directionsRecyclerView interactionImage generation (2)Snapshot NotificationShare snapshot imageDevice location (7)Track device locationBasic pulsing locationLocation camera optionsCustom pulsing locationCustomized location iconShow a user's location on a map fragmentShow a user's location

Calendar integration

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent" />
android:layout_marginBottom="8dp" />
package com.mapbox.mapboxandroiddemo.examples.labs;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PointF;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.widget.Toast;
import com.mapbox.android.core.permissions.PermissionsListener;
import com.mapbox.api.geocoding.v5.GeocodingCriteria;
import com.mapbox.api.geocoding.v5.MapboxGeocoding;
import com.mapbox.api.geocoding.v5.models.CarmenFeature;
import com.mapbox.api.geocoding.v5.models.GeocodingResponse;
import com.mapbox.core.exceptions.ServicesException;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxandroiddemo.R;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
* Use the Android system's calendar content provider and the Mapbox Geocoding API to show
* past calendar events on the map.
public class CalendarIntegrationActivity extends AppCompatActivity implements
OnMapReadyCallback, PermissionsListener, MapboxMap.OnMapClickListener {
private static final int MY_CAL_REQ = 0;
private static final int TITLE_INDEX = 1;
private static final int EVENT_LOCATION_INDEX = 2;
private static final String MARKER_IMAGE_ID = "MARKER_IMAGE_ID";
private static final String MARKER_LAYER_ID = "MARKER_LAYER_ID";
private static final String PROPERTY_TITLE = "title";
private static final String PROPERTY_LOCATION = "location";
private String geojsonSourceId = "geojsonSourceId";
private MapView mapView;
private MapboxMap mapboxMap;
private List<Feature> featureList;
private FeatureCollection featureCollection;
protected void onCreate(Bundle savedInstanceState) {
// Mapbox access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Mapbox.getInstance(this, getString(R.string.access_token));
// This contains the MapView in XML and needs to be called after the access token is configured.
mapView = findViewById(R.id.mapView);
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
CalendarIntegrationActivity.this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() {
public void onStyleLoaded(@NonNull Style style) {
featureCollection = FeatureCollection.fromFeatures(new Feature[]{});
public boolean onMapClick(@NonNull LatLng point) {
return handleClickIcon(mapboxMap.getProjection().toScreenLocation(point));
* This method handles click events for SymbolLayer symbols.
* @param screenPoint the point on screen clicked
private boolean handleClickIcon(PointF screenPoint) {
List<Feature> features = mapboxMap.queryRenderedFeatures(screenPoint, MARKER_LAYER_ID);
if (!features.isEmpty()) {
String calendarEventTitle = features.get(0).getStringProperty(PROPERTY_TITLE);
String calendarEventLocation = features.get(0).getStringProperty(PROPERTY_LOCATION);
Toast.makeText(this, calendarEventTitle + " – " + calendarEventLocation, Toast.LENGTH_SHORT).show();
return true;
return false;
* Using a Calendar content provider (https://developer.android.com/guide/topics/providers/calendar-provider),
* retrieve the title and location of calendar events that are from the main account signed in on the device.
public void getCalendarData(@NonNull Style style) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]
{ Manifest.permission.READ_CALENDAR}, MY_CAL_REQ);
} else {
Uri calendarUri;
calendarUri = CalendarContract.Events.CONTENT_URI;
Calendar startTime = Calendar.getInstance();
startTime.set(2018, 2, 1, 0, 0);
Calendar endTime = Calendar.getInstance();
endTime.set(2018, 6, 1, 0, 0);
String selection = "(( " + CalendarContract.Events.DTSTART + " >= "
+ startTime.getTimeInMillis() + " )" + " AND ( " + CalendarContract.Events.DTSTART
+ " <= " + endTime.getTimeInMillis() + " ))";
String[] projection = new String[] {
CalendarContract.Events.CALENDAR_ID, CalendarContract.Events.TITLE,
CalendarContract.Events.DTSTART };
Cursor cur = this.getContentResolver().query(calendarUri, projection, selection, null, null);
featureList = new ArrayList<>();
int index = 0;
if (cur != null) {
if (!deviceHasInternetConnection()) {
Toast.makeText(this, R.string.no_connectivity, Toast.LENGTH_LONG).show();
Timber.d("No internet connectivity");
} else {
while (cur.moveToNext()) {
if (index <= 80) {
if (cur.getString(EVENT_LOCATION_INDEX) != null && !cur.getString(EVENT_LOCATION_INDEX).isEmpty()) {
makeMapboxGeocodingRequest(cur.getString(TITLE_INDEX), cur.getString(EVENT_LOCATION_INDEX));
} else {
Timber.d("getCalendarData: location is null or empty");
* Use the Mapbox Java SDK's wrapper for making a Mapbox Geocoding API request. The text in the calendar event's
* location field is used to make a geocoding request.
* @param eventTitle title of the calendar event so that it can be added as a Feature property. The title is
* eventually displayed in a Toast when a calendar event icon is tapped on.
* @param eventLocation the event's location. This text is used in the Mapbox geocoding search
private void makeMapboxGeocodingRequest(final String eventTitle, final String eventLocation) {
try {
// Build a Mapbox geocoding request
MapboxGeocoding client = MapboxGeocoding.builder()
client.enqueueCall(new Callback<GeocodingResponse>() {
public void onResponse(Call<GeocodingResponse> call,
Response<GeocodingResponse> response) {
List<CarmenFeature> results = response.body().features();
if (results.size() > 0) {
// Get the first Feature from the successful geocoding response
CarmenFeature feature = results.get(0);
if (feature != null) {
mapboxMap.getStyle(new Style.OnStyleLoaded() {
public void onStyleLoaded(@NonNull Style style) {
LatLng featureLatLng = new LatLng(feature.center().latitude(), feature.center().longitude());
Feature singleFeature = Feature.fromGeometry(Point.fromLngLat(featureLatLng.getLongitude(),
singleFeature.addStringProperty(PROPERTY_TITLE, eventTitle);
singleFeature.addStringProperty(PROPERTY_LOCATION, eventLocation);
featureCollection = FeatureCollection.fromFeatures(featureList);
GeoJsonSource source = style.getSourceAs(geojsonSourceId);
if (source != null) {
} else {
Timber.d("onResponse: listOfCalendarEvents == null");
public void onFailure(Call<GeocodingResponse> call, Throwable throwable) {
Timber.d("Geocoding Failure: %s", throwable.getMessage());
} catch (ServicesException servicesException) {
Timber.d("Error geocoding: %s", servicesException.toString());
* Sets up all of the sources and layers needed for this example
* @param style style
public void setUpData(@NonNull Style style) {
Toast.makeText(CalendarIntegrationActivity.this, R.string.click_on_calendar_icon_instruction,
* Adds the GeoJSON source to the map
private void setupSource(@NonNull Style style) {
style.addSource(new GeoJsonSource(geojsonSourceId, featureCollection));
* Adds the marker image to the map for use as a SymbolLayer icon
private void setUpImage(@NonNull Style style) {
Bitmap icon = BitmapFactory.decodeResource(
this.getResources(), R.drawable.calendar_event_icon);
style.addImage(MARKER_IMAGE_ID, icon);
* Setup a layer with a calendar icon representing the location of each calendar event.
private void setUpCalendarIconLayer(@NonNull Style style) {
SymbolLayer eventSymbolLayer = new SymbolLayer(MARKER_LAYER_ID, geojsonSourceId);
public void onExplanationNeeded(List<String> permissionsToExplain) {
Toast.makeText(this, R.string.user_calendar_permission_explanation, Toast.LENGTH_LONG).show();
public void onPermissionResult(boolean granted) {
// Left empty on purpose
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
if (requestCode == MY_CAL_REQ) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (mapboxMap != null) {
mapboxMap.getStyle(new Style.OnStyleLoaded() {
public void onStyleLoaded(@NonNull Style style) {
} else {
Toast.makeText(this, R.string.user_calendar_permission_explanation, Toast.LENGTH_LONG).show();
public boolean deviceHasInternetConnection() {
ConnectivityManager connectivityManager = (ConnectivityManager)
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnected();
// Add the mapView lifecycle to the activity's lifecycle methods
public void onResume() {
protected void onStart() {
protected void onStop() {
public void onPause() {
public void onLowMemory() {
protected void onDestroy() {
if (mapboxMap != null) {
protected void onSaveInstanceState(Bundle outState) {
Was this page helpful?