com.mapbox.mapboxsdk.maps.MapboxMap Maven / Gradle / Ivy
package com.mapbox.mapboxsdk.maps;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.graphics.RectF;
import android.location.Location;
import android.os.SystemClock;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v4.util.LongSparseArray;
import android.support.v4.util.Pools;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.mapbox.mapboxsdk.MapboxAccountManager;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.InfoWindow;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException;
import com.mapbox.mapboxsdk.style.sources.NoSuchSourceException;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.commons.geojson.Feature;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* The general class to interact with in the Android Mapbox SDK. It exposes the entry point for all
* methods related to the MapView. You cannot instantiate {@link MapboxMap} object directly, rather,
* you must obtain one from the getMapAsync() method on a MapFragment or MapView that you have
* added to your application.
*
* Note: Similar to a View object, a MapboxMap should only be read and modified from the main thread.
*
*/
public class MapboxMap {
private static final String TAG = MapboxMap.class.getSimpleName();
private MapView mapView;
private UiSettings uiSettings;
private TrackingSettings trackingSettings;
private MyLocationViewSettings myLocationViewSettings;
private Projection projection;
private CameraPosition cameraPosition;
private boolean invalidCameraPosition;
private LongSparseArray annotations;
private List selectedMarkers;
private MarkerViewManager markerViewManager;
private List infoWindows;
private MapboxMap.InfoWindowAdapter infoWindowAdapter;
private boolean myLocationEnabled;
private boolean allowConcurrentMultipleInfoWindows;
private MapboxMap.OnMapClickListener onMapClickListener;
private MapboxMap.OnMapLongClickListener onMapLongClickListener;
private MapboxMap.OnMarkerClickListener onMarkerClickListener;
private MapboxMap.OnInfoWindowClickListener onInfoWindowClickListener;
private MapboxMap.OnInfoWindowLongClickListener onInfoWindowLongClickListener;
private MapboxMap.OnInfoWindowCloseListener onInfoWindowCloseListener;
private MapboxMap.OnFlingListener onFlingListener;
private MapboxMap.OnScrollListener onScrollListener;
private MapboxMap.OnMyLocationTrackingModeChangeListener onMyLocationTrackingModeChangeListener;
private MapboxMap.OnMyBearingTrackingModeChangeListener onMyBearingTrackingModeChangeListener;
private MapboxMap.OnFpsChangedListener onFpsChangedListener;
private MapboxMap.OnCameraChangeListener onCameraChangeListener;
private double maxZoomLevel = -1;
private double minZoomLevel = -1;
MapboxMap(@NonNull MapView mapView) {
this.mapView = mapView;
this.mapView.addOnMapChangedListener(new MapChangeCameraPositionListener());
uiSettings = new UiSettings(mapView);
trackingSettings = new TrackingSettings(this.mapView, uiSettings);
projection = new Projection(mapView);
annotations = new LongSparseArray<>();
selectedMarkers = new ArrayList<>();
infoWindows = new ArrayList<>();
markerViewManager = new MarkerViewManager(this, mapView);
}
// Style
/**
* Returns a layer that conforms to {@link Layer} if any layer with the given identifier was
* found.
*
* Layer identifiers are not guaranteed to exist across styles or different versions of the
* same style. Applications that use this API must set the style URL to an explicitly versioned
* style either by passing in the URL String using {@link MapboxMapOptions#styleUrl(String)} or
* setting through XML using {@link com.mapbox.mapboxsdk.R.attr#style_url}. This approach
* also avoids layer identifier name changes that will occur in the default style’s layers over
* time. These default styles can be found in the {@link Style} class.
*
*
* @param layerId a String matching the layer ID found within the current map style. This String
* is case sensitive.
* @return a {@link Layer}, null if the layer doesn't exist.
*/
@Nullable
@UiThread
public Layer getLayer(@NonNull String layerId) {
return getMapView().getNativeMapView().getLayer(layerId);
}
/**
* Tries to cast the Layer to T, returns null if it's another type.
*
* Layer identifiers are not guaranteed to exist across styles or different versions of the
* same style. Applications that use this API must set the style URL to an explicitly versioned
* style either by passing in the URL String using {@link MapboxMapOptions#styleUrl(String)} or
* setting through XML using {@link com.mapbox.mapboxsdk.R.attr#style_url}. This approach
* also avoids layer identifier name changes that will occur in the default style’s layers over
* time. These default styles can be found in the {@link Style} class.
*
*
* @param layerId a String matching the layer ID found within the current map style. This String
* is case sensitive.
* @param the generic attribute of a {@link Layer}.
* @return the casted {@link Layer}, null if another type.
*/
@Nullable
@UiThread
public T getLayerAs(@NonNull String layerId) {
try {
//noinspection unchecked
return (T) getMapView().getNativeMapView().getLayer(layerId);
} catch (ClassCastException e) {
Log.e(TAG, String.format("Layer: %s is a different type: %s", layerId, e.getMessage()));
return null;
}
}
/**
* Adds a new layer on top of existing layers. The layer must be newly created and not added to the map before
*
* @param layer a {@link Layer}.
*/
@UiThread
public void addLayer(@NonNull Layer layer) {
addLayer(layer, null);
}
/**
* Inserts a new layer below another layer. The layer must be newly created and not added to the map before
*
* Layer identifiers are not guaranteed to exist across styles or different versions of the
* same style. Applications that use this API must set the style URL to an explicitly versioned
* style either by passing in the URL String using {@link MapboxMapOptions#styleUrl(String)} or
* setting through XML using {@link com.mapbox.mapboxsdk.R.attr#style_url}. This approach
* also avoids layer identifier name changes that will occur in the default style’s layers over
* time. These default styles can be found in the {@link Style} class.
*
*
* @param layer a {@link Layer} to be added to map style.
* @param before a String layer identifier that's already found in the map view style. If the
* layer is not found in the current map style the layer will be added to the top
* of the map.
*/
@UiThread
public void addLayer(@NonNull Layer layer, String before) {
getMapView().getNativeMapView().addLayer(layer, before);
}
/**
* Removes a layer from the map style. Any references to the layer become invalid and should not
* be used anymore
*
* Layer identifiers are not guaranteed to exist across styles or different versions of the
* same style. Applications that use this API must set the style URL to an explicitly versioned
* style either by passing in the URL String using {@link MapboxMapOptions#styleUrl(String)} or
* setting through XML using {@link com.mapbox.mapboxsdk.R.attr#style_url}. This approach
* also avoids layer identifier name changes that will occur in the default style’s layers over
* time. These default styles can be found in the {@link Style} class.
*
*
* @param layerId a String matching the layer ID found within the current map style. This
* String is case sensitive. Any references to the layer become invalid and should
* not be used anymore
* @throws NoSuchLayerException If the layer doesn't exist in the current style, this exception
* will be thrown.
*/
@UiThread
public void removeLayer(@NonNull String layerId) throws NoSuchLayerException {
getMapView().getNativeMapView().removeLayer(layerId);
}
/**
* Removes the layer. The reference is re-usable after this and can be re-added
*
* @param layer the layer to remove
* @throws NoSuchLayerException
*/
@UiThread
public void removeLayer(@NonNull Layer layer) throws NoSuchLayerException {
getMapView().getNativeMapView().removeLayer(layer);
}
/**
* Returns a {@link Source} if any source with the given identifier was found.
*
* Source identifiers are not guaranteed to exist across styles or different versions of the
* same style. Applications that use this API must set the style URL to an explicitly versioned
* style either by passing in the URL String using {@link MapboxMapOptions#styleUrl(String)} or
* setting through XML using {@link com.mapbox.mapboxsdk.R.attr#style_url}. This approach
* also avoids source identifier name changes that will occur in the default style’s source over
* time. These default styles can be found in the {@link Style} class.
*
*
* @param sourceId a String matching the source ID found within the current map style. This
* String is case sensitive.
* @return a {@link Source} object, null if the layer doesn't exist.
*/
@Nullable
@UiThread
public Source getSource(@NonNull String sourceId) {
return getMapView().getNativeMapView().getSource(sourceId);
}
/**
* Tries to cast the Source to T, returns null if it's another type.
*
* Source identifiers are not guaranteed to exist across styles or different versions of the
* same style. Applications that use this API must set the style URL to an explicitly versioned
* style either by passing in the URL String using {@link MapboxMapOptions#styleUrl(String)} or
* setting through XML using {@link com.mapbox.mapboxsdk.R.attr#style_url}. This approach
* also avoids source identifier name changes that will occur in the default style’s source over
* time. These default styles can be found in the {@link Style} class.
*
*
* @param sourceId the id used to look up a layer.
* @param the generic type of a Source.
* @return the casted Source, null if another type.
*/
@Nullable
@UiThread
public T getSourceAs(@NonNull String sourceId) {
try {
//noinspection unchecked
return (T) getMapView().getNativeMapView().getSource(sourceId);
} catch (ClassCastException e) {
Log.e(TAG, String.format("Source: %s is a different type: %s", sourceId, e.getMessage()));
return null;
}
}
/**
* Adds the source to the map. The source must be newly created and not added to the map before
*
* @param source the {@link Source} to add to the map view.
*/
@UiThread
public void addSource(@NonNull Source source) {
getMapView().getNativeMapView().addSource(source);
}
/**
* Removes a source from the map style. Any references to the source become invalid and should not be used anymore
*
* Source identifiers are not guaranteed to exist across styles or different versions of the
* same style. Applications that use this API must set the style URL to an explicitly versioned
* style either by passing in the URL String using {@link MapboxMapOptions#styleUrl(String)} or
* setting through XML using {@link com.mapbox.mapboxsdk.R.attr#style_url}. This approach
* also avoids source identifier name changes that will occur in the default style’s source over
* time. These default styles can be found in the {@link Style} class.
*
*
* @param sourceId a String identifier representing the source to remove.
* @throws NoSuchSourceException the source trying to be removed doesn't exist in the map.
*/
@UiThread
public void removeSource(@NonNull String sourceId) throws NoSuchSourceException {
getMapView().getNativeMapView().removeSource(sourceId);
}
/**
* Removes the source, preserving the reverence for re-use
*
* @param source the source to remove
* @throws NoSuchSourceException
*/
@UiThread
public void removeSource(@NonNull Source source) throws NoSuchSourceException {
getMapView().getNativeMapView().removeSource(source);
}
/**
* Adds an image to be used in the map's style
*
* @param name the name of the image.
* @param image the pre-multiplied Bitmap.
*/
@UiThread
public void addImage(@NonNull String name, @NonNull Bitmap image) {
getMapView().getNativeMapView().addImage(name, image);
}
/**
* Removes an image from the map style
*
* @param name the name of the image to remove.
*/
@UiThread
public void removeImage(String name) {
getMapView().getNativeMapView().removeImage(name);
}
//
// MinZoom
//
/**
* Sets the minimum zoom level the map can be displayed at.
*
* @param minZoom The new minimum zoom level.
*/
@UiThread
public void setMinZoom(
@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) {
if ((minZoom < MapboxConstants.MINIMUM_ZOOM) || (minZoom > MapboxConstants.MAXIMUM_ZOOM)) {
Log.e(MapboxConstants.TAG, "Not setting minZoom, value is in unsupported range: " + minZoom);
return;
}
minZoomLevel = minZoom;
mapView.setMinZoom(minZoom);
}
/**
* Gets the maximum zoom level the map can be displayed at.
*
* @return The minimum zoom level.
*/
@UiThread
public double getMinZoom() {
if (minZoomLevel == -1) {
return minZoomLevel = mapView.getMinZoom();
}
return minZoomLevel;
}
//
// MaxZoom
//
/**
* Sets the maximum zoom level the map can be displayed at.
*
* @param maxZoom The new maximum zoom level.
*/
@UiThread
public void setMaxZoom(
@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) {
if ((maxZoom < MapboxConstants.MINIMUM_ZOOM) || (maxZoom > MapboxConstants.MAXIMUM_ZOOM)) {
Log.e(MapboxConstants.TAG, "Not setting maxZoom, value is in unsupported range: " + maxZoom);
return;
}
maxZoomLevel = maxZoom;
mapView.setMaxZoom(maxZoom);
}
/**
* Gets the maximum zoom level the map can be displayed at.
*
* @return The maximum zoom level.
*/
@UiThread
public double getMaxZoom() {
if (maxZoomLevel == -1) {
return maxZoomLevel = mapView.getMaxZoom();
}
return maxZoomLevel;
}
//
// UiSettings
//
/**
* Gets the user interface settings for the map.
*
* @return the UiSettings associated with this map
*/
public UiSettings getUiSettings() {
return uiSettings;
}
//
// TrackingSettings
//
/**
* Gets the tracking interface settings for the map.
*
* @return the TrackingSettings asssociated with this map
*/
public TrackingSettings getTrackingSettings() {
return trackingSettings;
}
//
// MyLocationViewSettings
//
/**
* Gets the settings of the user location for the map.
*
* @return the MyLocationViewSettings associated with this map
*/
public MyLocationViewSettings getMyLocationViewSettings() {
if (myLocationViewSettings == null) {
myLocationViewSettings = new MyLocationViewSettings(mapView, mapView.getUserLocationView());
}
return myLocationViewSettings;
}
//
// Projection
//
/**
* Get the Projection object that you can use to convert between screen coordinates and latitude/longitude
* coordinates.
*
* @return the Projection associated with this map
*/
public Projection getProjection() {
return projection;
}
//
// Camera API
//
/**
* Gets the current position of the camera.
* The CameraPosition returned is a snapshot of the current position, and will not automatically update when the
* camera moves.
*
* @return The current position of the Camera.
*/
public final CameraPosition getCameraPosition() {
invalidCameraPosition = invalidCameraPosition || cameraPosition == null;
if (invalidCameraPosition) {
invalidateCameraPosition();
}
return cameraPosition;
}
/**
* Repositions the camera according to the cameraPosition.
* The move is instantaneous, and a subsequent getCameraPosition() will reflect the new position.
* See CameraUpdateFactory for a set of updates.
*
* @param cameraPosition the camera position to set
*/
public void setCameraPosition(@NonNull CameraPosition cameraPosition) {
moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
/**
* Repositions the camera according to the instructions defined in the update.
* The move is instantaneous, and a subsequent getCameraPosition() will reflect the new position.
* See CameraUpdateFactory for a set of updates.
*
* @param update The change that should be applied to the camera.
*/
@UiThread
public final void moveCamera(CameraUpdate update) {
moveCamera(update, null);
}
/**
* Repositions the camera according to the instructions defined in the update.
* The move is instantaneous, and a subsequent getCameraPosition() will reflect the new position.
* See CameraUpdateFactory for a set of updates.
*
* @param update The change that should be applied to the camera
* @param callback the callback to be invoked when an animation finishes or is canceled
*/
@UiThread
public final void moveCamera(final CameraUpdate update, final MapboxMap.CancelableCallback callback) {
mapView.post(new Runnable() {
@Override
public void run() {
cameraPosition = update.getCameraPosition(MapboxMap.this);
mapView.resetTrackingModesIfRequired(cameraPosition);
mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom);
if (callback != null) {
callback.onFinish();
}
if (onCameraChangeListener != null) {
onCameraChangeListener.onCameraChange(cameraPosition);
}
}
});
}
/**
* Gradually move the camera by the default duration, zoom will not be affected unless specified
* within {@link CameraUpdate}. If {@link #getCameraPosition()} is called during the animation,
* it will return the current location of the camera in flight.
*
* @param update The change that should be applied to the camera.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void easeCamera(CameraUpdate update) {
easeCamera(update, MapboxConstants.ANIMATION_DURATION);
}
/**
* Gradually move the camera by a specified duration in milliseconds, zoom will not be affected
* unless specified within {@link CameraUpdate}. If {@link #getCameraPosition()} is called
* during the animation, it will return the current location of the camera in flight.
*
* @param update The change that should be applied to the camera.
* @param durationMs The duration of the animation in milliseconds. This must be strictly
* positive, otherwise an IllegalArgumentException will be thrown.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void easeCamera(CameraUpdate update, int durationMs) {
easeCamera(update, durationMs, null);
}
/**
* Gradually move the camera by a specified duration in milliseconds, zoom will not be affected
* unless specified within {@link CameraUpdate}. A callback can be used to be notified when
* easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it
* will return the current location of the camera in flight.
*
* Note that this will cancel location tracking mode if enabled.
*
*
* @param update The change that should be applied to the camera.
* @param durationMs The duration of the animation in milliseconds. This must be strictly
* positive, otherwise an IllegalArgumentException will be thrown.
* @param callback An optional callback to be notified from the main thread when the animation
* stops. If the animation stops due to its natural completion, the callback
* will be notified with onFinish(). If the animation stops due to interruption
* by a later camera movement or a user gesture, onCancel() will be called.
* Do not update or ease the camera from within onCancel().
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void easeCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) {
easeCamera(update, durationMs, true, callback);
}
/**
* Gradually move the camera by a specified duration in milliseconds, zoom will not be affected
* unless specified within {@link CameraUpdate}. A callback can be used to be notified when
* easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it
* will return the current location of the camera in flight.
*
* Note that this will cancel location tracking mode if enabled.
*
*
* @param update The change that should be applied to the camera.
* @param durationMs The duration of the animation in milliseconds. This must be strictly
* positive, otherwise an IllegalArgumentException will be thrown.
* @param easingInterpolator The rate of change of the camera animation. If false, the easing
* animation will be linear.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void easeCamera(CameraUpdate update, int durationMs, boolean easingInterpolator) {
easeCamera(update, durationMs, easingInterpolator, null);
}
/**
* Gradually move the camera by a specified duration in milliseconds, zoom will not be affected
* unless specified within {@link CameraUpdate}. A callback can be used to be notified when
* easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it
* will return the current location of the camera in flight.
*
* Note that this will cancel location tracking mode if enabled.
*
*
* @param update The change that should be applied to the camera.
* @param durationMs The duration of the animation in milliseconds. This must be strictly
* positive, otherwise an IllegalArgumentException will be thrown.
* @param easingInterpolator The rate of change of the camera animation. If false, the easing
* animation will be linear.
* @param callback An optional callback to be notified from the main thread when the
* animation stops. If the animation stops due to its natural
* completion, the callback will be notified with onFinish(). If the
* animation stops due to interruption by a later camera movement or a
* user gesture, onCancel() will be called. Do not update or ease the
* camera from within onCancel().
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void easeCamera(
CameraUpdate update, int durationMs, boolean easingInterpolator, final MapboxMap.CancelableCallback callback) {
// dismiss tracking, moving camera is equal to a gesture
easeCamera(update, durationMs, easingInterpolator, true, callback);
}
/**
* Gradually move the camera by a specified duration in milliseconds, zoom will not be affected
* unless specified within {@link CameraUpdate}. A callback can be used to be notified when
* easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it
* will return the current location of the camera in flight.
*
* Note that this will cancel location tracking mode if enabled.
*
*
* @param update The change that should be applied to the camera.
* @param durationMs The duration of the animation in milliseconds. This must be strictly
* positive, otherwise an IllegalArgumentException will be thrown.
* @param easingInterpolator The rate of change of the camera animation. If false, the easing
* animation will be linear.
* @param resetTrackingMode Dismiss tracking, moving camera is equal to a gesture.
* @param callback An optional callback to be notified from the main thread when the
* animation stops. If the animation stops due to its natural
* completion, the callback will be notified with onFinish(). If the
* animation stops due to interruption by a later camera movement or a
* user gesture, onCancel() will be called. Do not update or ease the
* camera from within onCancel().
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator, final boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) {
mapView.post(new Runnable() {
@Override
public void run() {
// dismiss tracking, moving camera is equal to a gesture
cameraPosition = update.getCameraPosition(MapboxMap.this);
if (resetTrackingMode) {
mapView.resetTrackingModesIfRequired(cameraPosition);
}
mapView.easeTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt,
cameraPosition.zoom, easingInterpolator, new CancelableCallback() {
@Override
public void onCancel() {
if (callback != null) {
callback.onCancel();
}
invalidateCameraPosition();
}
@Override
public void onFinish() {
if (callback != null) {
callback.onFinish();
}
invalidateCameraPosition();
}
});
}
});
}
/**
* Animate the camera to a new location defined within {@link CameraUpdate} using a transition
* animation that evokes powered flight. The animation will last the default amount of time.
* During the animation, a call to {@link #getCameraPosition()} returns an intermediate location
* of the camera in flight.
*
* @param update The change that should be applied to the camera.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void animateCamera(CameraUpdate update) {
animateCamera(update, MapboxConstants.ANIMATION_DURATION, null);
}
/**
* Animate the camera to a new location defined within {@link CameraUpdate} using a transition
* animation that evokes powered flight. The animation will last the default amount of time. A
* callback can be used to be notified when animating the camera stops. During the animation, a
* call to {@link #getCameraPosition()} returns an intermediate location of the camera in flight.
*
* @param update The change that should be applied to the camera.
* @param callback The callback to invoke from the main thread when the animation stops. If the
* animation completes normally, onFinish() is called; otherwise, onCancel() is
* called. Do not update or animate the camera from within onCancel().
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void animateCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) {
animateCamera(update, MapboxConstants.ANIMATION_DURATION, callback);
}
/**
* Animate the camera to a new location defined within {@link CameraUpdate} using a transition
* animation that evokes powered flight. The animation will last a specified amount of time
* given in milliseconds. During the animation, a call to {@link #getCameraPosition()} returns
* an intermediate location of the camera in flight.
*
* @param update The change that should be applied to the camera.
* @param durationMs The duration of the animation in milliseconds. This must be strictly
* positive, otherwise an IllegalArgumentException will be thrown.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void animateCamera(CameraUpdate update, int durationMs) {
animateCamera(update, durationMs, null);
}
/**
* Animate the camera to a new location defined within {@link CameraUpdate} using a transition
* animation that evokes powered flight. The animation will last a specified amount of time
* given in milliseconds. A callback can be used to be notified when animating the camera stops.
* During the animation, a call to {@link #getCameraPosition()} returns an intermediate location
* of the camera in flight.
*
* @param update The change that should be applied to the camera.
* @param durationMs The duration of the animation in milliseconds. This must be strictly
* positive, otherwise an IllegalArgumentException will be thrown.
* @param callback An optional callback to be notified from the main thread when the animation
* stops. If the animation stops due to its natural completion, the callback
* will be notified with onFinish(). If the animation stops due to interruption
* by a later camera movement or a user gesture, onCancel() will be called.
* Do not update or animate the camera from within onCancel(). If a callback
* isn't required, leave it as null.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
public final void animateCamera(final CameraUpdate update, final int durationMs, final MapboxMap.CancelableCallback callback) {
mapView.post(new Runnable() {
@Override
public void run() {
cameraPosition = update.getCameraPosition(MapboxMap.this);
mapView.resetTrackingModesIfRequired(cameraPosition);
mapView.flyTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt,
cameraPosition.zoom, new CancelableCallback() {
@Override
public void onCancel() {
if (callback != null) {
callback.onCancel();
}
invalidateCameraPosition();
}
@Override
public void onFinish() {
if (onCameraChangeListener != null) {
onCameraChangeListener.onCameraChange(cameraPosition);
}
if (callback != null) {
callback.onFinish();
}
invalidateCameraPosition();
}
});
}
});
}
/**
* Converts milliseconds to nanoseconds
*
* @param durationMs The time in milliseconds
* @return time in nanoseconds
*/
private long getDurationNano(long durationMs) {
return durationMs > 0 ? TimeUnit.NANOSECONDS.convert(durationMs, TimeUnit.MILLISECONDS) : 0;
}
/**
* Invalidates the current camera position by reconstructing it from mbgl
*/
private void invalidateCameraPosition() {
if (invalidCameraPosition) {
invalidCameraPosition = false;
CameraPosition cameraPosition = mapView.invalidateCameraPosition();
if (cameraPosition != null) {
this.cameraPosition = cameraPosition;
}
if (onCameraChangeListener != null) {
onCameraChangeListener.onCameraChange(this.cameraPosition);
}
}
}
//
// Reset North
//
/**
* Resets the map view to face north.
*/
public void resetNorth() {
mapView.resetNorth();
}
//
// Debug
//
/**
* Returns whether the map debug information is currently shown.
*
* @return If true, map debug information is currently shown.
*/
@UiThread
public boolean isDebugActive() {
return mapView.isDebugActive();
}
/**
*
* Changes whether the map debug information is shown.
*
* The default value is false.
*
* @param debugActive If true, map debug information is shown.
*/
@UiThread
public void setDebugActive(boolean debugActive) {
mapView.setDebugActive(debugActive);
}
/**
*
* Cycles through the map debug options.
*
* The value of {@link MapView#isDebugActive()} reflects whether there are
* any map debug options enabled or disabled.
*
* @see MapView#isDebugActive()
*/
@UiThread
public void cycleDebugOptions() {
mapView.cycleDebugOptions();
}
//
// Styling
//
/**
*
* Loads a new map style from the specified URL.
*
* {@code url} can take the following forms:
*
* - {@code Style.*}: load one of the bundled styles in {@link Style}.
* - {@code mapbox://styles/
/