#include "file_source.hpp" #include "attach_env.hpp" #include "mapbox.hpp" #include #include #include #include #include #include #include "asset_manager_file_source.hpp" namespace mbgl { std::shared_ptr FileSource::createPlatformFileSource(const ResourceOptions& options) { auto env{android::AttachEnv()}; auto assetManager = android::Mapbox::getAssetManager(*env); auto fileSource = std::make_shared(options.cachePath(), std::make_unique(*env, assetManager)); fileSource->setAccessToken(options.accessToken()); return fileSource; } namespace android { // FileSource // FileSource::FileSource(jni::JNIEnv& _env, const jni::String& accessToken, const jni::String& _cachePath) { std::string path = jni::Make(_env, _cachePath); mapbox::sqlite::setTempPath(path); resourceOptions.withAccessToken(accessToken ? jni::Make(_env, accessToken) : "") .withCachePath(path + DATABASE_FILE); // Create a core default file source fileSource = std::static_pointer_cast(mbgl::FileSource::getSharedFileSource(resourceOptions)); } FileSource::~FileSource() { } jni::Local FileSource::getAccessToken(jni::JNIEnv& env) { return jni::Make(env, fileSource->getAccessToken()); } void FileSource::setAccessToken(jni::JNIEnv& env, const jni::String& token) { fileSource->setAccessToken(token ? jni::Make(env, token) : ""); } void FileSource::setAPIBaseUrl(jni::JNIEnv& env, const jni::String& url) { fileSource->setAPIBaseURL(jni::Make(env, url)); } void FileSource::setResourceTransform(jni::JNIEnv& env, const jni::Object& transformCallback) { if (transformCallback) { auto global = jni::NewGlobal(env, transformCallback); resourceTransform = std::make_unique>( *Scheduler::GetCurrent(), // Capture the ResourceTransformCallback object as a managed global into // the lambda. It is released automatically when we're setting a new ResourceTransform in // a subsequent call. // Note: we're converting it to shared_ptr because this lambda is converted to a std::function, // which requires copyability of its captured variables. [callback = std::make_shared(std::move(global))](mbgl::Resource::Kind kind, const std::string& url_) { android::UniqueEnv _env = android::AttachEnv(); return FileSource::ResourceTransformCallback::onURL(*_env, *callback, int(kind), url_); }); fileSource->setResourceTransform(resourceTransform->self()); } else { // Reset the callback resourceTransform.reset(); fileSource->setResourceTransform({}); } } void FileSource::setResourceCachePath(jni::JNIEnv& env, const jni::String& path, const jni::Object& _callback) { if (pathChangeCallback) { FileSource::ResourcesCachePathChangeCallback::onError(env, _callback, jni::Make(env, "Another resources cache path change is in progress")); return; } std::string newPath = jni::Make(env, path); mapbox::sqlite::setTempPath(newPath); auto global = jni::NewGlobal(env, _callback); pathChangeCallback = std::make_unique>(*Scheduler::GetCurrent(), [this, callback = std::make_shared(std::move(global)), newPath] { android::UniqueEnv _env = android::AttachEnv(); FileSource::ResourcesCachePathChangeCallback::onSuccess(*_env, *callback, jni::Make(*_env, newPath)); pathChangeCallback.reset(); }); fileSource->setResourceCachePath(newPath + DATABASE_FILE, pathChangeCallback->self()); } void FileSource::resume(jni::JNIEnv&) { if (!activationCounter) { activationCounter = optional(1) ; return; } activationCounter.value()++; if (activationCounter == 1) { fileSource->resume(); } } void FileSource::pause(jni::JNIEnv&) { if (activationCounter) { activationCounter.value()--; if (activationCounter == 0) { fileSource->pause(); } } } jni::jboolean FileSource::isResumed(jni::JNIEnv&) { if (activationCounter) { return (jboolean) (activationCounter > 0); } return (jboolean) false; } FileSource* FileSource::getNativePeer(jni::JNIEnv& env, const jni::Object& jFileSource) { static auto& javaClass = jni::Class::Singleton(env); static auto field = javaClass.GetField(env, "nativePtr"); return reinterpret_cast(jFileSource.Get(env, field)); } mbgl::ResourceOptions FileSource::getSharedResourceOptions(jni::JNIEnv& env, const jni::Object& jFileSource) { FileSource* fileSource = FileSource::getNativePeer(env, jFileSource); assert(fileSource != nullptr); return fileSource->resourceOptions.clone(); } // FileSource::ResourcesCachePathChangeCallback // void FileSource::ResourcesCachePathChangeCallback::onSuccess(jni::JNIEnv& env, const jni::Object& callback, const jni::String& path) { static auto& javaClass = jni::Class::Singleton(env); static auto method = javaClass.GetMethod(env, "onSuccess"); callback.Call(env, method, path); } void FileSource::ResourcesCachePathChangeCallback::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 FileSource::registerNative(jni::JNIEnv& env) { // Ensure the classes are cached. If they're requested for the // first time on a background thread, Android's class loader heuristics will fail. // https://developer.android.com/training/articles/perf-jni#faq_FindClass jni::Class::Singleton(env); jni::Class::Singleton(env); static auto& javaClass = jni::Class::Singleton(env); #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) // Register the peer jni::RegisterNativePeer(env, javaClass, "nativePtr", jni::MakePeer, "initialize", "finalize", METHOD(&FileSource::getAccessToken, "getAccessToken"), METHOD(&FileSource::setAccessToken, "setAccessToken"), METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"), METHOD(&FileSource::setResourceTransform, "setResourceTransform"), METHOD(&FileSource::setResourceCachePath, "setResourceCachePath"), METHOD(&FileSource::resume, "activate"), METHOD(&FileSource::pause, "deactivate"), METHOD(&FileSource::isResumed, "isActivated")); } // FileSource::ResourceTransformCallback // std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, const jni::Object& callback, int kind, std::string url_) { static auto& javaClass = jni::Class::Singleton(env); static auto method = javaClass.GetMethod(env, "onURL"); return jni::Make(env, callback.Call(env, method, kind, jni::Make(env, url_))); } } // namespace android } // namespace mbgl