diff options
author | Asheem Mamoowala <asheem.mamoowala@mapbox.com> | 2017-10-20 14:14:21 -0700 |
---|---|---|
committer | Asheem Mamoowala <asheem.mamoowala@mapbox.com> | 2017-10-25 14:46:42 -0700 |
commit | 86ce3463b990c1062ead8504fb86d94bc5ab8c90 (patch) | |
tree | 4728d1e0487e9a54650d15a14d00e7a7e57d0df9 /platform/android | |
parent | 8d7f2c854ef9adbd2dbfd6b31699c2e45fde90b3 (diff) | |
download | qtlocation-mapboxgl-86ce3463b990c1062ead8504fb86d94bc5ab8c90.tar.gz |
Android bindingsupstream/android-custom-vector-source
Diffstat (limited to 'platform/android')
14 files changed, 533 insertions, 2 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index 4fcb91033c..c1ea669418 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -11,6 +11,8 @@ import com.mapbox.services.android.telemetry.constants.GeoConstants; import java.util.ArrayList; import java.util.List; +import static android.R.attr.id; + /** * A geographical area representing a latitude/longitude aligned rectangle. * <p> @@ -231,6 +233,22 @@ public class LatLngBounds implements Parcelable { return new LatLngBounds(latNorth, lonEast, latSouth, lonWest); } + private static double lat_(int z, int y) { + double n = Math.PI - 2.0 * Math.PI * y / Math.pow(2.0, z); + return Math.toDegrees(Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)))); + } + + private static double lon_(int z, int x) { + return x / Math.pow(2.0, z) * 360.0 - GeoConstants.MAX_LONGITUDE; + } + + /** + * Constructs a LatLngBounds from a Tile identifier. + */ + public static LatLngBounds from(int z, int x, int y) { + return new LatLngBounds(lat_(z, y), lon_(z, x + 1), lat_(z, y + 1), lon_(z, x)); + } + /** * Constructs a LatLngBounds from current bounds with an additional latitude-longitude pair. * diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomVectorSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomVectorSource.java new file mode 100644 index 0000000000..11ed3111b7 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomVectorSource.java @@ -0,0 +1,134 @@ +package com.mapbox.mapboxsdk.style.sources; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.UiThread; +import android.support.annotation.WorkerThread; + +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.style.layers.Filter; +import com.mapbox.services.commons.geojson.Feature; +import com.mapbox.services.commons.geojson.FeatureCollection; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +class TileID { + public int z; + public int x; + public int y; + public TileID(int _z, int _x, int _y) { + z = _z; + x = _x; + y = _y; + } +} + +class TileRequest implements Runnable { + private TileID id; + private TileProvider provider; + private WeakReference<CustomVectorSource> sourceRef; + public TileRequest(TileID _id, TileProvider p, CustomVectorSource _source) { + id = _id; + provider = p; + sourceRef = new WeakReference<>(_source); + } + + public void run() { + FeatureCollection data = provider.getFeaturesForBounds(LatLngBounds.from(id.z, id.x, id.y), id.z); + CustomVectorSource source = sourceRef.get(); + if(source != null) { + source.setTileData(id, data); + } + } +} + +/** + * Custom Vector Source, allows using FeatureCollections. + * + */ +@UiThread +public class CustomVectorSource extends Source { + private BlockingQueue requestQueue; + private ThreadPoolExecutor executor; + private TileProvider provider; + + /** + * Internal use + * + * @param nativePtr - pointer to native peer + */ + public CustomVectorSource(long nativePtr) { + super(nativePtr); + } + + /** + * Create a CustomVectorSource + * + * @param id the source id + */ + public CustomVectorSource(String id, TileProvider provider_) { + requestQueue = new ArrayBlockingQueue(80); + executor = new ThreadPoolExecutor(10, 10, 60, TimeUnit.SECONDS, requestQueue); + + provider = provider_; + initialize(this, id, new GeoJsonOptions()); + } + + /** + * Create a CustomVectorSource with non-default GeoJsonOptions. + * + * @param id the source id + * @param options options + */ + public CustomVectorSource(String id, TileProvider provider_, GeoJsonOptions options) { + provider = provider_; + initialize(this, id, options); + } + + public void setTileData(TileID tileId, FeatureCollection data) { + setTileData(tileId.z, tileId.x, tileId.y, data); + } + + /** + * Queries the source for features. + * + * @param filter an optional filter statement to filter the returned Features + * @return the features + */ + @NonNull + public List<Feature> querySourceFeatures(@Nullable Filter.Statement filter) { + Feature[] features = querySourceFeatures(filter != null ? filter.toArray() : null); + return features != null ? Arrays.asList(features) : new ArrayList<Feature>(); + } + + protected native void initialize(CustomVectorSource self, String sourceId, Object options); + + private native Feature[] querySourceFeatures(Object[] filter); + + private native void setTileData(int z, int x, int y, FeatureCollection data); + + @WorkerThread + public void fetchTile(int z, int x, int y) { + TileRequest request = new TileRequest(new TileID(z, x, y), provider, this); + long active = executor.getActiveCount(); + long complete = executor.getCompletedTaskCount(); + executor.execute(request); +// setTileData(z, x, y, data); + System.out.println("Active=" + active); + System.out.println("Completed=" + complete); + } + + @WorkerThread + public void cancelTile(int z, int x, int y) { + } + + @Override + protected native void finalize() throws Throwable; +} 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 index 1a1711e547..81f7255b86 100644 --- 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 @@ -16,6 +16,17 @@ public class GeoJsonOptions extends HashMap<String, Object> { * @param maxZoom the maximum zoom - Defaults to 18. * @return the current instance for chaining */ + public GeoJsonOptions withMinZoom(int minZoom) { + this.put("minzoom", minZoom); + return this; + } + + /** + * Maximum zoom level at which to create vector tiles (higher means greater detail at high zoom levels). + * + * @param maxZoom the maximum zoom - Defaults to 18. + * @return the current instance for chaining + */ public GeoJsonOptions withMaxZoom(int maxZoom) { this.put("maxzoom", maxZoom); return this; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileProvider.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileProvider.java new file mode 100644 index 0000000000..7e3befbc43 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileProvider.java @@ -0,0 +1,12 @@ +package com.mapbox.mapboxsdk.style.sources; + +import android.support.annotation.WorkerThread; + +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.services.commons.geojson.FeatureCollection; +import com.mapbox.services.commons.geojson.GeoJSON; + +public interface TileProvider { + @WorkerThread + FeatureCollection getFeaturesForBounds(LatLngBounds bounds, int zoomLevel); +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java index 8d9a360714..ac52b631ed 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java @@ -4,6 +4,7 @@ import android.os.Parcelable; import com.mapbox.mapboxsdk.exceptions.InvalidLatLngBoundsException; import com.mapbox.mapboxsdk.utils.MockParcel; +import com.mapbox.services.android.telemetry.constants.GeoConstants; import org.junit.Before; import org.junit.Test; @@ -281,4 +282,22 @@ public class LatLngBoundsTest { Parcelable parcel = MockParcel.obtain(latLngBounds); assertEquals("Parcel should match original object", parcel, latLngBounds); } + + @Test + public void fromTileID() { + //GeoConstants.MAX_LATITUDE is not defined to a high enough precision + double MAX_LATITUDE = 85.05112877980659; + LatLngBounds bounds = LatLngBounds.from(0, 0, 0); + assertEquals(-GeoConstants.MAX_LONGITUDE, bounds.getLonWest(), DELTA); + assertEquals(-MAX_LATITUDE, bounds.getLatSouth(), DELTA); + assertEquals(GeoConstants.MAX_LONGITUDE, bounds.getLonEast(), DELTA); + assertEquals(MAX_LATITUDE, bounds.getLatNorth(), DELTA); + + bounds = LatLngBounds.from(10, 288, 385); + assertEquals(-78.75, bounds.getLonWest(), DELTA); + assertEquals(40.446947059600497, bounds.getLatSouth(), DELTA); + assertEquals(-78.3984375, bounds.getLonEast(), DELTA); + assertEquals(40.713955826286039, bounds.getLatNorth(), DELTA); + + } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index bf97749b9e..0fdda2cf02 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -575,7 +575,17 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity"/> </activity> - + <activity + android:name=".activity.style.GridSourceActivity" + android:label="@string/title_activity_grid_source" + android:description="@string/description_grid_source"> + <meta-data + android:name="@string/category" + android:value="@string/category_style"/> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity"/> + </activity> <!-- Features --> <activity android:name=".activity.feature.QueryRenderedFeaturesPropertiesActivity" diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java new file mode 100644 index 0000000000..be0fce72fa --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java @@ -0,0 +1,143 @@ +package com.mapbox.mapboxsdk.testapp.activity.style; + +import android.graphics.Color; +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.NonNull; +import android.support.v7.app.AppCompatActivity; + +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.style.layers.LineLayer; +import com.mapbox.mapboxsdk.style.sources.CustomVectorSource; +import com.mapbox.mapboxsdk.style.sources.TileProvider; +import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.services.commons.geojson.Feature; +import com.mapbox.services.commons.geojson.FeatureCollection; +import com.mapbox.services.commons.geojson.GeoJSON; +import com.mapbox.services.commons.geojson.LineString; + +import java.util.ArrayList; +import java.util.List; + +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor; +import static com.mapbox.mapboxsdk.testapp.R.string.zoom; + +public class GridSourceActivity extends AppCompatActivity implements OnMapReadyCallback { + + private static final String ID_GRID_SOURCE = "grid_source"; + private static final String ID_GRID_LAYER = "grid_layer"; + + private MapView mapView; + private MapboxMap mapboxMap; + private CustomVectorSource source; + + class GridProvider implements TileProvider { + public FeatureCollection getFeaturesForBounds(LatLngBounds bounds, int zoom) { + List<Feature> features = new ArrayList<>(); + double gridSpacing; + if(zoom >= 13) { + gridSpacing = 0.01; + } else if(zoom >= 11) { + gridSpacing = 0.05; + } else if(zoom == 10) { + gridSpacing = .1; + } else if(zoom == 9) { + gridSpacing = 0.25; + } else if(zoom == 8) { + gridSpacing = 0.5; + } else if (zoom >= 6) { + gridSpacing = 1; + } else if(zoom == 5) { + gridSpacing = 2; + } else if(zoom >= 4) { + gridSpacing = 5; + } else if(zoom == 2) { + gridSpacing = 10; + } else { + gridSpacing = 20; + } + for (double y = Math.ceil(bounds.getLatNorth() / gridSpacing) * gridSpacing; y >= Math.floor(bounds.getLatSouth() / gridSpacing) * gridSpacing; y -= gridSpacing) { + LineString gridLine = LineString.fromCoordinates(new double[][]{ new double []{bounds.getLonWest(), y}, new double[]{bounds.getLonEast(), y}}); + features.add(Feature.fromGeometry(gridLine)); + } + + for (double x = Math.floor(bounds.getLonWest() / gridSpacing) * gridSpacing; x <= Math.ceil(bounds.getLonEast() / gridSpacing) * gridSpacing; x += gridSpacing) { + LineString gridLine = LineString.fromCoordinates(new double[][]{new double[]{x, bounds.getLatSouth()}, new double[] {x, bounds.getLatNorth()}}); + features.add(Feature.fromGeometry(gridLine)); + } + return FeatureCollection.fromFeatures(features); + } + } + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_grid_source); + + mapView = (MapView) findViewById(R.id.mapView); + mapView.onCreate(savedInstanceState); + mapView.getMapAsync(this); + } + + @Override + public void onMapReady(@NonNull final MapboxMap map) { + mapboxMap = map; + map.setDebugActive(true); + new Handler(getMainLooper()).post(new Runnable() { + @Override + public void run() { + // add source + source = new CustomVectorSource(ID_GRID_SOURCE, new GridProvider()); + mapboxMap.addSource(source); + + // add layer + LineLayer layer = new LineLayer(ID_GRID_LAYER, ID_GRID_SOURCE); + layer.setProperties( + lineColor(Color.parseColor("#000000")) + ); + + mapboxMap.addLayer(layer); + } + }); + + } + + @Override + protected void onStart() { + super.onStart(); + mapView.onStart(); + } + + @Override + public void onResume() { + super.onResume(); + mapView.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + protected void onStop() { + super.onStop(); + mapView.onStop(); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } + +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_grid_source.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_grid_source.xml new file mode 100644 index 0000000000..26b40b9ab6 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_grid_source.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <com.mapbox.mapboxsdk.maps.MapView + android:id="@id/mapView" + android:layout_width="match_parent" + android:layout_height="match_parent" + app:mapbox_cameraTargetLat="41.9567" + app:mapbox_cameraTargetLng="-78.6430" + app:mapbox_cameraZoom="5" + app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/> + +</RelativeLayout> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index 4d1f7eac38..6a4a7985ce 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -43,7 +43,7 @@ <string name="description_query_rendered_feature_properties_point">Query rendered feature properties on click</string> <string name="description_query_rendered_features_box_count">Count all rendered features in box</string> <string name="description_query_rendered_features_box_symbol_count">Count all rendered symbols in box</string> - <string name="description_query_rendered_features_box_highlight">Hightligh buildings in box</string> + <string name="description_query_rendered_features_box_highlight">Highlight buildings in box</string> <string name="description_query_source_features">Query source for features</string> <string name="description_simple_map">Shows a simple map</string> <string name="description_map_change">Logs map change events to Logcat</string> @@ -62,4 +62,5 @@ <string name="description_map_snapshotter">Show a static bitmap taken with the MapSnapshotter</string> <string name="description_camera_animator">Use Android SDK Animators to animate camera position changes</string> <string name="description_symbol_generator">Use Android SDK Views as symbols</string> + <string name="description_grid_source">Example Custom Geometry Source</string> </resources>
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml index 15a916fac9..b2bae9279f 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml @@ -1,4 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Mapbox Android SDK TestApp</string> + <string name="title_activity_grid_source">Grid Source</string> </resources> diff --git a/platform/android/config.cmake b/platform/android/config.cmake index 8dd537d36e..3bd1099382 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -178,6 +178,8 @@ add_library(mbgl-android STATIC platform/android/src/style/layers/unknown_layer.hpp platform/android/src/style/sources/geojson_source.cpp platform/android/src/style/sources/geojson_source.hpp + platform/android/src/style/sources/custom_vector_source.cpp + platform/android/src/style/sources/custom_vector_source.hpp platform/android/src/style/sources/source.cpp platform/android/src/style/sources/source.hpp platform/android/src/style/sources/sources.cpp diff --git a/platform/android/src/style/sources/custom_vector_source.cpp b/platform/android/src/style/sources/custom_vector_source.cpp new file mode 100644 index 0000000000..abc653c651 --- /dev/null +++ b/platform/android/src/style/sources/custom_vector_source.cpp @@ -0,0 +1,115 @@ +#include "custom_vector_source.hpp" + +#include <mbgl/renderer/query.hpp> + +// Java -> C++ conversion +#include "../android_conversion.hpp" +#include "../conversion/filter.hpp" +//#include "../conversion/geojson.hpp" + +// C++ -> Java conversion +#include "../../conversion/conversion.hpp" +#include "../../conversion/collection.hpp" +#include "../../geojson/conversion/feature.hpp" +#include <mbgl/style/conversion/custom_vector_source_options.hpp> + +#include <string> + +namespace mbgl { +namespace android { + + // This conversion is expected not to fail because it's used only in contexts where + // the value was originally a GeoJsonOptions object on the Java side. If it fails + // to convert, it's a bug in our serialization or Java-side static typing. + static style::CustomVectorSource::Options convertCustomVectorSourceOptions(jni::JNIEnv& env, jni::Object<> options, style::TileFunction fetchFn, style::TileFunction cancelFn) { + using namespace mbgl::style::conversion; + if (!options) { + return style::CustomVectorSource::Options(); + } + Error error; + optional<style::CustomVectorSource::Options> result = convert<style::CustomVectorSource::Options>(Value(env, options), error); + if (!result) { + throw std::logic_error(error.message); + } + result->fetchTileFunction = fetchFn; + result->cancelTileFunction = cancelFn; + return *result; + } + + CustomVectorSource::CustomVectorSource(jni::JNIEnv& env, jni::Object<CustomVectorSource> _obj, jni::String sourceId, jni::Object<> options) + : Source(env, std::make_unique<mbgl::style::CustomVectorSource>( + jni::Make<std::string>(env, sourceId), + convertCustomVectorSourceOptions(env, options, std::bind(&CustomVectorSource::fetchTile, this, std::placeholders::_1), std::bind(&CustomVectorSource::cancelTile, this, std::placeholders::_1))) + ), javaPeer(SeizeGenericWeakRef(env, jni::Object<CustomVectorSource>(jni::NewWeakGlobalRef(env, _obj.Get()).release()))) { + + } + + CustomVectorSource::CustomVectorSource(mbgl::style::CustomVectorSource& coreSource) + : Source(coreSource) { + } + + CustomVectorSource::~CustomVectorSource() = default; + + void CustomVectorSource::fetchTile (const mbgl::CanonicalTileID& tileID) { + android::UniqueEnv _env = android::AttachEnv(); + static auto fetchTile = javaClass.GetMethod<void (jni::jint, jni::jint, jni::jint)>(*_env, "fetchTile"); + assert(javaPeer); + javaPeer->Call(*_env, fetchTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); + }; + + void CustomVectorSource::cancelTile(const mbgl::CanonicalTileID& tileID) { + android::UniqueEnv _env = android::AttachEnv(); + static auto cancelTile = javaClass.GetMethod<void (jni::jint, jni::jint, jni::jint)>(*_env, "cancelTile"); + + javaPeer->Call(*_env, cancelTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); + }; + + + void CustomVectorSource::setTileData(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y, jni::Object<geojson::FeatureCollection> jFeatures) { + using namespace mbgl::android::geojson; + + // Convert the jni object + auto geometry = geojson::FeatureCollection::convert(env, jFeatures); + + // Update the core source + source.as<mbgl::style::CustomVectorSource>()->CustomVectorSource::setTileData(CanonicalTileID(z, x, y), GeoJSON(geometry)); + } + + jni::Array<jni::Object<geojson::Feature>> CustomVectorSource::querySourceFeatures(jni::JNIEnv& env, + jni::Array<jni::Object<>> jfilter) { + using namespace mbgl::android::conversion; + using namespace mbgl::android::geojson; + + std::vector<mbgl::Feature> features; + if (rendererFrontend) { + features = rendererFrontend->querySourceFeatures(source.getID(), { {}, toFilter(env, jfilter) }); + } + return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, features); + } + + jni::Class<CustomVectorSource> CustomVectorSource::javaClass; + + jni::jobject* CustomVectorSource::createJavaPeer(jni::JNIEnv& env) { + static auto constructor = CustomVectorSource::javaClass.template GetConstructor<jni::jlong>(env); + return CustomVectorSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this)); + } + + void CustomVectorSource::registerNative(jni::JNIEnv& env) { + // Lookup the class + CustomVectorSource::javaClass = *jni::Class<CustomVectorSource>::Find(env).NewGlobalRef(env).release(); + + #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) + + // Register the peer + jni::RegisterNativePeer<CustomVectorSource>( + env, CustomVectorSource::javaClass, "nativePtr", + std::make_unique<CustomVectorSource, JNIEnv&, jni::Object<CustomVectorSource>, jni::String, jni::Object<>>, + "initialize", + "finalize", + METHOD(&CustomVectorSource::querySourceFeatures, "querySourceFeatures"), + METHOD(&CustomVectorSource::setTileData, "setTileData") + ); + } + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/sources/custom_vector_source.hpp b/platform/android/src/style/sources/custom_vector_source.hpp new file mode 100644 index 0000000000..8e21393b30 --- /dev/null +++ b/platform/android/src/style/sources/custom_vector_source.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include "source.hpp" +#include <mbgl/style/sources/custom_vector_source.hpp> +#include <mbgl/util/geojson.hpp> +#include <mbgl/tile/tile_id.hpp> +#include "../../geojson/geometry.hpp" +#include "../../geojson/feature.hpp" +#include "../../geojson/feature_collection.hpp" +#include <jni/jni.hpp> + +namespace mbgl { +namespace android { + +class CustomVectorSource : public Source { +public: + + static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/CustomVectorSource"; }; + + static jni::Class<CustomVectorSource> javaClass; + + static void registerNative(jni::JNIEnv&); + + CustomVectorSource(jni::JNIEnv&, + jni::Object<CustomVectorSource>, + jni::String, + jni::Object<>); + + CustomVectorSource(mbgl::style::CustomVectorSource&); + + ~CustomVectorSource(); + + void fetchTile(const mbgl::CanonicalTileID& tileID); + void cancelTile(const mbgl::CanonicalTileID& tileID); + void setTileData(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y, jni::Object<geojson::FeatureCollection> jf); + + jni::Array<jni::Object<geojson::Feature>> querySourceFeatures(jni::JNIEnv&, + jni::Array<jni::Object<>> ); + + jni::jobject* createJavaPeer(jni::JNIEnv&); + + GenericUniqueWeakObject<CustomVectorSource> javaPeer; +}; // class CustomVectorSource + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/style/sources/sources.cpp b/platform/android/src/style/sources/sources.cpp index 9ab3ca8e84..023b04122f 100644 --- a/platform/android/src/style/sources/sources.cpp +++ b/platform/android/src/style/sources/sources.cpp @@ -12,6 +12,7 @@ #include "raster_source.hpp" #include "unknown_source.hpp" #include "vector_source.hpp" +#include "custom_vector_source.hpp" namespace { @@ -54,6 +55,7 @@ void registerNativeSources(jni::JNIEnv& env) { RasterSource::registerNative(env); UnknownSource::registerNative(env); VectorSource::registerNative(env); + CustomVectorSource::registerNative(env); } } |