blob: d56f2701113734081b58ec0ab0844f577868a2b6 [file] [log] [blame]
{%- macro encode_optional(target, source, depth, encodable) -%}
{
jobject optionalValue_{{depth}} = nullptr;
chip::JniReferences::GetInstance().GetOptionalValue({{source}}, optionalValue_{{depth}});
if (optionalValue_{{depth}}) {
auto & definedValue_{{depth}} = {{target}}.Emplace();
{{ encode_value(
"definedValue_{}".format(depth),
"optionalValue_{}".format(depth),
depth+1,
encodable.without_optional()
)}}
}
}
{%- endmacro %}
{%- macro encode_nullable(target, source, depth, encodable) -%}
if ({{source}} == nullptr) {
{{target}}.SetNull();
} else {
auto & nonNullValue_{{depth}} = {{target}}.SetNonNull();
{{encode_value("nonNullValue_{}".format(depth), source, depth+1, encodable.without_nullable())}}
}
{%- endmacro %}
{%- macro encode_list(target, source, depth, encodable) -%}
{
using ListType_{{depth}} = std::remove_reference_t<decltype({{target}})>;
using ListMemberType_{{depth}} = ListMemberTypeGetter<ListType_{{depth}}>::Type;
jint {{source}}Size;
chip::JniReferences::GetInstance().GetListSize({{source}}, {{source}}Size);
if ({{source}}Size != 0) {
auto * listHolder_{{depth}} = new ListHolder<ListMemberType_{{depth}}>({{source}}Size);
listFreer.add(listHolder_{{depth}});
for (jint i_{{depth}} = 0; i_{{depth}} < {{source}}Size; ++i_{{depth}}) {
jobject element_{{depth}};
chip::JniReferences::GetInstance().GetListItem({{source}}, i_{{depth}}, element_{{depth}});
{{encode_value(
"listHolder_{}->mList[static_cast<uint32_t>(i_{})]".format(depth, depth),
"element_{}".format(depth),
depth+1, encodable.without_list()
)}}
}
{{target}} = ListType_{{depth}}(listHolder_{{depth}}->mList, {{source}}Size);
} else {
{{target}} = ListType_{{depth}}();
}
}
{%- endmacro %}
{%- macro encode_value(target, source, depth, encodable) -%}
{%- if encodable.is_optional -%}
{{encode_optional(target, source, depth, encodable)}}
{%- elif encodable.is_nullable -%}
{{encode_nullable(target, source, depth, encodable)}}
{%- elif encodable.is_list -%}
{{encode_list(target, source, depth, encodable)}}
{%- elif encodable.is_octet_string -%}
cleanupByteArrays.push_back(chip::Platform::MakeUnique<chip::JniByteArray>(env, static_cast<jbyteArray>({{source}})));
{{target}} = cleanupByteArrays.back()->byteSpan();
{%- elif encodable.is_char_string -%}
cleanupStrings.push_back(chip::Platform::MakeUnique<chip::JniUtfString>(env, static_cast<jstring>({{source}})));
{{target}} = cleanupStrings.back()->charSpan();
{%- elif encodable.is_struct -%}
{% set struct = encodable.get_underlying_struct() -%}
{% for field in struct.fields %}
{% set fieldEncodable = field | asEncodable(encodable.context) -%}
jobject {{source}}_{{field.name}}Item_{{depth}};
chip::JniReferences::GetInstance().GetObjectField({{source}}, "{{field.name}}", "{{fieldEncodable.boxed_java_signature}}", {{source}}_{{field.name}}Item_{{depth}});
{{ encode_value(
"{}.{}".format(target, field.name | lowercaseFirst),
"{}_{}Item_{}".format(source, field.name, depth),
depth + 1,
fieldEncodable
)}}
{%- endfor -%}
{%- elif encodable.is_enum -%}
{{target}} = static_cast<std::remove_reference_t<decltype({{target}})>>(chip::JniReferences::GetInstance().IntegerToPrimitive({{source}}));
{%- elif encodable.is_bitmap -%}
{{target}} = static_cast<std::remove_reference_t<decltype({{target}})>>(chip::JniReferences::GetInstance().{{encodable.boxed_java_type}}ToPrimitive({{source}}));
{% else -%}
{{target}} = static_cast<std::remove_reference_t<decltype({{target}})>>(chip::JniReferences::GetInstance().{{encodable.boxed_java_type}}ToPrimitive({{source}}));
{% endif -%}
{% endmacro -%}
#include <controller/java/zap-generated/CHIPCallbackTypes.h>
#include <controller/java/zap-generated/CHIPInvokeCallbacks.h>
#include <controller/java/zap-generated/CHIPReadCallbacks.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <zap-generated/CHIPClientCallbacks.h>
#include <zap-generated/CHIPClusters.h>
#include <controller/java/AndroidCallbacks.h>
#include <controller/java/AndroidClusterExceptions.h>
#include <controller/java/CHIPDefaultCallbacks.h>
#include <jni.h>
#include <lib/support/CHIPListUtils.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/JniReferences.h>
#include <lib/support/JniTypeWrappers.h>
#include <lib/support/Span.h>
#include <platform/PlatformManager.h>
#include <vector>
#define JNI_METHOD(RETURN, CLASS_NAME, METHOD_NAME) \
extern "C" JNIEXPORT RETURN JNICALL Java_chip_devicecontroller_ChipClusters_00024##CLASS_NAME##_##METHOD_NAME
using namespace chip;
using namespace chip::Controller;
JNI_METHOD(jlong, {{cluster.name | capitalcase}}Cluster, initWithDevice)(JNIEnv * env, jobject self, jlong devicePtr, jint endpointId)
{
chip::DeviceLayer::StackLock lock;
DeviceProxy * device = reinterpret_cast<DeviceProxy *>(devicePtr);
{{cluster.name | capitalcase}}Cluster * cppCluster = new {{cluster.name | capitalcase}}Cluster(*device->GetExchangeManager(), device->GetSecureSession().Value(), endpointId);
return reinterpret_cast<jlong>(cppCluster);
}
{% for command in cluster.commands -%}
JNI_METHOD(void, {{cluster.name | capitalcase}}Cluster,
{{command.name | lowercaseFirst}})(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback,
{%- if command.input_param -%}
{%- for field in (cluster.structs | named(command.input_param)).fields -%}
{{ field | toBoxedJavaType }} {{field.name}},
{%- endfor -%}
{%- endif -%}
jobject timedInvokeTimeoutMs)
{
chip::DeviceLayer::StackLock lock;
CHIP_ERROR err = CHIP_NO_ERROR;
{{cluster.name | capitalcase}}Cluster * cppCluster;
ListFreer listFreer;
chip::app::Clusters::{{cluster.name | capitalcase}}::Commands::{{command.name | capitalcase}}::Type request;
std::vector<Platform::UniquePtr<JniByteArray>> cleanupByteArrays;
std::vector<Platform::UniquePtr<JniUtfString>> cleanupStrings;
{%- if command.input_param -%}
{%- for field in (cluster.structs | named(command.input_param)).fields -%}
{{ encode_value(
"request." + (field.name | lowercaseFirst),
(field.name | lowercaseFirst),
0,
field | asEncodable(typeLookup)
)}}
{%- endfor -%}
{% endif %}
{% set callbackName = command | commandCallbackName(cluster) %}
std::unique_ptr<CHIP{{callbackName}}Callback, void (*)(CHIP{{callbackName}}Callback *)> onSuccess(
Platform::New<CHIP{{callbackName}}Callback>(callback), Platform::Delete<CHIP{{callbackName}}Callback>);
std::unique_ptr<CHIPDefaultFailureCallback, void (*)(CHIPDefaultFailureCallback *)> onFailure(Platform::New<CHIPDefaultFailureCallback>(callback), Platform::Delete<CHIPDefaultFailureCallback>);
VerifyOrReturn(onSuccess.get() != nullptr, AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error creating native callback", CHIP_ERROR_NO_MEMORY));
VerifyOrReturn(onFailure.get() != nullptr, AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error creating native callback", CHIP_ERROR_NO_MEMORY));
cppCluster = reinterpret_cast<{{cluster.name | capitalcase}}Cluster *>(clusterPtr);
VerifyOrReturn(cppCluster != nullptr, AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error getting native cluster", CHIP_ERROR_INCORRECT_STATE));
auto successFn = chip::Callback::Callback<CHIP{{callbackName}}CallbackType>::FromCancelable(onSuccess->Cancel());
auto failureFn = chip::Callback::Callback<CHIPDefaultFailureCallbackType>::FromCancelable(onFailure->Cancel());
{% if command.is_timed_invoke -%}
err = cppCluster->InvokeCommand(request, onSuccess->mContext, successFn->mCall, failureFn->mCall, chip::JniReferences::GetInstance().IntegerToPrimitive(timedInvokeTimeoutMs));
{%- else -%}
if (timedInvokeTimeoutMs == nullptr) {
err = cppCluster->InvokeCommand(request, onSuccess->mContext, successFn->mCall, failureFn->mCall);
} else {
err = cppCluster->InvokeCommand(request, onSuccess->mContext, successFn->mCall, failureFn->mCall, chip::JniReferences::GetInstance().IntegerToPrimitive(timedInvokeTimeoutMs));
}
{%- endif %}
VerifyOrReturn(err == CHIP_NO_ERROR, AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error invoking command", CHIP_ERROR_INCORRECT_STATE));
onSuccess.release();
onFailure.release();
}
{% endfor %}
{%- for attr in cluster.attributes if attr.is_subscribable -%}
{%- if attr | canGenerateSubscribe(typeLookup) -%}
JNI_METHOD(void, {{cluster.name}}Cluster, subscribe{{attr.definition.name | capitalcase}}Attribute)(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, jint minInterval, jint maxInterval)
{
chip::DeviceLayer::StackLock lock;
{%- set callbackName = attr | callbackName(cluster, typeLookup) -%}
std::unique_ptr<{{callbackName}}, void (*)({{callbackName}} *)> onSuccess(Platform::New<{{callbackName}}>(callback, true), chip::Platform::Delete<{{callbackName}}>);
VerifyOrReturn(onSuccess.get() != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error creating native success callback", CHIP_ERROR_NO_MEMORY));
std::unique_ptr<CHIPDefaultFailureCallback, void (*)(CHIPDefaultFailureCallback *)> onFailure(Platform::New<CHIPDefaultFailureCallback>(callback), chip::Platform::Delete<CHIPDefaultFailureCallback>);
VerifyOrReturn(onFailure.get() != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error creating native failure callback", CHIP_ERROR_NO_MEMORY));
CHIP_ERROR err = CHIP_NO_ERROR;
{{cluster.name}}Cluster * cppCluster = reinterpret_cast<{{cluster.name}}Cluster *>(clusterPtr);
VerifyOrReturn(cppCluster != nullptr, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Could not get native cluster", CHIP_ERROR_INCORRECT_STATE));
using TypeInfo = chip::app::Clusters::{{cluster.name}}::Attributes::{{attr.definition.name | capitalcase}}::TypeInfo;
auto successFn = chip::Callback::Callback<CHIP{{cluster.name}}Cluster{{attr.definition.name | capitalcase}}AttributeCallbackType>::FromCancelable(onSuccess->Cancel());
auto failureFn = chip::Callback::Callback<CHIPDefaultFailureCallbackType>::FromCancelable(onFailure->Cancel());
err = cppCluster->SubscribeAttribute<TypeInfo>(onSuccess->mContext, successFn->mCall, failureFn->mCall, static_cast<uint16_t>(minInterval), static_cast<uint16_t>(maxInterval), {{callbackName}}::OnSubscriptionEstablished);
VerifyOrReturn(err == CHIP_NO_ERROR, chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error subscribing to attribute", err));
onSuccess.release();
onFailure.release();
}
{%- endif -%}
{% endfor %}