Skip to content

Commit bd4515c

Browse files
[Android] Use InvokeCommand and support nullable/optional for commands (#11873)
* Use InvokeCommand and support nullable/optional for commands. * Regenerate * Restyled by whitespace * Restyled by clang-format * Account for array/struct in encode_value/decode_value. * Add TODO for if_is_struct Co-authored-by: Restyled.io <commits@restyled.io>
1 parent 494fb9b commit bd4515c

23 files changed

+12308
-12283
lines changed

src/controller/java/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ shared_library("jni") {
3434
"CHIPDeviceController-JNI.cpp",
3535
"zap-generated/CHIPClusters-JNI.cpp",
3636
"zap-generated/CHIPClustersRead-JNI.cpp",
37+
"zap-generated/CHIPInvokeCallbacks.cpp",
38+
"zap-generated/CHIPInvokeCallbacks.h",
3739
"zap-generated/CHIPReadCallbacks.cpp",
3840
"zap-generated/CHIPReadCallbacks.h",
3941
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{{> header}}
2+
{{#if (chip_has_client_clusters)}}
3+
#include <app/util/af-enums.h>
4+
#include <app-common/zap-generated/cluster-objects.h>
5+
6+
typedef void (*CHIPDefaultSuccessCallbackType)(void *, const chip::app::DataModel::NullObjectType &);
7+
typedef void (*CHIPDefaultFailureCallbackType)(void *, EmberAfStatus);
8+
9+
{{#chip_client_clusters}}
10+
{{#chip_cluster_responses}}
11+
typedef void (*CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}CallbackType)(void *, const chip::app::Clusters::{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::DecodableType &);
12+
{{/chip_cluster_responses}}
13+
{{/chip_client_clusters}}
14+
{{/if}}

src/controller/java/templates/CHIPClusters-JNI.zapt

+21-145
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{{> header}}
22
{{#if (chip_has_client_clusters)}}
3+
#include "CHIPCallbackTypes.h"
4+
#include "CHIPInvokeCallbacks.h"
35
#include "CHIPReadCallbacks.h"
46

57
#include <app-common/zap-generated/cluster-objects.h>
@@ -8,7 +10,6 @@
810

911
#include <controller/java/AndroidClusterExceptions.h>
1012
#include <controller/java/CHIPDefaultCallbacks.h>
11-
#include <lib/support/CHIPJNIError.h>
1213
#include <lib/support/JniReferences.h>
1314
#include <lib/support/JniTypeWrappers.h>
1415
#include <jni.h>
@@ -22,110 +23,6 @@
2223
using namespace chip;
2324
using namespace chip::Controller;
2425

25-
{{! TODO(#8773): Clean up callbacks. }}
26-
27-
{{#chip_client_clusters}}
28-
{{#chip_cluster_responses}}
29-
class CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback : public Callback::Callback<{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback>
30-
{
31-
public:
32-
CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback(jobject javaCallback): Callback::Callback<{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback>(CallbackFn, this)
33-
{
34-
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
35-
if (env == nullptr) {
36-
ChipLogError(Zcl, "Could not create global reference for Java callback");
37-
return;
38-
}
39-
40-
javaCallbackRef = env->NewGlobalRef(javaCallback);
41-
if (javaCallbackRef == nullptr) {
42-
ChipLogError(Zcl, "Could not create global reference for Java callback");
43-
}
44-
}
45-
~CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback()
46-
{
47-
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
48-
if (env == nullptr) {
49-
ChipLogError(Zcl, "Could not create global reference for Java callback");
50-
return;
51-
}
52-
env->DeleteGlobalRef(javaCallbackRef);
53-
};
54-
55-
static void CallbackFn(void * context{{#chip_cluster_response_arguments}}, {{asUnderlyingZclType type}} {{asSymbol label}}{{/chip_cluster_response_arguments}})
56-
{
57-
chip::DeviceLayer::StackUnlock unlock;
58-
CHIP_ERROR err = CHIP_NO_ERROR;
59-
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
60-
jobject javaCallbackRef;
61-
jmethodID javaMethod;
62-
CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback * cppCallback = nullptr;
63-
{{#chip_cluster_response_arguments}}
64-
{{#if (isOctetString type)}}
65-
jbyteArray {{asSymbol label}}Arr;
66-
{{else if (isShortString type)}}
67-
UtfString {{asSymbol label}}Str(env, {{asSymbol label}});
68-
{{/if}}
69-
{{/chip_cluster_response_arguments}}
70-
71-
VerifyOrExit(env != nullptr, err = CHIP_JNI_ERROR_NO_ENV);
72-
73-
cppCallback = reinterpret_cast<CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback *>(context);
74-
VerifyOrExit(cppCallback != nullptr, err = CHIP_JNI_ERROR_NULL_OBJECT);
75-
76-
javaCallbackRef = cppCallback->javaCallbackRef;
77-
VerifyOrExit(javaCallbackRef != nullptr, err = CHIP_NO_ERROR);
78-
79-
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);
80-
SuccessOrExit(err);
81-
82-
{{#chip_cluster_response_arguments}}
83-
{{#if (isOctetString type)}}
84-
{{asSymbol label}}Arr = env->NewByteArray({{asSymbol label}}.size());
85-
VerifyOrExit({{asSymbol label}}Arr != nullptr, err = CHIP_ERROR_NO_MEMORY);
86-
env->ExceptionClear();
87-
env->SetByteArrayRegion({{asSymbol label}}Arr, 0, {{asSymbol label}}.size(), reinterpret_cast<const jbyte *>({{asSymbol label}}.data()));
88-
VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
89-
{{/if}}
90-
{{/chip_cluster_response_arguments}}
91-
92-
env->CallVoidMethod(javaCallbackRef, javaMethod
93-
{{#chip_cluster_response_arguments}}
94-
{{#if isArray}}
95-
// {{asSymbol label}}: {{asUnderlyingZclType type}}
96-
// Conversion from this type to Java is not properly implemented yet
97-
{{else if (isOctetString type)}}
98-
, {{asSymbol label}}Arr
99-
{{else if (isShortString type)}}
100-
, {{asSymbol label}}Str.jniValue()
101-
{{else}}
102-
, static_cast<{{asJniBasicTypeForZclType type}}>({{asSymbol label}})
103-
{{/if}}
104-
{{/chip_cluster_response_arguments}}
105-
);
106-
107-
{{#chip_cluster_response_arguments}}
108-
{{#if (isOctetString type)}}
109-
env->DeleteLocalRef({{asSymbol label}}Arr);
110-
{{/if}}
111-
{{/chip_cluster_response_arguments}}
112-
113-
exit:
114-
if (err != CHIP_NO_ERROR) {
115-
ChipLogError(Zcl, "Error invoking Java callback: %" CHIP_ERROR_FORMAT, err.Format());
116-
}
117-
if (cppCallback != nullptr) {
118-
cppCallback->Cancel();
119-
delete cppCallback;
120-
}
121-
}
122-
123-
private:
124-
jobject javaCallbackRef;
125-
};
126-
127-
{{/chip_cluster_responses}}
128-
{{/chip_client_clusters}}
12926
JNI_METHOD(void, BaseChipCluster, deleteCluster)(JNIEnv * env, jobject self, jlong clusterPtr)
13027
{
13128
chip::DeviceLayer::StackLock lock;
@@ -146,58 +43,37 @@ JNI_METHOD(jlong, {{asUpperCamelCase name}}Cluster, initWithDevice)(JNIEnv * env
14643
}
14744

14845
{{#chip_cluster_commands}}
149-
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}})
46+
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 true}} {{asLowerCamelCase label}}{{/chip_cluster_command_arguments_with_structs_expanded}})
15047
{
15148
chip::DeviceLayer::StackLock lock;
15249
CHIP_ERROR err = CHIP_NO_ERROR;
15350
{{asUpperCamelCase ../name}}Cluster * cppCluster;
15451

155-
{{#chip_cluster_command_arguments_with_structs_expanded}}
156-
{{#if (isOctetString type)}}
157-
JniByteArray {{asLowerCamelCase label}}Arr(env, {{asLowerCamelCase label}});
158-
{{else if (isCharString type)}}
159-
JniUtfString {{asLowerCamelCase label}}Str(env, {{asLowerCamelCase label}});
160-
{{/if}}
161-
{{/chip_cluster_command_arguments_with_structs_expanded}}
52+
chip::app::Clusters::{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::Type request;
16253

163-
{{#if hasSpecificResponse}}
164-
std::unique_ptr<CHIP{{asCamelCased parent.name false}}Cluster{{asCamelCased responseName false}}Callback, void (*)(CHIP{{asCamelCased parent.name false}}Cluster{{asCamelCased responseName false}}Callback *)> onSuccess(
165-
Platform::New<CHIP{{asCamelCased parent.name false}}Cluster{{asCamelCased responseName false}}Callback>(callback), Platform::Delete<CHIP{{asCamelCased parent.name false}}Cluster{{asCamelCased responseName false}}Callback>);
166-
{{else}}
167-
std::unique_ptr<CHIPDefaultSuccessCallback, void (*)(CHIPDefaultSuccessCallback *)> onSuccess(Platform::New<CHIPDefaultSuccessCallback>(callback), Platform::Delete<CHIPDefaultSuccessCallback>);
168-
{{/if}}
54+
{{#chip_cluster_command_arguments}}
55+
{{>encode_value target=(concat "request." (asLowerCamelCase label)) source=(asLowerCamelCase label)}}
56+
{{/chip_cluster_command_arguments}}
57+
58+
{{#*inline "callbackName"}}{{#if hasSpecificResponse}}{{asUpperCamelCase parent.name false}}Cluster{{asUpperCamelCase responseName false}}{{else}}DefaultSuccess{{/if}}{{/inline}}
59+
60+
std::unique_ptr<CHIP{{>callbackName}}Callback, void (*)(CHIP{{>callbackName}}Callback *)> onSuccess(
61+
Platform::New<CHIP{{>callbackName}}Callback>(callback), Platform::Delete<CHIP{{>callbackName}}Callback>);
16962
std::unique_ptr<CHIPDefaultFailureCallback, void (*)(CHIPDefaultFailureCallback *)> onFailure(Platform::New<CHIPDefaultFailureCallback>(callback), Platform::Delete<CHIPDefaultFailureCallback>);
170-
VerifyOrExit(onSuccess.get() != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
171-
VerifyOrExit(onFailure.get() != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
63+
VerifyOrReturn(onSuccess.get() != nullptr, AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error creating native callback", CHIP_ERROR_NO_MEMORY));
64+
VerifyOrReturn(onFailure.get() != nullptr, AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error creating native callback", CHIP_ERROR_NO_MEMORY));
17265

17366
cppCluster = reinterpret_cast<{{asUpperCamelCase ../name}}Cluster *>(clusterPtr);
174-
VerifyOrExit(cppCluster != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
175-
176-
err = cppCluster->{{asCamelCased name false}}(onSuccess->Cancel(), onFailure->Cancel()
177-
{{#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}});
178-
SuccessOrExit(err);
67+
VerifyOrReturn(cppCluster != nullptr, AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error getting native cluster", CHIP_ERROR_INCORRECT_STATE));
17968

180-
exit:
181-
if (err != CHIP_NO_ERROR) {
182-
jthrowable exception;
183-
jmethodID method;
69+
auto successFn = chip::Callback::Callback<CHIP{{>callbackName}}CallbackType>::FromCancelable(onSuccess->Cancel());
70+
auto failureFn = chip::Callback::Callback<CHIPDefaultFailureCallbackType>::FromCancelable(onFailure->Cancel());
18471

185-
err = JniReferences::GetInstance().FindMethod(env, callback, "onError", "(Ljava/lang/Exception;)V", &method);
186-
if (err != CHIP_NO_ERROR) {
187-
ChipLogError(Zcl, "Error throwing IllegalStateException %" CHIP_ERROR_FORMAT, err.Format());
188-
return;
189-
}
72+
err = cppCluster->InvokeCommand(request, onSuccess->mContext, successFn->mCall, failureFn->mCall);
73+
VerifyOrReturn(err == CHIP_NO_ERROR, AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error invoking command", CHIP_ERROR_INCORRECT_STATE));
19074

191-
err = chip::AndroidClusterExceptions::GetInstance().CreateIllegalStateException(env, "Error invoking cluster", err, exception);
192-
if (err != CHIP_NO_ERROR) {
193-
ChipLogError(Zcl, "Error throwing IllegalStateException %" CHIP_ERROR_FORMAT, err.Format());
194-
return;
195-
}
196-
env->CallVoidMethod(callback, method, exception);
197-
} else {
198-
onSuccess.release();
199-
onFailure.release();
200-
}
75+
onSuccess.release();
76+
onFailure.release();
20177
}
20278
{{/chip_cluster_commands}}
20379
{{#chip_server_cluster_attributes}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{{> header}}
2+
{{#if (chip_has_client_clusters)}}
3+
#include "CHIPCallbackTypes.h"
4+
#include "CHIPInvokeCallbacks.h"
5+
6+
#include <app-common/zap-generated/cluster-objects.h>
7+
#include <jni.h>
8+
#include <lib/support/CodeUtils.h>
9+
#include <lib/support/CHIPJNIError.h>
10+
#include <lib/support/JniReferences.h>
11+
#include <lib/support/JniTypeWrappers.h>
12+
#include <platform/PlatformManager.h>
13+
14+
{{! TODO(#8773): Clean up callbacks. }}
15+
16+
namespace chip {
17+
18+
{{#chip_client_clusters}}
19+
{{#chip_cluster_responses}}
20+
CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback::CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback(jobject javaCallback): Callback::Callback<CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}CallbackType>(CallbackFn, this)
21+
{
22+
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
23+
if (env == nullptr) {
24+
ChipLogError(Zcl, "Could not create global reference for Java callback");
25+
return;
26+
}
27+
28+
javaCallbackRef = env->NewGlobalRef(javaCallback);
29+
if (javaCallbackRef == nullptr) {
30+
ChipLogError(Zcl, "Could not create global reference for Java callback");
31+
}
32+
}
33+
34+
CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback::~CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback()
35+
{
36+
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
37+
if (env == nullptr) {
38+
ChipLogError(Zcl, "Could not delete global reference for Java callback");
39+
return;
40+
}
41+
env->DeleteGlobalRef(javaCallbackRef);
42+
};
43+
44+
void CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback::CallbackFn(void * context, const chip::app::Clusters::{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::DecodableType & dataResponse)
45+
{
46+
chip::DeviceLayer::StackUnlock unlock;
47+
CHIP_ERROR err = CHIP_NO_ERROR;
48+
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
49+
jobject javaCallbackRef;
50+
jmethodID javaMethod;
51+
52+
VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Error invoking Java callback: no JNIEnv"));
53+
54+
std::unique_ptr<CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback, void (*)(CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback *)> cppCallback(
55+
reinterpret_cast<CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback *>(context),
56+
chip::Platform::Delete<CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback>
57+
);
58+
VerifyOrReturn(cppCallback != nullptr, ChipLogError(Zcl, "Error invoking Java callback: failed to cast native callback"));
59+
60+
javaCallbackRef = cppCallback->javaCallbackRef;
61+
// Java callback is allowed to be null, exit early if this is the case.
62+
VerifyOrReturn(javaCallbackRef != nullptr);
63+
64+
err = JniReferences::GetInstance().FindMethod(env, javaCallbackRef, "onSuccess", "({{#chip_cluster_response_arguments}}{{#if isArray}}{{else if isOptional}}Ljava/util/Optional;{{else if (isOctetString type)}}[B{{else if (isShortString type)}}Ljava/lang/String;{{else}}{{asJniSignature type true}}{{/if}}{{/chip_cluster_response_arguments}})V", &javaMethod);
65+
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Zcl, "Error invoking Java callback: %s", ErrorStr(err)));
66+
67+
{{#chip_cluster_response_arguments}}
68+
{{>decode_value}}
69+
{{/chip_cluster_response_arguments}}
70+
71+
env->CallVoidMethod(javaCallbackRef, javaMethod{{#chip_cluster_response_arguments}}, {{asSymbol label}}{{/chip_cluster_response_arguments}});
72+
}
73+
{{/chip_cluster_responses}}
74+
{{/chip_client_clusters}}
75+
} // namespace chip
76+
{{/if}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{{> header}}
2+
{{#if (chip_has_client_clusters)}}
3+
#include "CHIPCallbackTypes.h"
4+
5+
#include <app-common/zap-generated/cluster-objects.h>
6+
#include <jni.h>
7+
#include <zap-generated/CHIPClientCallbacks.h>
8+
9+
namespace chip {
10+
11+
{{#chip_client_clusters}}
12+
{{#chip_cluster_responses}}
13+
class CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback : public Callback::Callback<CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}CallbackType>
14+
{
15+
public:
16+
CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback(jobject javaCallback);
17+
18+
~CHIP{{asUpperCamelCase parent.name}}Cluster{{asUpperCamelCase name}}Callback();
19+
20+
static void CallbackFn(void * context, const chip::app::Clusters::{{asUpperCamelCase parent.name}}::Commands::{{asUpperCamelCase name}}::DecodableType & data);
21+
22+
private:
23+
jobject javaCallbackRef;
24+
};
25+
26+
{{/chip_cluster_responses}}
27+
{{/chip_client_clusters}}
28+
} // namespace chip
29+
{{/if}}

0 commit comments

Comments
 (0)