#include "offline_manager.hpp" #include #include "../attach_env.hpp" #include "../jni/generic_global_ref_deleter.hpp" namespace mbgl { namespace android { // OfflineManager // OfflineManager::OfflineManager(jni::JNIEnv& env, jni::Object 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 jFileSource_, jni::Object 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(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()), jFileSource = std::shared_ptr(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()) ](std::exception_ptr error, mbgl::optional> regions) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); if (error) { OfflineManager::ListOfflineRegionsCallback::onError(*env, jni::Object(*callback), error); } else if (regions) { OfflineManager::ListOfflineRegionsCallback::onList(*env, jni::Object(*jFileSource), jni::Object(*callback), std::move(regions)); } }); } void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, jni::Object jFileSource_, jni::Object definition_, jni::Array metadata_, jni::Object callback_) { // Convert // XXX hardcoded cast for now as we only support OfflineTilePyramidRegionDefinition auto definition = OfflineTilePyramidRegionDefinition::getDefinition(env_, jni::Object(*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(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()), jFileSource = std::shared_ptr(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()) ](std::exception_ptr error, mbgl::optional region) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); if (error) { OfflineManager::CreateOfflineRegionCallback::onError(*env, jni::Object(*callback), error); } else if (region) { OfflineManager::CreateOfflineRegionCallback::onCreate( *env, jni::Object(*jFileSource), jni::Object(*callback), std::move(region) ); } }); } jni::Class OfflineManager::javaClass; void OfflineManager::registerNative(jni::JNIEnv& env) { OfflineManager::ListOfflineRegionsCallback::registerNative(env); OfflineManager::CreateOfflineRegionCallback::registerNative(env); javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) jni::RegisterNativePeer( env, javaClass, "nativePtr", std::make_unique>, "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 callback, std::exception_ptr error) { static auto method = javaClass.GetMethod(env, "onError"); std::string message = mbgl::util::toString(error); callback.Call(env, method, jni::Make(env, message)); } void OfflineManager::ListOfflineRegionsCallback::onList(jni::JNIEnv& env, jni::Object jFileSource, jni::Object callback, mbgl::optional> regions) { //Convert the regions to java peer objects std::size_t index = 0; auto jregions = jni::Array>::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>)>(env, "onList"); callback.Call(env, method, jregions); jni::DeleteLocalRef(env, jregions); } jni::Class OfflineManager::ListOfflineRegionsCallback::javaClass; void OfflineManager::ListOfflineRegionsCallback::registerNative(jni::JNIEnv& env) { javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); } // OfflineManager::CreateOfflineRegionCallback // void OfflineManager::CreateOfflineRegionCallback::onError(jni::JNIEnv& env, jni::Object callback, std::exception_ptr error) { static auto method = javaClass.GetMethod(env, "onError"); std::string message = mbgl::util::toString(error); callback.Call(env, method, jni::Make(env, message)); } void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env, jni::Object jFileSource, jni::Object callback, mbgl::optional region) { //Convert the region to java peer object auto jregion = OfflineRegion::New(env, jFileSource, std::move(*region)); // Trigger callback static auto method = javaClass.GetMethod)>(env, "onCreate"); callback.Call(env, method, jregion); jni::DeleteLocalRef(env, jregion); } jni::Class OfflineManager::CreateOfflineRegionCallback::javaClass; void OfflineManager::CreateOfflineRegionCallback::registerNative(jni::JNIEnv& env) { javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); } } // namespace android } // namespace mbgl