From 2fc070ca9995bf4ceb4599ce7a94bee7a03b10b4 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Mon, 6 Feb 2017 13:20:15 +0200 Subject: [android] native map view refactoring --- .../com/mapbox/mapboxsdk/annotations/Marker.java | 3 + .../java/com/mapbox/mapboxsdk/maps/MapView.java | 22 +- .../com/mapbox/mapboxsdk/maps/NativeMapView.java | 1055 +++++------------ platform/android/config.cmake | 28 +- platform/android/src/annotation/marker.cpp | 27 + platform/android/src/annotation/marker.hpp | 30 + platform/android/src/annotation/multi_point.hpp | 42 + platform/android/src/annotation/polygon.cpp | 49 + platform/android/src/annotation/polygon.hpp | 40 + platform/android/src/annotation/polyline.cpp | 49 + platform/android/src/annotation/polyline.hpp | 40 + platform/android/src/conversion/collection.hpp | 13 + platform/android/src/conversion/color.hpp | 24 + .../android/src/geometry/conversion/feature.hpp | 38 +- platform/android/src/geometry/feature.cpp | 20 + platform/android/src/geometry/feature.hpp | 29 + platform/android/src/geometry/geometry.hpp | 16 + platform/android/src/geometry/lat_lng.cpp | 31 + platform/android/src/geometry/lat_lng.hpp | 31 + platform/android/src/geometry/projected_meters.cpp | 20 + platform/android/src/geometry/projected_meters.hpp | 26 + platform/android/src/graphics/pointf.cpp | 20 + platform/android/src/graphics/pointf.hpp | 25 + platform/android/src/graphics/rectf.cpp | 35 + platform/android/src/graphics/rectf.hpp | 31 + platform/android/src/gson/json_object.hpp | 16 + platform/android/src/java/util.cpp | 18 + platform/android/src/java/util.hpp | 33 + platform/android/src/jni.cpp | 1224 +------------------- platform/android/src/jni.hpp | 14 +- platform/android/src/native_map_view.cpp | 875 ++++++++++++-- platform/android/src/native_map_view.hpp | 186 ++- platform/android/src/style/android_conversion.hpp | 1 - 33 files changed, 1949 insertions(+), 2162 deletions(-) create mode 100644 platform/android/src/annotation/marker.cpp create mode 100644 platform/android/src/annotation/marker.hpp create mode 100644 platform/android/src/annotation/multi_point.hpp create mode 100644 platform/android/src/annotation/polygon.cpp create mode 100644 platform/android/src/annotation/polygon.hpp create mode 100644 platform/android/src/annotation/polyline.cpp create mode 100644 platform/android/src/annotation/polyline.hpp create mode 100644 platform/android/src/conversion/color.hpp create mode 100644 platform/android/src/geometry/feature.cpp create mode 100644 platform/android/src/geometry/feature.hpp create mode 100644 platform/android/src/geometry/geometry.hpp create mode 100644 platform/android/src/geometry/lat_lng.cpp create mode 100644 platform/android/src/geometry/lat_lng.hpp create mode 100644 platform/android/src/geometry/projected_meters.cpp create mode 100644 platform/android/src/geometry/projected_meters.hpp create mode 100644 platform/android/src/graphics/pointf.cpp create mode 100644 platform/android/src/graphics/pointf.hpp create mode 100644 platform/android/src/graphics/rectf.cpp create mode 100644 platform/android/src/graphics/rectf.hpp create mode 100644 platform/android/src/gson/json_object.hpp create mode 100644 platform/android/src/java/util.cpp create mode 100644 platform/android/src/java/util.hpp diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java index edf118205b..4d7c620435 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java @@ -30,6 +30,8 @@ public class Marker extends Annotation { private LatLng position; private String snippet; private Icon icon; + //Redundantly stored for JNI access + private String iconId; private String title; private InfoWindow infoWindow; @@ -148,6 +150,7 @@ public class Marker extends Annotation { */ public void setIcon(@Nullable Icon icon) { this.icon = icon; + this.iconId = icon != null ? icon.getId() : null; MapboxMap map = getMapboxMap(); if (map != null) { map.updateMarker(this); 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 11928615d6..c124531fa5 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 @@ -149,6 +149,9 @@ public class MapView extends FrameLayout { // Create native Map object nativeMapView = new NativeMapView(MapView.this); + if (TextUtils.isEmpty(nativeMapView.getAccessToken())) { + nativeMapView.setAccessToken(Mapbox.getAccessToken()); + } //Continue configuring the map view on the main thread MapView.this.post(new Runnable() { @@ -173,7 +176,6 @@ public class MapView extends FrameLayout { nativeMapView.render(); } }); - } private void setupViewProperties() { @@ -188,19 +190,6 @@ public class MapView extends FrameLayout { requestDisallowInterceptTouchEvent(true); } -// private void loopRender() { -// postDelayed(new Runnable() { -// @Override -// public void run() { -// //glSurfaceView.queueEvent(renderRunnable); -// onInvalidate(); -//// nativeMapView.update(); -// //onInvalidate(); -// loopRender(); -// } -// }, 500); -// } - protected void onNativeMapViewReady() { // callback for focal point invalidation @@ -336,9 +325,6 @@ public class MapView extends FrameLayout { } destroyed = true; - //nativeMapView.terminateContext(); - //nativeMapView.terminateDisplay(); - //nativeMapView.destroySurface(); glSurfaceView.queueEvent(new Runnable() { @Override @@ -506,8 +492,6 @@ public class MapView extends FrameLayout { if (isInEditMode()) { return; } - - //glSurfaceView.queueEvent(renderRunnable); } @Override 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 5069a25d69..f5fd886662 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 @@ -8,20 +8,18 @@ import android.graphics.RectF; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.text.TextUtils; import android.util.DisplayMetrics; -import android.view.Surface; -import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.Polygon; import com.mapbox.mapboxsdk.annotations.Polyline; -import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.ProjectedMeters; import com.mapbox.mapboxsdk.offline.OfflineManager; +import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException; import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException; +import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException; import com.mapbox.mapboxsdk.style.sources.NoSuchSourceException; import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.services.commons.geojson.Feature; @@ -37,11 +35,8 @@ import timber.log.Timber; // Class that wraps the native methods for convenience final class NativeMapView { - // Flag to indicating destroy was called - private boolean destroyed = false; - // Holds the pointer to JNI NativeMapView - private long nativeMapViewPtr = 0; + private long nativePtr = 0; // Used for callbacks private MapView mapView; @@ -50,7 +45,7 @@ final class NativeMapView { private final float pixelRatio; // Listeners for Map change events - private CopyOnWriteArrayList onMapChangedListeners; + private CopyOnWriteArrayList onMapChangedListeners = new CopyOnWriteArrayList<>(); // Listener invoked to return a bitmap of the map private MapboxMap.SnapshotReadyCallback snapshotReadyCallback; @@ -67,23 +62,21 @@ final class NativeMapView { // Constructors // - public NativeMapView(MapView mapView) { + NativeMapView(MapView mapView) { this.mapView = mapView; Context context = mapView.getContext(); - String dataPath = OfflineManager.getDatabasePath(context); - - // With the availability of offline, we're unifying the ambient (cache) and the offline - // databases to be in the same folder, outside cache, to avoid automatic deletion from - // the system - String cachePath = dataPath; + String cachePath = OfflineManager.getDatabasePath(context); pixelRatio = context.getResources().getDisplayMetrics().density; String apkPath = context.getPackageCodePath(); + int availableProcessors = Runtime.getRuntime().availableProcessors(); + ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo(); ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); activityManager.getMemoryInfo(memoryInfo); + long totalMemory = memoryInfo.availMem; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { totalMemory = memoryInfo.totalMem; @@ -96,702 +89,389 @@ final class NativeMapView { if (totalMemory < 0) { throw new IllegalArgumentException("totalMemory cannot be negative."); } - onMapChangedListeners = new CopyOnWriteArrayList<>(); -// if (Looper.myLooper() == null) { -// Looper.prepare(); -// } - nativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath, pixelRatio, availableProcessors, totalMemory); + initialize(this, cachePath, apkPath, pixelRatio, availableProcessors, totalMemory); } // // Methods // - public void onViewportChanged(int width, int height) { - if (isDestroyedOn("onViewportChanged")) { - return; - } + private native void initialize(NativeMapView nativeMapView, String cachePath, String apkPath, float pixelRatio, + int availableProcessors, long totalMemory); - if (width < 0) { - throw new IllegalArgumentException("width cannot be negative."); - } + native void destroy(); - if (height < 0) { - throw new IllegalArgumentException("height cannot be negative."); - } + native void render(); - if (width > 65535) { - // we have seen edge cases where devices return incorrect values #6111 - Timber.e("Device returned an out of range width size, " - + "capping value at 65535 instead of " + width); - width = 65535; - } + native void setStyleUrl(String url); - if (height > 65535) { - // we have seen edge cases where devices return incorrect values #6111 - Timber.e("Device returned an out of range height size, " - + "capping value at 65535 instead of " + height); - height = 65535; - } + native String getStyleUrl(); - nativeOnViewportChanged(nativeMapViewPtr, width, height); - } + native void setStyleJson(String styleJson); - private boolean isDestroyedOn(String callingMethod) { - if (destroyed && !TextUtils.isEmpty(callingMethod)) { - Timber.e(String.format(MapboxConstants.MAPBOX_LOCALE, - "You're calling `%s` after the `MapView` was destroyed, were you invoking it after `onDestroy()`?", - callingMethod)); - } - return destroyed; - } + native String getStyleJson(); - public void destroy() { - nativeDestroy(nativeMapViewPtr); - nativeMapViewPtr = 0; - mapView = null; - destroyed = true; - } + native void setAccessToken(String accessToken); - public void update() { - if (isDestroyedOn("update")) { - return; - } - nativeUpdate(nativeMapViewPtr); - } + native String getAccessToken(); - public void render() { - Timber.i("Render"); - if (isDestroyedOn("render")) { - return; - } - nativeRender(nativeMapViewPtr); - } + native void cancelTransitions(); - public void addClass(String clazz) { - if (isDestroyedOn("addClass")) { - return; - } - nativeAddClass(nativeMapViewPtr, clazz); - } + native void setGestureInProgress(boolean inProgress); - public void removeClass(String clazz) { - if (isDestroyedOn("removeClass")) { - return; - } - nativeRemoveClass(nativeMapViewPtr, clazz); - } + native void setLatLng(double latitude, double longitude); - public boolean hasClass(String clazz) { - if (isDestroyedOn("hasClass")) { - return false; - } - return nativeHasClass(nativeMapViewPtr, clazz); - } + native void resetPosition(); - public void setClasses(List classes) { - if (isDestroyedOn("setClasses")) { - return; - } - nativeSetClasses(nativeMapViewPtr, classes); - } + native double getPitch(); - public List getClasses() { - if (isDestroyedOn("getClasses")) { - return new ArrayList<>(); - } - return nativeGetClasses(nativeMapViewPtr); - } + native void setPitch(double pitch); - public void setStyleUrl(String url) { - if (isDestroyedOn("setStyleUrl")) { - return; - } - nativeSetStyleUrl(nativeMapViewPtr, url); + @Deprecated + void setPitch(double pitch, int duration) { + setPitch(pitch); } - public String getStyleUrl() { - if (isDestroyedOn("getStyleUrl")) { - return null; - } - return nativeGetStyleUrl(nativeMapViewPtr); - } + native double getScale(); - public void setStyleJson(String newStyleJson) { - if (isDestroyedOn("setStyleJson")) { - return; - } - nativeSetStyleJson(nativeMapViewPtr, newStyleJson); - } + native void setZoom(double zoom); - public String getStyleJson() { - if (isDestroyedOn("getStyleJson")) { - return null; - } - return nativeGetStyleJson(nativeMapViewPtr); - } + native double getZoom(); - public void setAccessToken(String accessToken) { - if (isDestroyedOn("setAccessToken")) { - return; - } - nativeSetAccessToken(nativeMapViewPtr, accessToken); - } + native void resetZoom(); - public String getAccessToken() { - if (isDestroyedOn("getAccessToken")) { - return null; - } - return nativeGetAccessToken(nativeMapViewPtr); - } + native void setMinZoom(double zoom); - public void cancelTransitions() { - if (isDestroyedOn("cancelTransitions")) { - return; - } - nativeCancelTransitions(nativeMapViewPtr); - } + native double getMinZoom(); - public void setGestureInProgress(boolean inProgress) { - if (isDestroyedOn("setGestureInProgress")) { - return; - } - nativeSetGestureInProgress(nativeMapViewPtr, inProgress); - } + native void setMaxZoom(double zoom); - public void moveBy(double dx, double dy) { - if (isDestroyedOn("moveBy")) { - return; - } - moveBy(dx, dy, 0); - } + native double getMaxZoom(); - public void moveBy(double dx, double dy, long duration) { - Timber.i("Move by %sx%s - %s", dx, dy, duration); - if (isDestroyedOn("moveBy")) { - return; + void onViewportChanged(int width, int height) { + if (width < 0) { + throw new IllegalArgumentException("width cannot be negative."); } - nativeMoveBy(nativeMapViewPtr, dx / pixelRatio, dy / pixelRatio, duration); - } - public void setLatLng(LatLng latLng) { - if (isDestroyedOn("setLatLng")) { - return; + if (height < 0) { + throw new IllegalArgumentException("height cannot be negative."); } - setLatLng(latLng, 0); - } - public void setLatLng(LatLng latLng, long duration) { - Timber.i("setLatLng %sx%s - %s", latLng.getLatitude(), latLng.getLongitude(), duration); - if (isDestroyedOn("setLatLng")) { - return; + if (width > 65535) { + // we have seen edge cases where devices return incorrect values #6111 + Timber.e("Device returned an out of range width size, " + + "capping value at 65535 instead of " + width); + width = 65535; } - nativeSetLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude(), duration); - } - public LatLng getLatLng() { - if (isDestroyedOn("")) { - return new LatLng(); + if (height > 65535) { + // we have seen edge cases where devices return incorrect values #6111 + Timber.e("Device returned an out of range height size, " + + "capping value at 65535 instead of " + height); + height = 65535; } - // wrap longitude values coming from core - return nativeGetLatLng(nativeMapViewPtr).wrap(); - } - public void resetPosition() { - if (isDestroyedOn("resetPosition")) { - return; - } - nativeResetPosition(nativeMapViewPtr); + _onViewportChanged(width, height); } - public double getPitch() { - if (isDestroyedOn("getPitch")) { - return 0; - } - return nativeGetPitch(nativeMapViewPtr); - } + private native void _onViewportChanged(int width, int height); - public void setPitch(double pitch, long duration) { - Timber.i("setLatLng %s - %s", pitch, duration); - if (isDestroyedOn("setPitch")) { - return; - } - nativeSetPitch(nativeMapViewPtr, pitch, duration); + void update() { + //TODO, this circle makes little sense atm... + Timber.w("TODO; Implement update()"); + onInvalidate(); } - public void scaleBy(double ds) { - if (isDestroyedOn("scaleBy")) { - return; - } - scaleBy(ds, Double.NaN, Double.NaN); - } - public void scaleBy(double ds, double cx, double cy) { - if (isDestroyedOn("scaleBy")) { - return; - } - scaleBy(ds, cx, cy, 0); + void moveBy(double dx, double dy) { + Timber.i("Move by %sx%s", dx, dy); + _moveBy(dx / pixelRatio, dy / pixelRatio); } - public void scaleBy(double ds, double cx, double cy, long duration) { - if (isDestroyedOn("scaleBy")) { - return; - } - nativeScaleBy(nativeMapViewPtr, ds, cx / pixelRatio, cy / pixelRatio, duration); - } + private native void _moveBy(double dx, double dy); - public void setScale(double scale) { - if (isDestroyedOn("setScale")) { - return; - } - setScale(scale, Double.NaN, Double.NaN); + @Deprecated + void moveBy(double dx, double dy, long duration) { + moveBy(dx, dy); } - public void setScale(double scale, double cx, double cy) { - if (isDestroyedOn("setScale")) { - return; - } - setScale(scale, cx, cy, 0); + void setLatLng(LatLng latLng) { + Timber.i("setLatLng %sx%s - %s", latLng.getLatitude(), latLng.getLongitude()); + setLatLng(latLng.getLatitude(), latLng.getLongitude()); } - public void setScale(double scale, double cx, double cy, long duration) { - if (isDestroyedOn("setScale")) { - return; - } - nativeSetScale(nativeMapViewPtr, scale, cx / pixelRatio, cy / pixelRatio, duration); + @Deprecated + void setLatLng(LatLng latLng, long duration) { + setLatLng(latLng); } - public double getScale() { - if (isDestroyedOn("getScale")) { - return 0; - } - return nativeGetScale(nativeMapViewPtr); + LatLng getLatLng() { + // wrap longitude values coming from core + return _getLatLng().wrap(); } - public void setZoom(double zoom) { - if (isDestroyedOn("setZoom")) { - return; - } - setZoom(zoom, 0); - } + private native LatLng _getLatLng(); - public void setZoom(double zoom, long duration) { - if (isDestroyedOn("setZoom")) { - return; - } - nativeSetZoom(nativeMapViewPtr, zoom, duration); + void scaleBy(double ds) { + scaleBy(ds, Double.NaN, Double.NaN); } - public double getZoom() { - if (isDestroyedOn("getZoom")) { - return 0; - } - return nativeGetZoom(nativeMapViewPtr); + void scaleBy(double ds, double cx, double cy) { + _scaleBy(ds, cx / pixelRatio, cy / pixelRatio); } - public void resetZoom() { - if (isDestroyedOn("resetZoom")) { - return; - } - nativeResetZoom(nativeMapViewPtr); + private native void _scaleBy(double ds, double cx, double cy); + + @Deprecated + void scaleBy(double ds, double cx, double cy, long duration) { + scaleBy(ds, cx, cy); } - public void setMinZoom(double zoom) { - if (isDestroyedOn("setMinZoom")) { - return; - } - nativeSetMinZoom(nativeMapViewPtr, zoom); + void setScale(double scale) { + setScale(scale, Double.NaN, Double.NaN); } - public double getMinZoom() { - if (isDestroyedOn("getMinZoom")) { - return 0; - } - return nativeGetMinZoom(nativeMapViewPtr); + void setScale(double scale, double cx, double cy) { + _setScale(scale, cx / pixelRatio, cy / pixelRatio); } - public void setMaxZoom(double zoom) { - if (isDestroyedOn("setMaxZoom")) { - return; - } - nativeSetMaxZoom(nativeMapViewPtr, zoom); + private native void _setScale(double scale, double cx, double cy); + + @Deprecated + void setScale(double scale, double cx, double cy, long duration) { + setScale(scale, cx, cy); } - public double getMaxZoom() { - if (isDestroyedOn("getMaxZoom")) { - return 0; - } - return nativeGetMaxZoom(nativeMapViewPtr); + @Deprecated + void setZoom(double zoom, long duration) { + setZoom(zoom); } - public void rotateBy(double sx, double sy, double ex, double ey) { - if (isDestroyedOn("rotateBy")) { - return; - } - rotateBy(sx, sy, ex, ey, 0); + void rotateBy(double sx, double sy, double ex, double ey) { + _rotateBy(sx / pixelRatio, sy / pixelRatio, ex, ey); } - public void rotateBy(double sx, double sy, double ex, double ey, - long duration) { - if (isDestroyedOn("rotateBy")) { - return; - } - nativeRotateBy(nativeMapViewPtr, sx / pixelRatio, sy / pixelRatio, ex, ey, duration); + private native void _rotateBy(double sx, double sy, double ex, double ey); + + @Deprecated + void rotateBy(double sx, double sy, double ex, double ey, long duration) { + rotateBy(sx, sy, ex, ey); } - public void setContentPadding(int[] padding) { - if (isDestroyedOn("setContentPadding")) { - return; - } - nativeSetContentPadding(nativeMapViewPtr, + void setContentPadding(int[] padding) { + setContentPadding( padding[1] / pixelRatio, padding[0] / pixelRatio, padding[3] / pixelRatio, padding[2] / pixelRatio); } - public void setBearing(double degrees) { - if (isDestroyedOn("setBearing")) { - return; - } - setBearing(degrees, 0); - } + native void setContentPadding(double top, double left, double bottom, double right); - public void setBearing(double degrees, long duration) { - if (isDestroyedOn("setBearing")) { - return; - } - nativeSetBearing(nativeMapViewPtr, degrees, duration); + @Deprecated + void setBearing(double degrees, long duration) { + setBearing(degrees); } - public void setBearing(double degrees, double cx, double cy) { - if (isDestroyedOn("setBearing")) { - return; - } - nativeSetBearingXY(nativeMapViewPtr, degrees, cx / pixelRatio, cy / pixelRatio); - } + native void setBearing(double degrees); - public void setBearing(double degrees, double fx, double fy, long duration) { - if (isDestroyedOn("setBearing")) { - return; - } - nativeSetFocalBearing(nativeMapViewPtr, degrees, fx / pixelRatio, fy / pixelRatio, duration); + void setBearing(double degrees, double cx, double cy) { + _setBearingXY(degrees, cx / pixelRatio, cy / pixelRatio); } - public double getBearing() { - if (isDestroyedOn("getBearing")) { - return 0; - } - return nativeGetBearing(nativeMapViewPtr); + @Deprecated + void setBearing(double degrees, double cx, double cy, long duration) { + setBearing(degrees, cx, cy); } - public void resetNorth() { - if (isDestroyedOn("resetNorth")) { - return; - } - nativeResetNorth(nativeMapViewPtr); - } + private native void _setBearingXY(double degrees, double cx, double cy); - public long addMarker(Marker marker) { - if (isDestroyedOn("addMarker")) { - return 0; - } + native double getBearing(); + + native void resetNorth(); + + long addMarker(Marker marker) { Marker[] markers = {marker}; - return nativeAddMarkers(nativeMapViewPtr, markers)[0]; + return addMarkers(markers)[0]; } - public long[] addMarkers(List markers) { - if (isDestroyedOn("addMarkers")) { - return new long[] {}; - } - return nativeAddMarkers(nativeMapViewPtr, markers.toArray(new Marker[markers.size()])); + long[] addMarkers(List markers) { + return addMarkers(markers.toArray(new Marker[markers.size()])); } - public long addPolyline(Polyline polyline) { - if (isDestroyedOn("addPolyline")) { - return 0; - } + native long[] addMarkers(Marker... markers); + + long addPolyline(Polyline polyline) { Polyline[] polylines = {polyline}; - return nativeAddPolylines(nativeMapViewPtr, polylines)[0]; + return addPolylines(polylines)[0]; } - public long[] addPolylines(List polylines) { - if (isDestroyedOn("addPolylines")) { - return new long[] {}; - } - return nativeAddPolylines(nativeMapViewPtr, polylines.toArray(new Polyline[polylines.size()])); + long[] addPolylines(List polylines) { + return addPolylines(polylines.toArray(new Polyline[polylines.size()])); } - public long addPolygon(Polygon polygon) { - if (isDestroyedOn("addPolygon")) { - return 0; - } + native long[] addPolylines(Polyline[] polylines); + + long addPolygon(Polygon polygon) { Polygon[] polygons = {polygon}; - return nativeAddPolygons(nativeMapViewPtr, polygons)[0]; + return addPolygons(polygons)[0]; } - public long[] addPolygons(List polygons) { - if (isDestroyedOn("addPolygons")) { - return new long[] {}; - } - return nativeAddPolygons(nativeMapViewPtr, polygons.toArray(new Polygon[polygons.size()])); + long[] addPolygons(List polygons) { + return addPolygons(polygons.toArray(new Polygon[polygons.size()])); } - public void updateMarker(Marker marker) { - if (isDestroyedOn("updateMarker")) { - return; - } + native long[] addPolygons(Polygon[] polygons); + + void updateMarker(Marker marker) { LatLng position = marker.getPosition(); - Icon icon = marker.getIcon(); - nativeUpdateMarker(nativeMapViewPtr, marker.getId(), position.getLatitude(), position.getLongitude(), icon.getId()); + updateMarker(marker.getId(), position.getLatitude(), position.getLongitude(), marker.getIcon().getId()); } - public void updatePolygon(Polygon polygon) { - if (isDestroyedOn("updatePolygon")) { - return; - } - nativeUpdatePolygon(nativeMapViewPtr, polygon.getId(), polygon); + private native void updateMarker(long markerId, double lat, double lon, String iconId); + + void updatePolygon(Polygon polygon) { + updatePolygon(polygon.getId(), polygon); } - public void updatePolyline(Polyline polyline) { - if (isDestroyedOn("updatePolyline")) { - return; - } - nativeUpdatePolyline(nativeMapViewPtr, polyline.getId(), polyline); + private native void updatePolygon(long polygonId, Polygon polygon); + + void updatePolyline(Polyline polyline) { + updatePolyline(polyline.getId(), polyline); } - public void removeAnnotation(long id) { - if (isDestroyedOn("removeAnnotation")) { - return; - } + private native void updatePolyline(long polylineId, Polyline polyline); + + void removeAnnotation(long id) { long[] ids = {id}; removeAnnotations(ids); } - public void removeAnnotations(long[] ids) { - if (isDestroyedOn("removeAnnotations")) { - return; - } - nativeRemoveAnnotations(nativeMapViewPtr, ids); - } + native void removeAnnotations(long[] id); - public long[] queryPointAnnotations(RectF rect) { - if (isDestroyedOn("queryPointAnnotations")) { - return new long[] {}; - } - return nativeQueryPointAnnotations(nativeMapViewPtr, rect); - } + native long[] queryPointAnnotations(RectF rect); - public void addAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels) { - if (isDestroyedOn("addAnnotationIcon")) { - return; - } - nativeAddAnnotationIcon(nativeMapViewPtr, symbol, width, height, scale, pixels); - } + native void addAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels); - public void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration) { - if (isDestroyedOn("setVisibleCoordinateBounds")) { - return; - } - nativeSetVisibleCoordinateBounds(nativeMapViewPtr, coordinates, padding, direction, duration); + @Deprecated + void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration) { + setVisibleCoordinateBounds(coordinates, padding, direction); } - public void onLowMemory() { - if (isDestroyedOn("onLowMemory")) { - return; - } - nativeOnLowMemory(nativeMapViewPtr); - } + native void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction); - public void setDebug(boolean debug) { - if (isDestroyedOn("setDebug")) { - return; - } - nativeSetDebug(nativeMapViewPtr, debug); - } + native void onLowMemory(); - public void cycleDebugOptions() { - if (isDestroyedOn("cycleDebugOptions")) { - return; - } - nativeToggleDebug(nativeMapViewPtr); - } + native void setDebug(boolean debug); - public boolean getDebug() { - if (isDestroyedOn("getDebug")) { - return false; - } - return nativeGetDebug(nativeMapViewPtr); - } + native void cycleDebugOptions(); - public boolean isFullyLoaded() { - if (isDestroyedOn("isFullyLoaded")) { - return false; - } - return nativeIsFullyLoaded(nativeMapViewPtr); - } + native boolean getDebug(); - public void setReachability(boolean status) { - if (isDestroyedOn("setReachability")) { - return; - } - nativeSetReachability(nativeMapViewPtr, status); + native boolean isFullyLoaded(); + + double getMetersPerPixelAtLatitude(double lat) { + return getMetersPerPixelAtLatitude(lat, getZoom()); } - public double getMetersPerPixelAtLatitude(double lat) { - if (isDestroyedOn("getMetersPerPixelAtLatitude")) { - return 0; - } - return nativeGetMetersPerPixelAtLatitude(nativeMapViewPtr, lat, getZoom()); + private native double getMetersPerPixelAtLatitude(double lat, double zoom); + + ProjectedMeters projectedMetersForLatLng(LatLng latLng) { + return projectedMetersForLatLng(latLng.getLatitude(), latLng.getLongitude()); } - public ProjectedMeters projectedMetersForLatLng(LatLng latLng) { - if (isDestroyedOn("projectedMetersForLatLng")) { - return null; - } - return nativeProjectedMetersForLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude()); + native ProjectedMeters projectedMetersForLatLng(double latitude, double longitude); + + LatLng latLngForProjectedMeters(ProjectedMeters projectedMeters) { + return latLngForProjectedMeters(projectedMeters.getNorthing(), projectedMeters.getEasting()).wrap(); } - public LatLng latLngForProjectedMeters(ProjectedMeters projectedMeters) { - if (isDestroyedOn("latLngForProjectedMeters")) { - return new LatLng(); - } - return nativeLatLngForProjectedMeters(nativeMapViewPtr, projectedMeters.getNorthing(), - projectedMeters.getEasting()).wrap(); + private native LatLng latLngForProjectedMeters(double northing, double easting); + + LatLng latLngForPixel(PointF pixel) { + return latLngForPixel(pixel.x / pixelRatio, pixel.y / pixelRatio).wrap(); } - public PointF pixelForLatLng(LatLng latLng) { - if (isDestroyedOn("pixelForLatLng")) { - return new PointF(); - } - PointF pointF = nativePixelForLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude()); + private native LatLng latLngForPixel(float x, float y); + + PointF pixelForLatLng(LatLng latLng) { + PointF pointF = pixelForLatLng(latLng.getLatitude(), latLng.getLongitude()); pointF.set(pointF.x * pixelRatio, pointF.y * pixelRatio); return pointF; } - public LatLng latLngForPixel(PointF pixel) { - if (isDestroyedOn("latLngForPixel")) { - return new LatLng(); - } - return nativeLatLngForPixel(nativeMapViewPtr, pixel.x / pixelRatio, pixel.y / pixelRatio).wrap(); - } + private native PointF pixelForLatLng(double lat, double lon); - public double getTopOffsetPixelsForAnnotationSymbol(String symbolName) { - if (isDestroyedOn("getTopOffsetPixelsForAnnotationSymbol")) { - return 0; - } - return nativeGetTopOffsetPixelsForAnnotationSymbol(nativeMapViewPtr, symbolName); - } + native double getTopOffsetPixelsForAnnotationSymbol(String symbolName); - public void jumpTo(double angle, LatLng center, double pitch, double zoom) { - if (isDestroyedOn("jumpTo")) { - return; - } - nativeJumpTo(nativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), pitch, zoom); + @Deprecated + void jumpTo(double angle, LatLng center, double pitch, double zoom) { + Timber.w("Deprecated"); } - public void easeTo(double angle, LatLng center, long duration, double pitch, double zoom, - boolean easingInterpolator) { - if (isDestroyedOn("easeTo")) { - return; - } - nativeEaseTo(nativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom, - easingInterpolator); + @Deprecated + void easeTo(double angle, LatLng center, long duration, double pitch, double zoom, + boolean easingInterpolator) { + Timber.w("Deprecated"); } - public void flyTo(double angle, LatLng center, long duration, double pitch, double zoom) { - if (isDestroyedOn("flyTo")) { - return; - } - nativeFlyTo(nativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom); - } - - public double[] getCameraValues() { - if (isDestroyedOn("getCameraValues")) { - return new double[] {}; - } - return nativeGetCameraValues(nativeMapViewPtr); + @Deprecated + void flyTo(double angle, LatLng center, long duration, double pitch, double zoom) { + Timber.w("Deprecated"); } // Runtime style Api - public long getTransitionDuration() { - return nativeGetTransitionDuration(nativeMapViewPtr); - } + native long getTransitionDuration(); - public void setTransitionDuration(long duration) { - nativeSetTransitionDuration(nativeMapViewPtr, duration); - } + native void setTransitionDuration(long duration); - public long getTransitionDelay() { - return nativeGetTransitionDelay(nativeMapViewPtr); - } + native long getTransitionDelay(); - public void setTransitionDelay(long delay) { - nativeSetTransitionDelay(nativeMapViewPtr, delay); - } + native void setTransitionDelay(long delay); - public Layer getLayer(String layerId) { - if (isDestroyedOn("getLayer")) { - return null; - } - return nativeGetLayer(nativeMapViewPtr, layerId); - } + native Layer getLayer(String layerId); - public void addLayer(@NonNull Layer layer, @Nullable String before) { - if (isDestroyedOn("")) { - return; - } - nativeAddLayer(nativeMapViewPtr, layer.getNativePtr(), before); + void addLayer(@NonNull Layer layer, @Nullable String before) throws CannotAddLayerException { + addLayer(layer.getNativePtr(), before); } - public void removeLayer(@NonNull String layerId) throws NoSuchLayerException { - if (isDestroyedOn("removeLayer")) { - return; - } - nativeRemoveLayerById(nativeMapViewPtr, layerId); - } + private native void addLayer(long layerPtr, String before) throws CannotAddLayerException; - public void removeLayer(@NonNull Layer layer) throws NoSuchLayerException { - if (isDestroyedOn("removeLayer")) { - return; - } - nativeRemoveLayer(nativeMapViewPtr, layer.getNativePtr()); + void removeLayer(@NonNull String layerId) throws NoSuchLayerException { + removeLayerById(layerId); } - public Source getSource(@NonNull String sourceId) { - if (isDestroyedOn("getSource")) { - return null; - } - return nativeGetSource(nativeMapViewPtr, sourceId); + private native void removeLayerById(String layerId) throws NoSuchLayerException; + + void removeLayer(@NonNull Layer layer) throws NoSuchLayerException { + removeLayer(layer.getNativePtr()); } - public void addSource(@NonNull Source source) { - if (isDestroyedOn("addSource")) { - return; - } - nativeAddSource(nativeMapViewPtr, source.getNativePtr()); + private native void removeLayer(long layerId) throws NoSuchLayerException; + + native Source getSource(String sourceId); + + void addSource(@NonNull Source source) throws CannotAddSourceException { + addSource(source.getNativePtr()); } - public void removeSource(@NonNull String sourceId) throws NoSuchSourceException { - if (isDestroyedOn("removeSource")) { - return; - } - nativeRemoveSourceById(nativeMapViewPtr, sourceId); + private native void addSource(long nativeSourcePtr) throws CannotAddSourceException; + + void removeSource(@NonNull String sourceId) throws NoSuchSourceException { + removeSourceById(sourceId); } - public void removeSource(@NonNull Source source) throws NoSuchSourceException { - if (isDestroyedOn("removeSource")) { - return; - } - nativeRemoveSource(nativeMapViewPtr, source.getNativePtr()); + private native void removeSourceById(String sourceId) throws NoSuchSourceException; + + void removeSource(@NonNull Source source) throws NoSuchSourceException { + removeSource(source.getNativePtr()); } - public void addImage(@NonNull String name, @NonNull Bitmap image) { - if (isDestroyedOn("addImage")) { - return; - } + private native void removeSource(long sourcePtr) throws NoSuchSourceException; + + void addImage(@NonNull String name, @NonNull Bitmap image) { // Check/correct config if (image.getConfig() != Bitmap.Config.ARGB_8888) { image = image.copy(Bitmap.Config.ARGB_8888, false); @@ -805,35 +485,27 @@ final class NativeMapView { float density = image.getDensity() == Bitmap.DENSITY_NONE ? Bitmap.DENSITY_NONE : image.getDensity(); float pixelRatio = density / DisplayMetrics.DENSITY_DEFAULT; - nativeAddImage(nativeMapViewPtr, name, image.getWidth(), image.getHeight(), pixelRatio, buffer.array()); + addImage(name, image.getWidth(), image.getHeight(), pixelRatio, buffer.array()); } - public void removeImage(String name) { - if (isDestroyedOn("removeImage")) { - return; - } - nativeRemoveImage(nativeMapViewPtr, name); - } + private native void addImage(String name, int width, int height, float pixelRatio, byte[] array); + + native void removeImage(String name); - // Feature querying + // Feature querying // @NonNull - public List queryRenderedFeatures(PointF coordinates, String... layerIds) { - if (isDestroyedOn("queryRenderedFeatures")) { - return new ArrayList<>(); - } - Feature[] features = nativeQueryRenderedFeaturesForPoint(nativeMapViewPtr, coordinates.x / pixelRatio, + List queryRenderedFeatures(PointF coordinates, String... layerIds) { + Feature[] features = queryRenderedFeaturesForPoint(coordinates.x / pixelRatio, coordinates.y / pixelRatio, layerIds); return features != null ? Arrays.asList(features) : new ArrayList(); } + private native Feature[] queryRenderedFeaturesForPoint(float x, float y, String[] layerIds); + @NonNull - public List queryRenderedFeatures(RectF coordinates, String... layerIds) { - if (isDestroyedOn("queryRenderedFeatures")) { - return new ArrayList<>(); - } - Feature[] features = nativeQueryRenderedFeaturesForBox( - nativeMapViewPtr, + List queryRenderedFeatures(RectF coordinates, String... layerIds) { + Feature[] features = queryRenderedFeaturesForBox( coordinates.left / pixelRatio, coordinates.top / pixelRatio, coordinates.right / pixelRatio, @@ -842,25 +514,14 @@ final class NativeMapView { return features != null ? Arrays.asList(features) : new ArrayList(); } - public void scheduleTakeSnapshot() { - if (isDestroyedOn("scheduleTakeSnapshot")) { - return; - } - nativeScheduleTakeSnapshot(nativeMapViewPtr); - } - - public void setApiBaseUrl(String baseUrl) { - if (isDestroyedOn("setApiBaseUrl")) { - return; - } - nativeSetAPIBaseURL(nativeMapViewPtr, baseUrl); - } + private native Feature[] queryRenderedFeaturesForBox(float left, float top, float right, + float bottom, String[] layerIds); - public float getPixelRatio() { + float getPixelRatio() { return pixelRatio; } - public Context getContext() { + Context getContext() { return mapView.getContext(); } @@ -876,11 +537,19 @@ final class NativeMapView { mapView.onInvalidate(); } - protected void wakeCallback() { + /** + * Called through JNI when the render thread needs to be woken up + */ + protected void onWake() { Timber.i("wake!"); mapView.requestRender(); } + /** + * Called through JNI when the map state changed + * + * @param rawChange the mbgl::MapChange as an int + */ protected void onMapChanged(final int rawChange) { Timber.i("onMapChanged: %s", rawChange); if (onMapChangedListeners != null) { @@ -895,235 +564,41 @@ final class NativeMapView { } } + /** + * Called through JNI if fps is enabled and the fps changed + * + * @param fps the Frames Per Second + */ protected void onFpsChanged(double fps) { mapView.onFpsChanged(fps); } + /** + * Called through JNI when a requested snapshot is ready + * + * @param bitmap the snapshot as a bitmap + */ protected void onSnapshotReady(Bitmap bitmap) { if (snapshotReadyCallback != null && bitmap != null) { snapshotReadyCallback.onSnapshotReady(bitmap); } } - // - // JNI methods - // - - private native long nativeCreate(String cachePath, String dataPath, String apkPath, float pixelRatio, - int availableProcessors, long totalMemory); - - private native void nativeDestroy(long nativeMapViewPtr); - - private native void nativeInitializeDisplay(long nativeMapViewPtr); - - private native void nativeTerminateDisplay(long nativeMapViewPtr); - - private native void nativeInitializeContext(long nativeMapViewPtr); - - private native void nativeTerminateContext(long nativeMapViewPtr); - - private native void nativeCreateSurface(long nativeMapViewPtr, - Surface surface); - - private native void nativeDestroySurface(long nativeMapViewPtr); - - private native void nativeUpdate(long nativeMapViewPtr); - - private native void nativeRender(long nativeMapViewPtr); - - private native void nativeOnViewportChanged(long nativeMapViewPtr, int width, int height); - - private native void nativeAddClass(long nativeMapViewPtr, String clazz); - - private native void nativeRemoveClass(long nativeMapViewPtr, String clazz); + native void setReachability(boolean status); - private native boolean nativeHasClass(long nativeMapViewPtr, String clazz); + native double[] getCameraValues(); - private native void nativeSetClasses(long nativeMapViewPtr, - List classes); + native void scheduleSnapshot(); - private native List nativeGetClasses(long nativeMapViewPtr); + native void setApiBaseUrl(String baseUrl); - private native void nativeSetStyleUrl(long nativeMapViewPtr, String url); - - private native String nativeGetStyleUrl(long nativeMapViewPtr); - - private native void nativeSetStyleJson(long nativeMapViewPtr, String newStyleJson); - - private native String nativeGetStyleJson(long nativeMapViewPtr); - - private native void nativeSetAccessToken(long nativeMapViewPtr, String accessToken); - - private native String nativeGetAccessToken(long nativeMapViewPtr); - - private native void nativeCancelTransitions(long nativeMapViewPtr); - - private native void nativeSetGestureInProgress(long nativeMapViewPtr, boolean inProgress); - - private native void nativeMoveBy(long nativeMapViewPtr, double dx, - double dy, long duration); - - private native void nativeSetLatLng(long nativeMapViewPtr, double latitude, double longitude, - long duration); - - private native LatLng nativeGetLatLng(long nativeMapViewPtr); - - private native void nativeResetPosition(long nativeMapViewPtr); - - private native double nativeGetPitch(long nativeMapViewPtr); - - private native void nativeSetPitch(long nativeMapViewPtr, double pitch, long duration); - - private native void nativeScaleBy(long nativeMapViewPtr, double ds, - double cx, double cy, long duration); - - private native void nativeSetScale(long nativeMapViewPtr, double scale, - double cx, double cy, long duration); - - private native double nativeGetScale(long nativeMapViewPtr); - - private native void nativeSetZoom(long nativeMapViewPtr, double zoom, - long duration); - - private native double nativeGetZoom(long nativeMapViewPtr); - - private native void nativeResetZoom(long nativeMapViewPtr); - - private native void nativeSetMinZoom(long nativeMapViewPtr, double zoom); - - private native double nativeGetMinZoom(long nativeMapViewPtr); - - private native void nativeSetMaxZoom(long nativeMapViewPtr, double zoom); - - private native double nativeGetMaxZoom(long nativeMapViewPtr); - - private native void nativeRotateBy(long nativeMapViewPtr, double sx, - double sy, double ex, double ey, long duration); - - private native void nativeSetContentPadding(long nativeMapViewPtr, double top, double left, double bottom, - double right); - - private native void nativeSetBearing(long nativeMapViewPtr, double degrees, - long duration); - - private native void nativeSetBearingXY(long nativeMapViewPtr, double degrees, - double cx, double cy); - - private native void nativeSetFocalBearing(long nativeMapViewPtr, double degrees, - double fx, double fy, long duration); - - private native double nativeGetBearing(long nativeMapViewPtr); - - private native void nativeResetNorth(long nativeMapViewPtr); - - private native void nativeUpdateMarker(long nativeMapViewPtr, long markerId, double lat, double lon, String iconId); - - private native long[] nativeAddMarkers(long nativeMapViewPtr, Marker[] markers); - - private native long[] nativeAddPolylines(long nativeMapViewPtr, Polyline[] polylines); - - private native long[] nativeAddPolygons(long nativeMapViewPtr, Polygon[] polygons); - - private native void nativeRemoveAnnotations(long nativeMapViewPtr, long[] id); - - private native long[] nativeQueryPointAnnotations(long nativeMapViewPtr, RectF rect); - - private native void nativeAddAnnotationIcon(long nativeMapViewPtr, String symbol, - int width, int height, float scale, byte[] pixels); - - private native void nativeSetVisibleCoordinateBounds(long nativeMapViewPtr, LatLng[] coordinates, - RectF padding, double direction, long duration); - - private native void nativeOnLowMemory(long nativeMapViewPtr); - - private native void nativeSetDebug(long nativeMapViewPtr, boolean debug); - - private native void nativeToggleDebug(long nativeMapViewPtr); - - private native boolean nativeGetDebug(long nativeMapViewPtr); - - private native boolean nativeIsFullyLoaded(long nativeMapViewPtr); - - private native void nativeSetReachability(long nativeMapViewPtr, boolean status); - - private native double nativeGetMetersPerPixelAtLatitude(long nativeMapViewPtr, double lat, double zoom); - - private native ProjectedMeters nativeProjectedMetersForLatLng(long nativeMapViewPtr, double latitude, - double longitude); - - private native LatLng nativeLatLngForProjectedMeters(long nativeMapViewPtr, double northing, double easting); - - private native PointF nativePixelForLatLng(long nativeMapViewPtr, double lat, double lon); - - private native LatLng nativeLatLngForPixel(long nativeMapViewPtr, float x, float y); - - private native double nativeGetTopOffsetPixelsForAnnotationSymbol(long nativeMapViewPtr, String symbolName); - - private native void nativeJumpTo(long nativeMapViewPtr, double angle, double latitude, double longitude, - double pitch, double zoom); - - private native void nativeEaseTo(long nativeMapViewPtr, double angle, double latitude, double longitude, - long duration, double pitch, double zoom, boolean easingInterpolator); - - private native void nativeFlyTo(long nativeMapViewPtr, double angle, double latitude, double longitude, - long duration, double pitch, double zoom); - - private native double[] nativeGetCameraValues(long nativeMapViewPtr); - - private native long nativeGetTransitionDuration(long nativeMapViewPtr); - - private native void nativeSetTransitionDuration(long nativeMapViewPtr, long duration); - - private native long nativeGetTransitionDelay(long nativeMapViewPtr); - - private native void nativeSetTransitionDelay(long nativeMapViewPtr, long delay); - - private native Layer nativeGetLayer(long nativeMapViewPtr, String layerId); - - private native void nativeAddLayer(long nativeMapViewPtr, long layerPtr, String before); - - private native void nativeRemoveLayerById(long nativeMapViewPtr, String layerId) throws NoSuchLayerException; - - private native void nativeRemoveLayer(long nativeMapViewPtr, long layerId) throws NoSuchLayerException; - - private native Source nativeGetSource(long nativeMapViewPtr, String sourceId); - - private native void nativeAddSource(long nativeMapViewPtr, long nativeSourcePtr); - - private native void nativeRemoveSourceById(long nativeMapViewPtr, String sourceId) throws NoSuchSourceException; - - private native void nativeRemoveSource(long nativeMapViewPtr, long sourcePtr) throws NoSuchSourceException; - - private native void nativeAddImage(long nativeMapViewPtr, String name, int width, int height, float pixelRatio, - byte[] array); - - private native void nativeRemoveImage(long nativeMapViewPtr, String name); - - private native void nativeUpdatePolygon(long nativeMapViewPtr, long polygonId, Polygon polygon); - - private native void nativeUpdatePolyline(long nativeMapviewPtr, long polylineId, Polyline polyline); - - private native void nativeScheduleTakeSnapshot(long nativeMapViewPtr); - - private native Feature[] nativeQueryRenderedFeaturesForPoint(long nativeMapViewPtr, float x, float y, String[] - layerIds); - - private native Feature[] nativeQueryRenderedFeaturesForBox(long nativeMapViewPtr, float left, float top, float right, - float bottom, String[] layerIds); - - private native void nativeSetAPIBaseURL(long nativeMapViewPtr, String baseUrl); + native void enableFps(boolean enable); int getWidth() { - if (isDestroyedOn("")) { - return 0; - } return mapView.getWidth(); } int getHeight() { - if (isDestroyedOn("")) { - return 0; - } return mapView.getHeight(); } @@ -1145,7 +620,7 @@ final class NativeMapView { void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback) { snapshotReadyCallback = callback; - scheduleTakeSnapshot(); + scheduleSnapshot(); render(); } } diff --git a/platform/android/config.cmake b/platform/android/config.cmake index 9491071f2a..c24b816c04 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -15,7 +15,7 @@ if ((ANDROID_ABI STREQUAL "armeabi") OR (ANDROID_ABI STREQUAL "armeabi-v7a") OR set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=gold -Wl,--icf=safe ${CMAKE_SHARED_LINKER_FLAGS}") endif() -mason_use(jni.hpp VERSION 2.0.0-1 HEADER_ONLY) +mason_use(jni.hpp VERSION 3.0.0 HEADER_ONLY) mason_use(libzip VERSION 1.1.3) mason_use(nunicode VERSION 1.7.1) mason_use(sqlite VERSION 3.14.2) @@ -137,6 +137,32 @@ macro(mbgl_platform_core) platform/android/src/native_map_view.cpp platform/android/src/native_map_view.hpp + # Java core classes + platform/android/src/java/util.cpp + platform/android/src/java/util.hpp + + # Graphics + platform/android/src/graphics/pointf.cpp + platform/android/src/graphics/pointf.hpp + platform/android/src/graphics/rectf.cpp + platform/android/src/graphics/rectf.hpp + + # Geometry + platform/android/src/geometry/feature.cpp + platform/android/src/geometry/feature.hpp + platform/android/src/geometry/lat_lng.cpp + platform/android/src/geometry/lat_lng.hpp + platform/android/src/geometry/projected_meters.cpp + platform/android/src/geometry/projected_meters.hpp + + # Annotation + platform/android/src/annotation/marker.cpp + platform/android/src/annotation/marker.hpp + platform/android/src/annotation/polygon.cpp + platform/android/src/annotation/polygon.hpp + platform/android/src/annotation/polyline.cpp + platform/android/src/annotation/polyline.hpp + # Main jni bindings platform/android/src/attach_env.cpp platform/android/src/attach_env.hpp diff --git a/platform/android/src/annotation/marker.cpp b/platform/android/src/annotation/marker.cpp new file mode 100644 index 0000000000..fa709fd1c9 --- /dev/null +++ b/platform/android/src/annotation/marker.cpp @@ -0,0 +1,27 @@ +#include "marker.hpp" + +namespace mbgl { +namespace android { + +jni::Class Marker::javaClass; + +mbgl::Point Marker::getPosition(jni::JNIEnv& env, jni::Object marker) { + static auto positionField = Marker::javaClass.GetField>(env, "position"); + auto position = marker.Get(env, positionField); + return LatLng::getGeometry(env, position); +} + +std::string Marker::getIconId(jni::JNIEnv& env, jni::Object marker) { + static auto iconIdField = Marker::javaClass.GetField(env, "iconId"); + auto jIconId = marker.Get(env, iconIdField); + return jni::Make(env, jIconId); +} + +void Marker::registerNative(jni::JNIEnv& env) { + // Lookup the class + Marker::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/annotation/marker.hpp b/platform/android/src/annotation/marker.hpp new file mode 100644 index 0000000000..b11a225245 --- /dev/null +++ b/platform/android/src/annotation/marker.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#include + +#include "../geometry/lat_lng.hpp" + +namespace mbgl { +namespace android { + +class Marker : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Marker"; }; + + static jni::Class javaClass; + + static mbgl::Point getPosition(jni::JNIEnv&, jni::Object); + + static std::string getIconId(jni::JNIEnv&, jni::Object); + + static void registerNative(jni::JNIEnv&); + +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/annotation/multi_point.hpp b/platform/android/src/annotation/multi_point.hpp new file mode 100644 index 0000000000..e1152dfd60 --- /dev/null +++ b/platform/android/src/annotation/multi_point.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +#include "../geometry/lat_lng.hpp" +#include "../java/util.hpp" + +namespace mbgl { +namespace android { + +class MultiPoint : protected mbgl::util::noncopyable { + +protected: + + template + static Geometry toGeometry(JNIEnv& env, jni::Object pointsList) { + NullCheck(env, &pointsList); + auto jarray = java::util::List::toArray(env, pointsList); + NullCheck(env, &jarray); + + std::size_t size = jarray.Length(env); + + Geometry geometry; + geometry.reserve(size); + + for (std::size_t i = 0; i < size; i++) { + auto latLng = jarray.Get(env, i); + NullCheck(env, &latLng); + + geometry.push_back(LatLng::getGeometry(env, latLng)); + + jni::DeleteLocalRef(env, latLng); + } + + jni::DeleteLocalRef(env, jarray); + return geometry; + } +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/annotation/polygon.cpp b/platform/android/src/annotation/polygon.cpp new file mode 100644 index 0000000000..b0419628b0 --- /dev/null +++ b/platform/android/src/annotation/polygon.cpp @@ -0,0 +1,49 @@ +#include "polygon.hpp" + +#include "../conversion/color.hpp" + +namespace mbgl { +namespace android { + +jni::Class Polygon::javaClass; + +mbgl::FillAnnotation Polygon::toAnnotation(jni::JNIEnv& env, jni::Object polygon) { + auto points = Polygon::getPoints(env, polygon); + + mbgl::FillAnnotation annotation { mbgl::Polygon { MultiPoint::toGeometry>(env, points) } }; + annotation.opacity = { Polygon::getOpacity(env, polygon) }; + annotation.color = { Polygon::getFillColor(env, polygon) }; + annotation.outlineColor = { Polygon::getOutlineColor(env, polygon) }; + + jni::DeleteLocalRef(env, points); + + return annotation; +} + +jni::Object Polygon::getPoints(jni::JNIEnv& env, jni::Object polygon) { + static auto field = Polygon::javaClass.GetField>(env, "points"); + return polygon.Get(env, field); +} + +float Polygon::getOpacity(jni::JNIEnv& env, jni::Object polygon) { + static auto field = Polygon::javaClass.GetField(env, "alpha"); + return polygon.Get(env, field); +} + +mbgl::Color Polygon::getFillColor(jni::JNIEnv& env, jni::Object polygon) { + static auto field = Polygon::javaClass.GetField(env, "fillColor"); + return *conversion::convert(env, polygon.Get(env, field)); +} + +mbgl::Color Polygon::getOutlineColor(jni::JNIEnv& env, jni::Object polygon) { + static auto field = Polygon::javaClass.GetField(env, "strokeColor"); + return *conversion::convert(env, polygon.Get(env, field)); +} + +void Polygon::registerNative(jni::JNIEnv& env) { + Polygon::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/annotation/polygon.hpp b/platform/android/src/annotation/polygon.hpp new file mode 100644 index 0000000000..658aa5344b --- /dev/null +++ b/platform/android/src/annotation/polygon.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +#include + +#include "multi_point.hpp" + +#include "../geometry/lat_lng.hpp" +#include "../java/util.hpp" + +namespace mbgl { +namespace android { + +class Polygon : private MultiPoint { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polygon"; }; + + static jni::Class javaClass; + + static mbgl::FillAnnotation toAnnotation(jni::JNIEnv&, jni::Object); + + static void registerNative(jni::JNIEnv&); + +private: + + static jni::Object getPoints(jni::JNIEnv&, jni::Object); + + static float getOpacity(jni::JNIEnv&, jni::Object); + + static mbgl::Color getFillColor(jni::JNIEnv&, jni::Object); + + static mbgl::Color getOutlineColor(jni::JNIEnv&, jni::Object); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/annotation/polyline.cpp b/platform/android/src/annotation/polyline.cpp new file mode 100644 index 0000000000..3723dc1871 --- /dev/null +++ b/platform/android/src/annotation/polyline.cpp @@ -0,0 +1,49 @@ +#include "polyline.hpp" + +#include "../conversion/color.hpp" + +namespace mbgl { +namespace android { + +jni::Class Polyline::javaClass; + +mbgl::LineAnnotation Polyline::toAnnotation(jni::JNIEnv& env, jni::Object polyline) { + auto points = Polyline::getPoints(env, polyline); + + mbgl::LineAnnotation annotation { MultiPoint::toGeometry>(env, points) }; + annotation.opacity = { Polyline::getOpacity(env, polyline) }; + annotation.color = { Polyline::getColor(env, polyline) }; + annotation.width = { Polyline::getWidth(env, polyline) }; + + jni::DeleteLocalRef(env, points); + + return annotation; +} + +jni::Object Polyline::getPoints(jni::JNIEnv& env, jni::Object polyline) { + static auto field = Polyline::javaClass.GetField>(env, "points"); + return polyline.Get(env, field); +} + +float Polyline::getOpacity(jni::JNIEnv& env, jni::Object polyline) { + static auto field = Polyline::javaClass.GetField(env, "alpha"); + return polyline.Get(env, field); +} + +mbgl::Color Polyline::getColor(jni::JNIEnv& env, jni::Object polyline) { + static auto field = Polyline::javaClass.GetField(env, "color"); + return *conversion::convert(env, polyline.Get(env, field)); +} + +float Polyline::getWidth(jni::JNIEnv& env, jni::Object polyline) { + static auto field = Polyline::javaClass.GetField(env, "width"); + return polyline.Get(env, field); +} + +void Polyline::registerNative(jni::JNIEnv& env) { + Polyline::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/annotation/polyline.hpp b/platform/android/src/annotation/polyline.hpp new file mode 100644 index 0000000000..bcc616a5f7 --- /dev/null +++ b/platform/android/src/annotation/polyline.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +#include + +#include "multi_point.hpp" + +#include "../geometry/lat_lng.hpp" +#include "../java/util.hpp" + +namespace mbgl { +namespace android { + +class Polyline : private MultiPoint { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polyline"; }; + + static jni::Class javaClass; + + static mbgl::LineAnnotation toAnnotation(jni::JNIEnv&, jni::Object); + + static void registerNative(jni::JNIEnv&); + +private: + + static jni::Object getPoints(jni::JNIEnv&, jni::Object); + + static float getOpacity(jni::JNIEnv&, jni::Object); + + static mbgl::Color getColor(jni::JNIEnv&, jni::Object); + + static float getWidth(jni::JNIEnv&, jni::Object); +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/conversion/collection.hpp b/platform/android/src/conversion/collection.hpp index 0f67c685f4..da5eed64d2 100644 --- a/platform/android/src/conversion/collection.hpp +++ b/platform/android/src/conversion/collection.hpp @@ -38,6 +38,19 @@ inline std::vector toVector(JNIEnv& env, jni::jarray& return vector; } +inline std::vector toVector(JNIEnv& env, jni::Array array) { + std::vector vector; + std::size_t len = array.Length(env); + + for (std::size_t i = 0; i < len; i++) { + jni::String jstr = array.Get(env, i); + vector.push_back(*convert(env, jstr)); + jni::DeleteLocalRef(env, jstr); + } + + return vector; +} + } } } diff --git a/platform/android/src/conversion/color.hpp b/platform/android/src/conversion/color.hpp new file mode 100644 index 0000000000..40aa68d4a9 --- /dev/null +++ b/platform/android/src/conversion/color.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "conversion.hpp" + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +template <> +struct Converter { + Result operator()(jni::JNIEnv&, const int& color) const { + float r = (color >> 16) & 0xFF; + float g = (color >> 8) & 0xFF; + float b = (color) & 0xFF; + float a = (color >> 24) & 0xFF; + return { mbgl::Color( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ) }; + } +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/platform/android/src/geometry/conversion/feature.hpp b/platform/android/src/geometry/conversion/feature.hpp index 18f2741d66..921138e859 100644 --- a/platform/android/src/geometry/conversion/feature.hpp +++ b/platform/android/src/geometry/conversion/feature.hpp @@ -3,6 +3,7 @@ #include "../../conversion/constant.hpp" #include "../../conversion/conversion.hpp" #include "geometry.hpp" +#include "../../gson/json_object.hpp" #include #include @@ -10,6 +11,7 @@ #include #include "../../jni/local_object.hpp" +#include "../feature.hpp" #include #include @@ -168,39 +170,45 @@ struct Converter> { template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::Feature& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Feature")).release(); - static jni::jmethodID* fromGeometry = &jni::GetStaticMethodID(env, *javaClass, "fromGeometry", "(Lcom/mapbox/services/commons/geojson/Geometry;Lcom/google/gson/JsonObject;Ljava/lang/String;)Lcom/mapbox/services/commons/geojson/Feature;"); +struct Converter, mbgl::Feature> { + Result> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const { // Convert Id FeatureIdVisitor idEvaluator; std::string id = (value.id) ? mapbox::geometry::identifier::visit(value.id.value(), idEvaluator) : ""; - jni::LocalObject jid = jni::NewLocalObject(env, *convert(env, id)); + auto jid = jni::Make(env, id); // Convert properties - jni::LocalObject properties = jni::NewLocalObject(env, *convert(env, value.properties)); + auto properties = jni::Object(*convert(env, value.properties)); // Convert geometry - jni::LocalObject geometry = jni::NewLocalObject(env, *convert(env, value.geometry)); + auto geometry = jni::Object(*convert(env, value.geometry)); // Create feature - return {reinterpret_cast(jni::CallStaticMethod(env, *javaClass, *fromGeometry, geometry.get(), properties.get(), jid.get()))}; + auto feature = Feature::fromGeometry(env, geometry, properties, jid); + + //Cleanup + jni::DeleteLocalRef(env, jid); + jni::DeleteLocalRef(env, geometry); + jni::DeleteLocalRef(env, properties); + + return feature; } }; template <> -struct Converter*, std::vector> { - Result*> operator()(jni::JNIEnv& env, const std::vector& value) const { - static jni::jclass* featureClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Feature")).release(); - jni::jarray& jarray = jni::NewObjectArray(env, value.size(), *featureClass); +struct Converter>, std::vector> { + Result>> operator()(jni::JNIEnv& env, const std::vector& value) const { + + auto features = jni::Array>::New(env, value.size(), Feature::javaClass); for(size_t i = 0; i < value.size(); i = i + 1) { - jni::LocalObject converted = jni::NewLocalObject(env, *convert(env, value.at(i))); - jni::SetObjectArrayElement(env, jarray, i, converted.get()); + auto converted = *convert, mbgl::Feature>(env, value.at(i)); + features.Set(env, i, converted); + jni::DeleteLocalRef(env, converted); } - return {&jarray}; + return {features}; } }; diff --git a/platform/android/src/geometry/feature.cpp b/platform/android/src/geometry/feature.cpp new file mode 100644 index 0000000000..5355d50ab7 --- /dev/null +++ b/platform/android/src/geometry/feature.cpp @@ -0,0 +1,20 @@ +#include "feature.hpp" + +namespace mbgl { +namespace android { + +jni::Object Feature::fromGeometry(jni::JNIEnv& env, jni::Object geometry, jni::Object properties, jni::String id) { + static auto method = Feature::javaClass.GetStaticMethod (jni::Object, jni::Object, jni::String)>(env, "fromGeometry"); + return Feature::javaClass.Call(env, method, geometry, properties, id); +} + +void Feature::registerNative(jni::JNIEnv& env) { + // Lookup the class + Feature::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class Feature::javaClass; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geometry/feature.hpp b/platform/android/src/geometry/feature.hpp new file mode 100644 index 0000000000..7f2733430c --- /dev/null +++ b/platform/android/src/geometry/feature.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +#include + +#include "geometry.hpp" +#include "../gson/json_object.hpp" + +namespace mbgl { +namespace android { + +class Feature : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Feature"; }; + + static jni::Object fromGeometry(jni::JNIEnv&, jni::Object, jni::Object, jni::String); + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); + +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geometry/geometry.hpp b/platform/android/src/geometry/geometry.hpp new file mode 100644 index 0000000000..5c8ae39181 --- /dev/null +++ b/platform/android/src/geometry/geometry.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace mbgl { +namespace android { + +class Geometry : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Geometry"; }; + +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geometry/lat_lng.cpp b/platform/android/src/geometry/lat_lng.cpp new file mode 100644 index 0000000000..9cf3630107 --- /dev/null +++ b/platform/android/src/geometry/lat_lng.cpp @@ -0,0 +1,31 @@ +#include "lat_lng.hpp" + +namespace mbgl { +namespace android { + +jni::Object LatLng::New(jni::JNIEnv& env, double latitude, double longitude) { + static auto constructor = LatLng::javaClass.GetConstructor(env); + return LatLng::javaClass.New(env, constructor, latitude, longitude); +} + +mbgl::Point LatLng::getGeometry(jni::JNIEnv& env, jni::Object latLng) { + static auto latitudeField = LatLng::javaClass.GetField(env, "latitude"); + static auto longitudeField = LatLng::javaClass.GetField(env, "longitude"); + return mbgl::Point(latLng.Get(env, longitudeField), latLng.Get(env, latitudeField)); +} + +mbgl::LatLng LatLng::getLatLng(jni::JNIEnv& env, jni::Object latLng) { + auto point = LatLng::getGeometry(env, latLng); + return mbgl::LatLng(point.y, point.x); +} + +void LatLng::registerNative(jni::JNIEnv& env) { + // Lookup the class + LatLng::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class LatLng::javaClass; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geometry/lat_lng.hpp b/platform/android/src/geometry/lat_lng.hpp new file mode 100644 index 0000000000..1ac32ae32e --- /dev/null +++ b/platform/android/src/geometry/lat_lng.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +#include + +namespace mbgl { +namespace android { + +class LatLng : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLng"; }; + + static jni::Object New(jni::JNIEnv&, double, double); + + static mbgl::Point getGeometry(jni::JNIEnv&, jni::Object); + + static mbgl::LatLng getLatLng(jni::JNIEnv&, jni::Object); + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); + +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geometry/projected_meters.cpp b/platform/android/src/geometry/projected_meters.cpp new file mode 100644 index 0000000000..f3d9d1b0ef --- /dev/null +++ b/platform/android/src/geometry/projected_meters.cpp @@ -0,0 +1,20 @@ +#include "projected_meters.hpp" + +namespace mbgl { +namespace android { + +jni::Object ProjectedMeters::New(jni::JNIEnv& env, double northing, double easting) { + static auto constructor = ProjectedMeters::javaClass.GetConstructor(env); + return ProjectedMeters::javaClass.New(env, constructor, northing, easting); +} + +void ProjectedMeters::registerNative(jni::JNIEnv& env) { + // Lookup the class + ProjectedMeters::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class ProjectedMeters::javaClass; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/geometry/projected_meters.hpp b/platform/android/src/geometry/projected_meters.hpp new file mode 100644 index 0000000000..9b70967b5d --- /dev/null +++ b/platform/android/src/geometry/projected_meters.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { +namespace android { + +class ProjectedMeters : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/ProjectedMeters"; }; + + static jni::Object New(jni::JNIEnv&, double, double); + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); + +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/graphics/pointf.cpp b/platform/android/src/graphics/pointf.cpp new file mode 100644 index 0000000000..6e91b81416 --- /dev/null +++ b/platform/android/src/graphics/pointf.cpp @@ -0,0 +1,20 @@ +#include "pointf.hpp" + +namespace mbgl { +namespace android { + +jni::Object PointF::New(jni::JNIEnv& env, float x, float y) { + static auto constructor = PointF::javaClass.GetConstructor(env); + return PointF::javaClass.New(env, constructor, x, y); +} + +void PointF::registerNative(jni::JNIEnv& env) { + // Lookup the class + PointF::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class PointF::javaClass; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/graphics/pointf.hpp b/platform/android/src/graphics/pointf.hpp new file mode 100644 index 0000000000..ea25ad2b40 --- /dev/null +++ b/platform/android/src/graphics/pointf.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class PointF : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "android/graphics/PointF"; }; + + static jni::Object New(jni::JNIEnv&, float, float); + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); + +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/graphics/rectf.cpp b/platform/android/src/graphics/rectf.cpp new file mode 100644 index 0000000000..1b375dad18 --- /dev/null +++ b/platform/android/src/graphics/rectf.cpp @@ -0,0 +1,35 @@ +#include "rectf.hpp" + +namespace mbgl { +namespace android { + +float RectF::getLeft(jni::JNIEnv& env, jni::Object rectf) { + static auto field = RectF::javaClass.GetField(env, "left"); + return rectf.Get(env, field); +} + +float RectF::getTop(jni::JNIEnv& env, jni::Object rectf) { + static auto field = RectF::javaClass.GetField(env, "top"); + return rectf.Get(env, field); +} + +float RectF::getRight(jni::JNIEnv& env, jni::Object rectf) { + static auto field = RectF::javaClass.GetField(env, "right"); + return rectf.Get(env, field); +} + +float RectF::getBottom(jni::JNIEnv& env, jni::Object rectf) { + static auto field = RectF::javaClass.GetField(env, "bottom"); + return rectf.Get(env, field); +} + +void RectF::registerNative(jni::JNIEnv& env) { + // Lookup the class + RectF::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class RectF::javaClass; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/graphics/rectf.hpp b/platform/android/src/graphics/rectf.hpp new file mode 100644 index 0000000000..0f3a7756d5 --- /dev/null +++ b/platform/android/src/graphics/rectf.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { + +class RectF : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "android/graphics/RectF"; }; + + static float getLeft(jni::JNIEnv&, jni::Object); + + static float getTop(jni::JNIEnv&, jni::Object); + + static float getRight(jni::JNIEnv&, jni::Object); + + static float getBottom(jni::JNIEnv&, jni::Object); + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); + +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/gson/json_object.hpp b/platform/android/src/gson/json_object.hpp new file mode 100644 index 0000000000..a7de0b1978 --- /dev/null +++ b/platform/android/src/gson/json_object.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace mbgl { +namespace android { + +class JsonObject : private mbgl::util::noncopyable { +public: + static constexpr auto Name() { return "com/google/gson/JsonObject"; }; + +}; + + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/java/util.cpp b/platform/android/src/java/util.cpp new file mode 100644 index 0000000000..c630e403d9 --- /dev/null +++ b/platform/android/src/java/util.cpp @@ -0,0 +1,18 @@ +#include "util.hpp" + +namespace mbgl { +namespace android { +namespace java { +namespace util { + +jni::Class List::javaClass; + +void registerNative(jni::JNIEnv& env) { + List::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + + +} // namespace util +} // namespace java +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/java/util.hpp b/platform/android/src/java/util.hpp new file mode 100644 index 0000000000..1a552c7124 --- /dev/null +++ b/platform/android/src/java/util.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include + +namespace mbgl { +namespace android { +namespace java { +namespace util { + +class List : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "java/util/List"; }; + + template + static jni::Array> toArray(jni::JNIEnv& env, jni::Object list) { + static auto toArray = List::javaClass.GetMethod> ()>(env, "toArray"); + return (jni::Array>) list.Call(env, toArray); + }; + + static jni::Class javaClass; + +}; + +void registerNative(jni::JNIEnv&); + + +} // namespace util +} // namespace java +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index 3acb987445..e1164d3d2a 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -19,12 +19,19 @@ #include "style/functions/identity_stops.hpp" #include "style/functions/interval_stops.hpp" #include "style/functions/stop.hpp" +#include "annotation/marker.hpp" +#include "annotation/polygon.hpp" +#include "annotation/polyline.hpp" +#include "graphics/pointF.hpp" +#include "graphics/rectF.hpp" +#include "geometry/feature.hpp" +#include "geometry/lat_lng.hpp" +#include "geometry/projected_meters.hpp" #include "style/layers/layers.hpp" #include "style/sources/sources.hpp" #include "conversion/conversion.hpp" #include "conversion/collection.hpp" -#include "geometry/conversion/feature.hpp" #include #include @@ -42,8 +49,6 @@ #include -#include - #pragma clang diagnostic ignored "-Wunused-parameter" namespace mbgl { @@ -58,17 +63,6 @@ std::string dataPath; std::string apkPath; std::string androidRelease; -jni::jmethodID* onInvalidateId = nullptr; -jni::jmethodID* wakeCallbackId = nullptr; -jni::jmethodID* onMapChangedId = nullptr; -jni::jmethodID* onFpsChangedId = nullptr; -jni::jmethodID* onSnapshotReadyId = nullptr; - -jni::jclass* latLngClass = nullptr; -jni::jmethodID* latLngConstructorId = nullptr; -jni::jfieldID* latLngLatitudeId = nullptr; -jni::jfieldID* latLngLongitudeId = nullptr; - jni::jclass* latLngBoundsClass = nullptr; jni::jmethodID* latLngBoundsConstructorId = nullptr; jni::jfieldID* latLngBoundsLatNorthId = nullptr; @@ -76,49 +70,6 @@ jni::jfieldID* latLngBoundsLatSouthId = nullptr; jni::jfieldID* latLngBoundsLonEastId = nullptr; jni::jfieldID* latLngBoundsLonWestId = nullptr; -jni::jclass* iconClass = nullptr; -jni::jfieldID* iconIdId = nullptr; - -jni::jclass* markerClass = nullptr; -jni::jfieldID* markerPositionId = nullptr; -jni::jfieldID* markerIconId = nullptr; -jni::jfieldID* markerIdId = nullptr; - -jni::jclass* polylineClass = nullptr; -jni::jfieldID* polylineAlphaId = nullptr; -jni::jfieldID* polylineColorId = nullptr; -jni::jfieldID* polylineWidthId = nullptr; -jni::jfieldID* polylinePointsId = nullptr; - -jni::jclass* polygonClass = nullptr; -jni::jfieldID* polygonAlphaId = nullptr; -jni::jfieldID* polygonFillColorId = nullptr; -jni::jfieldID* polygonStrokeColorId = nullptr; -jni::jfieldID* polygonPointsId = nullptr; - -jni::jmethodID* listToArrayId = nullptr; - -jni::jclass* arrayListClass = nullptr; -jni::jmethodID* arrayListConstructorId = nullptr; -jni::jmethodID* arrayListAddId = nullptr; - -jni::jclass* projectedMetersClass = nullptr; -jni::jmethodID* projectedMetersConstructorId = nullptr; -jni::jfieldID* projectedMetersNorthingId = nullptr; -jni::jfieldID* projectedMetersEastingId = nullptr; - -jni::jclass* pointFClass = nullptr; -jni::jmethodID* pointFConstructorId = nullptr; -jni::jfieldID* pointFXId = nullptr; -jni::jfieldID* pointFYId = nullptr; - -jni::jclass* rectFClass = nullptr; -jni::jmethodID* rectFConstructorId = nullptr; -jni::jfieldID* rectFLeftId = nullptr; -jni::jfieldID* rectFTopId = nullptr; -jni::jfieldID* rectFRightId = nullptr; -jni::jfieldID* rectFBottomId = nullptr; - // Offline declarations start jni::jfieldID* offlineManagerClassPtrId = nullptr; @@ -224,46 +175,6 @@ jni::jstring* std_string_to_jstring(JNIEnv *env, std::string str) { return jni::Make(*env, str).Get(); } -std::vector std_vector_string_from_jobject(JNIEnv *env, jni::jobject* jlist) { - std::vector vector; - - jni::NullCheck(*env, jlist); - jni::jarray* jarray = - reinterpret_cast*>(jni::CallMethod(*env, jlist, *listToArrayId)); - - jni::NullCheck(*env, jarray); - std::size_t len = jni::GetArrayLength(*env, *jarray); - - for (std::size_t i = 0; i < len; i++) { - jni::jstring* jstr = reinterpret_cast(jni::GetObjectArrayElement(*env, *jarray, i)); - vector.push_back(std_string_from_jstring(env, jstr)); - } - - return vector; -} - -jni::jobject* std_vector_string_to_jobject(JNIEnv *env, std::vector vector) { - jni::jobject* jlist = &jni::NewObject(*env, *arrayListClass, *arrayListConstructorId); - - for (const auto& str : vector) { - jni::CallMethod(*env, jlist, *arrayListAddId, std_string_to_jstring(env, str)); - } - - return jlist; -} - -jni::jarray* std_vector_uint_to_jobject(JNIEnv *env, const std::vector& vector) { - jni::jarray& jarray = jni::NewArray(*env, vector.size()); - - std::vector v; - v.reserve(vector.size()); - std::move(vector.begin(), vector.end(), std::back_inserter(v)); - - jni::SetArrayRegion(*env, jarray, 0, v); - - return &jarray; -} - static std::vector metadata_from_java(JNIEnv* env, jni::jarray& j) { std::size_t length = jni::GetArrayLength(*env, j); std::vector c; @@ -307,939 +218,6 @@ namespace { using namespace mbgl::android; using DebugOptions = mbgl::MapDebugOptions; -jlong nativeCreate(JNIEnv *env, jni::jobject* obj, jni::jstring* cachePath_, jni::jstring* dataPath_, jni::jstring* apkPath_, jfloat pixelRatio, jint availableProcessors, jlong totalMemory) { - mbgl::Log::Info(mbgl::Event::JNI, "nativeCreate"); - cachePath = std_string_from_jstring(env, cachePath_); - dataPath = std_string_from_jstring(env, dataPath_); - apkPath = std_string_from_jstring(env, apkPath_); - - mbgl::Log::Info(mbgl::Event::JNI, "Create NativeMapView"); - return reinterpret_cast(new NativeMapView(env, jni::Unwrap(obj), pixelRatio, availableProcessors, totalMemory)); -} - -void nativeDestroy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Info(mbgl::Event::JNI, "nativeDestroy"); - assert(nativeMapViewPtr != 0); - delete reinterpret_cast(nativeMapViewPtr); -} - -void nativeUpdate(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->invalidate(); -} - -void nativeRender(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - mbgl::Log::Info(mbgl::Event::JNI, "nativeRender"); - mbgl::util::RunLoop::Get()->runOnce(); - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->render(); -} - -void nativeOnViewportChanged(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint width, jint height) { - mbgl::Log::Info(mbgl::Event::JNI, "nativeViewResize"); - assert(nativeMapViewPtr != 0); - assert(width >= 0); - assert(height >= 0); - assert(width <= UINT16_MAX); - assert(height <= UINT16_MAX); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->onViewportChanged(width, height); -} - -void nativeRemoveClass(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* clazz) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().removeClass(std_string_from_jstring(env, clazz)); -} - -jboolean nativeHasClass(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* clazz) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().hasClass(std_string_from_jstring(env, clazz)); -} - -void nativeAddClass(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* clazz) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().addClass(std_string_from_jstring(env, clazz)); -} - -void nativeSetClasses(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* classes) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().setClasses(std_vector_string_from_jobject(env, classes)); -} - -jni::jobject* nativeGetClasses(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return std_vector_string_to_jobject(env, nativeMapView->getMap().getClasses()); -} - -void nativeSetAPIBaseURL(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* url) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getFileSource().setAPIBaseURL(std_string_from_jstring(env, url)); -} - -void nativeSetStyleUrl(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* url) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().setStyleURL(std_string_from_jstring(env, url)); -} - -jni::jstring* nativeGetStyleUrl(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr){ - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return std_string_to_jstring(env, nativeMapView->getMap().getStyleURL()); -} - -void nativeSetStyleJson(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* newStyleJson) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().setStyleJSON(std_string_from_jstring(env, newStyleJson)); -} - -jni::jstring* nativeGetStyleJson(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return std_string_to_jstring(env, nativeMapView->getMap().getStyleJSON()); -} - -void nativeSetAccessToken(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* accessToken) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getFileSource().setAccessToken(std_string_from_jstring(env, accessToken)); -} - -jni::jstring* nativeGetAccessToken(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return std_string_to_jstring(env, nativeMapView->getFileSource().getAccessToken()); -} - -void nativeCancelTransitions(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().cancelTransitions(); -} - -void nativeSetGestureInProgress(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jboolean inProgress) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().setGestureInProgress(inProgress); -} - -void nativeMoveBy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble dx, jdouble dy, - jlong duration) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().moveBy({dx, dy}, mbgl::Milliseconds(duration)); -} - -void nativeSetLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude, jlong duration) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().setLatLng(mbgl::LatLng(latitude, longitude), nativeMapView->getInsets(), mbgl::Duration(duration)); -} - -jni::jobject* nativeGetLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::LatLng latLng = nativeMapView->getMap().getLatLng(nativeMapView->getInsets()); - return &jni::NewObject(*env, *latLngClass, *latLngConstructorId, latLng.latitude, latLng.longitude); -} - -jdoubleArray nativeGetCameraValues(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::LatLng latLng = nativeMapView->getMap().getLatLng(nativeMapView->getInsets()); - jdoubleArray output = env->NewDoubleArray(5); - jsize start = 0; - jsize leng = 5; - jdouble buf[5]; - buf[0] = latLng.latitude; - buf[1] = latLng.longitude; - buf[2] = -nativeMapView->getMap().getBearing(); - buf[3] = nativeMapView->getMap().getPitch(); - buf[4] = nativeMapView->getMap().getZoom(); - env->SetDoubleArrayRegion(output, start, leng, buf); - - if (output == nullptr) { - env->ExceptionDescribe(); - return nullptr; - } - - return output; -} - -void nativeResetPosition(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().resetPosition(); -} - -jdouble nativeGetPitch(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().getPitch(); -} - -void nativeSetPitch(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble pitch, jlong milliseconds) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::Duration duration((mbgl::Milliseconds(milliseconds))); - nativeMapView->getMap().setPitch(pitch, duration); -} - -void nativeScaleBy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble ds, jdouble cx, - jdouble cy, jlong duration) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::ScreenCoordinate center(cx, cy); - nativeMapView->getMap().scaleBy(ds, center, mbgl::Milliseconds(duration)); -} - -void nativeSetScale(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble scale, - jdouble cx, jdouble cy, jlong duration) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::ScreenCoordinate center(cx, cy); - nativeMapView->getMap().setScale(scale, center, mbgl::Milliseconds(duration)); -} - -jdouble nativeGetScale(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().getScale(); -} - -void nativeSetZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble zoom, jlong duration) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().setZoom(zoom, mbgl::Milliseconds(duration)); -} - -jdouble nativeGetZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().getZoom(); -} - -void nativeResetZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().resetZoom(); -} - -void nativeSetMinZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble zoom) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().setMinZoom(zoom); -} - -jdouble nativeGetMinZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().getMinZoom(); -} - -void nativeSetMaxZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble zoom) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().setMaxZoom(zoom); -} - -jdouble nativeGetMaxZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().getMaxZoom(); -} - -void nativeRotateBy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble sx, - jdouble sy, jdouble ex, jdouble ey, jlong duration) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::ScreenCoordinate first(sx, sy); - mbgl::ScreenCoordinate second(ex, ey); - nativeMapView->getMap().rotateBy(first, second, mbgl::Milliseconds(duration)); -} - -void nativeSetBearing(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble degrees, - jlong milliseconds) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::Duration duration((mbgl::Milliseconds(milliseconds))); - nativeMapView->getMap().setBearing(degrees, duration); -} - -void nativeSetFocalBearing(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble degrees, jdouble fx, - jdouble fy, jlong milliseconds) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::ScreenCoordinate center(fx, fy); - nativeMapView->getMap().setBearing(degrees, center, mbgl::Milliseconds(milliseconds)); -} - -void nativeSetBearingXY(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble degrees, - jdouble cx, jdouble cy) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::ScreenCoordinate center(cx, cy); - nativeMapView->getMap().setBearing(degrees, center); -} - -jdouble nativeGetBearing(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().getBearing(); -} - -void nativeResetNorth(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().resetNorth(); -} - -void nativeUpdateMarker(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong markerId, jdouble lat, jdouble lon, jni::jstring* jid) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - if (markerId == -1) { - return; - } - std::string iconId = std_string_from_jstring(env, jid); - // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long. - nativeMapView->getMap().updateAnnotation(markerId, mbgl::SymbolAnnotation { mbgl::Point(lon, lat), iconId }); -} - -jni::jarray* nativeAddMarkers(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray* jarray) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - NullCheck(*env, jarray); - std::size_t len = jni::GetArrayLength(*env, *jarray); - - mbgl::AnnotationIDs ids; - ids.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - jni::jobject* marker = jni::GetObjectArrayElement(*env, *jarray, i); - jni::jobject* position = jni::GetField(*env, marker, *markerPositionId); - jni::jobject* icon = jni::GetField(*env, marker, *markerIconId); - jni::jstring* jid = reinterpret_cast(jni::GetField(*env, icon, *iconIdId)); - - jdouble latitude = jni::GetField(*env, position, *latLngLatitudeId); - jdouble longitude = jni::GetField(*env, position, *latLngLongitudeId); - - ids.push_back(nativeMapView->getMap().addAnnotation(mbgl::SymbolAnnotation { - mbgl::Point(longitude, latitude), - std_string_from_jstring(env, jid) - })); - - jni::DeleteLocalRef(*env, position); - jni::DeleteLocalRef(*env, jid); - jni::DeleteLocalRef(*env, icon); - jni::DeleteLocalRef(*env, marker); - } - - return std_vector_uint_to_jobject(env, ids); -} - -static mbgl::Color toColor(jint color) { - float r = (color >> 16) & 0xFF; - float g = (color >> 8) & 0xFF; - float b = (color) & 0xFF; - float a = (color >> 24) & 0xFF; - return { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f }; -} - -template -Geometry toGeometry(JNIEnv *env, jni::jobject* jlist) { - NullCheck(*env, jlist); - jni::jarray* jarray = - reinterpret_cast*>(jni::CallMethod(*env, jlist, *listToArrayId)); - NullCheck(*env, jarray); - - std::size_t size = jni::GetArrayLength(*env, *jarray); - - Geometry geometry; - geometry.reserve(size); - - for (std::size_t i = 0; i < size; i++) { - jni::jobject* latLng = reinterpret_cast(jni::GetObjectArrayElement(*env, *jarray, i)); - NullCheck(*env, latLng); - - geometry.push_back(mbgl::Point( - jni::GetField(*env, latLng, *latLngLongitudeId), - jni::GetField(*env, latLng, *latLngLatitudeId))); - - jni::DeleteLocalRef(*env, latLng); - } - - jni::DeleteLocalRef(*env, jarray); - jni::DeleteLocalRef(*env, jlist); - - return geometry; -} - -jni::jarray* nativeAddPolylines(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray* jarray) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - NullCheck(*env, jarray); - std::size_t len = jni::GetArrayLength(*env, *jarray); - - mbgl::AnnotationIDs ids; - ids.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - jni::jobject* polyline = jni::GetObjectArrayElement(*env, *jarray, i); - jni::jobject* points = jni::GetField(*env, polyline, *polylinePointsId); - - mbgl::LineAnnotation annotation { toGeometry>(env, points) }; - annotation.opacity = { jni::GetField(*env, polyline, *polylineAlphaId) }; - annotation.color = { toColor(jni::GetField(*env, polyline, *polylineColorId)) }; - annotation.width = { jni::GetField(*env, polyline, *polylineWidthId) }; - ids.push_back(nativeMapView->getMap().addAnnotation(annotation)); - - jni::DeleteLocalRef(*env, polyline); - } - - return std_vector_uint_to_jobject(env, ids); -} - -jni::jarray* nativeAddPolygons(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray* jarray) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - NullCheck(*env, jarray); - std::size_t len = jni::GetArrayLength(*env, *jarray); - - mbgl::AnnotationIDs ids; - ids.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - jni::jobject* polygon = jni::GetObjectArrayElement(*env, *jarray, i); - jni::jobject* points = jni::GetField(*env, polygon, *polygonPointsId); - - mbgl::FillAnnotation annotation { mbgl::Polygon { toGeometry>(env, points) } }; - annotation.opacity = { jni::GetField(*env, polygon, *polygonAlphaId) }; - annotation.outlineColor = { toColor(jni::GetField(*env, polygon, *polygonStrokeColorId)) }; - annotation.color = { toColor(jni::GetField(*env, polygon, *polygonFillColorId)) }; - ids.push_back(nativeMapView->getMap().addAnnotation(annotation)); - - jni::DeleteLocalRef(*env, polygon); - } - - return std_vector_uint_to_jobject(env, ids); -} - -void nativeUpdatePolygon(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong polygonId, jni::jobject* polygon) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jni::jobject* points = jni::GetField(*env, polygon, *polygonPointsId); - - mbgl::FillAnnotation annotation { mbgl::Polygon { toGeometry>(env, points) } }; - annotation.opacity = { jni::GetField(*env, polygon, *polygonAlphaId) }; - annotation.outlineColor = { toColor(jni::GetField(*env, polygon, *polygonStrokeColorId)) }; - annotation.color = { toColor(jni::GetField(*env, polygon, *polygonFillColorId)) }; - nativeMapView->getMap().updateAnnotation(polygonId, annotation); -} - -void nativeUpdatePolyline(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong polylineId, jni::jobject* polyline) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - jni::jobject* points = jni::GetField(*env, polyline, *polylinePointsId); - - mbgl::LineAnnotation annotation { toGeometry>(env, points) }; - annotation.opacity = { jni::GetField(*env, polyline, *polylineAlphaId) }; - annotation.color = { toColor(jni::GetField(*env, polyline, *polylineColorId)) }; - annotation.width = { jni::GetField(*env, polyline, *polylineWidthId) }; - nativeMapView->getMap().updateAnnotation(polylineId, annotation); -} - -void nativeRemoveAnnotations(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray* jarray) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - NullCheck(*env, jarray); - std::size_t len = jni::GetArrayLength(*env, *jarray); - auto elements = jni::GetArrayElements(*env, *jarray); - jlong* jids = std::get<0>(elements).get(); - - for (std::size_t i = 0; i < len; i++) { - if(jids[i] == -1L) - continue; - nativeMapView->getMap().removeAnnotation(jids[i]); - } -} - -jni::jarray* nativeQueryPointAnnotations(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* rect) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - // Conversion - jfloat left = jni::GetField(*env, rect, *rectFLeftId); - jfloat right = jni::GetField(*env, rect, *rectFRightId); - jfloat top = jni::GetField(*env, rect, *rectFTopId); - jfloat bottom = jni::GetField(*env, rect, *rectFBottomId); - mbgl::ScreenBox box = { - { left, top }, - { right, bottom }, - }; - - // Assume only points for now - mbgl::AnnotationIDs ids = nativeMapView->getMap().queryPointAnnotations(box); - - return std_vector_uint_to_jobject(env, ids); -} - -void nativeAddAnnotationIcon(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, - jni::jstring* symbol, jint width, jint height, jfloat scale, jni::jarray* jpixels) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - const std::string symbolName = std_string_from_jstring(env, symbol); - - NullCheck(*env, jpixels); - std::size_t size = jni::GetArrayLength(*env, *jpixels); - mbgl::PremultipliedImage premultipliedImage( - { static_cast(width), static_cast(height) }); - - if (premultipliedImage.bytes() != uint32_t(size)) { - throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch"); - } - - jni::GetArrayRegion(*env, *jpixels, 0, size, reinterpret_cast(premultipliedImage.data.get())); - - auto iconImage = std::make_shared( - std::move(premultipliedImage), - float(scale)); - - nativeMapView->getMap().addAnnotationIcon(symbolName, iconImage); -} - -void nativeSetVisibleCoordinateBounds(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, - jni::jarray* coordinates, jni::jobject* padding, jdouble direction, jlong duration) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - jfloat left = jni::GetField(*env, padding, *rectFLeftId); - jfloat right = jni::GetField(*env, padding, *rectFRightId); - jfloat top = jni::GetField(*env, padding, *rectFTopId); - jfloat bottom = jni::GetField(*env, padding, *rectFBottomId); - - NullCheck(*env, coordinates); - std::size_t count = jni::GetArrayLength(*env, *coordinates); - - mbgl::EdgeInsets mbglInsets = {top, left, bottom, right}; - std::vector latLngs; - latLngs.reserve(count); - - for (std::size_t i = 0; i < count; i++) { - jni::jobject* latLng = jni::GetObjectArrayElement(*env, *coordinates, i); - jdouble latitude = jni::GetField(*env, latLng, *latLngLatitudeId); - jdouble longitude = jni::GetField(*env, latLng, *latLngLongitudeId); - latLngs.push_back(mbgl::LatLng(latitude, longitude)); - } - - mbgl::CameraOptions cameraOptions = nativeMapView->getMap().cameraForLatLngs(latLngs, mbglInsets); - if (direction >= 0) { - // convert from degrees to radians - cameraOptions.angle = (-direction * M_PI) / 180; - } - mbgl::AnimationOptions animationOptions; - if (duration > 0) { - animationOptions.duration.emplace(mbgl::Milliseconds(duration)); - // equivalent to kCAMediaTimingFunctionDefault in iOS - animationOptions.easing.emplace(mbgl::util::UnitBezier { 0.25, 0.1, 0.25, 0.1 }); - } - - nativeMapView->getMap().easeTo(cameraOptions, animationOptions); -} - -jni::jarray* nativeQueryRenderedFeaturesForPoint(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jfloat x, jni::jfloat y, jni::jarray* layerIds) { - using namespace mbgl::android::conversion; - using namespace mapbox::geometry; - - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - mbgl::optional> layers; - if (layerIds != nullptr && jni::GetArrayLength(*env, *layerIds) > 0) { - layers = toVector(*env, *layerIds); - } - point point = {x, y}; - - return *convert*, std::vector>(*env, nativeMapView->getMap().queryRenderedFeatures(point, layers)); -} - -jni::jarray* nativeQueryRenderedFeaturesForBox(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jfloat left, jni::jfloat top, jni::jfloat right, jni::jfloat bottom, jni::jarray* layerIds) { - using namespace mbgl::android::conversion; - using namespace mapbox::geometry; - - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - mbgl::optional> layers; - if (layerIds != nullptr && jni::GetArrayLength(*env, *layerIds) > 0) { - layers = toVector(*env, *layerIds); - } - box box = { point{ left, top}, point{ right, bottom } }; - - return *convert*, std::vector>(*env, nativeMapView->getMap().queryRenderedFeatures(box, layers)); -} - -void nativeOnLowMemory(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().onLowMemory(); -} - -void nativeSetDebug(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jboolean debug) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - DebugOptions debugOptions = debug ? DebugOptions::TileBorders | DebugOptions::ParseStatus | DebugOptions::Collision - : DebugOptions::NoDebug; - nativeMapView->getMap().setDebug(debugOptions); - nativeMapView->enableFps(debug); -} - -void nativeToggleDebug(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().cycleDebugOptions(); - nativeMapView->enableFps(nativeMapView->getMap().getDebug() != DebugOptions::NoDebug); -} - -jboolean nativeGetDebug(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().getDebug() != DebugOptions::NoDebug; -} - -jboolean nativeIsFullyLoaded(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().isFullyLoaded(); -} - -void nativeSetReachability(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jboolean status) { - assert(nativeMapViewPtr != 0); - if (status) { - mbgl::NetworkStatus::Reachable(); - } -} - -jdouble nativeGetMetersPerPixelAtLatitude(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble lat, jdouble zoom) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().getMetersPerPixelAtLatitude(lat, zoom); -} - -jni::jobject* nativeProjectedMetersForLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::ProjectedMeters projectedMeters = nativeMapView->getMap().projectedMetersForLatLng(mbgl::LatLng(latitude, longitude)); - return &jni::NewObject(*env, *projectedMetersClass, *projectedMetersConstructorId, projectedMeters.northing, projectedMeters.easting); -} - -jni::jobject* nativeLatLngForProjectedMeters(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble northing, jdouble easting) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::LatLng latLng = nativeMapView->getMap().latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting)); - return &jni::NewObject(*env, *latLngClass, *latLngConstructorId, latLng.latitude, latLng.longitude); -} - -jni::jobject* nativePixelForLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::ScreenCoordinate pixel = nativeMapView->getMap().pixelForLatLng(mbgl::LatLng(latitude, longitude)); - return &jni::NewObject(*env, *pointFClass, *pointFConstructorId, static_cast(pixel.x), static_cast(pixel.y)); -} - -jni::jobject* nativeLatLngForPixel(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jfloat x, jfloat y) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::LatLng latLng = nativeMapView->getMap().latLngForPixel(mbgl::ScreenCoordinate(x, y)); - return &jni::NewObject(*env, *latLngClass, *latLngConstructorId, latLng.latitude, latLng.longitude); -} - -jdouble nativeGetTopOffsetPixelsForAnnotationSymbol(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* symbolName) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - return nativeMapView->getMap().getTopOffsetPixelsForAnnotationIcon(std_string_from_jstring(env, symbolName)); -} - -void nativeJumpTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jdouble pitch, jdouble zoom) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - mbgl::CameraOptions options; - if (angle != -1) { - options.angle = (-angle * M_PI) / 180; - } - options.center = mbgl::LatLng(latitude, longitude); - options.padding = nativeMapView->getInsets(); - if (pitch != -1) { - options.pitch = pitch * M_PI / 180; - } - if (zoom != -1) { - options.zoom = zoom; - } - - nativeMapView->getMap().jumpTo(options); -} - -void nativeEaseTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jlong duration, jdouble pitch, jdouble zoom, jboolean easing) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - mbgl::CameraOptions cameraOptions; - if (angle != -1) { - cameraOptions.angle = (-angle * M_PI) / 180; - } - cameraOptions.center = mbgl::LatLng(latitude, longitude); - cameraOptions.padding = nativeMapView->getInsets(); - if (pitch != -1) { - cameraOptions.pitch = pitch * M_PI / 180; - } - if (zoom != -1) { - cameraOptions.zoom = zoom; - } - mbgl::AnimationOptions animationOptions; - animationOptions.duration.emplace(mbgl::Duration(duration)); - - if (!easing) { - // add a linear interpolator instead of easing - animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0, 1, 1 }); - } - - nativeMapView->getMap().easeTo(cameraOptions, animationOptions); -} - -void nativeSetContentPadding(JNIEnv *env, jni::jobject* obj,long nativeMapViewPtr, double top, double left, double bottom, double right) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->setInsets({top, left, bottom, right}); -} - -void nativeFlyTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jlong duration, jdouble pitch, jdouble zoom) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - mbgl::CameraOptions cameraOptions; - if (angle != -1) { - cameraOptions.angle = (-angle * M_PI) / 180 ; - } - cameraOptions.center = mbgl::LatLng(latitude, longitude); - cameraOptions.padding = nativeMapView->getInsets(); - if (pitch != -1) { - cameraOptions.pitch = pitch * M_PI / 180; - } - if (zoom != -1) { - cameraOptions.zoom = zoom; - } - mbgl::AnimationOptions animationOptions; - animationOptions.duration.emplace(mbgl::Duration(duration)); - - nativeMapView->getMap().flyTo(cameraOptions, animationOptions); -} - -jlong nativeGetTransitionDuration(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(env); - assert(nativeMapViewPtr != 0); - - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - const auto transitionOptions = nativeMapView->getMap().getTransitionOptions(); - return transitionOptions.duration.value_or(mbgl::Duration::zero()).count(); -} - -void nativeSetTransitionDuration(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong duration) { - assert(env); - assert(nativeMapViewPtr != 0); - - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - auto transitionOptions = nativeMapView->getMap().getTransitionOptions(); - transitionOptions.duration = std::chrono::duration_cast(std::chrono::duration(duration)); - nativeMapView->getMap().setTransitionOptions(transitionOptions); -} - -jlong nativeGetTransitionDelay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(env); - assert(nativeMapViewPtr != 0); - - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - const auto transitionOptions = nativeMapView->getMap().getTransitionOptions(); - return transitionOptions.delay.value_or(mbgl::Duration::zero()).count(); -} - -void nativeSetTransitionDelay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong delay) { - assert(env); - assert(nativeMapViewPtr != 0); - - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - auto transitionOptions = nativeMapView->getMap().getTransitionOptions(); - transitionOptions.delay = std::chrono::duration_cast(std::chrono::duration(delay)); - nativeMapView->getMap().setTransitionOptions(transitionOptions); -} - -jni::jobject* nativeGetLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* layerId) { - assert(env); - assert(nativeMapViewPtr != 0); - - // Get the native map peer - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - // Find the layer - mbgl::style::Layer* coreLayer = nativeMapView->getMap().getLayer(std_string_from_jstring(env, layerId)); - if (!coreLayer) { - mbgl::Log::Info(mbgl::Event::JNI, "No layer found"); - return jni::Object(); - } - - // Create and return the layer's native peer - return createJavaLayerPeer(*env, nativeMapView->getMap(), *coreLayer); -} - -void nativeAddLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong nativeLayerPtr, jni::jstring* before) { - assert(nativeMapViewPtr != 0); - assert(nativeLayerPtr != 0); - - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - Layer *layer = reinterpret_cast(nativeLayerPtr); - try { - layer->addToMap(nativeMapView->getMap(), before ? mbgl::optional(std_string_from_jstring(env, before)) : mbgl::optional()); - } catch (const std::runtime_error& error) { - jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); - } -} - -/** - * Remove by layer id. Ownership is not transferred back - */ -void nativeRemoveLayerById(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - try { - nativeMapView->getMap().removeLayer(std_string_from_jstring(env, id)); - } catch (const std::runtime_error& error) { - jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/layers/NoSuchLayerException"), error.what()); - } -} - -/** - * Remove with wrapper object id. Ownership is transferred back to the wrapper - */ -void nativeRemoveLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong layerPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::android::Layer *layer = reinterpret_cast(layerPtr); - try { - std::unique_ptr coreLayer = nativeMapView->getMap().removeLayer(layer->get().getID()); - layer->setLayer(std::move(coreLayer)); - } catch (const std::runtime_error& error) { - jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/layers/NoSuchLayerException"), error.what()); - } -} - - -jni::jobject* nativeGetSource(JNIEnv *env, jni::jobject* obj, jni::jlong nativeMapViewPtr, jni::jstring* sourceId) { - assert(env); - assert(nativeMapViewPtr != 0); - - // Get the native map peer - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - // Find the source - mbgl::style::Source* coreSource = nativeMapView->getMap().getSource(std_string_from_jstring(env, sourceId)); - if (!coreSource) { - mbgl::Log::Info(mbgl::Event::JNI, "No source found"); - return jni::Object(); - } - - // Create and return the source's native peer - return createJavaSourcePeer(*env, nativeMapView->getMap(), *coreSource); -} - -void nativeAddSource(JNIEnv *env, jni::jobject* obj, jni::jlong nativeMapViewPtr, jni::jlong nativeSourcePtr) { - assert(nativeMapViewPtr != 0); - assert(nativeSourcePtr != 0); - - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - Source *source = reinterpret_cast(nativeSourcePtr); - try { - source->addToMap(nativeMapView->getMap()); - } catch (const std::runtime_error& error) { - jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what()); - } -} - -void nativeRemoveSourceById(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - try { - nativeMapView->getMap().removeSource(std_string_from_jstring(env, id)); - } catch (const std::runtime_error& error) { - jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/sources/NoSuchSourceException"), error.what()); - } -} - -void nativeRemoveSource(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong sourcePtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - mbgl::android::Source *source = reinterpret_cast(sourcePtr); - try { - std::unique_ptr coreSource = nativeMapView->getMap().removeSource(source->get().getID()); - source->setSource(std::move(coreSource)); - } catch (const std::runtime_error& error) { - jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/sources/NoSuchSourceException"), error.what()); - } -} - -void nativeAddImage(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* name, jni::jint width, jni::jint height, jni::jfloat pixelRatio, jni::jarray* data) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - - // Create Pre-multiplied image from byte[] - NullCheck(*env, data); - std::size_t size = jni::GetArrayLength(*env, *data); - mbgl::PremultipliedImage premultipliedImage( - { static_cast(width), static_cast(height) }); - - if (premultipliedImage.bytes() != uint32_t(size)) { - throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch"); - } - - jni::GetArrayRegion(*env, *data, 0, size, reinterpret_cast(premultipliedImage.data.get())); - - // Wrap in a SpriteImage with the correct pixel ratio - auto spriteImage = std::make_unique(std::move(premultipliedImage), float(pixelRatio)); - - nativeMapView->getMap().addImage(std_string_from_jstring(env, name), std::move(spriteImage)); -} - -void nativeRemoveImage(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* name) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->getMap().removeImage(std_string_from_jstring(env, name)); -} - -void nativeScheduleTakeSnapshot(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { - assert(nativeMapViewPtr != 0); - NativeMapView *nativeMapView = reinterpret_cast(nativeMapViewPtr); - nativeMapView->scheduleTakeSnapshot(); -} - // Offline calls begin jlong createDefaultFileSource(JNIEnv *env, jni::jobject* obj, jni::jstring* cachePath_, jni::jstring* assetRoot_, jlong maximumCacheSize) { @@ -1731,11 +709,33 @@ void registerNatives(JavaVM *vm) { //For the DefaultFileSource static mbgl::util::RunLoop mainRunLoop; - mbgl::android::RegisterNativeHTTPRequest(env); - + //Basic types java::registerNatives(env); + java::util::registerNative(env); + PointF::registerNative(env); + RectF::registerNative(env); + + //Geometry + Feature::registerNative(env); + LatLng::registerNative(env); + ProjectedMeters::registerNative(env); + + //Annotation + Marker::registerNative(env); + Polygon::registerNative(env); + Polyline::registerNative(env); + + //Map + NativeMapView::registerNative(env); + + //Http + RegisterNativeHTTPRequest(env); + + //Bitmap Bitmap::registerNative(env); BitmapFactory::registerNative(env); + + //Style registerNativeLayers(env); registerNativeSources(env); Stop::registerNative(env); @@ -1743,13 +743,9 @@ void registerNatives(JavaVM *vm) { ExponentialStops::registerNative(env); IdentityStops::registerNative(env); IntervalStops::registerNative(env); - ConnectivityListener::registerNative(env); - latLngClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/LatLng"); - latLngClass = jni::NewGlobalRef(env, latLngClass).release(); - latLngConstructorId = &jni::GetMethodID(env, *latLngClass, "", "(DD)V"); - latLngLatitudeId = &jni::GetFieldID(env, *latLngClass, "latitude", "D"); - latLngLongitudeId = &jni::GetFieldID(env, *latLngClass, "longitude", "D"); + //Connectivity + ConnectivityListener::registerNative(env); latLngBoundsClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/LatLngBounds"); latLngBoundsClass = jni::NewGlobalRef(env, latLngBoundsClass).release(); @@ -1759,156 +755,6 @@ void registerNatives(JavaVM *vm) { latLngBoundsLonEastId = &jni::GetFieldID(env, *latLngBoundsClass, "mLonEast", "D"); latLngBoundsLonWestId = &jni::GetFieldID(env, *latLngBoundsClass, "mLonWest", "D"); - iconClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Icon"); - iconClass = jni::NewGlobalRef(env, iconClass).release(); - iconIdId = &jni::GetFieldID(env, *iconClass, "mId", "Ljava/lang/String;"); - - markerClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Marker"); - markerClass = jni::NewGlobalRef(env, markerClass).release(); - markerPositionId = &jni::GetFieldID(env, *markerClass, "position", "Lcom/mapbox/mapboxsdk/geometry/LatLng;"); - markerIconId = &jni::GetFieldID(env, *markerClass, "icon", "Lcom/mapbox/mapboxsdk/annotations/Icon;"); - markerIdId = &jni::GetFieldID(env, *markerClass, "id", "J"); - - polylineClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Polyline"); - polylineClass = jni::NewGlobalRef(env, polylineClass).release(); - polylineAlphaId = &jni::GetFieldID(env, *polylineClass, "alpha", "F"); - polylineColorId = &jni::GetFieldID(env, *polylineClass, "color", "I"); - polylineWidthId = &jni::GetFieldID(env, *polylineClass, "width", "F"); - polylinePointsId = &jni::GetFieldID(env, *polylineClass, "points", "Ljava/util/List;"); - - polygonClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Polygon"); - polygonClass = jni::NewGlobalRef(env, polygonClass).release(); - polygonAlphaId = &jni::GetFieldID(env, *polygonClass, "alpha", "F"); - polygonFillColorId = &jni::GetFieldID(env, *polygonClass, "fillColor", "I"); - polygonStrokeColorId = &jni::GetFieldID(env, *polygonClass, "strokeColor", "I"); - polygonPointsId = &jni::GetFieldID(env, *polygonClass, "points", "Ljava/util/List;"); - - jni::jclass* listClass = &jni::FindClass(env, "java/util/List"); - listToArrayId = &jni::GetMethodID(env, *listClass, "toArray", "()[Ljava/lang/Object;"); - - arrayListClass = &jni::FindClass(env, "java/util/ArrayList"); - arrayListClass = jni::NewGlobalRef(env, arrayListClass).release(); - arrayListConstructorId = &jni::GetMethodID(env, *arrayListClass, "", "()V"); - arrayListAddId = &jni::GetMethodID(env, *arrayListClass, "add", "(Ljava/lang/Object;)Z"); - - projectedMetersClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/ProjectedMeters"); - projectedMetersClass = jni::NewGlobalRef(env, projectedMetersClass).release(); - projectedMetersConstructorId = &jni::GetMethodID(env, *projectedMetersClass, "", "(DD)V"); - projectedMetersNorthingId = &jni::GetFieldID(env, *projectedMetersClass, "northing", "D"); - projectedMetersEastingId = &jni::GetFieldID(env, *projectedMetersClass, "easting", "D"); - - pointFClass = &jni::FindClass(env, "android/graphics/PointF"); - pointFClass = jni::NewGlobalRef(env, pointFClass).release(); - pointFConstructorId = &jni::GetMethodID(env, *pointFClass, "", "(FF)V"); - pointFXId = &jni::GetFieldID(env, *pointFClass, "x", "F"); - pointFYId = &jni::GetFieldID(env, *pointFClass, "y", "F"); - - rectFClass = &jni::FindClass(env, "android/graphics/RectF"); - rectFClass = jni::NewGlobalRef(env, rectFClass).release(); - rectFConstructorId = &jni::GetMethodID(env, *rectFClass, "", "()V"); - rectFLeftId = &jni::GetFieldID(env, *rectFClass, "left", "F"); - rectFRightId = &jni::GetFieldID(env, *rectFClass, "right", "F"); - rectFTopId = &jni::GetFieldID(env, *rectFClass, "top", "F"); - rectFBottomId = &jni::GetFieldID(env, *rectFClass, "bottom", "F"); - - jni::jclass& nativeMapViewClass = jni::FindClass(env, "com/mapbox/mapboxsdk/maps/NativeMapView"); - - onInvalidateId = &jni::GetMethodID(env, nativeMapViewClass, "onInvalidate", "()V"); - wakeCallbackId = &jni::GetMethodID(env, nativeMapViewClass, "wakeCallback","()V"); - onMapChangedId = &jni::GetMethodID(env, nativeMapViewClass, "onMapChanged", "(I)V"); - onFpsChangedId = &jni::GetMethodID(env, nativeMapViewClass, "onFpsChanged", "(D)V"); - onSnapshotReadyId = &jni::GetMethodID(env, nativeMapViewClass, "onSnapshotReady","(Landroid/graphics/Bitmap;)V"); - - #define MAKE_NATIVE_METHOD(name, sig) jni::MakeNativeMethod( #name, sig ) - - jni::RegisterNatives(env, nativeMapViewClass, - MAKE_NATIVE_METHOD(nativeCreate, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;FIJ)J"), - MAKE_NATIVE_METHOD(nativeDestroy, "(J)V"), - MAKE_NATIVE_METHOD(nativeUpdate, "(J)V"), - MAKE_NATIVE_METHOD(nativeRender, "(J)V"), - MAKE_NATIVE_METHOD(nativeOnViewportChanged, "(JII)V"), - MAKE_NATIVE_METHOD(nativeAddClass, "(JLjava/lang/String;)V"), - MAKE_NATIVE_METHOD(nativeRemoveClass, "(JLjava/lang/String;)V"), - MAKE_NATIVE_METHOD(nativeHasClass, "(JLjava/lang/String;)Z"), - MAKE_NATIVE_METHOD(nativeSetClasses, "(JLjava/util/List;)V"), - MAKE_NATIVE_METHOD(nativeGetClasses, "(J)Ljava/util/List;"), - MAKE_NATIVE_METHOD(nativeSetStyleUrl, "(JLjava/lang/String;)V"), - MAKE_NATIVE_METHOD(nativeGetStyleUrl, "(J)Ljava/lang/String;"), - MAKE_NATIVE_METHOD(nativeSetStyleJson, "(JLjava/lang/String;)V"), - MAKE_NATIVE_METHOD(nativeGetStyleJson, "(J)Ljava/lang/String;"), - MAKE_NATIVE_METHOD(nativeSetAccessToken, "(JLjava/lang/String;)V"), - MAKE_NATIVE_METHOD(nativeGetAccessToken, "(J)Ljava/lang/String;"), - MAKE_NATIVE_METHOD(nativeCancelTransitions, "(J)V"), - MAKE_NATIVE_METHOD(nativeSetGestureInProgress, "(JZ)V"), - MAKE_NATIVE_METHOD(nativeMoveBy, "(JDDJ)V"), - MAKE_NATIVE_METHOD(nativeSetLatLng, "(JDDJ)V"), - MAKE_NATIVE_METHOD(nativeGetLatLng, "(J)Lcom/mapbox/mapboxsdk/geometry/LatLng;"), - MAKE_NATIVE_METHOD(nativeResetPosition, "(J)V"), - MAKE_NATIVE_METHOD(nativeGetCameraValues, "(J)[D"), - MAKE_NATIVE_METHOD(nativeGetPitch, "(J)D"), - MAKE_NATIVE_METHOD(nativeSetPitch, "(JDJ)V"), - MAKE_NATIVE_METHOD(nativeScaleBy, "(JDDDJ)V"), - MAKE_NATIVE_METHOD(nativeSetScale, "(JDDDJ)V"), - MAKE_NATIVE_METHOD(nativeGetScale, "(J)D"), - MAKE_NATIVE_METHOD(nativeSetZoom, "(JDJ)V"), - MAKE_NATIVE_METHOD(nativeGetZoom, "(J)D"), - MAKE_NATIVE_METHOD(nativeResetZoom, "(J)V"), - MAKE_NATIVE_METHOD(nativeGetMinZoom, "(J)D"), - MAKE_NATIVE_METHOD(nativeSetMinZoom, "(JD)V"), - MAKE_NATIVE_METHOD(nativeGetMaxZoom, "(J)D"), - MAKE_NATIVE_METHOD(nativeSetMaxZoom, "(JD)V"), - MAKE_NATIVE_METHOD(nativeRotateBy, "(JDDDDJ)V"), - MAKE_NATIVE_METHOD(nativeSetBearing, "(JDJ)V"), - MAKE_NATIVE_METHOD(nativeSetFocalBearing, "(JDDDJ)V"), - MAKE_NATIVE_METHOD(nativeSetBearingXY, "(JDDD)V"), - MAKE_NATIVE_METHOD(nativeGetBearing, "(J)D"), - MAKE_NATIVE_METHOD(nativeResetNorth, "(J)V"), - MAKE_NATIVE_METHOD(nativeAddMarkers, "(J[Lcom/mapbox/mapboxsdk/annotations/Marker;)[J"), - MAKE_NATIVE_METHOD(nativeAddPolylines, "(J[Lcom/mapbox/mapboxsdk/annotations/Polyline;)[J"), - MAKE_NATIVE_METHOD(nativeAddPolygons, "(J[Lcom/mapbox/mapboxsdk/annotations/Polygon;)[J"), - MAKE_NATIVE_METHOD(nativeUpdateMarker, "(JJDDLjava/lang/String;)V"), - MAKE_NATIVE_METHOD(nativeUpdatePolygon, "(JJLcom/mapbox/mapboxsdk/annotations/Polygon;)V"), - MAKE_NATIVE_METHOD(nativeUpdatePolyline, "(JJLcom/mapbox/mapboxsdk/annotations/Polyline;)V"), - MAKE_NATIVE_METHOD(nativeRemoveAnnotations, "(J[J)V"), - MAKE_NATIVE_METHOD(nativeQueryPointAnnotations, "(JLandroid/graphics/RectF;)[J"), - MAKE_NATIVE_METHOD(nativeAddAnnotationIcon, "(JLjava/lang/String;IIF[B)V"), - MAKE_NATIVE_METHOD(nativeSetVisibleCoordinateBounds, "(J[Lcom/mapbox/mapboxsdk/geometry/LatLng;Landroid/graphics/RectF;DJ)V"), - MAKE_NATIVE_METHOD(nativeOnLowMemory, "(J)V"), - MAKE_NATIVE_METHOD(nativeSetDebug, "(JZ)V"), - MAKE_NATIVE_METHOD(nativeToggleDebug, "(J)V"), - MAKE_NATIVE_METHOD(nativeGetDebug, "(J)Z"), - MAKE_NATIVE_METHOD(nativeIsFullyLoaded, "(J)Z"), - MAKE_NATIVE_METHOD(nativeSetReachability, "(JZ)V"), - MAKE_NATIVE_METHOD(nativeGetMetersPerPixelAtLatitude, "(JDD)D"), - MAKE_NATIVE_METHOD(nativeProjectedMetersForLatLng, "(JDD)Lcom/mapbox/mapboxsdk/geometry/ProjectedMeters;"), - MAKE_NATIVE_METHOD(nativeLatLngForProjectedMeters, "(JDD)Lcom/mapbox/mapboxsdk/geometry/LatLng;"), - MAKE_NATIVE_METHOD(nativePixelForLatLng, "(JDD)Landroid/graphics/PointF;"), - MAKE_NATIVE_METHOD(nativeLatLngForPixel, "(JFF)Lcom/mapbox/mapboxsdk/geometry/LatLng;"), - MAKE_NATIVE_METHOD(nativeGetTopOffsetPixelsForAnnotationSymbol, "(JLjava/lang/String;)D"), - MAKE_NATIVE_METHOD(nativeJumpTo, "(JDDDDD)V"), - MAKE_NATIVE_METHOD(nativeEaseTo, "(JDDDJDDZ)V"), - MAKE_NATIVE_METHOD(nativeFlyTo, "(JDDDJDD)V"), - MAKE_NATIVE_METHOD(nativeGetTransitionDuration, "(J)J"), - MAKE_NATIVE_METHOD(nativeSetTransitionDuration, "(JJ)V"), - MAKE_NATIVE_METHOD(nativeGetTransitionDelay, "(J)J"), - MAKE_NATIVE_METHOD(nativeSetTransitionDelay, "(JJ)V"), - MAKE_NATIVE_METHOD(nativeGetLayer, "(JLjava/lang/String;)Lcom/mapbox/mapboxsdk/style/layers/Layer;"), - MAKE_NATIVE_METHOD(nativeAddLayer, "(JJLjava/lang/String;)V"), - MAKE_NATIVE_METHOD(nativeRemoveLayerById, "(JLjava/lang/String;)V"), - MAKE_NATIVE_METHOD(nativeRemoveLayer, "(JJ)V"), - MAKE_NATIVE_METHOD(nativeGetSource, "(JLjava/lang/String;)Lcom/mapbox/mapboxsdk/style/sources/Source;"), - MAKE_NATIVE_METHOD(nativeAddSource, "(JJ)V"), - MAKE_NATIVE_METHOD(nativeRemoveSourceById, "(JLjava/lang/String;)V"), - MAKE_NATIVE_METHOD(nativeRemoveSource, "(JJ)V"), - MAKE_NATIVE_METHOD(nativeAddImage, "(JLjava/lang/String;IIF[B)V"), - MAKE_NATIVE_METHOD(nativeRemoveImage, "(JLjava/lang/String;)V"), - MAKE_NATIVE_METHOD(nativeSetContentPadding, "(JDDDD)V"), - MAKE_NATIVE_METHOD(nativeScheduleTakeSnapshot, "(J)V"), - MAKE_NATIVE_METHOD(nativeQueryRenderedFeaturesForPoint, "(JFF[Ljava/lang/String;)[Lcom/mapbox/services/commons/geojson/Feature;"), - MAKE_NATIVE_METHOD(nativeQueryRenderedFeaturesForBox, "(JFFFF[Ljava/lang/String;)[Lcom/mapbox/services/commons/geojson/Feature;"), - MAKE_NATIVE_METHOD(nativeSetAPIBaseURL, "(JLjava/lang/String;)V") - ); - // Offline begin struct OfflineManager { @@ -1930,6 +776,8 @@ void registerNatives(JavaVM *vm) { jni::Class offlineManagerClass = jni::Class::Find(env); offlineManagerClassPtrId = &jni::GetFieldID(env, offlineManagerClass, "mDefaultFileSourcePtr", "J"); + #define MAKE_NATIVE_METHOD(name, sig) jni::MakeNativeMethod( #name, sig ) + jni::RegisterNatives(env, offlineManagerClass, MAKE_NATIVE_METHOD(createDefaultFileSource, "(Ljava/lang/String;Ljava/lang/String;J)J"), MAKE_NATIVE_METHOD(setAccessToken, "(JLjava/lang/String;)V"), diff --git a/platform/android/src/jni.hpp b/platform/android/src/jni.hpp index 04bad003f6..4b55173926 100644 --- a/platform/android/src/jni.hpp +++ b/platform/android/src/jni.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include typedef struct _jmethodID* jmethodID; typedef struct _JavaVM JavaVM; @@ -16,16 +17,13 @@ extern std::string dataPath; extern std::string apkPath; extern std::string androidRelease; -extern jmethodID onInvalidateId; -extern jmethodID wakeCallbackId; -extern jmethodID onMapChangedId; -extern jmethodID onFpsChangedId; -extern jmethodID onSnapshotReadyId; - -extern bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName); -extern void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach); +bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName); +void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach); extern void registerNatives(JavaVM* vm); +template +void attachThreadAndExecute(F&& function); + } // namespace android } // namespace mbgl diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 50fa8944f7..484e14b111 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -1,6 +1,4 @@ #include "native_map_view.hpp" -#include "jni.hpp" -#include #include #include @@ -11,130 +9,149 @@ #include -#include -#include -#include -#include +#include + +#include + #include +#include #include +#include +#include +#include #include +#include +#include +#include +#include "conversion/conversion.hpp" +#include "conversion/collection.hpp" +#include "geometry/conversion/feature.hpp" + +#include "jni.hpp" +#include "attach_env.hpp" #include "bitmap.hpp" #include "run_loop_impl.hpp" +#include "java/util.hpp" namespace mbgl { namespace android { -NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float _pixelRatio, int availableProcessors_, size_t totalMemory_) - : env(env_), - pixelRatio(_pixelRatio), - availableProcessors(availableProcessors_), - totalMemory(totalMemory_), - runLoop(std::make_unique(mbgl::util::RunLoop::Type::New)), - threadPool(4) { +using DebugOptions = mbgl::MapDebugOptions; + +NativeMapView::NativeMapView(jni::JNIEnv& _env, jni::Object _obj, jni::String _cachePath, jni::String _apkPath, + jni::jfloat _pixelRatio, jni::jint _availableProcessors, jni::jlong _totalMemory) : + javaPeer(_obj.NewWeakGlobalRef(_env)), + pixelRatio(_pixelRatio), + availableProcessors(_availableProcessors), + totalMemory(_totalMemory), + runLoop(std::make_unique(mbgl::util::RunLoop::Type::New)), + threadPool(4) { + mbgl::Log::Info(mbgl::Event::Android, "NativeMapView::NativeMapView"); //Add a wake function to wake the render thread when needed mbgl::util::RunLoop::Impl* loop = reinterpret_cast(mbgl::util::RunLoop::getLoopHandle()); loop->setWakeFunction(std::bind(&NativeMapView::wake, this)); - assert(env_ != nullptr); - assert(obj_ != nullptr); - - if (env->GetJavaVM(&vm) < 0) { - env->ExceptionDescribe(); - return; - } - - obj = env->NewWeakGlobalRef(obj_); - if (obj == nullptr) { - env->ExceptionDescribe(); + // Get a reference to the JavaVM for callbacks + //TODO: Why? + if (_env.GetJavaVM(&vm) < 0) { + _env.ExceptionDescribe(); return; } + // Create a default file source for this map instance fileSource = std::make_unique( - mbgl::android::cachePath + "/mbgl-offline.db", - mbgl::android::apkPath); + jni::Make(_env, _cachePath) + "/mbgl-offline.db", + jni::Make(_env, _apkPath)); + // Create the core map map = std::make_unique( *this, mbgl::Size{ static_cast(width), static_cast(height) }, pixelRatio, *fileSource, threadPool, MapMode::Continuous); + //Calculate a fitting cache size based on device parameters float zoomFactor = map->getMaxZoom() - map->getMinZoom() + 1; float cpuFactor = availableProcessors; float memoryFactor = static_cast(totalMemory) / 1000.0f / 1000.0f / 1000.0f; float sizeFactor = (static_cast(map->getSize().width) / mbgl::util::tileSize) * - (static_cast(map->getSize().height) / mbgl::util::tileSize); - - size_t cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f; + (static_cast(map->getSize().height) / mbgl::util::tileSize); - map->setSourceTileCacheSize(cacheSize); + map->setSourceTileCacheSize(zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f); } +/** + * Called through NativeMapView#destroy() + */ NativeMapView::~NativeMapView() { mbgl::Log::Info(mbgl::Event::Android, "NativeMapView::~NativeMapView"); - assert(vm != nullptr); - assert(obj != nullptr); + //Remove the wake function as the JVM object is going to be GC'd pretty soon + mbgl::util::RunLoop::Impl* loop = reinterpret_cast(mbgl::util::RunLoop::getLoopHandle()); + loop->setWakeFunction(nullptr); map.reset(); fileSource.reset(); - env->DeleteWeakGlobalRef(obj); - - obj = nullptr; - env = nullptr; vm = nullptr; } -mbgl::Size NativeMapView::getFramebufferSize() const { - mbgl::Log::Info(mbgl::Event::Android, "FB size %dx%d", fbWidth, fbHeight); - return { static_cast(fbWidth), static_cast(fbHeight) }; -} - -void NativeMapView::wake() { - mbgl::Log::Info(mbgl::Event::JNI, "Wake callback"); - - JNIEnv *env2; - jboolean detach = attach_jni_thread(theJVM, &env2, "GL Callback Thread"); - if (!detach) { - env2->CallVoidMethod(obj, wakeCallbackId); - if (env2->ExceptionCheck()) { - env2->ExceptionDescribe(); - } - } - detach_jni_thread(theJVM, &env2, detach); -} - -void NativeMapView::updateViewBinding() { - getContext().bindFramebuffer.setCurrentValue(0); - assert(mbgl::gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue()); - getContext().viewport.setCurrentValue({ 0, 0, getFramebufferSize() }); - assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue()); -} - +/** + * From mbgl::View + */ void NativeMapView::bind() { getContext().bindFramebuffer = 0; getContext().viewport = { 0, 0, getFramebufferSize() }; } +/** + * From mbgl::Backend. Callback to java NativeMapView#onInvalidate(). + * + * May be called from any thread + */ void NativeMapView::invalidate() { Log::Info(mbgl::Event::Android, "NativeMapView::invalidate"); + android::UniqueEnv _env = android::AttachEnv(); + static auto onInvalidate = javaClass.GetMethod(*_env, "onInvalidate"); + javaPeer->Call(*_env, onInvalidate); +} + +/** + * From mbgl::Backend. Callback to java NativeMapView#onMapChanged(int). + * + * May be called from any thread + */ +void NativeMapView::notifyMapChange(mbgl::MapChange change) { + mbgl::Log::Info(mbgl::Event::Android, "notifyMapChange"); assert(vm != nullptr); - assert(obj != nullptr); - JNIEnv *env2; - jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Callback Thread"); - if (!renderDetach) { - env2->CallVoidMethod(obj, onInvalidateId); - if(env2->ExceptionCheck()) { - env2->ExceptionDescribe(); - } - } + + android::UniqueEnv _env = android::AttachEnv(); + static auto onMapChanged = javaClass.GetMethod(*_env, "onMapChanged"); + javaPeer->Call(*_env, onMapChanged, (int) change); +} + +// JNI Methods // + +void NativeMapView::onViewportChanged(jni::JNIEnv&, jni::jint w, jni::jint h) { + resizeView((int) w / pixelRatio, (int) h / pixelRatio); + resizeFramebuffer(w, h); } -void NativeMapView::render() { +void NativeMapView::render(jni::JNIEnv& env) { mbgl::Log::Info(mbgl::Event::Android, "NativeMapView::render"); + if (firstRender) { + mbgl::Log::Info(mbgl::Event::Android, "Initialize GL extensions"); + mbgl::gl::InitializeExtensions([] (const char * name) { + return reinterpret_cast(eglGetProcAddress(name)); + }); + firstRender = false; + } + + //First, spin the run loop to process the queue (as there is no actual loop on the render thread) + mbgl::util::RunLoop::Get()->runOnce(); + if (framebufferSizeChanged) { getContext().viewport = { 0, 0, getFramebufferSize() }; framebufferSizeChanged = false; @@ -148,85 +165,576 @@ void NativeMapView::render() { // take snapshot auto image = getContext().readFramebuffer(getFramebufferSize()); - auto bitmap = Bitmap::CreateBitmap(*env, std::move(image)); - - JNIEnv *env2; - jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Callback Thread"); - if (!renderDetach) { - env2->CallVoidMethod(obj, onSnapshotReadyId, jni::Unwrap(*bitmap)); - if (env2->ExceptionCheck()) { - env2->ExceptionDescribe(); - } - } + auto bitmap = Bitmap::CreateBitmap(env, std::move(image)); + + android::UniqueEnv _env = android::AttachEnv(); + static auto onSnapshotReady = javaClass.GetMethod)>(*_env, "onSnapshotReady"); + javaPeer->Call(*_env, onSnapshotReady, bitmap); } updateFps(); } -mbgl::Map &NativeMapView::getMap() { return *map; } +void NativeMapView::setAPIBaseUrl(jni::JNIEnv& env, jni::String url) { + fileSource->setAPIBaseURL(jni::Make(env, url)); +} -mbgl::DefaultFileSource &NativeMapView::getFileSource() { return *fileSource; } +jni::String NativeMapView::getStyleUrl(jni::JNIEnv& env) { + return jni::Make(env, map->getStyleURL()); +} -void NativeMapView::scheduleTakeSnapshot() { - snapshot = true; +void NativeMapView::setStyleUrl(jni::JNIEnv& env, jni::String url) { + map->setStyleURL(jni::Make(env, url)); } +jni::String NativeMapView::getStyleJson(jni::JNIEnv& env) { + return jni::Make(env, map->getStyleJSON()); +} -void NativeMapView::notifyMapChange(mbgl::MapChange change) { - mbgl::Log::Info(mbgl::Event::Android, "notifyMapChange"); - assert(vm != nullptr); - assert(obj != nullptr); - - JNIEnv *env2; - jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Callback Thread"); - if (!renderDetach) { - env2->CallVoidMethod(obj, onMapChangedId, change); - if(env2->ExceptionCheck()) { - env2->ExceptionDescribe(); - } +void NativeMapView::setStyleJson(jni::JNIEnv& env, jni::String json) { + map->setStyleJSON(jni::Make(env, json)); +} + +jni::String NativeMapView::getAccessToken(jni::JNIEnv& env) { + return jni::Make(env, fileSource->getAccessToken()); +} + +void NativeMapView::setAccessToken(jni::JNIEnv& env, jni::String token) { + fileSource->setAccessToken(jni::Make(env, token)); +} + +void NativeMapView::cancelTransitions(jni::JNIEnv&) { + map->cancelTransitions(); +} + +void NativeMapView::setGestureInProgress(jni::JNIEnv&, jni::jboolean inProgress) { + map->setGestureInProgress(inProgress); +} + +void NativeMapView::moveBy(jni::JNIEnv&, jni::jdouble dx, jni::jdouble dy) { + map->moveBy({dx, dy}); +} + +jni::Object NativeMapView::getLatLng(JNIEnv& env) { + mbgl::LatLng latLng = map->getLatLng(insets); + return LatLng::New(env, latLng.latitude, latLng.longitude); +} + +void NativeMapView::setLatLng(jni::JNIEnv&, jni::jdouble latitude, jni::jdouble longitude) { + map->setLatLng(mbgl::LatLng(latitude, longitude), insets); +} + +void NativeMapView::setReachability(jni::JNIEnv&, jni::jboolean reachable) { + if (reachable) { + mbgl::NetworkStatus::Reachable(); } } -void NativeMapView::enableFps(bool enable) { +void NativeMapView::resetPosition(jni::JNIEnv&) { + map->resetPosition(); +} + +jni::jdouble NativeMapView::getPitch(jni::JNIEnv&) { + return map->getPitch(); +} + +void NativeMapView::setPitch(jni::JNIEnv&, jni::jdouble pitch) { + map->setPitch(pitch); +} + +void NativeMapView::scaleBy(jni::JNIEnv&, jni::jdouble ds, jni::jdouble cx, jni::jdouble cy) { + mbgl::ScreenCoordinate center(cx, cy); + map->scaleBy(ds, center); +} + +void NativeMapView::setScale(jni::JNIEnv&, jni::jdouble scale, jni::jdouble cx, jni::jdouble cy) { + mbgl::ScreenCoordinate center(cx, cy); + map->setScale(scale, center); +} + +jni::jdouble NativeMapView::getScale(jni::JNIEnv&) { + return map->getScale(); +} + +void NativeMapView::setZoom(jni::JNIEnv&, jni::jdouble zoom) { + map->setZoom(zoom); +} + +jni::jdouble NativeMapView::getZoom(jni::JNIEnv&) { + return map->getZoom(); +} + +void NativeMapView::resetZoom(jni::JNIEnv&) { + map->resetZoom(); +} + +void NativeMapView::setMinZoom(jni::JNIEnv&, jni::jdouble zoom) { + map->setMinZoom(zoom); +} + +jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) { + return map->getMinZoom(); +} + +void NativeMapView::setMaxZoom(jni::JNIEnv&, jni::jdouble zoom) { + map->setMaxZoom(zoom); +} + +jni::jdouble NativeMapView::getMaxZoom(jni::JNIEnv&) { + return map->getMaxZoom(); +} + +void NativeMapView::rotateBy(jni::JNIEnv&, jni::jdouble sx, jni::jdouble sy, jni::jdouble ex, jni::jdouble ey) { + mbgl::ScreenCoordinate first(sx, sy); + mbgl::ScreenCoordinate second(ex, ey); + map->rotateBy(first, second); +} + +void NativeMapView::setBearing(jni::JNIEnv&, jni::jdouble degrees) { + map->setBearing(degrees); +} + +void NativeMapView::setBearingXY(jni::JNIEnv&, jni::jdouble degrees, jni::jdouble cx, jni::jdouble cy) { + mbgl::ScreenCoordinate center(cx, cy); + map->setBearing(degrees, center); +} + +jni::jdouble NativeMapView::getBearing(jni::JNIEnv&) { + return map->getBearing(); +} + +void NativeMapView::resetNorth(jni::JNIEnv&) { + map->resetNorth(); +} + +void NativeMapView::setVisibleCoordinateBounds(JNIEnv& env, jni::Array> coordinates, jni::Object padding, jdouble direction) { + NullCheck(env, &coordinates); + std::size_t count = coordinates.Length(env); + + std::vector latLngs; + latLngs.reserve(count); + + for (std::size_t i = 0; i < count; i++) { + auto latLng = coordinates.Get(env, i); + latLngs.push_back(LatLng::getLatLng(env, latLng)); + jni::DeleteLocalRef(env, latLng); + } + + mbgl::EdgeInsets mbglInsets = { RectF::getTop(env, padding), RectF::getLeft(env, padding), RectF::getBottom(env, padding), RectF::getRight(env, padding) }; + mbgl::CameraOptions cameraOptions = map->cameraForLatLngs(latLngs, mbglInsets); + if (direction >= 0) { + // convert from degrees to radians + cameraOptions.angle = (-direction * M_PI) / 180; + } + + mbgl::AnimationOptions animationOptions; + map->easeTo(cameraOptions, animationOptions); +} + +void NativeMapView::setContentPadding(JNIEnv&, double top, double left, double bottom, double right) { + insets = {top, left, bottom, right}; +} + +void NativeMapView::scheduleSnapshot(jni::JNIEnv&) { + snapshot = true; +} + +void NativeMapView::enableFps(jni::JNIEnv&, jni::jboolean enable) { fpsEnabled = enable; } -void NativeMapView::updateFps() { - if (!fpsEnabled) { +jni::Array NativeMapView::getCameraValues(jni::JNIEnv& env) { + //Create buffer with values + jdouble buf[5]; + mbgl::LatLng latLng = map->getLatLng(insets); + buf[0] = latLng.latitude; + buf[1] = latLng.longitude; + buf[2] = -map->getBearing(); + buf[3] = map->getPitch(); + buf[4] = map->getZoom(); + + //Convert to Java array + auto output = jni::Array::New(env, 5); + jni::SetArrayRegion(env, *output, 0, 5, buf); + + return output; +} + +void NativeMapView::updateMarker(jni::JNIEnv& env, jni::jlong markerId, jni::jdouble lat, jni::jdouble lon, jni::String jid) { + if (markerId == -1) { return; } - static int frames = 0; - static int64_t timeElapsed = 0LL; + std::string iconId = jni::Make(env, jid); + // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long. + map->updateAnnotation(markerId, mbgl::SymbolAnnotation { mbgl::Point(lon, lat), iconId }); +} - frames++; - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - int64_t currentTime = now.tv_sec * 1000000000LL + now.tv_nsec; +jni::Array NativeMapView::addMarkers(jni::JNIEnv& env, jni::Array> jmarkers) { + jni::NullCheck(env, &jmarkers); + std::size_t len = jmarkers.Length(env); - if (currentTime - timeElapsed >= 1) { - fps = frames / ((currentTime - timeElapsed) / 1E9); - mbgl::Log::Info(mbgl::Event::Render, "FPS: %4.2f", fps); - timeElapsed = currentTime; - frames = 0; + std::vector ids; + ids.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + jni::Object marker = jmarkers.Get(env, i); + ids.push_back(map->addAnnotation(mbgl::SymbolAnnotation { + Marker::getPosition(env, marker), + Marker::getIconId(env, marker) + })); + + jni::DeleteLocalRef(env, marker); } - assert(vm != nullptr); - assert(obj != nullptr); - - JNIEnv *env2; - jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Callback Thread"); - if (!renderDetach) { - env2->CallVoidMethod(obj, onFpsChangedId, fps); - if(env2->ExceptionCheck()) { - env2->ExceptionDescribe(); + auto result = jni::Array::New(env, len); + result.SetRegion>(env, 0, ids); + + return result; +} + +void NativeMapView::onLowMemory(JNIEnv&) { + map->onLowMemory(); +} + +void NativeMapView::setDebug(JNIEnv&, jni::jboolean debug) { + DebugOptions debugOptions = debug ? DebugOptions::TileBorders | DebugOptions::ParseStatus | DebugOptions::Collision + : DebugOptions::NoDebug; + map->setDebug(debugOptions); + fpsEnabled = debug; +} + +void NativeMapView::cycleDebugOptions(JNIEnv&) { + map->cycleDebugOptions(); + fpsEnabled = map->getDebug() != DebugOptions::NoDebug; +} + +jni::jboolean NativeMapView::getDebug(JNIEnv&) { + return map->getDebug() != DebugOptions::NoDebug; +} + +jni::jboolean NativeMapView::isFullyLoaded(JNIEnv&) { + return map->isFullyLoaded(); +} + +jni::jdouble NativeMapView::getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble lat, jni::jdouble zoom) { + return map->getMetersPerPixelAtLatitude(lat, zoom); +} + +jni::Object NativeMapView::projectedMetersForLatLng(JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude) { + mbgl::ProjectedMeters projectedMeters = map->projectedMetersForLatLng(mbgl::LatLng(latitude, longitude)); + return ProjectedMeters::New(env, projectedMeters.northing, projectedMeters.easting); +} + +jni::Object NativeMapView::pixelForLatLng(JNIEnv& env, jdouble latitude, jdouble longitude) { + mbgl::ScreenCoordinate pixel = map->pixelForLatLng(mbgl::LatLng(latitude, longitude)); + return PointF::New(env, static_cast(pixel.x), static_cast(pixel.y)); +} + +jni::Object NativeMapView::latLngForProjectedMeters(JNIEnv& env, jdouble northing, jdouble easting) { + mbgl::LatLng latLng = map->latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting)); + return LatLng::New(env, latLng.latitude, latLng.longitude); +} + +jni::Object NativeMapView::latLngForPixel(JNIEnv& env, jfloat x, jfloat y) { + mbgl::LatLng latLng = map->latLngForPixel(mbgl::ScreenCoordinate(x, y)); + return LatLng::New(env, latLng.latitude, latLng.longitude); +} + +jni::Array NativeMapView::addPolylines(JNIEnv& env, jni::Array> polylines) { + NullCheck(env, &polylines); + std::size_t len = polylines.Length(env); + + std::vector ids; + ids.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + auto polyline = polylines.Get(env, i); + + mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polyline); + ids.push_back(map->addAnnotation(annotation)); + + jni::DeleteLocalRef(env, polyline); + } + + auto result = jni::Array::New(env, len); + result.SetRegion>(env, 0, ids); + + return result; +} + + +jni::Array NativeMapView::addPolygons(JNIEnv& env, jni::Array> polygons) { + NullCheck(env, &polygons); + std::size_t len = polygons.Length(env); + + std::vector ids; + ids.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + auto polygon = polygons.Get(env, i); + + mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygon); + ids.push_back(map->addAnnotation(annotation)); + + jni::DeleteLocalRef(env, polygon); + } + + auto result = jni::Array::New(env, len); + result.SetRegion>(env, 0, ids); + + return result; +} + +//TODO: Move to Polyline class and make native peer +void NativeMapView::updatePolyline(JNIEnv& env, jlong polylineId, jni::Object polyline) { + mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polyline); + map->updateAnnotation(polylineId, annotation); +} + +//TODO: Move to Polygon class and make native peer +void NativeMapView::updatePolygon(JNIEnv& env, jlong polygonId, jni::Object polygon) { + mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygon); + map->updateAnnotation(polygonId, annotation); +} + +void NativeMapView::removeAnnotations(JNIEnv& env, jni::Array ids) { + NullCheck(env, &ids); + std::size_t len = ids.Length(env); + auto elements = jni::GetArrayElements(env, *ids); + jlong* jids = std::get<0>(elements).get(); + + for (std::size_t i = 0; i < len; i++) { + if(jids[i] == -1L) { + continue; } + map->removeAnnotation(jids[i]); } } -void NativeMapView::onViewportChanged(int w, int h) { - resizeView((int) w / pixelRatio, (int) h / pixelRatio); - resizeFramebuffer(w, h); +void NativeMapView::addAnnotationIcon(JNIEnv& env, jni::String symbol, jint w, jint h, jfloat scale, jni::Array jpixels) { + const std::string symbolName = jni::Make(env, symbol); + + NullCheck(env, &jpixels); + std::size_t size = jpixels.Length(env); + + mbgl::PremultipliedImage premultipliedImage({ static_cast(w), static_cast(h) }); + if (premultipliedImage.bytes() != uint32_t(size)) { + throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch"); + } + + jni::GetArrayRegion(env, *jpixels, 0, size, reinterpret_cast(premultipliedImage.data.get())); + auto iconImage = std::make_shared(std::move(premultipliedImage), float(scale)); + map->addAnnotationIcon(symbolName, iconImage); +} + +jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, jni::String symbolName) { + return map->getTopOffsetPixelsForAnnotationIcon(jni::Make(env, symbolName)); +} + +jlong NativeMapView::getTransitionDuration(JNIEnv&) { + const auto transitionOptions = map->getTransitionOptions(); + return transitionOptions.duration.value_or(mbgl::Duration::zero()).count(); +} + +void NativeMapView::setTransitionDuration(JNIEnv&, jlong duration) { + auto transitionOptions = map->getTransitionOptions(); + transitionOptions.duration = std::chrono::duration_cast(std::chrono::duration(duration)); + map->setTransitionOptions(transitionOptions); +} + +jlong NativeMapView::getTransitionDelay(JNIEnv&) { + const auto transitionOptions = map->getTransitionOptions(); + return transitionOptions.delay.value_or(mbgl::Duration::zero()).count(); +} + +void NativeMapView::setTransitionDelay(JNIEnv&, jlong delay) { + auto transitionOptions = map->getTransitionOptions(); + transitionOptions.delay = std::chrono::duration_cast(std::chrono::duration(delay)); + map->setTransitionOptions(transitionOptions); +} + +jni::Array NativeMapView::queryPointAnnotations(JNIEnv& env, jni::Object rect) { + // Convert input + mbgl::ScreenBox box = { + { RectF::getLeft(env, rect), RectF::getTop(env, rect) }, + { RectF::getRight(env, rect), RectF::getBottom(env, rect) }, + }; + + // Assume only points for now + mbgl::AnnotationIDs ids = map->queryPointAnnotations(box); + + // Convert result + std::vector longIds(ids.begin(), ids.end()); + auto result = jni::Array::New(env, ids.size()); + result.SetRegion>(env, 0, longIds); + + return result; +} + +jni::Array> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y, jni::Array layerIds) { + using namespace mbgl::android::conversion; + using namespace mapbox::geometry; + + mbgl::optional> layers; + if (layerIds != nullptr && layerIds.Length(env) > 0) { + layers = toVector(env, layerIds); + } + point point = {x, y}; + + return *convert>, std::vector>(env, map->queryRenderedFeatures(point, layers)); +} + +jni::Array> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top, jni::jfloat right, jni::jfloat bottom, jni::Array layerIds) { + using namespace mbgl::android::conversion; + using namespace mapbox::geometry; + + mbgl::optional> layers; + if (layerIds != nullptr && layerIds.Length(env) > 0) { + layers = toVector(env, layerIds); + } + box box = { point{ left, top}, point{ right, bottom } }; + + return *convert>, std::vector>(env, map->queryRenderedFeatures(box, layers)); +} + +jni::Object NativeMapView::getLayer(JNIEnv& env, jni::String layerId) { + + // Find the layer + mbgl::style::Layer* coreLayer = map->getLayer(jni::Make(env, layerId)); + if (!coreLayer) { + mbgl::Log::Debug(mbgl::Event::JNI, "No layer found"); + return jni::Object(); + } + + // Create and return the layer's native peer + return jni::Object(createJavaLayerPeer(env, *map, *coreLayer)); +} + +void NativeMapView::addLayer(JNIEnv& env, jlong nativeLayerPtr, jni::String before) { + assert(nativeLayerPtr != 0); + + Layer *layer = reinterpret_cast(nativeLayerPtr); + try { + layer->addToMap(*map, before ? mbgl::optional(jni::Make(env, before)) : mbgl::optional()); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what()); + } +} + +/** + * Remove by layer id. Ownership is not transferred back + */ +void NativeMapView::removeLayerById(JNIEnv& env, jni::String id) { + try { + map->removeLayer(jni::Make(env, id)); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/NoSuchLayerException"), error.what()); + } +} + +/** + * Remove with wrapper object id. Ownership is transferred back to the wrapper + */ +void NativeMapView::removeLayer(JNIEnv& env, jlong layerPtr) { + assert(layerPtr != 0); + + mbgl::android::Layer *layer = reinterpret_cast(layerPtr); + try { + std::unique_ptr coreLayer = map->removeLayer(layer->get().getID()); + layer->setLayer(std::move(coreLayer)); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/NoSuchLayerException"), error.what()); + } +} + + +jni::Object NativeMapView::getSource(JNIEnv& env, jni::String sourceId) { + // Find the source + mbgl::style::Source* coreSource = map->getSource(jni::Make(env, sourceId)); + if (!coreSource) { + mbgl::Log::Debug(mbgl::Event::JNI, "No source found"); + return jni::Object(); + } + + // Create and return the source's native peer + return jni::Object(createJavaSourcePeer(env, *map, *coreSource)); +} + +void NativeMapView::addSource(JNIEnv& env, jni::jlong sourcePtr) { + assert(sourcePtr != 0); + + Source *source = reinterpret_cast(sourcePtr); + try { + source->addToMap(*map); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what()); + } +} + +void NativeMapView::removeSourceById(JNIEnv& env, jni::String id) { + try { + map->removeSource(jni::Make(env, id)); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/sources/NoSuchSourceException"), error.what()); + } +} + +void NativeMapView::removeSource(JNIEnv& env, jlong sourcePtr) { + assert(sourcePtr != 0); + + mbgl::android::Source *source = reinterpret_cast(sourcePtr); + try { + std::unique_ptr coreSource = map->removeSource(source->get().getID()); + source->setSource(std::move(coreSource)); + } catch (const std::runtime_error& error) { + jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/sources/NoSuchSourceException"), error.what()); + } +} + +void NativeMapView::addImage(JNIEnv& env, jni::String name, jni::jint w, jni::jint h, jni::jfloat scale, jni::Array pixels) { + jni::NullCheck(env, &pixels); + std::size_t size = pixels.Length(env); + + mbgl::PremultipliedImage premultipliedImage({ static_cast(w), static_cast(h) }); + if (premultipliedImage.bytes() != uint32_t(size)) { + throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch"); + } + + jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast(premultipliedImage.data.get())); + auto spriteImage = std::make_unique(std::move(premultipliedImage), float(scale)); + + map->addImage(jni::Make(env, name), std::move(spriteImage)); +} + +void NativeMapView::removeImage(JNIEnv& env, jni::String name) { + map->removeImage(jni::Make(env, name)); +} + +// Private methods // + +mbgl::Size NativeMapView::getFramebufferSize() const { + mbgl::Log::Info(mbgl::Event::Android, "FB size %dx%d", fbWidth, fbHeight); + return { static_cast(fbWidth), static_cast(fbHeight) }; +} + +/** + * Called whenever the associated thread needs to wake up (since there is no active run loop) + * + * May be called from any thread + */ +void NativeMapView::wake() { + mbgl::Log::Info(mbgl::Event::JNI, "Wake callback"); + android::UniqueEnv _env = android::AttachEnv(); + static auto wakeCallback = javaClass.GetMethod(*_env, "onWake"); + javaPeer->Call(*_env, wakeCallback); +} + +void NativeMapView::updateViewBinding() { + getContext().bindFramebuffer.setCurrentValue(0); + assert(mbgl::gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue()); + getContext().viewport.setCurrentValue({ 0, 0, getFramebufferSize() }); + assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue()); } void NativeMapView::resizeView(int w, int h) { @@ -244,8 +752,123 @@ void NativeMapView::resizeFramebuffer(int w, int h) { invalidate(); } -void NativeMapView::setInsets(mbgl::EdgeInsets insets_) { - insets = insets_; +void NativeMapView::updateFps() { + if (!fpsEnabled) { + return; + } + + static int frames = 0; + static int64_t timeElapsed = 0LL; + + frames++; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + int64_t currentTime = now.tv_sec * 1000000000LL + now.tv_nsec; + + if (currentTime - timeElapsed >= 1) { + fps = frames / ((currentTime - timeElapsed) / 1E9); + mbgl::Log::Info(mbgl::Event::Render, "FPS: %4.2f", fps); + timeElapsed = currentTime; + frames = 0; + } + + assert(vm != nullptr); + + android::UniqueEnv _env = android::AttachEnv(); + static auto onFpsChanged = javaClass.GetMethod(*_env, "onFpsChanged"); + javaPeer->Call(*_env, onFpsChanged, fps); +} + +// Static methods // + +jni::Class NativeMapView::javaClass; + +void NativeMapView::registerNative(jni::JNIEnv& env) { + // Lookup the class + NativeMapView::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) + + // Register the peer + jni::RegisterNativePeer(env, NativeMapView::javaClass, "nativePtr", + std::make_unique, jni::String, jni::String, jni::jfloat, jni::jint, jni::jlong>, + "initialize", + "destroy", + METHOD(&NativeMapView::render, "render"), + METHOD(&NativeMapView::onViewportChanged, "_onViewportChanged"), + METHOD(&NativeMapView::setAPIBaseUrl , "setApiBaseUrl"), + METHOD(&NativeMapView::getStyleUrl, "getStyleUrl"), + METHOD(&NativeMapView::setStyleUrl, "setStyleUrl"), + METHOD(&NativeMapView::getStyleJson, "getStyleJson"), + METHOD(&NativeMapView::setStyleJson, "setStyleJson"), + METHOD(&NativeMapView::getAccessToken, "getAccessToken"), + METHOD(&NativeMapView::setAccessToken, "setAccessToken"), + METHOD(&NativeMapView::cancelTransitions, "cancelTransitions"), + METHOD(&NativeMapView::setGestureInProgress, "setGestureInProgress"), + METHOD(&NativeMapView::moveBy, "_moveBy"), + METHOD(&NativeMapView::getLatLng, "_getLatLng"), + METHOD(&NativeMapView::setLatLng, "setLatLng"), + METHOD(&NativeMapView::setReachability, "setReachability"), + METHOD(&NativeMapView::resetPosition, "resetPosition"), + METHOD(&NativeMapView::getPitch, "getPitch"), + METHOD(&NativeMapView::setPitch, "setPitch"), + METHOD(&NativeMapView::scaleBy, "_scaleBy"), + METHOD(&NativeMapView::setScale, "_setScale"), + METHOD(&NativeMapView::getScale, "getScale"), + METHOD(&NativeMapView::setZoom, "setZoom"), + METHOD(&NativeMapView::getZoom, "getZoom"), + METHOD(&NativeMapView::resetZoom, "resetZoom"), + METHOD(&NativeMapView::setMinZoom, "setMinZoom"), + METHOD(&NativeMapView::getMinZoom, "getMinZoom"), + METHOD(&NativeMapView::setMaxZoom, "setMaxZoom"), + METHOD(&NativeMapView::getMaxZoom, "getMaxZoom"), + METHOD(&NativeMapView::rotateBy, "_rotateBy"), + METHOD(&NativeMapView::setBearing, "setBearing"), + METHOD(&NativeMapView::setBearingXY, "_setBearingXY"), + METHOD(&NativeMapView::getBearing, "getBearing"), + METHOD(&NativeMapView::resetNorth, "resetNorth"), + METHOD(&NativeMapView::setVisibleCoordinateBounds, "setVisibleCoordinateBounds"), + METHOD(&NativeMapView::setContentPadding, "setContentPadding"), + METHOD(&NativeMapView::scheduleSnapshot, "scheduleSnapshot"), + METHOD(&NativeMapView::enableFps, "enableFps"), + METHOD(&NativeMapView::getCameraValues, "getCameraValues"), + METHOD(&NativeMapView::updateMarker, "updateMarker"), + METHOD(&NativeMapView::addMarkers, "addMarkers"), + METHOD(&NativeMapView::setDebug, "setDebug"), + METHOD(&NativeMapView::cycleDebugOptions, "cycleDebugOptions"), + METHOD(&NativeMapView::getDebug, "getDebug"), + METHOD(&NativeMapView::isFullyLoaded, "isFullyLoaded"), + METHOD(&NativeMapView::onLowMemory, "onLowMemory"), + METHOD(&NativeMapView::getMetersPerPixelAtLatitude, "getMetersPerPixelAtLatitude"), + METHOD(&NativeMapView::projectedMetersForLatLng, "projectedMetersForLatLng"), + METHOD(&NativeMapView::pixelForLatLng, "pixelForLatLng"), + METHOD(&NativeMapView::latLngForProjectedMeters, "latLngForProjectedMeters"), + METHOD(&NativeMapView::latLngForPixel, "latLngForPixel"), + METHOD(&NativeMapView::addPolylines, "addPolylines"), + METHOD(&NativeMapView::addPolygons, "addPolygons"), + METHOD(&NativeMapView::updatePolyline, "updatePolyline"), + METHOD(&NativeMapView::updatePolygon, "updatePolygon"), + METHOD(&NativeMapView::removeAnnotations, "removeAnnotations"), + METHOD(&NativeMapView::addAnnotationIcon, "addAnnotationIcon"), + METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "getTopOffsetPixelsForAnnotationSymbol"), + METHOD(&NativeMapView::getTransitionDuration, "getTransitionDuration"), + METHOD(&NativeMapView::setTransitionDuration, "setTransitionDuration"), + METHOD(&NativeMapView::getTransitionDelay, "getTransitionDelay"), + METHOD(&NativeMapView::setTransitionDelay, "setTransitionDelay"), + METHOD(&NativeMapView::queryPointAnnotations, "queryPointAnnotations"), + METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "queryRenderedFeaturesForPoint"), + METHOD(&NativeMapView::queryRenderedFeaturesForBox, "queryRenderedFeaturesForBox"), + METHOD(&NativeMapView::getLayer, "getLayer"), + METHOD(&NativeMapView::addLayer, "addLayer"), + METHOD(&NativeMapView::removeLayerById, "removeLayerById"), + METHOD(&NativeMapView::removeLayer, "removeLayer"), + METHOD(&NativeMapView::getSource, "getSource"), + METHOD(&NativeMapView::addSource, "addSource"), + METHOD(&NativeMapView::removeSourceById, "removeSourceById"), + METHOD(&NativeMapView::removeSource, "removeSource"), + METHOD(&NativeMapView::addImage, "addImage"), + METHOD(&NativeMapView::removeImage, "removeImage") + ); } } diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index 81274f3a24..185bb7b65c 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -1,22 +1,44 @@ #pragma once +#include +#include #include #include -#include #include #include #include #include +#include + +#include "annotation/marker.hpp" +#include "annotation/polygon.hpp" +#include "annotation/polyline.hpp" +#include "graphics/pointF.hpp" +#include "graphics/rectF.hpp" +#include "geometry/feature.hpp" +#include "geometry/lat_lng.hpp" +#include "geometry/projected_meters.hpp" +#include "style/layers/layers.hpp" +#include "style/sources/sources.hpp" #include #include +#include namespace mbgl { namespace android { -class NativeMapView : public mbgl::View, public mbgl::Backend { +class NativeMapView : public View, public Backend { public: - NativeMapView(JNIEnv *env, jobject obj, float pixelRatio, int availableProcessors, size_t totalMemory); + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/NativeMapView"; }; + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); + + NativeMapView(jni::JNIEnv&, jni::Object, jni::String, jni::String, jni::jfloat, jni::jint, jni::jlong); + virtual ~NativeMapView(); // mbgl::View // @@ -30,22 +52,158 @@ public: // JNI // - mbgl::Map &getMap(); - mbgl::DefaultFileSource &getFileSource(); + void destroy(jni::JNIEnv&); + + void render(jni::JNIEnv&); + + void onViewportChanged(jni::JNIEnv&, jni::jint width, jni::jint height); + + void setAPIBaseUrl(jni::JNIEnv&, jni::String); + + jni::String getStyleUrl(jni::JNIEnv&); + + void setStyleUrl(jni::JNIEnv&, jni::String); + + jni::String getStyleJson(jni::JNIEnv&); + + void setStyleJson(jni::JNIEnv&, jni::String); + + jni::String getAccessToken(jni::JNIEnv&); + + void setAccessToken(jni::JNIEnv&, jni::String); + + void cancelTransitions(jni::JNIEnv&); + + void setGestureInProgress(jni::JNIEnv&, jni::jboolean); + + void moveBy(jni::JNIEnv&, jni::jdouble, jni::jdouble); + + jni::Object getLatLng(JNIEnv&); + + void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble); + + void setReachability(jni::JNIEnv&, jni::jboolean); + + void resetPosition(jni::JNIEnv&); + + jni::jdouble getPitch(jni::JNIEnv&); + + void setPitch(jni::JNIEnv&, jni::jdouble); + + void scaleBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble); + + void setScale(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble); + + jni::jdouble getScale(jni::JNIEnv&); + + void setZoom(jni::JNIEnv&, jni::jdouble); + + jni::jdouble getZoom(jni::JNIEnv&); + + void resetZoom(jni::JNIEnv&); + + void setMinZoom(jni::JNIEnv&, jni::jdouble); + + jni::jdouble getMinZoom(jni::JNIEnv&); + + void setMaxZoom(jni::JNIEnv&, jni::jdouble); + + jni::jdouble getMaxZoom(jni::JNIEnv&); + + void rotateBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble); + + void setBearing(jni::JNIEnv&, jni::jdouble); + + void setBearingXY(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble); + + jni::jdouble getBearing(jni::JNIEnv&); + + void resetNorth(jni::JNIEnv&); + + void setVisibleCoordinateBounds(JNIEnv&, jni::Array>, jni::Object, jdouble); + + void setContentPadding(JNIEnv&, double, double, double, double); + + void scheduleSnapshot(jni::JNIEnv&); + + void enableFps(jni::JNIEnv&, jni::jboolean enable); + + jni::Array getCameraValues(jni::JNIEnv&); + + void updateMarker(jni::JNIEnv&, jni::jlong, jni::jdouble, jni::jdouble, jni::String); + + jni::Array addMarkers(jni::JNIEnv&, jni::Array>); + + void onLowMemory(JNIEnv& env); + + void setDebug(JNIEnv&, jni::jboolean); + + void cycleDebugOptions(JNIEnv&); + + jni::jboolean getDebug(JNIEnv&); + + jni::jboolean isFullyLoaded(JNIEnv&); + + jni::jdouble getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble, jni::jdouble); + + jni::Object projectedMetersForLatLng(JNIEnv&, jni::jdouble, jni::jdouble); + + jni::Object pixelForLatLng(JNIEnv&, jdouble, jdouble); + + jni::Object latLngForProjectedMeters(JNIEnv&, jdouble, jdouble); + + jni::Object latLngForPixel(JNIEnv&, jfloat, jfloat); + + jni::Array addPolylines(JNIEnv&, jni::Array>); + + jni::Array addPolygons(JNIEnv&, jni::Array>); + + void updatePolyline(JNIEnv&, jlong, jni::Object); + + void updatePolygon(JNIEnv&, jlong, jni::Object); + + void removeAnnotations(JNIEnv&, jni::Array); + + void addAnnotationIcon(JNIEnv&, jni::String, jint, jint, jfloat, jni::Array); + + jdouble getTopOffsetPixelsForAnnotationSymbol(JNIEnv&, jni::String); + + jlong getTransitionDuration(JNIEnv&); + + void setTransitionDuration(JNIEnv&, jlong); + + jlong getTransitionDelay(JNIEnv&); + + void setTransitionDelay(JNIEnv&, jlong); + + jni::Array queryPointAnnotations(JNIEnv&, jni::Object); + + jni::Array> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat, jni::Array); + + jni::Array> queryRenderedFeaturesForBox(JNIEnv&, jni::jfloat, jni::jfloat, jni::jfloat, jni::jfloat, jni::Array); + + jni::Object getLayer(JNIEnv&, jni::String); + + void addLayer(JNIEnv&, jlong, jni::String); + + void removeLayerById(JNIEnv&, jni::String); + + void removeLayer(JNIEnv&, jlong); + + jni::Object getSource(JNIEnv&, jni::String); - void render(); + void addSource(JNIEnv&, jni::jlong); - void enableFps(bool enable); + void removeSourceById(JNIEnv&, jni::String); - void onViewportChanged(int width, int height); + void removeSource(JNIEnv&, jlong); - mbgl::EdgeInsets getInsets() { return insets;} - void setInsets(mbgl::EdgeInsets insets_); + void addImage(JNIEnv&, jni::String, jni::jint, jni::jint, jni::jfloat, jni::Array); - void scheduleTakeSnapshot(); + void removeImage(JNIEnv&, jni::String); protected: - // Unused // + // Unused methods from mbgl::Backend // void activate() override {}; void deactivate() override {}; @@ -63,8 +221,7 @@ private: private: JavaVM *vm = nullptr; - JNIEnv *env = nullptr; - jweak obj = nullptr; + jni::UniqueWeakObject javaPeer; std::string styleUrl; std::string apiKey; @@ -72,6 +229,7 @@ private: float pixelRatio; bool fpsEnabled = false; bool snapshot = false; + bool firstRender = true; double fps = 0.0; int width = 0; diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp index 8ae694d115..d9b88ab52b 100644 --- a/platform/android/src/style/android_conversion.hpp +++ b/platform/android/src/style/android_conversion.hpp @@ -4,7 +4,6 @@ #include #include -#include #include #include -- cgit v1.2.1