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.Bundle;
import android.os.Handler;
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.Pools;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
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.List;
import timber.log.Timber;
/**
* 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 final class MapboxMap {
private final NativeMapView nativeMapView;
private final UiSettings uiSettings;
private final TrackingSettings trackingSettings;
private final Projection projection;
private final Transform transform;
private final AnnotationManager annotationManager;
private final MyLocationViewSettings myLocationViewSettings;
private final OnRegisterTouchListener onRegisterTouchListener;
private MapboxMap.OnFpsChangedListener onFpsChangedListener;
MapboxMap(NativeMapView map, Transform transform, UiSettings ui, TrackingSettings tracking,
MyLocationViewSettings myLocationView, Projection projection, OnRegisterTouchListener listener,
AnnotationManager annotations) {
this.nativeMapView = map;
this.uiSettings = ui;
this.trackingSettings = tracking;
this.projection = projection;
this.myLocationViewSettings = myLocationView;
this.annotationManager = annotations.bind(this);
this.transform = transform;
this.onRegisterTouchListener = listener;
}
void initialise(@NonNull Context context, @NonNull MapboxMapOptions options) {
transform.initialise(this, options);
uiSettings.initialise(context, options);
myLocationViewSettings.initialise(options);
trackingSettings.initialise(options);
// Map configuration
setDebugActive(options.getDebugActive());
setApiBaseUrl(options);
setStyleUrl(options);
}
void onStart() {
nativeMapView.update();
trackingSettings.onStart();
if (TextUtils.isEmpty(nativeMapView.getStyleUrl())) {
// if user hasn't loaded a Style yet
nativeMapView.setStyleUrl(Style.MAPBOX_STREETS);
}
}
void onStop() {
trackingSettings.onStop();
}
void onSaveInstanceState(Bundle outState) {
outState.putParcelable(MapboxConstants.STATE_CAMERA_POSITION, transform.getCameraPosition());
outState.putBoolean(MapboxConstants.STATE_DEBUG_ACTIVE, nativeMapView.getDebug());
outState.putString(MapboxConstants.STATE_STYLE_URL, nativeMapView.getStyleUrl());
trackingSettings.onSaveInstanceState(outState);
uiSettings.onSaveInstanceState(outState);
}
void onRestoreInstanceState(Bundle savedInstanceState) {
final CameraPosition cameraPosition = savedInstanceState.getParcelable(MapboxConstants.STATE_CAMERA_POSITION);
if (cameraPosition != null) {
moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder(cameraPosition).build()));
}
uiSettings.onRestoreInstanceState(savedInstanceState);
trackingSettings.onRestoreInstanceState(savedInstanceState);
nativeMapView.setDebug(savedInstanceState.getBoolean(MapboxConstants.STATE_DEBUG_ACTIVE));
final String styleUrl = savedInstanceState.getString(MapboxConstants.STATE_STYLE_URL);
if (!TextUtils.isEmpty(styleUrl)) {
nativeMapView.setStyleUrl(savedInstanceState.getString(MapboxConstants.STATE_STYLE_URL));
}
}
/**
* Called before the OnMapReadyCallback is invoked.
*/
void onPreMapReady() {
annotationManager.reloadMarkers();
annotationManager.adjustTopOffsetPixels(this);
}
/**
* Called when the OnMapReadyCallback has finished executing.
*
* Invalidation of the camera position is required to update the added components in
* OnMapReadyCallback with the correct transformation.
*
*/
void onPostMapReady() {
invalidateCameraPosition();
}
/**
* Called when the user
*/
void onUpdate() {
CameraPosition cameraPosition = transform.invalidateCameraPosition();
uiSettings.update(cameraPosition);
// FIXME introduce update method with camera position
trackingSettings.update();
annotationManager.update();
}
// Style
/**
*
* Get the animation duration for style changes.
*
* The default value is zero, so any changes take effect without animation.
*
* @return Duration in seconds
*/
@UiThread
public long getTransitionDuration() {
return nativeMapView.getTransitionDuration();
}
/**
* Set the animation duration for style changes.
*
* @param duration Duration in seconds
*/
@UiThread
public void setTransitionDuration(long duration) {
nativeMapView.setTransitionDuration(duration);
}
/**
*
* Get the animation delay for style changes.
*
* The default value is zero, so any changes begin to animate immediately.
*
* @return Delay in seconds
*/
@UiThread
public long getTransitionDelay() {
return nativeMapView.getTransitionDelay();
}
/**
* Set the animation delay for style changes.
*
* @param delay Delay in seconds
*/
@UiThread
public void setTransitionDelay(long delay) {
nativeMapView.setTransitionDelay(delay);
}
@Nullable
@UiThread
public Layer getLayer(@NonNull String layerId) {
return nativeMapView.getLayer(layerId);
}
/**
* Tries to cast the Layer to T, returns null if it's another type.
*
* @param layerId the layer id used to look up a layer
* @param the generic attribute of a Layer
* @return the casted Layer, null if another type
*/
@Nullable
@UiThread
public T getLayerAs(@NonNull String layerId) {
try {
// noinspection unchecked
return (T) nativeMapView.getLayer(layerId);
} catch (ClassCastException exception) {
Timber.e(String.format("Layer: %s is a different type: %s", layerId, exception));
return null;
}
}
/**
* Adds the layer to the map. The layer must be newly created and not added to the map before
*
* @param layer the layer to add
*/
@UiThread
public void addLayer(@NonNull Layer layer) {
addLayer(layer, null);
}
/**
* Adds the layer to the map. The layer must be newly created and not added to the map before
*
* @param layer the layer to add
* @param before the layer id to add this layer before
*/
@UiThread
public void addLayer(@NonNull Layer layer, String before) {
nativeMapView.addLayer(layer, before);
}
/**
* Removes the layer. Any references to the layer become invalid and should not be used anymore
*
* @param layerId the layer to remove
* @throws NoSuchLayerException the exception thrown when layer with layerId doesn't exist
*/
@UiThread
public void removeLayer(@NonNull String layerId) throws NoSuchLayerException {
nativeMapView.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 the exeption thrown when the layer doesn't exist
*/
@UiThread
public void removeLayer(@NonNull Layer layer) throws NoSuchLayerException {
nativeMapView.removeLayer(layer);
}
@Nullable
@UiThread
public Source getSource(@NonNull String sourceId) {
return nativeMapView.getSource(sourceId);
}
/**
* Tries to cast the Source to T, returns null if it's another type.
*
* @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) nativeMapView.getSource(sourceId);
} catch (ClassCastException exception) {
Timber.e(String.format("Source: %s is a different type: %s", sourceId, exception));
return null;
}
}
/**
* Adds the source to the map. The source must be newly created and not added to the map before
*
* @param source the source to add
*/
@UiThread
public void addSource(@NonNull Source source) {
nativeMapView.addSource(source);
}
/**
* Removes the source. Any references to the source become invalid and should not be used anymore
*
* @param sourceId the source to remove
* @throws NoSuchSourceException the exception thrown when the source with sourceId doesn't exist
*/
@UiThread
public void removeSource(@NonNull String sourceId) throws NoSuchSourceException {
nativeMapView.removeSource(sourceId);
}
/**
* Removes the source, preserving the reverence for re-use
*
* @param source the source to remove
* @throws NoSuchSourceException the exception thrown when the source with sourceId doesn't exist
*/
@UiThread
public void removeSource(@NonNull Source source) throws NoSuchSourceException {
nativeMapView.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) {
nativeMapView.addImage(name, image);
}
/**
* Removes an image from the map's style
*
* @param name the name of the image to remove
*/
@UiThread
public void removeImage(String name) {
nativeMapView.removeImage(name);
}
//
// MinZoom
//
/**
*
* Sets the minimum zoom level the map can be displayed at.
*
*
* @param minZoom The new minimum zoom level.
*/
@UiThread
public void setMinZoomPreference(
@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) {
transform.setMinZoom(minZoom);
}
/**
*
* Gets the maximum zoom level the map can be displayed at.
*
*
* @return The minimum zoom level.
*/
@UiThread
public double getMinZoomLevel() {
return transform.getMinZoom();
}
//
// MaxZoom
//
/**
*
* Sets the maximum zoom level the map can be displayed at.
*
*
* @param maxZoom The new maximum zoom level.
*/
@UiThread
public void setMaxZoomPreference(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM,
to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) {
transform.setMaxZoom(maxZoom);
}
/**
*
* Gets the maximum zoom level the map can be displayed at.
*
*
* @return The maximum zoom level.
*/
@UiThread
public double getMaxZoomLevel() {
return transform.getMaxZoom();
}
//
// 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() {
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
//
/**
* Cancels ongoing animations.
*
* This invokes the {@link CancelableCallback} for ongoing camera updates.
*
*/
public void cancelTransitions() {
transform.cancelTransitions();
}
/**
* 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() {
return transform.getCameraPosition();
}
/**
* 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), 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.
*/
@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) {
new Handler().post(new Runnable() {
@Override
public void run() {
transform.moveCamera(MapboxMap.this, update, callback);
// MapChange.REGION_DID_CHANGE_ANIMATED is not called for `jumpTo`
// invalidate camera position to provide OnCameraChange event.
invalidateCameraPosition();
}
});
}
/**
* 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 True for easing interpolator, false for linear.
*/
@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. You can change this behaviour by calling
* {@link TrackingSettings#setDismissTrackingModeForCameraPositionChange(boolean)} with false before invoking this
* method and calling it with true in the {@link CancelableCallback#onFinish()}.
*
*
* @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 True for easing interpolator, false for 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().
*/
@UiThread
public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator,
final MapboxMap.CancelableCallback callback) {
new Handler().post(new Runnable() {
@Override
public void run() {
transform.easeCamera(MapboxMap.this, update, durationMs, easingInterpolator, callback);
}
});
}
/**
* 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) {
new Handler().post(new Runnable() {
@Override
public void run() {
transform.animateCamera(MapboxMap.this, update, durationMs, callback);
}
});
}
/**
* Invalidates the current camera position by reconstructing it from mbgl
*/
void invalidateCameraPosition() {
CameraPosition cameraPosition = transform.invalidateCameraPosition();
if (cameraPosition != null) {
transform.updateCameraPosition(cameraPosition);
}
}
//
// Reset North
//
/**
* Resets the map view to face north.
*/
public void resetNorth() {
transform.resetNorth();
}
/**
* Set focal bearing.
*/
public void setFocalBearing(double bearing, float focalX, float focalY, long duration) {
transform.setBearing(bearing, focalX, focalY, duration);
}
public float getHeight() {
return nativeMapView.getHeight();
}
public float getWidth() {
return nativeMapView.getWidth();
}
//
// Debug
//
/**
* Returns whether the map debug information is currently shown.
*
* @return If true, map debug information is currently shown.
*/
@UiThread
public boolean isDebugActive() {
return nativeMapView.getDebug();
}
/**
*
* 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) {
nativeMapView.setDebug(debugActive);
}
/**
*
* Cycles through the map debug options.
*
* The value of isDebugActive reflects whether there are
* any map debug options enabled or disabled.
*
* @see #isDebugActive()
*/
@UiThread
public void cycleDebugOptions() {
nativeMapView.cycleDebugOptions();
}
//
// API endpoint config
//
private void setApiBaseUrl(@NonNull MapboxMapOptions options) {
String apiBaseUrl = options.getApiBaseUrl();
if (!TextUtils.isEmpty(apiBaseUrl)) {
nativeMapView.setApiBaseUrl(apiBaseUrl);
}
}
//
// 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/
/