2021-06-27 04:37:54 -06:00
|
|
|
//
|
|
|
|
// Created by Marc Rousavy on 22.06.21.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "JSIJNIConversion.h"
|
|
|
|
|
|
|
|
#include <jsi/jsi.h>
|
|
|
|
#include <jni.h>
|
|
|
|
#include <fbjni/fbjni.h>
|
|
|
|
#include <android/log.h>
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
2022-07-18 02:40:56 -06:00
|
|
|
#include <memory>
|
2021-06-27 04:37:54 -06:00
|
|
|
|
|
|
|
#include <react/jni/NativeMap.h>
|
|
|
|
#include <react/jni/ReadableNativeMap.h>
|
|
|
|
#include <react/jni/WritableNativeMap.h>
|
|
|
|
|
|
|
|
#include <jsi/JSIDynamic.h>
|
|
|
|
#include <folly/dynamic.h>
|
|
|
|
|
2021-09-29 04:30:50 -06:00
|
|
|
#include "FrameHostObject.h"
|
2021-07-30 02:27:45 -06:00
|
|
|
#include "java-bindings/JImageProxy.h"
|
|
|
|
#include "java-bindings/JArrayList.h"
|
|
|
|
#include "java-bindings/JHashMap.h"
|
2021-06-27 04:37:54 -06:00
|
|
|
|
|
|
|
namespace vision {
|
|
|
|
|
|
|
|
using namespace facebook;
|
|
|
|
|
|
|
|
jobject JSIJNIConversion::convertJSIValueToJNIObject(jsi::Runtime &runtime, const jsi::Value &value) {
|
|
|
|
if (value.isBool()) {
|
|
|
|
// jsi::Bool
|
|
|
|
|
|
|
|
auto boolean = jni::JBoolean::valueOf(value.getBool());
|
|
|
|
return boolean.release();
|
|
|
|
|
|
|
|
} else if (value.isNumber()) {
|
|
|
|
// jsi::Number
|
|
|
|
|
|
|
|
auto number = jni::JDouble::valueOf(value.getNumber());
|
|
|
|
return number.release();
|
|
|
|
|
|
|
|
} else if (value.isNull() || value.isUndefined()) {
|
|
|
|
// jsi::undefined
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
} else if (value.isString()) {
|
|
|
|
// jsi::String
|
|
|
|
|
|
|
|
auto string = jni::make_jstring(value.getString(runtime).utf8(runtime));
|
|
|
|
return string.release();
|
|
|
|
|
|
|
|
} else if (value.isObject()) {
|
|
|
|
// jsi::Object
|
|
|
|
|
|
|
|
auto object = value.asObject(runtime);
|
|
|
|
|
|
|
|
if (object.isArray(runtime)) {
|
|
|
|
// jsi::Array
|
|
|
|
|
|
|
|
auto dynamic = jsi::dynamicFromValue(runtime, value);
|
|
|
|
auto nativeArray = react::ReadableNativeArray::newObjectCxxArgs(std::move(dynamic));
|
|
|
|
return nativeArray.release();
|
|
|
|
|
|
|
|
} else if (object.isHostObject(runtime)) {
|
|
|
|
// jsi::HostObject
|
|
|
|
|
|
|
|
auto boxedHostObject = object.getHostObject(runtime);
|
2021-09-29 04:30:50 -06:00
|
|
|
auto hostObject = dynamic_cast<FrameHostObject*>(boxedHostObject.get());
|
2021-06-27 04:37:54 -06:00
|
|
|
if (hostObject != nullptr) {
|
|
|
|
// return jni local_ref to the JImageProxy
|
|
|
|
return hostObject->frame.get();
|
|
|
|
} else {
|
|
|
|
// it's different kind of HostObject. We don't support it.
|
2021-08-05 02:10:49 -06:00
|
|
|
throw std::runtime_error("Received an unknown HostObject! Cannot convert to a JNI value.");
|
2021-06-27 04:37:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
} else if (object.isFunction(runtime)) {
|
|
|
|
// jsi::Function
|
|
|
|
|
|
|
|
// TODO: Convert Function to Callback
|
2021-08-05 02:10:49 -06:00
|
|
|
throw std::runtime_error("Cannot convert a JS Function to a JNI value (yet)!");
|
2021-06-27 04:37:54 -06:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// jsi::Object
|
|
|
|
|
|
|
|
auto dynamic = jsi::dynamicFromValue(runtime, value);
|
|
|
|
auto map = react::ReadableNativeMap::createWithContents(std::move(dynamic));
|
|
|
|
return map.release();
|
2021-08-05 02:10:49 -06:00
|
|
|
|
2021-06-27 04:37:54 -06:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// unknown jsi type!
|
2021-08-05 02:10:49 -06:00
|
|
|
|
2021-06-27 04:37:54 -06:00
|
|
|
auto stringRepresentation = value.toString(runtime).utf8(runtime);
|
2021-08-05 02:10:49 -06:00
|
|
|
auto message = "Received unknown JSI value! (" + stringRepresentation + ") Cannot convert to a JNI value.";
|
|
|
|
throw std::runtime_error(message);
|
|
|
|
|
2021-06-27 04:37:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
jsi::Value JSIJNIConversion::convertJNIObjectToJSIValue(jsi::Runtime &runtime, const jni::local_ref<jobject>& object) {
|
2021-10-14 04:46:42 -06:00
|
|
|
if (object == nullptr) {
|
|
|
|
// null
|
|
|
|
|
|
|
|
return jsi::Value::undefined();
|
|
|
|
|
|
|
|
} else if (object->isInstanceOf(jni::JBoolean::javaClassStatic())) {
|
2021-06-27 04:37:54 -06:00
|
|
|
// Boolean
|
|
|
|
|
|
|
|
static const auto getBooleanFunc = jni::findClassLocal("java/lang/Boolean")->getMethod<jboolean()>("booleanValue");
|
|
|
|
auto boolean = getBooleanFunc(object.get());
|
|
|
|
return jsi::Value(boolean == true);
|
|
|
|
|
|
|
|
} else if (object->isInstanceOf(jni::JDouble::javaClassStatic())) {
|
|
|
|
// Double
|
|
|
|
|
|
|
|
static const auto getDoubleFunc = jni::findClassLocal("java/lang/Double")->getMethod<jdouble()>("doubleValue");
|
|
|
|
auto d = getDoubleFunc(object.get());
|
|
|
|
return jsi::Value(d);
|
|
|
|
|
|
|
|
} else if (object->isInstanceOf(jni::JInteger::javaClassStatic())) {
|
|
|
|
// Integer
|
|
|
|
|
2021-09-15 02:13:55 -06:00
|
|
|
static const auto getIntegerFunc = jni::findClassLocal("java/lang/Integer")->getMethod<jint()>("intValue");
|
2021-06-27 04:37:54 -06:00
|
|
|
auto i = getIntegerFunc(object.get());
|
|
|
|
return jsi::Value(i);
|
|
|
|
|
|
|
|
} else if (object->isInstanceOf(jni::JString::javaClassStatic())) {
|
|
|
|
// String
|
|
|
|
|
|
|
|
return jsi::String::createFromUtf8(runtime, object->toString());
|
|
|
|
|
2021-08-04 08:07:08 -06:00
|
|
|
} else if (object->isInstanceOf(JArrayList<jobject>::javaClassStatic())) {
|
|
|
|
// ArrayList<E>
|
2021-06-27 04:37:54 -06:00
|
|
|
|
2021-08-04 08:07:08 -06:00
|
|
|
auto arrayList = static_ref_cast<JArrayList<jobject>>(object);
|
|
|
|
auto size = arrayList->size();
|
2021-06-27 04:37:54 -06:00
|
|
|
|
|
|
|
auto result = jsi::Array(runtime, size);
|
|
|
|
size_t i = 0;
|
2021-08-04 08:07:08 -06:00
|
|
|
for (const auto& item : *arrayList) {
|
2021-06-27 04:37:54 -06:00
|
|
|
result.setValueAtIndex(runtime, i, convertJNIObjectToJSIValue(runtime, item));
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
|
2021-08-04 08:07:08 -06:00
|
|
|
} else if (object->isInstanceOf(react::ReadableArray::javaClassStatic())) {
|
|
|
|
// ReadableArray
|
2021-06-27 04:37:54 -06:00
|
|
|
|
2021-08-04 08:07:08 -06:00
|
|
|
static const auto toArrayListFunc = react::ReadableArray::javaClassLocal()->getMethod<JArrayList<jobject>()>("toArrayList");
|
2021-06-27 04:37:54 -06:00
|
|
|
|
2021-08-04 08:07:08 -06:00
|
|
|
// call recursive, this time ArrayList<E>
|
|
|
|
auto array = toArrayListFunc(object.get());
|
|
|
|
return convertJNIObjectToJSIValue(runtime, array);
|
|
|
|
|
2021-11-23 07:48:07 -07:00
|
|
|
} else if (object->isInstanceOf(JHashMap<jstring, jobject>::javaClassStatic())) {
|
2021-08-04 08:07:08 -06:00
|
|
|
// HashMap<K, V>
|
2021-06-27 04:37:54 -06:00
|
|
|
|
2021-11-23 07:48:07 -07:00
|
|
|
auto map = static_ref_cast<JHashMap<jstring, jobject>>(object);
|
2021-08-04 08:07:08 -06:00
|
|
|
|
|
|
|
auto result = jsi::Object(runtime);
|
|
|
|
for (const auto& entry : *map) {
|
2021-06-27 04:37:54 -06:00
|
|
|
auto key = entry.first->toString();
|
|
|
|
auto value = entry.second;
|
|
|
|
auto jsiValue = convertJNIObjectToJSIValue(runtime, value);
|
|
|
|
result.setProperty(runtime, key.c_str(), jsiValue);
|
|
|
|
}
|
|
|
|
return result;
|
2021-08-04 08:07:08 -06:00
|
|
|
|
|
|
|
} else if (object->isInstanceOf(react::ReadableMap::javaClassStatic())) {
|
|
|
|
// ReadableMap
|
|
|
|
|
2021-11-23 07:48:07 -07:00
|
|
|
static const auto toHashMapFunc = react::ReadableMap::javaClassLocal()->getMethod<JHashMap<jstring, jobject>()>("toHashMap");
|
2021-08-04 08:07:08 -06:00
|
|
|
|
|
|
|
// call recursive, this time HashMap<K, V>
|
|
|
|
auto hashMap = toHashMapFunc(object.get());
|
|
|
|
return convertJNIObjectToJSIValue(runtime, hashMap);
|
|
|
|
|
2022-07-18 02:40:56 -06:00
|
|
|
} else if (object->isInstanceOf(JImageProxy::javaClassStatic())) {
|
|
|
|
// ImageProxy
|
|
|
|
|
|
|
|
auto frame = static_ref_cast<JImageProxy>(object);
|
|
|
|
|
|
|
|
// box into HostObject
|
|
|
|
auto hostObject = std::make_shared<FrameHostObject>(frame);
|
|
|
|
return jsi::Object::createFromHostObject(runtime, hostObject);
|
2021-06-27 04:37:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
auto type = object->getClass()->toString();
|
|
|
|
auto message = "Received unknown JNI type \"" + type + "\"! Cannot convert to jsi::Value.";
|
|
|
|
__android_log_write(ANDROID_LOG_ERROR, "VisionCamera", message.c_str());
|
2021-08-04 08:07:08 -06:00
|
|
|
throw std::runtime_error(message);
|
2021-06-27 04:37:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace vision
|