Skip to content

Commit

Permalink
[Android] Support list attribute nullable/optionals (#11704)
Browse files Browse the repository at this point in the history
* Support nullable/optionals in list attribute callbacks

* Regenerate
  • Loading branch information
austinh0 authored and pull[bot] committed May 7, 2022
1 parent 2e87edd commit 8329bcf
Show file tree
Hide file tree
Showing 12 changed files with 2,628 additions and 404 deletions.
2 changes: 1 addition & 1 deletion src/controller/java/CHIPDefaultCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ chip::CHIPDefaultSuccessCallback::~CHIPDefaultSuccessCallback()
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
if (env == nullptr)
{
ChipLogError(Zcl, "Could not create global reference for Java callback");
ChipLogError(Zcl, "Could not delete global reference for Java callback");
return;
}
env->DeleteGlobalRef(javaCallbackRef);
Expand Down
9 changes: 5 additions & 4 deletions src/controller/java/templates/CHIPClusters-JNI.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callba
javaCallbackRef = cppCallback->javaCallbackRef;
VerifyOrExit(javaCallbackRef != nullptr, err = CHIP_NO_ERROR);

err = JniReferences::GetInstance().FindMethod(env, javaCallbackRef, "onSuccess", "({{#chip_cluster_response_arguments}}{{#if isArray}}{{else if (isOctetString type)}}[B{{else if (isShortString type)}}Ljava/lang/String;{{else}}{{asJniSignature type}}{{/if}}{{/chip_cluster_response_arguments}})V", &javaMethod);
err = JniReferences::GetInstance().FindMethod(env, javaCallbackRef, "onSuccess", "({{#chip_cluster_response_arguments}}{{#if isArray}}{{else if (isOctetString type)}}[B{{else if (isShortString type)}}Ljava/lang/String;{{else}}{{asJniSignature type false}}{{/if}}{{/chip_cluster_response_arguments}})V", &javaMethod);
SuccessOrExit(err);

{{#chip_cluster_response_arguments}}
Expand Down Expand Up @@ -146,7 +146,7 @@ JNI_METHOD(jlong, {{asUpperCamelCase name}}Cluster, initWithDevice)(JNIEnv * env
}

{{#chip_cluster_commands}}
JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, {{asLowerCamelCase name}})(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback{{#chip_cluster_command_arguments_with_structs_expanded}}, {{asJniBasicType type}} {{asLowerCamelCase label}}{{/chip_cluster_command_arguments_with_structs_expanded}})
JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, {{asLowerCamelCase name}})(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback{{#chip_cluster_command_arguments_with_structs_expanded}}, {{asJniBasicType type false}} {{asLowerCamelCase label}}{{/chip_cluster_command_arguments_with_structs_expanded}})
{
chip::DeviceLayer::StackLock lock;
CHIP_ERROR err = CHIP_NO_ERROR;
Expand All @@ -173,7 +173,8 @@ JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, {{asLowerCamelCase name}})
cppCluster = reinterpret_cast<{{asUpperCamelCase ../name}}Cluster *>(clusterPtr);
VerifyOrExit(cppCluster != nullptr, err = CHIP_ERROR_INCORRECT_STATE);

err = cppCluster->{{asCamelCased name false}}(onSuccess->Cancel(), onFailure->Cancel(){{#chip_cluster_command_arguments_with_structs_expanded}}, {{#if_chip_enum type}}static_cast<{{chipType}}>({{asLowerCamelCase label}}){{else if (isOctetString type)}}{{asUnderlyingZclType type}}((const uint8_t*) {{asLowerCamelCase label}}Arr.data(), {{asLowerCamelCase label}}Arr.size()){{else if (isCharString type)}}chip::CharSpan({{asLowerCamelCase label}}Str.c_str(), strlen({{asLowerCamelCase label}}Str.c_str())){{else}}{{asLowerCamelCase label}}{{/if_chip_enum}}{{/chip_cluster_command_arguments_with_structs_expanded}});
err = cppCluster->{{asCamelCased name false}}(onSuccess->Cancel(), onFailure->Cancel()
{{#chip_cluster_command_arguments_with_structs_expanded}}, {{#if_chip_enum type}}static_cast<{{chipType}}>({{asLowerCamelCase label}}){{else if (isOctetString type)}}{{asUnderlyingZclType type}}((const uint8_t*) {{asLowerCamelCase label}}Arr.data(), {{asLowerCamelCase label}}Arr.size()){{else if (isCharString type)}}chip::CharSpan({{asLowerCamelCase label}}Str.c_str(), strlen({{asLowerCamelCase label}}Str.c_str())){{else}}{{asLowerCamelCase label}}{{/if_chip_enum}}{{/chip_cluster_command_arguments_with_structs_expanded}});
SuccessOrExit(err);

exit:
Expand Down Expand Up @@ -202,7 +203,7 @@ exit:
{{#chip_server_cluster_attributes}}
{{#if isWritableAttribute}}

JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, write{{asUpperCamelCase name}}Attribute)(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, {{asJniBasicType type}} value)
JNI_METHOD(void, {{asUpperCamelCase ../name}}Cluster, write{{asUpperCamelCase name}}Attribute)(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, {{asJniBasicType type false}} value)
{
chip::DeviceLayer::StackLock lock;
std::unique_ptr<CHIPDefaultSuccessCallback, void (*)(CHIPDefaultSuccessCallback *)> onSuccess(Platform::New<CHIPDefaultSuccessCallback>(callback), Platform::Delete<CHIPDefaultSuccessCallback>);
Expand Down
164 changes: 138 additions & 26 deletions src/controller/java/templates/CHIPReadCallbacks-src.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ CHIP{{chipCallback.name}}AttributeCallback::CHIP{{chipCallback.name}}AttributeCa
}
}

CHIP{{chipCallback.name}}AttributeCallback::~CHIP{{chipCallback.name}}AttributeCallback() {
JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread();
if (env == nullptr)
{
ChipLogError(Zcl, "Could not delete global reference for Java callback");
return;
}
env->DeleteGlobalRef(javaCallbackRef);
}

void CHIP{{chipCallback.name}}AttributeCallback::CallbackFn(void * context, {{chipCallback.type}} value)
{
chip::DeviceLayer::StackUnlock unlock;
Expand All @@ -43,7 +53,7 @@ void CHIP{{chipCallback.name}}AttributeCallback::CallbackFn(void * context, {{ch
jmethodID javaMethod;
{{#unless (isStrEqual chipCallback.name "OctetString")}}
{{#unless (isStrEqual chipCallback.name "CharString")}}
err = chip::JniReferences::GetInstance().FindMethod(env, javaCallbackRef, "onSuccess", "({{convertCTypeToJniSignature chipCallback.type}})V", &javaMethod);
err = chip::JniReferences::GetInstance().FindMethod(env, javaCallbackRef, "onSuccess", "({{convertCTypeToJniSignature chipCallback.type false}})V", &javaMethod);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Zcl, "Could not find onSuccess method"));
env->CallVoidMethod(javaCallbackRef, javaMethod, static_cast<{{convertBasicCTypeToJniType chipCallback.type}}>(value));
{{/unless}}
Expand Down Expand Up @@ -89,6 +99,16 @@ CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback::
}
}

CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback::~CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback() {
JNIEnv * env = chip::JniReferences::GetInstance().GetEnvForCurrentThread();
if (env == nullptr)
{
ChipLogError(Zcl, "Could not delete global reference for Java callback");
return;
}
env->DeleteGlobalRef(javaCallbackRef);
}

void CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback::CallbackFn(void * context, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true}} list)
{
chip::DeviceLayer::StackUnlock unlock;
Expand Down Expand Up @@ -124,7 +144,7 @@ void CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallb
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Zcl, "Could not find class chip/devicecontroller/ChipClusters${{asUpperCamelCase parent.name}}Cluster${{asUpperCamelCase name}}Attribute"));
chip::JniClass attributeJniClass(attributeClass);
jmethodID attributeCtor = env->GetMethodID(attributeClass, "<init>"
, "({{#chip_attribute_list_entryTypes}}{{#if isOptional}}{{! TODO: Add support for optional types here }}{{else if isNullable}}{{! TODO: Add support for nullable types here }}{{else if isArray}}{{! TODO: Add support for lists here }}{{else if isStruct}}{{! TODO: Add support for structs here }}{{else if (isString type)}}{{#if (isOctetString type)}}[B{{else}}Ljava/lang/String;{{/if}}{{else}}{{asJniSignature type}}{{/if}}{{/chip_attribute_list_entryTypes}})V");
, "({{#chip_attribute_list_entryTypes}}{{#if isArray}}{{! TODO: Add support for lists here }}{{else if isStruct}}{{! TODO: Add support for structs here }}{{else if isOptional}}Ljava/util/Optional;{{else if (isString type)}}{{#if (isOctetString type)}}[B{{else}}Ljava/lang/String;{{/if}}{{else}}{{asJniSignature type true}}{{/if}}{{/chip_attribute_list_entryTypes}})V");
VerifyOrReturn(attributeCtor != nullptr, ChipLogError(Zcl, "Could not find {{asUpperCamelCase name}}Attribute constructor"));
{{/if}}

Expand All @@ -135,35 +155,93 @@ void CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallb
{{#if isStruct}}
(void)entry; {{! In case all our struct members are not supported yet }}
{{#chip_attribute_list_entryTypes}}
{{#unless isArray}}
{{#unless isStruct}}
bool {{asLowerCamelCase name}}Null = false;
bool {{asLowerCamelCase name}}HasValue = true;
{{#if isNullable}}
{{#unless isOptional}}
{{chipType}} {{asLowerCamelCase name}}Value;
{{asLowerCamelCase name}}Null = entry.{{asLowerCamelCase name}}.IsNull();
if (!{{asLowerCamelCase name}}Null) {
{{asLowerCamelCase name}}Value = entry.{{asLowerCamelCase name}}.Value();
}
{{/unless}}
{{/if}}

{{#if isOptional}}
{{! TODO: Add support for optional types here }}
{{else if isNullable}}
{{! TODO: Add support for nullable types here }}
{{else if isArray}}
{{chipType}} {{asLowerCamelCase name}}Value;
{{#if isNullable}}
{{asLowerCamelCase name}}HasValue = entry.{{asLowerCamelCase name}}.HasValue();
if ({{asLowerCamelCase name}}HasValue) {
auto {{asLowerCamelCase name}}ValueFromOptional = entry.{{asLowerCamelCase name}}.Value();
{{asLowerCamelCase name}}Null = {{asLowerCamelCase name}}ValueFromOptional.IsNull();
if (!{{asLowerCamelCase name}}Null) {
{{asLowerCamelCase name}}Value = {{asLowerCamelCase name}}ValueFromOptional.Value();
}
}
{{else}}
{{asLowerCamelCase name}}HasValue = entry.{{asLowerCamelCase name}}.HasValue();
if ({{asLowerCamelCase name}}HasValue) {
{{asLowerCamelCase name}}Value = entry.{{asLowerCamelCase name}}.Value();
}
{{/if}}
{{/if}}

{{#unless isOptional}}
{{#unless isNullable}}
{{chipType}} {{asLowerCamelCase name}}Value = entry.{{asLowerCamelCase name}};
{{/unless}}
{{/unless}}

{{/unless}}
{{/unless}}

{{#if isArray}}
{{! TODO: Add support for lists here }}
{{else if isStruct}}
{{! TODO: Add support for structs here }}
{{else if (isOctetString type)}}
jbyteArray {{asLowerCamelCase name}} = env->NewByteArray(entry.{{asLowerCamelCase name}}.size());
env->SetByteArrayRegion({{asLowerCamelCase name}}, 0, entry.{{asLowerCamelCase name}}.size(), reinterpret_cast<const jbyte *>(entry.{{asLowerCamelCase name}}.data()));
jbyteArray {{asLowerCamelCase name}} = nullptr;
if (!{{asLowerCamelCase name}}Null && {{asLowerCamelCase name}}HasValue) {
{{asLowerCamelCase name}} = env->NewByteArray({{asLowerCamelCase name}}Value.size());
env->SetByteArrayRegion({{asLowerCamelCase name}}, 0, {{asLowerCamelCase name}}Value.size(), reinterpret_cast<const jbyte *>({{asLowerCamelCase name}}Value.data()));
}
{{else if (isCharString type)}}
chip::UtfString {{asLowerCamelCase name}}Str(env, entry.{{asLowerCamelCase name}});
jstring {{asLowerCamelCase name}}({{asLowerCamelCase name}}Str.jniValue());
jstring {{asLowerCamelCase name}} = nullptr;
chip::UtfString {{asLowerCamelCase name}}Str(env, {{asLowerCamelCase name}}Value);
if (!{{asLowerCamelCase name}}Null && {{asLowerCamelCase name}}HasValue) {
{{asLowerCamelCase name}} = jstring({{asLowerCamelCase name}}Str.jniValue());
}
{{else}}
{{asJniBasicType type}} {{asLowerCamelCase name}} = entry.{{asLowerCamelCase name}};
jobject {{asLowerCamelCase name}} = nullptr;
if (!{{asLowerCamelCase name}}Null && {{asLowerCamelCase name}}HasValue) {
jclass {{asLowerCamelCase name}}EntryCls;
chip::JniReferences::GetInstance().GetClassRef(env, "java/lang/{{asJavaBasicTypeForZclType type true}}", {{asLowerCamelCase name}}EntryCls);
chip::JniClass {{asLowerCamelCase name}}JniClass({{asLowerCamelCase name}}EntryCls);
jmethodID {{asLowerCamelCase name}}EntryTypeCtor = env->GetMethodID({{asLowerCamelCase name}}EntryCls, "<init>", "({{asJniSignature type false}})V");
{{asLowerCamelCase name}} = env->NewObject({{asLowerCamelCase name}}EntryCls, {{asLowerCamelCase name}}EntryTypeCtor, {{asLowerCamelCase name}}Value);
}
{{/if}}

{{#if isOptional}}
{{#unless isArray}}
{{#unless isStruct}}
jobject {{asLowerCamelCase name}}Optional = nullptr;
chip::JniReferences::GetInstance().CreateOptional({{asLowerCamelCase name}}, {{asLowerCamelCase name}}Optional);
{{/unless}}
{{/unless}}
{{/if}}
{{/chip_attribute_list_entryTypes}}

jobject attributeObj = env->NewObject(attributeClass, attributeCtor
{{#chip_attribute_list_entryTypes}}
{{#if isOptional}}
{{! TODO: Add support for optional types here }}
{{else if isNullable}}
{{! TODO: Add support for nullable types here }}
{{else if isArray}}
{{#if isArray}}
{{! TODO: Add support for lists here }}
{{else if isStruct}}
{{! TODO: Add support for structs here }}
{{else isOptional}}
, {{asLowerCamelCase name}}Optional
{{else}}
, {{asLowerCamelCase name}}
{{/if}}
Expand All @@ -173,19 +251,53 @@ void CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallb

env->CallBooleanMethod(arrayListObj, arrayListAddMethod, attributeObj);
{{else}}
{{#if (isOctetString type)}}
jbyteArray {{asLowerCamelCase name}} = env->NewByteArray(entry.size());
env->SetByteArrayRegion({{asLowerCamelCase name}}, 0, entry.size(), reinterpret_cast<const jbyte *>(entry.data()));
bool entryNull = false;
{{#unless isArray}}
{{#unless isStruct}}
{{#if isNullable}}
{{chipType}} entryValue;
entryNull = entry.IsNull();
if (!entryNull) {
entryValue = entry.Value();
}
{{else}}
{{chipType}} entryValue = entry;
{{/if}}
{{/unless}}
{{/unless}}

{{#if isStruct}}
{{! TODO: Add support for structs here }}
{{else if (isOctetString type)}}
jbyteArray entryObject = nullptr;
if (!entryNull) {
entryObject = env->NewByteArray(entryValue.size());
env->SetByteArrayRegion(entryObject, 0, entryValue.size(), reinterpret_cast<const jbyte *>(entryValue.data()));
}
{{else if (isCharString type)}}
chip::UtfString {{asLowerCamelCase name}}Str(env, entry);
jstring {{asLowerCamelCase name}}({{asLowerCamelCase name}}Str.jniValue());
jstring entryObject = nullptr;
chip::UtfString entryStr(env, entryValue);
if (!entryNull) {
entryObject = jstring(entryStr.jniValue());
}
{{else}}
jobject entryObject = nullptr;
if (!entryNull) {
jclass entryTypeCls;
chip::JniReferences::GetInstance().GetClassRef(env, "java/lang/{{asJavaBasicTypeForZclType type true}}", entryTypeCls);
chip::JniClass jniClass(entryTypeCls);
jmethodID entryTypeCtor = env->GetMethodID(entryTypeCls, "<init>", "({{asJniSignature type false}})V");
entryObject = env->NewObject(entryTypeCls, entryTypeCtor, entryValue);
}
{{/if}}

{{#if isOptional}}
jobject entryOptional = nullptr;
chip::JniReferences::GetInstance().CreateOptional(entryObject, entryOptional);
env->CallBooleanMethod(arrayListObj, arrayListAddMethod, entryOptional);
{{else}}
jclass entryTypeCls;
chip::JniReferences::GetInstance().GetClassRef(env, "java/lang/{{asJavaBasicTypeForZclType type true}}", entryTypeCls);
jmethodID entryTypeCtor = env->GetMethodID(entryTypeCls, "<init>", "({{asJniSignature type}})V");
jobject {{asLowerCamelCase name}} = env->NewObject(entryTypeCls, entryTypeCtor, entry);
env->CallBooleanMethod(arrayListObj, arrayListAddMethod, entryObject);
{{/if}}
env->CallBooleanMethod(arrayListObj, arrayListAddMethod, {{asLowerCamelCase name}});
{{/if}}
}
VerifyOrReturn(iter.GetStatus() == CHIP_NO_ERROR, ChipLogError(Zcl, "Error decoding {{asUpperCamelCase name}}Attribute value: %" CHIP_ERROR_FORMAT, iter.GetStatus().Format()));
Expand Down
4 changes: 4 additions & 0 deletions src/controller/java/templates/CHIPReadCallbacks.zapt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class CHIP{{chipCallback.name}}AttributeCallback : public chip::Callback::Callba
public:
CHIP{{chipCallback.name}}AttributeCallback(jobject javaCallback, bool keepAlive = false);

~CHIP{{chipCallback.name}}AttributeCallback();

static void maybeDestroy(CHIP{{chipCallback.name}}AttributeCallback * callback) {
if (!callback->keepAlive) {
callback->Cancel();
Expand All @@ -33,6 +35,8 @@ class CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCall
public:
CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback(jobject javaCallback);

~CHIP{{asUpperCamelCase parent.name}}{{asUpperCamelCase name}}AttributeCallback();

static void CallbackFn(void * context, {{zapTypeToDecodableClusterObjectType type ns=parent.name isArgument=true}} list);

private:
Expand Down
Loading

0 comments on commit 8329bcf

Please sign in to comment.