Files
MapLibreParticleLab/platform/android/src/offline/offline_region.cpp

315 lines
14 KiB
C++

#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);
auto jmessage = jni::Make<jni::String>(env, message);
callback.Call(env, method, jmessage);
jni::DeleteLocalRef(env, jmessage);
}
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);
auto jmessage = jni::Make<jni::String>(env, message);
callback.Call(env, method, jmessage);
jni::DeleteLocalRef(env, jmessage);
}
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);
auto jmessage = jni::Make<jni::String>(env, message);
callback.Call(env, method, jmessage);
jni::DeleteLocalRef(env, jmessage);
}
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