| {%- 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 (size_t i_{{depth}} = 0; i_{{depth}} < static_cast<size_t>({{source}}Size); ++i_{{depth}}) { |
| jobject element_{{depth}}; |
| chip::JniReferences::GetInstance().GetListItem({{source}}, i_{{depth}}, element_{{depth}}); |
| {{encode_value( |
| "listHolder_{}->mList[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 %} |