Files
MapLibreParticleLab/platform/android/MapboxGLAndroidSDK/src/cpp/offline/offline_region.cpp
Bart Louwers 71f6da2722 Add clang-format (#1086)
Co-authored-by: mwilsnd <mwilsnd@gmail.com>
2023-05-01 16:57:37 +02:00

339 lines
16 KiB
C++

#include "offline_region.hpp"
#include <mbgl/storage/file_source_manager.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"
namespace mbgl {
namespace android {
// OfflineRegion //
OfflineRegion::OfflineRegion(jni::JNIEnv& env, jni::jlong offlineRegionPtr, const jni::Object<FileSource>& jFileSource)
: region(reinterpret_cast<mbgl::OfflineRegion*>(offlineRegionPtr)),
fileSource(std::static_pointer_cast<mbgl::DatabaseFileSource>(std::shared_ptr<mbgl::FileSource>(
mbgl::FileSourceManager::get()->getFileSource(mbgl::FileSourceType::Database,
FileSource::getSharedResourceOptions(env, jFileSource),
FileSource::getSharedClientOptions(env, jFileSource))))) {
if (!fileSource) {
ThrowNew(env, jni::FindClass(env, "java/lang/IllegalStateException"), "Offline functionality is disabled.");
}
}
OfflineRegion::~OfflineRegion() {}
void OfflineRegion::setOfflineRegionObserver(jni::JNIEnv& env_,
const jni::Object<OfflineRegion::OfflineRegionObserver>& callback) {
// Define the observer
class Observer : public mbgl::OfflineRegionObserver {
public:
Observer(jni::Global<jni::Object<OfflineRegion::OfflineRegionObserver>, jni::EnvAttachingDeleter> callback_)
: callback(std::move(callback_)) {}
void statusChanged(mbgl::OfflineRegionStatus status) override {
// Reattach, the callback comes from a different thread
android::UniqueEnv env = android::AttachEnv();
static auto& javaClass = jni::Class<OfflineRegion::OfflineRegionObserver>::Singleton(*env);
static auto method = javaClass.GetMethod<void(jni::Object<OfflineRegionStatus>)>(*env, "onStatusChanged");
callback.Call(*env, method, OfflineRegionStatus::New(*env, status));
}
void responseError(mbgl::Response::Error error) override {
// Reattach, the callback comes from a different thread
android::UniqueEnv env = android::AttachEnv();
static auto& javaClass = jni::Class<OfflineRegion::OfflineRegionObserver>::Singleton(*env);
static auto method = javaClass.GetMethod<void(jni::Object<mbgl::android::OfflineRegionError>)>(*env,
"onError");
callback.Call(*env, method, OfflineRegionError::New(*env, error));
}
void mapboxTileCountLimitExceeded(uint64_t limit) override {
// Reattach, the callback comes from a different thread
android::UniqueEnv env = android::AttachEnv();
static auto& javaClass = jni::Class<OfflineRegion::OfflineRegionObserver>::Singleton(*env);
static auto method = javaClass.GetMethod<void(jni::jlong)>(*env, "mapboxTileCountLimitExceeded");
callback.Call(*env, method, jlong(limit));
}
jni::Global<jni::Object<OfflineRegion::OfflineRegionObserver>, jni::EnvAttachingDeleter> callback;
};
// Set the observer
fileSource->setOfflineRegionObserver(
*region, std::make_unique<Observer>(jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback)));
}
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_,
const jni::Object<OfflineRegionStatusCallback>& callback_) {
auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_);
fileSource->getOfflineRegionStatus(
*region,
[
// Ensure the object is not gc'd in the meanwhile
callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback))](
mbgl::expected<mbgl::OfflineRegionStatus, std::exception_ptr> status) mutable {
// Reattach, the callback comes from a different thread
android::UniqueEnv env = android::AttachEnv();
if (status) {
OfflineRegionStatusCallback::onStatus(*env, *callback, std::move(*status));
} else {
OfflineRegionStatusCallback::onError(*env, *callback, status.error());
}
});
}
void OfflineRegion::deleteOfflineRegion(jni::JNIEnv& env_, const jni::Object<OfflineRegionDeleteCallback>& callback_) {
auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_);
fileSource->deleteOfflineRegion(*region,
[
// Ensure the object is not gc'd in the meanwhile
callback = std::make_shared<decltype(globalCallback)>(
std::move(globalCallback))](std::exception_ptr error) mutable {
// Reattach, the callback comes from a different thread
android::UniqueEnv env = android::AttachEnv();
if (error) {
OfflineRegionDeleteCallback::onError(*env, *callback, error);
} else {
OfflineRegionDeleteCallback::onDelete(*env, *callback);
}
});
}
void OfflineRegion::invalidateOfflineRegion(jni::JNIEnv& env_,
const jni::Object<OfflineRegionInvalidateCallback>& callback_) {
auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_);
fileSource->invalidateOfflineRegion(*region,
[
// Ensure the object is not gc'd in the meanwhile
callback = std::make_shared<decltype(globalCallback)>(
std::move(globalCallback))](std::exception_ptr error) mutable {
// Reattach, the callback comes from a different thread
android::UniqueEnv env = android::AttachEnv();
if (error) {
OfflineRegionInvalidateCallback::onError(*env, *callback, error);
} else {
OfflineRegionInvalidateCallback::onInvalidate(*env, *callback);
}
});
}
void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_,
const jni::Array<jni::jbyte>& jMetadata,
const jni::Object<OfflineRegionUpdateMetadataCallback>& callback_) {
auto metadata = OfflineRegion::metadata(env_, jMetadata);
auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_);
fileSource->updateOfflineMetadata(
region->getID(),
metadata,
[
// Ensure the object is not gc'd in the meanwhile
callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback))](
mbgl::expected<mbgl::OfflineRegionMetadata, std::exception_ptr> data) mutable {
// Reattach, the callback comes from a different thread
android::UniqueEnv env = android::AttachEnv();
if (data) {
OfflineRegionUpdateMetadataCallback::onUpdate(*env, *callback, std::move(*data));
} else {
OfflineRegionUpdateMetadataCallback::onError(*env, *callback, data.error());
}
});
}
jni::Local<jni::Object<OfflineRegion>> OfflineRegion::New(jni::JNIEnv& env,
const jni::Object<FileSource>& jFileSource,
mbgl::OfflineRegion region) {
// Definition
auto definition = region.getDefinition().match(
[&](const mbgl::OfflineTilePyramidRegionDefinition def) {
return OfflineTilePyramidRegionDefinition::New(env, def);
},
[&](const mbgl::OfflineGeometryRegionDefinition def) {
return OfflineGeometryRegionDefinition::New(env, def);
});
// Create region java object
static auto& javaClass = jni::Class<OfflineRegion>::Singleton(env);
static auto constructor = javaClass.GetConstructor<jni::jlong,
jni::Object<FileSource>,
jni::jlong,
jni::Object<OfflineRegionDefinition>,
jni::Array<jni::jbyte>>(env);
return 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,
OfflineRegion::metadata(env, region.getMetadata()));
}
jni::Local<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, const 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;
}
void OfflineRegion::registerNative(jni::JNIEnv& env) {
jni::Class<OfflineRegionObserver>::Singleton(env);
jni::Class<OfflineRegionStatusCallback>::Singleton(env);
jni::Class<OfflineRegionDeleteCallback>::Singleton(env);
jni::Class<OfflineRegionUpdateMetadataCallback>::Singleton(env);
jni::Class<OfflineRegionInvalidateCallback>::Singleton(env);
static auto& javaClass = jni::Class<OfflineRegion>::Singleton(env);
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
jni::RegisterNativePeer<OfflineRegion>(
env,
javaClass,
"nativePtr",
jni::MakePeer<OfflineRegion, jni::jlong, const jni::Object<FileSource>&>,
"initialize",
"finalize",
METHOD(&OfflineRegion::setOfflineRegionObserver, "setOfflineRegionObserver"),
METHOD(&OfflineRegion::setOfflineRegionDownloadState, "setOfflineRegionDownloadState"),
METHOD(&OfflineRegion::getOfflineRegionStatus, "getOfflineRegionStatus"),
METHOD(&OfflineRegion::deleteOfflineRegion, "deleteOfflineRegion"),
METHOD(&OfflineRegion::invalidateOfflineRegion, "invalidateOfflineRegion"),
METHOD(&OfflineRegion::updateOfflineRegionMetadata, "updateOfflineRegionMetadata"));
}
// OfflineRegionObserver //
// OfflineRegionStatusCallback //
void OfflineRegion::OfflineRegionStatusCallback::onError(
jni::JNIEnv& env,
const jni::Object<OfflineRegion::OfflineRegionStatusCallback>& callback,
std::exception_ptr error) {
static auto& javaClass = jni::Class<OfflineRegion::OfflineRegionStatusCallback>::Singleton(env);
static auto method = javaClass.GetMethod<void(jni::String)>(env, "onError");
callback.Call(env, method, jni::Make<jni::String>(env, mbgl::util::toString(error)));
}
void OfflineRegion::OfflineRegionStatusCallback::onStatus(
jni::JNIEnv& env,
const jni::Object<OfflineRegion::OfflineRegionStatusCallback>& callback,
std::optional<mbgl::OfflineRegionStatus> status) {
static auto& javaClass = jni::Class<OfflineRegion::OfflineRegionStatusCallback>::Singleton(env);
static auto method = javaClass.GetMethod<void(jni::Object<OfflineRegionStatus>)>(env, "onStatus");
callback.Call(env, method, OfflineRegionStatus::New(env, std::move(*status)));
}
// OfflineRegionDeleteCallback //
void OfflineRegion::OfflineRegionDeleteCallback::onError(
jni::JNIEnv& env,
const jni::Object<OfflineRegion::OfflineRegionDeleteCallback>& callback,
std::exception_ptr error) {
static auto& javaClass = jni::Class<OfflineRegion::OfflineRegionDeleteCallback>::Singleton(env);
static auto method = javaClass.GetMethod<void(jni::String)>(env, "onError");
callback.Call(env, method, jni::Make<jni::String>(env, mbgl::util::toString(error)));
}
void OfflineRegion::OfflineRegionDeleteCallback::onDelete(
jni::JNIEnv& env, const jni::Object<OfflineRegion::OfflineRegionDeleteCallback>& callback) {
// Trigger callback
static auto& javaClass = jni::Class<OfflineRegion::OfflineRegionDeleteCallback>::Singleton(env);
static auto method = javaClass.GetMethod<void()>(env, "onDelete");
callback.Call(env, method);
}
// OfflineRegionUpdateMetadataCallback //
void OfflineRegion::OfflineRegionUpdateMetadataCallback::onError(
jni::JNIEnv& env,
const jni::Object<OfflineRegion::OfflineRegionUpdateMetadataCallback>& callback,
std::exception_ptr error) {
static auto& javaClass = jni::Class<OfflineRegion::OfflineRegionUpdateMetadataCallback>::Singleton(env);
static auto method = javaClass.GetMethod<void(jni::String)>(env, "onError");
callback.Call(env, method, jni::Make<jni::String>(env, mbgl::util::toString(error)));
}
void OfflineRegion::OfflineRegionUpdateMetadataCallback::onUpdate(
jni::JNIEnv& env,
const jni::Object<OfflineRegion::OfflineRegionUpdateMetadataCallback>& callback,
std::optional<mbgl::OfflineRegionMetadata> metadata) {
static auto& javaClass = jni::Class<OfflineRegion::OfflineRegionUpdateMetadataCallback>::Singleton(env);
static auto method = javaClass.GetMethod<void(jni::Array<jni::jbyte>)>(env, "onUpdate");
callback.Call(env, method, OfflineRegion::metadata(env, std::move(*metadata)));
}
// OfflineRegionInvalidateCallback //
void OfflineRegion::OfflineRegionInvalidateCallback::onError(
jni::JNIEnv& env,
const jni::Object<OfflineRegion::OfflineRegionInvalidateCallback>& callback,
std::exception_ptr error) {
static auto& javaClass = jni::Class<OfflineRegion::OfflineRegionInvalidateCallback>::Singleton(env);
static auto method = javaClass.GetMethod<void(jni::String)>(env, "onError");
callback.Call(env, method, jni::Make<jni::String>(env, mbgl::util::toString(error)));
}
void OfflineRegion::OfflineRegionInvalidateCallback::onInvalidate(
jni::JNIEnv& env, const jni::Object<OfflineRegion::OfflineRegionInvalidateCallback>& callback) {
static auto& javaClass = jni::Class<OfflineRegion::OfflineRegionInvalidateCallback>::Singleton(env);
static auto method = javaClass.GetMethod<void()>(env, "onInvalidate");
callback.Call(env, method);
}
} // namespace android
} // namespace mbgl