diff options
author | Tobrun <tobrun.van.nuland@gmail.com> | 2016-11-07 17:23:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-07 17:23:51 +0100 |
commit | 1f8f85fab32f583101cc6cccee8a5463aba6dab7 (patch) | |
tree | 168d0d6c20413b63c9695457bd0a942b164aeba6 /platform/android | |
parent | 5412191ab484cc82f2864fd9cf360939c823fc33 (diff) | |
download | qtlocation-mapboxgl-1f8f85fab32f583101cc6cccee8a5463aba6dab7.tar.gz |
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)
Diffstat (limited to 'platform/android')
8 files changed, 943 insertions, 766 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java index e17165ae49..36f43abb11 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java @@ -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 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 new file mode 100644 index 0000000000..0eae8eb0a9 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java @@ -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); + } + } + } +} 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 new file mode 100644 index 0000000000..71a9d4a2da --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java @@ -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; + } +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java new file mode 100644 index 0000000000..7b58807973 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java @@ -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; + } +} 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 2ac95cf163..d1e2b1a253 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 @@ -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; } 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 b1f0984e3c..65b67c9ff1 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 @@ -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); - - if (count > 0) { - for (PolylineOptions options : polylineOptionsList) { - polyline = options.getPolyline(); - if (!polyline.getPoints().isEmpty()) { - polylines.add(polyline); - } - } + return annotationManager.addPolylines(polylineOptionsList, this); + } - 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(); - - 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); - } - } + return annotationManager.addPolygons(polygonOptionsList, this); + } - 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; } // @@ -1611,17 +1333,6 @@ public class MapboxMap { } /** - * 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. * * @param listener The 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(); } // 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 4e0ce33c5b..3e4e1dd305 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 @@ -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 // diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java index 9d0a1c0ad7..848a1e2abb 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java @@ -79,10 +79,13 @@ public class MapboxMapTest { @Mock MapboxMap.OnMyBearingTrackingModeChangeListener mMyBearingTrackingModeChangeListener; + @Mock + IconManager iconManager; + @Before public void beforeTest() { MockitoAnnotations.initMocks(this); - mMapboxMap = new MapboxMap(mMapView); + mMapboxMap = new MapboxMap(mMapView, iconManager); } @Test |