summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAsheem Mamoowala <asheem.mamoowala@mapbox.com>2017-10-20 14:14:21 -0700
committerAsheem Mamoowala <asheem.mamoowala@mapbox.com>2017-10-25 14:46:42 -0700
commit86ce3463b990c1062ead8504fb86d94bc5ab8c90 (patch)
tree4728d1e0487e9a54650d15a14d00e7a7e57d0df9
parent8d7f2c854ef9adbd2dbfd6b31699c2e45fde90b3 (diff)
downloadqtlocation-mapboxgl-upstream/android-custom-vector-source.tar.gz
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomVectorSource.java134
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/TileProvider.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java19
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java143
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_grid_source.xml17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml1
-rw-r--r--platform/android/config.cmake2
-rw-r--r--platform/android/src/style/sources/custom_vector_source.cpp115
-rw-r--r--platform/android/src/style/sources/custom_vector_source.hpp46
-rw-r--r--platform/android/src/style/sources/sources.cpp2
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);
}
}