diff options
author | Ivo van Dongen <ivovandongen@users.noreply.github.com> | 2016-09-21 11:04:32 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-09-21 11:04:32 +0200 |
commit | eb97dbe383ca7697feab5860995b97181c39c607 (patch) | |
tree | 70bdd7b6ebea32aec132413fa703e92a2a0f63d0 | |
parent | 3b546b964609d0f596dac32e155b1489bb85645e (diff) | |
download | qtlocation-mapboxgl-eb97dbe383ca7697feab5860995b97181c39c607.tar.gz |
[android] Sources: peer model, mutability (#6054)
24 files changed, 886 insertions, 87 deletions
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 a97395695d..d99800863e 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 @@ -152,6 +152,31 @@ public class MapboxMap { getMapView().getNativeMapView().removeLayer(layerId); } + @Nullable + @UiThread + public Source getSource(@NonNull String sourceId) { + return getMapView().getNativeMapView().getSource(sourceId); + } + + /** + * Tries to cast the Source to T, returns null if it's another type. + * + * @param sourceId the id used to look up a layer + * @param <T> the generic type of a Source + * @return the casted Source, null if another type + */ + @Nullable + @UiThread + public <T extends Source> T getSourceAs(@NonNull String sourceId) { + try { + //noinspection unchecked + return (T) getMapView().getNativeMapView().getSource(sourceId); + } catch (ClassCastException e) { + Log.e(TAG, String.format("Source: %s is a different type: %s", sourceId, e.getMessage())); + return null; + } + } + @UiThread public void addSource(@NonNull Source source) { getMapView().getNativeMapView().addSource(source); 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 0750c987ea..30aa7c3199 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 @@ -494,8 +494,12 @@ final class NativeMapView { nativeRemoveLayer(nativeMapViewPtr, layerId); } + public Source getSource(@NonNull String sourceId) { + return nativeGetSource(nativeMapViewPtr, sourceId); + } + public void addSource(@NonNull Source source) { - nativeAddSource(nativeMapViewPtr, source.getId(), source); + nativeAddSource(nativeMapViewPtr, source.getNativePtr()); } public void removeSource(@NonNull String sourceId) throws NoSuchSourceException { @@ -712,7 +716,9 @@ final class NativeMapView { private native void nativeRemoveLayer(long nativeMapViewPtr, String layerId) throws NoSuchLayerException; - private native void nativeAddSource(long nativeMapViewPtr, String id, Source source); + private native Source nativeGetSource(long nativeMapViewPtr, String sourceId); + + private native void nativeAddSource(long nativeMapViewPtr, long nativeSourcePtr); private native void nativeRemoveSource(long nativeMapViewPtr, String sourceId) throws NoSuchSourceException; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java new file mode 100644 index 0000000000..d7a9282371 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java @@ -0,0 +1,63 @@ +package com.mapbox.mapboxsdk.style.sources; + +import java.util.HashMap; + +/** + * Options for the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">GeoJsonSource</a> + */ +public class GeoJsonOptions extends HashMap<String, Object> { + + /** + * Defaults to 18. + * Maximum zoom level at which to create vector tiles (higher means greater detail at high zoom levels). + */ + public GeoJsonOptions withMaxZoom(int maxZoom) { + this.put("maxzoom", maxZoom); + return this; + } + + /** + * Defaults to 128. + * Tile buffer size on each side (measured in 1/512ths of a tile; higher means fewer rendering artifacts near tile edges but slower performance). + */ + public GeoJsonOptions withBuffer(int buffer) { + this.put("buffer", buffer); + return this; + } + + /** + * Defaults to 0.375. + * Douglas-Peucker simplification tolerance (higher means simpler geometries and faster performance). + */ + public GeoJsonOptions withTolerance(float tolerance) { + this.put("tolerance", tolerance); + return this; + } + + /** + * Defaults to false. + * If the data is a collection of point features, setting this to true clusters the points by radius into groups. + */ + public GeoJsonOptions withCluster(boolean cluster) { + this.put("cluster", cluster); + return this; + } + + /** + * Defaults to 50. + * Radius of each cluster when clustering points, measured in 1/512ths of a tile. + */ + public GeoJsonOptions withClusterMaxZoom(int clusterMaxZoom) { + this.put("clusterMaxZoom", clusterMaxZoom); + return this; + } + + /** + * Max zoom to cluster points on. Defaults to one zoom less than maxzoom (so that last zoom features are not clustered). + */ + public GeoJsonOptions withClusterRadius(int clusterRadius) { + this.put("clusterRadius", clusterRadius); + return this; + } + +} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java index fd226a0060..a66e0a4adc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java @@ -1,9 +1,10 @@ package com.mapbox.mapboxsdk.style.sources; -import com.google.gson.Gson; +import com.mapbox.services.commons.geojson.Feature; import com.mapbox.services.commons.geojson.FeatureCollection; import java.net.URL; +import java.util.ArrayList; import java.util.HashMap; /** @@ -12,8 +13,34 @@ import java.util.HashMap; * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson">the style specification</a> */ public class GeoJsonSource extends Source { - public static final String TYPE = "geojson"; - private static final String DATA_KEY = "data"; + + /** + * Internal use + */ + public GeoJsonSource(long nativePtr) { + super(nativePtr); + } + + /** + * Create an empty GeoJsonSource + * + * @param id the source id + */ + public GeoJsonSource(String id) { + initialize(id, null); + setGeoJson(FeatureCollection.fromFeatures(new ArrayList<Feature>())); + } + + /** + * Create an empty GeoJsonSource + * + * @param id the source id + * @param options options + */ + public GeoJsonSource(String id, GeoJsonOptions options) { + initialize(id, options); + setGeoJson(FeatureCollection.fromFeatures(new ArrayList<Feature>())); + } /** * Create a GeoJsonSource from a raw json string @@ -22,11 +49,26 @@ public class GeoJsonSource extends Source { * @param geoJson raw Json body */ public GeoJsonSource(String id, String geoJson) { - super(id, TYPE); if (geoJson == null || geoJson.startsWith("http")) { throw new IllegalArgumentException("Expected a raw json body"); } - setRawJson(geoJson); + initialize(id, null); + setGeoJson(geoJson); + } + + /** + * Create a GeoJsonSource from a raw json string + * + * @param id the source id + * @param geoJson raw Json body + * @param options options + */ + public GeoJsonSource(String id, String geoJson, GeoJsonOptions options) { + if (geoJson == null || geoJson.startsWith("http")) { + throw new IllegalArgumentException("Expected a raw json body"); + } + initialize(id, options); + setGeoJson(geoJson); } /** @@ -36,8 +78,20 @@ public class GeoJsonSource extends Source { * @param url remote json file */ public GeoJsonSource(String id, URL url) { - super(id, TYPE); - this.put(DATA_KEY, url.toExternalForm()); + initialize(id, null); + nativeSetUrl(url.toExternalForm()); + } + + /** + * Create a GeoJsonSource from a remote geo json file + * + * @param id the source id + * @param url remote json file + * @param options options + */ + public GeoJsonSource(String id, URL url, GeoJsonOptions options) { + initialize(id, options); + nativeSetUrl(url.toExternalForm()); } /** @@ -47,30 +101,57 @@ public class GeoJsonSource extends Source { * @param features the features */ public GeoJsonSource(String id, FeatureCollection features) { - super(id, TYPE); - setRawJson(features.toJson()); + initialize(id, null); + setGeoJson(features); + } + + /** + * Create a GeoJsonSource from a FeatureCollection + * + * @param id the source id + * @param features the features + * @param options options + */ + public GeoJsonSource(String id, FeatureCollection features, GeoJsonOptions options) { + initialize(id, options); + setGeoJson(features); + } + + public void setGeoJson(FeatureCollection features) { + checkValidity(); + setGeoJson(features.toJson()); } - public GeoJsonSource withCluster(boolean cluster) { - this.put("cluster", cluster); - return this; + public void setGeoJson(String json) { + checkValidity(); + setRawJson(json); } - public GeoJsonSource withClusterMaxZoom(float zoom) { - this.put("clusterMaxZoom", zoom); - return this; + public void setUrl(URL url) { + checkValidity(); + setUrl(url.toExternalForm()); } - public GeoJsonSource withClusterRadius(float radius) { - this.put("clusterRadius", radius); - return this; + public void setUrl(String url) { + checkValidity(); + nativeSetUrl(url); } - private void setRawJson(String geoJson) { + protected void setRawJson(String geoJson) { //Wrap the String in a map as an Object is expected by the //style conversion template HashMap<String, String> wrapper = new HashMap<>(); - wrapper.put(DATA_KEY, geoJson); - this.put(DATA_KEY, wrapper); + wrapper.put("data", geoJson); + nativeSetGeoJson(wrapper); } + + protected native void initialize(String layerId, Object options); + + protected native void nativeSetUrl(String url); + + private native void nativeSetGeoJson(Object geoJson); + + @Override + protected native void finalize() throws Throwable; + } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java index f5db6f2a37..14bd8bb9ed 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java @@ -8,26 +8,37 @@ import java.net.URL; * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-raster">The style specificition</a> */ public class RasterSource extends Source { - public static final String TYPE = "raster"; - private static final String URL_KEY = "url"; - private static final String TILE_SIZE_KEY = "tileSize"; + public static final int DEFAULT_TILE_SIZE = 512; + + /** + * Internal use + */ + public RasterSource(long nativePtr) { + super(nativePtr); + } public RasterSource(String id, URL url) { this(id, url.toExternalForm()); } public RasterSource(String id, String url) { - super(id, TYPE); - this.put(URL_KEY, url); + initialize(id, url, DEFAULT_TILE_SIZE); + } + + public RasterSource(String id, String url, int tileSize) { + initialize(id, url, tileSize); } public RasterSource(String id, TileSet tileSet) { - super(id, TYPE); - this.putAll(tileSet.toValueObject()); + initialize(id, tileSet.toValueObject(), DEFAULT_TILE_SIZE); } - public RasterSource withTileSize(int tileSize) { - this.put(TILE_SIZE_KEY, (float) tileSize); - return this; + public RasterSource(String id, TileSet tileSet, int tileSize) { + initialize(id, tileSet.toValueObject(), tileSize); } + + protected native void initialize(String layerId, Object payload, int tileSize); + + @Override + protected native void finalize() throws Throwable; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java index d9aacdc80d..58ffa12e35 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java @@ -2,15 +2,38 @@ package com.mapbox.mapboxsdk.style.sources; import java.util.HashMap; -public abstract class Source extends HashMap<String, Object> { - private final String id; +/** + * Base Peer class for sources. see source.hpp for the other half of the peer. + */ +public abstract class Source { + private long nativePtr; + private boolean invalidated; - protected Source(String id, String type) { - this.put("type", type); - this.id = id; + public Source(long nativePtr) { + this.nativePtr = nativePtr; + } + + public Source() { } public String getId() { - return id; + checkValidity(); + return nativeGetId(); + } + + public long getNativePtr() { + return nativePtr; + } + + protected native String nativeGetId(); + + protected void checkValidity() { + if (invalidated) { + throw new RuntimeException("Layer has been invalidated. Request a new reference after adding"); + } + } + + public final void invalidate() { + this.invalidated = true; } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java index 381294083a..a9c191f96a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java @@ -8,8 +8,13 @@ import java.net.URL; * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-vector">the style specification</a> */ public class VectorSource extends Source { - public static final String TYPE = "vector"; - private static final String URL_KEY = "url"; + + /** + * Internal use + */ + public VectorSource(long nativePtr) { + super(nativePtr); + } /** * Create a vector source from a remote url @@ -28,8 +33,7 @@ public class VectorSource extends Source { * @param url the url */ public VectorSource(String id, String url) { - super(id, TYPE); - this.put(URL_KEY, url); + initialize(id, url); } /** @@ -39,7 +43,11 @@ public class VectorSource extends Source { * @param tileSet the tileset */ public VectorSource(String id, TileSet tileSet) { - super(id, TYPE); - this.putAll(tileSet.toValueObject()); + initialize(id, tileSet.toValueObject()); } + + protected native void initialize(String layerId, Object payload); + + @Override + protected native void finalize() throws Throwable; } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java index ca4460eac2..9d13ee165d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java @@ -16,6 +16,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.style.layers.CircleLayer; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; +import com.mapbox.mapboxsdk.style.sources.GeoJsonOptions; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import com.mapbox.mapboxsdk.testapp.R; @@ -110,10 +111,13 @@ public class GeoJsonClusteringActivity extends AppCompatActivity { //Add a clustered source try { mapboxMap.addSource( - new GeoJsonSource("earthquakes", new URL("https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson")) - .withCluster(true) - .withClusterMaxZoom(14) - .withClusterRadius(50) + new GeoJsonSource("earthquakes", + new URL("https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson"), + new GeoJsonOptions() + .withCluster(true) + .withClusterMaxZoom(14) + .withClusterRadius(50) + ) ); } catch (MalformedURLException malformedUrlException) { Log.e(TAG, "That's not an url... " + malformedUrlException.getMessage()); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java index d8a82168fd..84467b3aee 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java @@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.style; import android.graphics.Color; import android.os.Bundle; +import android.os.Handler; import android.support.annotation.RawRes; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; @@ -30,6 +31,8 @@ import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.mapboxsdk.style.sources.TileSet; import com.mapbox.mapboxsdk.style.sources.VectorSource; import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.services.commons.geojson.Feature; +import com.mapbox.services.commons.geojson.FeatureCollection; import java.io.BufferedReader; import java.io.IOException; @@ -38,6 +41,8 @@ import java.io.InputStreamReader; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; +import java.util.ArrayList; +import java.util.List; import static com.mapbox.mapboxsdk.style.layers.Filter.all; import static com.mapbox.mapboxsdk.style.layers.Filter.eq; @@ -154,6 +159,9 @@ public class RuntimeStyleActivity extends AppCompatActivity { case R.id.action_add_parks_layer: addParksLayer(); return true; + case R.id.action_add_dynamic_parks_layer: + addDynamicParksLayer(); + return true; case R.id.action_add_terrain_layer: addTerrainLayer(); return true; @@ -272,6 +280,71 @@ public class RuntimeStyleActivity extends AppCompatActivity { mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(12)); } + private void addDynamicParksLayer() { + //Load some data + FeatureCollection parks; + try { + String json = readRawResource(R.raw.amsterdam); + parks = FeatureCollection.fromJson(json); + } catch (IOException e) { + Toast.makeText(RuntimeStyleActivity.this, "Couldn't add source: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + return; + } + + //Add an empty source + mapboxMap.addSource(new GeoJsonSource("dynamic-park-source")); + + FillLayer layer = new FillLayer("dynamic-parks-layer", "dynamic-park-source"); + layer.setProperties( + fillColor(Color.GREEN), + fillOutlineColor(Color.GREEN), + fillOpacity(0.8f), + fillAntialias(true) + ); + + //Only show me parks + layer.setFilter(all(eq("type", "park"))); + + mapboxMap.addLayer(layer); + + //Get a good look at it all + mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(12)); + + //Animate the parks source + animateParksSource(parks, 0); + } + + private void animateParksSource(final FeatureCollection parks, final int counter) { + Handler handler = new Handler(getMainLooper()); + handler.postDelayed(new Runnable() { + @Override + public void run() { + if (mapboxMap == null) { + return; + } + + Log.d(TAG, "Updating parks source"); + //change the source + int park = counter < parks.getFeatures().size() - 1 ? counter : 0; + + GeoJsonSource source = mapboxMap.getSourceAs("dynamic-park-source"); + + if (source == null) { + Log.e(TAG, "Source not found"); + Toast.makeText(RuntimeStyleActivity.this, "Source not found", Toast.LENGTH_SHORT).show(); + return; + } + + List<Feature> features = new ArrayList<>(); + features.add(parks.getFeatures().get(park)); + source.setGeoJson(FeatureCollection.fromFeatures(features)); + + //Re-post + animateParksSource(parks, park + 1); + } + }, counter == 0 ? 100 : 1000); + } + private void addTerrainLayer() { //Add a source Source source = new VectorSource("my-terrain-source", "mapbox://mapbox.mapbox-terrain-v2"); @@ -302,7 +375,7 @@ public class RuntimeStyleActivity extends AppCompatActivity { private void addSatelliteLayer() { //Add a source - Source source = new RasterSource("my-raster-source", "mapbox://mapbox.satellite").withTileSize(512); + Source source = new RasterSource("my-raster-source", "mapbox://mapbox.satellite", 512); mapboxMap.addSource(source); //Add a layer diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml index 16713ae147..81e808e93c 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml @@ -23,6 +23,10 @@ android:title="Add a parks layer" mapbox:showAsAction="never" /> <item + android:id="@+id/action_add_dynamic_parks_layer" + android:title="Add a dynamic geojson source" + mapbox:showAsAction="never" /> + <item android:id="@+id/action_remove_layer" android:title="Remove buildings layer" mapbox:showAsAction="never" /> diff --git a/platform/android/config.cmake b/platform/android/config.cmake index 513e9e2bac..8eed13e53b 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -86,9 +86,10 @@ add_library(mapbox-gl SHARED # Style conversion Java -> C++ platform/android/src/style/android_conversion.hpp - platform/android/src/style/android_geojson.hpp + platform/android/src/style/conversion/geojson.hpp platform/android/src/style/value.cpp platform/android/src/style/value.hpp + platform/android/src/style/conversion/url_or_tileset.hpp # Style platform/android/src/style/layers/background_layer.cpp @@ -109,8 +110,16 @@ add_library(mapbox-gl SHARED platform/android/src/style/layers/raster_layer.hpp platform/android/src/style/layers/symbol_layer.cpp platform/android/src/style/layers/symbol_layer.hpp + platform/android/src/style/sources/geojson_source.cpp + platform/android/src/style/sources/geojson_source.hpp + platform/android/src/style/sources/source.cpp + platform/android/src/style/sources/source.hpp platform/android/src/style/sources/sources.cpp platform/android/src/style/sources/sources.hpp + platform/android/src/style/sources/raster_source.cpp + platform/android/src/style/sources/raster_source.hpp + platform/android/src/style/sources/vector_source.cpp + platform/android/src/style/sources/vector_source.hpp # Native map platform/android/src/native_map_view.cpp diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index 6752c1bbdb..1a5efce726 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -22,6 +22,7 @@ #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/platform/event.hpp> #include <mbgl/platform/log.hpp> @@ -1185,23 +1186,35 @@ void nativeRemoveLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, j } } -void nativeAddSource(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id, jni::jobject* jsource) { - mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddSource"); +jni::jobject* nativeGetSource(JNIEnv *env, jni::jobject* obj, jni::jlong nativeMapViewPtr, jni::jstring* sourceId) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetSource"); + + assert(env); assert(nativeMapViewPtr != 0); - assert(id != nullptr); - assert(jsource != nullptr); - //Convert - mbgl::optional<std::unique_ptr<mbgl::style::Source>> source = convertToNativeSource( - *env, - jni::Object<jni::jobject>(jsource), jni::String(id) - ); + //Get the native map peer + NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - //Add to map view - if (source) { - NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->getMap().addSource(std::move(*source)); + //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) { + mbgl::Log::Debug(mbgl::Event::JNI, "nativeAddSource"); + assert(nativeMapViewPtr != 0); + assert(nativeSourcePtr != 0); + + NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); + Source *source = reinterpret_cast<Source *>(nativeSourcePtr); + + nativeMapView->getMap().addSource(source->releaseCoreSource()); } void nativeRemoveSource(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id) { @@ -1687,6 +1700,7 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { java::registerNatives(env); registerNativeLayers(env); + registerNativeSources(env); latLngClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/LatLng"); latLngClass = jni::NewGlobalRef(env, latLngClass).release(); @@ -1838,7 +1852,8 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { MAKE_NATIVE_METHOD(nativeGetLayer, "(JLjava/lang/String;)Lcom/mapbox/mapboxsdk/style/layers/Layer;"), MAKE_NATIVE_METHOD(nativeAddLayer, "(JJLjava/lang/String;)V"), MAKE_NATIVE_METHOD(nativeRemoveLayer, "(JLjava/lang/String;)V"), - MAKE_NATIVE_METHOD(nativeAddSource, "(JLjava/lang/String;Lcom/mapbox/mapboxsdk/style/sources/Source;)V"), + MAKE_NATIVE_METHOD(nativeGetSource, "(JLjava/lang/String;)Lcom/mapbox/mapboxsdk/style/sources/Source;"), + MAKE_NATIVE_METHOD(nativeAddSource, "(JJ)V"), MAKE_NATIVE_METHOD(nativeRemoveSource, "(JLjava/lang/String;)V"), MAKE_NATIVE_METHOD(nativeSetContentPadding, "(JDDDD)V"), MAKE_NATIVE_METHOD(nativeScheduleTakeSnapshot, "(J)V"), diff --git a/platform/android/src/style/android_geojson.hpp b/platform/android/src/style/conversion/geojson.hpp index b2e0ca0a4a..920c670fcb 100644 --- a/platform/android/src/style/android_geojson.hpp +++ b/platform/android/src/style/conversion/geojson.hpp @@ -1,6 +1,6 @@ #pragma once -#include "value.hpp" +#include "../value.hpp" #include <mapbox/geojson.hpp> #include <mbgl/style/conversion.hpp> @@ -43,6 +43,15 @@ Result<GeoJSON> convertGeoJSON(const mbgl::android::Value& value) { return geoJSON; } +template <> +struct Converter<GeoJSON> { + + Result<GeoJSON> operator()(const mbgl::android::Value& value) const { + return convertGeoJSON(value); + } + +}; + } // namespace conversion } // namespace style } // namespace mbgl
\ No newline at end of file diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp new file mode 100644 index 0000000000..c1801f56d0 --- /dev/null +++ b/platform/android/src/style/conversion/url_or_tileset.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include <mbgl/util/optional.hpp> +#include <mbgl/util/variant.hpp> + +#include <mbgl/util/tileset.hpp> +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/tileset.hpp> + +#include <jni/jni.hpp> + +#include <string> + +namespace mbgl { +namespace style { +namespace conversion { + +template <> +struct Converter<variant<std::string, Tileset>> { + + template <class V> + Result<variant<std::string, Tileset>> operator()(const V& value) const { + if (isObject(value)) { + Result<Tileset> tileset = convert<Tileset>(value); + if (!tileset) { + return tileset.error(); + } + return *tileset; + } else { + return *toString(value); + } + } + +}; + +} +} +}
\ No newline at end of file diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp new file mode 100644 index 0000000000..cb03cc06c6 --- /dev/null +++ b/platform/android/src/style/sources/geojson_source.cpp @@ -0,0 +1,77 @@ +#include "geojson_source.hpp" + +#include "../android_conversion.hpp" +#include "../conversion/geojson.hpp" +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/geojson_options.hpp> + +#include <string> + +namespace mbgl { +namespace android { + + GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, jni::String sourceId, jni::Object<> options) + : Source(env, std::make_unique<mbgl::style::GeoJSONSource>( + jni::Make<std::string>(env, sourceId), + options ? *style::conversion::convert<style::GeoJSONOptions>(Value(env, options)) : style::GeoJSONOptions() + ) + ) { + } + + GeoJSONSource::GeoJSONSource(mbgl::Map& map, mbgl::style::GeoJSONSource& coreSource) + : Source(map, coreSource) { + } + + GeoJSONSource::~GeoJSONSource() = default; + + void GeoJSONSource::setGeoJSON(jni::JNIEnv& env, jni::Object<> json) { + using namespace mbgl::style::conversion; + + //Convert the jni object + Result<GeoJSON> converted = convert<GeoJSON>(Value(env, json)); + if(!converted) { + mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + converted.error().message); + return; + } + + //Update the core source + source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(*converted); + + //Repaint + updateStyle(false); + } + + void GeoJSONSource::setURL(jni::JNIEnv& env, jni::String url) { + //Update the core source + source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setURL(jni::Make<std::string>(env, url)); + + //Repaint + updateStyle(false); + } + + jni::Class<GeoJSONSource> GeoJSONSource::javaClass; + + jni::jobject* GeoJSONSource::createJavaPeer(jni::JNIEnv& env) { + static auto constructor = GeoJSONSource::javaClass.template GetConstructor<jni::jlong>(env); + return GeoJSONSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)); + } + + void GeoJSONSource::registerNative(jni::JNIEnv& env) { + //Lookup the class + GeoJSONSource::javaClass = *jni::Class<GeoJSONSource>::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) + + //Register the peer + jni::RegisterNativePeer<GeoJSONSource>( + env, GeoJSONSource::javaClass, "nativePtr", + std::make_unique<GeoJSONSource, JNIEnv&, jni::String, jni::Object<>>, + "initialize", + "finalize", + METHOD(&GeoJSONSource::setGeoJSON, "nativeSetGeoJson"), + METHOD(&GeoJSONSource::setURL, "nativeSetUrl") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/sources/geojson_source.hpp b/platform/android/src/style/sources/geojson_source.hpp new file mode 100644 index 0000000000..10c51e81b2 --- /dev/null +++ b/platform/android/src/style/sources/geojson_source.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "source.hpp" +#include <mbgl/style/sources/geojson_source.hpp> +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { + +class GeoJSONSource : public Source { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/GeoJsonSource"; }; + + static jni::Class<GeoJSONSource> javaClass; + + static void registerNative(jni::JNIEnv&); + + GeoJSONSource(jni::JNIEnv&, jni::String, jni::Object<>); + + GeoJSONSource(mbgl::Map&, mbgl::style::GeoJSONSource&); + + ~GeoJSONSource(); + + void setGeoJSON(jni::JNIEnv&, jni::Object<>); + + void setURL(jni::JNIEnv&, jni::String); + + jni::jobject* createJavaPeer(jni::JNIEnv&); + +}; // class GeoJSONSource + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/sources/raster_source.cpp b/platform/android/src/style/sources/raster_source.cpp new file mode 100644 index 0000000000..b56b56676d --- /dev/null +++ b/platform/android/src/style/sources/raster_source.cpp @@ -0,0 +1,54 @@ +#include "raster_source.hpp" + +#include "../android_conversion.hpp" +#include "../value.hpp" +#include "../conversion/url_or_tileset.hpp" + +#include <mbgl/util/variant.hpp> + +#include <string> + +namespace mbgl { +namespace android { + + RasterSource::RasterSource(jni::JNIEnv& env, jni::String sourceId, jni::Object<> urlOrTileSet, jni::jint tileSize) + : Source( + env, + std::make_unique<mbgl::style::RasterSource>( + jni::Make<std::string>(env, sourceId), + *style::conversion::convert<variant<std::string, Tileset>>(Value(env, urlOrTileSet)), + tileSize + ) + ) { + } + + RasterSource::RasterSource(mbgl::Map& map, mbgl::style::RasterSource& coreSource) + : Source(map, coreSource) { + } + + RasterSource::~RasterSource() = default; + + jni::Class<RasterSource> RasterSource::javaClass; + + jni::jobject* RasterSource::createJavaPeer(jni::JNIEnv& env) { + static auto constructor = RasterSource::javaClass.template GetConstructor<jni::jlong>(env); + return RasterSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)); + } + + void RasterSource::registerNative(jni::JNIEnv& env) { + //Lookup the class + RasterSource::javaClass = *jni::Class<RasterSource>::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) + + //Register the peer + jni::RegisterNativePeer<RasterSource>( + env, RasterSource::javaClass, "nativePtr", + std::make_unique<RasterSource, JNIEnv&, jni::String, jni::Object<>, jni::jint>, + "initialize", + "finalize" + ); + } + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/sources/raster_source.hpp b/platform/android/src/style/sources/raster_source.hpp new file mode 100644 index 0000000000..6600096f6d --- /dev/null +++ b/platform/android/src/style/sources/raster_source.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "source.hpp" +#include <mbgl/style/sources/raster_source.hpp> +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { + +class RasterSource : public Source { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/RasterSource"; }; + + static jni::Class<RasterSource> javaClass; + + static void registerNative(jni::JNIEnv&); + + RasterSource(jni::JNIEnv&, jni::String, jni::Object<>, jni::jint); + + RasterSource(mbgl::Map&, mbgl::style::RasterSource&); + + ~RasterSource(); + + jni::jobject* createJavaPeer(jni::JNIEnv&); + +}; // class RasterSource + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp new file mode 100644 index 0000000000..4f306e7c54 --- /dev/null +++ b/platform/android/src/style/sources/source.cpp @@ -0,0 +1,72 @@ +#include "source.hpp" +#include "../android_conversion.hpp" + +#include <jni/jni.hpp> + +#include <mbgl/platform/log.hpp> + +//Java -> C++ conversion +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/source.hpp> + +//C++ -> Java conversion +#include "../conversion/property_value.hpp" + +#include <string> + +namespace mbgl { +namespace android { + + /** + * Invoked when the construction is initiated from the jvm through a subclass + */ + Source::Source(jni::JNIEnv&, std::unique_ptr<mbgl::style::Source> coreSource) + : ownedSource(std::move(coreSource)) + , source(*ownedSource) { + } + + Source::Source(mbgl::Map& coreMap, mbgl::style::Source& coreSource) : source(coreSource) , map(&coreMap) { + } + + Source::~Source() { + } + + jni::String Source::getId(jni::JNIEnv& env) { + return jni::Make<jni::String>(env, source.getID()); + } + + void Source::updateStyle(jni::jboolean updateClasses) { + //Update the style only if attached + if (ownedSource == nullptr) { + Update flags = mbgl::Update::RecalculateStyle; + if(updateClasses) { + flags = flags | mbgl::Update::Classes; + } + map->update(flags); + } else { + mbgl::Log::Debug(mbgl::Event::JNI, "Not updating as source is not attached to map (yet)"); + } + } + + std::unique_ptr<mbgl::style::Source> Source::releaseCoreSource() { + assert(ownedSource != nullptr); + return std::move(ownedSource); + } + + jni::Class<Source> Source::javaClass; + + void Source::registerNative(jni::JNIEnv& env) { + //Lookup the class + Source::javaClass = *jni::Class<Source>::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) + + //Register the peer + jni::RegisterNativePeer<Source>(env, Source::javaClass, "nativePtr", + METHOD(&Source::getId, "nativeGetId") + ); + + } + +} //android +} //mbgl
\ No newline at end of file diff --git a/platform/android/src/style/sources/source.hpp b/platform/android/src/style/sources/source.hpp new file mode 100644 index 0000000000..7fdc43a833 --- /dev/null +++ b/platform/android/src/style/sources/source.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include <mbgl/util/noncopyable.hpp> +#include <mbgl/map/map.hpp> +#include <mbgl/style/source.hpp> + +#include "../value.hpp" + +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { + +class Source : private mbgl::util::noncopyable { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/Source"; }; + + static jni::Class<Source> javaClass; + + static void registerNative(jni::JNIEnv&); + + /* + * Called when a Java object is created on the c++ side + */ + Source(mbgl::Map&, mbgl::style::Source&); + + /* + * Called when a Java object was created from the jvm side + */ + Source(jni::JNIEnv&, std::unique_ptr<mbgl::style::Source>); + + virtual ~Source(); + + virtual jni::jobject* createJavaPeer(jni::JNIEnv&) = 0; + + jni::String getId(jni::JNIEnv&); + + //Release the owned view and return it + std::unique_ptr<mbgl::style::Source> releaseCoreSource(); + +protected: + void updateStyle(jni::jboolean); + + std::unique_ptr<mbgl::style::Source> ownedSource; + mbgl::style::Source& source; + mbgl::Map* map; + +}; + +} //android +} //mbgl + + + + diff --git a/platform/android/src/style/sources/sources.cpp b/platform/android/src/style/sources/sources.cpp index 47c9757e9d..210acd607f 100644 --- a/platform/android/src/style/sources/sources.cpp +++ b/platform/android/src/style/sources/sources.cpp @@ -1,28 +1,46 @@ #include "sources.hpp" -#include "../value.hpp" -#include "../android_conversion.hpp" -#include "../android_geojson.hpp" +#include <mbgl/style/source.hpp> +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/style/sources/raster_source.hpp> +#include <mbgl/style/sources/vector_source.hpp> -#include <mbgl/util/constants.hpp> -#include <mbgl/style/conversion.hpp> -#include <mbgl/style/conversion/source.hpp> - -#include <string> +#include "source.hpp" +#include "geojson_source.hpp" +#include "raster_source.hpp" +#include "vector_source.hpp" namespace mbgl { namespace android { - mbgl::optional<std::unique_ptr<mbgl::style::Source>> convertToNativeSource(jni::JNIEnv& env, jni::Object<jni::jobject> jvalue, jni::String id) { - using namespace mbgl::style; - - Value value(env, jvalue); - conversion::Result<std::unique_ptr<Source>> source = conversion::convert<std::unique_ptr<Source>>(value, jni::Make<std::string>(env, id)); - if (!source) { - mbgl::Log::Error(mbgl::Event::JNI, "Unable to add source: " + source.error().message); - return {}; - } - return std::move(*source); +Source* initializeSourcePeer(mbgl::Map& map, mbgl::style::Source& coreSource) { + Source* source; + if (coreSource.is<mbgl::style::VectorSource>()) { + source = new VectorSource(map, *coreSource.as<mbgl::style::VectorSource>()); + } else if (coreSource.is<mbgl::style::RasterSource>()) { + source = new RasterSource(map, *coreSource.as<mbgl::style::RasterSource>()); + } else if (coreSource.is<mbgl::style::GeoJSONSource>()) { + source = new GeoJSONSource(map, *coreSource.as<mbgl::style::GeoJSONSource>()); + } else { + throw new std::runtime_error("Source type not implemented"); } + + return source; +} + +jni::jobject* createJavaSourcePeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Source& coreSource) { + std::unique_ptr<Source> peerSource = std::unique_ptr<Source>(initializeSourcePeer(map, coreSource)); + jni::jobject* result = peerSource->createJavaPeer(env); + peerSource.release(); + return result; +} + +void registerNativeSources(jni::JNIEnv& env) { + Source::registerNative(env); + VectorSource::registerNative(env); + RasterSource::registerNative(env); + GeoJSONSource::registerNative(env); +} + } }
\ No newline at end of file diff --git a/platform/android/src/style/sources/sources.hpp b/platform/android/src/style/sources/sources.hpp index b967685dfb..3038873733 100644 --- a/platform/android/src/style/sources/sources.hpp +++ b/platform/android/src/style/sources/sources.hpp @@ -1,14 +1,20 @@ #pragma once +#include <mbgl/map/map.hpp> #include <mbgl/style/source.hpp> -#include <mbgl/util/optional.hpp> + +#include "source.hpp" #include <jni/jni.hpp> namespace mbgl { namespace android { - - mbgl::optional<std::unique_ptr<mbgl::style::Source>> convertToNativeSource(jni::JNIEnv& env, jni::Object<jni::jobject> jsource, jni::String id); + + mbgl::android::Source* initializeSourcePeer(mbgl::Map&, mbgl::style::Source&); + + jni::jobject* createJavaSourcePeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Source&); + + void registerNativeSources(jni::JNIEnv&); } }
\ No newline at end of file diff --git a/platform/android/src/style/sources/vector_source.cpp b/platform/android/src/style/sources/vector_source.cpp new file mode 100644 index 0000000000..0d065a3348 --- /dev/null +++ b/platform/android/src/style/sources/vector_source.cpp @@ -0,0 +1,53 @@ +#include "vector_source.hpp" + +#include "../android_conversion.hpp" +#include "../value.hpp" +#include "../conversion/url_or_tileset.hpp" + +#include <mbgl/util/variant.hpp> + +#include <string> + +namespace mbgl { +namespace android { + + VectorSource::VectorSource(jni::JNIEnv& env, jni::String sourceId, jni::Object<> urlOrTileSet) + : Source( + env, + std::make_unique<mbgl::style::VectorSource>( + jni::Make<std::string>(env, sourceId), + *style::conversion::convert<variant<std::string, Tileset>>(Value(env, urlOrTileSet)) + ) + ) { + } + + VectorSource::VectorSource(mbgl::Map& map, mbgl::style::VectorSource& coreSource) + : Source(map, coreSource) { + } + + VectorSource::~VectorSource() = default; + + jni::Class<VectorSource> VectorSource::javaClass; + + jni::jobject* VectorSource::createJavaPeer(jni::JNIEnv& env) { + static auto constructor = VectorSource::javaClass.template GetConstructor<jni::jlong>(env); + return VectorSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)); + } + + void VectorSource::registerNative(jni::JNIEnv& env) { + //Lookup the class + VectorSource::javaClass = *jni::Class<VectorSource>::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) + + //Register the peer + jni::RegisterNativePeer<VectorSource>( + env, VectorSource::javaClass, "nativePtr", + std::make_unique<VectorSource, JNIEnv&, jni::String, jni::Object<>>, + "initialize", + "finalize" + ); + } + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/sources/vector_source.hpp b/platform/android/src/style/sources/vector_source.hpp new file mode 100644 index 0000000000..95d22ef7b7 --- /dev/null +++ b/platform/android/src/style/sources/vector_source.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "source.hpp" +#include <mbgl/style/sources/vector_source.hpp> +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { + +class VectorSource : public Source { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/VectorSource"; }; + + static jni::Class<VectorSource> javaClass; + + static void registerNative(jni::JNIEnv&); + + VectorSource(jni::JNIEnv&, jni::String, jni::Object<>); + + VectorSource(mbgl::Map&, mbgl::style::VectorSource&); + + ~VectorSource(); + + jni::jobject* createJavaPeer(jni::JNIEnv&); + +}; // class VectorSource + +} // namespace android +} // namespace mbgl |