Skip to content

Commit

Permalink
[Android] Add Status handling for onReport code path
Browse files Browse the repository at this point in the history
  • Loading branch information
yunhanw-google committed Feb 12, 2024
1 parent 7cc357e commit bbd1cdf
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 28 deletions.
93 changes: 65 additions & 28 deletions src/controller/java/AndroidCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,6 @@ CHIP_ERROR CreateChipAttributePath(JNIEnv * env, const app::ConcreteDataAttribut
return CHIP_NO_ERROR;
}

CHIP_ERROR ReportCallback::CreateChipEventPath(JNIEnv * env, const app::ConcreteEventPath & aPath, jobject & outObj)
{
jclass eventPathCls = nullptr;
ReturnErrorOnFailure(
JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/model/ChipEventPath", eventPathCls));

jmethodID eventPathCtor =
env->GetStaticMethodID(eventPathCls, "newInstance", "(IJJ)Lchip/devicecontroller/model/ChipEventPath;");
VerifyOrReturnError(eventPathCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND);

outObj = env->CallStaticObjectMethod(eventPathCls, eventPathCtor, static_cast<jint>(aPath.mEndpointId),
static_cast<jlong>(aPath.mClusterId), static_cast<jlong>(aPath.mEventId));
VerifyOrReturnError(outObj != nullptr, CHIP_JNI_ERROR_NULL_OBJECT);
return CHIP_NO_ERROR;
}

GetConnectedDeviceCallback::GetConnectedDeviceCallback(jobject wrapperCallback, jobject javaCallback) :
mOnSuccess(OnDeviceConnectedFn, this), mOnFailure(OnDeviceConnectionFailureFn, this)
{
Expand Down Expand Up @@ -270,21 +254,60 @@ CHIP_ERROR ConvertReportTlvToJson(const uint32_t id, TLV::TLVReader & data, std:
return TlvToJson(readerForJson, json);
}

static CHIP_ERROR CreateStatus(JNIEnv * env, const app::StatusIB & aStatus, jobject & outObj)
{
jclass statusCls = nullptr;
ReturnErrorOnFailure(JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/model/Status", statusCls));
jmethodID statusCtor = nullptr;
if (aStatus.mClusterStatus.HasValue())
{
statusCtor = env->GetStaticMethodID(statusCls, "newInstance",
"(II)Lchip/devicecontroller/model/Status");
VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN);
VerifyOrReturnError(statusCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND);
outObj = env->CallStaticObjectMethod(statusCls, statusCtor, static_cast<jint>(aStatus.mStatus),
static_cast<jint>(aStatus.mClusterStatus.Value()));
}
else
{
statusCtor = env->GetStaticMethodID(statusCls, "newInstance",
"(I)Lchip/devicecontroller/model/Status");
VerifyOrReturnError(!env->ExceptionCheck(), CHIP_JNI_ERROR_EXCEPTION_THROWN);
VerifyOrReturnError(statusCtor != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND);
outObj = env->CallStaticObjectMethod(statusCls, statusCtor, static_cast<jint>(aStatus.mStatus));
}
VerifyOrReturnError(outObj != nullptr, CHIP_JNI_ERROR_METHOD_NOT_FOUND);
return CHIP_NO_ERROR;
}


void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPath, TLV::TLVReader * apData,
const app::StatusIB & aStatus)
{
CHIP_ERROR err = CHIP_NO_ERROR;
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread"));
JniLocalReferenceScope scope(env);

jobject attributePathObj = nullptr;
err = CreateChipAttributePath(env, aPath, attributePathObj);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to create Java ChipAttributePath: %s", ErrorStr(err)));

VerifyOrReturn(!aPath.IsListItemOperation(), ChipLogError(Controller, "Expect non-list item operation"); aPath.LogPath());
VerifyOrReturn(aStatus.IsSuccess(), ChipLogError(Controller, "Receive bad status %s", ErrorStr(aStatus.ToChipError()));
aPath.LogPath());

jobject nodeState = mNodeStateObj.ObjectRef();
if (aStatus.IsFailure())
{
ChipLogError(Controller, "Receive bad status %s", ErrorStr(aStatus.ToChipError()));
jobject statusObj = nullptr;
err = CreateStatus(env, aStatus, statusObj);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Fail to create status with error %" CHIP_ERROR_FORMAT, err.Format()));
// Add Attribute Status to NodeState
jmethodID addAttributeStatusMethod = nullptr;
err = JniReferences::GetInstance().FindMethod(env, nodeState, "addAttributeStatus",
"(IJJLchip/devicecontroller/model/Status;)V", &addAttributeStatusMethod);
VerifyOrReturn(err == CHIP_NO_ERROR,
ChipLogError(Controller, "Could not find addAttributeStatus method with error %" CHIP_ERROR_FORMAT, err.Format()));
env->CallVoidMethod(nodeState, addAttributeStatusMethod, static_cast<jint>(aPath.mEndpointId), static_cast<jlong>(aPath.mClusterId),
static_cast<jlong>(aPath.mAttributeId), statusObj);
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe());
return;
}
VerifyOrReturn(apData != nullptr, ChipLogError(Controller, "Receive empty apData"); aPath.LogPath());

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

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

jobject nodeState = mNodeStateObj.ObjectRef();
if (apStatus != nullptr && apStatus->IsFailure())
{
ChipLogError(Controller, "Receive bad status %s", ErrorStr(apStatus->ToChipError()));
jobject statusObj = nullptr;
err = CreateStatus(env, *apStatus, statusObj);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Fail to create status with error %" CHIP_ERROR_FORMAT, err.Format()));
// Add Event Status to NodeState
jmethodID addEventStatusMethod;
err = JniReferences::GetInstance().FindMethod(env, nodeState, "addEventStatus",
"(IJJLchip/devicecontroller/model/Status;)V", &addEventStatusMethod);
VerifyOrReturn(err == CHIP_NO_ERROR,
ChipLogError(Controller, "Could not find addEventStatus method with error %" CHIP_ERROR_FORMAT, err.Format()));
env->CallVoidMethod(nodeState, addEventStatusMethod, static_cast<jint>(aEventHeader.mPath.mEndpointId),
static_cast<jlong>(aEventHeader.mPath.mClusterId), static_cast<jlong>(aEventHeader.mPath.mEventId), statusObj);
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe());
return;
}
VerifyOrReturn(apData != nullptr, ChipLogError(Controller, "Receive empty apData"); aEventHeader.LogPath());

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

// Add EventState to NodeState
jmethodID addEventMethod;
jobject nodeState = mNodeStateObj.ObjectRef();

err = JniReferences::GetInstance().FindMethod(env, nodeState, "addEvent", "(IJJLchip/devicecontroller/model/EventState;)V",
&addEventMethod);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Could not find addEvent method with error %s", ErrorStr(err));
Expand Down
1 change: 1 addition & 0 deletions src/controller/java/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ android_library("java") {
"src/chip/devicecontroller/model/EventState.java",
"src/chip/devicecontroller/model/InvokeElement.java",
"src/chip/devicecontroller/model/NodeState.java",
"src/chip/devicecontroller/model/Status.java",
]

if (matter_enable_tlv_decoder_api) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public final class ClusterState {
private static final String TAG = "ClusterState";
private Map<Long, AttributeState> attributes;
private Map<Long, ArrayList<EventState>> events;
private Map<Long, Status> attributeStatuses;
private Map<Long, ArrayList<Status>> eventStatuses;
private Optional<Long> dataVersion;

public ClusterState(
Expand All @@ -45,10 +47,18 @@ public Map<Long, AttributeState> getAttributeStates() {
return attributes;
}

public Map<Long, Status> getAttributeStatuses() {
return attributeStatuses;
}

public Map<Long, ArrayList<EventState>> getEventStates() {
return events;
}

public Map<Long, ArrayList<Status>> getEventStatuses() {
return eventStatuses;
}

public void setDataVersion(long version) {
dataVersion = Optional.of(version);
}
Expand Down Expand Up @@ -130,6 +140,27 @@ public String toString() {
builder.append("\n");
});
});
attributeStatuses.forEach(
(attributeId, status) -> {
builder.append("Attribute Status ");
builder.append(attributeId);
builder.append(": ");
builder.append(
status.toString());
builder.append("\n");
});
eventStatuses.forEach(
(eventId, status) -> {
status.forEach(
(eventState) -> {
builder.append("Event Status");
builder.append(eventId);
builder.append(": ");
builder.append(
status.toString());
builder.append("\n");
});
});
return builder.toString();
}
}
37 changes: 37 additions & 0 deletions src/controller/java/src/chip/devicecontroller/model/NodeState.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,43 @@ private void addEvent(int endpointId, long clusterId, long eventId, EventState e
clusterState.getEventStates().get(eventId).add(eventStateToAdd);
}

// Called from native code only, which ignores access modifiers.
private void addAttributeStatus(
int endpointId, long clusterId, long attributeId, Status statusToAdd) {
EndpointState endpointState = getEndpointState(endpointId);
if (endpointState == null) {
endpointState = new EndpointState(new HashMap<>());
getEndpointStates().put(endpointId, endpointState);
}

ClusterState clusterState = endpointState.getClusterState(clusterId);
if (clusterState == null) {
clusterState = new ClusterState(new HashMap<>(), new HashMap<>());
endpointState.getClusterStates().put(clusterId, clusterState);
}

clusterState.getAttributeStatuses().put(attributeId, statusToAdd);
}

private void addEventStatus(int endpointId, long clusterId, long eventId, Status statusToAdd) {
EndpointState endpointState = getEndpointState(endpointId);
if (endpointState == null) {
endpointState = new EndpointState(new HashMap<>());
getEndpointStates().put(endpointId, endpointState);
}

ClusterState clusterState = endpointState.getClusterState(clusterId);
if (clusterState == null) {
clusterState = new ClusterState(new HashMap<>(), new HashMap<>());
endpointState.getClusterStates().put(clusterId, clusterState);
}

if (!clusterState.getEventStatuses().containsKey(eventId)) {
clusterState.getEventStatuses().put(eventId, new ArrayList<Status>());
}
clusterState.getEventStatuses().get(eventId).add(statusToAdd);
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
Expand Down
64 changes: 64 additions & 0 deletions src/controller/java/src/chip/devicecontroller/model/Status.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (c) 2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package chip.devicecontroller.model;

import java.util.Locale;
import java.util.Optional;

public final class Status {
private Integer status;
private Optional<Integer> clusterStatus;

private Status(int status, Optional<Integer> clusterStatus) {
this.status = status;
this.clusterStatus = clusterStatus;
}

// Getters
public int getStatus() {
return status;
}

public Optional<Integer> getClusterStatus() {
return clusterStatus;
}

public String toString() {
return String.format(
Locale.ENGLISH,
"status %s, clusterStatus %s",
String.valueOf(status),
clusterStatus.isPresent() ? String.valueOf(clusterStatus) : "None");
}

public static Status newInstance(
int status,
int clusterStatus) {
return new Status(
status,
Optional.of(clusterStatus));
}

public static Status newInstance(
int status) {
return new Status(
status,
Optional.empty());
}
}

0 comments on commit bbd1cdf

Please sign in to comment.