Skip to content

Commit bbd1cdf

Browse files
[Android] Add Status handling for onReport code path
1 parent 7cc357e commit bbd1cdf

File tree

5 files changed

+198
-28
lines changed

5 files changed

+198
-28
lines changed

src/controller/java/AndroidCallbacks.cpp

+65-28
Original file line numberDiff line numberDiff line change
@@ -55,22 +55,6 @@ CHIP_ERROR CreateChipAttributePath(JNIEnv * env, const app::ConcreteDataAttribut
5555
return CHIP_NO_ERROR;
5656
}
5757

58-
CHIP_ERROR ReportCallback::CreateChipEventPath(JNIEnv * env, const app::ConcreteEventPath & aPath, jobject & outObj)
59-
{
60-
jclass eventPathCls = nullptr;
61-
ReturnErrorOnFailure(
62-
JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/model/ChipEventPath", eventPathCls));
63-
64-
jmethodID eventPathCtor =
65-
env->GetStaticMethodID(eventPathCls, "newInstance", "(IJJ)Lchip/devicecontroller/model/ChipEventPath;");
66-
VerifyOrReturnError(eventPathCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND);
67-
68-
outObj = env->CallStaticObjectMethod(eventPathCls, eventPathCtor, static_cast<jint>(aPath.mEndpointId),
69-
static_cast<jlong>(aPath.mClusterId), static_cast<jlong>(aPath.mEventId));
70-
VerifyOrReturnError(outObj != nullptr, CHIP_JNI_ERROR_NULL_OBJECT);
71-
return CHIP_NO_ERROR;
72-
}
73-
7458
GetConnectedDeviceCallback::GetConnectedDeviceCallback(jobject wrapperCallback, jobject javaCallback) :
7559
mOnSuccess(OnDeviceConnectedFn, this), mOnFailure(OnDeviceConnectionFailureFn, this)
7660
{
@@ -270,21 +254,60 @@ CHIP_ERROR ConvertReportTlvToJson(const uint32_t id, TLV::TLVReader & data, std:
270254
return TlvToJson(readerForJson, json);
271255
}
272256

257+
static CHIP_ERROR CreateStatus(JNIEnv * env, const app::StatusIB & aStatus, jobject & outObj)
258+
{
259+
jclass statusCls = nullptr;
260+
ReturnErrorOnFailure(JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/model/Status", statusCls));
261+
jmethodID statusCtor = nullptr;
262+
if (aStatus.mClusterStatus.HasValue())
263+
{
264+
statusCtor = env->GetStaticMethodID(statusCls, "newInstance",
265+
"(II)Lchip/devicecontroller/model/Status");
266+
VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN);
267+
VerifyOrReturnError(statusCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND);
268+
outObj = env->CallStaticObjectMethod(statusCls, statusCtor, static_cast<jint>(aStatus.mStatus),
269+
static_cast<jint>(aStatus.mClusterStatus.Value()));
270+
}
271+
else
272+
{
273+
statusCtor = env->GetStaticMethodID(statusCls, "newInstance",
274+
"(I)Lchip/devicecontroller/model/Status");
275+
VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN);
276+
VerifyOrReturnError(statusCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND);
277+
outObj = env->CallStaticObjectMethod(statusCls, statusCtor, static_cast<jint>(aStatus.mStatus));
278+
}
279+
VerifyOrReturnError(outObj != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND);
280+
return CHIP_NO_ERROR;
281+
}
282+
283+
273284
void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPath, TLV::TLVReader * apData,
274285
const app::StatusIB & aStatus)
275286
{
276287
CHIP_ERROR err = CHIP_NO_ERROR;
277288
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
278289
VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread"));
279290
JniLocalReferenceScope scope(env);
280-
281-
jobject attributePathObj = nullptr;
282-
err = CreateChipAttributePath(env, aPath, attributePathObj);
283-
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to create Java ChipAttributePath: %s", ErrorStr(err)));
284-
285291
VerifyOrReturn(!aPath.IsListItemOperation(), ChipLogError(Controller, "Expect non-list item operation"); aPath.LogPath());
286-
VerifyOrReturn(aStatus.IsSuccess(), ChipLogError(Controller, "Receive bad status %s", ErrorStr(aStatus.ToChipError()));
287-
aPath.LogPath());
292+
293+
jobject nodeState = mNodeStateObj.ObjectRef();
294+
if (aStatus.IsFailure())
295+
{
296+
ChipLogError(Controller, "Receive bad status %s", ErrorStr(aStatus.ToChipError()));
297+
jobject statusObj = nullptr;
298+
err = CreateStatus(env, aStatus, statusObj);
299+
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Fail to create status with error %" CHIP_ERROR_FORMAT, err.Format()));
300+
// Add Attribute Status to NodeState
301+
jmethodID addAttributeStatusMethod = nullptr;
302+
err = JniReferences::GetInstance().FindMethod(env, nodeState, "addAttributeStatus",
303+
"(IJJLchip/devicecontroller/model/Status;)V", &addAttributeStatusMethod);
304+
VerifyOrReturn(err == CHIP_NO_ERROR,
305+
ChipLogError(Controller, "Could not find addAttributeStatus method with error %" CHIP_ERROR_FORMAT, err.Format()));
306+
env->CallVoidMethod(nodeState, addAttributeStatusMethod, static_cast<jint>(aPath.mEndpointId), static_cast<jlong>(aPath.mClusterId),
307+
static_cast<jlong>(aPath.mAttributeId), statusObj);
308+
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe());
309+
return;
310+
}
288311
VerifyOrReturn(apData != nullptr, ChipLogError(Controller, "Receive empty apData"); aPath.LogPath());
289312

290313
TLV::TLVReader readerForJavaTLV;
@@ -345,7 +368,6 @@ void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPat
345368
VerifyOrReturn(attributeStateObj != nullptr, ChipLogError(Controller, "Could not create AttributeState object");
346369
aPath.LogPath());
347370

348-
jobject nodeState = mNodeStateObj.ObjectRef();
349371
// Add AttributeState to NodeState
350372
jmethodID addAttributeMethod;
351373
err = JniReferences::GetInstance().FindMethod(env, nodeState, "addAttribute",
@@ -401,10 +423,25 @@ void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLV
401423
CHIP_ERROR err = CHIP_NO_ERROR;
402424
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
403425
VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread"));
404-
jobject eventPathObj = nullptr;
405-
err = CreateChipEventPath(env, aEventHeader.mPath, eventPathObj);
406-
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to create Java ChipEventPath: %s", ErrorStr(err)));
407426

427+
jobject nodeState = mNodeStateObj.ObjectRef();
428+
if (apStatus != nullptr && apStatus->IsFailure())
429+
{
430+
ChipLogError(Controller, "Receive bad status %s", ErrorStr(apStatus->ToChipError()));
431+
jobject statusObj = nullptr;
432+
err = CreateStatus(env, *apStatus, statusObj);
433+
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Fail to create status with error %" CHIP_ERROR_FORMAT, err.Format()));
434+
// Add Event Status to NodeState
435+
jmethodID addEventStatusMethod;
436+
err = JniReferences::GetInstance().FindMethod(env, nodeState, "addEventStatus",
437+
"(IJJLchip/devicecontroller/model/Status;)V", &addEventStatusMethod);
438+
VerifyOrReturn(err == CHIP_NO_ERROR,
439+
ChipLogError(Controller, "Could not find addEventStatus method with error %" CHIP_ERROR_FORMAT, err.Format()));
440+
env->CallVoidMethod(nodeState, addEventStatusMethod, static_cast<jint>(aEventHeader.mPath.mEndpointId),
441+
static_cast<jlong>(aEventHeader.mPath.mClusterId), static_cast<jlong>(aEventHeader.mPath.mEventId), statusObj);
442+
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe());
443+
return;
444+
}
408445
VerifyOrReturn(apData != nullptr, ChipLogError(Controller, "Receive empty apData"); aEventHeader.LogPath());
409446

410447
TLV::TLVReader readerForJavaTLV;
@@ -484,7 +521,7 @@ void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLV
484521

485522
// Add EventState to NodeState
486523
jmethodID addEventMethod;
487-
jobject nodeState = mNodeStateObj.ObjectRef();
524+
488525
err = JniReferences::GetInstance().FindMethod(env, nodeState, "addEvent", "(IJJLchip/devicecontroller/model/EventState;)V",
489526
&addEventMethod);
490527
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find addEvent method with error %s", ErrorStr(err));

src/controller/java/BUILD.gn

+1
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ android_library("java") {
482482
"src/chip/devicecontroller/model/EventState.java",
483483
"src/chip/devicecontroller/model/InvokeElement.java",
484484
"src/chip/devicecontroller/model/NodeState.java",
485+
"src/chip/devicecontroller/model/Status.java",
485486
]
486487

487488
if (matter_enable_tlv_decoder_api) {

src/controller/java/src/chip/devicecontroller/model/ClusterState.java

+31
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public final class ClusterState {
3232
private static final String TAG = "ClusterState";
3333
private Map<Long, AttributeState> attributes;
3434
private Map<Long, ArrayList<EventState>> events;
35+
private Map<Long, Status> attributeStatuses;
36+
private Map<Long, ArrayList<Status>> eventStatuses;
3537
private Optional<Long> dataVersion;
3638

3739
public ClusterState(
@@ -45,10 +47,18 @@ public Map<Long, AttributeState> getAttributeStates() {
4547
return attributes;
4648
}
4749

50+
public Map<Long, Status> getAttributeStatuses() {
51+
return attributeStatuses;
52+
}
53+
4854
public Map<Long, ArrayList<EventState>> getEventStates() {
4955
return events;
5056
}
5157

58+
public Map<Long, ArrayList<Status>> getEventStatuses() {
59+
return eventStatuses;
60+
}
61+
5262
public void setDataVersion(long version) {
5363
dataVersion = Optional.of(version);
5464
}
@@ -130,6 +140,27 @@ public String toString() {
130140
builder.append("\n");
131141
});
132142
});
143+
attributeStatuses.forEach(
144+
(attributeId, status) -> {
145+
builder.append("Attribute Status ");
146+
builder.append(attributeId);
147+
builder.append(": ");
148+
builder.append(
149+
status.toString());
150+
builder.append("\n");
151+
});
152+
eventStatuses.forEach(
153+
(eventId, status) -> {
154+
status.forEach(
155+
(eventState) -> {
156+
builder.append("Event Status");
157+
builder.append(eventId);
158+
builder.append(": ");
159+
builder.append(
160+
status.toString());
161+
builder.append("\n");
162+
});
163+
});
133164
return builder.toString();
134165
}
135166
}

src/controller/java/src/chip/devicecontroller/model/NodeState.java

+37
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,43 @@ private void addEvent(int endpointId, long clusterId, long eventId, EventState e
8282
clusterState.getEventStates().get(eventId).add(eventStateToAdd);
8383
}
8484

85+
// Called from native code only, which ignores access modifiers.
86+
private void addAttributeStatus(
87+
int endpointId, long clusterId, long attributeId, Status statusToAdd) {
88+
EndpointState endpointState = getEndpointState(endpointId);
89+
if (endpointState == null) {
90+
endpointState = new EndpointState(new HashMap<>());
91+
getEndpointStates().put(endpointId, endpointState);
92+
}
93+
94+
ClusterState clusterState = endpointState.getClusterState(clusterId);
95+
if (clusterState == null) {
96+
clusterState = new ClusterState(new HashMap<>(), new HashMap<>());
97+
endpointState.getClusterStates().put(clusterId, clusterState);
98+
}
99+
100+
clusterState.getAttributeStatuses().put(attributeId, statusToAdd);
101+
}
102+
103+
private void addEventStatus(int endpointId, long clusterId, long eventId, Status statusToAdd) {
104+
EndpointState endpointState = getEndpointState(endpointId);
105+
if (endpointState == null) {
106+
endpointState = new EndpointState(new HashMap<>());
107+
getEndpointStates().put(endpointId, endpointState);
108+
}
109+
110+
ClusterState clusterState = endpointState.getClusterState(clusterId);
111+
if (clusterState == null) {
112+
clusterState = new ClusterState(new HashMap<>(), new HashMap<>());
113+
endpointState.getClusterStates().put(clusterId, clusterState);
114+
}
115+
116+
if (!clusterState.getEventStatuses().containsKey(eventId)) {
117+
clusterState.getEventStatuses().put(eventId, new ArrayList<Status>());
118+
}
119+
clusterState.getEventStatuses().get(eventId).add(statusToAdd);
120+
}
121+
85122
@Override
86123
public String toString() {
87124
StringBuilder builder = new StringBuilder();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) 2024 Project CHIP Authors
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package chip.devicecontroller.model;
20+
21+
import java.util.Locale;
22+
import java.util.Optional;
23+
24+
public final class Status {
25+
private Integer status;
26+
private Optional<Integer> clusterStatus;
27+
28+
private Status(int status, Optional<Integer> clusterStatus) {
29+
this.status = status;
30+
this.clusterStatus = clusterStatus;
31+
}
32+
33+
// Getters
34+
public int getStatus() {
35+
return status;
36+
}
37+
38+
public Optional<Integer> getClusterStatus() {
39+
return clusterStatus;
40+
}
41+
42+
public String toString() {
43+
return String.format(
44+
Locale.ENGLISH,
45+
"status %s, clusterStatus %s",
46+
String.valueOf(status),
47+
clusterStatus.isPresent() ? String.valueOf(clusterStatus) : "None");
48+
}
49+
50+
public static Status newInstance(
51+
int status,
52+
int clusterStatus) {
53+
return new Status(
54+
status,
55+
Optional.of(clusterStatus));
56+
}
57+
58+
public static Status newInstance(
59+
int status) {
60+
return new Status(
61+
status,
62+
Optional.empty());
63+
}
64+
}

0 commit comments

Comments
 (0)