Skip to content

Commit

Permalink
[Android]Pass write response status from jni to application
Browse files Browse the repository at this point in the history
  • Loading branch information
yunhanw-google committed Feb 17, 2024
1 parent 5589ecb commit 67b4d29
Show file tree
Hide file tree
Showing 14 changed files with 170 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import chip.devicecontroller.model.AttributeWriteRequest
import chip.devicecontroller.model.ChipAttributePath
import chip.devicecontroller.model.ChipEventPath
import chip.devicecontroller.model.NodeState
import chip.devicecontroller.model.Status
import com.google.chip.chiptool.ChipClient
import com.google.chip.chiptool.GenericChipDeviceListener
import com.google.chip.chiptool.R
Expand Down Expand Up @@ -191,8 +192,8 @@ class BasicClientFragment : Fragment() {
Log.e(TAG, "Write ${attribute.name} failure", ex)
}

override fun onResponse(attributePath: ChipAttributePath?) {
showMessage("Write ${attribute.name} success")
override fun onResponse(attributePath: ChipAttributePath, status: Status) {
showMessage("Write ${attribute.name} response: $Status")
}
},
devicePtr,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import chip.devicecontroller.model.ChipEventPath
import chip.devicecontroller.model.ChipPathId
import chip.devicecontroller.model.InvokeElement
import chip.devicecontroller.model.NodeState
import chip.devicecontroller.model.Status
import com.google.chip.chiptool.ChipClient
import com.google.chip.chiptool.R
import com.google.chip.chiptool.databinding.WildcardFragmentBinding
Expand Down Expand Up @@ -92,8 +93,8 @@ class WildcardFragment : Fragment() {
Log.e(TAG, "Report error for $attributePath: $ex")
}

override fun onResponse(attributePath: ChipAttributePath?) {
val text = "$attributePath : Write Success"
override fun onResponse(attributePath: ChipAttributePath, status: Status) {
val text = "$attributePath : Write response: $Status"
requireActivity().runOnUiThread { binding.outputTv.text = text }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import chip.devicecontroller.GetConnectedDeviceCallbackJni.GetConnectedDeviceCal
import chip.devicecontroller.WriteAttributesCallback
import chip.devicecontroller.model.AttributeWriteRequest
import chip.devicecontroller.model.ChipAttributePath
import chip.devicecontroller.model.Status
import com.matter.controller.commands.common.CredentialsIssuer
import java.util.logging.Level
import java.util.logging.Logger
Expand Down Expand Up @@ -51,11 +52,8 @@ class PairOnNetworkLongImWriteCommand(
setFailure("write failure")
}

override fun onResponse(attributePath: ChipAttributePath?) {
logger.log(Level.INFO, "Write receive OnResponse on ")
if (attributePath != null) {
logger.log(Level.INFO, attributePath.toString())
}
override fun onResponse(attributePath: ChipAttributePath, status: Status) {
logger.log(Level.INFO, "$attributePath : Write response: $status")
setSuccess()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ import chip.devicecontroller.model.ClusterState;
import chip.devicecontroller.model.EndpointState;
import chip.devicecontroller.model.InvokeElement;
import chip.devicecontroller.model.NodeState;
import chip.devicecontroller.model.Status;

import javax.annotation.Nullable;
import java.util.ArrayList;
Expand Down Expand Up @@ -318,8 +319,15 @@ public class ChipClusters {
}

@Override
public void onResponse(ChipAttributePath attributePath) {
callback.onSuccess();
public void onResponse(ChipAttributePath attributePath, Status status) {
if (status.getStatus() == Status.StatusCode.Success)
{
callback.onSuccess();
}
else
{
callback.onError(new StatusException(status.getStatus()));
}
}

@Override
Expand Down
22 changes: 13 additions & 9 deletions src/controller/java/AndroidCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,23 +669,27 @@ void WriteAttributesCallback::OnResponse(const app::WriteClient * apWriteClient,
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
VerifyOrReturn(env != nullptr, ChipLogError(Controller, "Could not get JNIEnv for current thread"));
JniLocalReferenceScope scope(env);

if (aStatus.mStatus != Protocols::InteractionModel::Status::Success)
{
ReportError(&aPath, aStatus.mStatus);
return;
}

jmethodID onResponseMethod;
VerifyOrReturn(mWrapperCallbackRef.HasValidObjectRef(),
ChipLogError(Controller, "mWrapperCallbackRef is not valid in %s", __func__));
jobject wrapperCallback = mWrapperCallbackRef.ObjectRef();
err = JniReferences::GetInstance().FindMethod(env, wrapperCallback, "onResponse", "(IJJ)V", &onResponseMethod);
err = JniReferences::GetInstance().FindMethod(env, wrapperCallback, "onResponse", "(IJJILjava/lang/Integer;)V",
&onResponseMethod);
VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(Controller, "Unable to find onError method: %s", ErrorStr(err)));

jobject jClusterState = nullptr;
if (aStatus.mClusterStatus.HasValue())
{
err = JniReferences::GetInstance().CreateBoxedObject<jint>(
"java/lang/Integer", "(I)V", static_cast<jint>(aStatus.mClusterStatus.Value()), jClusterState);
VerifyOrReturn(err == CHIP_NO_ERROR,
ChipLogError(Controller, "Could not CreateBoxedObject with error %" CHIP_ERROR_FORMAT, err.Format()));
}

DeviceLayer::StackUnlock unlock;
env->CallVoidMethod(wrapperCallback, onResponseMethod, static_cast<jint>(aPath.mEndpointId),
static_cast<jlong>(aPath.mClusterId), static_cast<jlong>(aPath.mAttributeId));
static_cast<jlong>(aPath.mClusterId), static_cast<jlong>(aPath.mAttributeId), aStatus.mStatus,
jClusterState);
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe());
}

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 @@ -477,6 +477,7 @@ android_library("java") {
"src/chip/devicecontroller/ReportCallback.java",
"src/chip/devicecontroller/ReportCallbackJni.java",
"src/chip/devicecontroller/ResubscriptionAttemptCallback.java",
"src/chip/devicecontroller/StatusException.java",
"src/chip/devicecontroller/SubscriptionEstablishedCallback.java",
"src/chip/devicecontroller/ThreadScanResult.java",
"src/chip/devicecontroller/UnpairDeviceCallback.java",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import chip.devicecontroller.model.EndpointState;
import chip.devicecontroller.model.InvokeElement;
import chip.devicecontroller.model.NodeState;
import chip.devicecontroller.model.Status;

import javax.annotation.Nullable;
import java.util.ArrayList;
Expand Down Expand Up @@ -241,8 +242,15 @@ static class WriteAttributesCallbackImpl implements WriteAttributesCallback {
}

@Override
public void onResponse(ChipAttributePath attributePath) {
callback.onSuccess();
public void onResponse(ChipAttributePath attributePath, Status status) {
if (status.getStatus() == Status.StatusCode.Success)
{
callback.onSuccess();
}
else
{
callback.onError(new StatusException(status.getStatus()));
}
}

@Override
Expand Down
34 changes: 34 additions & 0 deletions src/controller/java/src/chip/devicecontroller/StatusException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2020-2021 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;

import chip.devicecontroller.model.Status;

/** Exception class holding error codes defined by clusters. */
public class StatusException extends Exception {
private static final long serialVersionUID = 1L;

public Status.StatusCode code = Status.StatusCode.Success;

public StatusException() {}

public StatusException(Status.StatusCode code) {
super(String.format("CHIP IM status error: %s", code.name()));
this.code = code;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package chip.devicecontroller;

import chip.devicecontroller.model.ChipAttributePath;
import chip.devicecontroller.model.Status;
import javax.annotation.Nullable;

/** An interface for receiving write response. */
Expand All @@ -40,8 +41,9 @@ public interface WriteAttributesCallback {
* path.
*
* @param attributePath The attribute path field in write response.
* @param status The status field in write response.
*/
void onResponse(ChipAttributePath attributePath);
void onResponse(ChipAttributePath attributePath, Status status);

default void onDone() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package chip.devicecontroller;

import chip.devicecontroller.model.ChipAttributePath;
import chip.devicecontroller.model.Status;
import javax.annotation.Nullable;

/** JNI wrapper callback class for {@link WriteAttributesCallback}. */
public final class WriteAttributesCallbackJni {
Expand Down Expand Up @@ -45,9 +47,15 @@ private void onError(
e);
}

private void onResponse(int endpointId, long clusterId, long attributeId) {
private void onResponse(
int endpointId,
long clusterId,
long attributeId,
int status,
@Nullable Integer clusterStatus) {
wrappedWriteAttributesCallback.onResponse(
ChipAttributePath.newInstance(endpointId, clusterId, attributeId));
ChipAttributePath.newInstance(endpointId, clusterId, attributeId),
Status.newInstance(status, clusterStatus));
}

private void onDone() {
Expand Down
78 changes: 73 additions & 5 deletions src/controller/java/src/chip/devicecontroller/model/Status.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,84 @@
import java.util.Optional;

public final class Status {
private Integer status;
public enum StatusCode {
Success(0x0),
Failure(0x01),
InvalidSusbscription(0x7d),
UnsupportedAccess(0x7e),
UnsupportedEndPoint(0x7f),
InvalidAction(0x80),
UnsupportedCommand(0x81),
Deprecated82(0x82),
Deprecated83(0x83),
Deprecated84(0x84),
InvalidCommand(0x85),
UnsupportedAttribute(0x86),
ConstraintError(0x87),
UnsupportedWrite(0x88),
ResourceExhausted(0x89),
Deprecated8a(0x8a),
NotFound(0x8b),
UnreportableAttribute(0x8c),
InvalidDataType(0x8d),
Deprecated8e(0x8e),
UnsupportedRead(0x8f),
Deprecated90(0x90),
Deprecated91(0x91),
DataVersionMismatch(0x92),
Deprecated93(0x93),
Timeout(0x94),
Reserved95(0x95),
Reserved96(0x96),
Reserved97(0x97),
Reserved98(0x98),
Reserved99(0x99),
Reserved9a(0x9a),
Busy(0x9c),
Deprecatedc0(0xc0),
Deprecatedc1(0xc1),
Deprecatedc2(0xc2),
UnsupportedCluster(0xc3),
Deprecatedc4(0xc4),
NoUpstreamSubsricption(0xc5),
NeedTimedInteraction(0xc6),
UnsupportedEvent(0xc7),
PathExhausted(0xc8),
TimedRequestMismatch(0xc9),
FailsafeRequired(0xca),
InvalidInState(0xcb),
NoCommandResponse(0xcc);

private int id = 0;

StatusCode(int id) {
this.id = id;
}

public int getId() {
return id;
}

public static StatusCode fromId(int id) {
for (StatusCode type : values()) {
if (type.getId() == id) {
return type;
}
}
return null;
}
}

private StatusCode status = StatusCode.Success;
private Optional<Integer> clusterStatus;

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

// Getters
public Integer getStatus() {
public StatusCode getStatus() {
return status;
}

Expand All @@ -43,7 +111,7 @@ public String toString() {
return String.format(
Locale.ENGLISH,
"status %s, clusterStatus %s",
String.valueOf(status),
status.name(),
clusterStatus.isPresent() ? String.valueOf(clusterStatus.get()) : "None");
}

Expand All @@ -55,7 +123,7 @@ public static Status newInstance(int status) {
return new Status(status, Optional.empty());
}

static Status newInstance(int status, Integer clusterStatus) {
public static Status newInstance(int status, Integer clusterStatus) {
return new Status(status, Optional.ofNullable(clusterStatus));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,10 @@ class MatterControllerImpl(params: ControllerParams) : MatterController {
return suspendCancellableCoroutine { continuation ->
val writeCallback =
object : WriteAttributesCallback {
override fun onResponse(attributePath: AttributePath) {
logger.log(Level.INFO, "write success for attributePath:%s", attributePath.toString())
override fun onResponse(attributePath: AttributePath, status: Status) {
logger.log(Level.INFO, "Receive write response for attributePath:%s, status:%s"",
attributePath.toString(), logger.log(Level.INFO, "write success for attributePath:%s",
status.toString()))
}
override fun onError(attributePath: AttributePath?, ex: Exception) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ interface WriteAttributesCallback {
* path.
*
* @param attributePath The attribute path field in write response.
* @param status The attribute status field in write response.
*/
fun onResponse(attributePath: AttributePath)
fun onResponse(attributePath: AttributePath, status: Status)

fun onDone() {}
}
1 change: 1 addition & 0 deletions src/protocols/interaction_model/StatusCodeList.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

/// WARNING: If you touch this list, please also update src/controller/python/chip/interaction_model/__init__.py
/// WARNING: If you touch this list, please also update src/controller/java/src/chip/devicecontroller/model/Status.java

// clang-format off
CHIP_IM_STATUS_CODE(Success , SUCCESS , 0x0)
Expand Down

0 comments on commit 67b4d29

Please sign in to comment.