summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java26
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java200
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java267
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java25
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java24
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java143
7 files changed, 387 insertions, 302 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
index 4b26be558f..9e08d93bfc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
@@ -30,7 +30,7 @@ import java.util.List;
* Exposes convenience methods to add/remove/update all subtypes of annotations found in com.mapbox.mapboxsdk.annotations.
* </p>
*/
-class AnnotationManager {
+class AnnotationManager implements MapView.OnMapChangedListener {
private NativeMapView nativeMapView;
private IconManager iconManager;
@@ -41,6 +41,7 @@ class AnnotationManager {
private List<Marker> selectedMarkers;
private MapboxMap.OnMarkerClickListener onMarkerClickListener;
+ private boolean isWaitingForRenderInvoke;
AnnotationManager(NativeMapView view, IconManager iconManager, InfoWindowManager manager) {
this.nativeMapView = view;
@@ -48,6 +49,19 @@ class AnnotationManager {
this.infoWindowManager = manager;
this.selectedMarkers = new ArrayList<>();
this.annotations = new LongSparseArray<>();
+
+ if (view != null) {
+ // null checking needed for unit tests
+ view.addOnMapChangedListener(this);
+ }
+ }
+
+ @Override
+ public void onMapChanged(@MapView.MapChange int change) {
+ if (isWaitingForRenderInvoke && change == MapView.DID_FINISH_RENDERING_FRAME_FULLY_RENDERED) {
+ isWaitingForRenderInvoke = false;
+ markerViewManager.invalidateViewMarkersInVisibleRegion();
+ }
}
//
@@ -194,18 +208,24 @@ class AnnotationManager {
}
MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap) {
+ isWaitingForRenderInvoke = true;
MarkerView marker = prepareViewMarker(markerOptions);
marker.setMapboxMap(mapboxMap);
long id = nativeMapView.addMarker(marker);
marker.setId(id);
annotations.put(id, marker);
- markerViewManager.invalidateViewMarkersInVisibleRegion();
return marker;
}
List<MarkerView> addMarkerViews(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions, @NonNull MapboxMap mapboxMap) {
List<MarkerView> markers = new ArrayList<>();
for (BaseMarkerViewOptions markerViewOption : markerViewOptions) {
+ // if last marker
+ if (markerViewOptions.indexOf(markerViewOption) == markerViewOptions.size() - 1) {
+ // get notified when render occurs to invalidate and draw MarkerViews
+ isWaitingForRenderInvoke = true;
+ }
+ // add marker to map
MarkerView marker = prepareViewMarker(markerViewOption);
marker.setMapboxMap(mapboxMap);
long id = nativeMapView.addMarker(marker);
@@ -283,7 +303,7 @@ class AnnotationManager {
}
if (infoWindowManager.isInfoWindowValidForMarker(marker) || infoWindowManager.getInfoWindowAdapter() != null) {
- infoWindowManager.getInfoWindows().add(marker.showInfoWindow(mapboxMap, mapboxMap.getMapView()));
+ infoWindowManager.add(marker.showInfoWindow(mapboxMap, mapboxMap.getMapView()));
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java
index 7b58807973..791f310b4c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java
@@ -80,4 +80,8 @@ class InfoWindowManager {
MapboxMap.OnInfoWindowCloseListener getOnInfoWindowCloseListener() {
return onInfoWindowCloseListener;
}
+
+ public void add(InfoWindow infoWindow) {
+ infoWindows.add(infoWindow);
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
index a9f2ed23fc..5840e574c8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
@@ -87,7 +87,6 @@ import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
import static com.mapbox.mapboxsdk.utils.MathUtils.convertNativeBearing;
@@ -126,7 +125,6 @@ public class MapView extends FrameLayout {
private Projection projection;
- private CopyOnWriteArrayList<OnMapChangedListener> onMapChangedListener;
private ZoomButtonsController zoomButtonsController;
private ConnectivityReceiver connectivityReceiver;
private float screenDensity = 1.0f;
@@ -153,7 +151,6 @@ public class MapView extends FrameLayout {
private boolean styleWasSet = false;
private List<OnMapReadyCallback> onMapReadyCallbackList;
- private MapboxMap.CancelableCallback cameraCancelableCallback;
private SnapshotRequest snapshotRequest;
private boolean onStartCalled;
@@ -192,7 +189,6 @@ public class MapView extends FrameLayout {
initialLoad = true;
onMapReadyCallbackList = new ArrayList<>();
- onMapChangedListener = new CopyOnWriteArrayList<>();
View view = LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_internal, this);
setWillNotDraw(false);
@@ -483,7 +479,7 @@ public class MapView extends FrameLayout {
}
// invalidate camera to update overlain views with correct tilt value
- invalidateCameraPosition();
+ mapboxMap.invalidateCameraPosition();
} else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) {
mapboxMap.getMarkerViewManager().scheduleViewMarkerInvalidation();
@@ -705,11 +701,11 @@ public class MapView extends FrameLayout {
// Center coordinate
//
- LatLng getCenterCoordinate(){
+ LatLng getCenterCoordinate() {
return nativeMapView.getLatLng();
}
- void setCenterCoordinate(LatLng centerCoordinate){
+ void setCenterCoordinate(LatLng centerCoordinate) {
nativeMapView.setLatLng(centerCoordinate);
}
@@ -737,7 +733,7 @@ public class MapView extends FrameLayout {
return;
}
long duration = animated ? MapboxConstants.ANIMATION_DURATION : 0;
- cancelTransitions();
+ mapboxMap.cancelTransitions();
// Out of range directions are normalised in setBearing
nativeMapView.setBearing(-direction, duration);
}
@@ -747,7 +743,7 @@ public class MapView extends FrameLayout {
return;
}
myLocationView.setBearing(0);
- cancelTransitions();
+ mapboxMap.cancelTransitions();
nativeMapView.resetNorth();
}
@@ -817,16 +813,13 @@ public class MapView extends FrameLayout {
private void zoom(boolean zoomIn, float x, float y) {
// Cancel any animation
- cancelTransitions();
+ mapboxMap.cancelTransitions();
if (zoomIn) {
nativeMapView.scaleBy(2.0, x / screenDensity, y / screenDensity, MapboxConstants.ANIMATION_DURATION);
} else {
nativeMapView.scaleBy(0.5, x / screenDensity, y / screenDensity, MapboxConstants.ANIMATION_DURATION);
}
-
- // work around to invalidate camera position
- postDelayed(new ZoomInvalidator(mapboxMap), MapboxConstants.ANIMATION_DURATION);
}
//
@@ -1068,76 +1061,6 @@ public class MapView extends FrameLayout {
}
//
- // Mapbox Core GL Camera
- //
-
- private void cancelTransitions(){
- if (cameraCancelableCallback != null) {
- cameraCancelableCallback.onCancel();
- cameraCancelableCallback = null;
- }
- nativeMapView.cancelTransitions();
- }
-
- void jumpTo(double bearing, LatLng center, double pitch, double zoom) {
- if (destroyed) {
- return;
- }
- cancelTransitions();
- nativeMapView.jumpTo(bearing, center, pitch, zoom);
- }
-
- void easeTo(double bearing, LatLng center, long duration, double pitch, double zoom, boolean easingInterpolator, @Nullable final MapboxMap.CancelableCallback cancelableCallback) {
- if (destroyed) {
- return;
- }
- cancelTransitions();
-
- // Register callbacks early enough
- if (cancelableCallback != null) {
- cameraCancelableCallback = cancelableCallback;
- addOnMapChangedListener(new OnMapChangedListener() {
- @Override
- public void onMapChanged(@MapChange int change) {
- if (change == REGION_DID_CHANGE_ANIMATED && cameraCancelableCallback != null) {
- cameraCancelableCallback.onFinish();
- cameraCancelableCallback = null;
- // Clean up after self
- removeOnMapChangedListener(this);
- }
- }
- });
- }
-
- nativeMapView.easeTo(bearing, center, duration, pitch, zoom, easingInterpolator);
- }
-
- void flyTo(double bearing, LatLng center, long duration, double pitch, double zoom, @Nullable final MapboxMap.CancelableCallback cancelableCallback) {
- if (destroyed) {
- return;
- }
- cancelTransitions();
-
- // Register callbacks early enough
- if (cancelableCallback != null) {
- cameraCancelableCallback = cancelableCallback;
- addOnMapChangedListener(new OnMapChangedListener() {
- @Override
- public void onMapChanged(@MapChange int change) {
- if (change == REGION_DID_CHANGE_ANIMATED && cameraCancelableCallback != null) {
- cancelableCallback.onFinish();
- cameraCancelableCallback = null;
- // Clean up after self
- removeOnMapChangedListener(this);
- }
- }
- });
- }
-
- nativeMapView.flyTo(bearing, center, duration, pitch, zoom);
- }
-
- //
// Rendering
//
@@ -1268,14 +1191,9 @@ public class MapView extends FrameLayout {
}
}
- CameraPosition invalidateCameraPosition() {
- if (destroyed) {
- return new CameraPosition.Builder().build();
- }
- CameraPosition position = new CameraPosition.Builder(nativeMapView.getCameraValues()).build();
+ void updateCameraPosition(@NonNull CameraPosition position) {
myLocationView.setCameraPosition(position);
mapboxMap.getMarkerViewManager().setTilt((float) position.tilt);
- return position;
}
double getBearing() {
@@ -1560,7 +1478,7 @@ public class MapView extends FrameLayout {
return false;
}
// Cancel any animation
- cancelTransitions();
+ mapboxMap.cancelTransitions();
return true;
}
@@ -1649,12 +1567,12 @@ public class MapView extends FrameLayout {
return false;
}
- resetTrackingModesIfRequired(true, false);
+ mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(true, false);
double decelerationRate = 1;
// Cancel any animation
- cancelTransitions();
+ mapboxMap.cancelTransitions();
double offsetX = velocityX * decelerationRate / 4 / screenDensity;
double offsetY = velocityY * decelerationRate / 4 / screenDensity;
@@ -1689,9 +1607,9 @@ public class MapView extends FrameLayout {
requestDisallowInterceptTouchEvent(true);
// reset tracking if needed
- resetTrackingModesIfRequired(true, false);
+ mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(true, false);
// Cancel any animation
- cancelTransitions();
+ mapboxMap.cancelTransitions();
// Scroll the map
nativeMapView.moveBy(-distanceX / screenDensity, -distanceY / screenDensity);
@@ -1762,7 +1680,7 @@ public class MapView extends FrameLayout {
}
// Cancel any animation
- cancelTransitions();
+ mapboxMap.cancelTransitions();
// Gesture is a quickzoom if there aren't two fingers
quickZoom = !twoTap;
@@ -1771,7 +1689,7 @@ public class MapView extends FrameLayout {
// to be in the center of the map. Therefore the zoom will translate the map center, so tracking
// should be disabled.
- resetTrackingModesIfRequired(!quickZoom, false);
+ mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(!quickZoom, false);
// Scale the map
if (focalPoint != null) {
// arround user provided focal point
@@ -1843,12 +1761,12 @@ public class MapView extends FrameLayout {
}
// Cancel any animation
- cancelTransitions();
+ mapboxMap.cancelTransitions();
// rotation constitutes translation of anything except the center of
// rotation, so cancel both location and bearing tracking if required
- resetTrackingModesIfRequired(true, true);
+ mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(true, true);
// Get rotate value
double bearing = nativeMapView.getBearing();
@@ -1919,7 +1837,7 @@ public class MapView extends FrameLayout {
}
// Cancel any animation
- cancelTransitions();
+ mapboxMap.cancelTransitions();
// Get tilt value (scale and clamp)
double pitch = getTilt();
@@ -1986,7 +1904,7 @@ public class MapView extends FrameLayout {
}
// Cancel any animation
- cancelTransitions();
+ mapboxMap.cancelTransitions();
// Move left
nativeMapView.moveBy(scrollDist / screenDensity, 0.0 / screenDensity);
@@ -1998,8 +1916,8 @@ public class MapView extends FrameLayout {
}
// Cancel any animation
- cancelTransitions();
-
+ mapboxMap.cancelTransitions();
+
// Move right
nativeMapView.moveBy(-scrollDist / screenDensity, 0.0 / screenDensity);
return true;
@@ -2010,8 +1928,8 @@ public class MapView extends FrameLayout {
}
// Cancel any animation
- cancelTransitions();
-
+ mapboxMap.cancelTransitions();
+
// Move up
nativeMapView.moveBy(0.0 / screenDensity, scrollDist / screenDensity);
return true;
@@ -2022,7 +1940,7 @@ public class MapView extends FrameLayout {
}
// Cancel any animation
- cancelTransitions();
+ mapboxMap.cancelTransitions();
// Move down
nativeMapView.moveBy(0.0 / screenDensity, -scrollDist / screenDensity);
@@ -2102,8 +2020,8 @@ public class MapView extends FrameLayout {
}
// Cancel any animation
- cancelTransitions();
-
+ mapboxMap.cancelTransitions();
+
// Scroll the map
nativeMapView.moveBy(-10.0 * event.getX() / screenDensity, -10.0 * event.getY() / screenDensity);
return true;
@@ -2198,8 +2116,8 @@ public class MapView extends FrameLayout {
}
// Cancel any animation
- cancelTransitions();
-
+ mapboxMap.cancelTransitions();
+
// Get the vertical scroll amount, one click = 1
float scrollDist = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
@@ -2289,7 +2207,7 @@ public class MapView extends FrameLayout {
*/
public void addOnMapChangedListener(@Nullable OnMapChangedListener listener) {
if (listener != null) {
- onMapChangedListener.add(listener);
+ nativeMapView.addOnMapChangedListener(listener);
}
}
@@ -2301,7 +2219,7 @@ public class MapView extends FrameLayout {
*/
public void removeOnMapChangedListener(@Nullable OnMapChangedListener listener) {
if (listener != null) {
- onMapChangedListener.remove(listener);
+ nativeMapView.removeOnMapChangedListener(listener);
}
}
@@ -2309,14 +2227,7 @@ public class MapView extends FrameLayout {
// Called via JNI from NativeMapView
// Forward to any listeners
protected void onMapChanged(int mapChange) {
- if (onMapChangedListener != null) {
- OnMapChangedListener listener;
- final Iterator<OnMapChangedListener> iterator = onMapChangedListener.iterator();
- while (iterator.hasNext()) {
- listener = iterator.next();
- listener.onMapChanged(mapChange);
- }
- }
+ nativeMapView.onMapChangedEventDispatch(mapChange);
}
//
@@ -2382,42 +2293,6 @@ public class MapView extends FrameLayout {
ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
- void resetTrackingModesIfRequired(boolean translate, boolean rotate) {
- TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
-
- // if tracking is on, and we should dismiss tracking with gestures, and this is a scroll action, turn tracking off
- if (translate && !trackingSettings.isLocationTrackingDisabled() && trackingSettings.isDismissLocationTrackingOnGesture()) {
- resetLocationTrackingMode();
- }
-
- // reset bearing tracking only on rotate
- if (rotate && !trackingSettings.isBearingTrackingDisabled() && trackingSettings.isDismissBearingTrackingOnGesture()) {
- resetBearingTrackingMode();
- }
- }
-
- void resetTrackingModesIfRequired(CameraPosition cameraPosition) {
- resetTrackingModesIfRequired(cameraPosition.target != null, cameraPosition.bearing != -1);
- }
-
- private void resetLocationTrackingMode() {
- try {
- TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
- trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
- } catch (SecurityException ignore) {
- // User did not accept location permissions
- }
- }
-
- private void resetBearingTrackingMode() {
- try {
- TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
- trackingSettings.setMyBearingTrackingMode(MyBearingTracking.NONE);
- } catch (SecurityException ignore) {
- // User did not accept location permissions
- }
- }
-
//
// Compass
//
@@ -2653,21 +2528,6 @@ public class MapView extends FrameLayout {
}
}
- private static class ZoomInvalidator implements Runnable {
-
- private MapboxMap mapboxMap;
-
- ZoomInvalidator(MapboxMap mapboxMap) {
- this.mapboxMap = mapboxMap;
- }
-
- @Override
- public void run() {
- // invalidate camera position
- mapboxMap.getCameraPosition();
- }
- }
-
/**
* Definition of a map change event.
*
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
index ab6476f6e6..8e42e794be 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
@@ -5,7 +5,6 @@ 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;
@@ -45,7 +44,6 @@ import com.mapbox.services.commons.geojson.Feature;
import java.lang.reflect.ParameterizedType;
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
@@ -64,9 +62,7 @@ public class MapboxMap {
private TrackingSettings trackingSettings;
private MyLocationViewSettings myLocationViewSettings;
private Projection projection;
- private CameraPosition cameraPosition;
- private boolean invalidCameraPosition;
-
+ private Transform transform;
private boolean myLocationEnabled;
private MapboxMap.OnMapClickListener onMapClickListener;
@@ -78,7 +74,6 @@ public class MapboxMap {
private MapboxMap.OnMyLocationTrackingModeChangeListener onMyLocationTrackingModeChangeListener;
private MapboxMap.OnMyBearingTrackingModeChangeListener onMyBearingTrackingModeChangeListener;
private MapboxMap.OnFpsChangedListener onFpsChangedListener;
- private MapboxMap.OnCameraChangeListener onCameraChangeListener;
private AnnotationManager annotationManager;
private InfoWindowManager infoWindowManager;
@@ -88,12 +83,18 @@ public class MapboxMap {
MapboxMap(@NonNull MapView mapView, IconManager iconManager) {
this.mapView = mapView;
- this.mapView.addOnMapChangedListener(new MapChangeCameraPositionListener());
uiSettings = new UiSettings(mapView);
trackingSettings = new TrackingSettings(this.mapView, uiSettings);
projection = new Projection(mapView);
infoWindowManager = new InfoWindowManager();
annotationManager = new AnnotationManager(mapView.getNativeMapView(), iconManager, infoWindowManager);
+
+ // TODO inject NativeMapView https://github.com/mapbox/mapbox-gl-native/issues/4100
+ NativeMapView nativeMapView = mapView.getNativeMapView();
+ if (nativeMapView != null) {
+ transform = new Transform(nativeMapView, this);
+ nativeMapView.addOnMapChangedListener(new CameraInvalidator());
+ }
}
// Style
@@ -379,6 +380,16 @@ public class MapboxMap {
//
/**
+ * Cancels ongoing animations.
+ * <p>
+ * This invokes the {@link CancelableCallback} for ongoing camera updates.
+ * </p>
+ */
+ 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.
@@ -386,10 +397,7 @@ public class MapboxMap {
* @return The current position of the Camera.
*/
public final CameraPosition getCameraPosition() {
- if (invalidCameraPosition) {
- invalidateCameraPosition();
- }
- return cameraPosition;
+ return transform.getCameraPosition();
}
/**
@@ -400,7 +408,7 @@ public class MapboxMap {
* @param cameraPosition the camera position to set
*/
public void setCameraPosition(@NonNull CameraPosition cameraPosition) {
- moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
+ moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), null);
}
/**
@@ -424,17 +432,13 @@ public class MapboxMap {
* @param callback the callback to be invoked when an animation finishes or is canceled
*/
@UiThread
- public final void moveCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) {
- cameraPosition = update.getCameraPosition(this);
- mapView.resetTrackingModesIfRequired(cameraPosition);
- mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom);
- if (callback != null) {
- callback.onFinish();
- }
-
- if (onCameraChangeListener != null) {
- onCameraChangeListener.onCameraChange(this.cameraPosition);
- }
+ public final void moveCamera(final CameraUpdate update, final MapboxMap.CancelableCallback callback) {
+ mapView.post(new Runnable() {
+ @Override
+ public void run() {
+ transform.moveCamera(update, callback);
+ }
+ });
}
/**
@@ -489,11 +493,44 @@ public class MapboxMap {
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.
+ * <p>
+ * Note that this will cancel location tracking mode if enabled.
+ * </p>
+ *
+ * @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.
+ * <p>
+ * Note that this will cancel location tracking mode if enabled.
+ * </p>
+ *
+ * @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(
CameraUpdate update, int durationMs, boolean easingInterpolator, final MapboxMap.CancelableCallback callback) {
@@ -501,33 +538,34 @@ public class MapboxMap {
easeCamera(update, durationMs, easingInterpolator, true, callback);
}
- @UiThread
- public final void easeCamera(
- CameraUpdate update, int durationMs, boolean easingInterpolator, boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) {
- // dismiss tracking, moving camera is equal to a gesture
- cameraPosition = update.getCameraPosition(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();
- }
- });
+ /**
+ * 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.
+ * <p>
+ * Note that this will cancel location tracking mode if enabled.
+ * </p>
+ *
+ * @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 resetTrackingMode True to reset tracking modes if required, false to ignore
+ * @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 boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) {
+ mapView.post(new Runnable() {
+ @Override
+ public void run() {
+ transform.easeCamera(update, durationMs, easingInterpolator, resetTrackingMode, callback);
+ }
+ });
}
/**
@@ -596,58 +634,22 @@ public class MapboxMap {
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
@UiThread
- public final void animateCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) {
- cameraPosition = update.getCameraPosition(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;
+ public final void animateCamera(final CameraUpdate update, final int durationMs, final MapboxMap.CancelableCallback callback) {
+ mapView.post(new Runnable() {
+ @Override
+ public void run() {
+ transform.animateCamera(update, durationMs, callback);
+ }
+ });
}
/**
* 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);
- }
+ void invalidateCameraPosition() {
+ CameraPosition cameraPosition = transform.invalidateCameraPosition();
+ if (cameraPosition != null) {
+ mapView.updateCameraPosition(cameraPosition);
}
}
@@ -659,7 +661,7 @@ public class MapboxMap {
* Resets the map view to face north.
*/
public void resetNorth() {
- mapView.resetNorth();
+ transform.resetNorth();
}
//
@@ -875,7 +877,8 @@ public class MapboxMap {
@UiThread
@NonNull
- public List<MarkerView> addMarkerViews(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions) {
+ public List<MarkerView> addMarkerViews(@NonNull List<? extends
+ BaseMarkerViewOptions> markerViewOptions) {
return annotationManager.addMarkerViews(markerViewOptions, this);
}
@@ -897,7 +900,8 @@ public class MapboxMap {
*/
@UiThread
@NonNull
- public List<Marker> addMarkers(@NonNull List<? extends BaseMarkerOptions> markerOptionsList) {
+ public List<Marker> addMarkers(@NonNull List<? extends
+ BaseMarkerOptions> markerOptionsList) {
return annotationManager.addMarkers(markerOptionsList, this);
}
@@ -1239,7 +1243,7 @@ public class MapboxMap {
return infoWindowManager.isAllowConcurrentMultipleOpenInfoWindows();
}
- // used by MapView
+ // Internal API
List<InfoWindow> getInfoWindows() {
return infoWindowManager.getInfoWindows();
}
@@ -1248,6 +1252,11 @@ public class MapboxMap {
return annotationManager;
}
+ Transform getTransform() {
+ return transform;
+ }
+
+
//
// Padding
//
@@ -1299,7 +1308,7 @@ public class MapboxMap {
*/
@UiThread
public void setOnCameraChangeListener(@Nullable OnCameraChangeListener listener) {
- onCameraChangeListener = listener;
+ transform.setOnCameraChangeListener(listener);
}
/**
@@ -1410,7 +1419,8 @@ public class MapboxMap {
* use null.
*/
@UiThread
- public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener listener) {
+ public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener
+ listener) {
infoWindowManager.setOnInfoWindowLongClickListener(listener);
}
@@ -1493,7 +1503,8 @@ public class MapboxMap {
* To unset the callback, use null.
*/
@UiThread
- public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener listener) {
+ public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener
+ listener) {
mapView.setOnMyLocationChangeListener(listener);
}
@@ -1504,12 +1515,14 @@ public class MapboxMap {
* To unset the callback, use null.
*/
@UiThread
- public void setOnMyLocationTrackingModeChangeListener(@Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) {
+ public void setOnMyLocationTrackingModeChangeListener
+ (@Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) {
onMyLocationTrackingModeChangeListener = listener;
}
// used by MapView
- MapboxMap.OnMyLocationTrackingModeChangeListener getOnMyLocationTrackingModeChangeListener() {
+ MapboxMap.OnMyLocationTrackingModeChangeListener getOnMyLocationTrackingModeChangeListener
+ () {
return onMyLocationTrackingModeChangeListener;
}
@@ -1520,7 +1533,8 @@ public class MapboxMap {
* To unset the callback, use null.
*/
@UiThread
- public void setOnMyBearingTrackingModeChangeListener(@Nullable OnMyBearingTrackingModeChangeListener listener) {
+ public void setOnMyBearingTrackingModeChangeListener
+ (@Nullable OnMyBearingTrackingModeChangeListener listener) {
onMyBearingTrackingModeChangeListener = listener;
}
@@ -1582,7 +1596,8 @@ public class MapboxMap {
*/
@UiThread
@NonNull
- public List<Feature> queryRenderedFeatures(@NonNull PointF coordinates, @Nullable String... layerIds) {
+ public List<Feature> queryRenderedFeatures(@NonNull PointF coordinates, @Nullable String...
+ layerIds) {
return mapView.getNativeMapView().queryRenderedFeatures(coordinates, layerIds);
}
@@ -1595,11 +1610,26 @@ public class MapboxMap {
*/
@UiThread
@NonNull
- public List<Feature> queryRenderedFeatures(@NonNull RectF coordinates, @Nullable String... layerIds) {
+ public List<Feature> queryRenderedFeatures(@NonNull RectF coordinates, @Nullable String...
+ layerIds) {
return mapView.getNativeMapView().queryRenderedFeatures(coordinates, layerIds);
}
//
+ // Innner classes
+ //
+
+ private class CameraInvalidator implements MapView.OnMapChangedListener {
+
+ @Override
+ public void onMapChanged(@MapView.MapChange int change) {
+ if (change == MapView.REGION_DID_CHANGE_ANIMATED) {
+ invalidateCameraPosition();
+ }
+ }
+ }
+
+ //
// Interfaces
//
@@ -1963,23 +1993,4 @@ public class MapboxMap {
*/
void onSnapshotReady(Bitmap snapshot);
}
-
- private class MapChangeCameraPositionListener implements MapView.OnMapChangedListener {
-
- private static final long UPDATE_RATE_MS = 400;
- private long previousUpdateTimestamp = 0;
-
- @Override
- public void onMapChanged(@MapView.MapChange int change) {
- if (change >= MapView.REGION_WILL_CHANGE && change <= MapView.REGION_DID_CHANGE_ANIMATED) {
- invalidCameraPosition = true;
- long currentTime = SystemClock.elapsedRealtime();
- if (currentTime < previousUpdateTimestamp) {
- return;
- }
- invalidateCameraPosition();
- previousUpdateTimestamp = currentTime + UPDATE_RATE_MS;
- }
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
index e7e3e647af..cdd275ee34 100755
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
@@ -30,6 +30,7 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
// Class that wraps the native methods for convenience
final class NativeMapView {
@@ -44,6 +45,8 @@ final class NativeMapView {
private final float pixelRatio;
+ private CopyOnWriteArrayList<MapView.OnMapChangedListener> onMapChangedListeners;
+
//
// Static methods
//
@@ -83,7 +86,7 @@ final class NativeMapView {
if (totalMemory < 0) {
throw new IllegalArgumentException("totalMemory cannot be negative.");
}
-
+ onMapChangedListeners = new CopyOnWriteArrayList<>();
this.mapView = mapView;
nativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath, pixelRatio, availableProcessors, totalMemory);
}
@@ -778,4 +781,24 @@ final class NativeMapView {
private native Feature[] nativeQueryRenderedFeaturesForBox(long nativeMapViewPtr, float left, float top, float right, float bottom, String[] layerIds);
private native void nativeSetAPIBaseURL(long nativeMapViewPtr, String baseUrl);
+
+ //
+ // MapChangeEvents
+ //
+
+ void addOnMapChangedListener(@NonNull MapView.OnMapChangedListener listener) {
+ onMapChangedListeners.add(listener);
+ }
+
+ void removeOnMapChangedListener(@NonNull MapView.OnMapChangedListener listener) {
+ onMapChangedListeners.remove(listener);
+ }
+
+ void onMapChangedEventDispatch(int mapChange) {
+ if (onMapChangedListeners != null) {
+ for (MapView.OnMapChangedListener onMapChangedListener : onMapChangedListeners) {
+ onMapChangedListener.onMapChanged(mapChange);
+ }
+ }
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
index c32d4a8906..7f655fbeef 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.maps;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
@@ -211,4 +212,27 @@ public class TrackingSettings {
return uiSettings.isScrollGesturesEnabled() &&
(dismissLocationTrackingOnGesture || myLocationTrackingMode == MyLocationTracking.TRACKING_NONE);
}
+
+ /**
+ * Reset the tracking modes as necessary. Location tracking is reset if the map center is changed,
+ * bearing tracking if there is a rotation.
+ *
+ * @param translate
+ * @param rotate
+ */
+ public void resetTrackingModesIfRequired(boolean translate, boolean rotate) {
+ // if tracking is on, and we should dismiss tracking with gestures, and this is a scroll action, turn tracking off
+ if (translate && !isLocationTrackingDisabled() && isDismissLocationTrackingOnGesture()) {
+ setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
+ }
+
+ // reset bearing tracking only on rotate
+ if (rotate && !isBearingTrackingDisabled() && isDismissBearingTrackingOnGesture()) {
+ setMyBearingTrackingMode(MyBearingTracking.NONE);
+ }
+ }
+
+ public void resetTrackingModesIfRequired(CameraPosition cameraPosition) {
+ resetTrackingModesIfRequired(cameraPosition.target != null, cameraPosition.bearing != -1);
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
new file mode 100644
index 0000000000..1532bb6745
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
@@ -0,0 +1,143 @@
+package com.mapbox.mapboxsdk.maps;
+
+import android.support.annotation.Nullable;
+import android.support.annotation.UiThread;
+
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdate;
+
+import java.util.concurrent.TimeUnit;
+
+import static com.mapbox.mapboxsdk.maps.MapView.REGION_DID_CHANGE_ANIMATED;
+
+/**
+ * Resembles the current Map transformation.
+ * <p>
+ * Responsible for synchronising {@link CameraPosition} state and notifying {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraChangeListener}.
+ * </p>
+ */
+class Transform {
+
+ private NativeMapView mapView;
+ private MapboxMap mapboxMap;
+
+ private CameraPosition cameraPosition;
+ private MapboxMap.CancelableCallback cameraCancelableCallback;
+ private MapboxMap.OnCameraChangeListener onCameraChangeListener;
+
+ Transform(NativeMapView mapView, MapboxMap mapboxMap) {
+ this.mapView = mapView;
+ this.mapboxMap = mapboxMap;
+ }
+
+ //
+ // Camera API
+ //
+
+ @UiThread
+ public final CameraPosition getCameraPosition() {
+ if (cameraPosition == null) {
+ cameraPosition = invalidateCameraPosition();
+ }
+ return cameraPosition;
+ }
+
+ @UiThread
+ final void moveCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) {
+ cameraPosition = update.getCameraPosition(mapboxMap);
+ mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(cameraPosition);
+ cancelTransitions();
+ mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom);
+
+ // MapChange.REGION_DID_CHANGE_ANIMATED is not called for `jumpTo`
+ // invalidate camera position to provide OnCameraChange event.
+ mapboxMap.invalidateCameraPosition();
+ if (callback != null) {
+ callback.onFinish();
+ }
+ }
+
+ @UiThread
+ final void easeCamera(CameraUpdate update, int durationMs, boolean easingInterpolator, boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) {
+ cameraPosition = update.getCameraPosition(mapboxMap);
+ if (resetTrackingMode) {
+ mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(cameraPosition);
+ }
+
+ cancelTransitions();
+ if (callback != null) {
+ cameraCancelableCallback = callback;
+ mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
+ @Override
+ public void onMapChanged(@MapView.MapChange int change) {
+ if (change == REGION_DID_CHANGE_ANIMATED && cameraCancelableCallback != null) {
+ cameraCancelableCallback.onFinish();
+ cameraCancelableCallback = null;
+ mapView.removeOnMapChangedListener(this);
+ }
+ }
+ });
+ }
+
+ mapView.easeTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt, cameraPosition.zoom, easingInterpolator);
+ }
+
+ @UiThread
+ final void animateCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) {
+ cameraPosition = update.getCameraPosition(mapboxMap);
+ mapboxMap.getTrackingSettings().resetTrackingModesIfRequired(cameraPosition);
+
+ cancelTransitions();
+ if (callback != null) {
+ cameraCancelableCallback = callback;
+ mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
+ @Override
+ public void onMapChanged(@MapView.MapChange int change) {
+ if (change == REGION_DID_CHANGE_ANIMATED && cameraCancelableCallback != null) {
+ cameraCancelableCallback.onFinish();
+ cameraCancelableCallback = null;
+ mapView.removeOnMapChangedListener(this);
+ }
+ }
+ });
+ }
+
+ mapView.flyTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt, cameraPosition.zoom);
+ }
+
+ @UiThread
+ @Nullable
+ CameraPosition invalidateCameraPosition() {
+ CameraPosition cameraPosition = null;
+ if (mapView != null) {
+ cameraPosition = new CameraPosition.Builder(mapView.getCameraValues()).build();
+ this.cameraPosition = cameraPosition;
+ if (onCameraChangeListener != null) {
+ onCameraChangeListener.onCameraChange(this.cameraPosition);
+ }
+ }
+ return cameraPosition;
+ }
+
+ void cancelTransitions() {
+ if (cameraCancelableCallback != null) {
+ cameraCancelableCallback.onCancel();
+ cameraCancelableCallback = null;
+ }
+ mapView.cancelTransitions();
+ }
+
+ @UiThread
+ void resetNorth() {
+ cancelTransitions();
+ mapView.resetNorth();
+ }
+
+ void setOnCameraChangeListener(@Nullable MapboxMap.OnCameraChangeListener listener) {
+ this.onCameraChangeListener = listener;
+ }
+
+ private long getDurationNano(long durationMs) {
+ return durationMs > 0 ? TimeUnit.NANOSECONDS.convert(durationMs, TimeUnit.MILLISECONDS) : 0;
+ }
+}