summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK
diff options
context:
space:
mode:
authorTobrun <tobrun.van.nuland@gmail.com>2016-11-23 10:53:39 +0100
committerGitHub <noreply@github.com>2016-11-23 10:53:39 +0100
commitedb487b74d800d46f04b27dd7610a028720de79a (patch)
tree9c505790a26cc01ba3a8bc4c3565b824bcf8979e /platform/android/MapboxGLAndroidSDK
parent4577c56745d90cfa00837d00e5e5605260a54879 (diff)
downloadqtlocation-mapboxgl-edb487b74d800d46f04b27dd7610a028720de79a.tar.gz
[android] - move camera logic to dedicated transform class (#6919)
* [android] - move camera logic to dedicated transform class post camera updates to the message queue, this makes calling an new camera update in the on finish of another update possible. Simplify transform.java implementation. * fail the step if instrumentation tests fail, fixup typo
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK')
-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;
+ }
+}