diff options
7 files changed, 223 insertions, 7 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index 0529489783..5a505af959 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -10,6 +10,7 @@ dependencies { api (dependenciesList.mapboxAndroidGestures) { exclude group: 'com.android.support', module: 'appcompat-v7' } + implementation dependenciesList.mapboxJavaTurf implementation dependenciesList.supportAnnotations implementation dependenciesList.supportFragmentV4 implementation dependenciesList.timber diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java new file mode 100644 index 0000000000..0db3ee3202 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java @@ -0,0 +1,128 @@ +package com.mapbox.mapboxsdk.offline; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.Geometry; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.turf.TurfMeasurement; + +/** + * An offline region defined by a style URL, geometry, zoom range, and + * device pixel ratio. + * <p> + * Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom. + * <p> + * maxZoom may be ∞, in which case for each tile source, the region will include + * tiles from minZoom up to the maximum zoom level provided by that source. + * <p> + * pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0. + */ +public class OfflineGeometryRegionDefinition implements OfflineRegionDefinition, Parcelable { + + private String styleURL; + private Geometry geometry; + private double minZoom; + private double maxZoom; + private float pixelRatio; + + /** + * Constructor to create an OfflineGeometryRegionDefinition from parameters. + * + * @param styleURL the style + * @param geometry the geometry + * @param minZoom min zoom + * @param maxZoom max zoom + * @param pixelRatio pixel ratio of the device + */ + public OfflineGeometryRegionDefinition( + String styleURL, Geometry geometry, double minZoom, double maxZoom, float pixelRatio) { + // Note: Also used in JNI + this.styleURL = styleURL; + this.geometry = geometry; + this.minZoom = minZoom; + this.maxZoom = maxZoom; + this.pixelRatio = pixelRatio; + } + + /** + * Constructor to create an OfflineGeometryRegionDefinition from a Parcel. + * + * @param parcel the parcel to create the OfflineGeometryRegionDefinition from + */ + public OfflineGeometryRegionDefinition(Parcel parcel) { + this.styleURL = parcel.readString(); + this.geometry = Feature.fromJson(parcel.readString()).geometry(); + this.minZoom = parcel.readDouble(); + this.maxZoom = parcel.readDouble(); + this.pixelRatio = parcel.readFloat(); + } + + /* + * Getters + */ + + public String getStyleURL() { + return styleURL; + } + + public Geometry getGeometry() { + return geometry; + } + + /** + * Calculates the bounding box for the Geometry it contains + * to retain backwards compatibility + * @return the {@link LatLngBounds} or null + */ + @Override + public LatLngBounds getBounds() { + if (geometry == null) { + return null; + } + + double[] bbox = TurfMeasurement.bbox(geometry); + return LatLngBounds.from(bbox[3], bbox[2], bbox[1], bbox[0]); + } + + public double getMinZoom() { + return minZoom; + } + + public double getMaxZoom() { + return maxZoom; + } + + public float getPixelRatio() { + return pixelRatio; + } + + /* + * Parceable + */ + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(styleURL); + dest.writeString(Feature.fromGeometry(geometry).toJson()); + dest.writeDouble(minZoom); + dest.writeDouble(maxZoom); + dest.writeFloat(pixelRatio); + } + + public static final Creator CREATOR = new Creator() { + public OfflineGeometryRegionDefinition createFromParcel(Parcel in) { + return new OfflineGeometryRegionDefinition(in); + } + + public OfflineGeometryRegionDefinition[] newArray(int size) { + return new OfflineGeometryRegionDefinition[size]; + } + }; +} diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index beb2c14eb3..18b966e261 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -180,6 +180,7 @@ void registerNatives(JavaVM *vm) { OfflineRegion::registerNative(env); OfflineRegionDefinition::registerNative(env); OfflineTilePyramidRegionDefinition::registerNative(env); + OfflineGeometryRegionDefinition::registerNative(env); OfflineRegionError::registerNative(env); OfflineRegionStatus::registerNative(env); diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp index 4f94a1c3a5..e96ed7e4d2 100644 --- a/platform/android/src/offline/offline_manager.cpp +++ b/platform/android/src/offline/offline_manager.cpp @@ -48,9 +48,7 @@ void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, jni::Array<jni::jbyte> metadata_, jni::Object<CreateOfflineRegionCallback> callback_) { // Convert - - // XXX hardcoded cast for now as we only support OfflineTilePyramidRegionDefinition - auto definition = OfflineTilePyramidRegionDefinition::getDefinition(env_, jni::Object<OfflineTilePyramidRegionDefinition>(*definition_)); + auto definition = OfflineRegionDefinition::getDefinition(env_, definition_); mbgl::OfflineRegionMetadata metadata; if (metadata_) { @@ -152,7 +150,7 @@ void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env, jni::Object<FileSource> jFileSource, jni::Object<OfflineManager::CreateOfflineRegionCallback> callback, mbgl::optional<mbgl::OfflineRegion> region) { - //Convert the region to java peer object + // Convert the region to java peer object auto jregion = OfflineRegion::New(env, jFileSource, std::move(*region)); // Trigger callback diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp index fe4dbecf14..5ed37eda73 100644 --- a/platform/android/src/offline/offline_region.cpp +++ b/platform/android/src/offline/offline_region.cpp @@ -159,7 +159,14 @@ void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, jni::Array<jn jni::Object<OfflineRegion> OfflineRegion::New(jni::JNIEnv& env, jni::Object<FileSource> jFileSource, mbgl::OfflineRegion region) { // Definition - auto definition = jni::Object<OfflineRegionDefinition>(*OfflineTilePyramidRegionDefinition::New(env, region.getDefinition())); + auto definition = region.getDefinition().match( + [&](const mbgl::OfflineTilePyramidRegionDefinition def) { + return jni::Object<OfflineRegionDefinition>( + *OfflineTilePyramidRegionDefinition::New(env, def)); + }, [&](const mbgl::OfflineGeometryRegionDefinition def) { + return jni::Object<OfflineRegionDefinition>( + *OfflineGeometryRegionDefinition::New(env, def)); + }); // Metadata auto metadata = OfflineRegion::metadata(env, region.getMetadata()); diff --git a/platform/android/src/offline/offline_region_definition.cpp b/platform/android/src/offline/offline_region_definition.cpp index 66a9bdf99d..a856672902 100644 --- a/platform/android/src/offline/offline_region_definition.cpp +++ b/platform/android/src/offline/offline_region_definition.cpp @@ -1,6 +1,9 @@ #include "offline_region_definition.hpp" #include "../geometry/lat_lng_bounds.hpp" +#include "../geojson/geometry.hpp" + +#include <exception> namespace mbgl { namespace android { @@ -13,9 +16,21 @@ void OfflineRegionDefinition::registerNative(jni::JNIEnv& env) { javaClass = *jni::Class<OfflineRegionDefinition>::Find(env).NewGlobalRef(env).release(); } +mbgl::OfflineRegionDefinition OfflineRegionDefinition::getDefinition(JNIEnv& env, + jni::Object<OfflineRegionDefinition> jDefinition) { + + if (jDefinition.IsInstanceOf(env, OfflineTilePyramidRegionDefinition::javaClass)) { + return OfflineTilePyramidRegionDefinition::getDefinition(env, jni::Object<OfflineTilePyramidRegionDefinition>(*jDefinition)); + } else if (jDefinition.IsInstanceOf(env, OfflineGeometryRegionDefinition::javaClass)) { + return OfflineGeometryRegionDefinition::getDefinition(env, jni::Object<OfflineGeometryRegionDefinition>(*jDefinition)); + } + + throw std::runtime_error("Unknown offline region definition java class"); +} + // OfflineTilePyramidRegionDefinition // -jni::Object<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, mbgl::OfflineTilePyramidRegionDefinition definition) { +jni::Object<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineTilePyramidRegionDefinition& definition) { //Convert objects auto styleURL = jni::Make<jni::String>(env, definition.styleURL); @@ -65,5 +80,56 @@ void OfflineTilePyramidRegionDefinition::registerNative(jni::JNIEnv& env) { javaClass = *jni::Class<OfflineTilePyramidRegionDefinition>::Find(env).NewGlobalRef(env).release(); } +// OfflineGeometryRegionDefinition // + +jni::Object<OfflineGeometryRegionDefinition> OfflineGeometryRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineGeometryRegionDefinition& definition) { + //Convert objects + auto styleURL = jni::Make<jni::String>(env, definition.styleURL); + auto geometry = geojson::Geometry::New(env, definition.geometry); + + static auto constructor = javaClass.GetConstructor<jni::String, jni::Object<geojson::Geometry>, jni::jdouble, jni::jdouble, jni::jfloat>(env); + auto jdefinition = javaClass.New(env, constructor, styleURL, geometry, definition.minZoom, definition.maxZoom, definition.pixelRatio); + + //Delete References + jni::DeleteLocalRef(env, styleURL); + jni::DeleteLocalRef(env, geometry); + + return jdefinition; +} + +mbgl::OfflineGeometryRegionDefinition OfflineGeometryRegionDefinition::getDefinition(jni::JNIEnv& env, jni::Object<OfflineGeometryRegionDefinition> jDefinition) { + // Field references + static auto styleURLF = javaClass.GetField<jni::String>(env, "styleURL"); + static auto geometryF = javaClass.GetField<jni::Object<geojson::Geometry>>(env, "geometry"); + static auto minZoomF = javaClass.GetField<jni::jdouble>(env, "minZoom"); + static auto maxZoomF = javaClass.GetField<jni::jdouble>(env, "maxZoom"); + static auto pixelRatioF = javaClass.GetField<jni::jfloat>(env, "pixelRatio"); + + // Get objects + auto jStyleURL = jDefinition.Get(env, styleURLF); + auto jGeometry = jDefinition.Get(env, geometryF); + + // Create definition + mbgl::OfflineGeometryRegionDefinition definition( + jni::Make<std::string>(env, jStyleURL), + geojson::Geometry::convert(env, jGeometry), + jDefinition.Get(env, minZoomF), + jDefinition.Get(env, maxZoomF), + jDefinition.Get(env, pixelRatioF) + ); + + // Delete references + jni::DeleteLocalRef(env, jStyleURL); + jni::DeleteLocalRef(env, jGeometry); + + return definition; +} + +jni::Class<OfflineGeometryRegionDefinition> OfflineGeometryRegionDefinition::javaClass; + +void OfflineGeometryRegionDefinition::registerNative(jni::JNIEnv& env) { + javaClass = *jni::Class<OfflineGeometryRegionDefinition>::Find(env).NewGlobalRef(env).release(); +} + } // namespace android } // namespace mbgl diff --git a/platform/android/src/offline/offline_region_definition.hpp b/platform/android/src/offline/offline_region_definition.hpp index 2ca82a4d96..a9dfb54634 100644 --- a/platform/android/src/offline/offline_region_definition.hpp +++ b/platform/android/src/offline/offline_region_definition.hpp @@ -14,13 +14,14 @@ public: static void registerNative(jni::JNIEnv&); + static mbgl::OfflineRegionDefinition getDefinition(JNIEnv& env, jni::Object<OfflineRegionDefinition> jDefinition); }; class OfflineTilePyramidRegionDefinition: public OfflineRegionDefinition { public: static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition"; }; - static jni::Object<OfflineTilePyramidRegionDefinition> New(jni::JNIEnv&, mbgl::OfflineTilePyramidRegionDefinition); + static jni::Object<OfflineTilePyramidRegionDefinition> New(jni::JNIEnv&, const mbgl::OfflineTilePyramidRegionDefinition&); static mbgl::OfflineTilePyramidRegionDefinition getDefinition(jni::JNIEnv&, jni::Object<OfflineTilePyramidRegionDefinition>); @@ -30,5 +31,19 @@ public: }; +class OfflineGeometryRegionDefinition: public OfflineRegionDefinition { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition"; }; + + static jni::Object<OfflineGeometryRegionDefinition> New(jni::JNIEnv&, const mbgl::OfflineGeometryRegionDefinition&); + + static mbgl::OfflineGeometryRegionDefinition getDefinition(jni::JNIEnv&, jni::Object<OfflineGeometryRegionDefinition>); + + static jni::Class<OfflineGeometryRegionDefinition> javaClass; + + static void registerNative(jni::JNIEnv&); + +}; + } // namespace android } // namespace mbgl |