summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvo van Dongen <info@ivovandongen.nl>2017-02-16 16:16:47 +0200
committerIvo van Dongen <ivovandongen@users.noreply.github.com>2017-02-24 17:54:20 +0200
commit465c949153a838bb3159204ab268eb551fbd2e6c (patch)
tree250922b879261580b1252a78b461218be9012bc0
parent7d9018093a61d327fa7ca1312845d2a00d928380 (diff)
downloadqtlocation-mapboxgl-465c949153a838bb3159204ab268eb551fbd2e6c.tar.gz
[android] jni high level binding refactor
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java8
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java5
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java464
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java148
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java81
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java23
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java139
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java168
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_delete.xml21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml2
-rw-r--r--platform/android/config.cmake48
-rw-r--r--platform/android/src/annotation/marker.cpp31
-rw-r--r--platform/android/src/annotation/marker.hpp30
-rw-r--r--platform/android/src/annotation/multi_point.hpp42
-rw-r--r--platform/android/src/annotation/polygon.cpp49
-rw-r--r--platform/android/src/annotation/polygon.hpp40
-rw-r--r--platform/android/src/annotation/polyline.cpp49
-rw-r--r--platform/android/src/annotation/polyline.hpp40
-rw-r--r--platform/android/src/conversion/collection.hpp13
-rw-r--r--platform/android/src/conversion/color.hpp24
-rw-r--r--platform/android/src/default_file_source.cpp20
-rw-r--r--platform/android/src/default_file_source.hpp12
-rw-r--r--platform/android/src/file_source.cpp106
-rw-r--r--platform/android/src/file_source.hpp53
-rw-r--r--platform/android/src/geometry/conversion/feature.hpp38
-rw-r--r--platform/android/src/geometry/feature.cpp20
-rw-r--r--platform/android/src/geometry/feature.hpp29
-rw-r--r--platform/android/src/geometry/geometry.hpp16
-rw-r--r--platform/android/src/geometry/lat_lng.cpp31
-rw-r--r--platform/android/src/geometry/lat_lng.hpp31
-rw-r--r--platform/android/src/geometry/lat_lng_bounds.cpp31
-rw-r--r--platform/android/src/geometry/lat_lng_bounds.hpp29
-rw-r--r--platform/android/src/geometry/projected_meters.cpp20
-rw-r--r--platform/android/src/geometry/projected_meters.hpp26
-rw-r--r--platform/android/src/graphics/pointf.cpp20
-rw-r--r--platform/android/src/graphics/pointf.hpp25
-rw-r--r--platform/android/src/graphics/rectf.cpp35
-rw-r--r--platform/android/src/graphics/rectf.hpp31
-rw-r--r--platform/android/src/gson/json_object.hpp16
-rw-r--r--platform/android/src/java/util.cpp18
-rw-r--r--platform/android/src/java/util.hpp33
-rwxr-xr-xplatform/android/src/jni.cpp2094
-rw-r--r--platform/android/src/jni.hpp10
-rw-r--r--platform/android/src/jni/generic_global_ref_deleter.hpp22
-rwxr-xr-xplatform/android/src/native_map_view.cpp1163
-rwxr-xr-xplatform/android/src/native_map_view.hpp256
-rw-r--r--platform/android/src/offline/offline_manager.cpp164
-rw-r--r--platform/android/src/offline/offline_manager.hpp75
-rw-r--r--platform/android/src/offline/offline_region.cpp308
-rw-r--r--platform/android/src/offline/offline_region.hpp99
-rw-r--r--platform/android/src/offline/offline_region_definition.cpp69
-rw-r--r--platform/android/src/offline/offline_region_definition.hpp34
-rw-r--r--platform/android/src/offline/offline_region_error.cpp53
-rw-r--r--platform/android/src/offline/offline_region_error.hpp21
-rw-r--r--platform/android/src/offline/offline_region_status.cpp39
-rw-r--r--platform/android/src/offline/offline_region_status.hpp21
-rw-r--r--platform/android/src/style/android_conversion.hpp1
62 files changed, 3709 insertions, 2846 deletions
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..0707cc5cdd 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;
@@ -51,24 +53,19 @@ public class Marker extends Annotation {
* @param baseMarkerOptions The builder used to construct the Marker.
*/
public Marker(BaseMarkerOptions baseMarkerOptions) {
- position = baseMarkerOptions.position;
- snippet = baseMarkerOptions.snippet;
- icon = baseMarkerOptions.icon;
- title = baseMarkerOptions.title;
+ this(baseMarkerOptions.position, baseMarkerOptions.icon, baseMarkerOptions.title, baseMarkerOptions.snippet);
}
Marker(BaseMarkerViewOptions baseMarkerViewOptions) {
- position = baseMarkerViewOptions.position;
- snippet = baseMarkerViewOptions.snippet;
- icon = baseMarkerViewOptions.icon;
- title = baseMarkerViewOptions.title;
+ this(baseMarkerViewOptions.position, baseMarkerViewOptions.icon,
+ baseMarkerViewOptions.title, baseMarkerViewOptions.snippet);
}
Marker(LatLng position, Icon icon, String title, String snippet) {
this.position = position;
- this.icon = icon;
this.title = title;
this.snippet = snippet;
+ setIcon(icon);
}
/**
@@ -148,6 +145,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 2a3aeea979..658889761a 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
@@ -22,7 +22,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v7.app.AlertDialog;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -203,8 +202,6 @@ public class MapView extends FrameLayout {
*/
@UiThread
public void onCreate(@Nullable Bundle savedInstanceState) {
- nativeMapView.setAccessToken(Mapbox.getAccessToken());
-
if (savedInstanceState == null) {
MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapLoadEvent());
} else if (savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) {
@@ -409,11 +406,6 @@ public class MapView extends FrameLayout {
return;
}
- // stopgap for https://github.com/mapbox/mapbox-gl-native/issues/6242
- if (TextUtils.isEmpty(nativeMapView.getAccessToken())) {
- nativeMapView.setAccessToken(Mapbox.getAccessToken());
- }
-
nativeMapView.setStyleUrl(url);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
index 697e62828a..c95d391271 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
@@ -16,7 +16,6 @@ import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
-import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
@@ -866,10 +865,6 @@ public final class MapboxMap {
private void setStyleUrl(@NonNull MapboxMapOptions options) {
String style = options.getStyle();
if (!TextUtils.isEmpty(style)) {
- // stopgap for https://github.com/mapbox/mapbox-gl-native/issues/6242
- if (TextUtils.isEmpty(nativeMapView.getAccessToken())) {
- nativeMapView.setAccessToken(Mapbox.getAccessToken());
- }
setStyleUrl(style);
}
}
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 c17f538434..aed3f6b307 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
@@ -19,8 +19,10 @@ 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.storage.FileSource;
+import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.commons.geojson.Feature;
@@ -32,6 +34,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
import timber.log.Timber;
+;
+
// Class that wraps the native methods for convenience
final class NativeMapView {
@@ -39,11 +43,14 @@ final class NativeMapView {
private boolean destroyed = false;
// Holds the pointer to JNI NativeMapView
- private long nativeMapViewPtr = 0;
+ private long nativePtr = 0;
// Used for callbacks
private MapView mapView;
+ //Hold a reference to prevent it from being GC'd as long as it's used on the native side
+ private final FileSource fileSource;
+
// Device density
private final float pixelRatio;
@@ -67,15 +74,9 @@ final class NativeMapView {
public NativeMapView(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;
+ fileSource = FileSource.getInstance(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);
@@ -94,7 +95,8 @@ final class NativeMapView {
}
onMapChangedListeners = new CopyOnWriteArrayList<>();
this.mapView = mapView;
- nativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath, pixelRatio, availableProcessors, totalMemory);
+
+ nativeInitialize(this, fileSource, pixelRatio, availableProcessors, totalMemory);
}
//
@@ -111,8 +113,7 @@ final class NativeMapView {
}
public void destroy() {
- nativeDestroy(nativeMapViewPtr);
- nativeMapViewPtr = 0;
+ nativeDestroy();
mapView = null;
destroyed = true;
}
@@ -121,56 +122,56 @@ final class NativeMapView {
if (isDestroyedOn("initializeDisplay")) {
return;
}
- nativeInitializeDisplay(nativeMapViewPtr);
+ nativeInitializeDisplay();
}
public void terminateDisplay() {
if (isDestroyedOn("terminateDisplay")) {
return;
}
- nativeTerminateDisplay(nativeMapViewPtr);
+ nativeTerminateDisplay();
}
public void initializeContext() {
if (isDestroyedOn("initializeContext")) {
return;
}
- nativeInitializeContext(nativeMapViewPtr);
+ nativeInitializeContext();
}
public void terminateContext() {
if (isDestroyedOn("terminateContext")) {
return;
}
- nativeTerminateContext(nativeMapViewPtr);
+ nativeTerminateContext();
}
public void createSurface(Surface surface) {
if (isDestroyedOn("createSurface")) {
return;
}
- nativeCreateSurface(nativeMapViewPtr, surface);
+ nativeCreateSurface(surface);
}
public void destroySurface() {
if (isDestroyedOn("destroySurface")) {
return;
}
- nativeDestroySurface(nativeMapViewPtr);
+ nativeDestroySurface();
}
public void update() {
if (isDestroyedOn("update")) {
return;
}
- nativeUpdate(nativeMapViewPtr);
+ nativeUpdate();
}
public void render() {
if (isDestroyedOn("render")) {
return;
}
- nativeRender(nativeMapViewPtr);
+ nativeRender();
}
public void resizeView(int width, int height) {
@@ -201,7 +202,7 @@ final class NativeMapView {
+ "capping value at 65535 instead of " + height);
height = 65535;
}
- nativeViewResize(nativeMapViewPtr, width, height);
+ nativeResizeView(width, height);
}
public void resizeFramebuffer(int fbWidth, int fbHeight) {
@@ -225,98 +226,49 @@ final class NativeMapView {
throw new IllegalArgumentException(
"fbHeight cannot be greater than 65535.");
}
- nativeFramebufferResize(nativeMapViewPtr, fbWidth, fbHeight);
- }
-
- public void addClass(String clazz) {
- if (isDestroyedOn("addClass")) {
- return;
- }
- nativeAddClass(nativeMapViewPtr, clazz);
- }
-
- public void removeClass(String clazz) {
- if (isDestroyedOn("removeClass")) {
- return;
- }
- nativeRemoveClass(nativeMapViewPtr, clazz);
- }
-
- public boolean hasClass(String clazz) {
- if (isDestroyedOn("hasClass")) {
- return false;
- }
- return nativeHasClass(nativeMapViewPtr, clazz);
- }
-
- public void setClasses(List<String> classes) {
- if (isDestroyedOn("setClasses")) {
- return;
- }
- nativeSetClasses(nativeMapViewPtr, classes);
- }
-
- public List<String> getClasses() {
- if (isDestroyedOn("getClasses")) {
- return new ArrayList<>();
- }
- return nativeGetClasses(nativeMapViewPtr);
+ nativeResizeFramebuffer(fbWidth, fbHeight);
}
public void setStyleUrl(String url) {
if (isDestroyedOn("setStyleUrl")) {
return;
}
- nativeSetStyleUrl(nativeMapViewPtr, url);
+ nativeSetStyleUrl(url);
}
public String getStyleUrl() {
if (isDestroyedOn("getStyleUrl")) {
return null;
}
- return nativeGetStyleUrl(nativeMapViewPtr);
+ return nativeGetStyleUrl();
}
public void setStyleJson(String newStyleJson) {
if (isDestroyedOn("setStyleJson")) {
return;
}
- nativeSetStyleJson(nativeMapViewPtr, newStyleJson);
+ nativeSetStyleJson(newStyleJson);
}
public String getStyleJson() {
if (isDestroyedOn("getStyleJson")) {
return null;
}
- return nativeGetStyleJson(nativeMapViewPtr);
- }
-
- public void setAccessToken(String accessToken) {
- if (isDestroyedOn("setAccessToken")) {
- return;
- }
- nativeSetAccessToken(nativeMapViewPtr, accessToken);
- }
-
- public String getAccessToken() {
- if (isDestroyedOn("getAccessToken")) {
- return null;
- }
- return nativeGetAccessToken(nativeMapViewPtr);
+ return nativeGetStyleJson();
}
public void cancelTransitions() {
if (isDestroyedOn("cancelTransitions")) {
return;
}
- nativeCancelTransitions(nativeMapViewPtr);
+ nativeCancelTransitions();
}
public void setGestureInProgress(boolean inProgress) {
if (isDestroyedOn("setGestureInProgress")) {
return;
}
- nativeSetGestureInProgress(nativeMapViewPtr, inProgress);
+ nativeSetGestureInProgress(inProgress);
}
public void moveBy(double dx, double dy) {
@@ -330,7 +282,7 @@ final class NativeMapView {
if (isDestroyedOn("moveBy")) {
return;
}
- nativeMoveBy(nativeMapViewPtr, dx / pixelRatio, dy / pixelRatio, duration);
+ nativeMoveBy(dx / pixelRatio, dy / pixelRatio, duration);
}
public void setLatLng(LatLng latLng) {
@@ -344,7 +296,7 @@ final class NativeMapView {
if (isDestroyedOn("setLatLng")) {
return;
}
- nativeSetLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude(), duration);
+ nativeSetLatLng(latLng.getLatitude(), latLng.getLongitude(), duration);
}
public LatLng getLatLng() {
@@ -352,28 +304,28 @@ final class NativeMapView {
return new LatLng();
}
// wrap longitude values coming from core
- return nativeGetLatLng(nativeMapViewPtr).wrap();
+ return nativeGetLatLng().wrap();
}
public void resetPosition() {
if (isDestroyedOn("resetPosition")) {
return;
}
- nativeResetPosition(nativeMapViewPtr);
+ nativeResetPosition();
}
public double getPitch() {
if (isDestroyedOn("getPitch")) {
return 0;
}
- return nativeGetPitch(nativeMapViewPtr);
+ return nativeGetPitch();
}
public void setPitch(double pitch, long duration) {
if (isDestroyedOn("setPitch")) {
return;
}
- nativeSetPitch(nativeMapViewPtr, pitch, duration);
+ nativeSetPitch(pitch, duration);
}
public void scaleBy(double ds) {
@@ -394,7 +346,7 @@ final class NativeMapView {
if (isDestroyedOn("scaleBy")) {
return;
}
- nativeScaleBy(nativeMapViewPtr, ds, cx / pixelRatio, cy / pixelRatio, duration);
+ nativeScaleBy(ds, cx / pixelRatio, cy / pixelRatio, duration);
}
public void setScale(double scale) {
@@ -415,14 +367,14 @@ final class NativeMapView {
if (isDestroyedOn("setScale")) {
return;
}
- nativeSetScale(nativeMapViewPtr, scale, cx / pixelRatio, cy / pixelRatio, duration);
+ nativeSetScale(scale, cx / pixelRatio, cy / pixelRatio, duration);
}
public double getScale() {
if (isDestroyedOn("getScale")) {
return 0;
}
- return nativeGetScale(nativeMapViewPtr);
+ return nativeGetScale();
}
public void setZoom(double zoom) {
@@ -436,49 +388,49 @@ final class NativeMapView {
if (isDestroyedOn("setZoom")) {
return;
}
- nativeSetZoom(nativeMapViewPtr, zoom, duration);
+ nativeSetZoom(zoom, duration);
}
public double getZoom() {
if (isDestroyedOn("getZoom")) {
return 0;
}
- return nativeGetZoom(nativeMapViewPtr);
+ return nativeGetZoom();
}
public void resetZoom() {
if (isDestroyedOn("resetZoom")) {
return;
}
- nativeResetZoom(nativeMapViewPtr);
+ nativeResetZoom();
}
public void setMinZoom(double zoom) {
if (isDestroyedOn("setMinZoom")) {
return;
}
- nativeSetMinZoom(nativeMapViewPtr, zoom);
+ nativeSetMinZoom(zoom);
}
public double getMinZoom() {
if (isDestroyedOn("getMinZoom")) {
return 0;
}
- return nativeGetMinZoom(nativeMapViewPtr);
+ return nativeGetMinZoom();
}
public void setMaxZoom(double zoom) {
if (isDestroyedOn("setMaxZoom")) {
return;
}
- nativeSetMaxZoom(nativeMapViewPtr, zoom);
+ nativeSetMaxZoom(zoom);
}
public double getMaxZoom() {
if (isDestroyedOn("getMaxZoom")) {
return 0;
}
- return nativeGetMaxZoom(nativeMapViewPtr);
+ return nativeGetMaxZoom();
}
public void rotateBy(double sx, double sy, double ex, double ey) {
@@ -493,14 +445,14 @@ final class NativeMapView {
if (isDestroyedOn("rotateBy")) {
return;
}
- nativeRotateBy(nativeMapViewPtr, sx / pixelRatio, sy / pixelRatio, ex, ey, duration);
+ nativeRotateBy(sx / pixelRatio, sy / pixelRatio, ex, ey, duration);
}
public void setContentPadding(int[] padding) {
if (isDestroyedOn("setContentPadding")) {
return;
}
- nativeSetContentPadding(nativeMapViewPtr,
+ nativeSetContentPadding(
padding[1] / pixelRatio,
padding[0] / pixelRatio,
padding[3] / pixelRatio,
@@ -518,35 +470,35 @@ final class NativeMapView {
if (isDestroyedOn("setBearing")) {
return;
}
- nativeSetBearing(nativeMapViewPtr, degrees, duration);
+ nativeSetBearing(degrees, duration);
}
public void setBearing(double degrees, double cx, double cy) {
if (isDestroyedOn("setBearing")) {
return;
}
- nativeSetBearingXY(nativeMapViewPtr, degrees, cx / pixelRatio, cy / pixelRatio);
+ setBearing(degrees, cx, cy, 0);
}
public void setBearing(double degrees, double fx, double fy, long duration) {
if (isDestroyedOn("setBearing")) {
return;
}
- nativeSetFocalBearing(nativeMapViewPtr, degrees, fx / pixelRatio, fy / pixelRatio, duration);
+ nativeSetBearingXY(degrees, fx / pixelRatio, fy / pixelRatio, duration);
}
public double getBearing() {
if (isDestroyedOn("getBearing")) {
return 0;
}
- return nativeGetBearing(nativeMapViewPtr);
+ return nativeGetBearing();
}
public void resetNorth() {
if (isDestroyedOn("resetNorth")) {
return;
}
- nativeResetNorth(nativeMapViewPtr);
+ nativeResetNorth();
}
public long addMarker(Marker marker) {
@@ -554,14 +506,14 @@ final class NativeMapView {
return 0;
}
Marker[] markers = {marker};
- return nativeAddMarkers(nativeMapViewPtr, markers)[0];
+ return nativeAddMarkers(markers)[0];
}
public long[] addMarkers(List<Marker> markers) {
if (isDestroyedOn("addMarkers")) {
return new long[] {};
}
- return nativeAddMarkers(nativeMapViewPtr, markers.toArray(new Marker[markers.size()]));
+ return nativeAddMarkers(markers.toArray(new Marker[markers.size()]));
}
public long addPolyline(Polyline polyline) {
@@ -569,14 +521,14 @@ final class NativeMapView {
return 0;
}
Polyline[] polylines = {polyline};
- return nativeAddPolylines(nativeMapViewPtr, polylines)[0];
+ return nativeAddPolylines(polylines)[0];
}
public long[] addPolylines(List<Polyline> polylines) {
if (isDestroyedOn("addPolylines")) {
return new long[] {};
}
- return nativeAddPolylines(nativeMapViewPtr, polylines.toArray(new Polyline[polylines.size()]));
+ return nativeAddPolylines(polylines.toArray(new Polyline[polylines.size()]));
}
public long addPolygon(Polygon polygon) {
@@ -584,14 +536,14 @@ final class NativeMapView {
return 0;
}
Polygon[] polygons = {polygon};
- return nativeAddPolygons(nativeMapViewPtr, polygons)[0];
+ return nativeAddPolygons(polygons)[0];
}
public long[] addPolygons(List<Polygon> polygons) {
if (isDestroyedOn("addPolygons")) {
return new long[] {};
}
- return nativeAddPolygons(nativeMapViewPtr, polygons.toArray(new Polygon[polygons.size()]));
+ return nativeAddPolygons(polygons.toArray(new Polygon[polygons.size()]));
}
public void updateMarker(Marker marker) {
@@ -600,21 +552,21 @@ final class NativeMapView {
}
LatLng position = marker.getPosition();
Icon icon = marker.getIcon();
- nativeUpdateMarker(nativeMapViewPtr, marker.getId(), position.getLatitude(), position.getLongitude(), icon.getId());
+ nativeUpdateMarker(marker.getId(), position.getLatitude(), position.getLongitude(), icon.getId());
}
public void updatePolygon(Polygon polygon) {
if (isDestroyedOn("updatePolygon")) {
return;
}
- nativeUpdatePolygon(nativeMapViewPtr, polygon.getId(), polygon);
+ nativeUpdatePolygon(polygon.getId(), polygon);
}
public void updatePolyline(Polyline polyline) {
if (isDestroyedOn("updatePolyline")) {
return;
}
- nativeUpdatePolyline(nativeMapViewPtr, polyline.getId(), polyline);
+ nativeUpdatePolyline(polyline.getId(), polyline);
}
public void removeAnnotation(long id) {
@@ -629,91 +581,98 @@ final class NativeMapView {
if (isDestroyedOn("removeAnnotations")) {
return;
}
- nativeRemoveAnnotations(nativeMapViewPtr, ids);
+ nativeRemoveAnnotations(ids);
}
public long[] queryPointAnnotations(RectF rect) {
if (isDestroyedOn("queryPointAnnotations")) {
return new long[] {};
}
- return nativeQueryPointAnnotations(nativeMapViewPtr, rect);
+ return nativeQueryPointAnnotations(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);
+ nativeAddAnnotationIcon(symbol, width, height, scale, pixels);
}
public void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration) {
if (isDestroyedOn("setVisibleCoordinateBounds")) {
return;
}
- nativeSetVisibleCoordinateBounds(nativeMapViewPtr, coordinates, padding, direction, duration);
+ nativeSetVisibleCoordinateBounds(coordinates, padding, direction, duration);
}
public void onLowMemory() {
if (isDestroyedOn("onLowMemory")) {
return;
}
- nativeOnLowMemory(nativeMapViewPtr);
+ nativeOnLowMemory();
}
public void setDebug(boolean debug) {
if (isDestroyedOn("setDebug")) {
return;
}
- nativeSetDebug(nativeMapViewPtr, debug);
+ nativeSetDebug(debug);
}
public void cycleDebugOptions() {
if (isDestroyedOn("cycleDebugOptions")) {
return;
}
- nativeToggleDebug(nativeMapViewPtr);
+ nativeCycleDebugOptions();
}
public boolean getDebug() {
if (isDestroyedOn("getDebug")) {
return false;
}
- return nativeGetDebug(nativeMapViewPtr);
+ return nativeGetDebug();
+ }
+
+ public void setEnableFps(boolean enable) {
+ if (isDestroyedOn("setEnableFps")) {
+ return;
+ }
+ nativeSetEnableFps(enable);
}
public boolean isFullyLoaded() {
if (isDestroyedOn("isFullyLoaded")) {
return false;
}
- return nativeIsFullyLoaded(nativeMapViewPtr);
+ return nativeIsFullyLoaded();
}
public void setReachability(boolean status) {
if (isDestroyedOn("setReachability")) {
return;
}
- nativeSetReachability(nativeMapViewPtr, status);
+ nativeSetReachability(status);
}
public double getMetersPerPixelAtLatitude(double lat) {
if (isDestroyedOn("getMetersPerPixelAtLatitude")) {
return 0;
}
- return nativeGetMetersPerPixelAtLatitude(nativeMapViewPtr, lat, getZoom());
+ return nativeGetMetersPerPixelAtLatitude(lat, getZoom());
}
public ProjectedMeters projectedMetersForLatLng(LatLng latLng) {
if (isDestroyedOn("projectedMetersForLatLng")) {
return null;
}
- return nativeProjectedMetersForLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude());
+ return nativeProjectedMetersForLatLng(latLng.getLatitude(), latLng.getLongitude());
}
public LatLng latLngForProjectedMeters(ProjectedMeters projectedMeters) {
if (isDestroyedOn("latLngForProjectedMeters")) {
return new LatLng();
}
- return nativeLatLngForProjectedMeters(nativeMapViewPtr, projectedMeters.getNorthing(),
+ return nativeLatLngForProjectedMeters(projectedMeters.getNorthing(),
projectedMeters.getEasting()).wrap();
}
@@ -721,7 +680,7 @@ final class NativeMapView {
if (isDestroyedOn("pixelForLatLng")) {
return new PointF();
}
- PointF pointF = nativePixelForLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude());
+ PointF pointF = nativePixelForLatLng(latLng.getLatitude(), latLng.getLongitude());
pointF.set(pointF.x * pixelRatio, pointF.y * pixelRatio);
return pointF;
}
@@ -730,21 +689,21 @@ final class NativeMapView {
if (isDestroyedOn("latLngForPixel")) {
return new LatLng();
}
- return nativeLatLngForPixel(nativeMapViewPtr, pixel.x / pixelRatio, pixel.y / pixelRatio).wrap();
+ return nativeLatLngForPixel(pixel.x / pixelRatio, pixel.y / pixelRatio).wrap();
}
public double getTopOffsetPixelsForAnnotationSymbol(String symbolName) {
if (isDestroyedOn("getTopOffsetPixelsForAnnotationSymbol")) {
return 0;
}
- return nativeGetTopOffsetPixelsForAnnotationSymbol(nativeMapViewPtr, symbolName);
+ return nativeGetTopOffsetPixelsForAnnotationSymbol(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);
+ nativeJumpTo(angle, center.getLatitude(), center.getLongitude(), pitch, zoom);
}
public void easeTo(double angle, LatLng center, long duration, double pitch, double zoom,
@@ -752,7 +711,7 @@ final class NativeMapView {
if (isDestroyedOn("easeTo")) {
return;
}
- nativeEaseTo(nativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom,
+ nativeEaseTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom,
easingInterpolator);
}
@@ -760,88 +719,88 @@ final class NativeMapView {
if (isDestroyedOn("flyTo")) {
return;
}
- nativeFlyTo(nativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom);
+ nativeFlyTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom);
}
public double[] getCameraValues() {
if (isDestroyedOn("getCameraValues")) {
return new double[] {};
}
- return nativeGetCameraValues(nativeMapViewPtr);
+ return nativeGetCameraValues();
}
// Runtime style Api
public long getTransitionDuration() {
- return nativeGetTransitionDuration(nativeMapViewPtr);
+ return nativeGetTransitionDuration();
}
public void setTransitionDuration(long duration) {
- nativeSetTransitionDuration(nativeMapViewPtr, duration);
+ nativeSetTransitionDuration(duration);
}
public long getTransitionDelay() {
- return nativeGetTransitionDelay(nativeMapViewPtr);
+ return nativeGetTransitionDelay();
}
public void setTransitionDelay(long delay) {
- nativeSetTransitionDelay(nativeMapViewPtr, delay);
+ nativeSetTransitionDelay(delay);
}
public Layer getLayer(String layerId) {
if (isDestroyedOn("getLayer")) {
return null;
}
- return nativeGetLayer(nativeMapViewPtr, layerId);
+ return nativeGetLayer(layerId);
}
public void addLayer(@NonNull Layer layer, @Nullable String before) {
if (isDestroyedOn("")) {
return;
}
- nativeAddLayer(nativeMapViewPtr, layer.getNativePtr(), before);
+ nativeAddLayer(layer.getNativePtr(), before);
}
public void removeLayer(@NonNull String layerId) {
if (isDestroyedOn("removeLayer")) {
return;
}
- nativeRemoveLayerById(nativeMapViewPtr, layerId);
+ nativeRemoveLayerById(layerId);
}
public void removeLayer(@NonNull Layer layer) {
if (isDestroyedOn("removeLayer")) {
return;
}
- nativeRemoveLayer(nativeMapViewPtr, layer.getNativePtr());
+ nativeRemoveLayer(layer.getNativePtr());
}
public Source getSource(@NonNull String sourceId) {
if (isDestroyedOn("getSource")) {
return null;
}
- return nativeGetSource(nativeMapViewPtr, sourceId);
+ return nativeGetSource(sourceId);
}
public void addSource(@NonNull Source source) {
if (isDestroyedOn("addSource")) {
return;
}
- nativeAddSource(nativeMapViewPtr, source.getNativePtr());
+ nativeAddSource(source.getNativePtr());
}
- public void removeSource(@NonNull String sourceId) {
+ public void removeSource(@NonNull String sourceId) {
if (isDestroyedOn("removeSource")) {
return;
}
- nativeRemoveSourceById(nativeMapViewPtr, sourceId);
+ nativeRemoveSourceById(sourceId);
}
public void removeSource(@NonNull Source source) {
if (isDestroyedOn("removeSource")) {
return;
}
- nativeRemoveSource(nativeMapViewPtr, source.getNativePtr());
+ nativeRemoveSource(source.getNativePtr());
}
public void addImage(@NonNull String name, @NonNull Bitmap image) {
@@ -861,14 +820,14 @@ 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());
+ nativeAddImage(name, image.getWidth(), image.getHeight(), pixelRatio, buffer.array());
}
public void removeImage(String name) {
if (isDestroyedOn("removeImage")) {
return;
}
- nativeRemoveImage(nativeMapViewPtr, name);
+ nativeRemoveImage(name);
}
// Feature querying
@@ -878,7 +837,7 @@ final class NativeMapView {
if (isDestroyedOn("queryRenderedFeatures")) {
return new ArrayList<>();
}
- Feature[] features = nativeQueryRenderedFeaturesForPoint(nativeMapViewPtr, coordinates.x / pixelRatio,
+ Feature[] features = nativeQueryRenderedFeaturesForPoint(coordinates.x / pixelRatio,
coordinates.y / pixelRatio, layerIds);
return features != null ? Arrays.asList(features) : new ArrayList<Feature>();
}
@@ -889,7 +848,7 @@ final class NativeMapView {
return new ArrayList<>();
}
Feature[] features = nativeQueryRenderedFeaturesForBox(
- nativeMapViewPtr,
+
coordinates.left / pixelRatio,
coordinates.top / pixelRatio,
coordinates.right / pixelRatio,
@@ -902,14 +861,14 @@ final class NativeMapView {
if (isDestroyedOn("scheduleTakeSnapshot")) {
return;
}
- nativeScheduleTakeSnapshot(nativeMapViewPtr);
+ nativeTakeSnapshot();
}
public void setApiBaseUrl(String baseUrl) {
if (isDestroyedOn("setApiBaseUrl")) {
return;
}
- nativeSetAPIBaseURL(nativeMapViewPtr, baseUrl);
+ fileSource.setApiBaseUrl(baseUrl);
}
public float getPixelRatio() {
@@ -952,211 +911,182 @@ final class NativeMapView {
// 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 nativeInitialize(NativeMapView nativeMapView, FileSource fileSource,
+ float pixelRatio, int availableProcessors, long totalMemory);
- private native void nativeInitializeContext(long nativeMapViewPtr);
+ private native void nativeDestroy();
- private native void nativeTerminateContext(long nativeMapViewPtr);
+ private native void nativeInitializeDisplay();
- private native void nativeCreateSurface(long nativeMapViewPtr,
- Surface surface);
+ private native void nativeTerminateDisplay();
- private native void nativeDestroySurface(long nativeMapViewPtr);
+ private native void nativeInitializeContext();
- private native void nativeUpdate(long nativeMapViewPtr);
+ private native void nativeTerminateContext();
- private native void nativeRender(long nativeMapViewPtr);
+ private native void nativeCreateSurface(Object surface);
- private native void nativeViewResize(long nativeMapViewPtr, int width, int height);
+ private native void nativeDestroySurface();
- private native void nativeFramebufferResize(long nativeMapViewPtr, int fbWidth, int fbHeight);
+ private native void nativeUpdate();
- private native void nativeAddClass(long nativeMapViewPtr, String clazz);
+ private native void nativeRender();
- private native void nativeRemoveClass(long nativeMapViewPtr, String clazz);
+ private native void nativeResizeView(int width, int height);
- private native boolean nativeHasClass(long nativeMapViewPtr, String clazz);
+ private native void nativeResizeFramebuffer(int fbWidth, int fbHeight);
- private native void nativeSetClasses(long nativeMapViewPtr,
- List<String> classes);
+ private native void nativeSetStyleUrl(String url);
- private native List<String> nativeGetClasses(long nativeMapViewPtr);
+ private native String nativeGetStyleUrl();
- private native void nativeSetStyleUrl(long nativeMapViewPtr, String url);
+ private native void nativeSetStyleJson(String newStyleJson);
- private native String nativeGetStyleUrl(long nativeMapViewPtr);
+ private native String nativeGetStyleJson();
- private native void nativeSetStyleJson(long nativeMapViewPtr, String newStyleJson);
+ private native void nativeCancelTransitions();
- private native String nativeGetStyleJson(long nativeMapViewPtr);
+ private native void nativeSetGestureInProgress(boolean inProgress);
- private native void nativeSetAccessToken(long nativeMapViewPtr, String accessToken);
+ private native void nativeMoveBy(double dx, double dy, long duration);
- private native String nativeGetAccessToken(long nativeMapViewPtr);
+ private native void nativeSetLatLng(double latitude, double longitude, long duration);
- private native void nativeCancelTransitions(long nativeMapViewPtr);
+ private native LatLng nativeGetLatLng();
- private native void nativeSetGestureInProgress(long nativeMapViewPtr, boolean inProgress);
+ private native void nativeResetPosition();
- private native void nativeMoveBy(long nativeMapViewPtr, double dx,
- double dy, long duration);
+ private native double nativeGetPitch();
- private native void nativeSetLatLng(long nativeMapViewPtr, double latitude, double longitude,
- long duration);
+ private native void nativeSetPitch(double pitch, long duration);
- private native LatLng nativeGetLatLng(long nativeMapViewPtr);
+ private native void nativeScaleBy(double ds, double cx, double cy, long duration);
- private native void nativeResetPosition(long nativeMapViewPtr);
+ private native void nativeSetScale(double scale, double cx, double cy, long duration);
- private native double nativeGetPitch(long nativeMapViewPtr);
+ private native double nativeGetScale();
- private native void nativeSetPitch(long nativeMapViewPtr, double pitch, long duration);
+ private native void nativeSetZoom(double zoom, long duration);
- private native void nativeScaleBy(long nativeMapViewPtr, double ds,
- double cx, double cy, long duration);
+ private native double nativeGetZoom();
- private native void nativeSetScale(long nativeMapViewPtr, double scale,
- double cx, double cy, long duration);
+ private native void nativeResetZoom();
- private native double nativeGetScale(long nativeMapViewPtr);
+ private native void nativeSetMinZoom(double zoom);
- private native void nativeSetZoom(long nativeMapViewPtr, double zoom,
- long duration);
+ private native double nativeGetMinZoom();
- private native double nativeGetZoom(long nativeMapViewPtr);
+ private native void nativeSetMaxZoom(double zoom);
- private native void nativeResetZoom(long nativeMapViewPtr);
+ private native double nativeGetMaxZoom();
- private native void nativeSetMinZoom(long nativeMapViewPtr, double zoom);
+ private native void nativeRotateBy(double sx, double sy, double ex, double ey, long duration);
- private native double nativeGetMinZoom(long nativeMapViewPtr);
+ private native void nativeSetContentPadding(double top, double left, double bottom, double right);
- private native void nativeSetMaxZoom(long nativeMapViewPtr, double zoom);
+ private native void nativeSetBearing(double degrees, long duration);
- private native double nativeGetMaxZoom(long nativeMapViewPtr);
+ private native void nativeSetBearingXY(double degrees, double fx, double fy, long duration);
- private native void nativeRotateBy(long nativeMapViewPtr, double sx,
- double sy, double ex, double ey, long duration);
+ private native double nativeGetBearing();
- private native void nativeSetContentPadding(long nativeMapViewPtr, double top, double left, double bottom,
- double right);
+ private native void nativeResetNorth();
- private native void nativeSetBearing(long nativeMapViewPtr, double degrees,
- long duration);
+ private native void nativeUpdateMarker(long markerId, double lat, double lon, String iconId);
- private native void nativeSetBearingXY(long nativeMapViewPtr, double degrees,
- double cx, double cy);
+ private native long[] nativeAddMarkers(Marker[] markers);
- private native void nativeSetFocalBearing(long nativeMapViewPtr, double degrees,
- double fx, double fy, long duration);
+ private native long[] nativeAddPolylines(Polyline[] polylines);
- private native double nativeGetBearing(long nativeMapViewPtr);
+ private native long[] nativeAddPolygons(Polygon[] polygons);
- private native void nativeResetNorth(long nativeMapViewPtr);
+ private native void nativeRemoveAnnotations(long[] id);
- private native void nativeUpdateMarker(long nativeMapViewPtr, long markerId, double lat, double lon, String iconId);
+ private native long[] nativeQueryPointAnnotations(RectF rect);
- private native long[] nativeAddMarkers(long nativeMapViewPtr, Marker[] markers);
+ private native void nativeAddAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels);
- private native long[] nativeAddPolylines(long nativeMapViewPtr, Polyline[] polylines);
+ private native void nativeSetVisibleCoordinateBounds(LatLng[] coordinates, RectF padding,
+ double direction, long duration);
- private native long[] nativeAddPolygons(long nativeMapViewPtr, Polygon[] polygons);
+ private native void nativeOnLowMemory();
- private native void nativeRemoveAnnotations(long nativeMapViewPtr, long[] id);
+ private native void nativeSetDebug(boolean debug);
- private native long[] nativeQueryPointAnnotations(long nativeMapViewPtr, RectF rect);
+ private native void nativeCycleDebugOptions();
- private native void nativeAddAnnotationIcon(long nativeMapViewPtr, String symbol,
- int width, int height, float scale, byte[] pixels);
+ private native boolean nativeGetDebug();
- private native void nativeSetVisibleCoordinateBounds(long nativeMapViewPtr, LatLng[] coordinates,
- RectF padding, double direction, long duration);
+ private native void nativeSetEnableFps(boolean enable);
- private native void nativeOnLowMemory(long nativeMapViewPtr);
+ private native boolean nativeIsFullyLoaded();
- private native void nativeSetDebug(long nativeMapViewPtr, boolean debug);
+ private native void nativeSetReachability(boolean status);
- private native void nativeToggleDebug(long nativeMapViewPtr);
+ private native double nativeGetMetersPerPixelAtLatitude(double lat, double zoom);
- private native boolean nativeGetDebug(long nativeMapViewPtr);
+ private native ProjectedMeters nativeProjectedMetersForLatLng(double latitude, double longitude);
- private native boolean nativeIsFullyLoaded(long nativeMapViewPtr);
+ private native LatLng nativeLatLngForProjectedMeters(double northing, double easting);
- private native void nativeSetReachability(long nativeMapViewPtr, boolean status);
+ private native PointF nativePixelForLatLng(double lat, double lon);
- private native double nativeGetMetersPerPixelAtLatitude(long nativeMapViewPtr, double lat, double zoom);
+ private native LatLng nativeLatLngForPixel(float x, float y);
- private native ProjectedMeters nativeProjectedMetersForLatLng(long nativeMapViewPtr, double latitude,
- double longitude);
+ private native double nativeGetTopOffsetPixelsForAnnotationSymbol(String symbolName);
- private native LatLng nativeLatLngForProjectedMeters(long nativeMapViewPtr, double northing, double easting);
+ private native void nativeJumpTo(double angle, double latitude, double longitude, double pitch, double zoom);
- private native PointF nativePixelForLatLng(long nativeMapViewPtr, double lat, double lon);
+ private native void nativeEaseTo(double angle, double latitude, double longitude,
+ long duration, double pitch, double zoom,
+ boolean easingInterpolator);
- 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,
+ private native void nativeFlyTo(double angle, double latitude, double longitude,
long duration, double pitch, double zoom);
- private native double[] nativeGetCameraValues(long nativeMapViewPtr);
+ private native double[] nativeGetCameraValues();
- private native long nativeGetTransitionDuration(long nativeMapViewPtr);
+ private native long nativeGetTransitionDuration();
- private native void nativeSetTransitionDuration(long nativeMapViewPtr, long duration);
+ private native void nativeSetTransitionDuration(long duration);
- private native long nativeGetTransitionDelay(long nativeMapViewPtr);
+ private native long nativeGetTransitionDelay();
- private native void nativeSetTransitionDelay(long nativeMapViewPtr, long delay);
+ private native void nativeSetTransitionDelay(long delay);
- private native Layer nativeGetLayer(long nativeMapViewPtr, String layerId);
+ private native Layer nativeGetLayer(String layerId);
- private native void nativeAddLayer(long nativeMapViewPtr, long layerPtr, String before);
+ private native void nativeAddLayer(long layerPtr, String before) throws CannotAddLayerException;
- private native void nativeRemoveLayerById(long nativeMapViewPtr, String layerId);
+ private native void nativeRemoveLayerById(String layerId);
- private native void nativeRemoveLayer(long nativeMapViewPtr, long layerId);
+ private native void nativeRemoveLayer(long layerId);
- private native Source nativeGetSource(long nativeMapViewPtr, String sourceId);
+ private native Source nativeGetSource(String sourceId);
- private native void nativeAddSource(long nativeMapViewPtr, long nativeSourcePtr);
+ private native void nativeAddSource(long nativeSourcePtr) throws CannotAddSourceException;
- private native void nativeRemoveSourceById(long nativeMapViewPtr, String sourceId);
+ private native void nativeRemoveSourceById(String sourceId);
- private native void nativeRemoveSource(long nativeMapViewPtr, long sourcePtr);
+ private native void nativeRemoveSource(long sourcePtr);
- private native void nativeAddImage(long nativeMapViewPtr, String name, int width, int height, float pixelRatio,
+ private native void nativeAddImage(String name, int width, int height, float pixelRatio,
byte[] array);
- private native void nativeRemoveImage(long nativeMapViewPtr, String name);
+ private native void nativeRemoveImage(String name);
- private native void nativeUpdatePolygon(long nativeMapViewPtr, long polygonId, Polygon polygon);
+ private native void nativeUpdatePolygon(long polygonId, Polygon polygon);
- private native void nativeUpdatePolyline(long nativeMapviewPtr, long polylineId, Polyline polyline);
+ private native void nativeUpdatePolyline(long polylineId, Polyline polyline);
- private native void nativeScheduleTakeSnapshot(long nativeMapViewPtr);
+ private native void nativeTakeSnapshot();
- private native Feature[] nativeQueryRenderedFeaturesForPoint(long nativeMapViewPtr, float x, float y, String[]
+ private native Feature[] nativeQueryRenderedFeaturesForPoint(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);
+ private native Feature[] nativeQueryRenderedFeaturesForBox(float left, float top,
+ float right, float bottom,
+ String[] layerIds);
int getWidth() {
if (isDestroyedOn("")) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
index 09acda792c..cda79e30c6 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
@@ -1,16 +1,11 @@
package com.mapbox.mapboxsdk.offline;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
-import com.mapbox.mapboxsdk.Mapbox;
-import com.mapbox.mapboxsdk.constants.MapboxConstants;
-import com.mapbox.mapboxsdk.storage.Resource;
+import com.mapbox.mapboxsdk.storage.FileSource;
import java.io.File;
@@ -30,11 +25,13 @@ public class OfflineManager {
System.loadLibrary("mapbox-gl");
}
- // Default database name
- private static final String DATABASE_NAME = "mbgl-offline.db";
- // Holds the pointer to JNI DefaultFileSource
- private long mDefaultFileSourcePtr = 0;
+ // Native peer pointer
+ private long nativePtr;
+
+ // Reference to the file source to keep it alive for the
+ // lifetime of this object
+ private final FileSource fileSource;
// Makes sure callbacks come back to the main thread
private Handler handler;
@@ -82,94 +79,17 @@ public class OfflineManager {
void onError(String error);
}
- /**
- * This callback allows implementors to transform URLs before they are requested
- * from the internet. This can be used add or remove custom parameters, or reroute
- * certain requests to other servers or endpoints.
- */
- public interface ResourceTransformCallback {
- /**
- * Called whenever a URL needs to be transformed.
- *
- * @param kind The kind of URL to be transformed.
- * @param offlineRegions The original URL to be transformed.
- * @return A URL that will now be downloaded.
- */
- String onURL(@Resource.Kind int kind, String url);
- }
-
/*
- * Constructors
+ * Constructor
*/
private OfflineManager(Context context) {
- // Get a pointer to the DefaultFileSource instance
- String cachePath = getDatabasePath(context) + File.separator + DATABASE_NAME;
- String apkPath = context.getPackageCodePath();
- mDefaultFileSourcePtr = sharedDefaultFileSource(cachePath, apkPath);
- setAccessToken(mDefaultFileSourcePtr, Mapbox.getAccessToken());
+ this.fileSource = FileSource.getInstance(context);
+ initialize(fileSource);
// Delete any existing previous ambient cache database
deleteAmbientDatabase(context);
}
- public static String getDatabasePath(Context context) {
- // Default value
- boolean setStorageExternal = MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL;
-
- try {
- // Try getting a custom value from the app Manifest
- ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
- context.getPackageName(), PackageManager.GET_META_DATA);
- setStorageExternal = appInfo.metaData.getBoolean(
- MapboxConstants.KEY_META_DATA_SET_STORAGE_EXTERNAL,
- MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL);
- } catch (PackageManager.NameNotFoundException exception) {
- Timber.e("Failed to read the package metadata: ", exception);
- } catch (Exception exception) {
- Timber.e("Failed to read the storage key: ", exception);
- }
-
- String databasePath = null;
- if (setStorageExternal && isExternalStorageReadable()) {
- try {
- // Try getting the external storage path
- databasePath = context.getExternalFilesDir(null).getAbsolutePath();
- } catch (NullPointerException exception) {
- Timber.e("Failed to obtain the external storage path: ", exception);
- }
- }
-
- if (databasePath == null) {
- // Default to internal storage
- databasePath = context.getFilesDir().getAbsolutePath();
- }
-
- return databasePath;
- }
-
- /**
- * Checks if external storage is available to at least read. In order for this to work, make
- * sure you include &lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /&gt;
- * (or WRITE_EXTERNAL_STORAGE) for API level &lt; 18 in your app Manifest.
- * <p>
- * Code from https://developer.android.com/guide/topics/data/data-storage.html#filesExternal
- * </p>
- *
- * @return true if external storage is readable
- */
- public static boolean isExternalStorageReadable() {
- String state = Environment.getExternalStorageState();
- if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
- return true;
- }
-
- Timber.w("External storage was requested but it isn't readable. For API level < 18"
- + " make sure you've requested READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE"
- + " permissions in your app Manifest (defaulting to internal storage).");
-
- return false;
- }
-
private void deleteAmbientDatabase(final Context context) {
// Delete the file in a separate thread to avoid affecting the UI
new Thread(new Runnable() {
@@ -215,7 +135,8 @@ public class OfflineManager {
* @param callback the callback to be invoked
*/
public void listOfflineRegions(@NonNull final ListOfflineRegionsCallback callback) {
- listOfflineRegions(mDefaultFileSourcePtr, new ListOfflineRegionsCallback() {
+ listOfflineRegions(fileSource, new ListOfflineRegionsCallback() {
+
@Override
public void onList(final OfflineRegion[] offlineRegions) {
getHandler().post(new Runnable() {
@@ -259,7 +180,8 @@ public class OfflineManager {
@NonNull byte[] metadata,
@NonNull final CreateOfflineRegionCallback callback) {
- createOfflineRegion(mDefaultFileSourcePtr, definition, metadata, new CreateOfflineRegionCallback() {
+ createOfflineRegion(fileSource, definition, metadata, new CreateOfflineRegionCallback() {
+
@Override
public void onCreate(final OfflineRegion offlineRegion) {
getHandler().post(new Runnable() {
@@ -282,48 +204,20 @@ public class OfflineManager {
});
}
- /**
- * Sets a callback for transforming URLs requested from the internet
- * <p>
- * The callback will be executed on the main thread once for every requested URL.
- * </p>
- *
- * @param callback the callback to be invoked
- */
- public void setResourceTransform(@NonNull final ResourceTransformCallback callback) {
- setResourceTransform(mDefaultFileSourcePtr, callback);
- }
-
/*
* Changing or bypassing this limit without permission from Mapbox is prohibited
* by the Mapbox Terms of Service.
*/
- public void setOfflineMapboxTileCountLimit(long limit) {
- setOfflineMapboxTileCountLimit(mDefaultFileSourcePtr, limit);
- }
-
-
- /*
- * Native methods
- */
- private native long sharedDefaultFileSource(
- String cachePath, String assetRoot);
-
- private native void setAccessToken(long defaultFileSourcePtr, String accessToken);
-
- private native String getAccessToken(long defaultFileSourcePtr);
+ public native void setOfflineMapboxTileCountLimit(long limit);
- private native void listOfflineRegions(
- long defaultFileSourcePtr, ListOfflineRegionsCallback callback);
+ private native void initialize(FileSource fileSource);
- private native void createOfflineRegion(
- long defaultFileSourcePtr, OfflineRegionDefinition definition,
- byte[] metadata, CreateOfflineRegionCallback callback);
+ @Override
+ protected native void finalize() throws Throwable;
- private native void setResourceTransform(
- long defaultFileSourcePtr, ResourceTransformCallback callback);
+ private native void listOfflineRegions(FileSource fileSource, ListOfflineRegionsCallback callback);
- private native void setOfflineMapboxTileCountLimit(
- long defaultFileSourcePtr, long limit);
+ private native void createOfflineRegion(FileSource fileSource, OfflineRegionDefinition definition,
+ byte[] metadata, CreateOfflineRegionCallback callback);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
index a4d8a646d3..a55e8dd848 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
@@ -5,7 +5,7 @@ import android.os.Looper;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
-import timber.log.Timber;
+import com.mapbox.mapboxsdk.storage.FileSource;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -25,22 +25,25 @@ public class OfflineRegion {
System.loadLibrary("mapbox-gl");
}
- // Parent OfflineManager
- private OfflineManager offlineManager;
-
// Members
- private long mId = 0;
- private OfflineRegionDefinition mDefinition = null;
+
+ // Holds the pointer to JNI OfflineRegion
+ private long nativePtr;
+
+ // Holds a reference to the FileSource to keep it alive
+ private FileSource fileSource;
+
+ //Region id
+ private long id;
+
+ private OfflineRegionDefinition definition;
/**
* Arbitrary binary region metadata. The contents are opaque to the SDK implementation;
* it just stores and retrieves a byte[]. Check the `OfflineActivity` in the TestApp
* for a sample implementation that uses JSON to store an offline region name.
*/
- private byte[] mMetadata = null;
-
- // Holds the pointer to JNI OfflineRegion
- private long mOfflineRegionPtr = 0;
+ private byte[] metadata;
// Makes sure callbacks come back to the main thread
private Handler handler;
@@ -197,19 +200,22 @@ public class OfflineRegion {
if (state == STATE_ACTIVE) {
return true;
}
- if (isDeliveringInactiveMessages()) {
- return true;
- }
- return false;
+ return isDeliveringInactiveMessages();
}
- /*
+ /**
* Constructor
+ *
+ * For JNI use only, to create a new offline region, use
+ * {@link OfflineManager#createOfflineRegion} instead.
*/
-
- private OfflineRegion() {
- // For JNI use only, to create a new offline region, use
- // OfflineManager.createOfflineRegion() instead.
+ private OfflineRegion(long offlineRegionPtr, FileSource fileSource, long id,
+ OfflineRegionDefinition definition, byte[] metadata) {
+ this.fileSource = fileSource;
+ this.id = id;
+ this.definition = definition;
+ this.metadata = metadata;
+ initialize(offlineRegionPtr, fileSource);
}
/*
@@ -217,15 +223,15 @@ public class OfflineRegion {
*/
public long getID() {
- return mId;
+ return id;
}
public OfflineRegionDefinition getDefinition() {
- return mDefinition;
+ return definition;
}
public byte[] getMetadata() {
- return mMetadata;
+ return metadata;
}
private Handler getHandler() {
@@ -383,7 +389,7 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
- mMetadata = metadata;
+ OfflineRegion.this.metadata = metadata;
callback.onUpdate(metadata);
}
});
@@ -401,33 +407,18 @@ public class OfflineRegion {
});
}
- @Override
- protected void finalize() {
- try {
- super.finalize();
- destroyOfflineRegion();
- } catch (Throwable throwable) {
- Timber.e("Failed to finalize OfflineRegion: " + throwable.getMessage());
- }
- }
-
- /*
- * Native methods
- */
+ private native void initialize(long offlineRegionPtr, FileSource fileSource);
- private native void destroyOfflineRegion();
+ @Override
+ protected native void finalize();
- private native void setOfflineRegionObserver(
- OfflineRegionObserver observerCallback);
+ private native void setOfflineRegionObserver(OfflineRegionObserver callback);
- private native void setOfflineRegionDownloadState(
- @DownloadState int offlineRegionDownloadState);
+ private native void setOfflineRegionDownloadState(@DownloadState int offlineRegionDownloadState);
- private native void getOfflineRegionStatus(
- OfflineRegionStatusCallback statusCallback);
+ private native void getOfflineRegionStatus(OfflineRegionStatusCallback callback);
- private native void deleteOfflineRegion(
- OfflineRegionDeleteCallback deleteCallback);
+ private native void deleteOfflineRegion(OfflineRegionDeleteCallback callback);
private native void updateOfflineRegionMetadata(byte[] metadata, OfflineRegionUpdateMetadataCallback callback);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java
index 60c4a8661c..83f3c06d68 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java
@@ -25,25 +25,23 @@ public class OfflineRegionError {
public static final String REASON_OTHER = "REASON_OTHER";
@ErrorReason
- private String reason;
+ private final String reason;
/**
* /* An error message from the request handler, e.g. a server message or a system message
* /* informing the user about the reason for the failure.
*/
- private String message;
+ private final String message;
- /*
- * Constructors
- */
+ // Constructors
- private OfflineRegionError() {
+ private OfflineRegionError(String reason, String message) {
// For JNI use only
+ this.reason = reason;
+ this.message = message;
}
- /*
- * Getters
- */
+ // Getters
@ErrorReason
public String getReason() {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
index 11f2da132d..9c3655fbec 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
@@ -56,24 +56,29 @@ public class OfflineRegionStatus {
/*
* Use setObserver(OfflineRegionObserver observer) to obtain a OfflineRegionStatus object.
+ *
+ * For JNI use only
*/
-
- private OfflineRegionStatus() {
- // For JNI use only
+ private OfflineRegionStatus(int downloadState, long completedResourceCount,
+ long completedResourceSize, long completedTileCount,
+ long completedTileSize, long requiredResourceCount,
+ boolean requiredResourceCountIsPrecise) {
+ this.downloadState = downloadState;
+ this.completedResourceCount = completedResourceCount;
+ this.completedResourceSize = completedResourceSize;
+ this.completedTileCount = completedTileCount;
+ this.completedTileSize = completedTileSize;
+ this.requiredResourceCount = requiredResourceCount;
+ this.requiredResourceCountIsPrecise = requiredResourceCountIsPrecise;
}
- /*
+ /**
* Is the region complete?
*/
-
public boolean isComplete() {
return (completedResourceCount == requiredResourceCount);
}
- /*
- * Getters
- */
-
@OfflineRegion.DownloadState
public int getDownloadState() {
return downloadState;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java
index 5fc844afe5..f8ec0f3d39 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java
@@ -21,16 +21,18 @@ public class OfflineTilePyramidRegionDefinition implements OfflineRegionDefiniti
private double maxZoom;
private float pixelRatio;
- /*
- * Constructors
+ /**
+ * Constructor
+ *
+ * @param styleURL the style
+ * @param bounds the bounds
+ * @param minZoom min zoom
+ * @param maxZoom max zoom
+ * @param pixelRatio pixel ratio of the device
*/
-
- private OfflineTilePyramidRegionDefinition() {
- // For JNI use only
- }
-
public OfflineTilePyramidRegionDefinition(
String styleURL, LatLngBounds bounds, double minZoom, double maxZoom, float pixelRatio) {
+ // Note: Also used in JNI
this.styleURL = styleURL;
this.bounds = bounds;
this.minZoom = minZoom;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
new file mode 100644
index 0000000000..4123261f0f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
@@ -0,0 +1,139 @@
+package com.mapbox.mapboxsdk.storage;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+
+import java.lang.ref.WeakReference;
+
+import timber.log.Timber;
+
+/**
+ * Holds a central reference to the core's DefaultFileSource for as long as
+ * there are active mapviews / offline managers
+ */
+public class FileSource {
+
+ /**
+ * This callback allows implementors to transform URLs before they are requested
+ * from the internet. This can be used add or remove custom parameters, or reroute
+ * certain requests to other servers or endpoints.
+ */
+ public interface ResourceTransformCallback {
+
+ /**
+ * Called whenever a URL needs to be transformed.
+ *
+ * @param kind The kind of URL to be transformed.
+ * @return A URL that will now be downloaded.
+ */
+ String onURL(@Resource.Kind int kind, String url);
+
+ }
+
+ // Use weak reference to avoid blocking GC on this reference.
+ // Should only block when mapview / Offline manager instances
+ // are alive
+ private static WeakReference<FileSource> INSTANCE;
+
+ public static synchronized FileSource getInstance(Context context) {
+ if (INSTANCE == null || INSTANCE.get() == null) {
+ String cachePath = getCachePath(context);
+ String apkPath = context.getPackageCodePath();
+ INSTANCE = new WeakReference<>(new FileSource(cachePath, apkPath));
+ }
+
+ return INSTANCE.get();
+ }
+
+ public static String getCachePath(Context context) {
+ // Default value
+ boolean setStorageExternal = MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL;
+
+ try {
+ // Try getting a custom value from the app Manifest
+ ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(),
+ PackageManager.GET_META_DATA);
+ setStorageExternal = appInfo.metaData.getBoolean(
+ MapboxConstants.KEY_META_DATA_SET_STORAGE_EXTERNAL,
+ MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL);
+ } catch (PackageManager.NameNotFoundException exception) {
+ Timber.e("Failed to read the package metadata: ", exception);
+ } catch (Exception exception) {
+ Timber.e("Failed to read the storage key: ", exception);
+ }
+
+ String cachePath = null;
+ if (setStorageExternal && isExternalStorageReadable()) {
+ try {
+ // Try getting the external storage path
+ cachePath = context.getExternalFilesDir(null).getAbsolutePath();
+ } catch (NullPointerException exception) {
+ Timber.e("Failed to obtain the external storage path: ", exception);
+ }
+ }
+
+ if (cachePath == null) {
+ // Default to internal storage
+ cachePath = context.getFilesDir().getAbsolutePath();
+ }
+
+ return cachePath;
+ }
+
+ /**
+ * Checks if external storage is available to at least read. In order for this to work, make
+ * sure you include &lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /&gt;
+ * (or WRITE_EXTERNAL_STORAGE) for API level &lt; 18 in your app Manifest.
+ * <p>
+ * Code from https://developer.android.com/guide/topics/data/data-storage.html#filesExternal
+ * </p>
+ *
+ * @return true if external storage is readable
+ */
+ public static boolean isExternalStorageReadable() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ return true;
+ }
+
+ Timber.w("External storage was requested but it isn't readable. For API level < 18"
+ + " make sure you've requested READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE"
+ + " permissions in your app Manifest (defaulting to internal storage).");
+
+ return false;
+ }
+
+ private long nativePtr;
+
+ private FileSource(String cachePath, String apkPath) {
+ initialize(Mapbox.getAccessToken(), cachePath, apkPath);
+ }
+
+ public native void setAccessToken(@NonNull String accessToken);
+
+ public native String getAccessToken();
+
+ public native void setApiBaseUrl(String baseUrl);
+
+ /**
+ * Sets a callback for transforming URLs requested from the internet
+ * <p>
+ * The callback will be executed on the main thread once for every requested URL.
+ * </p>
+ *
+ * @param callback the callback to be invoked
+ */
+ public native void setResourceTransform(@NonNull final ResourceTransformCallback callback);
+
+ private native void initialize(String accessToken, String cachePath, String apkPath);
+
+ @Override
+ protected native void finalize() throws Throwable;
+
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 23372b49e3..9aeb0282b9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -329,6 +329,17 @@
android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
+ android:name=".activity.offline.DeleteRegionActivity"
+ android:description="@string/description_offline_region_delete"
+ android:label="@string/activity_offline_region_delete">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_offline"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
+ </activity>
+ <activity
android:name=".activity.imagegenerator.SnapshotActivity"
android:description="@string/description_snapshot"
android:label="@string/activity_snapshot">
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java
new file mode 100644
index 0000000000..220f46f4e8
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java
@@ -0,0 +1,168 @@
+package com.mapbox.mapboxsdk.testapp.activity.offline;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.mapbox.mapboxsdk.offline.OfflineManager;
+import com.mapbox.mapboxsdk.offline.OfflineRegion;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.utils.OfflineUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test activity showing integration of deleting an OfflineRegion.
+ */
+public class DeleteRegionActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
+
+ private OfflineRegionAdapter adapter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_offline_region_delete);
+
+ ListView listView = (ListView) findViewById(R.id.listView);
+ listView.setAdapter(adapter = new OfflineRegionAdapter(this));
+ listView.setEmptyView(findViewById(android.R.id.empty));
+ listView.setOnItemClickListener(this);
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ final OfflineRegion region = adapter.getItem(position);
+ String metadata = OfflineUtils.convertRegionName(region.getMetadata());
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Delete region");
+
+ final TextView input = new TextView(this);
+ input.setText(metadata);
+ builder.setView(input);
+
+ builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ delete(region);
+ }
+ });
+ builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
+
+ builder.show();
+ }
+
+ private void delete(OfflineRegion region) {
+ region.delete(new OfflineRegion.OfflineRegionDeleteCallback() {
+ @Override
+ public void onDelete() {
+ Toast.makeText(
+ DeleteRegionActivity.this,
+ "Region deleted",
+ Toast.LENGTH_SHORT
+ ).show();
+ loadOfflineRegions();
+ }
+
+ @Override
+ public void onError(String error) {
+ Toast.makeText(
+ DeleteRegionActivity.this,
+ "Region deletion failed with " + error,
+ Toast.LENGTH_LONG
+ ).show();
+ }
+ });
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ loadOfflineRegions();
+ }
+
+ private void loadOfflineRegions() {
+ OfflineManager.getInstance(this).listOfflineRegions(new OfflineManager.ListOfflineRegionsCallback() {
+ @Override
+ public void onList(OfflineRegion[] offlineRegions) {
+ if (offlineRegions != null && offlineRegions.length > 0) {
+ adapter.setOfflineRegions(Arrays.asList(offlineRegions));
+ }
+ }
+
+ @Override
+ public void onError(String error) {
+ Toast.makeText(DeleteRegionActivity.this, "Error loading regions " + error, Toast.LENGTH_LONG).show();
+ }
+ });
+ }
+
+ private static class OfflineRegionAdapter extends BaseAdapter {
+
+ private Context context;
+ private List<OfflineRegion> offlineRegions;
+
+ OfflineRegionAdapter(Context ctx) {
+ context = ctx;
+ offlineRegions = new ArrayList<>();
+ }
+
+ void setOfflineRegions(List<OfflineRegion> offlineRegions) {
+ this.offlineRegions = offlineRegions;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return offlineRegions.size();
+ }
+
+ @Override
+ public OfflineRegion getItem(int position) {
+ return offlineRegions.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ViewHolder holder;
+
+ if (convertView == null) {
+ holder = new ViewHolder();
+ convertView = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false);
+ holder.text = (TextView) convertView.findViewById(android.R.id.text1);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ holder.text.setText(OfflineUtils.convertRegionName(getItem(position).getMetadata()));
+ return convertView;
+ }
+
+ static class ViewHolder {
+ TextView text;
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
index c2b0cb0769..137ee2d478 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
@@ -260,6 +260,7 @@ public class OfflineActivity extends AppCompatActivity
if (status.isComplete()) {
// Download complete
endProgress("Region downloaded successfully.");
+ offlineRegion.setObserver(null);
return;
} else if (status.isRequiredResourceCountPrecise()) {
// Switch to determinate state
@@ -277,6 +278,7 @@ public class OfflineActivity extends AppCompatActivity
public void onError(OfflineRegionError error) {
Timber.e("onError reason: " + error.getReason());
Timber.e("onError message: " + error.getMessage());
+ offlineRegion.setObserver(null);
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_delete.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_delete.xml
new file mode 100644
index 0000000000..084675fb2c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_delete.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <ListView
+ android:id="@+id/listView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+ <TextView
+ android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:text="No Results"
+ android:textSize="24sp"/>
+
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
index 2012a92593..61d251f861 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
@@ -33,6 +33,7 @@
<string name="activity_debug_mode">Debug Mode</string>
<string name="activity_offline">Offline Map</string>
<string name="activity_update_metadata">Update metadata Map</string>
+ <string name="activity_offline_region_delete">Delete region</string>
<string name="activity_minmax_zoom">Min/Max Zoom</string>
<string name="activity_viewpager">ViewPager</string>
<string name="activity_runtime_style">Runtime Style</string>
@@ -76,6 +77,7 @@
<string name="description_debug_mode">Debug Mode</string>
<string name="description_offline">Offline Map example</string>
<string name="description_update_metadata">Update metadata example</string>
+ <string name="description_offline_region_delete">Delete region example</string>
<string name="description_animated_marker">Animate the position change of a marker</string>
<string name="description_polyline">Add a polyline to a map</string>
<string name="description_polygon">Add a polygon to a map</string>
diff --git a/platform/android/config.cmake b/platform/android/config.cmake
index 27f538b95e..3d3728aed7 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)
@@ -49,8 +49,6 @@ macro(mbgl_platform_core)
PRIVATE platform/default/default_file_source.cpp
PRIVATE platform/default/local_file_source.cpp
PRIVATE platform/default/online_file_source.cpp
- PRIVATE platform/android/src/default_file_source.cpp
- PRIVATE platform/android/src/default_file_source.hpp
# Offline
# PRIVATE include/mbgl/storage/offline.hpp
@@ -137,6 +135,10 @@ macro(mbgl_platform_core)
platform/android/src/style/functions/interval_stops.cpp
platform/android/src/style/functions/interval_stops.hpp
+ # FileSource holder
+ platform/android/src/file_source.cpp
+ platform/android/src/file_source.hpp
+
# Connectivity
platform/android/src/connectivity_listener.cpp
platform/android/src/connectivity_listener.hpp
@@ -145,6 +147,46 @@ 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/lat_lng_bounds.cpp
+ platform/android/src/geometry/lat_lng_bounds.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
+
+ # Offline
+ platform/android/src/offline/offline_manager.cpp
+ platform/android/src/offline/offline_manager.hpp
+ platform/android/src/offline/offline_region.cpp
+ platform/android/src/offline/offline_region.hpp
+ platform/android/src/offline/offline_region_definition.cpp
+ platform/android/src/offline/offline_region_definition.hpp
+ platform/android/src/offline/offline_region_error.cpp
+ platform/android/src/offline/offline_region_error.hpp
+ platform/android/src/offline/offline_region_status.cpp
+ platform/android/src/offline/offline_region_status.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..a1fe436dbd
--- /dev/null
+++ b/platform/android/src/annotation/marker.cpp
@@ -0,0 +1,31 @@
+#include "marker.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Class<Marker> Marker::javaClass;
+
+mbgl::Point<double> Marker::getPosition(jni::JNIEnv& env, jni::Object<Marker> marker) {
+ static auto positionField = Marker::javaClass.GetField<jni::Object<LatLng>>(env, "position");
+ auto jPosition = marker.Get(env, positionField);
+ auto position = LatLng::getGeometry(env, jPosition);
+ jni::DeleteLocalRef(env, jPosition);
+ return position;
+}
+
+std::string Marker::getIconId(jni::JNIEnv& env, jni::Object<Marker> marker) {
+ static auto iconIdField = Marker::javaClass.GetField<jni::String>(env, "iconId");
+ auto jIconId = marker.Get(env, iconIdField);
+ auto iconId = jni::Make<std::string>(env, jIconId);
+ jni::DeleteLocalRef(env, jIconId);
+ return iconId;
+}
+
+void Marker::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ Marker::javaClass = *jni::Class<Marker>::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 <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
+#include <string>
+
+#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<Marker> javaClass;
+
+ static mbgl::Point<double> getPosition(jni::JNIEnv&, jni::Object<Marker>);
+
+ static std::string getIconId(jni::JNIEnv&, jni::Object<Marker>);
+
+ 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 <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
+#include "../geometry/lat_lng.hpp"
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+
+class MultiPoint : protected mbgl::util::noncopyable {
+
+protected:
+
+ template <class Geometry>
+ static Geometry toGeometry(JNIEnv& env, jni::Object<java::util::List> pointsList) {
+ NullCheck(env, &pointsList);
+ auto jarray = java::util::List::toArray<LatLng>(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..ba82fc34dc
--- /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> Polygon::javaClass;
+
+mbgl::FillAnnotation Polygon::toAnnotation(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ auto points = Polygon::getPoints(env, polygon);
+
+ mbgl::FillAnnotation annotation { mbgl::Polygon<double> { MultiPoint::toGeometry<mbgl::LinearRing<double>>(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<java::util::List> Polygon::getPoints(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<jni::Object<java::util::List>>(env, "points");
+ return polygon.Get(env, field);
+}
+
+float Polygon::getOpacity(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<float>(env, "alpha");
+ return polygon.Get(env, field);
+}
+
+mbgl::Color Polygon::getFillColor(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<int>(env, "fillColor");
+ return *conversion::convert<mbgl::Color, int>(env, polygon.Get(env, field));
+}
+
+mbgl::Color Polygon::getOutlineColor(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<int>(env, "strokeColor");
+ return *conversion::convert<mbgl::Color, int>(env, polygon.Get(env, field));
+}
+
+void Polygon::registerNative(jni::JNIEnv& env) {
+ Polygon::javaClass = *jni::Class<Polygon>::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 <mbgl/annotation/annotation.hpp>
+#include <mbgl/util/color.hpp>
+
+#include <string>
+
+#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<Polygon> javaClass;
+
+ static mbgl::FillAnnotation toAnnotation(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+
+ static jni::Object<java::util::List> getPoints(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static float getOpacity(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static mbgl::Color getFillColor(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static mbgl::Color getOutlineColor(jni::JNIEnv&, jni::Object<Polygon>);
+};
+
+
+} // 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> Polyline::javaClass;
+
+mbgl::LineAnnotation Polyline::toAnnotation(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ auto points = Polyline::getPoints(env, polyline);
+
+ mbgl::LineAnnotation annotation { MultiPoint::toGeometry<mbgl::LineString<double>>(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<java::util::List> Polyline::getPoints(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<jni::Object<java::util::List>>(env, "points");
+ return polyline.Get(env, field);
+}
+
+float Polyline::getOpacity(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<float>(env, "alpha");
+ return polyline.Get(env, field);
+}
+
+mbgl::Color Polyline::getColor(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<int>(env, "color");
+ return *conversion::convert<mbgl::Color, int>(env, polyline.Get(env, field));
+}
+
+float Polyline::getWidth(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<float>(env, "width");
+ return polyline.Get(env, field);
+}
+
+void Polyline::registerNative(jni::JNIEnv& env) {
+ Polyline::javaClass = *jni::Class<Polyline>::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 <mbgl/annotation/annotation.hpp>
+#include <mbgl/util/color.hpp>
+
+#include <string>
+
+#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<Polyline> javaClass;
+
+ static mbgl::LineAnnotation toAnnotation(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+
+ static jni::Object<java::util::List> getPoints(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static float getOpacity(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static mbgl::Color getColor(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static float getWidth(jni::JNIEnv&, jni::Object<Polyline>);
+};
+
+
+} // 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<std::string> toVector(JNIEnv& env, jni::jarray<jni::jobject>&
return vector;
}
+inline std::vector<std::string> toVector(JNIEnv& env, jni::Array<jni::String> array) {
+ std::vector<std::string> 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<std::string, jni::String>(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 <mbgl/util/color.hpp>
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+template <>
+struct Converter<mbgl::Color, int> {
+ Result<mbgl::Color> 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/default_file_source.cpp b/platform/android/src/default_file_source.cpp
deleted file mode 100644
index 4d6924b496..0000000000
--- a/platform/android/src/default_file_source.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "default_file_source.hpp"
-#include <mbgl/util/logging.hpp>
-
-#include <cassert>
-
-namespace mbgl {
-namespace android {
-
-DefaultFileSource& defaultFileSource(const std::string& cachePath_, const std::string& assetRoot_) {
- static auto cachePath = cachePath_;
- assert(cachePath == cachePath_);
- static auto assetRoot = assetRoot_;
- assert(assetRoot == assetRoot_);
-
- static DefaultFileSource defaultFileSource{ cachePath, assetRoot };
- return defaultFileSource;
-}
-
-} // namespace android
-} // namespace mbgl
diff --git a/platform/android/src/default_file_source.hpp b/platform/android/src/default_file_source.hpp
deleted file mode 100644
index e0cc28583c..0000000000
--- a/platform/android/src/default_file_source.hpp
+++ /dev/null
@@ -1,12 +0,0 @@
-#pragma once
-
-#include <mbgl/storage/default_file_source.hpp>
-
-namespace mbgl {
-namespace android {
-
-DefaultFileSource& defaultFileSource(const std::string& cachePath = ":memory:",
- const std::string& assetRoot = ".");
-
-} // namespace android
-} // namespace mbgl
diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp
new file mode 100644
index 0000000000..30e1ff50fe
--- /dev/null
+++ b/platform/android/src/file_source.cpp
@@ -0,0 +1,106 @@
+#include "file_source.hpp"
+
+#include <mbgl/util/logging.hpp>
+
+#include <string>
+
+#include "jni/generic_global_ref_deleter.hpp"
+
+
+namespace mbgl {
+namespace android {
+
+// FileSource //
+
+FileSource::FileSource(jni::JNIEnv& _env, jni::String accessToken, jni::String _cachePath, jni::String _apkPath) {
+ // Create a core default file source
+ fileSource = std::make_unique<mbgl::DefaultFileSource>(
+ jni::Make<std::string>(_env, _cachePath) + "/mbgl-offline.db",
+ jni::Make<std::string>(_env, _apkPath));
+
+ // Set access token
+ fileSource->setAccessToken(jni::Make<std::string>(_env, accessToken));
+}
+
+FileSource::~FileSource() {
+}
+
+jni::String FileSource::getAccessToken(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, fileSource->getAccessToken());
+}
+
+void FileSource::setAccessToken(jni::JNIEnv& env, jni::String token) {
+ fileSource->setAccessToken(jni::Make<std::string>(env, token));
+}
+
+void FileSource::setAPIBaseUrl(jni::JNIEnv& env, jni::String url) {
+ fileSource->setAPIBaseURL(jni::Make<std::string>(env, url));
+}
+
+void FileSource::setResourceTransform(jni::JNIEnv& env, jni::Object<FileSource::ResourceTransformCallback> transformCallback) {
+ if (transformCallback) {
+ // Launch transformCallback
+ fileSource->setResourceTransform([
+ // Capture the ResourceTransformCallback object as a managed global into
+ // the lambda. It is released automatically when we're setting a new ResourceTransform in
+ // a subsequent call.
+ // Note: we're converting it to shared_ptr because this lambda is converted to a std::function,
+ // which requires copyability of its captured variables.
+ callback = std::shared_ptr<jni::jobject>(transformCallback.NewGlobalRef(env).release()->Get(), GenericGlobalRefDeleter()),
+ env
+ ](mbgl::Resource::Kind kind, std::string&& url_) {
+ return FileSource::ResourceTransformCallback::onURL(const_cast<jni::JNIEnv&>(env), jni::Object<FileSource::ResourceTransformCallback>(*callback), int(kind), url_);
+ });
+ } else {
+ // Reset the callback
+ fileSource->setResourceTransform(nullptr);
+ }
+}
+
+jni::Class<FileSource> FileSource::javaClass;
+
+FileSource* FileSource::getNativePeer(jni::JNIEnv& env, jni::Object<FileSource> jFileSource) {
+ static auto field = FileSource::javaClass.GetField<jlong>(env, "nativePtr");
+ return reinterpret_cast<FileSource *>(jFileSource.Get(env, field));
+}
+
+mbgl::DefaultFileSource& FileSource::getDefaultFileSource(jni::JNIEnv& env, jni::Object<FileSource> jFileSource) {
+ FileSource* fileSource = FileSource::getNativePeer(env, jFileSource);
+ assert(fileSource != nullptr);
+ return *fileSource->fileSource;
+}
+
+void FileSource::registerNative(jni::JNIEnv& env) {
+ //Register classes
+ FileSource::javaClass = *jni::Class<FileSource>::Find(env).NewGlobalRef(env).release();
+ FileSource::ResourceTransformCallback::javaClass = *jni::Class<FileSource::ResourceTransformCallback>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<FileSource>(
+ env, FileSource::javaClass, "nativePtr",
+ std::make_unique<FileSource, JNIEnv&, jni::String, jni::String, jni::String>,
+ "initialize",
+ "finalize",
+ METHOD(&FileSource::getAccessToken, "getAccessToken"),
+ METHOD(&FileSource::setAccessToken, "setAccessToken"),
+ METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"),
+ METHOD(&FileSource::setResourceTransform, "setResourceTransform")
+ );
+}
+
+
+// FileSource::ResourceTransformCallback //
+
+jni::Class<FileSource::ResourceTransformCallback> FileSource::ResourceTransformCallback::javaClass;
+
+std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, jni::Object<FileSource::ResourceTransformCallback> callback, int kind, std::string url_) {
+ static auto method = FileSource::ResourceTransformCallback::javaClass.GetMethod<jni::String (jni::jint, jni::String)>(env, "onURL");
+ auto url = jni::Make<jni::String>(env, url_);
+ url = callback.Call(env, method, kind, url);
+ return jni::Make<std::string>(env, url);
+}
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp
new file mode 100644
index 0000000000..073e393e05
--- /dev/null
+++ b/platform/android/src/file_source.hpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <mbgl/storage/default_file_source.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+/**
+ * Peer class for the Android FileSource holder. Ensures that a single DefaultFileSource is used
+ */
+class FileSource {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource"; };
+
+ struct ResourceTransformCallback {
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource$ResourceTransformCallback"; }
+
+ static std::string onURL(jni::JNIEnv&, jni::Object<FileSource::ResourceTransformCallback>, int, std::string);
+
+ static jni::Class<ResourceTransformCallback> javaClass;
+ };
+
+ FileSource(jni::JNIEnv&, jni::String, jni::String, jni::String);
+
+ ~FileSource();
+
+ jni::String getAccessToken(jni::JNIEnv&);
+
+ void setAccessToken(jni::JNIEnv&, jni::String);
+
+ void setAPIBaseUrl(jni::JNIEnv&, jni::String);
+
+ void setResourceTransform(jni::JNIEnv&, jni::Object<FileSource::ResourceTransformCallback>);
+
+ static jni::Class<FileSource> javaClass;
+
+ static FileSource* getNativePeer(jni::JNIEnv&, jni::Object<FileSource>);
+
+ static mbgl::DefaultFileSource& getDefaultFileSource(jni::JNIEnv&, jni::Object<FileSource>);
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+
+ std::unique_ptr<mbgl::DefaultFileSource> fileSource;
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
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 <mbgl/util/feature.hpp>
#include <mapbox/variant.hpp>
@@ -10,6 +11,7 @@
#include <jni/jni.hpp>
#include "../../jni/local_object.hpp"
+#include "../feature.hpp"
#include <string>
#include <array>
@@ -168,39 +170,45 @@ struct Converter<jni::jobject*, std::unordered_map<std::string, mbgl::Value>> {
template <>
-struct Converter<jni::jobject*, mbgl::Feature> {
- Result<jni::jobject*> 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<jni::Object<Feature>, mbgl::Feature> {
+ Result<jni::Object<Feature>> 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<jni::jobject> jid = jni::NewLocalObject(env, *convert<jni::jobject*>(env, id));
+ auto jid = jni::Make<jni::String>(env, id);
// Convert properties
- jni::LocalObject<jni::jobject> properties = jni::NewLocalObject(env, *convert<jni::jobject*>(env, value.properties));
+ auto properties = jni::Object<JsonObject>(*convert<jni::jobject*>(env, value.properties));
// Convert geometry
- jni::LocalObject<jni::jobject> geometry = jni::NewLocalObject(env, *convert<jni::jobject*>(env, value.geometry));
+ auto geometry = jni::Object<Geometry>(*convert<jni::jobject*>(env, value.geometry));
// Create feature
- return {reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(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<jni::jarray<jni::jobject>*, std::vector<mbgl::Feature>> {
- Result<jni::jarray<jni::jobject>*> operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const {
- static jni::jclass* featureClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Feature")).release();
- jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *featureClass);
+struct Converter<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>> {
+ Result<jni::Array<jni::Object<Feature>>> operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const {
+
+ auto features = jni::Array<jni::Object<Feature>>::New(env, value.size(), Feature::javaClass);
for(size_t i = 0; i < value.size(); i = i + 1) {
- jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, mbgl::Feature>(env, value.at(i)));
- jni::SetObjectArrayElement(env, jarray, i, converted.get());
+ auto converted = *convert<jni::Object<Feature>, 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> Feature::fromGeometry(jni::JNIEnv& env, jni::Object<Geometry> geometry, jni::Object<JsonObject> properties, jni::String id) {
+ static auto method = Feature::javaClass.GetStaticMethod<jni::Object<Feature> (jni::Object<Geometry>, jni::Object<JsonObject>, 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<Feature>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Feature> 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 <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+#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<Feature> fromGeometry(jni::JNIEnv&, jni::Object<Geometry>, jni::Object<JsonObject>, jni::String);
+
+ static jni::Class<Feature> 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 <mbgl/util/noncopyable.hpp>
+
+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> LatLng::New(jni::JNIEnv& env, double latitude, double longitude) {
+ static auto constructor = LatLng::javaClass.GetConstructor<double, double>(env);
+ return LatLng::javaClass.New(env, constructor, latitude, longitude);
+}
+
+mbgl::Point<double> LatLng::getGeometry(jni::JNIEnv& env, jni::Object<LatLng> latLng) {
+ static auto latitudeField = LatLng::javaClass.GetField<jni::jdouble>(env, "latitude");
+ static auto longitudeField = LatLng::javaClass.GetField<jni::jdouble>(env, "longitude");
+ return mbgl::Point<double>(latLng.Get(env, longitudeField), latLng.Get(env, latitudeField));
+}
+
+mbgl::LatLng LatLng::getLatLng(jni::JNIEnv& env, jni::Object<LatLng> 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<LatLng>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<LatLng> 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 <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class LatLng : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLng"; };
+
+ static jni::Object<LatLng> New(jni::JNIEnv&, double, double);
+
+ static mbgl::Point<double> getGeometry(jni::JNIEnv&, jni::Object<LatLng>);
+
+ static mbgl::LatLng getLatLng(jni::JNIEnv&, jni::Object<LatLng>);
+
+ static jni::Class<LatLng> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng_bounds.cpp b/platform/android/src/geometry/lat_lng_bounds.cpp
new file mode 100644
index 0000000000..9efacde120
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng_bounds.cpp
@@ -0,0 +1,31 @@
+#include "lat_lng_bounds.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<LatLngBounds> LatLngBounds::New(jni::JNIEnv& env, mbgl::LatLngBounds bounds) {
+ static auto constructor = LatLngBounds::javaClass.GetConstructor<double, double, double, double>(env);
+ return LatLngBounds::javaClass.New(env, constructor, bounds.north(), bounds.east(), bounds.south(), bounds.west());
+}
+
+mbgl::LatLngBounds LatLngBounds::getLatLngBounds(jni::JNIEnv& env, jni::Object<LatLngBounds> bounds) {
+ static auto swLat = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLatSouth");
+ static auto swLon = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLonWest");
+ static auto neLat = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLatNorth");
+ static auto neLon = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLonEast");
+ return mbgl::LatLngBounds::hull(
+ { bounds.Get(env, swLat), bounds.Get(env, swLon) },
+ { bounds.Get(env, neLat), bounds.Get(env, neLon) }
+ );
+}
+
+void LatLngBounds::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ LatLngBounds::javaClass = *jni::Class<LatLngBounds>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<LatLngBounds> LatLngBounds::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng_bounds.hpp b/platform/android/src/geometry/lat_lng_bounds.hpp
new file mode 100644
index 0000000000..1c853e4b67
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng_bounds.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class LatLngBounds : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLngBounds"; };
+
+ static jni::Object<LatLngBounds> New(jni::JNIEnv&, mbgl::LatLngBounds);
+
+ static mbgl::LatLngBounds getLatLngBounds(jni::JNIEnv&, jni::Object<LatLngBounds>);
+
+ static jni::Class<LatLngBounds> 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> ProjectedMeters::New(jni::JNIEnv& env, double northing, double easting) {
+ static auto constructor = ProjectedMeters::javaClass.GetConstructor<double, double>(env);
+ return ProjectedMeters::javaClass.New(env, constructor, northing, easting);
+}
+
+void ProjectedMeters::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ ProjectedMeters::javaClass = *jni::Class<ProjectedMeters>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<ProjectedMeters> 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 <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class ProjectedMeters : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/ProjectedMeters"; };
+
+ static jni::Object<ProjectedMeters> New(jni::JNIEnv&, double, double);
+
+ static jni::Class<ProjectedMeters> 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> PointF::New(jni::JNIEnv& env, float x, float y) {
+ static auto constructor = PointF::javaClass.GetConstructor<float, float>(env);
+ return PointF::javaClass.New(env, constructor, x, y);
+}
+
+void PointF::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ PointF::javaClass = *jni::Class<PointF>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<PointF> 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 <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class PointF : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "android/graphics/PointF"; };
+
+ static jni::Object<PointF> New(jni::JNIEnv&, float, float);
+
+ static jni::Class<PointF> 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> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "left");
+ return rectf.Get(env, field);
+}
+
+float RectF::getTop(jni::JNIEnv& env, jni::Object<RectF> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "top");
+ return rectf.Get(env, field);
+}
+
+float RectF::getRight(jni::JNIEnv& env, jni::Object<RectF> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "right");
+ return rectf.Get(env, field);
+}
+
+float RectF::getBottom(jni::JNIEnv& env, jni::Object<RectF> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "bottom");
+ return rectf.Get(env, field);
+}
+
+void RectF::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ RectF::javaClass = *jni::Class<RectF>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<RectF> 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 <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+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<RectF>);
+
+ static float getTop(jni::JNIEnv&, jni::Object<RectF>);
+
+ static float getRight(jni::JNIEnv&, jni::Object<RectF>);
+
+ static float getBottom(jni::JNIEnv&, jni::Object<RectF>);
+
+ static jni::Class<RectF> 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 <mbgl/util/noncopyable.hpp>
+
+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> List::javaClass;
+
+void registerNative(jni::JNIEnv& env) {
+ List::javaClass = *jni::Class<List>::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 <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+namespace java {
+namespace util {
+
+class List : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "java/util/List"; };
+
+ template<class T>
+ static jni::Array<jni::Object<T>> toArray(jni::JNIEnv& env, jni::Object<List> list) {
+ static auto toArray = List::javaClass.GetMethod<jni::Array<jni::Object<>> ()>(env, "toArray");
+ return (jni::Array<jni::Object<T>>) list.Call(env, toArray);
+ };
+
+ static jni::Class<List> 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 59602c3299..bd12cff3fa 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -1,21 +1,29 @@
-#include <cstdint>
-#include <cinttypes>
-#include <cassert>
-#include <string>
-#include <array>
-#include <vector>
+#include "jni.hpp"
-#include <android/native_window_jni.h>
-#include <sys/system_properties.h>
+#include <mbgl/util/logging.hpp>
-#include "jni.hpp"
-#include "java_types.hpp"
-#include "native_map_view.hpp"
+#include "annotation/marker.hpp"
+#include "annotation/polygon.hpp"
+#include "annotation/polyline.hpp"
#include "bitmap.hpp"
#include "bitmap_factory.hpp"
#include "connectivity_listener.hpp"
-#include "default_file_source.hpp"
-#include "attach_env.hpp"
+#include "conversion/conversion.hpp"
+#include "conversion/collection.hpp"
+#include "file_source.hpp"
+#include "geometry/feature.hpp"
+#include "geometry/lat_lng.hpp"
+#include "geometry/lat_lng_bounds.hpp"
+#include "geometry/projected_meters.hpp"
+#include "graphics/pointf.hpp"
+#include "graphics/rectf.hpp"
+#include "java_types.hpp"
+#include "native_map_view.hpp"
+#include "offline/offline_manager.hpp"
+#include "offline/offline_region.hpp"
+#include "offline/offline_region_definition.hpp"
+#include "offline/offline_region_error.hpp"
+#include "offline/offline_region_status.hpp"
#include "style/functions/categorical_stops.hpp"
#include "style/functions/exponential_stops.hpp"
#include "style/functions/identity_stops.hpp"
@@ -24,30 +32,6 @@
#include "style/layers/layers.hpp"
#include "style/sources/sources.hpp"
-#include "conversion/conversion.hpp"
-#include "conversion/collection.hpp"
-#include "geometry/conversion/feature.hpp"
-
-#include <mbgl/map/map.hpp>
-#include <mbgl/map/camera.hpp>
-#include <mbgl/annotation/annotation.hpp>
-#include <mbgl/style/layer.hpp>
-#include <mbgl/style/source.hpp>
-#include <mbgl/sprite/sprite_image.hpp>
-#include <mbgl/util/event.hpp>
-#include <mbgl/util/logging.hpp>
-#include <mbgl/storage/network_status.hpp>
-#include <mbgl/util/exception.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-#include <mapbox/geometry.hpp>
-
-#include <jni/jni.hpp>
-
-#pragma clang diagnostic ignored "-Wunused-parameter"
-
namespace mbgl {
namespace android {
@@ -55,129 +39,7 @@ void RegisterNativeHTTPRequest(JNIEnv&);
JavaVM* theJVM;
-std::string cachePath;
-std::string dataPath;
-std::string apkPath;
-std::string androidRelease;
-
-jni::jmethodID* onInvalidateId = 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;
-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;
-
-jni::jmethodID* listOnListMethodId = nullptr;
-jni::jmethodID* listOnErrorMethodId = nullptr;
-
-jni::jclass* offlineRegionClass = nullptr;
-jni::jmethodID* offlineRegionConstructorId = nullptr;
-jni::jfieldID* offlineRegionOfflineManagerId = nullptr;
-jni::jfieldID* offlineRegionIdId = nullptr;
-jni::jfieldID* offlineRegionDefinitionId = nullptr;
-jni::jfieldID* offlineRegionMetadataId = nullptr;
-jni::jfieldID* offlineRegionPtrId = nullptr;
-
-jni::jclass* offlineRegionDefinitionClass = nullptr;
-jni::jmethodID* offlineRegionDefinitionConstructorId = nullptr;
-jni::jfieldID* offlineRegionDefinitionStyleURLId = nullptr;
-jni::jfieldID* offlineRegionDefinitionBoundsId = nullptr;
-jni::jfieldID* offlineRegionDefinitionMinZoomId = nullptr;
-jni::jfieldID* offlineRegionDefinitionMaxZoomId = nullptr;
-jni::jfieldID* offlineRegionDefinitionPixelRatioId = nullptr;
-
-jni::jmethodID* createOnCreateMethodId = nullptr;
-jni::jmethodID* createOnErrorMethodId = nullptr;
-
-jni::jmethodID* transformOnURLMethodId = nullptr;
-
-jni::jmethodID* updateMetadataOnUpdateMethodId = nullptr;
-jni::jmethodID* updateMetadataOnErrorMethodId = nullptr;
-
-jni::jmethodID* offlineRegionObserveronStatusChangedId = nullptr;
-jni::jmethodID* offlineRegionObserveronErrorId = nullptr;
-jni::jmethodID* offlineRegionObserveronLimitId = nullptr;
-
-jni::jclass* offlineRegionStatusClass = nullptr;
-jni::jmethodID* offlineRegionStatusConstructorId = nullptr;
-jni::jfieldID* offlineRegionStatusDownloadStateId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedResourceCountId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedResourceSizeId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedTileCountId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedTileSizeId = nullptr;
-jni::jfieldID* offlineRegionStatusRequiredResourceCountId = nullptr;
-jni::jfieldID* offlineRegionStatusRequiredResourceCountIsPreciseId = nullptr;
-
-jni::jclass* offlineRegionErrorClass = nullptr;
-jni::jmethodID* offlineRegionErrorConstructorId = nullptr;
-jni::jfieldID* offlineRegionErrorReasonId = nullptr;
-jni::jfieldID* offlineRegionErrorMessageId = nullptr;
-
-jni::jmethodID* offlineRegionStatusOnStatusId = nullptr;
-jni::jmethodID* offlineRegionStatusOnErrorId = nullptr;
-
-jni::jmethodID* offlineRegionDeleteOnDeleteId = nullptr;
-jni::jmethodID* offlineRegionDeleteOnErrorId = nullptr;
-
-// Offline declarations end
-
+//TODO: remove
bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName) {
assert(vm != nullptr);
assert(env != nullptr);
@@ -205,6 +67,7 @@ bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName) {
return detach;
}
+//TODO: remove
void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) {
if (detach) {
assert(vm != nullptr);
@@ -219,1608 +82,43 @@ void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) {
*env = nullptr;
}
-std::string std_string_from_jstring(JNIEnv *env, jni::jstring* jstr) {
- return jni::Make<std::string>(*env, jni::String(jstr));
-}
-
-jni::jstring* std_string_to_jstring(JNIEnv *env, std::string str) {
- return jni::Make<jni::String>(*env, str).Get();
-}
-
-std::vector<std::string> std_vector_string_from_jobject(JNIEnv *env, jni::jobject* jlist) {
- std::vector<std::string> vector;
-
- jni::NullCheck(*env, jlist);
- jni::jarray<jni::jobject>* jarray =
- reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*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::jstring*>(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<std::string> vector) {
- jni::jobject* jlist = &jni::NewObject(*env, *arrayListClass, *arrayListConstructorId);
-
- for (const auto& str : vector) {
- jni::CallMethod<jboolean>(*env, jlist, *arrayListAddId, std_string_to_jstring(env, str));
- }
-
- return jlist;
-}
-
-jni::jarray<jlong>* std_vector_uint_to_jobject(JNIEnv *env, const std::vector<uint32_t>& vector) {
- jni::jarray<jlong>& jarray = jni::NewArray<jlong>(*env, vector.size());
-
- std::vector<jlong> 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<uint8_t> metadata_from_java(JNIEnv* env, jni::jarray<jbyte>& j) {
- std::size_t length = jni::GetArrayLength(*env, j);
- std::vector<uint8_t> c;
- c.resize(length);
- jni::GetArrayRegion(*env, j, 0, length, reinterpret_cast<jbyte*>(c.data()));
- return c;
-}
-
-static jni::jarray<jbyte>* metadata_from_native(JNIEnv* env, const std::vector<uint8_t>& c) {
- std::size_t length = static_cast<std::size_t>(c.size());
- jni::jarray<jbyte>& j = jni::NewArray<jbyte>(*env, length);
- jni::SetArrayRegion(*env, j, 0, c.size(), reinterpret_cast<const jbyte*>(c.data()));
- return &j;
-}
-
-static mbgl::LatLngBounds latlngbounds_from_java(JNIEnv *env, jni::jobject* latLngBounds) {
- jdouble swLat = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLatSouthId);
- jdouble swLon = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLonWestId);
- jdouble neLat = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLatNorthId);
- jdouble neLon = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLonEastId);
- return mbgl::LatLngBounds::hull({ swLat, swLon }, { neLat, neLon });
-}
-
-static jni::jobject* latlngbounds_from_native(JNIEnv *env, mbgl::LatLngBounds bounds) {
- double northLatitude = bounds.north();
- double eastLongitude = bounds.east();
- double southLatitude = bounds.south();
- double westLongitude = bounds.west();
-
- jni::jobject* jbounds = &jni::NewObject(*env, *latLngBoundsClass, *latLngBoundsConstructorId,
- northLatitude, eastLongitude, southLatitude, westLongitude);
-
- return jbounds;
-}
-
-}
-}
-
-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::Debug(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_);
- return reinterpret_cast<jlong>(new NativeMapView(env, jni::Unwrap(obj), pixelRatio, availableProcessors, totalMemory));
-}
-
-void nativeDestroy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeDestroy");
- assert(nativeMapViewPtr != 0);
- delete reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-}
-
-void nativeInitializeDisplay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeDisplay");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->initializeDisplay();
-}
-
-void nativeTerminateDisplay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateDisplay");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->terminateDisplay();
-}
-
-void nativeInitializeContext(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeContext");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->initializeContext();
-}
-
-void nativeTerminateContext(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateContext");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->terminateContext();
-}
-
-void nativeCreateSurface(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* surface) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeCreateSurface");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->createSurface(ANativeWindow_fromSurface(env, jni::Unwrap(surface)));
-}
-
-void nativeDestroySurface(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeDestroySurface");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->destroySurface();
-}
-
-void nativeUpdate(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->invalidate();
-}
-
-void nativeRender(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->render();
-}
-
-void nativeViewResize(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint width, jint height) {
- mbgl::Log::Debug(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<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->resizeView(width, height);
-}
-
-void nativeFramebufferResize(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint fbWidth, jint fbHeight) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeFramebufferResize");
- assert(nativeMapViewPtr != 0);
- assert(fbWidth >= 0);
- assert(fbHeight >= 0);
- assert(fbWidth <= UINT16_MAX);
- assert(fbHeight <= UINT16_MAX);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->resizeFramebuffer(fbWidth, fbHeight);
-}
-
-void nativeRemoveClass(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* clazz) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().cancelTransitions();
-}
-
-void nativeSetGestureInProgress(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jboolean inProgress) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::AnimationOptions animationOptions;
- if (duration > 0) {
- animationOptions.duration.emplace(mbgl::Milliseconds(duration));
- animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0.3, 0.6, 1.0 });
- }
-
- nativeMapView->getMap().moveBy({dx, dy}, animationOptions);
-}
-
-void nativeSetLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().resetPosition();
-}
-
-jdouble nativeGetPitch(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setZoom(zoom, mbgl::Milliseconds(duration));
-}
-
-jdouble nativeGetZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getZoom();
-}
-
-void nativeResetZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().resetZoom();
-}
-
-void nativeSetMinZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setMinZoom(zoom);
-}
-
-jdouble nativeGetMinZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getMinZoom();
-}
-
-void nativeSetMaxZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setMaxZoom(zoom);
-}
-
-jdouble nativeGetMaxZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getBearing();
-}
-
-void nativeResetNorth(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<NativeMapView *>(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<double>(lon, lat), iconId });
-}
-
-jni::jarray<jlong>* nativeAddMarkers(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<jni::jobject*>(*env, marker, *markerPositionId);
- jni::jobject* icon = jni::GetField<jni::jobject*>(*env, marker, *markerIconId);
- jni::jstring* jid = reinterpret_cast<jni::jstring*>(jni::GetField<jni::jobject*>(*env, icon, *iconIdId));
-
- jdouble latitude = jni::GetField<jdouble>(*env, position, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, position, *latLngLongitudeId);
-
- ids.push_back(nativeMapView->getMap().addAnnotation(mbgl::SymbolAnnotation {
- mbgl::Point<double>(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 <class Geometry>
-Geometry toGeometry(JNIEnv *env, jni::jobject* jlist) {
- NullCheck(*env, jlist);
- jni::jarray<jni::jobject>* jarray =
- reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*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::jobject*>(jni::GetObjectArrayElement(*env, *jarray, i));
- NullCheck(*env, latLng);
-
- geometry.push_back(mbgl::Point<double>(
- jni::GetField<jdouble>(*env, latLng, *latLngLongitudeId),
- jni::GetField<jdouble>(*env, latLng, *latLngLatitudeId)));
-
- jni::DeleteLocalRef(*env, latLng);
- }
-
- jni::DeleteLocalRef(*env, jarray);
- jni::DeleteLocalRef(*env, jlist);
-
- return geometry;
-}
-
-jni::jarray<jlong>* nativeAddPolylines(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<jni::jobject*>(*env, polyline, *polylinePointsId);
-
- mbgl::LineAnnotation annotation { toGeometry<mbgl::LineString<double>>(env, points) };
- annotation.opacity = { jni::GetField<jfloat>(*env, polyline, *polylineAlphaId) };
- annotation.color = { toColor(jni::GetField<jint>(*env, polyline, *polylineColorId)) };
- annotation.width = { jni::GetField<jfloat>(*env, polyline, *polylineWidthId) };
- ids.push_back(nativeMapView->getMap().addAnnotation(annotation));
-
- jni::DeleteLocalRef(*env, polyline);
- }
-
- return std_vector_uint_to_jobject(env, ids);
-}
-
-jni::jarray<jlong>* nativeAddPolygons(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<jni::jobject*>(*env, polygon, *polygonPointsId);
-
- mbgl::FillAnnotation annotation { mbgl::Polygon<double> { toGeometry<mbgl::LinearRing<double>>(env, points) } };
- annotation.opacity = { jni::GetField<jfloat>(*env, polygon, *polygonAlphaId) };
- annotation.outlineColor = { toColor(jni::GetField<jint>(*env, polygon, *polygonStrokeColorId)) };
- annotation.color = { toColor(jni::GetField<jint>(*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<NativeMapView *>(nativeMapViewPtr);
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polygon, *polygonPointsId);
-
- mbgl::FillAnnotation annotation { mbgl::Polygon<double> { toGeometry<mbgl::LinearRing<double>>(env, points) } };
- annotation.opacity = { jni::GetField<jfloat>(*env, polygon, *polygonAlphaId) };
- annotation.outlineColor = { toColor(jni::GetField<jint>(*env, polygon, *polygonStrokeColorId)) };
- annotation.color = { toColor(jni::GetField<jint>(*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<NativeMapView *>(nativeMapViewPtr);
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polyline, *polylinePointsId);
-
- mbgl::LineAnnotation annotation { toGeometry<mbgl::LineString<double>>(env, points) };
- annotation.opacity = { jni::GetField<jfloat>(*env, polyline, *polylineAlphaId) };
- annotation.color = { toColor(jni::GetField<jint>(*env, polyline, *polylineColorId)) };
- annotation.width = { jni::GetField<jfloat>(*env, polyline, *polylineWidthId) };
- nativeMapView->getMap().updateAnnotation(polylineId, annotation);
-}
-
-void nativeRemoveAnnotations(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jlong>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<jlong>* nativeQueryPointAnnotations(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* rect) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- // Conversion
- jfloat left = jni::GetField<jfloat>(*env, rect, *rectFLeftId);
- jfloat right = jni::GetField<jfloat>(*env, rect, *rectFRightId);
- jfloat top = jni::GetField<jfloat>(*env, rect, *rectFTopId);
- jfloat bottom = jni::GetField<jfloat>(*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<jbyte>* jpixels) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<uint32_t>(width), static_cast<uint32_t>(height) });
-
- if (premultipliedImage.bytes() != uint32_t(size)) {
- throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch");
- }
-
- jni::GetArrayRegion(*env, *jpixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
-
- auto iconImage = std::make_shared<mbgl::SpriteImage>(
- std::move(premultipliedImage),
- float(scale));
-
- nativeMapView->getMap().addAnnotationIcon(symbolName, iconImage);
-}
-
-void nativeSetVisibleCoordinateBounds(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr,
- jni::jarray<jni::jobject>* coordinates, jni::jobject* padding, jdouble direction, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- jfloat left = jni::GetField<jfloat>(*env, padding, *rectFLeftId);
- jfloat right = jni::GetField<jfloat>(*env, padding, *rectFRightId);
- jfloat top = jni::GetField<jfloat>(*env, padding, *rectFTopId);
- jfloat bottom = jni::GetField<jfloat>(*env, padding, *rectFBottomId);
-
- NullCheck(*env, coordinates);
- std::size_t count = jni::GetArrayLength(*env, *coordinates);
-
- mbgl::EdgeInsets mbglInsets = {top, left, bottom, right};
- std::vector<mbgl::LatLng> 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<jdouble>(*env, latLng, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*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<jni::jobject>* nativeQueryRenderedFeaturesForPoint(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jfloat x, jni::jfloat y, jni::jarray<jni::jobject>* layerIds) {
- using namespace mbgl::android::conversion;
- using namespace mapbox::geometry;
-
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::optional<std::vector<std::string>> layers;
- if (layerIds != nullptr && jni::GetArrayLength(*env, *layerIds) > 0) {
- layers = toVector(*env, *layerIds);
- }
- point<double> point = {x, y};
-
- return *convert<jni::jarray<jni::jobject>*, std::vector<mbgl::Feature>>(*env, nativeMapView->getMap().queryRenderedFeatures(point, layers));
-}
-
-jni::jarray<jni::jobject>* nativeQueryRenderedFeaturesForBox(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jfloat left, jni::jfloat top, jni::jfloat right, jni::jfloat bottom, jni::jarray<jni::jobject>* layerIds) {
- using namespace mbgl::android::conversion;
- using namespace mapbox::geometry;
-
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::optional<std::vector<std::string>> layers;
- if (layerIds != nullptr && jni::GetArrayLength(*env, *layerIds) > 0) {
- layers = toVector(*env, *layerIds);
- }
- box<double> box = { point<double>{ left, top}, point<double>{ right, bottom } };
-
- return *convert<jni::jarray<jni::jobject>*, std::vector<mbgl::Feature>>(*env, nativeMapView->getMap().queryRenderedFeatures(box, layers));
-}
-
-void nativeOnLowMemory(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().onLowMemory();
-}
-
-void nativeSetDebug(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jboolean debug) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getDebug() != DebugOptions::NoDebug;
-}
-
-jboolean nativeIsFullyLoaded(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(nativeMapViewPtr);
- mbgl::ScreenCoordinate pixel = nativeMapView->getMap().pixelForLatLng(mbgl::LatLng(latitude, longitude));
- return &jni::NewObject(*env, *pointFClass, *pointFConstructorId, static_cast<jfloat>(pixel.x), static_cast<jfloat>(pixel.y));
-}
-
-jni::jobject* nativeLatLngForPixel(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jfloat x, jfloat y) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(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<NativeMapView *>(nativeMapViewPtr);
-
- auto transitionOptions = nativeMapView->getMap().getTransitionOptions();
- transitionOptions.duration = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(duration));
- nativeMapView->getMap().setTransitionOptions(transitionOptions);
-}
-
-jlong nativeGetTransitionDelay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(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<NativeMapView *>(nativeMapViewPtr);
-
- auto transitionOptions = nativeMapView->getMap().getTransitionOptions();
- transitionOptions.delay = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(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<NativeMapView *>(nativeMapViewPtr);
-
- // Find the layer
- mbgl::style::Layer* coreLayer = nativeMapView->getMap().getLayer(std_string_from_jstring(env, layerId));
- if (!coreLayer) {
- mbgl::Log::Debug(mbgl::Event::JNI, "No layer found");
- return jni::Object<Layer>();
- }
-
- // 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<NativeMapView *>(nativeMapViewPtr);
-
- Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
- try {
- layer->addToMap(nativeMapView->getMap(), before ? mbgl::optional<std::string>(std_string_from_jstring(env, before)) : mbgl::optional<std::string>());
- } 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<NativeMapView *>(nativeMapViewPtr);
-
- nativeMapView->getMap().removeLayer(std_string_from_jstring(env, id));
-}
-
-/**
- * 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<NativeMapView *>(nativeMapViewPtr);
- mbgl::android::Layer *layer = reinterpret_cast<mbgl::android::Layer *>(layerPtr);
-
- std::unique_ptr<mbgl::style::Layer> coreLayer = nativeMapView->getMap().removeLayer(layer->get().getID());
- if (coreLayer) {
- layer->setLayer(std::move(coreLayer));
- }
-}
-
-
-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<NativeMapView *>(nativeMapViewPtr);
-
- // Find the source
- mbgl::style::Source* coreSource = nativeMapView->getMap().getSource(std_string_from_jstring(env, sourceId));
- if (!coreSource) {
- mbgl::Log::Debug(mbgl::Event::JNI, "No source found");
- return jni::Object<Source>();
- }
-
- // 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<NativeMapView *>(nativeMapViewPtr);
-
- Source *source = reinterpret_cast<Source *>(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<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().removeSource(std_string_from_jstring(env, id));
-}
-
-void nativeRemoveSource(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong sourcePtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::android::Source *source = reinterpret_cast<mbgl::android::Source *>(sourcePtr);
-
- std::unique_ptr<mbgl::style::Source> coreSource = nativeMapView->getMap().removeSource(source->get().getID());
- if (coreSource) {
- source->setSource(std::move(coreSource));
- }
-}
-
-void nativeAddImage(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* name, jni::jint width, jni::jint height, jni::jfloat pixelRatio, jni::jarray<jbyte>* data) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- // Create Pre-multiplied image from byte[]
- NullCheck(*env, data);
- std::size_t size = jni::GetArrayLength(*env, *data);
- mbgl::PremultipliedImage premultipliedImage(
- { static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
-
- if (premultipliedImage.bytes() != uint32_t(size)) {
- throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch");
- }
-
- jni::GetArrayRegion(*env, *data, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
-
- // Wrap in a SpriteImage with the correct pixel ratio
- auto spriteImage = std::make_unique<mbgl::SpriteImage>(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<NativeMapView *>(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<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->scheduleTakeSnapshot();
-}
-
-// Offline calls begin
-
-jlong sharedDefaultFileSource(JNIEnv *env, jni::jobject* obj, jni::jstring* cachePath_, jni::jstring* assetRoot_) {
- return reinterpret_cast<jlong>(&defaultFileSource(std_string_from_jstring(env, cachePath_),
- std_string_from_jstring(env, assetRoot_)));
-}
-
-void setAccessToken(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jni::jstring* accessToken_) {
- assert(defaultFileSourcePtr != 0);
- std::string accessToken = std_string_from_jstring(env, accessToken_);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->setAccessToken(accessToken);
-}
-
-jni::jstring* getAccessToken(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr) {
- assert(defaultFileSourcePtr != 0);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- std::string accessToken = defaultFileSource->getAccessToken();
- return std_string_to_jstring(env, accessToken);
-}
-
-void listOfflineRegions(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jni::jobject* listCallback) {
- // Checks
- assert(defaultFileSourcePtr != 0);
- NullCheck(*env, listCallback);
-
- // Makes sure the objects don't get GC'ed
- obj = jni::NewGlobalRef(*env, obj).release();
- listCallback = jni::NewGlobalRef(*env, listCallback).release();
-
- // Launch listCallback
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->listOfflineRegions([obj, defaultFileSourcePtr, listCallback](std::exception_ptr error, mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, listCallback, *listOnErrorMethodId, std_string_to_jstring(env2, message));
- } else if (regions) {
- // Build jni::jarray<jni::jobject>*
- std::size_t index = 0;
- jni::jarray<jni::jobject>* jregions = &jni::NewObjectArray(*env2, regions->size(), *offlineRegionClass, NULL);
- for (auto& region : *regions) {
- // Create a new local reference frame (capacity 2 for the NewObject allocations below)
- // to avoid a local reference table overflow (#5629)
- jni::UniqueLocalFrame frame = jni::PushLocalFrame(*env2, 2);
-
- // Build the Region object
- jni::jobject* jregion = &jni::NewObject(*env2, *offlineRegionClass, *offlineRegionConstructorId);
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionOfflineManagerId, obj);
- jni::SetField<jlong>(*env2, jregion, *offlineRegionIdId, region.getID());
-
- // Definition object
- mbgl::OfflineTilePyramidRegionDefinition definition = region.getDefinition();
- jni::jobject* jdefinition = &jni::NewObject(*env2, *offlineRegionDefinitionClass, *offlineRegionDefinitionConstructorId);
- jni::SetField<jni::jobject*>(*env2, jdefinition, *offlineRegionDefinitionStyleURLId, std_string_to_jstring(env2, definition.styleURL));
- jni::SetField<jni::jobject*>(*env2, jdefinition, *offlineRegionDefinitionBoundsId, latlngbounds_from_native(env2, definition.bounds));
- jni::SetField<jdouble>(*env2, jdefinition, *offlineRegionDefinitionMinZoomId, definition.minZoom);
- jni::SetField<jdouble>(*env2, jdefinition, *offlineRegionDefinitionMaxZoomId, definition.maxZoom);
- jni::SetField<jfloat>(*env2, jdefinition, *offlineRegionDefinitionPixelRatioId, definition.pixelRatio);
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionDefinitionId, jdefinition);
-
- // Metadata object
- jni::jarray<jbyte>* metadata = metadata_from_native(env2, region.getMetadata());
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionMetadataId, metadata);
-
- // Moves the region on the stack into a heap-allocated one
- jni::SetField<jlong>(*env2, jregion, *offlineRegionPtrId,
- reinterpret_cast<jlong>(new mbgl::OfflineRegion(std::move(region))));
-
- jni::SetObjectArrayElement(*env2, *jregions, index, jregion);
- index++;
- }
-
- // Trigger callback
- jni::CallMethod<void>(*env2, listCallback, *listOnListMethodId, jregions);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(obj));
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(listCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-void createOfflineRegion(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jni::jobject* definition_, jni::jarray<jbyte>* metadata_, jni::jobject* createCallback) {
- // Checks
- assert(defaultFileSourcePtr != 0);
- NullCheck(*env, createCallback);
-
- // Definition fields
- jni::jstring* jStyleURL = reinterpret_cast<jni::jstring*>(jni::GetField<jni::jobject*>(*env, definition_, *offlineRegionDefinitionStyleURLId));
- std::string styleURL = std_string_from_jstring(env, jStyleURL);
- jni::jobject* jBounds = jni::GetField<jni::jobject*>(*env, definition_, *offlineRegionDefinitionBoundsId);
- jdouble jMinZoom = jni::GetField<jdouble>(*env, definition_, *offlineRegionDefinitionMinZoomId);
- jdouble jMaxZoom = jni::GetField<jdouble>(*env, definition_, *offlineRegionDefinitionMaxZoomId);
- jfloat jPixelRatio = jni::GetField<jfloat>(*env, definition_, *offlineRegionDefinitionPixelRatioId);
-
- // Convert bounds fields to native
- mbgl::LatLngBounds bounds = latlngbounds_from_java(env, jBounds);
-
- // Definition
- mbgl::OfflineTilePyramidRegionDefinition definition(styleURL, bounds, jMinZoom, jMaxZoom, jPixelRatio);
-
- // Metadata
- mbgl::OfflineRegionMetadata metadata;
- if (metadata_ != nullptr) {
- metadata = metadata_from_java(env, *metadata_);
- }
-
- // Makes sure the objects don't get GC'ed
- obj = jni::NewGlobalRef(*env, obj).release();
- createCallback = jni::NewGlobalRef(*env, createCallback).release();
-
- // Launch createCallback
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->createOfflineRegion(definition, metadata, [obj, defaultFileSourcePtr, createCallback] (std::exception_ptr error, mbgl::optional<mbgl::OfflineRegion> region) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, createCallback, *createOnErrorMethodId, std_string_to_jstring(env2, message));
- } else if (region) {
- // Build the Region object
- jni::jobject* jregion = &jni::NewObject(*env2, *offlineRegionClass, *offlineRegionConstructorId);
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionOfflineManagerId, obj);
- jni::SetField<jlong>(*env2, jregion, *offlineRegionIdId, region->getID());
-
- // Metadata object
- jni::jarray<jbyte>* jmetadata = metadata_from_native(env2, region->getMetadata());
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionMetadataId, jmetadata);
-
- // Moves the region on the stack into a heap-allocated one
- jni::SetField<jlong>(*env2, jregion, *offlineRegionPtrId,
- reinterpret_cast<jlong>(new mbgl::OfflineRegion(std::move(*region))));
-
- // Invoke Java callback
- jni::CallMethod<void>(*env2, createCallback, *createOnCreateMethodId, jregion);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(obj));
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(createCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-// A deleter that doesn't retain an JNIEnv handle but instead tries to attach the JVM. This means
-// it can be used on any thread to delete a global ref.
-struct GenericGlobalRefDeleter {
- void operator()(jni::jobject* p) const {
- if (p) {
- auto env = AttachEnv();
- env->DeleteGlobalRef(jni::Unwrap(p));
- }
- }
-};
-
-void setResourceTransform(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jni::jobject* transformCallback) {
- // Checks
- assert(defaultFileSourcePtr != 0);
-
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- if (transformCallback) {
- // Launch transformCallback
- defaultFileSource->setResourceTransform([
- // Capture the OfflineManager and ResourceTransformCallback objects as a managed global into
- // the lambda. They are released automatically when we're setting a new ResourceTransform in
- // a subsequent call.
- // Note: we're converting them to shared_ptrs because this lambda is converted to a std::function,
- // which requires copyability of its captured variables.
- offlineManager = std::shared_ptr<jni::jobject>(jni::NewGlobalRef(*env, obj).release(), GenericGlobalRefDeleter()),
- callback = std::shared_ptr<jni::jobject>(jni::NewGlobalRef(*env, transformCallback).release(), GenericGlobalRefDeleter()),
- env
- ](mbgl::Resource::Kind kind, std::string&& url_) {
- auto url = std_string_to_jstring(env, url_);
- url = reinterpret_cast<jni::jstring*>(jni::CallMethod<jni::jobject*>(
- *env, callback.get(), *transformOnURLMethodId, int(kind), url));
- return std_string_from_jstring(env, url);
- });
- } else {
- // Reset the callback
- defaultFileSource->setResourceTransform(nullptr);
- }
-}
-
-void setOfflineMapboxTileCountLimit(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jlong limit) {
- // Checks
- assert(defaultFileSourcePtr != 0);
- assert(limit > 0);
-
- // Set limit
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->setOfflineMapboxTileCountLimit(limit);
-}
-
-mbgl::OfflineRegion* getOfflineRegionPeer(JNIEnv *env, jni::jobject* offlineRegion_) {
- jlong offlineRegionPtr = jni::GetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId);
- if (!offlineRegionPtr) {
- jni::ThrowNew(*env, jni::FindClass(*env, "java/lang/IllegalStateException"),
- "Use of OfflineRegion after OfflineRegion.delete");
- }
- return reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr);
-}
-
-void destroyOfflineRegion(JNIEnv *env, jni::jobject* offlineRegion_) {
- // Offline region
- jlong offlineRegionPtr = jni::GetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId);
- if (!offlineRegionPtr) {
- return; // Already deleted
- }
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Release the observer and delete the region
- mbgl::OfflineRegion *offlineRegion = reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr);
- defaultFileSource->setOfflineRegionObserver(*offlineRegion, nullptr);
- jni::SetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId, 0);
- delete offlineRegion;
-}
-
-void setOfflineRegionObserver(JNIEnv *env, jni::jobject* offlineRegion_, jni::jobject* observerCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Define the observer
- class Observer : public mbgl::OfflineRegionObserver {
- public:
- Observer(jni::UniqueGlobalRef<jni::jobject>&& observerCallback_)
- : observerCallback(std::move(observerCallback_)) {
- }
-
- ~Observer() override {
- mbgl::Log::Debug(mbgl::Event::JNI, "~Observer()");
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- jni::DeleteGlobalRef(*env2, std::move(observerCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- void statusChanged(mbgl::OfflineRegionStatus status) override {
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
-
- // Conver to jint
- jint downloadState;
- switch(status.downloadState) {
- case mbgl::OfflineRegionDownloadState::Inactive:
- downloadState = 0;
- break;
- case mbgl::OfflineRegionDownloadState::Active:
- downloadState = 1;
- break;
- }
-
- // Create a new local reference frame (capacity 1 for the NewObject allocation below)
- // to avoid a local reference table overflow (#4706)
- jni::UniqueLocalFrame frame = jni::PushLocalFrame(*env2, 1);
-
- // Stats object
- jni::jobject* jstatus = &jni::NewObject(*env2, *offlineRegionStatusClass, *offlineRegionStatusConstructorId);
- jni::SetField<jint>(*env2, jstatus, *offlineRegionStatusDownloadStateId, downloadState);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceCountId, status.completedResourceCount);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceSizeId, status.completedResourceSize);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedTileCountId, status.completedTileCount);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedTileSizeId, status.completedTileSize);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountId, status.requiredResourceCount);
- jni::SetField<jboolean>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountIsPreciseId, status.requiredResourceCountIsPrecise);
- jni::CallMethod<void>(*env2, observerCallback.get(), *offlineRegionObserveronStatusChangedId, jstatus);
-
- // Detach when we're done
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- void responseError(mbgl::Response::Error error) override {
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
-
- // Handle the value of reason independently of the underlying int value
- std::string errorReason;
- switch(error.reason) {
- case mbgl::Response::Error::Reason::Success:
- errorReason = "REASON_SUCCESS";
- break;
- case mbgl::Response::Error::Reason::NotFound:
- errorReason = "REASON_NOT_FOUND";
- break;
- case mbgl::Response::Error::Reason::Server:
- errorReason = "REASON_SERVER";
- break;
- case mbgl::Response::Error::Reason::Connection:
- errorReason = "REASON_CONNECTION";
- break;
- case mbgl::Response::Error::Reason::RateLimit:
- errorReason = "REASON_RATE_LIMIT";
- break;
- case mbgl::Response::Error::Reason::Other:
- errorReason = "REASON_OTHER";
- break;
- }
-
- // Error object
- jni::UniqueLocalFrame frame = jni::PushLocalFrame(*env2, 3);
- jni::jobject* jerror = &jni::NewObject(*env2, *offlineRegionErrorClass, *offlineRegionErrorConstructorId);
- jni::SetField<jni::jobject*>(*env2, jerror, *offlineRegionErrorReasonId, std_string_to_jstring(env2, errorReason));
- jni::SetField<jni::jobject*>(*env2, jerror, *offlineRegionErrorMessageId, std_string_to_jstring(env2, error.message));
- jni::CallMethod<void>(*env2, observerCallback.get(), *offlineRegionObserveronErrorId, jerror);
-
- // Detach when we're done
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- void mapboxTileCountLimitExceeded(uint64_t limit) override {
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
-
- // Send limit
- jni::CallMethod<void>(*env2, observerCallback.get(), *offlineRegionObserveronLimitId, jlong(limit));
-
- // Detach when we're done
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- jni::UniqueGlobalRef<jni::jobject> observerCallback;
- };
-
- // Set the observer
- defaultFileSource->setOfflineRegionObserver(*offlineRegion,
- std::make_unique<Observer>(jni::NewGlobalRef(*env, observerCallback)));
-}
-
-void setOfflineRegionDownloadState(JNIEnv *env, jni::jobject* offlineRegion_, jint offlineRegionDownloadState) {
- // State
- mbgl::OfflineRegionDownloadState state;
- if (offlineRegionDownloadState == 0) {
- state = mbgl::OfflineRegionDownloadState::Inactive;
- } else if (offlineRegionDownloadState == 1) {
- state = mbgl::OfflineRegionDownloadState::Active;
- } else {
- mbgl::Log::Error(mbgl::Event::JNI, "State can only be 0 (inactive) or 1 (active).");
- return;
- }
-
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Set new state
- defaultFileSource->setOfflineRegionDownloadState(*offlineRegion, state);
-}
-
-void getOfflineRegionStatus(JNIEnv *env, jni::jobject* offlineRegion_, jni::jobject* statusCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Makes sure the callback doesn't get GC'ed
- statusCallback = jni::NewGlobalRef(*env, statusCallback).release();
-
- // Set new state
- defaultFileSource->getOfflineRegionStatus(*offlineRegion, [statusCallback](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionStatus> status) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, statusCallback, *offlineRegionStatusOnErrorId, std_string_to_jstring(env2, message));
- } else if (status) {
- // Conver to jint
- jint downloadState = -1;
- if (status->downloadState == mbgl::OfflineRegionDownloadState::Inactive) {
- downloadState = 0;
- } else if (status->downloadState == mbgl::OfflineRegionDownloadState::Active) {
- downloadState = 1;
- } else {
- mbgl::Log::Error(mbgl::Event::JNI, "Unsupported OfflineRegionDownloadState value.");
- return;
- }
-
- // Stats object
- jni::jobject* jstatus = &jni::NewObject(*env2, *offlineRegionStatusClass, *offlineRegionStatusConstructorId);
- jni::SetField<jint>(*env2, jstatus, *offlineRegionStatusDownloadStateId, downloadState);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceCountId, status->completedResourceCount);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceSizeId, status->completedResourceSize);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountId, status->requiredResourceCount);
- jni::SetField<jboolean>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountIsPreciseId, status->requiredResourceCountIsPrecise);
- jni::CallMethod<void>(*env2, statusCallback, *offlineRegionStatusOnStatusId, jstatus);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(statusCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-void deleteOfflineRegion(JNIEnv *env, jni::jobject* offlineRegion_, jni::jobject* deleteCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Makes sure the callback doesn't get GC'ed
- deleteCallback = jni::NewGlobalRef(*env, deleteCallback).release();
-
- // Set new state
- jni::SetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId, 0);
- defaultFileSource->deleteOfflineRegion(std::move(*offlineRegion), [deleteCallback](std::exception_ptr error) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, deleteCallback, *offlineRegionDeleteOnErrorId, std_string_to_jstring(env2, message));
- } else {
- jni::CallMethod<void>(*env2, deleteCallback, *offlineRegionDeleteOnDeleteId);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(deleteCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-void updateOfflineRegionMetadata(JNIEnv *env, jni::jobject* offlineRegion_, jni::jarray<jbyte>* metadata_, jni::jobject* updateCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Id conversion
- int64_t id = offlineRegion->getID();
-
- // Metadata
- mbgl::OfflineRegionMetadata metadata;
- if (metadata_ != nullptr) {
- metadata = metadata_from_java(env, *metadata_);
- }
-
- // Makes sure the objects don't get GC'ed
- updateCallback = jni::NewGlobalRef(*env, updateCallback).release();
-
- // Launch updateCallback
- defaultFileSource->updateOfflineMetadata(id, metadata, [updateCallback] (std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionMetadata> data) mutable {
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, updateCallback, *updateMetadataOnErrorMethodId, std_string_to_jstring(env2, message));
- } else if (data) {
- jni::jarray<jbyte>* jmetadata = metadata_from_native(env2, *data);
- jni::CallMethod<void>(*env2, updateCallback, *updateMetadataOnUpdateMethodId, jmetadata);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(updateCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-// Offline calls end
-
-} // anonymous
-
-namespace mbgl {
-namespace android {
-
void registerNatives(JavaVM *vm) {
theJVM = vm;
jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
+ // For the DefaultFileSource
static mbgl::util::RunLoop mainRunLoop;
+ FileSource::registerNative(env);
- 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);
+ LatLngBounds::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);
@@ -1828,291 +126,17 @@ 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, "<init>", "(DD)V");
- latLngLatitudeId = &jni::GetFieldID(env, *latLngClass, "latitude", "D");
- latLngLongitudeId = &jni::GetFieldID(env, *latLngClass, "longitude", "D");
- latLngBoundsClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/LatLngBounds");
- latLngBoundsClass = jni::NewGlobalRef(env, latLngBoundsClass).release();
- latLngBoundsConstructorId = &jni::GetMethodID(env, *latLngBoundsClass, "<init>", "(DDDD)V");
- latLngBoundsLatNorthId = &jni::GetFieldID(env, *latLngBoundsClass, "mLatNorth", "D");
- latLngBoundsLatSouthId = &jni::GetFieldID(env, *latLngBoundsClass, "mLatSouth", "D");
- 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, "<init>", "()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, "<init>", "(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, "<init>", "(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, "<init>", "()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");
- 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<decltype(name), name>( #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(nativeInitializeDisplay, "(J)V"),
- MAKE_NATIVE_METHOD(nativeTerminateDisplay, "(J)V"),
- MAKE_NATIVE_METHOD(nativeInitializeContext, "(J)V"),
- MAKE_NATIVE_METHOD(nativeTerminateContext, "(J)V"),
- MAKE_NATIVE_METHOD(nativeCreateSurface, "(JLandroid/view/Surface;)V"),
- MAKE_NATIVE_METHOD(nativeDestroySurface, "(J)V"),
- MAKE_NATIVE_METHOD(nativeUpdate, "(J)V"),
- MAKE_NATIVE_METHOD(nativeRender, "(J)V"),
- MAKE_NATIVE_METHOD(nativeViewResize, "(JII)V"),
- MAKE_NATIVE_METHOD(nativeFramebufferResize, "(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 {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager"; }
-
- struct ListOfflineRegionsCallback {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback"; }
- };
-
- struct CreateOfflineRegionsCallback {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback"; }
- };
-
- struct ResourceTransformCallback {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$ResourceTransformCallback"; }
- };
- };
-
- struct OfflineRegion {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion"; }
- };
-
- jni::Class<OfflineManager> offlineManagerClass = jni::Class<OfflineManager>::Find(env);
- offlineManagerClassPtrId = &jni::GetFieldID(env, offlineManagerClass, "mDefaultFileSourcePtr", "J");
-
- jni::RegisterNatives(env, offlineManagerClass,
- MAKE_NATIVE_METHOD(sharedDefaultFileSource, "(Ljava/lang/String;Ljava/lang/String;)J"),
- MAKE_NATIVE_METHOD(setAccessToken, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(getAccessToken, "(J)Ljava/lang/String;"),
- MAKE_NATIVE_METHOD(listOfflineRegions, "(JLcom/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback;)V"),
- MAKE_NATIVE_METHOD(createOfflineRegion, "(JLcom/mapbox/mapboxsdk/offline/OfflineRegionDefinition;[BLcom/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback;)V"),
- MAKE_NATIVE_METHOD(setResourceTransform, "(JLcom/mapbox/mapboxsdk/offline/OfflineManager$ResourceTransformCallback;)V"),
- MAKE_NATIVE_METHOD(setOfflineMapboxTileCountLimit, "(JJ)V")
- );
-
- jni::Class<OfflineManager::ListOfflineRegionsCallback> listOfflineRegionsCallbackClass = jni::Class<OfflineManager::ListOfflineRegionsCallback>::Find(env);
- listOnListMethodId = &jni::GetMethodID(env, listOfflineRegionsCallbackClass, "onList", "([Lcom/mapbox/mapboxsdk/offline/OfflineRegion;)V");
- listOnErrorMethodId = &jni::GetMethodID(env, listOfflineRegionsCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- jni::Class<OfflineManager::CreateOfflineRegionsCallback> createOfflineRegionCallbackClass = jni::Class<OfflineManager::CreateOfflineRegionsCallback>::Find(env);
- createOnCreateMethodId = &jni::GetMethodID(env, createOfflineRegionCallbackClass, "onCreate", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion;)V");
- createOnErrorMethodId = &jni::GetMethodID(env, createOfflineRegionCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- jni::Class<OfflineManager::ResourceTransformCallback> resourceTransformCallbackClass = jni::Class<OfflineManager::ResourceTransformCallback>::Find(env);
- transformOnURLMethodId = &jni::GetMethodID(env, resourceTransformCallbackClass, "onURL", "(ILjava/lang/String;)Ljava/lang/String;");
-
- offlineRegionClass = &jni::FindClass(env, OfflineRegion::Name());
- offlineRegionClass = jni::NewGlobalRef(env, offlineRegionClass).release();
- offlineRegionConstructorId = &jni::GetMethodID(env, *offlineRegionClass, "<init>", "()V");
- offlineRegionOfflineManagerId = &jni::GetFieldID(env, *offlineRegionClass, "offlineManager", "Lcom/mapbox/mapboxsdk/offline/OfflineManager;");
- offlineRegionIdId = &jni::GetFieldID(env, *offlineRegionClass, "mId", "J");
- offlineRegionDefinitionId = &jni::GetFieldID(env, *offlineRegionClass, "mDefinition", "Lcom/mapbox/mapboxsdk/offline/OfflineRegionDefinition;");
- offlineRegionMetadataId = &jni::GetFieldID(env, *offlineRegionClass, "mMetadata", "[B");
- offlineRegionPtrId = &jni::GetFieldID(env, *offlineRegionClass, "mOfflineRegionPtr", "J");
-
- jni::RegisterNatives(env, *offlineRegionClass,
- MAKE_NATIVE_METHOD(destroyOfflineRegion, "()V"),
- MAKE_NATIVE_METHOD(setOfflineRegionObserver, "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver;)V"),
- MAKE_NATIVE_METHOD(setOfflineRegionDownloadState, "(I)V"),
- MAKE_NATIVE_METHOD(getOfflineRegionStatus, "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback;)V"),
- MAKE_NATIVE_METHOD(deleteOfflineRegion, "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback;)V"),
- MAKE_NATIVE_METHOD(updateOfflineRegionMetadata, "([BLcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback;)V")
- );
-
- // This needs to be updated once we support more than one type of region definition
- offlineRegionDefinitionClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition");
- offlineRegionDefinitionClass = jni::NewGlobalRef(env, offlineRegionDefinitionClass).release();
- offlineRegionDefinitionConstructorId = &jni::GetMethodID(env, *offlineRegionDefinitionClass, "<init>", "()V");
- offlineRegionDefinitionStyleURLId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "styleURL", "Ljava/lang/String;");
- offlineRegionDefinitionBoundsId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "bounds", "Lcom/mapbox/mapboxsdk/geometry/LatLngBounds;");
- offlineRegionDefinitionMinZoomId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "minZoom", "D");
- offlineRegionDefinitionMaxZoomId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "maxZoom", "D");
- offlineRegionDefinitionPixelRatioId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "pixelRatio", "F");
-
- jni::jclass* offlineRegionObserverClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver");
- offlineRegionObserveronStatusChangedId = &jni::GetMethodID(env, *offlineRegionObserverClass, "onStatusChanged", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegionStatus;)V");
- offlineRegionObserveronErrorId = &jni::GetMethodID(env, *offlineRegionObserverClass, "onError", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegionError;)V");
- offlineRegionObserveronLimitId = &jni::GetMethodID(env, *offlineRegionObserverClass, "mapboxTileCountLimitExceeded", "(J)V");
-
- offlineRegionStatusClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegionStatus");
- offlineRegionStatusClass = jni::NewGlobalRef(env, offlineRegionStatusClass).release();
- offlineRegionStatusConstructorId = &jni::GetMethodID(env, *offlineRegionStatusClass, "<init>", "()V");
- offlineRegionStatusDownloadStateId = &jni::GetFieldID(env, *offlineRegionStatusClass, "downloadState", "I");
- offlineRegionStatusCompletedResourceCountId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedResourceCount", "J");
- offlineRegionStatusCompletedResourceSizeId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedResourceSize", "J");
- offlineRegionStatusCompletedTileCountId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedTileCount", "J");
- offlineRegionStatusCompletedTileSizeId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedTileSize", "J");
- offlineRegionStatusRequiredResourceCountId = &jni::GetFieldID(env, *offlineRegionStatusClass, "requiredResourceCount", "J");
- offlineRegionStatusRequiredResourceCountIsPreciseId = &jni::GetFieldID(env, *offlineRegionStatusClass, "requiredResourceCountIsPrecise", "Z");
-
- offlineRegionErrorClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegionError");
- offlineRegionErrorClass = jni::NewGlobalRef(env, offlineRegionErrorClass).release();
- offlineRegionErrorConstructorId = &jni::GetMethodID(env, *offlineRegionErrorClass, "<init>", "()V");
- offlineRegionErrorReasonId = &jni::GetFieldID(env, *offlineRegionErrorClass, "reason", "Ljava/lang/String;");
- offlineRegionErrorMessageId = &jni::GetFieldID(env, *offlineRegionErrorClass, "message", "Ljava/lang/String;");
-
- jni::jclass* offlineRegionStatusCallbackClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback");
- offlineRegionStatusOnStatusId = &jni::GetMethodID(env, *offlineRegionStatusCallbackClass, "onStatus", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegionStatus;)V");
- offlineRegionStatusOnErrorId = &jni::GetMethodID(env, *offlineRegionStatusCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- jni::jclass* offlineRegionDeleteCallbackClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback");
- offlineRegionDeleteOnDeleteId = &jni::GetMethodID(env, *offlineRegionDeleteCallbackClass, "onDelete", "()V");
- offlineRegionDeleteOnErrorId = &jni::GetMethodID(env, *offlineRegionDeleteCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- jni::jclass* offlineRegionUpdateMetadataCallbackClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback");
- updateMetadataOnUpdateMethodId = &jni::GetMethodID(env, *offlineRegionUpdateMetadataCallbackClass, "onUpdate", "([B)V");
- updateMetadataOnErrorMethodId = &jni::GetMethodID(env, *offlineRegionUpdateMetadataCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- // Offline end
+ // Connectivity
+ ConnectivityListener::registerNative(env);
- char release[PROP_VALUE_MAX] = "";
- __system_property_get("ro.build.version.release", release);
- androidRelease = std::string(release);
+ // Offline
+ OfflineManager::registerNative(env);
+ OfflineRegion::registerNative(env);
+ OfflineRegionDefinition::registerNative(env);
+ OfflineTilePyramidRegionDefinition::registerNative(env);
+ OfflineRegionError::registerNative(env);
+ OfflineRegionStatus::registerNative(env);
}
} // namespace android
diff --git a/platform/android/src/jni.hpp b/platform/android/src/jni.hpp
index d12030f3c1..f0c113f754 100644
--- a/platform/android/src/jni.hpp
+++ b/platform/android/src/jni.hpp
@@ -14,15 +14,9 @@ extern JavaVM* theJVM;
extern std::string cachePath;
extern std::string dataPath;
extern std::string apkPath;
-extern std::string androidRelease;
-extern jmethodID onInvalidateId;
-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);
diff --git a/platform/android/src/jni/generic_global_ref_deleter.hpp b/platform/android/src/jni/generic_global_ref_deleter.hpp
new file mode 100644
index 0000000000..4e53e0a0ce
--- /dev/null
+++ b/platform/android/src/jni/generic_global_ref_deleter.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <jni/jni.hpp>
+
+#include "../attach_env.hpp"
+
+namespace mbgl {
+namespace android {
+
+// A deleter that doesn't retain an JNIEnv handle but instead tries to attach the JVM. This means
+// it can be used on any thread to delete a global ref.
+struct GenericGlobalRefDeleter {
+ void operator()(jni::jobject* p) const {
+ if (p) {
+ auto env = AttachEnv();
+ env->DeleteGlobalRef(jni::Unwrap(p));
+ }
+ }
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index b36b477f2f..a0bd06345f 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 "default_file_source.hpp"
#include <cstdlib>
#include <ctime>
@@ -11,90 +9,91 @@
#include <sys/system_properties.h>
-#include <mbgl/util/platform.hpp>
-#include <mbgl/util/event.hpp>
-#include <mbgl/util/logging.hpp>
-#include <mbgl/gl/extension.hpp>
+#include <EGL/egl.h>
+#include <android/native_window_jni.h>
+
+#include <jni/jni.hpp>
+
#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/extension.hpp>
#include <mbgl/map/backend_scope.hpp>
#include <mbgl/util/constants.hpp>
+#include <mbgl/util/event.hpp>
+#include <mbgl/util/exception.hpp>
+#include <mbgl/util/geo.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/shared_thread_pool.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/platform.hpp>
+#include <mbgl/sprite/sprite_image.hpp>
+
+#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_),
- availableProcessors(availableProcessors_),
- totalMemory(totalMemory_),
- fileSource(defaultFileSource(mbgl::android::cachePath + "/mbgl-offline.db", mbgl::android::apkPath)),
- threadPool(sharedThreadPool()) {
-
- assert(env_ != nullptr);
- assert(obj_ != nullptr);
-
- if (env->GetJavaVM(&vm) < 0) {
- env->ExceptionDescribe();
- return;
- }
-
- obj = env->NewWeakGlobalRef(obj_);
- if (obj == nullptr) {
- env->ExceptionDescribe();
+NativeMapView::NativeMapView(jni::JNIEnv& _env, jni::Object<NativeMapView> _obj, jni::Object<FileSource> jFileSource,
+ jni::jfloat _pixelRatio, jni::jint _availableProcessors, jni::jlong _totalMemory) :
+ javaPeer(_obj.NewWeakGlobalRef(_env)),
+ pixelRatio(_pixelRatio),
+ availableProcessors(_availableProcessors),
+ totalMemory(_totalMemory),
+ threadPool(sharedThreadPool()) {
+
+ // Get a reference to the JavaVM for callbacks
+ if (_env.GetJavaVM(&vm) < 0) {
+ _env.ExceptionDescribe();
return;
}
+ // Create the core map
map = std::make_unique<mbgl::Map>(
*this, mbgl::Size{ static_cast<uint32_t>(width), static_cast<uint32_t>(height) },
- pixelRatio, fileSource, *threadPool, MapMode::Continuous);
+ pixelRatio, mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource)
+ , *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<float>(totalMemory) / 1000.0f / 1000.0f / 1000.0f;
float sizeFactor = (static_cast<float>(map->getSize().width) / mbgl::util::tileSize) *
- (static_cast<float>(map->getSize().height) / mbgl::util::tileSize);
+ (static_cast<float>(map->getSize().height) / mbgl::util::tileSize);
- size_t cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f;
-
- map->setSourceTileCacheSize(cacheSize);
+ map->setSourceTileCacheSize(zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f);
}
+/**
+ * Called through NativeMapView#destroy()
+ */
NativeMapView::~NativeMapView() {
- terminateContext();
- destroySurface();
- terminateDisplay();
-
- assert(vm != nullptr);
- assert(obj != nullptr);
+ _terminateContext();
+ _destroySurface();
+ _terminateDisplay();
map.reset();
- env->DeleteWeakGlobalRef(obj);
-
- obj = nullptr;
- env = nullptr;
vm = nullptr;
}
-mbgl::Size NativeMapView::getFramebufferSize() const {
- return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
-}
-
-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.
+ */
void NativeMapView::activate() {
if (active++) {
return;
@@ -123,6 +122,9 @@ void NativeMapView::activate() {
}
}
+/**
+ * From mbgl::Backend.
+ */
void NativeMapView::deactivate() {
if (--active) {
return;
@@ -147,17 +149,57 @@ void NativeMapView::deactivate() {
}
}
+/**
+ * From mbgl::Backend. Callback to java NativeMapView#onInvalidate().
+ *
+ * May be called from any thread
+ */
void NativeMapView::invalidate() {
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onInvalidate = javaClass.GetMethod<void ()>(*_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) {
assert(vm != nullptr);
- assert(obj != nullptr);
- env->CallVoidMethod(obj, onInvalidateId);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- }
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onMapChanged = javaClass.GetMethod<void (int)>(*_env, "onMapChanged");
+ javaPeer->Call(*_env, onMapChanged, (int) change);
+}
+
+// JNI Methods //
+
+void NativeMapView::initializeDisplay(jni::JNIEnv&) {
+ _initializeDisplay();
+}
+
+void NativeMapView::terminateDisplay(jni::JNIEnv&) {
+ _terminateDisplay();
+}
+
+void NativeMapView::initializeContext(jni::JNIEnv&) {
+ _initializeContext();
}
-void NativeMapView::render() {
+void NativeMapView::terminateContext(jni::JNIEnv&) {
+ _terminateContext();
+}
+
+void NativeMapView::createSurface(jni::JNIEnv& env, jni::Object<> _surface) {
+ _createSurface(ANativeWindow_fromSurface(&env, jni::Unwrap(*_surface)));
+}
+
+void NativeMapView::destroySurface(jni::JNIEnv&) {
+ _destroySurface();
+}
+
+void NativeMapView::render(jni::JNIEnv& env) {
BackendScope guard(*this);
if (framebufferSizeChanged) {
@@ -173,13 +215,12 @@ void NativeMapView::render() {
// take snapshot
auto image = getContext().readFramebuffer<mbgl::PremultipliedImage>(getFramebufferSize());
- auto bitmap = Bitmap::CreateBitmap(*env, std::move(image));
+ auto bitmap = Bitmap::CreateBitmap(env, std::move(image));
// invoke Mapview#OnSnapshotReady
- env->CallVoidMethod(obj, onSnapshotReadyId, jni::Unwrap(*bitmap));
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- }
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onSnapshotReady = javaClass.GetMethod<void (jni::Object<Bitmap>)>(*_env, "onSnapshotReady");
+ javaPeer->Call(*_env, onSnapshotReady, bitmap);
}
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) {
@@ -195,13 +236,611 @@ void NativeMapView::render() {
}
}
-mbgl::Map &NativeMapView::getMap() { return *map; }
+void NativeMapView::update(jni::JNIEnv&) {
+ invalidate();
+}
+
+void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) {
+ width = w;
+ height = h;
+ map->setSize({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
+}
+
+void NativeMapView::resizeFramebuffer(jni::JNIEnv&, int w, int h) {
+ fbWidth = w;
+ fbHeight = h;
+ framebufferSizeChanged = true;
+ invalidate();
+}
+
+jni::String NativeMapView::getStyleUrl(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, map->getStyleURL());
+}
+
+void NativeMapView::setStyleUrl(jni::JNIEnv& env, jni::String url) {
+ map->setStyleURL(jni::Make<std::string>(env, url));
+}
+
+jni::String NativeMapView::getStyleJson(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, map->getStyleJSON());
+}
+
+void NativeMapView::setStyleJson(jni::JNIEnv& env, jni::String json) {
+ map->setStyleJSON(jni::Make<std::string>(env, json));
+}
+
+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, jni::jlong duration) {
+ mbgl::AnimationOptions animationOptions;
+ if (duration > 0) {
+ animationOptions.duration.emplace(mbgl::Milliseconds(duration));
+ animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0.3, 0.6, 1.0 });
+ }
+ map->moveBy({dx, dy}, animationOptions);
+}
+
+void NativeMapView::jumpTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom) {
+ mbgl::CameraOptions options;
+ if (angle != -1) {
+ options.angle = (-angle * M_PI) / 180;
+ }
+ options.center = mbgl::LatLng(latitude, longitude);
+ options.padding = insets;
+ if (pitch != -1) {
+ options.pitch = pitch * M_PI / 180;
+ }
+ if (zoom != -1) {
+ options.zoom = zoom;
+ }
+
+ map->jumpTo(options);
+}
+
+void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, jni::jboolean easing) {
+ mbgl::CameraOptions cameraOptions;
+ if (angle != -1) {
+ cameraOptions.angle = (-angle * M_PI) / 180;
+ }
+ cameraOptions.center = mbgl::LatLng(latitude, longitude);
+ cameraOptions.padding = insets;
+ 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 });
+ }
+
+ map->easeTo(cameraOptions, animationOptions);
+}
+
+void NativeMapView::flyTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom) {
+ mbgl::CameraOptions cameraOptions;
+ if (angle != -1) {
+ cameraOptions.angle = (-angle * M_PI) / 180 ;
+ }
+ cameraOptions.center = mbgl::LatLng(latitude, longitude);
+ cameraOptions.padding = insets;
+ if (pitch != -1) {
+ cameraOptions.pitch = pitch * M_PI / 180;
+ }
+ if (zoom != -1) {
+ cameraOptions.zoom = zoom;
+ }
+
+ mbgl::AnimationOptions animationOptions;
+ animationOptions.duration.emplace(mbgl::Duration(duration));
+ map->flyTo(cameraOptions, animationOptions);
+}
+
+jni::Object<LatLng> 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, jni::jlong duration) {
+ map->setLatLng(mbgl::LatLng(latitude, longitude), insets, mbgl::Milliseconds(duration));
+}
+
+void NativeMapView::setReachability(jni::JNIEnv&, jni::jboolean reachable) {
+ if (reachable) {
+ mbgl::NetworkStatus::Reachable();
+ }
+}
+
+void NativeMapView::resetPosition(jni::JNIEnv&) {
+ map->resetPosition();
+}
+
+jni::jdouble NativeMapView::getPitch(jni::JNIEnv&) {
+ return map->getPitch();
+}
+
+void NativeMapView::setPitch(jni::JNIEnv&, jni::jdouble pitch, jni::jlong duration) {
+ map->setPitch(pitch, mbgl::Milliseconds(duration));
+}
+
+void NativeMapView::scaleBy(jni::JNIEnv&, jni::jdouble ds, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) {
+ mbgl::ScreenCoordinate center(cx, cy);
+ map->scaleBy(ds, center, mbgl::Milliseconds(duration));
+}
+
+void NativeMapView::setScale(jni::JNIEnv&, jni::jdouble scale, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) {
+ mbgl::ScreenCoordinate center(cx, cy);
+ map->setScale(scale, center, mbgl::Milliseconds(duration));
+}
+
+jni::jdouble NativeMapView::getScale(jni::JNIEnv&) {
+ return map->getScale();
+}
+
+void NativeMapView::setZoom(jni::JNIEnv&, jni::jdouble zoom, jni::jlong duration) {
+ map->setZoom(zoom, mbgl::Milliseconds(duration));
+}
+
+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, jni::jlong duration) {
+ mbgl::ScreenCoordinate first(sx, sy);
+ mbgl::ScreenCoordinate second(ex, ey);
+ map->rotateBy(first, second, mbgl::Milliseconds(duration));
+}
+
+void NativeMapView::setBearing(jni::JNIEnv&, jni::jdouble degrees, jni::jlong duration) {
+ map->setBearing(degrees, mbgl::Milliseconds(duration));
+}
+
+void NativeMapView::setBearingXY(jni::JNIEnv&, jni::jdouble degrees, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) {
+ mbgl::ScreenCoordinate center(cx, cy);
+ map->setBearing(degrees, center, mbgl::Milliseconds(duration));
+}
+
+jni::jdouble NativeMapView::getBearing(jni::JNIEnv&) {
+ return map->getBearing();
+}
+
+void NativeMapView::resetNorth(jni::JNIEnv&) {
+ map->resetNorth();
+}
+
+void NativeMapView::setVisibleCoordinateBounds(JNIEnv& env, jni::Array<jni::Object<LatLng>> coordinates, jni::Object<RectF> padding, jdouble direction, jni::jlong duration) {
+ NullCheck(env, &coordinates);
+ std::size_t count = coordinates.Length(env);
+
+ std::vector<mbgl::LatLng> 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;
+ 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 });
+ }
+
+ 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;
+}
+
+jni::Array<jni::jdouble> 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<jni::jdouble>::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;
+ }
+
+ std::string iconId = jni::Make<std::string>(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<double>(lon, lat), iconId });
+}
+
+jni::Array<jni::jlong> NativeMapView::addMarkers(jni::JNIEnv& env, jni::Array<jni::Object<Marker>> jmarkers) {
+ jni::NullCheck(env, &jmarkers);
+ std::size_t len = jmarkers.Length(env);
+
+ std::vector<jni::jlong> ids;
+ ids.reserve(len);
+
+ for (std::size_t i = 0; i < len; i++) {
+ jni::Object<Marker> marker = jmarkers.Get(env, i);
+ ids.push_back(map->addAnnotation(mbgl::SymbolAnnotation {
+ Marker::getPosition(env, marker),
+ Marker::getIconId(env, marker)
+ }));
+
+ jni::DeleteLocalRef(env, marker);
+ }
+
+ auto result = jni::Array<jni::jlong>::New(env, len);
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, ids);
+
+ return result;
+}
+
+void NativeMapView::onLowMemory(JNIEnv&) {
+ map->onLowMemory();
+}
+
+using DebugOptions = mbgl::MapDebugOptions;
+
+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<ProjectedMeters> 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<PointF> NativeMapView::pixelForLatLng(JNIEnv& env, jdouble latitude, jdouble longitude) {
+ mbgl::ScreenCoordinate pixel = map->pixelForLatLng(mbgl::LatLng(latitude, longitude));
+ return PointF::New(env, static_cast<float>(pixel.x), static_cast<float>(pixel.y));
+}
+
+jni::Object<LatLng> 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<LatLng> 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<jlong> NativeMapView::addPolylines(JNIEnv& env, jni::Array<jni::Object<Polyline>> polylines) {
+ NullCheck(env, &polylines);
+ std::size_t len = polylines.Length(env);
+
+ std::vector<jni::jlong> 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<jni::jlong>::New(env, len);
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, ids);
+
+ return result;
+}
+
+
+jni::Array<jlong> NativeMapView::addPolygons(JNIEnv& env, jni::Array<jni::Object<Polygon>> polygons) {
+ NullCheck(env, &polygons);
+ std::size_t len = polygons.Length(env);
+
+ std::vector<jni::jlong> 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<jni::jlong>::New(env, len);
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, ids);
+
+ return result;
+}
+
+//TODO: Move to Polyline class and make native peer
+void NativeMapView::updatePolyline(JNIEnv& env, jlong polylineId, jni::Object<Polyline> 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> polygon) {
+ mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygon);
+ map->updateAnnotation(polygonId, annotation);
+}
+
+void NativeMapView::removeAnnotations(JNIEnv& env, jni::Array<jlong> 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::addAnnotationIcon(JNIEnv& env, jni::String symbol, jint w, jint h, jfloat scale, jni::Array<jbyte> jpixels) {
+ const std::string symbolName = jni::Make<std::string>(env, symbol);
+
+ NullCheck(env, &jpixels);
+ std::size_t size = jpixels.Length(env);
+
+ mbgl::PremultipliedImage premultipliedImage({ static_cast<uint32_t>(w), static_cast<uint32_t>(h) });
+ if (premultipliedImage.bytes() != uint32_t(size)) {
+ throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch");
+ }
+
+ jni::GetArrayRegion(env, *jpixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
+ auto iconImage = std::make_shared<mbgl::SpriteImage>(std::move(premultipliedImage), float(scale));
+ map->addAnnotationIcon(symbolName, iconImage);
+}
+
+jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, jni::String symbolName) {
+ return map->getTopOffsetPixelsForAnnotationIcon(jni::Make<std::string>(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<mbgl::Duration>(std::chrono::duration<jlong>(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<mbgl::Duration>(std::chrono::duration<jlong>(delay));
+ map->setTransitionOptions(transitionOptions);
+}
+
+jni::Array<jlong> NativeMapView::queryPointAnnotations(JNIEnv& env, jni::Object<RectF> 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<jlong> longIds(ids.begin(), ids.end());
+ auto result = jni::Array<jni::jlong>::New(env, ids.size());
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, longIds);
+
+ return result;
+}
+
+jni::Array<jni::Object<Feature>> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y, jni::Array<jni::String> layerIds) {
+ using namespace mbgl::android::conversion;
+ using namespace mapbox::geometry;
+
+ mbgl::optional<std::vector<std::string>> layers;
+ if (layerIds != nullptr && layerIds.Length(env) > 0) {
+ layers = toVector(env, layerIds);
+ }
+ point<double> point = {x, y};
+
+ return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(point, layers));
+}
+
+jni::Array<jni::Object<Feature>> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top, jni::jfloat right, jni::jfloat bottom, jni::Array<jni::String> layerIds) {
+ using namespace mbgl::android::conversion;
+ using namespace mapbox::geometry;
+
+ mbgl::optional<std::vector<std::string>> layers;
+ if (layerIds != nullptr && layerIds.Length(env) > 0) {
+ layers = toVector(env, layerIds);
+ }
+ box<double> box = { point<double>{ left, top}, point<double>{ right, bottom } };
+
+ return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(box, layers));
+}
+
+jni::Object<Layer> NativeMapView::getLayer(JNIEnv& env, jni::String layerId) {
+
+ // Find the layer
+ mbgl::style::Layer* coreLayer = map->getLayer(jni::Make<std::string>(env, layerId));
+ if (!coreLayer) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "No layer found");
+ return jni::Object<Layer>();
+ }
+
+ // Create and return the layer's native peer
+ return jni::Object<Layer>(createJavaLayerPeer(env, *map, *coreLayer));
+}
+
+void NativeMapView::addLayer(JNIEnv& env, jlong nativeLayerPtr, jni::String before) {
+ assert(nativeLayerPtr != 0);
+
+ Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
+ try {
+ layer->addToMap(*map, before ? mbgl::optional<std::string>(jni::Make<std::string>(env, before)) : mbgl::optional<std::string>());
+ } 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) {
+ map->removeLayer(jni::Make<std::string>(env, id));
+}
+
+/**
+ * Remove with wrapper object id. Ownership is transferred back to the wrapper
+ */
+void NativeMapView::removeLayer(JNIEnv&, jlong layerPtr) {
+ assert(layerPtr != 0);
+
+ mbgl::android::Layer *layer = reinterpret_cast<mbgl::android::Layer *>(layerPtr);
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->removeLayer(layer->get().getID());
+ if (coreLayer) {
+ layer->setLayer(std::move(coreLayer));
+ }
+}
+
+
+jni::Object<Source> NativeMapView::getSource(JNIEnv& env, jni::String sourceId) {
+ // Find the source
+ mbgl::style::Source* coreSource = map->getSource(jni::Make<std::string>(env, sourceId));
+ if (!coreSource) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "No source found");
+ return jni::Object<Source>();
+ }
+
+ // Create and return the source's native peer
+ return jni::Object<Source>(createJavaSourcePeer(env, *map, *coreSource));
+}
+
+void NativeMapView::addSource(JNIEnv& env, jni::jlong sourcePtr) {
+ assert(sourcePtr != 0);
+
+ Source *source = reinterpret_cast<Source *>(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) {
+ map->removeSource(jni::Make<std::string>(env, id));
+}
+
+void NativeMapView::removeSource(JNIEnv&, jlong sourcePtr) {
+ assert(sourcePtr != 0);
+
+ mbgl::android::Source *source = reinterpret_cast<mbgl::android::Source *>(sourcePtr);
+ std::unique_ptr<mbgl::style::Source> coreSource = map->removeSource(source->get().getID());
+ if (coreSource) {
+ source->setSource(std::move(coreSource));
+ }
+}
+
+void NativeMapView::addImage(JNIEnv& env, jni::String name, jni::jint w, jni::jint h, jni::jfloat scale, jni::Array<jbyte> pixels) {
+ jni::NullCheck(env, &pixels);
+ std::size_t size = pixels.Length(env);
+
+ mbgl::PremultipliedImage premultipliedImage({ static_cast<uint32_t>(w), static_cast<uint32_t>(h) });
+ if (premultipliedImage.bytes() != uint32_t(size)) {
+ throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch");
+ }
-mbgl::DefaultFileSource& NativeMapView::getFileSource() {
- return fileSource;
+ jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
+ auto spriteImage = std::make_unique<mbgl::SpriteImage>(std::move(premultipliedImage), float(scale));
+
+ map->addImage(jni::Make<std::string>(env, name), std::move(spriteImage));
+}
+
+void NativeMapView::removeImage(JNIEnv& env, jni::String name) {
+ map->removeImage(jni::Make<std::string>(env, name));
}
-void NativeMapView::initializeDisplay() {
+// Private methods //
+
+void NativeMapView::_initializeDisplay() {
assert(display == EGL_NO_DISPLAY);
assert(config == nullptr);
assert(format < 0);
@@ -286,145 +925,6 @@ void NativeMapView::initializeDisplay() {
}
}
-void NativeMapView::terminateDisplay() {
- if (display != EGL_NO_DISPLAY) {
- // Destroy the surface first, if it still exists. This call needs a valid surface.
- if (surface != EGL_NO_SURFACE) {
- if (!eglDestroySurface(display, surface)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
- eglGetError());
- throw std::runtime_error("eglDestroySurface() failed");
- }
- surface = EGL_NO_SURFACE;
- }
-
- if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
- throw std::runtime_error("eglMakeCurrent() failed");
- }
-
- if (!eglTerminate(display)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglTerminate() returned error %d",
- eglGetError());
- throw std::runtime_error("eglTerminate() failed");
- }
- }
-
- display = EGL_NO_DISPLAY;
- config = nullptr;
- format = -1;
-}
-
-void NativeMapView::initializeContext() {
- assert(display != EGL_NO_DISPLAY);
- assert(context == EGL_NO_CONTEXT);
- assert(config != nullptr);
-
- const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
- context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
- if (context == EGL_NO_CONTEXT) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error %d",
- eglGetError());
- throw std::runtime_error("eglCreateContext() failed");
- }
-}
-
-void NativeMapView::terminateContext() {
- if (display != EGL_NO_DISPLAY) {
-
- if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
- throw std::runtime_error("eglMakeCurrent() failed");
- }
-
- if (context != EGL_NO_CONTEXT) {
- if (!eglDestroyContext(display, context)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroyContext() returned error %d",
- eglGetError());
- throw std::runtime_error("eglDestroyContext() failed");
- }
- }
- }
-
- context = EGL_NO_CONTEXT;
-}
-
-void NativeMapView::createSurface(ANativeWindow *window_) {
- assert(window == nullptr);
- assert(window_ != nullptr);
- window = window_;
-
- assert(display != EGL_NO_DISPLAY);
- assert(surface == EGL_NO_SURFACE);
- assert(config != nullptr);
- assert(format >= 0);
-
- ANativeWindow_setBuffersGeometry(window, 0, 0, format);
-
- const EGLint surfaceAttribs[] = {EGL_NONE};
- surface = eglCreateWindowSurface(display, config, window, surfaceAttribs);
- if (surface == EGL_NO_SURFACE) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateWindowSurface() returned error %d",
- eglGetError());
- throw std::runtime_error("eglCreateWindowSurface() failed");
- }
-
- if (!firstTime) {
- firstTime = true;
-
- BackendScope guard(*this);
-
- if (!eglMakeCurrent(display, surface, surface, context)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d",
- eglGetError());
- throw std::runtime_error("eglMakeCurrent() failed");
- }
-
- mbgl::gl::InitializeExtensions([] (const char * name) {
- return reinterpret_cast<mbgl::gl::glProc>(eglGetProcAddress(name));
- });
- }
-}
-
-void NativeMapView::destroySurface() {
- if (surface != EGL_NO_SURFACE) {
- if (!eglDestroySurface(display, surface)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
- eglGetError());
- throw std::runtime_error("eglDestroySurface() failed");
- }
- }
-
- surface = EGL_NO_SURFACE;
-
- if (window != nullptr) {
- ANativeWindow_release(window);
- window = nullptr;
- }
-}
-
-void NativeMapView::scheduleTakeSnapshot() {
- snapshot = true;
-}
-
-// Speed
-/*
-typedef enum {
- Format16Bit = 0,
- Format32BitNoAlpha = 1,
- Format32BitAlpha = 2,
- Format24Bit = 3,
- Unknown = 4
-} BufferFormat;
-
-typedef enum {
- Format16Depth8Stencil = 0,
- Format24Depth8Stencil = 1,
-} DepthStencilFormat;
-*/
-
// Quality
typedef enum {
Format16Bit = 3,
@@ -589,18 +1089,134 @@ EGLConfig NativeMapView::chooseConfig(const EGLConfig configs[], EGLint numConfi
return configId;
}
-void NativeMapView::notifyMapChange(mbgl::MapChange change) {
- assert(vm != nullptr);
- assert(obj != nullptr);
+void NativeMapView::_terminateDisplay() {
+ if (display != EGL_NO_DISPLAY) {
+ // Destroy the surface first, if it still exists. This call needs a valid surface.
+ if (surface != EGL_NO_SURFACE) {
+ if (!eglDestroySurface(display, surface)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglDestroySurface() failed");
+ }
+ surface = EGL_NO_SURFACE;
+ }
- env->CallVoidMethod(obj, onMapChangedId, change);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
+ if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL,
+ "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
+ throw std::runtime_error("eglMakeCurrent() failed");
+ }
+
+ if (!eglTerminate(display)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglTerminate() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglTerminate() failed");
+ }
}
+
+ display = EGL_NO_DISPLAY;
+ config = nullptr;
+ format = -1;
}
-void NativeMapView::enableFps(bool enable) {
- fpsEnabled = enable;
+void NativeMapView::_initializeContext() {
+ assert(display != EGL_NO_DISPLAY);
+ assert(context == EGL_NO_CONTEXT);
+ assert(config != nullptr);
+
+ const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
+ if (context == EGL_NO_CONTEXT) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglCreateContext() failed");
+ }
+}
+
+void NativeMapView::_terminateContext() {
+ if (display != EGL_NO_DISPLAY) {
+
+ if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL,
+ "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
+ throw std::runtime_error("eglMakeCurrent() failed");
+ }
+
+ if (context != EGL_NO_CONTEXT) {
+ if (!eglDestroyContext(display, context)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroyContext() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglDestroyContext() failed");
+ }
+ }
+ }
+
+ context = EGL_NO_CONTEXT;
+}
+
+void NativeMapView::_createSurface(ANativeWindow *window_) {
+ assert(window == nullptr);
+ assert(window_ != nullptr);
+ window = window_;
+
+ assert(display != EGL_NO_DISPLAY);
+ assert(surface == EGL_NO_SURFACE);
+ assert(config != nullptr);
+ assert(format >= 0);
+
+ ANativeWindow_setBuffersGeometry(window, 0, 0, format);
+
+ const EGLint surfaceAttribs[] = {EGL_NONE};
+ surface = eglCreateWindowSurface(display, config, window, surfaceAttribs);
+ if (surface == EGL_NO_SURFACE) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateWindowSurface() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglCreateWindowSurface() failed");
+ }
+
+ if (firstRender) {
+ firstRender = false;
+
+ BackendScope guard(*this);
+
+ if (!eglMakeCurrent(display, surface, surface, context)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglMakeCurrent() failed");
+ }
+
+ mbgl::gl::InitializeExtensions([] (const char * name) {
+ return reinterpret_cast<mbgl::gl::glProc>(eglGetProcAddress(name));
+ });
+ }
+}
+
+void NativeMapView::_destroySurface() {
+ if (surface != EGL_NO_SURFACE) {
+ if (!eglDestroySurface(display, surface)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglDestroySurface() failed");
+ }
+ }
+
+ surface = EGL_NO_SURFACE;
+
+ if (window != nullptr) {
+ ANativeWindow_release(window);
+ window = nullptr;
+ }
+}
+
+mbgl::Size NativeMapView::getFramebufferSize() const {
+ return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
+}
+
+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::updateFps() {
@@ -618,35 +1234,116 @@ void NativeMapView::updateFps() {
if (currentTime - timeElapsed >= 1) {
fps = frames / ((currentTime - timeElapsed) / 1E9);
- mbgl::Log::Debug(mbgl::Event::Render, "FPS: %4.2f", fps);
+ mbgl::Log::Info(mbgl::Event::Render, "FPS: %4.2f", fps);
timeElapsed = currentTime;
frames = 0;
}
assert(vm != nullptr);
- assert(obj != nullptr);
- env->CallVoidMethod(obj, onFpsChangedId, fps);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- }
-}
-
-void NativeMapView::resizeView(int w, int h) {
- width = w;
- height = h;
- map->setSize({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
-}
-
-void NativeMapView::resizeFramebuffer(int w, int h) {
- fbWidth = w;
- fbHeight = h;
- framebufferSizeChanged = true;
- invalidate();
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onFpsChanged = javaClass.GetMethod<void (double)>(*_env, "onFpsChanged");
+ javaPeer->Call(*_env, onFpsChanged, fps);
}
-void NativeMapView::setInsets(mbgl::EdgeInsets insets_) {
- insets = insets_;
+// Static methods //
+
+jni::Class<NativeMapView> NativeMapView::javaClass;
+
+void NativeMapView::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ NativeMapView::javaClass = *jni::Class<NativeMapView>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<NativeMapView>(env, NativeMapView::javaClass, "nativePtr",
+ std::make_unique<NativeMapView, JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::jfloat, jni::jint, jni::jlong>,
+ "nativeInitialize",
+ "nativeDestroy",
+ METHOD(&NativeMapView::render, "nativeRender"),
+ METHOD(&NativeMapView::update, "nativeUpdate"),
+ METHOD(&NativeMapView::resizeView, "nativeResizeView"),
+ METHOD(&NativeMapView::resizeFramebuffer, "nativeResizeFramebuffer"),
+ METHOD(&NativeMapView::initializeDisplay, "nativeInitializeDisplay"),
+ METHOD(&NativeMapView::terminateDisplay, "nativeTerminateDisplay"),
+ METHOD(&NativeMapView::initializeContext, "nativeInitializeContext"),
+ METHOD(&NativeMapView::terminateContext, "nativeTerminateContext"),
+ METHOD(&NativeMapView::createSurface, "nativeCreateSurface"),
+ METHOD(&NativeMapView::destroySurface, "nativeDestroySurface"),
+ METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"),
+ METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"),
+ METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"),
+ METHOD(&NativeMapView::setStyleJson, "nativeSetStyleJson"),
+ METHOD(&NativeMapView::cancelTransitions, "nativeCancelTransitions"),
+ METHOD(&NativeMapView::setGestureInProgress, "nativeSetGestureInProgress"),
+ METHOD(&NativeMapView::moveBy, "nativeMoveBy"),
+ METHOD(&NativeMapView::jumpTo, "nativeJumpTo"),
+ METHOD(&NativeMapView::easeTo, "nativeEaseTo"),
+ METHOD(&NativeMapView::flyTo, "nativeFlyTo"),
+ METHOD(&NativeMapView::getLatLng, "nativeGetLatLng"),
+ METHOD(&NativeMapView::setLatLng, "nativeSetLatLng"),
+ METHOD(&NativeMapView::setReachability, "nativeSetReachability"),
+ METHOD(&NativeMapView::resetPosition, "nativeResetPosition"),
+ METHOD(&NativeMapView::getPitch, "nativeGetPitch"),
+ METHOD(&NativeMapView::setPitch, "nativeSetPitch"),
+ METHOD(&NativeMapView::scaleBy, "nativeScaleBy"),
+ METHOD(&NativeMapView::getScale, "nativeGetScale"),
+ METHOD(&NativeMapView::setScale, "nativeSetScale"),
+ METHOD(&NativeMapView::getZoom, "nativeGetZoom"),
+ METHOD(&NativeMapView::setZoom, "nativeSetZoom"),
+ METHOD(&NativeMapView::resetZoom, "nativeResetZoom"),
+ METHOD(&NativeMapView::setMinZoom, "nativeSetMinZoom"),
+ METHOD(&NativeMapView::getMinZoom, "nativeGetMinZoom"),
+ METHOD(&NativeMapView::setMaxZoom, "nativeSetMaxZoom"),
+ METHOD(&NativeMapView::getMaxZoom, "nativeGetMaxZoom"),
+ METHOD(&NativeMapView::rotateBy, "nativeRotateBy"),
+ METHOD(&NativeMapView::setBearing, "nativeSetBearing"),
+ METHOD(&NativeMapView::setBearingXY, "nativeSetBearingXY"),
+ METHOD(&NativeMapView::getBearing, "nativeGetBearing"),
+ METHOD(&NativeMapView::resetNorth, "nativeResetNorth"),
+ METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"),
+ METHOD(&NativeMapView::setContentPadding, "nativeSetContentPadding"),
+ METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"),
+ METHOD(&NativeMapView::enableFps, "nativeSetEnableFps"),
+ METHOD(&NativeMapView::getCameraValues, "nativeGetCameraValues"),
+ METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"),
+ METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"),
+ METHOD(&NativeMapView::setDebug, "nativeSetDebug"),
+ METHOD(&NativeMapView::cycleDebugOptions, "nativeCycleDebugOptions"),
+ METHOD(&NativeMapView::getDebug, "nativeGetDebug"),
+ METHOD(&NativeMapView::isFullyLoaded, "nativeIsFullyLoaded"),
+ METHOD(&NativeMapView::onLowMemory, "nativeOnLowMemory"),
+ METHOD(&NativeMapView::getMetersPerPixelAtLatitude, "nativeGetMetersPerPixelAtLatitude"),
+ METHOD(&NativeMapView::projectedMetersForLatLng, "nativeProjectedMetersForLatLng"),
+ METHOD(&NativeMapView::pixelForLatLng, "nativePixelForLatLng"),
+ METHOD(&NativeMapView::latLngForProjectedMeters, "nativeLatLngForProjectedMeters"),
+ METHOD(&NativeMapView::latLngForPixel, "nativeLatLngForPixel"),
+ METHOD(&NativeMapView::addPolylines, "nativeAddPolylines"),
+ METHOD(&NativeMapView::addPolygons, "nativeAddPolygons"),
+ METHOD(&NativeMapView::updatePolyline, "nativeUpdatePolyline"),
+ METHOD(&NativeMapView::updatePolygon, "nativeUpdatePolygon"),
+ METHOD(&NativeMapView::removeAnnotations, "nativeRemoveAnnotations"),
+ METHOD(&NativeMapView::addAnnotationIcon, "nativeAddAnnotationIcon"),
+ METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "nativeGetTopOffsetPixelsForAnnotationSymbol"),
+ METHOD(&NativeMapView::getTransitionDuration, "nativeGetTransitionDuration"),
+ METHOD(&NativeMapView::setTransitionDuration, "nativeSetTransitionDuration"),
+ METHOD(&NativeMapView::getTransitionDelay, "nativeGetTransitionDelay"),
+ METHOD(&NativeMapView::setTransitionDelay, "nativeSetTransitionDelay"),
+ METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"),
+ METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"),
+ METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"),
+ METHOD(&NativeMapView::getLayer, "nativeGetLayer"),
+ METHOD(&NativeMapView::addLayer, "nativeAddLayer"),
+ METHOD(&NativeMapView::removeLayerById, "nativeRemoveLayerById"),
+ METHOD(&NativeMapView::removeLayer, "nativeRemoveLayer"),
+ METHOD(&NativeMapView::getSource, "nativeGetSource"),
+ METHOD(&NativeMapView::addSource, "nativeAddSource"),
+ METHOD(&NativeMapView::removeSourceById, "nativeRemoveSourceById"),
+ METHOD(&NativeMapView::removeSource, "nativeRemoveSource"),
+ METHOD(&NativeMapView::addImage, "nativeAddImage"),
+ METHOD(&NativeMapView::removeImage, "nativeRemoveImage")
+ );
}
}
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index e776b839fc..b8a7a3914c 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -1,71 +1,265 @@
#pragma once
+#include <mbgl/map/backend.hpp>
+#include <mbgl/map/camera.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/map/view.hpp>
-#include <mbgl/map/backend.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/util/run_loop.hpp>
#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/network_status.hpp>
+
+#include "file_source.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 <string>
#include <jni.h>
#include <android/native_window.h>
#include <EGL/egl.h>
+#include <jni/jni.hpp>
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<NativeMapView> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ NativeMapView(jni::JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::jfloat, jni::jint, jni::jlong);
+
virtual ~NativeMapView();
- mbgl::Size getFramebufferSize() const;
- void updateViewBinding();
+ // mbgl::View //
+
void bind() override;
- void invalidate() override;
+ // mbgl::Backend //
+ void invalidate() override;
void notifyMapChange(mbgl::MapChange) override;
- mbgl::Map &getMap();
- mbgl::DefaultFileSource &getFileSource();
+ // JNI //
- void initializeDisplay();
- void terminateDisplay();
+ void destroy(jni::JNIEnv&);
- void initializeContext();
- void terminateContext();
+ void render(jni::JNIEnv&);
- void createSurface(ANativeWindow *window);
- void destroySurface();
+ void update(jni::JNIEnv&);
- void render();
+ void resizeView(jni::JNIEnv&, int, int);
- void enableFps(bool enable);
- void updateFps();
+ void resizeFramebuffer(jni::JNIEnv&, int, int);
+
+ void initializeDisplay(jni::JNIEnv&);
+
+ void terminateDisplay(jni::JNIEnv&);
+
+ void initializeContext(jni::JNIEnv&);
+
+ void terminateContext(jni::JNIEnv&);
+
+ void createSurface(jni::JNIEnv&, jni::Object<>);
+
+ void destroySurface(jni::JNIEnv&);
+
+ jni::String getStyleUrl(jni::JNIEnv&);
+
+ void setStyleUrl(jni::JNIEnv&, jni::String);
+
+ jni::String getStyleJson(jni::JNIEnv&);
+
+ void setStyleJson(jni::JNIEnv&, jni::String);
+
+ void cancelTransitions(jni::JNIEnv&);
+
+ void setGestureInProgress(jni::JNIEnv&, jni::jboolean);
+
+ void moveBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong);
+
+ void jumpTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble);
+
+ void easeTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, jni::jboolean);
+
+ void flyTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble);
+
+ jni::Object<LatLng> getLatLng(JNIEnv&);
+
+ void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong);
+
+ void setReachability(jni::JNIEnv&, jni::jboolean);
+
+ void resetPosition(jni::JNIEnv&);
+
+ jni::jdouble getPitch(jni::JNIEnv&);
+
+ void setPitch(jni::JNIEnv&, jni::jdouble, jni::jlong);
+
+ void scaleBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
+
+ void setScale(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
+
+ jni::jdouble getScale(jni::JNIEnv&);
+
+ void setZoom(jni::JNIEnv&, jni::jdouble, jni::jlong);
+
+ 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, jni::jlong);
+
+ void setBearing(jni::JNIEnv&, jni::jdouble, jni::jlong);
+
+ void setBearingXY(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
+
+ jni::jdouble getBearing(jni::JNIEnv&);
+
+ void resetNorth(jni::JNIEnv&);
+
+ void setVisibleCoordinateBounds(JNIEnv&, jni::Array<jni::Object<LatLng>>, jni::Object<RectF>, jni::jdouble, jni::jlong);
+
+ void setContentPadding(JNIEnv&, double, double, double, double);
+
+ void scheduleSnapshot(jni::JNIEnv&);
+
+ void enableFps(jni::JNIEnv&, jni::jboolean enable);
+
+ jni::Array<jni::jdouble> getCameraValues(jni::JNIEnv&);
+
+ void updateMarker(jni::JNIEnv&, jni::jlong, jni::jdouble, jni::jdouble, jni::String);
+
+ jni::Array<jni::jlong> addMarkers(jni::JNIEnv&, jni::Array<jni::Object<Marker>>);
- void resizeView(int width, int height);
- void resizeFramebuffer(int width, int height);
- mbgl::EdgeInsets getInsets() { return insets;}
- void setInsets(mbgl::EdgeInsets insets_);
+ void onLowMemory(JNIEnv& env);
- void scheduleTakeSnapshot();
+ 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<ProjectedMeters> projectedMetersForLatLng(JNIEnv&, jni::jdouble, jni::jdouble);
+
+ jni::Object<PointF> pixelForLatLng(JNIEnv&, jdouble, jdouble);
+
+ jni::Object<LatLng> latLngForProjectedMeters(JNIEnv&, jdouble, jdouble);
+
+ jni::Object<LatLng> latLngForPixel(JNIEnv&, jfloat, jfloat);
+
+ jni::Array<jlong> addPolylines(JNIEnv&, jni::Array<jni::Object<Polyline>>);
+
+ jni::Array<jlong> addPolygons(JNIEnv&, jni::Array<jni::Object<Polygon>>);
+
+ void updatePolyline(JNIEnv&, jlong, jni::Object<Polyline>);
+
+ void updatePolygon(JNIEnv&, jlong, jni::Object<Polygon>);
+
+ void removeAnnotations(JNIEnv&, jni::Array<jlong>);
+
+ void addAnnotationIcon(JNIEnv&, jni::String, jint, jint, jfloat, jni::Array<jbyte>);
+
+ jni::jdouble getTopOffsetPixelsForAnnotationSymbol(JNIEnv&, jni::String);
+
+ jni::jlong getTransitionDuration(JNIEnv&);
+
+ void setTransitionDuration(JNIEnv&, jni::jlong);
+
+ jni::jlong getTransitionDelay(JNIEnv&);
+
+ void setTransitionDelay(JNIEnv&, jni::jlong);
+
+ jni::Array<jlong> queryPointAnnotations(JNIEnv&, jni::Object<RectF>);
+
+ jni::Array<jni::Object<Feature>> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat, jni::Array<jni::String>);
+
+ jni::Array<jni::Object<Feature>> queryRenderedFeaturesForBox(JNIEnv&, jni::jfloat, jni::jfloat, jni::jfloat, jni::jfloat, jni::Array<jni::String>);
+
+ jni::Object<Layer> getLayer(JNIEnv&, jni::String);
+
+ void addLayer(JNIEnv&, jlong, jni::String);
+
+ void removeLayerById(JNIEnv&, jni::String);
+
+ void removeLayer(JNIEnv&, jlong);
+
+ jni::Object<Source> getSource(JNIEnv&, jni::String);
+
+ void addSource(JNIEnv&, jni::jlong);
+
+ void removeSourceById(JNIEnv&, jni::String);
+
+ void removeSource(JNIEnv&, jlong);
+
+ void addImage(JNIEnv&, jni::String, jni::jint, jni::jint, jni::jfloat, jni::Array<jbyte>);
+
+ void removeImage(JNIEnv&, jni::String);
protected:
+ // mbgl::Backend //
+
void activate() override;
void deactivate() override;
private:
+ void _initializeDisplay();
+
+ void _terminateDisplay();
+
+ void _initializeContext();
+
+ void _terminateContext();
+
+ void _createSurface(ANativeWindow*);
+
+ void _destroySurface();
+
EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs);
+ void updateViewBinding();
+ mbgl::Size getFramebufferSize() const;
+
+ void updateFps();
+
private:
+
JavaVM *vm = nullptr;
- JNIEnv *env = nullptr;
- jweak obj = nullptr;
+ jni::UniqueWeakObject<NativeMapView> javaPeer;
+
+ std::string styleUrl;
+ std::string apiKey;
ANativeWindow *window = nullptr;
+ EGLConfig config = nullptr;
+ EGLint format = -1;
+
EGLDisplay oldDisplay = EGL_NO_DISPLAY;
EGLSurface oldReadSurface = EGL_NO_SURFACE;
EGLSurface oldDrawSurface = EGL_NO_SURFACE;
@@ -75,15 +269,11 @@ private:
EGLSurface surface = EGL_NO_SURFACE;
EGLContext context = EGL_NO_CONTEXT;
- EGLConfig config = nullptr;
- EGLint format = -1;
- std::string styleUrl;
- std::string apiKey;
-
- bool firstTime = false;
+ float pixelRatio;
bool fpsEnabled = false;
bool snapshot = false;
+ bool firstRender = true;
double fps = 0.0;
int width = 0;
@@ -96,12 +286,12 @@ private:
size_t totalMemory = 0;
// Ensure these are initialised last
- mbgl::DefaultFileSource& fileSource;
std::shared_ptr<mbgl::ThreadPool> threadPool;
std::unique_ptr<mbgl::Map> map;
mbgl::EdgeInsets insets;
unsigned active = 0;
};
-}
-}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp
new file mode 100644
index 0000000000..02871e7fdf
--- /dev/null
+++ b/platform/android/src/offline/offline_manager.cpp
@@ -0,0 +1,164 @@
+#include "offline_manager.hpp"
+
+#include <mbgl/util/string.hpp>
+
+#include "../attach_env.hpp"
+#include "../jni/generic_global_ref_deleter.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineManager //
+
+OfflineManager::OfflineManager(jni::JNIEnv& env, jni::Object<FileSource> jFileSource)
+ : fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {
+}
+
+OfflineManager::~OfflineManager() {}
+
+void OfflineManager::setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit) {
+ fileSource.setOfflineMapboxTileCountLimit(limit);
+}
+
+void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, jni::Object<FileSource> jFileSource_, jni::Object<ListOfflineRegionsCallback> callback_) {
+ // list regions
+ fileSource.listOfflineRegions([
+ //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()),
+ jFileSource = std::shared_ptr<jni::jobject>(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) mutable {
+
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineManager::ListOfflineRegionsCallback::onError(*env, jni::Object<ListOfflineRegionsCallback>(*callback), error);
+ } else if (regions) {
+ OfflineManager::ListOfflineRegionsCallback::onList(*env, jni::Object<FileSource>(*jFileSource), jni::Object<ListOfflineRegionsCallback>(*callback), std::move(regions));
+ }
+ });
+}
+
+void OfflineManager::createOfflineRegion(jni::JNIEnv& env_,
+ jni::Object<FileSource> jFileSource_,
+ jni::Object<OfflineRegionDefinition> definition_,
+ jni::Array<jni::jbyte> metadata_,
+ jni::Object<CreateOfflineRegionCallback> callback_) {
+ // Convert
+
+ // XXX hardcoded cast for now as we only support OfflineTilePyramidRegionDefinition
+ auto definition = OfflineTilePyramidRegionDefinition::getDefinition(env_, jni::Object<OfflineTilePyramidRegionDefinition>(*definition_));
+
+ mbgl::OfflineRegionMetadata metadata;
+ if (metadata_) {
+ metadata = OfflineRegion::metadata(env_, metadata_);
+ }
+
+ // Create region
+ fileSource.createOfflineRegion(definition, metadata, [
+ //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()),
+ jFileSource = std::shared_ptr<jni::jobject>(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegion> region) mutable {
+
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineManager::CreateOfflineRegionCallback::onError(*env, jni::Object<CreateOfflineRegionCallback>(*callback), error);
+ } else if (region) {
+ OfflineManager::CreateOfflineRegionCallback::onCreate(
+ *env,
+ jni::Object<FileSource>(*jFileSource),
+ jni::Object<CreateOfflineRegionCallback>(*callback), std::move(region)
+ );
+ }
+ });
+}
+
+jni::Class<OfflineManager> OfflineManager::javaClass;
+
+void OfflineManager::registerNative(jni::JNIEnv& env) {
+ OfflineManager::ListOfflineRegionsCallback::registerNative(env);
+ OfflineManager::CreateOfflineRegionCallback::registerNative(env);
+
+ javaClass = *jni::Class<OfflineManager>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ jni::RegisterNativePeer<OfflineManager>( env, javaClass, "nativePtr",
+ std::make_unique<OfflineManager, JNIEnv&, jni::Object<FileSource>>,
+ "initialize",
+ "finalize",
+ METHOD(&OfflineManager::setOfflineMapboxTileCountLimit, "setOfflineMapboxTileCountLimit"),
+ METHOD(&OfflineManager::listOfflineRegions, "listOfflineRegions"),
+ METHOD(&OfflineManager::createOfflineRegion, "createOfflineRegion"));
+}
+
+// OfflineManager::ListOfflineRegionsCallback //
+
+void OfflineManager::ListOfflineRegionsCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineManager::ListOfflineRegionsCallback::onList(jni::JNIEnv& env,
+ jni::Object<FileSource> jFileSource,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback> callback,
+ mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) {
+ //Convert the regions to java peer objects
+ std::size_t index = 0;
+ auto jregions = jni::Array<jni::Object<OfflineRegion>>::New(env, regions->size(), OfflineRegion::javaClass);
+ for (auto& region : *regions) {
+ auto jregion = OfflineRegion::New(env, jFileSource, std::move(region));
+ jregions.Set(env, index, jregion);
+ jni::DeleteLocalRef(env, jregion);
+ index++;
+ }
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Array<jni::Object<OfflineRegion>>)>(env, "onList");
+ callback.Call(env, method, jregions);
+ jni::DeleteLocalRef(env, jregions);
+}
+
+jni::Class<OfflineManager::ListOfflineRegionsCallback> OfflineManager::ListOfflineRegionsCallback::javaClass;
+
+void OfflineManager::ListOfflineRegionsCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineManager::ListOfflineRegionsCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineManager::CreateOfflineRegionCallback //
+
+void OfflineManager::CreateOfflineRegionCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env,
+ jni::Object<FileSource> jFileSource,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback> callback,
+ mbgl::optional<mbgl::OfflineRegion> region) {
+ //Convert the region to java peer object
+ auto jregion = OfflineRegion::New(env, jFileSource, std::move(*region));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Object<OfflineRegion>)>(env, "onCreate");
+ callback.Call(env, method, jregion);
+ jni::DeleteLocalRef(env, jregion);
+}
+
+jni::Class<OfflineManager::CreateOfflineRegionCallback> OfflineManager::CreateOfflineRegionCallback::javaClass;
+
+void OfflineManager::CreateOfflineRegionCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineManager::CreateOfflineRegionCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_manager.hpp b/platform/android/src/offline/offline_manager.hpp
new file mode 100644
index 0000000000..9ae2714ca2
--- /dev/null
+++ b/platform/android/src/offline/offline_manager.hpp
@@ -0,0 +1,75 @@
+#pragma once
+
+
+#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+#include "../file_source.hpp"
+#include "offline_region.hpp"
+#include "offline_region_definition.hpp"
+
+
+namespace mbgl {
+namespace android {
+
+class OfflineManager {
+public:
+
+ class ListOfflineRegionsCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback";}
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineManager::ListOfflineRegionsCallback>, std::exception_ptr);
+
+ static void onList(jni::JNIEnv&,
+ jni::Object<FileSource>,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback>,
+ mbgl::optional<std::vector<mbgl::OfflineRegion>>);
+
+ static jni::Class<OfflineManager::ListOfflineRegionsCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class CreateOfflineRegionCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback"; }
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineManager::CreateOfflineRegionCallback>, std::exception_ptr);
+
+ static void onCreate(jni::JNIEnv&,
+ jni::Object<FileSource>,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback>,
+ mbgl::optional<mbgl::OfflineRegion>);
+
+ static jni::Class<OfflineManager::CreateOfflineRegionCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager"; };
+
+ static jni::Class<OfflineManager> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ OfflineManager(jni::JNIEnv&, jni::Object<FileSource>);
+ ~OfflineManager();
+
+ void setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit);
+
+ void listOfflineRegions(jni::JNIEnv&, jni::Object<FileSource>, jni::Object<ListOfflineRegionsCallback> callback);
+
+ void createOfflineRegion(jni::JNIEnv&,
+ jni::Object<FileSource> jFileSource_,
+ jni::Object<OfflineRegionDefinition> definition,
+ jni::Array<jni::jbyte> metadata,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback> callback);
+
+private:
+ mbgl::DefaultFileSource& fileSource;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp
new file mode 100644
index 0000000000..856434d266
--- /dev/null
+++ b/platform/android/src/offline/offline_region.cpp
@@ -0,0 +1,308 @@
+#include "offline_region.hpp"
+
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/string.hpp>
+
+#include "offline_region_definition.hpp"
+#include "offline_region_error.hpp"
+#include "offline_region_status.hpp"
+#include "../attach_env.hpp"
+#include "../jni/generic_global_ref_deleter.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineRegion //
+
+OfflineRegion::OfflineRegion(jni::JNIEnv& env, jni::jlong offlineRegionPtr, jni::Object<FileSource> jFileSource)
+ : region(reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr)),
+ fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {}
+
+OfflineRegion::~OfflineRegion() {}
+
+void OfflineRegion::setOfflineRegionObserver(jni::JNIEnv& env_, jni::Object<OfflineRegion::OfflineRegionObserver> callback) {
+
+ // Define the observer
+ class Observer : public mbgl::OfflineRegionObserver {
+ public:
+ Observer(jni::UniqueObject<OfflineRegion::OfflineRegionObserver>&& callback_)
+ //TODO add a generic deleter for jni::Object
+ : callback(callback_.release()->Get()) {
+ }
+
+ ~Observer() override {
+ android::UniqueEnv env = android::AttachEnv();
+ env->DeleteGlobalRef(Unwrap(*callback));
+ }
+
+ void statusChanged(mbgl::OfflineRegionStatus status) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Status object
+ auto jStatus = OfflineRegionStatus::New(*env, status);
+
+ // Call
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::Object<OfflineRegionStatus>)>(*env, "onStatusChanged");
+ callback.Call(*env, method, jStatus);
+
+ // Delete references
+ jni::DeleteLocalRef(*env, jStatus);
+ }
+
+ void responseError(mbgl::Response::Error error) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Error object
+ auto jError = OfflineRegionError::New(*env, error);
+
+ // Call
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::Object<mbgl::android::OfflineRegionError>)>(*env, "onError");
+ callback.Call(*env, method, jError);
+
+ // Delete references
+ jni::DeleteLocalRef(*env, jError);
+ }
+
+ void mapboxTileCountLimitExceeded(uint64_t limit) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Send limit
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::jlong)>(*env, "mapboxTileCountLimitExceeded");
+ callback.Call(*env, method, jlong(limit));
+ }
+
+ jni::Object<OfflineRegion::OfflineRegionObserver> callback;
+ };
+
+ // Set the observer
+ fileSource.setOfflineRegionObserver(*region, std::make_unique<Observer>(callback.NewGlobalRef(env_)));
+}
+
+void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState) {
+ // State
+ mbgl::OfflineRegionDownloadState state;
+ switch (jState) {
+ case 0:
+ state = mbgl::OfflineRegionDownloadState::Inactive;
+ break;
+ case 1:
+ state = mbgl::OfflineRegionDownloadState::Active;
+ break;
+ default:
+ mbgl::Log::Error(mbgl::Event::JNI, "State can only be 0 (inactive) or 1 (active).");
+ return;
+ }
+
+ fileSource.setOfflineRegionDownloadState(*region, state);
+}
+
+void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, jni::Object<OfflineRegionStatusCallback> callback_) {
+
+ fileSource.getOfflineRegionStatus(*region, [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionStatus> status) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionStatusCallback::onError(*env, jni::Object<OfflineRegionStatusCallback>(*callback), error);
+ } else if (status) {
+ OfflineRegionStatusCallback::onStatus(*env, jni::Object<OfflineRegionStatusCallback>(*callback), std::move(status));
+ }
+ });
+}
+
+void OfflineRegion::deleteOfflineRegion(jni::JNIEnv& env_, jni::Object<OfflineRegionDeleteCallback> callback_) {
+ // Delete
+ fileSource.deleteOfflineRegion(std::move(*region), [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionDeleteCallback::onError(*env, jni::Object<OfflineRegionDeleteCallback>(*callback), error);
+ } else {
+ OfflineRegionDeleteCallback::onDelete(*env, jni::Object<OfflineRegionDeleteCallback>(*callback));
+ }
+ });
+}
+
+void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, jni::Array<jni::jbyte> jMetadata, jni::Object<OfflineRegionUpdateMetadataCallback> callback_) {
+
+ // Convert
+ auto metadata = OfflineRegion::metadata(env_, jMetadata);
+
+ fileSource.updateOfflineMetadata(region->getID(), metadata, [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionMetadata> data) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionUpdateMetadataCallback::onError(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), error);
+ } else if (data) {
+ OfflineRegionUpdateMetadataCallback::onUpdate(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), std::move(data));
+ }
+ });
+}
+
+jni::Object<OfflineRegion> OfflineRegion::New(jni::JNIEnv& env, jni::Object<FileSource> jFileSource, mbgl::OfflineRegion region) {
+
+ // Definition
+ auto definition = jni::Object<OfflineRegionDefinition>(*OfflineTilePyramidRegionDefinition::New(env, region.getDefinition()));
+
+ // Metadata
+ auto metadata = OfflineRegion::metadata(env, region.getMetadata());
+
+ // Create region java object
+ static auto constructor = OfflineRegion::javaClass.GetConstructor<jni::jlong, jni::Object<FileSource>, jni::jlong, jni::Object<OfflineRegionDefinition>, jni::Array<jni::jbyte>>(env);
+ auto jregion = OfflineRegion::javaClass.New(env, constructor,
+ reinterpret_cast<jni::jlong>(new mbgl::OfflineRegion(std::move(region))), //Copy a region to the heap
+ jFileSource, jni::jlong(region.getID()), definition, metadata);
+
+ //Delete references
+ jni::DeleteLocalRef(env, definition);
+ jni::DeleteLocalRef(env, metadata);
+
+ return jregion;
+}
+
+jni::Array<jni::jbyte> OfflineRegion::metadata(jni::JNIEnv& env, mbgl::OfflineRegionMetadata metadata_) {
+ std::vector<jni::jbyte> convertedMetadata(metadata_.begin(), metadata_.end());
+ std::size_t length = static_cast<std::size_t>(convertedMetadata.size());
+ auto metadata = jni::Array<jni::jbyte>::New(env, length);
+ metadata.SetRegion<std::vector<jni::jbyte>>(env, 0, convertedMetadata);
+ return metadata;
+}
+
+mbgl::OfflineRegionMetadata OfflineRegion::metadata(jni::JNIEnv& env, jni::Array<jni::jbyte> metadata_) {
+ std::size_t length = metadata_.Length(env);
+ auto metadata_tmp = std::vector<jni::jbyte>();
+ metadata_tmp.resize(length);
+ metadata_.GetRegion<std::vector<jni::jbyte>>(env, 0, metadata_tmp);
+ auto metadata = std::vector<uint8_t>(metadata_tmp.begin(), metadata_tmp.end());
+ return metadata;
+}
+
+jni::Class<OfflineRegion> OfflineRegion::javaClass;
+
+void OfflineRegion::registerNative(jni::JNIEnv& env) {
+ OfflineRegion::OfflineRegionObserver::registerNative(env);
+ OfflineRegion::OfflineRegionStatusCallback::registerNative(env);
+ OfflineRegion::OfflineRegionDeleteCallback::registerNative(env);
+ OfflineRegion::OfflineRegionUpdateMetadataCallback::registerNative(env);
+
+ javaClass = *jni::Class<OfflineRegion>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ jni::RegisterNativePeer<OfflineRegion>( env, javaClass, "nativePtr",
+ std::make_unique<OfflineRegion, JNIEnv&, jni::jlong, jni::Object<FileSource>>,
+ "initialize",
+ "finalize",
+ METHOD(&OfflineRegion::setOfflineRegionObserver, "setOfflineRegionObserver"),
+ METHOD(&OfflineRegion::setOfflineRegionDownloadState, "setOfflineRegionDownloadState"),
+ METHOD(&OfflineRegion::getOfflineRegionStatus, "getOfflineRegionStatus"),
+ METHOD(&OfflineRegion::deleteOfflineRegion, "deleteOfflineRegion"),
+ METHOD(&OfflineRegion::updateOfflineRegionMetadata, "updateOfflineRegionMetadata")
+ );
+}
+
+// OfflineRegionObserver //
+
+jni::Class<OfflineRegion::OfflineRegionObserver> OfflineRegion::OfflineRegionObserver::javaClass;
+
+void OfflineRegion::OfflineRegionObserver::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegion::OfflineRegionObserver>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineRegionStatusCallback //
+
+jni::Class<OfflineRegion::OfflineRegionStatusCallback> OfflineRegion::OfflineRegionStatusCallback::javaClass;
+
+void OfflineRegion::OfflineRegionStatusCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionStatusCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionStatusCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionStatusCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineRegion::OfflineRegionStatusCallback::onStatus(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionStatusCallback> callback,
+ mbgl::optional<mbgl::OfflineRegionStatus> status) {
+ //Convert to java peer object
+ auto jStatus = OfflineRegionStatus::New(env, std::move(*status));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Object<OfflineRegionStatus>)>(env, "onStatus");
+ callback.Call(env, method, jStatus);
+ jni::DeleteLocalRef(env, jStatus);
+}
+
+// OfflineRegionDeleteCallback //
+
+jni::Class<OfflineRegion::OfflineRegionDeleteCallback> OfflineRegion::OfflineRegionDeleteCallback::javaClass;
+
+void OfflineRegion::OfflineRegionDeleteCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionDeleteCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionDeleteCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionDeleteCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineRegion::OfflineRegionDeleteCallback::onDelete(jni::JNIEnv& env, jni::Object<OfflineRegion::OfflineRegionDeleteCallback> callback) {
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void ()>(env, "onDelete");
+ callback.Call(env, method);
+}
+
+// OfflineRegionUpdateMetadataCallback //
+
+jni::Class<OfflineRegion::OfflineRegionUpdateMetadataCallback> OfflineRegion::OfflineRegionUpdateMetadataCallback::javaClass;
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionUpdateMetadataCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionUpdateMetadataCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::onUpdate(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionUpdateMetadataCallback> callback,
+ mbgl::optional<mbgl::OfflineRegionMetadata> metadata) {
+ //Convert to java peer object
+ auto jMetadata = OfflineRegion::metadata(env, std::move(*metadata));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Array<jni::jbyte>)>(env, "onUpdate");
+ callback.Call(env, method, jMetadata);
+ jni::DeleteLocalRef(env, jMetadata);
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region.hpp b/platform/android/src/offline/offline_region.hpp
new file mode 100644
index 0000000000..c05383a91a
--- /dev/null
+++ b/platform/android/src/offline/offline_region.hpp
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+#include "../file_source.hpp"
+
+#include <memory>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegion {
+public:
+ class OfflineRegionObserver {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver"; };
+
+ static jni::Class<OfflineRegionObserver> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionStatusCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionStatusCallback>, std::exception_ptr);
+
+ static void onStatus(jni::JNIEnv&,
+ jni::Object<OfflineRegionStatusCallback>,
+ mbgl::optional<mbgl::OfflineRegionStatus>);
+
+ static jni::Class<OfflineRegionStatusCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionDeleteCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>, std::exception_ptr);
+
+ static void onDelete(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>);
+
+ static jni::Class<OfflineRegionDeleteCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionUpdateMetadataCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionUpdateMetadataCallback>, std::exception_ptr);
+
+ static void onUpdate(jni::JNIEnv&,
+ jni::Object<OfflineRegionUpdateMetadataCallback>,
+ mbgl::optional<mbgl::OfflineRegionMetadata>);
+
+ static jni::Class<OfflineRegionUpdateMetadataCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion"; };
+
+ OfflineRegion(jni::JNIEnv&, jni::jlong, jni::Object<FileSource>);
+
+ ~OfflineRegion();
+
+ void setOfflineRegionObserver(jni::JNIEnv&, jni::Object<OfflineRegion::OfflineRegionObserver>);
+
+ void setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint);
+
+ void getOfflineRegionStatus(jni::JNIEnv&, jni::Object<OfflineRegion::OfflineRegionStatusCallback>);
+
+ void deleteOfflineRegion(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>);
+
+ void updateOfflineRegionMetadata(jni::JNIEnv&, jni::Array<jni::jbyte>, jni::Object<OfflineRegionUpdateMetadataCallback>);
+
+ static jni::Object<OfflineRegion> New(jni::JNIEnv&, jni::Object<FileSource>, mbgl::OfflineRegion);
+
+ static jni::Array<jni::jbyte> metadata(jni::JNIEnv&, mbgl::OfflineRegionMetadata);
+
+ static mbgl::OfflineRegionMetadata metadata(jni::JNIEnv&, jni::Array<jni::jbyte>);
+
+ static jni::Class<OfflineRegion> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+ std::unique_ptr<mbgl::OfflineRegion> region;
+ mbgl::DefaultFileSource& fileSource;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_definition.cpp b/platform/android/src/offline/offline_region_definition.cpp
new file mode 100644
index 0000000000..66a9bdf99d
--- /dev/null
+++ b/platform/android/src/offline/offline_region_definition.cpp
@@ -0,0 +1,69 @@
+#include "offline_region_definition.hpp"
+
+#include "../geometry/lat_lng_bounds.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineRegionDefinition //
+
+jni::Class<OfflineRegionDefinition> OfflineRegionDefinition::javaClass;
+
+void OfflineRegionDefinition::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionDefinition>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineTilePyramidRegionDefinition //
+
+jni::Object<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, mbgl::OfflineTilePyramidRegionDefinition definition) {
+
+ //Convert objects
+ auto styleURL = jni::Make<jni::String>(env, definition.styleURL);
+ auto bounds = LatLngBounds::New(env, definition.bounds);
+
+ static auto constructor = javaClass.GetConstructor<jni::String, jni::Object<LatLngBounds>, jni::jdouble, jni::jdouble, jni::jfloat>(env);
+ auto jdefinition = javaClass.New(env, constructor, styleURL, bounds, definition.minZoom, definition.maxZoom, definition.pixelRatio);
+
+ //Delete References
+ jni::DeleteLocalRef(env, styleURL);
+ jni::DeleteLocalRef(env, bounds);
+
+ return jdefinition;
+}
+
+mbgl::OfflineTilePyramidRegionDefinition OfflineTilePyramidRegionDefinition::getDefinition(jni::JNIEnv& env, jni::Object<OfflineTilePyramidRegionDefinition> jDefinition) {
+ // Field references
+ static auto styleURLF = javaClass.GetField<jni::String>(env, "styleURL");
+ static auto boundsF = javaClass.GetField<jni::Object<LatLngBounds>>(env, "bounds");
+ static auto minZoomF = javaClass.GetField<jni::jdouble>(env, "minZoom");
+ static auto maxZoomF = javaClass.GetField<jni::jdouble>(env, "maxZoom");
+ static auto pixelRatioF = javaClass.GetField<jni::jfloat>(env, "pixelRatio");
+
+ // Get objects
+ auto jStyleURL = jDefinition.Get(env, styleURLF);
+ auto jBounds = jDefinition.Get(env, boundsF);
+
+ // Create definition
+ mbgl::OfflineTilePyramidRegionDefinition definition(
+ jni::Make<std::string>(env, jStyleURL),
+ LatLngBounds::getLatLngBounds(env, jBounds),
+ jDefinition.Get(env, minZoomF),
+ jDefinition.Get(env, maxZoomF),
+ jDefinition.Get(env, pixelRatioF)
+ );
+
+ // Delete references
+ jni::DeleteLocalRef(env, jStyleURL);
+ jni::DeleteLocalRef(env, jBounds);
+
+ return definition;
+}
+
+jni::Class<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::javaClass;
+
+void OfflineTilePyramidRegionDefinition::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineTilePyramidRegionDefinition>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_definition.hpp b/platform/android/src/offline/offline_region_definition.hpp
new file mode 100644
index 0000000000..2ca82a4d96
--- /dev/null
+++ b/platform/android/src/offline/offline_region_definition.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionDefinition {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionDefinition"; };
+
+ static jni::Class<OfflineRegionDefinition> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+class OfflineTilePyramidRegionDefinition: public OfflineRegionDefinition {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition"; };
+
+ static jni::Object<OfflineTilePyramidRegionDefinition> New(jni::JNIEnv&, mbgl::OfflineTilePyramidRegionDefinition);
+
+ static mbgl::OfflineTilePyramidRegionDefinition getDefinition(jni::JNIEnv&, jni::Object<OfflineTilePyramidRegionDefinition>);
+
+ static jni::Class<OfflineTilePyramidRegionDefinition> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_error.cpp b/platform/android/src/offline/offline_region_error.cpp
new file mode 100644
index 0000000000..b0a19f934f
--- /dev/null
+++ b/platform/android/src/offline/offline_region_error.cpp
@@ -0,0 +1,53 @@
+#include "offline_region_error.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<OfflineRegionError> OfflineRegionError::New(jni::JNIEnv& env, mbgl::Response::Error error) {
+
+ // Handle the value of reason independently of the underlying int value
+ std::string reason;
+ switch(error.reason) {
+ case mbgl::Response::Error::Reason::Success:
+ reason = "REASON_SUCCESS";
+ break;
+ case mbgl::Response::Error::Reason::NotFound:
+ reason = "REASON_NOT_FOUND";
+ break;
+ case mbgl::Response::Error::Reason::Server:
+ reason = "REASON_SERVER";
+ break;
+ case mbgl::Response::Error::Reason::Connection:
+ reason = "REASON_CONNECTION";
+ break;
+ case mbgl::Response::Error::Reason::RateLimit:
+ reason = "REASON_RATE_LIMIT";
+ break;
+ case mbgl::Response::Error::Reason::Other:
+ reason = "REASON_OTHER";
+ break;
+ }
+
+ // Convert
+ auto jReason = jni::Make<jni::String>(env, reason);
+ auto jMessage = jni::Make<jni::String>(env, error.message);
+
+ // Create java object
+ static auto constructor = javaClass.GetConstructor<jni::String, jni::String>(env);
+ auto jError = javaClass.New(env, constructor, jReason, jMessage);
+
+ // Delete references
+ jni::DeleteLocalRef(env, jReason);
+ jni::DeleteLocalRef(env, jMessage);
+
+ return jError;
+}
+
+jni::Class<OfflineRegionError> OfflineRegionError::javaClass;
+
+void OfflineRegionError::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionError>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_error.hpp b/platform/android/src/offline/offline_region_error.hpp
new file mode 100644
index 0000000000..61efaca67e
--- /dev/null
+++ b/platform/android/src/offline/offline_region_error.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionError {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionError"; };
+
+ static jni::Object<OfflineRegionError> New(jni::JNIEnv&, mbgl::Response::Error);
+
+ static jni::Class<OfflineRegionError> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_status.cpp b/platform/android/src/offline/offline_region_status.cpp
new file mode 100644
index 0000000000..d0bbae124f
--- /dev/null
+++ b/platform/android/src/offline/offline_region_status.cpp
@@ -0,0 +1,39 @@
+#include "offline_region_status.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<OfflineRegionStatus> OfflineRegionStatus::New(jni::JNIEnv& env, mbgl::OfflineRegionStatus status) {
+
+ // Convert to jint
+ jint downloadState;
+ switch(status.downloadState) {
+ case mbgl::OfflineRegionDownloadState::Inactive:
+ downloadState = 0;
+ break;
+ case mbgl::OfflineRegionDownloadState::Active:
+ downloadState = 1;
+ break;
+ }
+
+ // Create java object
+ static auto constructor = javaClass.GetConstructor<jint, jlong, jlong, jlong, jlong, jlong, jboolean>(env);
+ return javaClass.New(env, constructor,
+ downloadState,
+ jlong(status.completedResourceCount),
+ jlong(status.completedResourceSize),
+ jlong(status.completedTileCount),
+ jlong(status.completedTileSize),
+ jlong(status.requiredResourceCount),
+ jboolean(status.requiredResourceCountIsPrecise)
+ );
+}
+
+jni::Class<OfflineRegionStatus> OfflineRegionStatus::javaClass;
+
+void OfflineRegionStatus::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionStatus>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_status.hpp b/platform/android/src/offline/offline_region_status.hpp
new file mode 100644
index 0000000000..b29a653655
--- /dev/null
+++ b/platform/android/src/offline/offline_region_status.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionStatus {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionStatus"; };
+
+ static jni::Object<OfflineRegionStatus> New(jni::JNIEnv&, mbgl::OfflineRegionStatus status);
+
+ static jni::Class<OfflineRegionStatus> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl
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 <mbgl/util/logging.hpp>
#include <mbgl/style/conversion.hpp>
-#include <mbgl/util/feature.hpp>
#include <mbgl/util/optional.hpp>
#include <jni/jni.hpp>