#include "offline_manager.hpp" #include #include "../attach_env.hpp" namespace mbgl { namespace android { namespace { // Reattach, the callback comes from a different thread void handleException(std::exception_ptr exception, const jni::Object& callback, android::UniqueEnv env = android::AttachEnv()) { if (exception) { OfflineManager::FileSourceCallback::onError( *env, callback, jni::Make(*env, mbgl::util::toString(exception))); } else { OfflineManager::FileSourceCallback::onSuccess(*env, callback); } } } // namespace // OfflineManager // OfflineManager::OfflineManager(jni::JNIEnv& env, const jni::Object& jFileSource) : fileSource(std::static_pointer_cast(mbgl::FileSource::getSharedFileSource(FileSource::getSharedResourceOptions(env, jFileSource)))) {} OfflineManager::~OfflineManager() {} void OfflineManager::setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit) { fileSource->setOfflineMapboxTileCountLimit(limit); } void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, const jni::Object& jFileSource_, const jni::Object& callback_) { auto globalCallback = jni::NewGlobal(env_, callback_); auto globalFilesource = jni::NewGlobal(env_, jFileSource_); 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::make_shared(std::move(globalCallback)), jFileSource = std::make_shared(std::move(globalFilesource)) ](mbgl::expected regions) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); if (regions) { OfflineManager::ListOfflineRegionsCallback::onList( *env, *jFileSource, *callback, *regions); } else { OfflineManager::ListOfflineRegionsCallback::onError( *env, *callback, regions.error()); } }); } void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, const jni::Object& jFileSource_, const jni::Object& definition_, const jni::Array& metadata_, const jni::Object& callback_) { // Convert auto definition = OfflineRegionDefinition::getDefinition(env_, definition_); mbgl::OfflineRegionMetadata metadata; if (metadata_) { metadata = OfflineRegion::metadata(env_, metadata_); } auto globalCallback = jni::NewGlobal(env_, callback_); auto globalFilesource = jni::NewGlobal(env_, jFileSource_); // 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::make_shared(std::move(globalCallback)), jFileSource = std::make_shared(std::move(globalFilesource)) ](mbgl::expected region) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); if (region) { OfflineManager::CreateOfflineRegionCallback::onCreate( *env, *jFileSource, *callback, *region ); } else { OfflineManager::CreateOfflineRegionCallback::onError( *env, *callback, region.error()); } }); } void OfflineManager::mergeOfflineRegions(jni::JNIEnv& env_, const jni::Object& jFileSource_, const jni::String& jString_, const jni::Object& callback_) { auto globalCallback = jni::NewGlobal(env_, callback_); auto globalFilesource = jni::NewGlobal(env_, jFileSource_); auto path = jni::Make(env_, jString_); fileSource->mergeOfflineRegions(path, [ //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::make_shared(std::move(globalCallback)), jFileSource = std::make_shared(std::move(globalFilesource)) ](mbgl::expected regions) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); if (regions) { OfflineManager::MergeOfflineRegionsCallback::onMerge( *env, *jFileSource, *callback, *regions); } else { OfflineManager::MergeOfflineRegionsCallback::onError( *env, *callback, regions.error()); } }); } void OfflineManager::resetDatabase(jni::JNIEnv& env_, const jni::Object& callback_) { auto globalCallback = jni::NewGlobal(env_, callback_); fileSource->resetDatabase( [ // Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile callback = std::make_shared(std::move(globalCallback))]( std::exception_ptr exception) mutable { handleException(exception, *callback); }); } void OfflineManager::packDatabase(jni::JNIEnv& env_, const jni::Object& callback_) { auto globalCallback = jni::NewGlobal(env_, callback_); fileSource->packDatabase( [ // Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile callback = std::make_shared(std::move(globalCallback))]( std::exception_ptr exception) mutable { handleException(exception, *callback); }); } void OfflineManager::invalidateAmbientCache(jni::JNIEnv& env_, const jni::Object& callback_) { auto globalCallback = jni::NewGlobal(env_, callback_); fileSource->invalidateAmbientCache( [ // Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile callback = std::make_shared(std::move(globalCallback))]( std::exception_ptr exception) mutable { handleException(exception, *callback); }); } void OfflineManager::clearAmbientCache(jni::JNIEnv& env_, const jni::Object& callback_) { auto globalCallback = jni::NewGlobal(env_, callback_); fileSource->clearAmbientCache( [ // Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile callback = std::make_shared(std::move(globalCallback))]( std::exception_ptr exception) mutable { handleException(exception, *callback); }); } void OfflineManager::setMaximumAmbientCacheSize(jni::JNIEnv& env_, const jni::jlong size_, const jni::Object& callback_) { auto globalCallback = jni::NewGlobal(env_, callback_); fileSource->setMaximumAmbientCacheSize( size_, [ // Keep a shared ptr to a global reference of the callback so they are not GC'd in the meanwhile callback = std::make_shared(std::move(globalCallback))]( std::exception_ptr exception) mutable { handleException(exception, *callback); }); } // FileSource::FileSourceCallback // void OfflineManager::FileSourceCallback::onSuccess(jni::JNIEnv& env, const jni::Object& callback) { static auto& javaClass = jni::Class::Singleton(env); static auto method = javaClass.GetMethod(env, "onSuccess"); callback.Call(env, method); } void OfflineManager::FileSourceCallback::onError(jni::JNIEnv& env, const jni::Object& callback, const jni::String& message) { static auto& javaClass = jni::Class::Singleton(env); static auto method = javaClass.GetMethod(env, "onError"); callback.Call(env, method, message); } void OfflineManager::registerNative(jni::JNIEnv& env) { jni::Class::Singleton(env); jni::Class::Singleton(env); jni::Class::Singleton(env); jni::Class::Singleton(env); static auto& javaClass = jni::Class::Singleton(env); #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) jni::RegisterNativePeer( env, javaClass, "nativePtr", jni::MakePeer&>, "initialize", "finalize", METHOD(&OfflineManager::setOfflineMapboxTileCountLimit, "setOfflineMapboxTileCountLimit"), METHOD(&OfflineManager::listOfflineRegions, "listOfflineRegions"), METHOD(&OfflineManager::createOfflineRegion, "createOfflineRegion"), METHOD(&OfflineManager::mergeOfflineRegions, "mergeOfflineRegions"), METHOD(&OfflineManager::resetDatabase, "nativeResetDatabase"), METHOD(&OfflineManager::packDatabase, "nativePackDatabase"), METHOD(&OfflineManager::invalidateAmbientCache, "nativeInvalidateAmbientCache"), METHOD(&OfflineManager::clearAmbientCache, "nativeClearAmbientCache"), METHOD(&OfflineManager::setMaximumAmbientCacheSize, "nativeSetMaximumAmbientCacheSize"), METHOD(&OfflineManager::putResourceWithUrl, "putResourceWithUrl")); } // OfflineManager::ListOfflineRegionsCallback // void OfflineManager::ListOfflineRegionsCallback::onError(jni::JNIEnv& env, const jni::Object& callback, std::exception_ptr error) { static auto& javaClass = jni::Class::Singleton(env); static auto method = javaClass.GetMethod(env, "onError"); callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); } void OfflineManager::ListOfflineRegionsCallback::onList(jni::JNIEnv& env, const jni::Object& jFileSource, const jni::Object& callback, mbgl::OfflineRegions& regions) { static auto& javaClass = jni::Class::Singleton(env); static auto method = javaClass.GetMethod>)>(env, "onList"); std::size_t index = 0; auto jregions = jni::Array>::New(env, regions.size()); for (auto& region : regions) { jregions.Set(env, index, OfflineRegion::New(env, jFileSource, std::move(region))); index++; } callback.Call(env, method, jregions); } // OfflineManager::CreateOfflineRegionCallback // void OfflineManager::CreateOfflineRegionCallback::onError(jni::JNIEnv& env, const jni::Object& callback, std::exception_ptr error) { static auto& javaClass = jni::Class::Singleton(env); static auto method = javaClass.GetMethod(env, "onError"); callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); } void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env, const jni::Object& jFileSource, const jni::Object& callback, mbgl::OfflineRegion& region) { static auto& javaClass = jni::Class::Singleton(env); static auto method = javaClass.GetMethod)>(env, "onCreate"); callback.Call(env, method, OfflineRegion::New(env, jFileSource, std::move(region))); } // OfflineManager::MergeOfflineRegionsCallback // void OfflineManager::MergeOfflineRegionsCallback::onError(jni::JNIEnv& env, const jni::Object& callback, std::exception_ptr error) { static auto& javaClass = jni::Class::Singleton(env); static auto method = javaClass.GetMethod(env, "onError"); callback.Call(env, method, jni::Make(env, mbgl::util::toString(error))); } void OfflineManager::MergeOfflineRegionsCallback::onMerge(jni::JNIEnv& env, const jni::Object& jFileSource, const jni::Object& callback, mbgl::OfflineRegions& regions) { static auto& javaClass = jni::Class::Singleton(env); static auto method = javaClass.GetMethod>)>(env, "onMerge"); std::size_t index = 0; auto jregions = jni::Array>::New(env, regions.size()); for (auto& region : regions) { jregions.Set(env, index, OfflineRegion::New(env, jFileSource, std::move(region))); index++; } callback.Call(env, method, jregions); } void OfflineManager::putResourceWithUrl(jni::JNIEnv& env, const jni::String& url_, const jni::Array& arr, jlong modified, jlong expires, const jni::String& eTag_, jboolean mustRevalidate) { auto url = jni::Make(env, url_); auto data = std::make_shared(arr.Length(env), char()); jni::GetArrayRegion(env, *arr, 0, data->size(), reinterpret_cast(&(*data)[0])); mbgl::Resource resource(mbgl::Resource::Kind::Unknown, url); mbgl::Response response; response.data = data; response.mustRevalidate = mustRevalidate; if (eTag_) { response.etag = jni::Make(env, eTag_); } if (modified > 0) { response.modified = Timestamp(mbgl::Seconds(modified)); } if (expires > 0) { response.expires = Timestamp(mbgl::Seconds(expires)); } fileSource->put(resource, response); } } // namespace android } // namespace mbgl