summaryrefslogtreecommitdiff
path: root/platform/android/src/offline
diff options
context:
space:
mode:
authorIvo van Dongen <info@ivovandongen.nl>2017-02-16 16:16:47 +0200
committerIvo van Dongen <ivovandongen@users.noreply.github.com>2017-02-24 17:54:20 +0200
commit465c949153a838bb3159204ab268eb551fbd2e6c (patch)
tree250922b879261580b1252a78b461218be9012bc0 /platform/android/src/offline
parent7d9018093a61d327fa7ca1312845d2a00d928380 (diff)
downloadqtlocation-mapboxgl-465c949153a838bb3159204ab268eb551fbd2e6c.tar.gz
[android] jni high level binding refactor
Diffstat (limited to 'platform/android/src/offline')
-rw-r--r--platform/android/src/offline/offline_manager.cpp164
-rw-r--r--platform/android/src/offline/offline_manager.hpp75
-rw-r--r--platform/android/src/offline/offline_region.cpp308
-rw-r--r--platform/android/src/offline/offline_region.hpp99
-rw-r--r--platform/android/src/offline/offline_region_definition.cpp69
-rw-r--r--platform/android/src/offline/offline_region_definition.hpp34
-rw-r--r--platform/android/src/offline/offline_region_error.cpp53
-rw-r--r--platform/android/src/offline/offline_region_error.hpp21
-rw-r--r--platform/android/src/offline/offline_region_status.cpp39
-rw-r--r--platform/android/src/offline/offline_region_status.hpp21
10 files changed, 883 insertions, 0 deletions
diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp
new file mode 100644
index 0000000000..02871e7fdf
--- /dev/null
+++ b/platform/android/src/offline/offline_manager.cpp
@@ -0,0 +1,164 @@
+#include "offline_manager.hpp"
+
+#include <mbgl/util/string.hpp>
+
+#include "../attach_env.hpp"
+#include "../jni/generic_global_ref_deleter.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineManager //
+
+OfflineManager::OfflineManager(jni::JNIEnv& env, jni::Object<FileSource> jFileSource)
+ : fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {
+}
+
+OfflineManager::~OfflineManager() {}
+
+void OfflineManager::setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit) {
+ fileSource.setOfflineMapboxTileCountLimit(limit);
+}
+
+void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, jni::Object<FileSource> jFileSource_, jni::Object<ListOfflineRegionsCallback> callback_) {
+ // list regions
+ fileSource.listOfflineRegions([
+ //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()),
+ jFileSource = std::shared_ptr<jni::jobject>(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) mutable {
+
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineManager::ListOfflineRegionsCallback::onError(*env, jni::Object<ListOfflineRegionsCallback>(*callback), error);
+ } else if (regions) {
+ OfflineManager::ListOfflineRegionsCallback::onList(*env, jni::Object<FileSource>(*jFileSource), jni::Object<ListOfflineRegionsCallback>(*callback), std::move(regions));
+ }
+ });
+}
+
+void OfflineManager::createOfflineRegion(jni::JNIEnv& env_,
+ jni::Object<FileSource> jFileSource_,
+ jni::Object<OfflineRegionDefinition> definition_,
+ 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_));
+
+ mbgl::OfflineRegionMetadata metadata;
+ if (metadata_) {
+ metadata = OfflineRegion::metadata(env_, metadata_);
+ }
+
+ // Create region
+ fileSource.createOfflineRegion(definition, metadata, [
+ //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()),
+ jFileSource = std::shared_ptr<jni::jobject>(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegion> region) mutable {
+
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineManager::CreateOfflineRegionCallback::onError(*env, jni::Object<CreateOfflineRegionCallback>(*callback), error);
+ } else if (region) {
+ OfflineManager::CreateOfflineRegionCallback::onCreate(
+ *env,
+ jni::Object<FileSource>(*jFileSource),
+ jni::Object<CreateOfflineRegionCallback>(*callback), std::move(region)
+ );
+ }
+ });
+}
+
+jni::Class<OfflineManager> OfflineManager::javaClass;
+
+void OfflineManager::registerNative(jni::JNIEnv& env) {
+ OfflineManager::ListOfflineRegionsCallback::registerNative(env);
+ OfflineManager::CreateOfflineRegionCallback::registerNative(env);
+
+ javaClass = *jni::Class<OfflineManager>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ jni::RegisterNativePeer<OfflineManager>( env, javaClass, "nativePtr",
+ std::make_unique<OfflineManager, JNIEnv&, jni::Object<FileSource>>,
+ "initialize",
+ "finalize",
+ METHOD(&OfflineManager::setOfflineMapboxTileCountLimit, "setOfflineMapboxTileCountLimit"),
+ METHOD(&OfflineManager::listOfflineRegions, "listOfflineRegions"),
+ METHOD(&OfflineManager::createOfflineRegion, "createOfflineRegion"));
+}
+
+// OfflineManager::ListOfflineRegionsCallback //
+
+void OfflineManager::ListOfflineRegionsCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineManager::ListOfflineRegionsCallback::onList(jni::JNIEnv& env,
+ jni::Object<FileSource> jFileSource,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback> callback,
+ mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) {
+ //Convert the regions to java peer objects
+ std::size_t index = 0;
+ auto jregions = jni::Array<jni::Object<OfflineRegion>>::New(env, regions->size(), OfflineRegion::javaClass);
+ for (auto& region : *regions) {
+ auto jregion = OfflineRegion::New(env, jFileSource, std::move(region));
+ jregions.Set(env, index, jregion);
+ jni::DeleteLocalRef(env, jregion);
+ index++;
+ }
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Array<jni::Object<OfflineRegion>>)>(env, "onList");
+ callback.Call(env, method, jregions);
+ jni::DeleteLocalRef(env, jregions);
+}
+
+jni::Class<OfflineManager::ListOfflineRegionsCallback> OfflineManager::ListOfflineRegionsCallback::javaClass;
+
+void OfflineManager::ListOfflineRegionsCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineManager::ListOfflineRegionsCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineManager::CreateOfflineRegionCallback //
+
+void OfflineManager::CreateOfflineRegionCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+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
+ auto jregion = OfflineRegion::New(env, jFileSource, std::move(*region));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Object<OfflineRegion>)>(env, "onCreate");
+ callback.Call(env, method, jregion);
+ jni::DeleteLocalRef(env, jregion);
+}
+
+jni::Class<OfflineManager::CreateOfflineRegionCallback> OfflineManager::CreateOfflineRegionCallback::javaClass;
+
+void OfflineManager::CreateOfflineRegionCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineManager::CreateOfflineRegionCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_manager.hpp b/platform/android/src/offline/offline_manager.hpp
new file mode 100644
index 0000000000..9ae2714ca2
--- /dev/null
+++ b/platform/android/src/offline/offline_manager.hpp
@@ -0,0 +1,75 @@
+#pragma once
+
+
+#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+#include "../file_source.hpp"
+#include "offline_region.hpp"
+#include "offline_region_definition.hpp"
+
+
+namespace mbgl {
+namespace android {
+
+class OfflineManager {
+public:
+
+ class ListOfflineRegionsCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback";}
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineManager::ListOfflineRegionsCallback>, std::exception_ptr);
+
+ static void onList(jni::JNIEnv&,
+ jni::Object<FileSource>,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback>,
+ mbgl::optional<std::vector<mbgl::OfflineRegion>>);
+
+ static jni::Class<OfflineManager::ListOfflineRegionsCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class CreateOfflineRegionCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback"; }
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineManager::CreateOfflineRegionCallback>, std::exception_ptr);
+
+ static void onCreate(jni::JNIEnv&,
+ jni::Object<FileSource>,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback>,
+ mbgl::optional<mbgl::OfflineRegion>);
+
+ static jni::Class<OfflineManager::CreateOfflineRegionCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager"; };
+
+ static jni::Class<OfflineManager> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ OfflineManager(jni::JNIEnv&, jni::Object<FileSource>);
+ ~OfflineManager();
+
+ void setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit);
+
+ void listOfflineRegions(jni::JNIEnv&, jni::Object<FileSource>, jni::Object<ListOfflineRegionsCallback> callback);
+
+ void createOfflineRegion(jni::JNIEnv&,
+ jni::Object<FileSource> jFileSource_,
+ jni::Object<OfflineRegionDefinition> definition,
+ jni::Array<jni::jbyte> metadata,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback> callback);
+
+private:
+ mbgl::DefaultFileSource& fileSource;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp
new file mode 100644
index 0000000000..856434d266
--- /dev/null
+++ b/platform/android/src/offline/offline_region.cpp
@@ -0,0 +1,308 @@
+#include "offline_region.hpp"
+
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/string.hpp>
+
+#include "offline_region_definition.hpp"
+#include "offline_region_error.hpp"
+#include "offline_region_status.hpp"
+#include "../attach_env.hpp"
+#include "../jni/generic_global_ref_deleter.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineRegion //
+
+OfflineRegion::OfflineRegion(jni::JNIEnv& env, jni::jlong offlineRegionPtr, jni::Object<FileSource> jFileSource)
+ : region(reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr)),
+ fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {}
+
+OfflineRegion::~OfflineRegion() {}
+
+void OfflineRegion::setOfflineRegionObserver(jni::JNIEnv& env_, jni::Object<OfflineRegion::OfflineRegionObserver> callback) {
+
+ // Define the observer
+ class Observer : public mbgl::OfflineRegionObserver {
+ public:
+ Observer(jni::UniqueObject<OfflineRegion::OfflineRegionObserver>&& callback_)
+ //TODO add a generic deleter for jni::Object
+ : callback(callback_.release()->Get()) {
+ }
+
+ ~Observer() override {
+ android::UniqueEnv env = android::AttachEnv();
+ env->DeleteGlobalRef(Unwrap(*callback));
+ }
+
+ void statusChanged(mbgl::OfflineRegionStatus status) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Status object
+ auto jStatus = OfflineRegionStatus::New(*env, status);
+
+ // Call
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::Object<OfflineRegionStatus>)>(*env, "onStatusChanged");
+ callback.Call(*env, method, jStatus);
+
+ // Delete references
+ jni::DeleteLocalRef(*env, jStatus);
+ }
+
+ void responseError(mbgl::Response::Error error) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Error object
+ auto jError = OfflineRegionError::New(*env, error);
+
+ // Call
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::Object<mbgl::android::OfflineRegionError>)>(*env, "onError");
+ callback.Call(*env, method, jError);
+
+ // Delete references
+ jni::DeleteLocalRef(*env, jError);
+ }
+
+ void mapboxTileCountLimitExceeded(uint64_t limit) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Send limit
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::jlong)>(*env, "mapboxTileCountLimitExceeded");
+ callback.Call(*env, method, jlong(limit));
+ }
+
+ jni::Object<OfflineRegion::OfflineRegionObserver> callback;
+ };
+
+ // Set the observer
+ fileSource.setOfflineRegionObserver(*region, std::make_unique<Observer>(callback.NewGlobalRef(env_)));
+}
+
+void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState) {
+ // State
+ mbgl::OfflineRegionDownloadState state;
+ switch (jState) {
+ case 0:
+ state = mbgl::OfflineRegionDownloadState::Inactive;
+ break;
+ case 1:
+ state = mbgl::OfflineRegionDownloadState::Active;
+ break;
+ default:
+ mbgl::Log::Error(mbgl::Event::JNI, "State can only be 0 (inactive) or 1 (active).");
+ return;
+ }
+
+ fileSource.setOfflineRegionDownloadState(*region, state);
+}
+
+void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, jni::Object<OfflineRegionStatusCallback> callback_) {
+
+ fileSource.getOfflineRegionStatus(*region, [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionStatus> status) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionStatusCallback::onError(*env, jni::Object<OfflineRegionStatusCallback>(*callback), error);
+ } else if (status) {
+ OfflineRegionStatusCallback::onStatus(*env, jni::Object<OfflineRegionStatusCallback>(*callback), std::move(status));
+ }
+ });
+}
+
+void OfflineRegion::deleteOfflineRegion(jni::JNIEnv& env_, jni::Object<OfflineRegionDeleteCallback> callback_) {
+ // Delete
+ fileSource.deleteOfflineRegion(std::move(*region), [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionDeleteCallback::onError(*env, jni::Object<OfflineRegionDeleteCallback>(*callback), error);
+ } else {
+ OfflineRegionDeleteCallback::onDelete(*env, jni::Object<OfflineRegionDeleteCallback>(*callback));
+ }
+ });
+}
+
+void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, jni::Array<jni::jbyte> jMetadata, jni::Object<OfflineRegionUpdateMetadataCallback> callback_) {
+
+ // Convert
+ auto metadata = OfflineRegion::metadata(env_, jMetadata);
+
+ fileSource.updateOfflineMetadata(region->getID(), metadata, [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionMetadata> data) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionUpdateMetadataCallback::onError(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), error);
+ } else if (data) {
+ OfflineRegionUpdateMetadataCallback::onUpdate(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), std::move(data));
+ }
+ });
+}
+
+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()));
+
+ // Metadata
+ auto metadata = OfflineRegion::metadata(env, region.getMetadata());
+
+ // Create region java object
+ static auto constructor = OfflineRegion::javaClass.GetConstructor<jni::jlong, jni::Object<FileSource>, jni::jlong, jni::Object<OfflineRegionDefinition>, jni::Array<jni::jbyte>>(env);
+ auto jregion = OfflineRegion::javaClass.New(env, constructor,
+ reinterpret_cast<jni::jlong>(new mbgl::OfflineRegion(std::move(region))), //Copy a region to the heap
+ jFileSource, jni::jlong(region.getID()), definition, metadata);
+
+ //Delete references
+ jni::DeleteLocalRef(env, definition);
+ jni::DeleteLocalRef(env, metadata);
+
+ return jregion;
+}
+
+jni::Array<jni::jbyte> OfflineRegion::metadata(jni::JNIEnv& env, mbgl::OfflineRegionMetadata metadata_) {
+ std::vector<jni::jbyte> convertedMetadata(metadata_.begin(), metadata_.end());
+ std::size_t length = static_cast<std::size_t>(convertedMetadata.size());
+ auto metadata = jni::Array<jni::jbyte>::New(env, length);
+ metadata.SetRegion<std::vector<jni::jbyte>>(env, 0, convertedMetadata);
+ return metadata;
+}
+
+mbgl::OfflineRegionMetadata OfflineRegion::metadata(jni::JNIEnv& env, jni::Array<jni::jbyte> metadata_) {
+ std::size_t length = metadata_.Length(env);
+ auto metadata_tmp = std::vector<jni::jbyte>();
+ metadata_tmp.resize(length);
+ metadata_.GetRegion<std::vector<jni::jbyte>>(env, 0, metadata_tmp);
+ auto metadata = std::vector<uint8_t>(metadata_tmp.begin(), metadata_tmp.end());
+ return metadata;
+}
+
+jni::Class<OfflineRegion> OfflineRegion::javaClass;
+
+void OfflineRegion::registerNative(jni::JNIEnv& env) {
+ OfflineRegion::OfflineRegionObserver::registerNative(env);
+ OfflineRegion::OfflineRegionStatusCallback::registerNative(env);
+ OfflineRegion::OfflineRegionDeleteCallback::registerNative(env);
+ OfflineRegion::OfflineRegionUpdateMetadataCallback::registerNative(env);
+
+ javaClass = *jni::Class<OfflineRegion>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ jni::RegisterNativePeer<OfflineRegion>( env, javaClass, "nativePtr",
+ std::make_unique<OfflineRegion, JNIEnv&, jni::jlong, jni::Object<FileSource>>,
+ "initialize",
+ "finalize",
+ METHOD(&OfflineRegion::setOfflineRegionObserver, "setOfflineRegionObserver"),
+ METHOD(&OfflineRegion::setOfflineRegionDownloadState, "setOfflineRegionDownloadState"),
+ METHOD(&OfflineRegion::getOfflineRegionStatus, "getOfflineRegionStatus"),
+ METHOD(&OfflineRegion::deleteOfflineRegion, "deleteOfflineRegion"),
+ METHOD(&OfflineRegion::updateOfflineRegionMetadata, "updateOfflineRegionMetadata")
+ );
+}
+
+// OfflineRegionObserver //
+
+jni::Class<OfflineRegion::OfflineRegionObserver> OfflineRegion::OfflineRegionObserver::javaClass;
+
+void OfflineRegion::OfflineRegionObserver::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegion::OfflineRegionObserver>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineRegionStatusCallback //
+
+jni::Class<OfflineRegion::OfflineRegionStatusCallback> OfflineRegion::OfflineRegionStatusCallback::javaClass;
+
+void OfflineRegion::OfflineRegionStatusCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionStatusCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionStatusCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionStatusCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineRegion::OfflineRegionStatusCallback::onStatus(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionStatusCallback> callback,
+ mbgl::optional<mbgl::OfflineRegionStatus> status) {
+ //Convert to java peer object
+ auto jStatus = OfflineRegionStatus::New(env, std::move(*status));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Object<OfflineRegionStatus>)>(env, "onStatus");
+ callback.Call(env, method, jStatus);
+ jni::DeleteLocalRef(env, jStatus);
+}
+
+// OfflineRegionDeleteCallback //
+
+jni::Class<OfflineRegion::OfflineRegionDeleteCallback> OfflineRegion::OfflineRegionDeleteCallback::javaClass;
+
+void OfflineRegion::OfflineRegionDeleteCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionDeleteCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionDeleteCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionDeleteCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineRegion::OfflineRegionDeleteCallback::onDelete(jni::JNIEnv& env, jni::Object<OfflineRegion::OfflineRegionDeleteCallback> callback) {
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void ()>(env, "onDelete");
+ callback.Call(env, method);
+}
+
+// OfflineRegionUpdateMetadataCallback //
+
+jni::Class<OfflineRegion::OfflineRegionUpdateMetadataCallback> OfflineRegion::OfflineRegionUpdateMetadataCallback::javaClass;
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionUpdateMetadataCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionUpdateMetadataCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::onUpdate(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionUpdateMetadataCallback> callback,
+ mbgl::optional<mbgl::OfflineRegionMetadata> metadata) {
+ //Convert to java peer object
+ auto jMetadata = OfflineRegion::metadata(env, std::move(*metadata));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Array<jni::jbyte>)>(env, "onUpdate");
+ callback.Call(env, method, jMetadata);
+ jni::DeleteLocalRef(env, jMetadata);
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region.hpp b/platform/android/src/offline/offline_region.hpp
new file mode 100644
index 0000000000..c05383a91a
--- /dev/null
+++ b/platform/android/src/offline/offline_region.hpp
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+#include "../file_source.hpp"
+
+#include <memory>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegion {
+public:
+ class OfflineRegionObserver {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver"; };
+
+ static jni::Class<OfflineRegionObserver> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionStatusCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionStatusCallback>, std::exception_ptr);
+
+ static void onStatus(jni::JNIEnv&,
+ jni::Object<OfflineRegionStatusCallback>,
+ mbgl::optional<mbgl::OfflineRegionStatus>);
+
+ static jni::Class<OfflineRegionStatusCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionDeleteCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>, std::exception_ptr);
+
+ static void onDelete(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>);
+
+ static jni::Class<OfflineRegionDeleteCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionUpdateMetadataCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionUpdateMetadataCallback>, std::exception_ptr);
+
+ static void onUpdate(jni::JNIEnv&,
+ jni::Object<OfflineRegionUpdateMetadataCallback>,
+ mbgl::optional<mbgl::OfflineRegionMetadata>);
+
+ static jni::Class<OfflineRegionUpdateMetadataCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion"; };
+
+ OfflineRegion(jni::JNIEnv&, jni::jlong, jni::Object<FileSource>);
+
+ ~OfflineRegion();
+
+ void setOfflineRegionObserver(jni::JNIEnv&, jni::Object<OfflineRegion::OfflineRegionObserver>);
+
+ void setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint);
+
+ void getOfflineRegionStatus(jni::JNIEnv&, jni::Object<OfflineRegion::OfflineRegionStatusCallback>);
+
+ void deleteOfflineRegion(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>);
+
+ void updateOfflineRegionMetadata(jni::JNIEnv&, jni::Array<jni::jbyte>, jni::Object<OfflineRegionUpdateMetadataCallback>);
+
+ static jni::Object<OfflineRegion> New(jni::JNIEnv&, jni::Object<FileSource>, mbgl::OfflineRegion);
+
+ static jni::Array<jni::jbyte> metadata(jni::JNIEnv&, mbgl::OfflineRegionMetadata);
+
+ static mbgl::OfflineRegionMetadata metadata(jni::JNIEnv&, jni::Array<jni::jbyte>);
+
+ static jni::Class<OfflineRegion> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+ std::unique_ptr<mbgl::OfflineRegion> region;
+ mbgl::DefaultFileSource& fileSource;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_definition.cpp b/platform/android/src/offline/offline_region_definition.cpp
new file mode 100644
index 0000000000..66a9bdf99d
--- /dev/null
+++ b/platform/android/src/offline/offline_region_definition.cpp
@@ -0,0 +1,69 @@
+#include "offline_region_definition.hpp"
+
+#include "../geometry/lat_lng_bounds.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineRegionDefinition //
+
+jni::Class<OfflineRegionDefinition> OfflineRegionDefinition::javaClass;
+
+void OfflineRegionDefinition::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionDefinition>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineTilePyramidRegionDefinition //
+
+jni::Object<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, mbgl::OfflineTilePyramidRegionDefinition definition) {
+
+ //Convert objects
+ auto styleURL = jni::Make<jni::String>(env, definition.styleURL);
+ auto bounds = LatLngBounds::New(env, definition.bounds);
+
+ static auto constructor = javaClass.GetConstructor<jni::String, jni::Object<LatLngBounds>, jni::jdouble, jni::jdouble, jni::jfloat>(env);
+ auto jdefinition = javaClass.New(env, constructor, styleURL, bounds, definition.minZoom, definition.maxZoom, definition.pixelRatio);
+
+ //Delete References
+ jni::DeleteLocalRef(env, styleURL);
+ jni::DeleteLocalRef(env, bounds);
+
+ return jdefinition;
+}
+
+mbgl::OfflineTilePyramidRegionDefinition OfflineTilePyramidRegionDefinition::getDefinition(jni::JNIEnv& env, jni::Object<OfflineTilePyramidRegionDefinition> jDefinition) {
+ // Field references
+ static auto styleURLF = javaClass.GetField<jni::String>(env, "styleURL");
+ static auto boundsF = javaClass.GetField<jni::Object<LatLngBounds>>(env, "bounds");
+ 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 jBounds = jDefinition.Get(env, boundsF);
+
+ // Create definition
+ mbgl::OfflineTilePyramidRegionDefinition definition(
+ jni::Make<std::string>(env, jStyleURL),
+ LatLngBounds::getLatLngBounds(env, jBounds),
+ jDefinition.Get(env, minZoomF),
+ jDefinition.Get(env, maxZoomF),
+ jDefinition.Get(env, pixelRatioF)
+ );
+
+ // Delete references
+ jni::DeleteLocalRef(env, jStyleURL);
+ jni::DeleteLocalRef(env, jBounds);
+
+ return definition;
+}
+
+jni::Class<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::javaClass;
+
+void OfflineTilePyramidRegionDefinition::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineTilePyramidRegionDefinition>::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
new file mode 100644
index 0000000000..2ca82a4d96
--- /dev/null
+++ b/platform/android/src/offline/offline_region_definition.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionDefinition {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionDefinition"; };
+
+ static jni::Class<OfflineRegionDefinition> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+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 mbgl::OfflineTilePyramidRegionDefinition getDefinition(jni::JNIEnv&, jni::Object<OfflineTilePyramidRegionDefinition>);
+
+ static jni::Class<OfflineTilePyramidRegionDefinition> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_error.cpp b/platform/android/src/offline/offline_region_error.cpp
new file mode 100644
index 0000000000..b0a19f934f
--- /dev/null
+++ b/platform/android/src/offline/offline_region_error.cpp
@@ -0,0 +1,53 @@
+#include "offline_region_error.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<OfflineRegionError> OfflineRegionError::New(jni::JNIEnv& env, mbgl::Response::Error error) {
+
+ // Handle the value of reason independently of the underlying int value
+ std::string reason;
+ switch(error.reason) {
+ case mbgl::Response::Error::Reason::Success:
+ reason = "REASON_SUCCESS";
+ break;
+ case mbgl::Response::Error::Reason::NotFound:
+ reason = "REASON_NOT_FOUND";
+ break;
+ case mbgl::Response::Error::Reason::Server:
+ reason = "REASON_SERVER";
+ break;
+ case mbgl::Response::Error::Reason::Connection:
+ reason = "REASON_CONNECTION";
+ break;
+ case mbgl::Response::Error::Reason::RateLimit:
+ reason = "REASON_RATE_LIMIT";
+ break;
+ case mbgl::Response::Error::Reason::Other:
+ reason = "REASON_OTHER";
+ break;
+ }
+
+ // Convert
+ auto jReason = jni::Make<jni::String>(env, reason);
+ auto jMessage = jni::Make<jni::String>(env, error.message);
+
+ // Create java object
+ static auto constructor = javaClass.GetConstructor<jni::String, jni::String>(env);
+ auto jError = javaClass.New(env, constructor, jReason, jMessage);
+
+ // Delete references
+ jni::DeleteLocalRef(env, jReason);
+ jni::DeleteLocalRef(env, jMessage);
+
+ return jError;
+}
+
+jni::Class<OfflineRegionError> OfflineRegionError::javaClass;
+
+void OfflineRegionError::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionError>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_error.hpp b/platform/android/src/offline/offline_region_error.hpp
new file mode 100644
index 0000000000..61efaca67e
--- /dev/null
+++ b/platform/android/src/offline/offline_region_error.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionError {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionError"; };
+
+ static jni::Object<OfflineRegionError> New(jni::JNIEnv&, mbgl::Response::Error);
+
+ static jni::Class<OfflineRegionError> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_status.cpp b/platform/android/src/offline/offline_region_status.cpp
new file mode 100644
index 0000000000..d0bbae124f
--- /dev/null
+++ b/platform/android/src/offline/offline_region_status.cpp
@@ -0,0 +1,39 @@
+#include "offline_region_status.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<OfflineRegionStatus> OfflineRegionStatus::New(jni::JNIEnv& env, mbgl::OfflineRegionStatus status) {
+
+ // Convert to jint
+ jint downloadState;
+ switch(status.downloadState) {
+ case mbgl::OfflineRegionDownloadState::Inactive:
+ downloadState = 0;
+ break;
+ case mbgl::OfflineRegionDownloadState::Active:
+ downloadState = 1;
+ break;
+ }
+
+ // Create java object
+ static auto constructor = javaClass.GetConstructor<jint, jlong, jlong, jlong, jlong, jlong, jboolean>(env);
+ return javaClass.New(env, constructor,
+ downloadState,
+ jlong(status.completedResourceCount),
+ jlong(status.completedResourceSize),
+ jlong(status.completedTileCount),
+ jlong(status.completedTileSize),
+ jlong(status.requiredResourceCount),
+ jboolean(status.requiredResourceCountIsPrecise)
+ );
+}
+
+jni::Class<OfflineRegionStatus> OfflineRegionStatus::javaClass;
+
+void OfflineRegionStatus::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionStatus>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_status.hpp b/platform/android/src/offline/offline_region_status.hpp
new file mode 100644
index 0000000000..b29a653655
--- /dev/null
+++ b/platform/android/src/offline/offline_region_status.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionStatus {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionStatus"; };
+
+ static jni::Object<OfflineRegionStatus> New(jni::JNIEnv&, mbgl::OfflineRegionStatus status);
+
+ static jni::Class<OfflineRegionStatus> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl