summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java67
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java148
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java52
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java115
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java4
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java57
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java28
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java1
13 files changed, 396 insertions, 133 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 9b6706b90c..7e7947047e 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
@@ -100,6 +100,10 @@ class AnnotationManager {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
+ if (selectedMarkers.contains(marker)) {
+ selectedMarkers.remove(marker);
+ }
+
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
@@ -112,6 +116,10 @@ class AnnotationManager {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
+ if (selectedMarkers.contains(marker)) {
+ selectedMarkers.remove(marker);
+ }
+
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
@@ -124,6 +132,7 @@ class AnnotationManager {
Annotation annotation;
int count = annotationsArray.size();
long[] ids = new long[count];
+ selectedMarkers.clear();
for (int i = 0; i < count; i++) {
ids[i] = annotationsArray.keyAt(i);
annotation = annotationsArray.get(ids[i]);
@@ -383,12 +392,15 @@ class AnnotationManager {
for (Marker nearbyMarker : nearbyMarkers) {
for (Marker selectedMarker : selectedMarkers) {
if (nearbyMarker.equals(selectedMarker)) {
- if (onMarkerClickListener != null) {
- // end developer has provided a custom click listener
+ if (nearbyMarker instanceof MarkerView) {
+ handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) nearbyMarker);
+ } else if (onMarkerClickListener != null) {
handledDefaultClick = onMarkerClickListener.onMarkerClick(nearbyMarker);
- if (!handledDefaultClick) {
- deselectMarker(nearbyMarker);
- }
+ }
+
+ if (!handledDefaultClick) {
+ // only deselect marker if user didn't handle the click event themselves
+ deselectMarker(nearbyMarker);
}
return true;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
new file mode 100644
index 0000000000..bd028aecb6
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
@@ -0,0 +1,67 @@
+package com.mapbox.mapboxsdk.maps;
+
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveCanceledListener;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener;
+
+class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnCameraMoveListener,
+ MapboxMap.OnCameraMoveCanceledListener, OnCameraIdleListener {
+
+ private boolean idle = true;
+
+ private OnCameraMoveStartedListener onCameraMoveStartedListener;
+ private OnCameraMoveCanceledListener onCameraMoveCanceledListener;
+ private OnCameraMoveListener onCameraMoveListener;
+ private OnCameraIdleListener onCameraIdleListener;
+
+ void setOnCameraMoveStartedListener(OnCameraMoveStartedListener onCameraMoveStartedListener) {
+ this.onCameraMoveStartedListener = onCameraMoveStartedListener;
+ }
+
+ void setOnCameraMoveCanceledListener(OnCameraMoveCanceledListener onCameraMoveCanceledListener) {
+ this.onCameraMoveCanceledListener = onCameraMoveCanceledListener;
+ }
+
+ void setOnCameraMoveListener(OnCameraMoveListener onCameraMoveListener) {
+ this.onCameraMoveListener = onCameraMoveListener;
+ }
+
+ void setOnCameraIdleListener(OnCameraIdleListener onCameraIdleListener) {
+ this.onCameraIdleListener = onCameraIdleListener;
+ }
+
+ @Override
+ public void onCameraMoveStarted(int reason) {
+ if (!idle) {
+ return;
+ }
+
+ idle = false;
+ if (onCameraMoveStartedListener != null) {
+ onCameraMoveStartedListener.onCameraMoveStarted(reason);
+ }
+ }
+
+ @Override
+ public void onCameraMove() {
+ if (onCameraMoveListener != null && !idle) {
+ onCameraMoveListener.onCameraMove();
+ }
+ }
+
+ @Override
+ public void onCameraMoveCanceled() {
+ if (onCameraMoveCanceledListener != null && !idle) {
+ onCameraMoveCanceledListener.onCameraMoveCanceled();
+ }
+ }
+
+ @Override
+ public void onCameraIdle() {
+ if (onCameraIdleListener != null && !idle) {
+ idle = true;
+ onCameraIdleListener.onCameraIdle();
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java
index 006122a4e2..aec9a848b7 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java
@@ -2,6 +2,9 @@ package com.mapbox.mapboxsdk.maps;
import android.graphics.PointF;
+/**
+ * Interface definition of a callback that is invoked when the focal point will change.
+ */
public interface FocalPointChangeListener {
void onFocalPointChanged(PointF pointF);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
index c9d81a88bc..9f4171aee8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
@@ -1,15 +1,14 @@
package com.mapbox.mapboxsdk.maps;
import android.graphics.Bitmap;
-import android.util.DisplayMetrics;
+import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
@@ -41,118 +40,109 @@ class IconManager {
Icon loadIconForMarker(Marker marker) {
Icon icon = marker.getIcon();
-
- // calculating average before adding
- int iconSize = icons.size() + 1;
-
- // TODO replace former if case with anchor implementation,
- // current workaround for having extra pixels is diving height by 2
if (icon == null) {
- icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarker();
- Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() / 2 - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- marker.setIcon(icon);
- } else {
- Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- }
-
- if (!icons.contains(icon)) {
- icons.add(icon);
- loadIcon(icon);
+ // TODO replace with anchor implementation, we are faking an anchor by adding extra pixels and diving height by 2
+ // TODO we can move this code afterwards to getIcon as with MarkerView.getIcon
+ icon = loadDefaultIconForMarker(marker);
} else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
+ updateAverageIconSize(icon);
}
+ addIcon(icon);
return icon;
}
- Icon loadIconForMarkerView(MarkerView marker) {
+ void loadIconForMarkerView(MarkerView marker) {
Icon icon = marker.getIcon();
- int iconSize = icons.size() + 1;
- if (icon == null) {
- icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarkerView();
- marker.setIcon(icon);
- }
Bitmap bitmap = icon.getBitmap();
- averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize;
- if (!icons.contains(icon)) {
- icons.add(icon);
- } else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
- }
- return icon;
+ updateAverageIconSize(bitmap);
+ addIcon(icon, false);
}
int getTopOffsetPixelsForIcon(Icon icon) {
return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId()) * nativeMapView.getPixelRatio());
}
- void loadIcon(Icon icon) {
+ int getAverageIconHeight() {
+ return averageIconHeight;
+ }
+
+ int getAverageIconWidth() {
+ return averageIconWidth;
+ }
+
+ private Icon loadDefaultIconForMarker(Marker marker) {
+ Icon icon = IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarker();
Bitmap bitmap = icon.getBitmap();
- String id = icon.getId();
- if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
- bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
- }
- ByteBuffer buffer = ByteBuffer.allocate(bitmap.getRowBytes() * bitmap.getHeight());
- bitmap.copyPixelsToBuffer(buffer);
+ updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight() / 2);
+ marker.setIcon(icon);
+ return icon;
+ }
+
+ private void addIcon(Icon icon) {
+ addIcon(icon, true);
+ }
- float density = bitmap.getDensity();
- if (density == Bitmap.DENSITY_NONE) {
- density = DisplayMetrics.DENSITY_DEFAULT;
+ private void addIcon(Icon icon, boolean addIconToMap) {
+ if (!icons.contains(icon)) {
+ icons.add(icon);
+ if (addIconToMap) {
+ loadIcon(icon);
+ }
+ } else {
+ validateIconChanged(icon);
}
- float scale = density / DisplayMetrics.DENSITY_DEFAULT;
- nativeMapView.addAnnotationIcon(
- id,
+ }
+
+ private void updateAverageIconSize(Icon icon) {
+ updateAverageIconSize(icon.getBitmap());
+ }
+
+ private void updateAverageIconSize(Bitmap bitmap) {
+ updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight());
+ }
+
+ private void updateAverageIconSize(int width, int height) {
+ int iconSize = icons.size() + 1;
+ averageIconHeight = averageIconHeight + (height - averageIconHeight) / iconSize;
+ averageIconWidth = averageIconWidth + (width - averageIconWidth) / iconSize;
+ }
+
+ private void loadIcon(Icon icon) {
+ Bitmap bitmap = icon.getBitmap();
+ nativeMapView.addAnnotationIcon(icon.getId(),
bitmap.getWidth(),
bitmap.getHeight(),
- scale, buffer.array());
+ icon.getScale(),
+ icon.toBytes());
}
void reloadIcons() {
- int count = icons.size();
- for (int i = 0; i < count; i++) {
- Icon icon = icons.get(i);
+ for (Icon icon : icons) {
loadIcon(icon);
}
}
+ private void validateIconChanged(Icon icon) {
+ Icon oldIcon = icons.get(icons.indexOf(icon));
+ if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
+ throw new IconBitmapChangedException();
+ }
+ }
+
void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) {
Icon icon = marker.getIcon();
if (icon == null) {
- icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarker();
- marker.setIcon(icon);
- }
- if (!icons.contains(icon)) {
- icons.add(icon);
- loadIcon(icon);
- } else {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
+ icon = loadDefaultIconForMarker(marker);
}
+ addIcon(icon);
+ setTopOffsetPixels(marker, mapboxMap, icon);
+ }
+ private void setTopOffsetPixels(Marker marker, MapboxMap mapboxMap, Icon icon) {
// this seems to be a costly operation according to the profiler so I'm trying to save some calls
Marker previousMarker = marker.getId() != -1 ? (Marker) mapboxMap.getAnnotation(marker.getId()) : null;
if (previousMarker == null || previousMarker.getIcon() == null || previousMarker.getIcon() != marker.getIcon()) {
marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon));
}
}
-
- int getAverageIconHeight() {
- return averageIconHeight;
- }
-
- int getAverageIconWidth() {
- return averageIconWidth;
- }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
index 80fd6248bc..33e13c5ecc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
@@ -22,6 +22,8 @@ import com.mapbox.services.android.telemetry.MapboxTelemetry;
import com.mapbox.services.android.telemetry.utils.MathUtils;
import com.mapbox.services.android.telemetry.utils.TelemetryUtils;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE;
+
/**
* Manages gestures events on a MapView.
* <p>
@@ -35,6 +37,7 @@ final class MapGestureDetector {
private final UiSettings uiSettings;
private final TrackingSettings trackingSettings;
private final AnnotationManager annotationManager;
+ private final CameraChangeDispatcher cameraChangeDispatcher;
private final GestureDetectorCompat gestureDetector;
private final ScaleGestureDetector scaleGestureDetector;
@@ -56,12 +59,14 @@ final class MapGestureDetector {
private boolean scaleGestureOccurred = false;
MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings,
- TrackingSettings trackingSettings, AnnotationManager annotationManager) {
+ TrackingSettings trackingSettings, AnnotationManager annotationManager,
+ CameraChangeDispatcher cameraChangeDispatcher) {
this.annotationManager = annotationManager;
this.transform = transform;
this.projection = projection;
this.uiSettings = uiSettings;
this.trackingSettings = trackingSettings;
+ this.cameraChangeDispatcher = cameraChangeDispatcher;
// Touch gesture detectors
gestureDetector = new GestureDetectorCompat(context, new GestureListener());
@@ -187,6 +192,7 @@ final class MapGestureDetector {
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapDragEndEvent(
getLocationFromGesture(event.getX(), event.getY()), transform));
scrollInProgress = false;
+ cameraChangeDispatcher.onCameraIdle();
}
twoTap = false;
@@ -273,6 +279,9 @@ final class MapGestureDetector {
break;
}
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+
// Single finger double tap
if (focalPoint != null) {
// User provided focal point
@@ -337,6 +346,7 @@ final class MapGestureDetector {
// and ignore when a scale gesture has occurred
return false;
}
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
float screenDensity = uiSettings.getPixelRatio();
@@ -362,9 +372,7 @@ final class MapGestureDetector {
long animationTime = (long) (velocityXY / 7 / tiltFactor + MapboxConstants.ANIMATION_DURATION_FLING_BASE);
// update transformation
- transform.setGestureInProgress(true);
transform.moveBy(offsetX, offsetY, animationTime);
- transform.setGestureInProgress(false);
if (onFlingListener != null) {
onFlingListener.onFling();
@@ -375,12 +383,6 @@ final class MapGestureDetector {
// Called for drags
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- if (!scrollInProgress) {
- scrollInProgress = true;
- MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
- getLocationFromGesture(e1.getX(), e1.getY()),
- MapboxEvent.GESTURE_PAN_START, transform));
- }
if (!trackingSettings.isScrollGestureCurrentlyEnabled()) {
return false;
}
@@ -389,10 +391,19 @@ final class MapGestureDetector {
return false;
}
+ if (!scrollInProgress) {
+ scrollInProgress = true;
+
+ // Cancel any animation
+ transform.cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
+ getLocationFromGesture(e1.getX(), e1.getY()),
+ MapboxEvent.GESTURE_PAN_START, transform));
+ }
+
// reset tracking if needed
trackingSettings.resetTrackingModesIfRequired(true, false, false);
- // Cancel any animation
- transform.cancelTransitions();
// Scroll the map
transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/);
@@ -446,6 +457,8 @@ final class MapGestureDetector {
// If scale is large enough ignore a tap
scaleFactor *= detector.getScaleFactor();
if ((scaleFactor > 1.05f) || (scaleFactor < 0.95f)) {
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
zoomStarted = true;
}
@@ -465,9 +478,6 @@ final class MapGestureDetector {
return false;
}
- // Cancel any animation
- transform.cancelTransitions();
-
// Gesture is a quickzoom if there aren't two fingers
quickZoom = !twoTap;
@@ -512,6 +522,9 @@ final class MapGestureDetector {
return false;
}
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+
beginTime = detector.getEventTime();
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
@@ -522,6 +535,7 @@ final class MapGestureDetector {
// Called when the fingers leave the screen
@Override
public void onRotateEnd(RotateGestureDetector detector) {
+ // notify camera change listener
beginTime = 0;
totalAngle = 0.0f;
started = false;
@@ -553,13 +567,8 @@ final class MapGestureDetector {
if (!started) {
return false;
}
-
- // Cancel any animation
- transform.cancelTransitions();
-
// rotation constitutes translation of anything except the center of
// rotation, so cancel both location and bearing tracking if required
-
trackingSettings.resetTrackingModesIfRequired(true, true, false);
// Get rotate value
@@ -593,6 +602,8 @@ final class MapGestureDetector {
return false;
}
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
beginTime = detector.getEventTime();
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
@@ -633,9 +644,6 @@ final class MapGestureDetector {
return false;
}
- // Cancel any animation
- transform.cancelTransitions();
-
// Get tilt value (scale and clamp)
double pitch = transform.getTilt();
pitch -= 0.1 * detector.getShovePixelsDelta();
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 4f90b0a8fe..cf1841e180 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
@@ -131,6 +131,9 @@ public class MapView extends FrameLayout {
// callback for zooming in the camera
CameraZoomInvalidator zoomInvalidator = new CameraZoomInvalidator();
+ // callback for camera change events
+ CameraChangeDispatcher cameraChangeDispatcher = new CameraChangeDispatcher();
+
// setup components for MapboxMap creation
Projection proj = new Projection(nativeMapView);
UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, view.findViewById(R.id.logoView));
@@ -145,13 +148,14 @@ public class MapView extends FrameLayout {
Polylines polylines = new PolylineContainer(nativeMapView, annotationsArray);
AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, annotationsArray,
markerViewManager, iconManager, annotations, markers, polygons, polylines);
- Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings);
+ Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings,
+ cameraChangeDispatcher);
mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, proj,
- registerTouchListener, annotationManager);
+ registerTouchListener, annotationManager, cameraChangeDispatcher);
// user input
mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings,
- annotationManager);
+ annotationManager, cameraChangeDispatcher);
mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings);
MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform);
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 5f1ed0755c..f60ddf616a 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
@@ -41,6 +41,7 @@ import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.style.layers.Filter;
import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.light.Light;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.commons.geojson.Feature;
@@ -69,6 +70,7 @@ public final class MapboxMap {
private final Transform transform;
private final AnnotationManager annotationManager;
private final MyLocationViewSettings myLocationViewSettings;
+ private final CameraChangeDispatcher cameraChangeDispatcher;
private final OnRegisterTouchListener onRegisterTouchListener;
@@ -76,7 +78,7 @@ public final class MapboxMap {
MapboxMap(NativeMapView map, Transform transform, UiSettings ui, TrackingSettings tracking,
MyLocationViewSettings myLocationView, Projection projection, OnRegisterTouchListener listener,
- AnnotationManager annotations) {
+ AnnotationManager annotations, CameraChangeDispatcher cameraChangeDispatcher) {
this.nativeMapView = map;
this.uiSettings = ui;
this.trackingSettings = tracking;
@@ -85,6 +87,7 @@ public final class MapboxMap {
this.annotationManager = annotations.bind(this);
this.transform = transform;
this.onRegisterTouchListener = listener;
+ this.cameraChangeDispatcher = cameraChangeDispatcher;
}
void initialise(@NonNull Context context, @NonNull MapboxMapOptions options) {
@@ -566,6 +569,20 @@ public final class MapboxMap {
}
//
+ //
+ //
+
+ /**
+ * Get the global light source used to change lighting conditions on extruded fill layers.
+ *
+ * @return the global light source
+ */
+ @Nullable
+ public Light getLight() {
+ return nativeMapView.getLight();
+ }
+
+ //
// Camera API
//
@@ -1623,11 +1640,52 @@ public final class MapboxMap {
* To unset the callback, use null.
*/
@UiThread
+ @Deprecated
public void setOnCameraChangeListener(@Nullable OnCameraChangeListener listener) {
transform.setOnCameraChangeListener(listener);
}
/**
+ * Sets a callback that is invoked when camera movement has ended.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraIdleListener(@Nullable OnCameraIdleListener listener) {
+ cameraChangeDispatcher.setOnCameraIdleListener(listener);
+ }
+
+ /**
+ * Sets a callback that is invoked when camera movement was cancelled.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraMoveCancelListener(@Nullable OnCameraMoveCanceledListener listener) {
+ cameraChangeDispatcher.setOnCameraMoveCanceledListener(listener);
+ }
+
+ /**
+ * Sets a callback that is invoked when camera movement has started.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraMoveStartedistener(@Nullable OnCameraMoveStartedListener listener) {
+ cameraChangeDispatcher.setOnCameraMoveStartedListener(listener);
+ }
+
+ /**
+ * Sets a callback that is invoked when camera position changes.
+ *
+ * @param listener the listener to notify
+ */
+ @UiThread
+ public void setOnCameraMoveListener(@Nullable OnCameraMoveListener listener) {
+ cameraChangeDispatcher.setOnCameraMoveListener(listener);
+ }
+
+ /**
* Sets a callback that's invoked on every frame rendered to the map view.
*
* @param listener The callback that's invoked on every frame rendered to the map view.
@@ -1941,7 +1999,12 @@ public final class MapboxMap {
/**
* Interface definition for a callback to be invoked when the camera changes position.
+ *
+ * @deprecated Replaced by {@link MapboxMap.OnCameraMoveStartedListener}, {@link MapboxMap.OnCameraMoveListener} and
+ * {@link MapboxMap.OnCameraIdleListener}. The order in which the deprecated onCameraChange method will be called in
+ * relation to the methods in the new camera change listeners is undefined.
*/
+ @Deprecated
public interface OnCameraChangeListener {
/**
* Called after the camera position has changed. During an animation,
@@ -1954,6 +2017,56 @@ public final class MapboxMap {
}
/**
+ * Interface definition for a callback to be invoked for when the camera motion starts.
+ */
+ public interface OnCameraMoveStartedListener {
+ int REASON_API_GESTURE = 1;
+ int REASON_DEVELOPER_ANIMATION = 2;
+ int REASON_API_ANIMATION = 3;
+
+ /**
+ * Called when the camera starts moving after it has been idle or when the reason for camera motion has changed.
+ *
+ * @param reason the reason for the camera change
+ */
+ void onCameraMoveStarted(int reason);
+ }
+
+ /**
+ * Interface definition for a callback to be invoked for when the camera changes position.
+ */
+ public interface OnCameraMoveListener {
+ /**
+ * Called repeatedly as the camera continues to move after an onCameraMoveStarted call.
+ * This may be called as often as once every frame and should not perform expensive operations.
+ */
+ void onCameraMove();
+ }
+
+ /**
+ * Interface definition for a callback to be invoked for when the camera's motion has been stopped or when the camera
+ * starts moving for a new reason.
+ */
+ public interface OnCameraMoveCanceledListener {
+ /**
+ * Called when the developer explicitly calls the cancelTransitions() method or if the reason for camera motion has
+ * changed before the onCameraIdle had a chance to fire after the previous animation.
+ * Do not update or animate the camera from within this method.
+ */
+ void onCameraMoveCanceled();
+ }
+
+ /**
+ * Interface definition for a callback to be invoked for when camera movement has ended.
+ */
+ public interface OnCameraIdleListener {
+ /**
+ * Called when camera movement has ended.
+ */
+ void onCameraIdle();
+ }
+
+ /**
* Interface definition for a callback to be invoked when a frame is rendered to the map view.
*
* @see MapboxMap#setOnFpsChangedListener(OnFpsChangedListener)
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
index 68603ab1a3..98f94ddb39 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
@@ -36,7 +36,7 @@ import java.util.Arrays;
public class MapboxMapOptions implements Parcelable {
private static final float FOUR_DP = 4f;
- private static final float EIGHTY_NINE_DP = 92f;
+ private static final float NINETY_TWO_DP = 92f;
private CameraPosition cameraPosition;
@@ -241,7 +241,7 @@ public class MapboxMapOptions implements Parcelable {
R.styleable.mapbox_MapView_mapbox_uiAttributionGravity, Gravity.BOTTOM));
mapboxMapOptions.attributionMargins(new int[] {
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginLeft,
- EIGHTY_NINE_DP * pxlRatio)),
+ NINETY_TWO_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginTop,
FOUR_DP * pxlRatio)),
(int) (typedArray.getDimension(R.styleable.mapbox_MapView_mapbox_uiAttributionMarginRight,
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 ae4a8ee8d2..6d9df8aebd 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
@@ -27,6 +27,7 @@ import com.mapbox.mapboxsdk.storage.FileSource;
import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
import com.mapbox.mapboxsdk.style.layers.Filter;
import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.light.Light;
import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.commons.geojson.Feature;
@@ -617,7 +618,7 @@ final class NativeMapView {
if (isDestroyedOn("getMetersPerPixelAtLatitude")) {
return 0;
}
- return nativeGetMetersPerPixelAtLatitude(lat, getZoom());
+ return nativeGetMetersPerPixelAtLatitude(lat, getZoom()) / pixelRatio;
}
public ProjectedMeters projectedMetersForLatLng(LatLng latLng) {
@@ -882,12 +883,15 @@ final class NativeMapView {
fileSource.setApiBaseUrl(baseUrl);
}
- public float getPixelRatio() {
- return pixelRatio;
+ public Light getLight() {
+ if (isDestroyedOn("getLight")) {
+ return null;
+ }
+ return nativeGetLight();
}
- public Context getContext() {
- return mapView.getContext();
+ public float getPixelRatio() {
+ return pixelRatio;
}
//
@@ -1117,6 +1121,8 @@ final class NativeMapView {
String[] layerIds,
Object[] filter);
+ private native Light nativeGetLight();
+
int getWidth() {
if (isDestroyedOn("")) {
return 0;
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 09213934ae..7dcd84de75 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
@@ -282,8 +282,10 @@ public final class TrackingSettings {
*/
void resetTrackingModesIfRequired(CameraPosition currentCameraPosition, CameraPosition targetCameraPosition,
boolean isFromLocation) {
- resetTrackingModesIfRequired(!currentCameraPosition.target.equals(targetCameraPosition.target), false,
- isFromLocation);
+ if (currentCameraPosition.target != null) {
+ resetTrackingModesIfRequired(!currentCameraPosition.target.equals(targetCameraPosition.target), false,
+ isFromLocation);
+ }
}
Location getMyLocation() {
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
index 507bec270d..7f44e0de07 100644
--- 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
@@ -16,6 +16,7 @@ import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.maps.MapView.REGION_DID_CHANGE_ANIMATED;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
/**
* Resembles the current Map transformation.
@@ -33,13 +34,18 @@ final class Transform implements MapView.OnMapChangedListener {
private CameraPosition cameraPosition;
private MapboxMap.CancelableCallback cameraCancelableCallback;
+
private MapboxMap.OnCameraChangeListener onCameraChangeListener;
- Transform(NativeMapView mapView, MarkerViewManager markerViewManager, TrackingSettings trackingSettings) {
+ private CameraChangeDispatcher cameraChangeDispatcher;
+
+ Transform(NativeMapView mapView, MarkerViewManager markerViewManager, TrackingSettings trackingSettings,
+ CameraChangeDispatcher cameraChangeDispatcher) {
this.mapView = mapView;
this.markerViewManager = markerViewManager;
this.trackingSettings = trackingSettings;
this.myLocationView = trackingSettings.getMyLocationView();
+ this.cameraChangeDispatcher = cameraChangeDispatcher;
}
void initialise(@NonNull MapboxMap mapboxMap, @NonNull MapboxMapOptions options) {
@@ -79,6 +85,7 @@ final class Transform implements MapView.OnMapChangedListener {
cameraCancelableCallback.onFinish();
cameraCancelableCallback = null;
}
+ cameraChangeDispatcher.onCameraIdle();
mapView.removeOnMapChangedListener(this);
}
}
@@ -89,10 +96,12 @@ final class Transform implements MapView.OnMapChangedListener {
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false);
cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom);
if (callback != null) {
callback.onFinish();
}
+ cameraChangeDispatcher.onCameraIdle();
}
}
@@ -103,6 +112,8 @@ final class Transform implements MapView.OnMapChangedListener {
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, isDismissable);
cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
+
if (callback != null) {
cameraCancelableCallback = callback;
mapView.addOnMapChangedListener(this);
@@ -118,8 +129,9 @@ final class Transform implements MapView.OnMapChangedListener {
CameraPosition cameraPosition = update.getCameraPosition(mapboxMap);
if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false);
-
cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
+
if (callback != null) {
cameraCancelableCallback = callback;
mapView.addOnMapChangedListener(this);
@@ -134,7 +146,12 @@ final class Transform implements MapView.OnMapChangedListener {
@Nullable
CameraPosition invalidateCameraPosition() {
if (mapView != null) {
- cameraPosition = mapView.getCameraPosition();
+ CameraPosition cameraPosition = mapView.getCameraPosition();
+ if (this.cameraPosition != null && !this.cameraPosition.equals(cameraPosition)) {
+ cameraChangeDispatcher.onCameraMove();
+ }
+
+ this.cameraPosition = cameraPosition;
if (onCameraChangeListener != null) {
onCameraChangeListener.onCameraChange(this.cameraPosition);
}
@@ -143,10 +160,17 @@ final class Transform implements MapView.OnMapChangedListener {
}
void cancelTransitions() {
+ // notify user about cancel
+ cameraChangeDispatcher.onCameraMoveCanceled();
+
+ // notify animateCamera and easeCamera about cancelling
if (cameraCancelableCallback != null) {
+ cameraChangeDispatcher.onCameraIdle();
cameraCancelableCallback.onCancel();
cameraCancelableCallback = null;
}
+
+ // cancel ongoing transitions
mapView.cancelTransitions();
}
@@ -156,6 +180,10 @@ final class Transform implements MapView.OnMapChangedListener {
mapView.resetNorth();
}
+ //
+ // Camera change listener API
+ //
+
void setOnCameraChangeListener(@Nullable MapboxMap.OnCameraChangeListener listener) {
this.onCameraChangeListener = listener;
}
@@ -171,9 +199,6 @@ final class Transform implements MapView.OnMapChangedListener {
}
void zoom(boolean zoomIn, @NonNull PointF focalPoint) {
- // Cancel any animation
- cancelTransitions();
-
CameraPosition cameraPosition = invalidateCameraPosition();
if (cameraPosition != null) {
int newZoom = (int) Math.round(cameraPosition.zoom + (zoomIn ? 1 : -1));
@@ -186,6 +211,15 @@ final class Transform implements MapView.OnMapChangedListener {
}
void setZoom(double zoom, @NonNull PointF focalPoint, long duration) {
+ mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
+ @Override
+ public void onMapChanged(int change) {
+ if (change == MapView.REGION_DID_CHANGE_ANIMATED) {
+ mapView.removeOnMapChangedListener(this);
+ cameraChangeDispatcher.onCameraIdle();
+ }
+ }
+ });
mapView.setZoom(zoom, focalPoint, duration);
}
@@ -277,6 +311,17 @@ final class Transform implements MapView.OnMapChangedListener {
}
void moveBy(double offsetX, double offsetY, long duration) {
+ if (duration > 0) {
+ mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
+ @Override
+ public void onMapChanged(int change) {
+ if (change == MapView.DID_FINISH_RENDERING_MAP_FULLY_RENDERED) {
+ mapView.removeOnMapChangedListener(this);
+ cameraChangeDispatcher.onCameraIdle();
+ }
+ }
+ });
+ }
mapView.moveBy(offsetX, offsetY, duration);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
index 1bcf8a70b9..5f7b6c571b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
@@ -193,12 +193,16 @@ public final class UiSettings {
private void initialiseLogo(MapboxMapOptions options, Resources resources) {
setLogoEnabled(options.getLogoEnabled());
setLogoGravity(options.getLogoGravity());
- int[] logoMargins = options.getLogoMargins();
+ setLogoMargins(resources, options.getLogoMargins());
+ }
+
+ private void setLogoMargins(Resources resources, int[] logoMargins) {
if (logoMargins != null) {
setLogoMargins(logoMargins[0], logoMargins[1], logoMargins[2], logoMargins[3]);
} else {
- int twoDp = (int) resources.getDimension(R.dimen.mapbox_two_dp);
- setLogoMargins(twoDp, twoDp, twoDp, twoDp);
+ // user did not specify margins when programmatically creating a map
+ int fourDp = (int) resources.getDimension(R.dimen.mapbox_four_dp);
+ setLogoMargins(fourDp, fourDp, fourDp, fourDp);
}
}
@@ -223,15 +227,23 @@ public final class UiSettings {
private void initialiseAttribution(Context context, MapboxMapOptions options) {
setAttributionEnabled(options.getAttributionEnabled());
setAttributionGravity(options.getAttributionGravity());
- int[] attributionMargins = options.getAttributionMargins();
+ setAttributionMargins(context, options.getAttributionMargins());
+ int attributionTintColor = options.getAttributionTintColor();
+ setAttributionTintColor(attributionTintColor != -1
+ ? attributionTintColor : ColorUtils.getPrimaryColor(context));
+ }
+
+ private void setAttributionMargins(Context context, int[] attributionMargins) {
if (attributionMargins != null) {
setAttributionMargins(attributionMargins[0], attributionMargins[1],
attributionMargins[2], attributionMargins[3]);
+ } else {
+ // user did not specify margins when programmatically creating a map
+ Resources resources = context.getResources();
+ int margin = (int) resources.getDimension(R.dimen.mapbox_four_dp);
+ int leftMargin = (int) resources.getDimension(R.dimen.mapbox_ninety_two_dp);
+ setAttributionMargins(leftMargin, margin, margin, margin);
}
-
- int attributionTintColor = options.getAttributionTintColor();
- setAttributionTintColor(attributionTintColor != -1
- ? attributionTintColor : ColorUtils.getPrimaryColor(context));
}
private void saveAttribution(Bundle outState) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
index db2a335453..f5ef46a5d3 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
@@ -440,6 +440,7 @@ public class MyLocationView extends View {
} else {
// Disable location and user dot
location = null;
+ locationSource.removeLocationUpdates();
locationSource.removeLocationEngineListener(userLocationListener);
locationSource.deactivate();
}