6067 annotation manager (#6913)

* [android] - AnnotationManager and InfoWindowManager refactor

* make AnnotationManager independent from MapView/MapboxMap, add IconManager,

* make code unit testable

* added some class level documentation (for internal use)
This commit is contained in:
Tobrun
2016-11-07 17:23:51 +01:00
committed by GitHub
parent 5412191ab4
commit 1f8f85fab3
8 changed files with 942 additions and 765 deletions

View File

@@ -400,7 +400,7 @@ public class MarkerViewManager {
*/
public void invalidateViewMarkersInVisibleRegion() {
RectF mapViewRect = new RectF(0, 0, mapView.getWidth(), mapView.getHeight());
List<MarkerView> markers = mapView.getMarkerViewsInRect(mapViewRect);
List<MarkerView> markers = mapboxMap.getMarkerViewsInRect(mapViewRect);
View convertView;
// remove old markers

View File

@@ -0,0 +1,576 @@
package com.mapbox.mapboxsdk.maps;
import android.graphics.RectF;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import java.util.ArrayList;
import java.util.List;
/**
* Responsible for managing and tracking state of Annotations linked to Map. All events related to
* annotations that occur on {@link MapboxMap} are forwarded to this class.
* <p>
* Responsible for referencing {@link InfoWindowManager} and {@link MarkerViewManager}.
* </p>
* <p>
* Exposes convenience methods to add/remove/update all subtypes of annotations found in com.mapbox.mapboxsdk.annotations.
* </p>
*/
class AnnotationManager {
private NativeMapView nativeMapView;
private IconManager iconManager;
private InfoWindowManager infoWindowManager;
private MarkerViewManager markerViewManager;
private LongSparseArray<Annotation> annotations;
private List<Marker> selectedMarkers;
private MapboxMap.OnMarkerClickListener onMarkerClickListener;
AnnotationManager(NativeMapView view, IconManager iconManager, InfoWindowManager manager) {
this.nativeMapView = view;
this.iconManager = iconManager;
this.infoWindowManager = manager;
this.selectedMarkers = new ArrayList<>();
this.annotations = new LongSparseArray<>();
}
//
// Annotations
//
Annotation getAnnotation(long id) {
return annotations.get(id);
}
List<Annotation> getAnnotations() {
List<Annotation> annotations = new ArrayList<>();
for (int i = 0; i < this.annotations.size(); i++) {
annotations.add(this.annotations.get(this.annotations.keyAt(i)));
}
return annotations;
}
void removeAnnotation(@NonNull Annotation annotation) {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
}
long id = annotation.getId();
if (nativeMapView != null) {
nativeMapView.removeAnnotation(id);
}
annotations.remove(id);
}
void removeAnnotation(long id) {
if (nativeMapView != null) {
nativeMapView.removeAnnotation(id);
}
annotations.remove(id);
}
void removeAnnotations(@NonNull List<? extends Annotation> annotationList) {
int count = annotationList.size();
long[] ids = new long[count];
for (int i = 0; i < count; i++) {
Annotation annotation = annotationList.get(i);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
}
ids[i] = annotationList.get(i).getId();
}
if (nativeMapView != null) {
nativeMapView.removeAnnotations(ids);
}
for (long id : ids) {
annotations.remove(id);
}
}
void removeAnnotations() {
Annotation annotation;
int count = annotations.size();
long[] ids = new long[count];
for (int i = 0; i < count; i++) {
ids[i] = annotations.keyAt(i);
annotation = annotations.get(ids[i]);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
}
}
if (nativeMapView != null) {
nativeMapView.removeAnnotations(ids);
}
annotations.clear();
}
//
// Markers
//
Marker addMarker(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap) {
Marker marker = prepareMarker(markerOptions);
long id = nativeMapView != null ? nativeMapView.addMarker(marker) : 0;
marker.setMapboxMap(mapboxMap);
marker.setId(id);
annotations.put(id, marker);
return marker;
}
List<Marker> addMarkers(@NonNull List<? extends BaseMarkerOptions> markerOptionsList, @NonNull MapboxMap mapboxMap) {
int count = markerOptionsList.size();
List<Marker> markers = new ArrayList<>(count);
if (count > 0) {
BaseMarkerOptions markerOptions;
Marker marker;
for (int i = 0; i < count; i++) {
markerOptions = markerOptionsList.get(i);
marker = prepareMarker(markerOptions);
markers.add(marker);
}
if (markers.size() > 0) {
long[] ids = null;
if (nativeMapView != null) {
ids = nativeMapView.addMarkers(markers);
}
long id = 0;
Marker m;
for (int i = 0; i < markers.size(); i++) {
m = markers.get(i);
m.setMapboxMap(mapboxMap);
if (ids != null) {
id = ids[i];
} else {
//unit test
id++;
}
m.setId(id);
annotations.put(id, m);
}
}
}
return markers;
}
private Marker prepareMarker(BaseMarkerOptions markerOptions) {
Marker marker = markerOptions.getMarker();
Icon icon = iconManager.loadIconForMarker(marker);
marker.setTopOffsetPixels(iconManager.getTopOffsetPixelsForIcon(icon));
return marker;
}
MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap) {
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) {
MarkerView marker = prepareViewMarker(markerViewOption);
marker.setMapboxMap(mapboxMap);
long id = nativeMapView.addMarker(marker);
marker.setId(id);
annotations.put(id, marker);
markers.add(marker);
}
markerViewManager.invalidateViewMarkersInVisibleRegion();
return markers;
}
private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) {
MarkerView marker = markerViewOptions.getMarker();
iconManager.loadIconForMarkerView(marker);
return marker;
}
void updateMarker(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) {
if (updatedMarker == null) {
return;
}
if (updatedMarker.getId() == -1) {
return;
}
if (!(updatedMarker instanceof MarkerView)) {
iconManager.ensureIconLoaded(updatedMarker, mapboxMap);
}
nativeMapView.updateMarker(updatedMarker);
int index = annotations.indexOfKey(updatedMarker.getId());
if (index > -1) {
annotations.setValueAt(index, updatedMarker);
}
}
List<Marker> getMarkers() {
List<Marker> markers = new ArrayList<>();
Annotation annotation;
for (int i = 0; i < annotations.size(); i++) {
annotation = annotations.get(annotations.keyAt(i));
if (annotation instanceof Marker) {
markers.add((Marker) annotation);
}
}
return markers;
}
void setOnMarkerClickListener(@Nullable MapboxMap.OnMarkerClickListener listener) {
onMarkerClickListener = listener;
}
void selectMarker(@NonNull Marker marker, @NonNull MapboxMap mapboxMap) {
if (selectedMarkers.contains(marker)) {
return;
}
// Need to deselect any currently selected annotation first
if (!infoWindowManager.isAllowConcurrentMultipleOpenInfoWindows()) {
deselectMarkers();
}
boolean handledDefaultClick = false;
if (onMarkerClickListener != null) {
// end developer has provided a custom click listener
handledDefaultClick = onMarkerClickListener.onMarkerClick(marker);
}
if (!handledDefaultClick) {
if (marker instanceof MarkerView) {
markerViewManager.select((MarkerView) marker, false);
markerViewManager.ensureInfoWindowOffset((MarkerView) marker);
}
if (infoWindowManager.isInfoWindowValidForMarker(marker) || infoWindowManager.getInfoWindowAdapter() != null) {
infoWindowManager.getInfoWindows().add(marker.showInfoWindow(mapboxMap, mapboxMap.getMapView()));
}
}
selectedMarkers.add(marker);
}
void deselectMarkers() {
if (selectedMarkers.isEmpty()) {
return;
}
for (Marker marker : selectedMarkers) {
if (marker.isInfoWindowShown()) {
marker.hideInfoWindow();
}
if (marker instanceof MarkerView) {
markerViewManager.deselect((MarkerView) marker, false);
}
}
// Removes all selected markers from the list
selectedMarkers.clear();
}
void deselectMarker(@NonNull Marker marker) {
if (!selectedMarkers.contains(marker)) {
return;
}
if (marker.isInfoWindowShown()) {
marker.hideInfoWindow();
}
if (marker instanceof MarkerView) {
markerViewManager.deselect((MarkerView) marker, false);
}
selectedMarkers.remove(marker);
}
List<Marker> getSelectedMarkers() {
return selectedMarkers;
}
public List<Marker> getMarkersInRect(@NonNull RectF rect) {
long[] ids = nativeMapView.queryPointAnnotations(rect);
List<Long> idsList = new ArrayList<>(ids.length);
for (long id : ids) {
idsList.add(id);
}
List<Marker> annotations = new ArrayList<>(ids.length);
List<Annotation> annotationList = getAnnotations();
int count = annotationList.size();
for (int i = 0; i < count; i++) {
Annotation annotation = annotationList.get(i);
if (annotation instanceof com.mapbox.mapboxsdk.annotations.Marker && idsList.contains(annotation.getId())) {
annotations.add((com.mapbox.mapboxsdk.annotations.Marker) annotation);
}
}
return new ArrayList<>(annotations);
}
public List<MarkerView> getMarkerViewsInRect(@NonNull RectF rect) {
long[] ids = nativeMapView.queryPointAnnotations(rect);
List<Long> idsList = new ArrayList<>(ids.length);
for (long id : ids) {
idsList.add(id);
}
List<MarkerView> annotations = new ArrayList<>(ids.length);
List<Annotation> annotationList = getAnnotations();
int count = annotationList.size();
for (int i = 0; i < count; i++) {
Annotation annotation = annotationList.get(i);
if (annotation instanceof MarkerView) {
annotations.add((MarkerView) annotation);
}
}
return new ArrayList<>(annotations);
}
//
// Polygons
//
Polygon addPolygon(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) {
Polygon polygon = polygonOptions.getPolygon();
if (!polygon.getPoints().isEmpty()) {
long id = nativeMapView != null ? nativeMapView.addPolygon(polygon) : 0;
polygon.setId(id);
polygon.setMapboxMap(mapboxMap);
annotations.put(id, polygon);
}
return polygon;
}
List<Polygon> addPolygons(@NonNull List<PolygonOptions> polygonOptionsList, @NonNull MapboxMap mapboxMap) {
int count = polygonOptionsList.size();
Polygon polygon;
List<Polygon> polygons = new ArrayList<>(count);
if (count > 0) {
for (PolygonOptions polygonOptions : polygonOptionsList) {
polygon = polygonOptions.getPolygon();
if (!polygon.getPoints().isEmpty()) {
polygons.add(polygon);
}
}
long[] ids = null;
if (nativeMapView != null) {
ids = nativeMapView.addPolygons(polygons);
}
long id = 0;
for (int i = 0; i < polygons.size(); i++) {
polygon = polygons.get(i);
polygon.setMapboxMap(mapboxMap);
if (ids != null) {
id = ids[i];
} else {
// unit test
id++;
}
polygon.setId(id);
annotations.put(id, polygon);
}
}
return polygons;
}
void updatePolygon(Polygon polygon) {
if (polygon == null) {
return;
}
if (polygon.getId() == -1) {
return;
}
nativeMapView.updatePolygon(polygon);
int index = annotations.indexOfKey(polygon.getId());
if (index > -1) {
annotations.setValueAt(index, polygon);
}
}
List<Polygon> getPolygons() {
List<Polygon> polygons = new ArrayList<>();
Annotation annotation;
for (int i = 0; i < annotations.size(); i++) {
annotation = annotations.get(annotations.keyAt(i));
if (annotation instanceof Polygon) {
polygons.add((Polygon) annotation);
}
}
return polygons;
}
//
// Polylines
//
Polyline addPolyline(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) {
Polyline polyline = polylineOptions.getPolyline();
if (!polyline.getPoints().isEmpty()) {
long id = nativeMapView != null ? nativeMapView.addPolyline(polyline) : 0;
polyline.setMapboxMap(mapboxMap);
polyline.setId(id);
annotations.put(id, polyline);
}
return polyline;
}
List<Polyline> addPolylines(@NonNull List<PolylineOptions> polylineOptionsList, @NonNull MapboxMap mapboxMap) {
int count = polylineOptionsList.size();
Polyline polyline;
List<Polyline> polylines = new ArrayList<>(count);
if (count > 0) {
for (PolylineOptions options : polylineOptionsList) {
polyline = options.getPolyline();
if (!polyline.getPoints().isEmpty()) {
polylines.add(polyline);
}
}
long[] ids = null;
if (nativeMapView != null) {
ids = nativeMapView.addPolylines(polylines);
}
long id = 0;
Polyline p;
for (int i = 0; i < polylines.size(); i++) {
p = polylines.get(i);
p.setMapboxMap(mapboxMap);
if (ids != null) {
id = ids[i];
} else {
// unit test
id++;
}
p.setId(id);
annotations.put(id, p);
}
}
return polylines;
}
void updatePolyline(Polyline polyline) {
if (polyline == null) {
return;
}
if (polyline.getId() == -1) {
return;
}
nativeMapView.updatePolyline(polyline);
int index = annotations.indexOfKey(polyline.getId());
if (index > -1) {
annotations.setValueAt(index, polyline);
}
}
List<Polyline> getPolylines() {
List<Polyline> polylines = new ArrayList<>();
Annotation annotation;
for (int i = 0; i < annotations.size(); i++) {
annotation = annotations.get(annotations.keyAt(i));
if (annotation instanceof Polyline) {
polylines.add((Polyline) annotation);
}
}
return polylines;
}
//
// MarkerViewManager
//
MarkerViewManager getMarkerViewManager(MapboxMap mapboxMap) {
if (markerViewManager == null) {
this.markerViewManager = new MarkerViewManager(mapboxMap, mapboxMap.getMapView());
}
return markerViewManager;
}
void adjustTopOffsetPixels(MapboxMap mapboxMap) {
int count = annotations.size();
for (int i = 0; i < count; i++) {
Annotation annotation = annotations.get(i);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.setTopOffsetPixels(
iconManager.getTopOffsetPixelsForIcon(marker.getIcon()));
}
}
for (Marker marker : selectedMarkers) {
if (marker.isInfoWindowShown()) {
marker.hideInfoWindow();
marker.showInfoWindow(mapboxMap, mapboxMap.getMapView());
}
}
}
void reloadMarkers() {
int count = annotations.size();
for (int i = 0; i < count; i++) {
Annotation annotation = annotations.get(i);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
nativeMapView.removeAnnotation(annotation.getId());
long newId = nativeMapView.addMarker(marker);
marker.setId(newId);
}
}
}
}

View File

@@ -0,0 +1,158 @@
package com.mapbox.mapboxsdk.maps;
import android.graphics.Bitmap;
import android.util.DisplayMetrics;
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;
/**
* Responsible for managing icons added to the Map.
* <p>
* Maintains a {@link List} of {@link Icon} and is responsible for initialising default markers and
* setting up {@link MarkerView} annotation ghosting.
* </p>
* <p>
* Keep track of icons added and the resulting average icon size. This is used internally by our
* gestures detection to calculate the size of a touch target.
* </p>
*/
class IconManager {
private NativeMapView nativeMapView;
private List<Icon> icons;
private int averageIconHeight;
private int averageIconWidth;
IconManager(NativeMapView nativeMapView) {
this.nativeMapView = nativeMapView;
this.icons = new ArrayList<>();
// load transparent icon for MarkerView to trace actual markers, see #6352
loadIcon(IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, IconFactory.ICON_MARKERVIEW_BITMAP));
}
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);
} else {
Icon oldIcon = icons.get(icons.indexOf(icon));
if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
throw new IconBitmapChangedException();
}
}
return icon;
}
Icon 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;
}
int getTopOffsetPixelsForIcon(Icon icon) {
return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId()) * nativeMapView.getPixelRatio());
}
void loadIcon(Icon icon) {
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);
float density = bitmap.getDensity();
if (density == Bitmap.DENSITY_NONE) {
density = DisplayMetrics.DENSITY_DEFAULT;
}
float scale = density / DisplayMetrics.DENSITY_DEFAULT;
nativeMapView.addAnnotationIcon(
id,
bitmap.getWidth(),
bitmap.getHeight(),
scale, buffer.array());
}
void reloadIcons() {
int count = icons.size();
for (int i = 0; i < count; i++) {
Icon icon = icons.get(i);
loadIcon(icon);
}
}
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();
}
}
// 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;
}
}

View File

@@ -0,0 +1,83 @@
package com.mapbox.mapboxsdk.maps;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.mapbox.mapboxsdk.annotations.InfoWindow;
import com.mapbox.mapboxsdk.annotations.Marker;
import java.util.ArrayList;
import java.util.List;
/**
* Responsible for managing InfoWindows shown on the Map.
* <p>
* Maintains a {@link List} of opened {@link InfoWindow} and tracks configurations as
* allowConcurrentMultipleInfoWindows which allows to have multiple {@link InfoWindow} open at the
* same time. Responsible for managing listeners as {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnInfoWindowClickListener}
* and {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnInfoWindowLongClickListener}.
* </p>
*/
class InfoWindowManager {
private List<InfoWindow> infoWindows;
private MapboxMap.InfoWindowAdapter infoWindowAdapter;
private boolean allowConcurrentMultipleInfoWindows;
private MapboxMap.OnInfoWindowClickListener onInfoWindowClickListener;
private MapboxMap.OnInfoWindowLongClickListener onInfoWindowLongClickListener;
private MapboxMap.OnInfoWindowCloseListener onInfoWindowCloseListener;
InfoWindowManager() {
this.infoWindows = new ArrayList<>();
}
void setInfoWindowAdapter(@Nullable MapboxMap.InfoWindowAdapter infoWindowAdapter) {
this.infoWindowAdapter = infoWindowAdapter;
}
MapboxMap.InfoWindowAdapter getInfoWindowAdapter() {
return infoWindowAdapter;
}
void setAllowConcurrentMultipleOpenInfoWindows(boolean allow) {
allowConcurrentMultipleInfoWindows = allow;
}
boolean isAllowConcurrentMultipleOpenInfoWindows() {
return allowConcurrentMultipleInfoWindows;
}
List<InfoWindow> getInfoWindows() {
return infoWindows;
}
boolean isInfoWindowValidForMarker(@NonNull Marker marker) {
return !TextUtils.isEmpty(marker.getTitle()) || !TextUtils.isEmpty(marker.getSnippet());
}
void setOnInfoWindowClickListener(@Nullable MapboxMap.OnInfoWindowClickListener listener) {
onInfoWindowClickListener = listener;
}
MapboxMap.OnInfoWindowClickListener getOnInfoWindowClickListener() {
return onInfoWindowClickListener;
}
void setOnInfoWindowLongClickListener(@Nullable MapboxMap.OnInfoWindowLongClickListener listener) {
onInfoWindowLongClickListener = listener;
}
MapboxMap.OnInfoWindowLongClickListener getOnInfoWindowLongClickListener() {
return onInfoWindowLongClickListener;
}
void setOnInfoWindowCloseListener(@Nullable MapboxMap.OnInfoWindowCloseListener listener) {
onInfoWindowCloseListener = listener;
}
MapboxMap.OnInfoWindowCloseListener getOnInfoWindowCloseListener() {
return onInfoWindowCloseListener;
}
}

View File

@@ -35,7 +35,6 @@ import android.support.v4.view.ScaleGestureDetectorCompat;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.InputDevice;
@@ -61,20 +60,15 @@ import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector;
import com.mapbox.mapboxsdk.MapboxAccountManager;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.InfoWindow;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.location.LocationListener;
import com.mapbox.mapboxsdk.location.LocationServices;
@@ -87,7 +81,6 @@ import com.mapbox.mapboxsdk.utils.ColorUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
@@ -112,13 +105,12 @@ import java.util.concurrent.CopyOnWriteArrayList;
public class MapView extends FrameLayout {
private MapboxMap mapboxMap;
private IconManager iconManager;
private AnnotationManager annotationManager;
private boolean initialLoad;
private boolean destroyed;
private List<Icon> icons;
private int averageIconHeight;
private int averageIconWidth;
private NativeMapView nativeMapView;
private boolean hasSurface = false;
@@ -197,10 +189,7 @@ public class MapView extends FrameLayout {
initialLoad = true;
onMapReadyCallbackList = new ArrayList<>();
onMapChangedListener = new CopyOnWriteArrayList<>();
mapboxMap = new MapboxMap(this);
projection = mapboxMap.getProjection();
icons = new ArrayList<>();
View view = LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_internal, this);
setWillNotDraw(false);
@@ -215,9 +204,10 @@ public class MapView extends FrameLayout {
}
nativeMapView = new NativeMapView(this);
// load transparent icon for MarkerView to trace actual markers, see #6352
loadIcon(IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, IconFactory.ICON_MARKERVIEW_BITMAP));
iconManager = new IconManager(nativeMapView);
mapboxMap = new MapboxMap(this, iconManager);
annotationManager = mapboxMap.getAnnotationManager();
projection = mapboxMap.getProjection();
// Ensure this view is interactable
setClickable(true);
@@ -474,9 +464,9 @@ public class MapView extends FrameLayout {
public void onMapChanged(@MapChange int change) {
if (change == DID_FINISH_LOADING_STYLE && initialLoad) {
initialLoad = false;
reloadIcons();
reloadMarkers();
adjustTopOffsetPixels();
iconManager.reloadIcons();
annotationManager.reloadMarkers();
annotationManager.adjustTopOffsetPixels(mapboxMap);
// Notify listeners the map is ready
if (onMapReadyCallbackList.size() > 0) {
@@ -649,7 +639,7 @@ public class MapView extends FrameLayout {
nativeMapView.destroy();
nativeMapView = null;
}
void setFocalPoint(PointF focalPoint) {
if (focalPoint == null) {
// resetting focal point,
@@ -775,14 +765,6 @@ public class MapView extends FrameLayout {
return contentPaddingBottom;
}
int getContentWidth() {
return getWidth() - contentPaddingLeft - contentPaddingRight;
}
int getContentHeight() {
return getHeight() - contentPaddingBottom - contentPaddingTop;
}
//
// Zoom
//
@@ -846,10 +828,7 @@ public class MapView extends FrameLayout {
//
boolean isDebugActive() {
if (destroyed) {
return false;
}
return nativeMapView.getDebug();
return !destroyed && nativeMapView.getDebug();
}
void setDebugActive(boolean debugActive) {
@@ -1034,282 +1013,6 @@ public class MapView extends FrameLayout {
return nativeMapView.pixelForLatLng(location);
}
//
// Annotations
//
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(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);
} else {
Icon oldIcon = icons.get(icons.indexOf(icon));
if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
throw new IconBitmapChangedException();
}
}
return icon;
}
Icon loadIconForMarkerView(MarkerView marker) {
Icon icon = marker.getIcon();
int iconSize = icons.size() + 1;
if (icon == null) {
icon = IconFactory.getInstance(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;
}
void loadIcon(Icon icon) {
if (destroyed) {
return;
}
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);
float density = bitmap.getDensity();
if (density == Bitmap.DENSITY_NONE) {
density = DisplayMetrics.DENSITY_DEFAULT;
}
float scale = density / DisplayMetrics.DENSITY_DEFAULT;
nativeMapView.addAnnotationIcon(
id,
bitmap.getWidth(),
bitmap.getHeight(),
scale, buffer.array());
}
void reloadIcons() {
int count = icons.size();
for (int i = 0; i < count; i++) {
Icon icon = icons.get(i);
loadIcon(icon);
}
}
void updateMarker(@NonNull Marker updatedMarker) {
if (destroyed) {
return;
}
if (updatedMarker == null) {
Log.w(MapboxConstants.TAG, "marker was null, doing nothing");
return;
}
if (updatedMarker.getId() == -1) {
Log.w(MapboxConstants.TAG, "marker has an id of -1, possibly was not added yet, doing nothing");
return;
}
if (!(updatedMarker instanceof MarkerView)) {
ensureIconLoaded(updatedMarker);
}
nativeMapView.updateMarker(updatedMarker);
}
void updatePolygon(Polygon polygon) {
if (destroyed) {
return;
}
if (polygon == null) {
Log.w(MapboxConstants.TAG, "polygon was null, doing nothing");
return;
}
if (polygon.getId() == -1) {
Log.w(MapboxConstants.TAG, "polygon has an id of -1, indicating the polygon was not added to the map yet.");
return;
}
nativeMapView.updatePolygon(polygon);
}
void updatePolyline(Polyline polyline) {
if (destroyed) {
return;
}
if (polyline == null) {
Log.w(MapboxConstants.TAG, "polygon was null, doing nothing");
return;
}
if (polyline.getId() == -1) {
Log.w(MapboxConstants.TAG, "polygon has an id of -1, indicating the polygon was not added to the map yet.");
return;
}
nativeMapView.updatePolyline(polyline);
}
private void ensureIconLoaded(Marker marker) {
Icon icon = marker.getIcon();
if (icon == null) {
icon = IconFactory.getInstance(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();
}
}
// 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));
}
}
long addMarker(@NonNull Marker marker) {
if (destroyed) {
return 0L;
}
return nativeMapView.addMarker(marker);
}
long[] addMarkers(@NonNull List<Marker> markerList) {
if (destroyed) {
return new long[]{};
}
return nativeMapView.addMarkers(markerList);
}
long addPolyline(@NonNull Polyline polyline) {
if (destroyed) {
return 0L;
}
return nativeMapView.addPolyline(polyline);
}
long[] addPolylines(@NonNull List<Polyline> polylines) {
if (destroyed) {
return new long[]{};
}
return nativeMapView.addPolylines(polylines);
}
long addPolygon(@NonNull Polygon polygon) {
if (destroyed) {
return 0L;
}
return nativeMapView.addPolygon(polygon);
}
long[] addPolygons(@NonNull List<Polygon> polygons) {
if (destroyed) {
return new long[]{};
}
return nativeMapView.addPolygons(polygons);
}
void removeAnnotation(long id) {
if (destroyed) {
return;
}
nativeMapView.removeAnnotation(id);
}
void removeAnnotations(@NonNull long[] ids) {
if (destroyed) {
return;
}
nativeMapView.removeAnnotations(ids);
}
List<Marker> getMarkersInRect(@NonNull RectF rect) {
if (destroyed || rect == null) {
return new ArrayList<>();
}
long[] ids = nativeMapView.queryPointAnnotations(rect);
List<Long> idsList = new ArrayList<>(ids.length);
for (int i = 0; i < ids.length; i++) {
idsList.add(ids[i]);
}
List<Marker> annotations = new ArrayList<>(ids.length);
List<Annotation> annotationList = mapboxMap.getAnnotations();
int count = annotationList.size();
for (int i = 0; i < count; i++) {
Annotation annotation = annotationList.get(i);
if (annotation instanceof Marker && idsList.contains(annotation.getId())) {
annotations.add((Marker) annotation);
}
}
return new ArrayList<>(annotations);
}
public List<MarkerView> getMarkerViewsInRect(@NonNull RectF rect) {
if (destroyed || rect == null) {
return new ArrayList<>();
}
long[] ids = nativeMapView.queryPointAnnotations(rect);
List<Long> idsList = new ArrayList<>(ids.length);
for (int i = 0; i < ids.length; i++) {
idsList.add(ids[i]);
}
List<MarkerView> annotations = new ArrayList<>(ids.length);
List<Annotation> annotationList = mapboxMap.getAnnotations();
int count = annotationList.size();
for (int i = 0; i < count; i++) {
Annotation annotation = annotationList.get(i);
if (annotation instanceof MarkerView) {
annotations.add((MarkerView) annotation);
}
}
return new ArrayList<>(annotations);
}
/**
* @return the ViewGroup containing the marker views
*/
@@ -1317,16 +1020,6 @@ public class MapView extends FrameLayout {
return markerViewContainer;
}
int getTopOffsetPixelsForIcon(Icon icon) {
if (destroyed) {
return 0;
}
return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId())
* screenDensity);
}
void setContentPadding(int left, int top, int right, int bottom) {
if (destroyed) {
return;
@@ -1428,43 +1121,6 @@ public class MapView extends FrameLayout {
nativeMapView.flyTo(bearing, center, duration, pitch, zoom);
}
private void adjustTopOffsetPixels() {
List<Annotation> annotations = mapboxMap.getAnnotations();
int count = annotations.size();
for (int i = 0; i < count; i++) {
Annotation annotation = annotations.get(i);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.setTopOffsetPixels(
getTopOffsetPixelsForIcon(marker.getIcon()));
}
}
for (Marker marker : mapboxMap.getSelectedMarkers()) {
if (marker.isInfoWindowShown()) {
marker.hideInfoWindow();
marker.showInfoWindow(mapboxMap, this);
}
}
}
private void reloadMarkers() {
if (destroyed) {
return;
}
List<Annotation> annotations = mapboxMap.getAnnotations();
int count = annotations.size();
for (int i = 0; i < count; i++) {
Annotation annotation = annotations.get(i);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
nativeMapView.removeAnnotation(annotation.getId());
long newId = nativeMapView.addMarker(marker);
marker.setId(newId);
}
}
}
//
// Rendering
//
@@ -1700,7 +1356,7 @@ public class MapView extends FrameLayout {
* @param xCoordinate Original x screen coordinate at start of gesture
* @param yCoordinate Original y screen cooridnate at start of gesture
*/
private void trackGestureEvent(@NonNull String gestureId, @NonNull float xCoordinate, @NonNull float yCoordinate) {
private void trackGestureEvent(@NonNull String gestureId, float xCoordinate, float yCoordinate) {
LatLng tapLatLng = projection.fromScreenLocation(new PointF(xCoordinate, yCoordinate));
// NaN and Infinite checks to prevent JSON errors at send to server time
@@ -1732,7 +1388,7 @@ public class MapView extends FrameLayout {
* @param xCoordinate Original x screen coordinate at end of drag
* @param yCoordinate Orginal y screen coordinate at end of drag
*/
private void trackGestureDragEndEvent(@NonNull float xCoordinate, @NonNull float yCoordinate) {
private void trackGestureDragEndEvent(float xCoordinate, float yCoordinate) {
LatLng tapLatLng = projection.fromScreenLocation(new PointF(xCoordinate, yCoordinate));
// NaN and Infinite checks to prevent JSON errors at send to server time
@@ -1900,12 +1556,12 @@ public class MapView extends FrameLayout {
float toleranceSides = 4 * screenDensity;
float toleranceTopBottom = 10 * screenDensity;
RectF tapRect = new RectF((tapPoint.x - averageIconWidth / 2 - toleranceSides) / screenDensity,
(tapPoint.y - averageIconHeight / 2 - toleranceTopBottom) / screenDensity,
(tapPoint.x + averageIconWidth / 2 + toleranceSides) / screenDensity,
(tapPoint.y + averageIconHeight / 2 + toleranceTopBottom) / screenDensity);
RectF tapRect = new RectF((tapPoint.x - iconManager.getAverageIconWidth() / 2 - toleranceSides) / screenDensity,
(tapPoint.y - iconManager.getAverageIconHeight() / 2 - toleranceTopBottom) / screenDensity,
(tapPoint.x + iconManager.getAverageIconWidth() / 2 + toleranceSides) / screenDensity,
(tapPoint.y + iconManager.getAverageIconHeight() / 2 + toleranceTopBottom) / screenDensity);
List<Marker> nearbyMarkers = getMarkersInRect(tapRect);
List<Marker> nearbyMarkers = annotationManager.getMarkersInRect(tapRect);
long newSelectedMarkerId = -1;
if (nearbyMarkers != null && nearbyMarkers.size() > 0) {
@@ -2487,7 +2143,7 @@ public class MapView extends FrameLayout {
// Track if we have been cancelled
private boolean cancelled;
public TrackballLongPressTimeOut() {
TrackballLongPressTimeOut() {
cancelled = false;
}
@@ -2713,13 +2369,6 @@ public class MapView extends FrameLayout {
ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
/**
* 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
*/
void resetTrackingModesIfRequired(boolean translate, boolean rotate) {
TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
@@ -2881,7 +2530,7 @@ public class MapView extends FrameLayout {
private Bitmap bitmap;
private MapboxMap.SnapshotReadyCallback callback;
public SnapshotRequest(Bitmap bitmap, MapboxMap.SnapshotReadyCallback callback) {
SnapshotRequest(Bitmap bitmap, MapboxMap.SnapshotReadyCallback callback) {
this.bitmap = bitmap;
this.callback = callback;
}
@@ -2921,7 +2570,7 @@ public class MapView extends FrameLayout {
private static final int ATTRIBUTION_INDEX_TELEMETRY_SETTINGS = 3;
private MapView mapView;
public AttributionOnClickListener(MapView mapView) {
AttributionOnClickListener(MapView mapView) {
super();
this.mapView = mapView;
}
@@ -2929,14 +2578,11 @@ public class MapView extends FrameLayout {
// Called when someone presses the attribution icon
@Override
public void onClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(mapView.getContext(), R.style.mapbox_AlertDialogStyle);
builder.setTitle(R.string.mapbox_attributionsDialogTitle);
String[] items = mapView.getContext().getResources().getStringArray(R.array.mapbox_attribution_names);
builder.setAdapter(new ArrayAdapter<>(mapView.getContext(), R.layout.mapbox_attribution_list_item, items), this);
AlertDialog attributionDialog = builder.show();
// TODO Change listview text color to mapView.getAttributionTintColor()
builder.show();
}
// Called when someone selects an attribution, 'Improve this map' adds location data to the url
@@ -2993,7 +2639,7 @@ public class MapView extends FrameLayout {
private MapboxMap mapboxMap;
public ZoomInvalidator(MapboxMap mapboxMap) {
ZoomInvalidator(MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
}

View File

@@ -10,9 +10,7 @@ import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v4.util.LongSparseArray;
import android.support.v4.util.Pools;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -21,7 +19,6 @@ import com.mapbox.mapboxsdk.MapboxAccountManager;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.InfoWindow;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
@@ -47,7 +44,6 @@ import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.commons.geojson.Feature;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -70,23 +66,13 @@ public class MapboxMap {
private Projection projection;
private CameraPosition cameraPosition;
private boolean invalidCameraPosition;
private LongSparseArray<Annotation> annotations;
private List<Marker> selectedMarkers;
private MarkerViewManager markerViewManager;
private List<InfoWindow> infoWindows;
private MapboxMap.InfoWindowAdapter infoWindowAdapter;
private boolean myLocationEnabled;
private boolean allowConcurrentMultipleInfoWindows;
private MapboxMap.OnMapClickListener onMapClickListener;
private MapboxMap.OnMapLongClickListener onMapLongClickListener;
private MapboxMap.OnMarkerClickListener onMarkerClickListener;
private MapboxMap.OnInfoWindowClickListener onInfoWindowClickListener;
private MapboxMap.OnInfoWindowLongClickListener onInfoWindowLongClickListener;
private MapboxMap.OnInfoWindowCloseListener onInfoWindowCloseListener;
private MapboxMap.OnFlingListener onFlingListener;
private MapboxMap.OnScrollListener onScrollListener;
private MapboxMap.OnMyLocationTrackingModeChangeListener onMyLocationTrackingModeChangeListener;
@@ -94,19 +80,20 @@ public class MapboxMap {
private MapboxMap.OnFpsChangedListener onFpsChangedListener;
private MapboxMap.OnCameraChangeListener onCameraChangeListener;
private AnnotationManager annotationManager;
private InfoWindowManager infoWindowManager;
private double maxZoomLevel = -1;
private double minZoomLevel = -1;
MapboxMap(@NonNull MapView mapView) {
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);
annotations = new LongSparseArray<>();
selectedMarkers = new ArrayList<>();
infoWindows = new ArrayList<>();
markerViewManager = new MarkerViewManager(this, mapView);
infoWindowManager = new InfoWindowManager();
annotationManager = new AnnotationManager(mapView.getNativeMapView(), iconManager, infoWindowManager);
}
// Style
@@ -220,7 +207,7 @@ public class MapboxMap {
*/
@UiThread
public void setMinZoom(
@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) {
@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) {
if ((minZoom < MapboxConstants.MINIMUM_ZOOM) || (minZoom > MapboxConstants.MAXIMUM_ZOOM)) {
Log.e(MapboxConstants.TAG, "Not setting minZoom, value is in unsupported range: " + minZoom);
return;
@@ -257,7 +244,7 @@ public class MapboxMap {
*/
@UiThread
public void setMaxZoom(
@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) {
@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) {
if ((maxZoom < MapboxConstants.MINIMUM_ZOOM) || (maxZoom > MapboxConstants.MAXIMUM_ZOOM)) {
Log.e(MapboxConstants.TAG, "Not setting maxZoom, value is in unsupported range: " + maxZoom);
return;
@@ -600,7 +587,7 @@ public class MapboxMap {
* Invalidates the current camera position by reconstructing it from mbgl
*/
private void invalidateCameraPosition() {
if(invalidCameraPosition) {
if (invalidCameraPosition) {
invalidCameraPosition = false;
CameraPosition cameraPosition = mapView.invalidateCameraPosition();
@@ -801,7 +788,7 @@ public class MapboxMap {
@UiThread
@NonNull
public Marker addMarker(@NonNull MarkerOptions markerOptions) {
return addMarker((BaseMarkerOptions) markerOptions);
return annotationManager.addMarker(markerOptions, this);
}
/**
@@ -817,12 +804,7 @@ public class MapboxMap {
@UiThread
@NonNull
public Marker addMarker(@NonNull BaseMarkerOptions markerOptions) {
Marker marker = prepareMarker(markerOptions);
long id = mapView.addMarker(marker);
marker.setMapboxMap(this);
marker.setId(id);
annotations.put(id, marker);
return marker;
return annotationManager.addMarker(markerOptions, this);
}
/**
@@ -838,29 +820,19 @@ public class MapboxMap {
@UiThread
@NonNull
public MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions) {
MarkerView marker = prepareViewMarker(markerOptions);
marker.setMapboxMap(this);
long id = mapView.addMarker(marker);
marker.setId(id);
annotations.put(id, marker);
markerViewManager.invalidateViewMarkersInVisibleRegion();
return marker;
return annotationManager.addMarker(markerOptions, this);
}
@UiThread
@NonNull
public List<MarkerView> addMarkerViews(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions) {
List<MarkerView> markers = new ArrayList<>();
for (BaseMarkerViewOptions markerViewOption : markerViewOptions) {
MarkerView marker = prepareViewMarker(markerViewOption);
marker.setMapboxMap(this);
long id = mapView.addMarker(marker);
marker.setId(id);
annotations.put(id, marker);
markers.add(marker);
}
markerViewManager.invalidateViewMarkersInVisibleRegion();
return markers;
return annotationManager.addMarkerViews(markerViewOptions, this);
}
@UiThread
@NonNull
public List<MarkerView> getMarkerViewsInRect(@NonNull RectF rect) {
return annotationManager.getMarkerViewsInRect(rect);
}
/**
@@ -876,40 +848,7 @@ public class MapboxMap {
@UiThread
@NonNull
public List<Marker> addMarkers(@NonNull List<? extends BaseMarkerOptions> markerOptionsList) {
int count = markerOptionsList.size();
List<Marker> markers = new ArrayList<>(count);
if (count > 0) {
BaseMarkerOptions markerOptions;
Marker marker;
for (int i = 0; i < count; i++) {
markerOptions = markerOptionsList.get(i);
marker = prepareMarker(markerOptions);
markers.add(marker);
}
if (markers.size() > 0) {
long[] ids = mapView.addMarkers(markers);
// if unittests or markers are correctly added to map
if (ids == null || ids.length == markers.size()) {
long id = 0;
Marker m;
for (int i = 0; i < markers.size(); i++) {
m = markers.get(i);
m.setMapboxMap(this);
if (ids != null) {
id = ids[i];
} else {
//unit test
id++;
}
m.setId(id);
annotations.put(id, m);
}
}
}
}
return markers;
return annotationManager.addMarkers(markerOptionsList, this);
}
/**
@@ -921,42 +860,7 @@ public class MapboxMap {
*/
@UiThread
public void updateMarker(@NonNull Marker updatedMarker) {
mapView.updateMarker(updatedMarker);
int index = annotations.indexOfKey(updatedMarker.getId());
if (index > -1) {
annotations.setValueAt(index, updatedMarker);
}
}
/**
* Update a polygon on this map.
*
* @param polygon An updated polygon object.
*/
@UiThread
public void updatePolygon(Polygon polygon) {
mapView.updatePolygon(polygon);
int index = annotations.indexOfKey(polygon.getId());
if (index > -1) {
annotations.setValueAt(index, polygon);
}
}
/**
* Update a polyline on this map.
*
* @param polyline An updated polyline object.
*/
@UiThread
public void updatePolyline(Polyline polyline) {
mapView.updatePolyline(polyline);
int index = annotations.indexOfKey(polyline.getId());
if (index > -1) {
annotations.setValueAt(index, polyline);
}
annotationManager.updateMarker(updatedMarker, this);
}
/**
@@ -968,14 +872,7 @@ public class MapboxMap {
@UiThread
@NonNull
public Polyline addPolyline(@NonNull PolylineOptions polylineOptions) {
Polyline polyline = polylineOptions.getPolyline();
if (!polyline.getPoints().isEmpty()) {
long id = mapView.addPolyline(polyline);
polyline.setMapboxMap(this);
polyline.setId(id);
annotations.put(id, polyline);
}
return polyline;
return annotationManager.addPolyline(polylineOptions, this);
}
/**
@@ -987,40 +884,17 @@ public class MapboxMap {
@UiThread
@NonNull
public List<Polyline> addPolylines(@NonNull List<PolylineOptions> polylineOptionsList) {
int count = polylineOptionsList.size();
Polyline polyline;
List<Polyline> polylines = new ArrayList<>(count);
return annotationManager.addPolylines(polylineOptionsList, this);
}
if (count > 0) {
for (PolylineOptions options : polylineOptionsList) {
polyline = options.getPolyline();
if (!polyline.getPoints().isEmpty()) {
polylines.add(polyline);
}
}
long[] ids = mapView.addPolylines(polylines);
// if unit tests or polylines are correctly added to map
if (ids == null || ids.length == polylines.size()) {
long id = 0;
Polyline p;
for (int i = 0; i < polylines.size(); i++) {
p = polylines.get(i);
p.setMapboxMap(this);
if (ids != null) {
id = ids[i];
} else {
// unit test
id++;
}
p.setId(id);
annotations.put(id, p);
}
}
}
return polylines;
/**
* Update a polyline on this map.
*
* @param polyline An updated polyline object.
*/
@UiThread
public void updatePolyline(Polyline polyline) {
annotationManager.updatePolyline(polyline);
}
/**
@@ -1032,14 +906,7 @@ public class MapboxMap {
@UiThread
@NonNull
public Polygon addPolygon(@NonNull PolygonOptions polygonOptions) {
Polygon polygon = polygonOptions.getPolygon();
if (!polygon.getPoints().isEmpty()) {
long id = mapView.addPolygon(polygon);
polygon.setId(id);
polygon.setMapboxMap(this);
annotations.put(id, polygon);
}
return polygon;
return annotationManager.addPolygon(polygonOptions, this);
}
/**
@@ -1051,38 +918,18 @@ public class MapboxMap {
@UiThread
@NonNull
public List<Polygon> addPolygons(@NonNull List<PolygonOptions> polygonOptionsList) {
int count = polygonOptionsList.size();
return annotationManager.addPolygons(polygonOptionsList, this);
}
Polygon polygon;
List<Polygon> polygons = new ArrayList<>(count);
if (count > 0) {
for (PolygonOptions polygonOptions : polygonOptionsList) {
polygon = polygonOptions.getPolygon();
if (!polygon.getPoints().isEmpty()) {
polygons.add(polygon);
}
}
long[] ids = mapView.addPolygons(polygons);
// if unit tests or polygons correctly added to map
if (ids == null || ids.length == polygons.size()) {
long id = 0;
for (int i = 0; i < polygons.size(); i++) {
polygon = polygons.get(i);
polygon.setMapboxMap(this);
if (ids != null) {
id = ids[i];
} else {
// unit test
id++;
}
polygon.setId(id);
annotations.put(id, polygon);
}
}
}
return polygons;
/**
* Update a polygon on this map.
*
* @param polygon An updated polygon object.
*/
@UiThread
public void updatePolygon(Polygon polygon) {
annotationManager.updatePolygon(polygon);
}
/**
@@ -1095,7 +942,7 @@ public class MapboxMap {
*/
@UiThread
public void removeMarker(@NonNull Marker marker) {
removeAnnotation(marker);
annotationManager.removeAnnotation(marker);
}
/**
@@ -1108,7 +955,7 @@ public class MapboxMap {
*/
@UiThread
public void removePolyline(@NonNull Polyline polyline) {
removeAnnotation(polyline);
annotationManager.removeAnnotation(polyline);
}
/**
@@ -1121,7 +968,7 @@ public class MapboxMap {
*/
@UiThread
public void removePolygon(@NonNull Polygon polygon) {
removeAnnotation(polygon);
annotationManager.removeAnnotation(polygon);
}
/**
@@ -1131,16 +978,7 @@ public class MapboxMap {
*/
@UiThread
public void removeAnnotation(@NonNull Annotation annotation) {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
}
long id = annotation.getId();
mapView.removeAnnotation(id);
annotations.remove(id);
annotationManager.removeAnnotation(annotation);
}
/**
@@ -1150,8 +988,7 @@ public class MapboxMap {
*/
@UiThread
public void removeAnnotation(long id) {
mapView.removeAnnotation(id);
annotations.remove(id);
annotationManager.removeAnnotation(id);
}
/**
@@ -1161,23 +998,7 @@ public class MapboxMap {
*/
@UiThread
public void removeAnnotations(@NonNull List<? extends Annotation> annotationList) {
int count = annotationList.size();
long[] ids = new long[count];
for (int i = 0; i < count; i++) {
Annotation annotation = annotationList.get(i);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
}
ids[i] = annotationList.get(i).getId();
}
mapView.removeAnnotations(ids);
for (long id : ids) {
annotations.remove(id);
}
annotationManager.removeAnnotations(annotationList);
}
/**
@@ -1185,22 +1006,7 @@ public class MapboxMap {
*/
@UiThread
public void removeAnnotations() {
Annotation annotation;
int count = annotations.size();
long[] ids = new long[count];
for (int i = 0; i < count; i++) {
ids[i] = annotations.keyAt(i);
annotation = annotations.get(ids[i]);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
}
}
}
mapView.removeAnnotations(ids);
annotations.clear();
annotationManager.removeAnnotations();
}
/**
@@ -1208,7 +1014,7 @@ public class MapboxMap {
*/
@UiThread
public void clear() {
removeAnnotations();
annotationManager.removeAnnotations();
}
/**
@@ -1219,7 +1025,7 @@ public class MapboxMap {
*/
@Nullable
public Annotation getAnnotation(long id) {
return annotations.get(id);
return annotationManager.getAnnotation(id);
}
/**
@@ -1230,11 +1036,7 @@ public class MapboxMap {
*/
@NonNull
public List<Annotation> getAnnotations() {
List<Annotation> annotations = new ArrayList<>();
for (int i = 0; i < this.annotations.size(); i++) {
annotations.add(this.annotations.get(this.annotations.keyAt(i)));
}
return annotations;
return annotationManager.getAnnotations();
}
/**
@@ -1245,15 +1047,7 @@ public class MapboxMap {
*/
@NonNull
public List<Marker> getMarkers() {
List<Marker> markers = new ArrayList<>();
Annotation annotation;
for (int i = 0; i < annotations.size(); i++) {
annotation = annotations.get(annotations.keyAt(i));
if (annotation instanceof Marker) {
markers.add((Marker) annotation);
}
}
return markers;
return annotationManager.getMarkers();
}
/**
@@ -1264,15 +1058,7 @@ public class MapboxMap {
*/
@NonNull
public List<Polygon> getPolygons() {
List<Polygon> polygons = new ArrayList<>();
Annotation annotation;
for (int i = 0; i < annotations.size(); i++) {
annotation = annotations.get(annotations.keyAt(i));
if (annotation instanceof Polygon) {
polygons.add((Polygon) annotation);
}
}
return polygons;
return annotationManager.getPolygons();
}
/**
@@ -1283,15 +1069,18 @@ public class MapboxMap {
*/
@NonNull
public List<Polyline> getPolylines() {
List<Polyline> polylines = new ArrayList<>();
Annotation annotation;
for (int i = 0; i < annotations.size(); i++) {
annotation = annotations.get(annotations.keyAt(i));
if (annotation instanceof Polyline) {
polylines.add((Polyline) annotation);
}
}
return polylines;
return annotationManager.getPolylines();
}
/**
* Sets a callback that's invoked when the user clicks on a marker.
*
* @param listener The callback that's invoked when the user clicks on a marker.
* To unset the callback, use null.
*/
@UiThread
public void setOnMarkerClickListener(@Nullable OnMarkerClickListener listener) {
annotationManager.setOnMarkerClickListener(listener);
}
/**
@@ -1310,34 +1099,7 @@ public class MapboxMap {
Log.w(MapboxConstants.TAG, "marker was null, so just returning");
return;
}
if (selectedMarkers.contains(marker)) {
return;
}
// Need to deselect any currently selected annotation first
if (!isAllowConcurrentMultipleOpenInfoWindows()) {
deselectMarkers();
}
boolean handledDefaultClick = false;
if (onMarkerClickListener != null) {
// end developer has provided a custom click listener
handledDefaultClick = onMarkerClickListener.onMarkerClick(marker);
}
if (!handledDefaultClick) {
if (marker instanceof MarkerView) {
markerViewManager.select((MarkerView) marker, false);
markerViewManager.ensureInfoWindowOffset((MarkerView) marker);
}
if (isInfoWindowValidForMarker(marker) || getInfoWindowAdapter() != null) {
infoWindows.add(marker.showInfoWindow(this, mapView));
}
}
selectedMarkers.add(marker);
annotationManager.selectMarker(marker, this);
}
/**
@@ -1345,22 +1107,7 @@ public class MapboxMap {
*/
@UiThread
public void deselectMarkers() {
if (selectedMarkers.isEmpty()) {
return;
}
for (Marker marker : selectedMarkers) {
if (marker.isInfoWindowShown()) {
marker.hideInfoWindow();
}
if (marker instanceof MarkerView) {
markerViewManager.deselect((MarkerView) marker, false);
}
}
// Removes all selected markers from the list
selectedMarkers.clear();
annotationManager.deselectMarkers();
}
/**
@@ -1370,19 +1117,7 @@ public class MapboxMap {
*/
@UiThread
public void deselectMarker(@NonNull Marker marker) {
if (!selectedMarkers.contains(marker)) {
return;
}
if (marker.isInfoWindowShown()) {
marker.hideInfoWindow();
}
if (marker instanceof MarkerView) {
markerViewManager.deselect((MarkerView) marker, false);
}
selectedMarkers.remove(marker);
annotationManager.deselectMarker(marker);
}
/**
@@ -1392,20 +1127,7 @@ public class MapboxMap {
*/
@UiThread
public List<Marker> getSelectedMarkers() {
return selectedMarkers;
}
private Marker prepareMarker(BaseMarkerOptions markerOptions) {
Marker marker = markerOptions.getMarker();
Icon icon = mapView.loadIconForMarker(marker);
marker.setTopOffsetPixels(mapView.getTopOffsetPixelsForIcon(icon));
return marker;
}
private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) {
MarkerView marker = markerViewOptions.getMarker();
mapView.loadIconForMarkerView(marker);
return marker;
return annotationManager.getSelectedMarkers();
}
/**
@@ -1414,7 +1136,7 @@ public class MapboxMap {
* @return the associated MarkerViewManager
*/
public MarkerViewManager getMarkerViewManager() {
return markerViewManager;
return annotationManager.getMarkerViewManager(this);
}
//
@@ -1433,7 +1155,7 @@ public class MapboxMap {
*/
@UiThread
public void setInfoWindowAdapter(@Nullable InfoWindowAdapter infoWindowAdapter) {
this.infoWindowAdapter = infoWindowAdapter;
infoWindowManager.setInfoWindowAdapter(infoWindowAdapter);
}
/**
@@ -1444,7 +1166,7 @@ public class MapboxMap {
@UiThread
@Nullable
public InfoWindowAdapter getInfoWindowAdapter() {
return infoWindowAdapter;
return infoWindowManager.getInfoWindowAdapter();
}
/**
@@ -1454,7 +1176,7 @@ public class MapboxMap {
*/
@UiThread
public void setAllowConcurrentMultipleOpenInfoWindows(boolean allow) {
allowConcurrentMultipleInfoWindows = allow;
infoWindowManager.setAllowConcurrentMultipleOpenInfoWindows(allow);
}
/**
@@ -1464,16 +1186,16 @@ public class MapboxMap {
*/
@UiThread
public boolean isAllowConcurrentMultipleOpenInfoWindows() {
return allowConcurrentMultipleInfoWindows;
return infoWindowManager.isAllowConcurrentMultipleOpenInfoWindows();
}
// used by MapView
List<InfoWindow> getInfoWindows() {
return infoWindows;
return infoWindowManager.getInfoWindows();
}
private boolean isInfoWindowValidForMarker(@NonNull Marker marker) {
return !TextUtils.isEmpty(marker.getTitle()) || !TextUtils.isEmpty(marker.getSnippet());
AnnotationManager getAnnotationManager() {
return annotationManager;
}
//
@@ -1610,17 +1332,6 @@ public class MapboxMap {
return onMapLongClickListener;
}
/**
* Sets a callback that's invoked when the user clicks on a marker.
*
* @param listener The callback that's invoked when the user clicks on a marker.
* To unset the callback, use null.
*/
@UiThread
public void setOnMarkerClickListener(@Nullable OnMarkerClickListener listener) {
onMarkerClickListener = listener;
}
/**
* Sets a callback that's invoked when the user clicks on an info window.
*
@@ -1629,7 +1340,7 @@ public class MapboxMap {
*/
@UiThread
public void setOnInfoWindowClickListener(@Nullable OnInfoWindowClickListener listener) {
onInfoWindowClickListener = listener;
infoWindowManager.setOnInfoWindowClickListener(listener);
}
/**
@@ -1639,7 +1350,7 @@ public class MapboxMap {
*/
@UiThread
public OnInfoWindowClickListener getOnInfoWindowClickListener() {
return onInfoWindowClickListener;
return infoWindowManager.getOnInfoWindowClickListener();
}
/**
@@ -1650,7 +1361,7 @@ public class MapboxMap {
*/
@UiThread
public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener listener) {
onInfoWindowLongClickListener = listener;
infoWindowManager.setOnInfoWindowLongClickListener(listener);
}
/**
@@ -1659,11 +1370,11 @@ public class MapboxMap {
* @return Current active InfoWindow long Click Listener
*/
public OnInfoWindowLongClickListener getOnInfoWindowLongClickListener() {
return onInfoWindowLongClickListener;
return infoWindowManager.getOnInfoWindowLongClickListener();
}
public void setOnInfoWindowCloseListener(@Nullable OnInfoWindowCloseListener listener) {
onInfoWindowCloseListener = listener;
infoWindowManager.setOnInfoWindowCloseListener(listener);
}
/**
@@ -1673,7 +1384,7 @@ public class MapboxMap {
*/
@UiThread
public OnInfoWindowCloseListener getOnInfoWindowCloseListener() {
return onInfoWindowCloseListener;
return infoWindowManager.getOnInfoWindowCloseListener();
}
//

View File

@@ -34,14 +34,6 @@ import java.util.List;
// Class that wraps the native methods for convenience
final class NativeMapView {
//
// Static members
//
//
// Instance members
//
boolean destroyed = false;
// Holds the pointer to JNI NativeMapView
@@ -547,7 +539,7 @@ final class NativeMapView {
@NonNull
public List<Feature> queryRenderedFeatures(RectF coordinates, String... layerIds) {
Feature[] features = nativeQueryRenderedFeaturesForBox(
nativeMapViewPtr,
nativeMapViewPtr,
coordinates.left / pixelRatio,
coordinates.top / pixelRatio,
coordinates.right / pixelRatio,
@@ -564,6 +556,14 @@ final class NativeMapView {
nativeSetAPIBaseURL(nativeMapViewPtr, baseUrl);
}
public float getPixelRatio() {
return pixelRatio;
}
public Context getContext() {
return mapView.getContext();
}
//
// Callbacks
//