Add feature state functionality to Android (#4219)
This commit is contained in:
@@ -170,6 +170,28 @@ std::vector<Feature> AndroidRendererFrontend::querySourceFeatures(const std::str
|
||||
return mapRenderer.actor().ask(&Renderer::querySourceFeatures, sourceID, options).get();
|
||||
}
|
||||
|
||||
void AndroidRendererFrontend::setFeatureState(const std::string& sourceID,
|
||||
const std::optional<std::string>& sourceLayerID,
|
||||
const std::string& featureID,
|
||||
const FeatureState& state) const {
|
||||
mapRenderer.actor().invoke(&Renderer::setFeatureState, sourceID, sourceLayerID, featureID, state);
|
||||
}
|
||||
|
||||
FeatureState AndroidRendererFrontend::getFeatureState(const std::string& sourceID,
|
||||
const std::optional<std::string>& sourceLayerID,
|
||||
const std::string& featureID) const {
|
||||
auto getFeatureState = static_cast<FeatureState (Renderer::*)(
|
||||
const std::string&, const std::optional<std::string>&, const std::string&) const>(&Renderer::getFeatureState);
|
||||
return mapRenderer.actor().ask(getFeatureState, sourceID, sourceLayerID, featureID).get();
|
||||
}
|
||||
|
||||
void AndroidRendererFrontend::removeFeatureState(const std::string& sourceID,
|
||||
const std::optional<std::string>& sourceLayerID,
|
||||
const std::optional<std::string>& featureID,
|
||||
const std::optional<std::string>& stateKey) const {
|
||||
mapRenderer.actor().invoke(&Renderer::removeFeatureState, sourceID, sourceLayerID, featureID, stateKey);
|
||||
}
|
||||
|
||||
std::vector<Feature> AndroidRendererFrontend::queryRenderedFeatures(const ScreenBox& box,
|
||||
const RenderedQueryOptions& options) const {
|
||||
// Select the right overloaded method
|
||||
|
||||
@@ -52,6 +52,17 @@ public:
|
||||
std::vector<Feature> queryRenderedFeatures(const ScreenCoordinate&, const RenderedQueryOptions&) const;
|
||||
std::vector<Feature> queryRenderedFeatures(const ScreenBox&, const RenderedQueryOptions&) const;
|
||||
std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const;
|
||||
void setFeatureState(const std::string& sourceID,
|
||||
const std::optional<std::string>& sourceLayerID,
|
||||
const std::string& featureID,
|
||||
const FeatureState& state) const;
|
||||
FeatureState getFeatureState(const std::string& sourceID,
|
||||
const std::optional<std::string>& sourceLayerID,
|
||||
const std::string& featureID) const;
|
||||
void removeFeatureState(const std::string& sourceID,
|
||||
const std::optional<std::string>& sourceLayerID,
|
||||
const std::optional<std::string>& featureID,
|
||||
const std::optional<std::string>& stateKey) const;
|
||||
AnnotationIDs queryPointAnnotations(const ScreenBox& box, const std::chrono::milliseconds& timeout) const;
|
||||
AnnotationIDs queryShapeAnnotations(const ScreenBox& box, const std::chrono::milliseconds& timeout) const;
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "conversion/collection.hpp"
|
||||
#include "style/conversion/filter.hpp"
|
||||
#include "geojson/feature.hpp"
|
||||
#include "gson/json_object.hpp"
|
||||
#include "rendering_stats.hpp"
|
||||
|
||||
#include "android_renderer_frontend.hpp"
|
||||
@@ -1015,6 +1016,59 @@ jni::Local<jni::Array<jni::Object<geojson::Feature>>> NativeMapView::queryRender
|
||||
return Feature::convert(env, rendererFrontend->queryRenderedFeatures(box, {layers, toFilter(env, jfilter)}));
|
||||
}
|
||||
|
||||
void NativeMapView::setFeatureState(JNIEnv& env,
|
||||
const jni::String& sourceId,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId,
|
||||
const jni::Object<gson::JsonObject>& state) {
|
||||
if (!sourceId || !featureId || !state) {
|
||||
return;
|
||||
}
|
||||
|
||||
rendererFrontend->setFeatureState(
|
||||
jni::Make<std::string>(env, sourceId),
|
||||
sourceLayerId ? std::optional<std::string>(jni::Make<std::string>(env, sourceLayerId)) : std::nullopt,
|
||||
jni::Make<std::string>(env, featureId),
|
||||
gson::JsonObject::convert(env, state));
|
||||
map->triggerRepaint();
|
||||
}
|
||||
|
||||
jni::Local<jni::Object<gson::JsonObject>> NativeMapView::getFeatureState(JNIEnv& env,
|
||||
const jni::String& sourceId,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId) {
|
||||
if (!sourceId || !featureId) {
|
||||
return jni::Local<jni::Object<gson::JsonObject>>();
|
||||
}
|
||||
|
||||
const auto state = rendererFrontend->getFeatureState(
|
||||
jni::Make<std::string>(env, sourceId),
|
||||
sourceLayerId ? std::optional<std::string>(jni::Make<std::string>(env, sourceLayerId)) : std::nullopt,
|
||||
jni::Make<std::string>(env, featureId));
|
||||
if (state.empty()) {
|
||||
return jni::Local<jni::Object<gson::JsonObject>>();
|
||||
}
|
||||
|
||||
return gson::JsonObject::New(env, state);
|
||||
}
|
||||
|
||||
void NativeMapView::removeFeatureState(JNIEnv& env,
|
||||
const jni::String& sourceId,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId,
|
||||
const jni::String& stateKey) {
|
||||
if (!sourceId) {
|
||||
return;
|
||||
}
|
||||
|
||||
rendererFrontend->removeFeatureState(
|
||||
jni::Make<std::string>(env, sourceId),
|
||||
sourceLayerId ? std::optional<std::string>(jni::Make<std::string>(env, sourceLayerId)) : std::nullopt,
|
||||
featureId ? std::optional<std::string>(jni::Make<std::string>(env, featureId)) : std::nullopt,
|
||||
stateKey ? std::optional<std::string>(jni::Make<std::string>(env, stateKey)) : std::nullopt);
|
||||
map->triggerRepaint();
|
||||
}
|
||||
|
||||
jni::Local<jni::Object<Light>> NativeMapView::getLight(JNIEnv& env) {
|
||||
mbgl::style::Light* light = map->getStyle().getLight();
|
||||
if (light) {
|
||||
@@ -1183,7 +1237,7 @@ jni::Local<jni::Array<jni::Object<Source>>> NativeMapView::getSources(JNIEnv& en
|
||||
auto jSources = jni::Array<jni::Object<Source>>::New(env, sources.size());
|
||||
int index = 0;
|
||||
for (auto source : sources) {
|
||||
jSources.Set(env, index, Source::peerForCoreSource(env, *source, *rendererFrontend));
|
||||
jSources.Set(env, index, Source::peerForCoreSource(env, *source, *rendererFrontend, *map));
|
||||
index++;
|
||||
}
|
||||
|
||||
@@ -1199,7 +1253,7 @@ jni::Local<jni::Object<Source>> NativeMapView::getSource(JNIEnv& env, const jni:
|
||||
}
|
||||
|
||||
// Create and return the source's native peer
|
||||
return jni::NewLocal(env, Source::peerForCoreSource(env, *coreSource, *rendererFrontend));
|
||||
return jni::NewLocal(env, Source::peerForCoreSource(env, *coreSource, *rendererFrontend, *map));
|
||||
}
|
||||
|
||||
void NativeMapView::addSource(JNIEnv& env, const jni::Object<Source>& obj, jlong sourcePtr) {
|
||||
@@ -1428,6 +1482,9 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
|
||||
METHOD(&NativeMapView::queryShapeAnnotations, "nativeQueryShapeAnnotations"),
|
||||
METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"),
|
||||
METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"),
|
||||
METHOD(&NativeMapView::setFeatureState, "nativeSetFeatureState"),
|
||||
METHOD(&NativeMapView::getFeatureState, "nativeGetFeatureState"),
|
||||
METHOD(&NativeMapView::removeFeatureState, "nativeRemoveFeatureState"),
|
||||
METHOD(&NativeMapView::getLight, "nativeGetLight"),
|
||||
METHOD(&NativeMapView::getLayers, "nativeGetLayers"),
|
||||
METHOD(&NativeMapView::getLayer, "nativeGetLayer"),
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "graphics/rectf.hpp"
|
||||
#include "geojson/feature.hpp"
|
||||
#include "geojson/geometry.hpp"
|
||||
#include "gson/json_object.hpp"
|
||||
#include "geometry/lat_lng.hpp"
|
||||
#include "geometry/projected_meters.hpp"
|
||||
#include "style/layers/layer_manager.hpp"
|
||||
@@ -258,6 +259,23 @@ public:
|
||||
const jni::Array<jni::String>&,
|
||||
const jni::Array<jni::Object<>>& jfilter);
|
||||
|
||||
void setFeatureState(JNIEnv&,
|
||||
const jni::String& sourceId,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId,
|
||||
const jni::Object<gson::JsonObject>& state);
|
||||
|
||||
jni::Local<jni::Object<gson::JsonObject>> getFeatureState(JNIEnv&,
|
||||
const jni::String& sourceId,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId);
|
||||
|
||||
void removeFeatureState(JNIEnv&,
|
||||
const jni::String& sourceId,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId,
|
||||
const jni::String& stateKey);
|
||||
|
||||
jni::Local<jni::Object<Light>> getLight(JNIEnv&);
|
||||
|
||||
jni::Local<jni::Array<jni::Object<Layer>>> getLayers(JNIEnv&);
|
||||
|
||||
@@ -52,11 +52,14 @@ static std::unique_ptr<Source> createSourcePeer(jni::JNIEnv& env,
|
||||
|
||||
const jni::Object<Source>& Source::peerForCoreSource(jni::JNIEnv& env,
|
||||
mbgl::style::Source& coreSource,
|
||||
AndroidRendererFrontend& frontend) {
|
||||
AndroidRendererFrontend& frontend,
|
||||
mbgl::Map& map) {
|
||||
if (!coreSource.peer.has_value()) {
|
||||
coreSource.peer = createSourcePeer(env, coreSource, &frontend);
|
||||
}
|
||||
return coreSource.peer.get<std::unique_ptr<Source>>()->javaPeer;
|
||||
auto* peer = coreSource.peer.get<std::unique_ptr<Source>>().get();
|
||||
peer->bindToMap(frontend, map);
|
||||
return peer->javaPeer;
|
||||
}
|
||||
|
||||
const jni::Object<Source>& Source::peerForCoreSource(jni::JNIEnv& env, mbgl::style::Source& coreSource) {
|
||||
@@ -172,7 +175,7 @@ void Source::addToMap(JNIEnv& env, const jni::Object<Source>& obj, mbgl::Map& ma
|
||||
// Add strong reference to java source
|
||||
javaPeer = jni::NewGlobal(env, obj);
|
||||
|
||||
rendererFrontend = &frontend;
|
||||
bindToMap(frontend, map);
|
||||
}
|
||||
|
||||
bool Source::removeFromMap(JNIEnv&, const jni::Object<Source>&, mbgl::Map& map) {
|
||||
@@ -204,6 +207,67 @@ jni::Local<jni::Long> Source::getMinimumTileUpdateInterval(JNIEnv& env) {
|
||||
return jni::Box(env, jni::jlong(source.getMinimumTileUpdateInterval().count() / 1000000));
|
||||
}
|
||||
|
||||
jni::jboolean Source::setFeatureState(JNIEnv& env,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId,
|
||||
const jni::Object<gson::JsonObject>& state) {
|
||||
if (!rendererFrontend || !featureId || !state) {
|
||||
return jni::jni_false;
|
||||
}
|
||||
|
||||
rendererFrontend->setFeatureState(
|
||||
source.getID(),
|
||||
sourceLayerId ? std::optional<std::string>(jni::Make<std::string>(env, sourceLayerId)) : std::nullopt,
|
||||
jni::Make<std::string>(env, featureId),
|
||||
gson::JsonObject::convert(env, state));
|
||||
if (map) {
|
||||
map->triggerRepaint();
|
||||
}
|
||||
return jni::jni_true;
|
||||
}
|
||||
|
||||
jni::Local<jni::Object<gson::JsonObject>> Source::getFeatureState(JNIEnv& env,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId) {
|
||||
if (!rendererFrontend || !featureId) {
|
||||
return jni::Local<jni::Object<gson::JsonObject>>();
|
||||
}
|
||||
|
||||
const auto state = rendererFrontend->getFeatureState(
|
||||
source.getID(),
|
||||
sourceLayerId ? std::optional<std::string>(jni::Make<std::string>(env, sourceLayerId)) : std::nullopt,
|
||||
jni::Make<std::string>(env, featureId));
|
||||
if (state.empty()) {
|
||||
return jni::Local<jni::Object<gson::JsonObject>>();
|
||||
}
|
||||
|
||||
return gson::JsonObject::New(env, state);
|
||||
}
|
||||
|
||||
jni::jboolean Source::removeFeatureState(JNIEnv& env,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId,
|
||||
const jni::String& stateKey) {
|
||||
if (!rendererFrontend) {
|
||||
return jni::jni_false;
|
||||
}
|
||||
|
||||
rendererFrontend->removeFeatureState(
|
||||
source.getID(),
|
||||
sourceLayerId ? std::optional<std::string>(jni::Make<std::string>(env, sourceLayerId)) : std::nullopt,
|
||||
featureId ? std::optional<std::string>(jni::Make<std::string>(env, featureId)) : std::nullopt,
|
||||
stateKey ? std::optional<std::string>(jni::Make<std::string>(env, stateKey)) : std::nullopt);
|
||||
if (map) {
|
||||
map->triggerRepaint();
|
||||
}
|
||||
return jni::jni_true;
|
||||
}
|
||||
|
||||
void Source::bindToMap(AndroidRendererFrontend& frontend, mbgl::Map& map) {
|
||||
rendererFrontend = &frontend;
|
||||
this->map = ↦
|
||||
}
|
||||
|
||||
void Source::releaseJavaPeer() {
|
||||
// We can't release the peer if the source was not removed from the map
|
||||
if (!ownedSource) {
|
||||
@@ -220,6 +284,7 @@ void Source::releaseJavaPeer() {
|
||||
javaPeer.reset();
|
||||
|
||||
rendererFrontend = nullptr;
|
||||
map = nullptr;
|
||||
}
|
||||
|
||||
void Source::registerNative(jni::JNIEnv& env) {
|
||||
@@ -242,7 +307,10 @@ void Source::registerNative(jni::JNIEnv& env) {
|
||||
METHOD(&Source::isVolatile, "nativeIsVolatile"),
|
||||
METHOD(&Source::setVolatile, "nativeSetVolatile"),
|
||||
METHOD(&Source::setMinimumTileUpdateInterval, "nativeSetMinimumTileUpdateInterval"),
|
||||
METHOD(&Source::getMinimumTileUpdateInterval, "nativeGetMinimumTileUpdateInterval"));
|
||||
METHOD(&Source::getMinimumTileUpdateInterval, "nativeGetMinimumTileUpdateInterval"),
|
||||
METHOD(&Source::setFeatureState, "nativeSetFeatureState"),
|
||||
METHOD(&Source::getFeatureState, "nativeGetFeatureState"),
|
||||
METHOD(&Source::removeFeatureState, "nativeRemoveFeatureState"));
|
||||
|
||||
// Register subclasses
|
||||
GeoJSONSource::registerNative(env);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "../value.hpp"
|
||||
#include "../../android_renderer_frontend.hpp"
|
||||
#include "../../gson/json_object.hpp"
|
||||
|
||||
#include <jni/jni.hpp>
|
||||
|
||||
@@ -19,7 +20,10 @@ public:
|
||||
static void registerNative(jni::JNIEnv&);
|
||||
|
||||
static const jni::Object<Source>& peerForCoreSource(jni::JNIEnv&, mbgl::style::Source&);
|
||||
static const jni::Object<Source>& peerForCoreSource(jni::JNIEnv&, mbgl::style::Source&, AndroidRendererFrontend&);
|
||||
static const jni::Object<Source>& peerForCoreSource(jni::JNIEnv&,
|
||||
mbgl::style::Source&,
|
||||
AndroidRendererFrontend&,
|
||||
mbgl::Map&);
|
||||
|
||||
/*
|
||||
* Called when a Java object is created for a core source that belongs to a map.
|
||||
@@ -62,6 +66,22 @@ public:
|
||||
|
||||
jni::Local<jni::Long> getMinimumTileUpdateInterval(JNIEnv&);
|
||||
|
||||
jni::jboolean setFeatureState(JNIEnv&,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId,
|
||||
const jni::Object<gson::JsonObject>& state);
|
||||
|
||||
jni::Local<jni::Object<gson::JsonObject>> getFeatureState(JNIEnv&,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId);
|
||||
|
||||
jni::jboolean removeFeatureState(JNIEnv&,
|
||||
const jni::String& sourceLayerId,
|
||||
const jni::String& featureId,
|
||||
const jni::String& stateKey);
|
||||
|
||||
void bindToMap(AndroidRendererFrontend&, mbgl::Map&);
|
||||
|
||||
protected:
|
||||
// Set on newly created sources until added to the map.
|
||||
std::unique_ptr<mbgl::style::Source> ownedSource;
|
||||
@@ -74,6 +94,9 @@ protected:
|
||||
|
||||
// RendererFrontend pointer is valid only when added to the map.
|
||||
AndroidRendererFrontend* rendererFrontend{nullptr};
|
||||
|
||||
// Map pointer is valid only when added to the map.
|
||||
mbgl::Map* map{nullptr};
|
||||
};
|
||||
|
||||
} // namespace android
|
||||
|
||||
Reference in New Issue
Block a user