[Android]Pass write response status from jni to application (#32164)

diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt
index 0662ec0..f38cacb 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt
@@ -17,6 +17,7 @@
 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
@@ -191,8 +192,8 @@
             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,
diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OtaProviderClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OtaProviderClientFragment.kt
index 8773585..c271591 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OtaProviderClientFragment.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OtaProviderClientFragment.kt
@@ -32,6 +32,7 @@
 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
@@ -223,9 +224,9 @@
           showMessage("Error : ${e.toString()}")
         }
 
-        override fun onResponse(attributePath: ChipAttributePath?) {
+        override fun onResponse(attributePath: ChipAttributePath, status: Status) {
           Log.d(TAG, "onResponse")
-          showMessage("write Success")
+          showMessage("$attributePath : Write response: $status")
         }
       },
       ChipClient.getConnectedDevicePointer(requireContext(), addressUpdateFragment.deviceId),
@@ -350,9 +351,9 @@
           showMessage("error : ${e.toString()}")
         }
 
-        override fun onResponse(attributePath: ChipAttributePath?) {
+        override fun onResponse(attributePath: ChipAttributePath, status: Status) {
           Log.d(TAG, "onResponse")
-          showMessage("write success")
+          showMessage("$attributePath : Write response: $status")
         }
       },
       ChipClient.getConnectedDevicePointer(requireContext(), addressUpdateFragment.deviceId),
diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt
index 1978951..af11958 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt
@@ -27,6 +27,7 @@
 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
@@ -92,8 +93,8 @@
         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 }
       }
 
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImReadCommand.kt b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImReadCommand.kt
index e0a95d5..1758fbd 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImReadCommand.kt
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImReadCommand.kt
@@ -67,13 +67,12 @@
     }
 
     fun checkUnitTestClusterGeneralStatus(status: Status): Boolean =
-      (status.getStatus() == CLUSTER_ID_TEST_GENERAL_ERROR_STATUS) &&
-        !status.getClusterStatus().isPresent()
+      (status.getStatus() == Status.Code.InvalidDataType) && !status.getClusterStatus().isPresent()
 
     fun checkUnitTestClusterClusterStatus(status: Status): Boolean =
-      (status.getStatus() == CLUSTER_ID_TEST_CLUSTER_ERROR_STATUS) &&
+      (status.getStatus() == Status.Code.Failure) &&
         status.getClusterStatus().isPresent() &&
-        status.getClusterStatus().get() == CLUSTER_ID_TEST_CLUSTER_ERROR_CLUSTER_STATUS
+        (status.getClusterStatus().get() == CLUSTER_ID_TEST_CLUSTER_ERROR_CLUSTER_STATUS)
 
     private fun validateResponse(nodeState: NodeState) {
       val endpointZero =
@@ -243,8 +242,6 @@
     private const val CLUSTER_ID_BASIC_VERSION = 0L
     private const val CLUSTER_ID_TEST_GENERAL_ERROR_BOOLEAN = 0x0031L
     private const val CLUSTER_ID_TEST_CLUSTER_ERROR_BOOLEAN = 0x0032L
-    private const val CLUSTER_ID_TEST_GENERAL_ERROR_STATUS = 0x8d
-    private const val CLUSTER_ID_TEST_CLUSTER_ERROR_STATUS = 1
     private const val CLUSTER_ID_TEST_CLUSTER_ERROR_CLUSTER_STATUS = 17
   }
 }
diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImWriteCommand.kt b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImWriteCommand.kt
index 3e90935..fdb74c5 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImWriteCommand.kt
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImWriteCommand.kt
@@ -22,6 +22,7 @@
 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
@@ -51,11 +52,8 @@
       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()
     }
   }
diff --git a/kotlin-detect-config.yaml b/kotlin-detect-config.yaml
index 6de03b2..2ad54a0 100644
--- a/kotlin-detect-config.yaml
+++ b/kotlin-detect-config.yaml
@@ -36,8 +36,8 @@
             - "**/src/controller/java/src/matter/tlv/types.kt"
             - "**/src/controller/java/src/matter/tlv/utils.kt"
             - "**/src/controller/java/src/matter/tlv/values.kt"
-            - "**/src/controller/java/src/chip/WildcardImport
-              examples/android/CHIPTest/app/src/androidTest/java/com/tcl/chip/chiptest/ExampleInstrumentedTest.kt"
+            - "**/src/controller/java/src/matter/tlv/values.kt"
+            - "**/src/controller/java/src/matter/controller/model/Status.kt"
             - "**/src/controller/java/tests/chip/devicecontroller/cluster/ChipClusterEventStructTest.kt"
             - "**/src/controller/java/tests/chip/devicecontroller/cluster/ChipClusterStructTest.kt"
             - "**/src/controller/java/tests/matter/jsontlv/JsonToTlvToJsonTest.kt"
diff --git a/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja b/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja
index ba0abf5..6c8ad74 100644
--- a/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja
+++ b/scripts/py_matter_idl/matter_idl/generators/java/ChipClusters_java.jinja
@@ -102,6 +102,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;
@@ -318,8 +319,15 @@
     }
 
     @Override
-    public void onResponse(ChipAttributePath attributePath) {
-      callback.onSuccess();
+    public void onResponse(ChipAttributePath attributePath, Status status) {
+      if (status.getStatus() == Status.Code.Success)
+      {
+        callback.onSuccess();
+      }
+      else
+      {
+        callback.onError(new StatusException(status.getStatus()));
+      }
     }
 
     @Override
diff --git a/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java b/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java
index 9b6287a..37c5c03 100644
--- a/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java
+++ b/scripts/py_matter_idl/matter_idl/tests/outputs/several_clusters/java/ChipClusters.java
@@ -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;
@@ -241,8 +242,15 @@
     }
 
     @Override
-    public void onResponse(ChipAttributePath attributePath) {
-      callback.onSuccess();
+    public void onResponse(ChipAttributePath attributePath, Status status) {
+      if (status.getStatus() == Status.Code.Success)
+      {
+        callback.onSuccess();
+      }
+      else
+      {
+        callback.onError(new StatusException(status.getStatus()));
+      }
     }
 
     @Override
diff --git a/src/controller/java/AndroidCallbacks.cpp b/src/controller/java/AndroidCallbacks.cpp
index eb6e8b1..eb1584b 100644
--- a/src/controller/java/AndroidCallbacks.cpp
+++ b/src/controller/java/AndroidCallbacks.cpp
@@ -669,23 +669,27 @@
     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());
 }
 
diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn
index b2ec93c..bf41b96 100644
--- a/src/controller/java/BUILD.gn
+++ b/src/controller/java/BUILD.gn
@@ -391,6 +391,7 @@
     "src/matter/controller/WriteAttributesCallbackJni.kt",
     "src/matter/controller/model/Paths.kt",
     "src/matter/controller/model/States.kt",
+    "src/matter/controller/model/Status.kt",
   ]
 
   sources += matter_structs_sources
@@ -477,6 +478,7 @@
     "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",
diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java
index 6e479c5..fcc9154 100644
--- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java
+++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java
@@ -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;
@@ -241,8 +242,15 @@
     }
 
     @Override
-    public void onResponse(ChipAttributePath attributePath) {
-      callback.onSuccess();
+    public void onResponse(ChipAttributePath attributePath, Status status) {
+      if (status.getStatus() == Status.Code.Success)
+      {
+        callback.onSuccess();
+      }
+      else
+      {
+        callback.onError(new StatusException(status.getStatus()));
+      }
     }
 
     @Override
diff --git a/src/controller/java/src/chip/devicecontroller/StatusException.java b/src/controller/java/src/chip/devicecontroller/StatusException.java
new file mode 100644
index 0000000..6a97e5b
--- /dev/null
+++ b/src/controller/java/src/chip/devicecontroller/StatusException.java
@@ -0,0 +1,34 @@
+/*
+ *   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;
+
+import chip.devicecontroller.model.Status;
+
+/** Exception class holding error codes defined by Interaction Model */
+public class StatusException extends Exception {
+  private static final long serialVersionUID = 1L;
+
+  public Status.Code code = Status.Code.Success;
+
+  public StatusException() {}
+
+  public StatusException(Status.Code code) {
+    super(String.format("CHIP IM status error: %s", code.name()));
+    this.code = code;
+  }
+}
diff --git a/src/controller/java/src/chip/devicecontroller/WriteAttributesCallback.java b/src/controller/java/src/chip/devicecontroller/WriteAttributesCallback.java
index 4e469ab..477f133 100644
--- a/src/controller/java/src/chip/devicecontroller/WriteAttributesCallback.java
+++ b/src/controller/java/src/chip/devicecontroller/WriteAttributesCallback.java
@@ -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. */
@@ -40,8 +41,9 @@
    * 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() {}
 }
diff --git a/src/controller/java/src/chip/devicecontroller/WriteAttributesCallbackJni.java b/src/controller/java/src/chip/devicecontroller/WriteAttributesCallbackJni.java
index fd7f806..7b95b30 100644
--- a/src/controller/java/src/chip/devicecontroller/WriteAttributesCallbackJni.java
+++ b/src/controller/java/src/chip/devicecontroller/WriteAttributesCallbackJni.java
@@ -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 {
@@ -45,9 +47,15 @@
         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() {
diff --git a/src/controller/java/src/chip/devicecontroller/model/Status.java b/src/controller/java/src/chip/devicecontroller/model/Status.java
index c367535..d859fae 100644
--- a/src/controller/java/src/chip/devicecontroller/model/Status.java
+++ b/src/controller/java/src/chip/devicecontroller/model/Status.java
@@ -21,17 +21,87 @@
 import java.util.Locale;
 import java.util.Optional;
 
+/** Class for Interaction Model Status * */
 public final class Status {
-  private Integer status;
+  public enum Code {
+    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),
+    WriteIgnored(0xf0);
+
+    private int id = 0;
+
+    Code(int id) {
+      this.id = id;
+    }
+
+    public int getId() {
+      return id;
+    }
+
+    public static Code fromId(int id) {
+      for (Code type : values()) {
+        if (type.getId() == id) {
+          return type;
+        }
+      }
+      return null;
+    }
+  }
+
+  private Code status = Code.Success;
   private Optional<Integer> clusterStatus;
 
   private Status(int status, Optional<Integer> clusterStatus) {
-    this.status = status;
+    this.status = Code.fromId(status);
     this.clusterStatus = clusterStatus;
   }
 
   // Getters
-  public Integer getStatus() {
+  public Code getStatus() {
     return status;
   }
 
@@ -43,7 +113,7 @@
     return String.format(
         Locale.ENGLISH,
         "status %s, clusterStatus %s",
-        String.valueOf(status),
+        status.name(),
         clusterStatus.isPresent() ? String.valueOf(clusterStatus.get()) : "None");
   }
 
@@ -51,7 +121,7 @@
     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));
   }
 }
diff --git a/src/controller/java/src/matter/controller/MatterControllerImpl.kt b/src/controller/java/src/matter/controller/MatterControllerImpl.kt
index 202d97a..6ae71f3 100644
--- a/src/controller/java/src/matter/controller/MatterControllerImpl.kt
+++ b/src/controller/java/src/matter/controller/MatterControllerImpl.kt
@@ -36,6 +36,7 @@
 import matter.controller.model.EventPath
 import matter.controller.model.EventState
 import matter.controller.model.NodeState
+import matter.controller.model.Status
 
 /** Controller to interact with the CHIP device. */
 class MatterControllerImpl(params: ControllerParams) : MatterController {
@@ -340,8 +341,11 @@
     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: ${attributePath} and status ${status}"
+            )
           }
 
           override fun onError(attributePath: AttributePath?, ex: Exception) {
diff --git a/src/controller/java/src/matter/controller/WriteAttributesCallback.kt b/src/controller/java/src/matter/controller/WriteAttributesCallback.kt
index b4a3f11..6b1b3f7 100644
--- a/src/controller/java/src/matter/controller/WriteAttributesCallback.kt
+++ b/src/controller/java/src/matter/controller/WriteAttributesCallback.kt
@@ -18,6 +18,7 @@
 package matter.controller
 
 import matter.controller.model.AttributePath
+import matter.controller.model.Status
 
 /** An interface for receiving write response. */
 interface WriteAttributesCallback {
@@ -38,8 +39,9 @@
    * 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() {}
 }
diff --git a/src/controller/java/src/matter/controller/WriteAttributesCallbackJni.kt b/src/controller/java/src/matter/controller/WriteAttributesCallbackJni.kt
index bd0bad3..fe52a32 100644
--- a/src/controller/java/src/matter/controller/WriteAttributesCallbackJni.kt
+++ b/src/controller/java/src/matter/controller/WriteAttributesCallbackJni.kt
@@ -18,6 +18,7 @@
 package matter.controller
 
 import matter.controller.model.AttributePath
+import matter.controller.model.Status
 
 /** JNI wrapper callback class for [WriteAttributesCallback]. */
 class WriteAttributesCallbackJni(
@@ -53,9 +54,16 @@
     )
   }
 
-  private fun onResponse(endpointId: Int, clusterId: Long, attributeId: Long) {
+  private fun onResponse(
+    endpointId: Int,
+    clusterId: Long,
+    attributeId: Long,
+    status: Int,
+    clusterStatus: Int?
+  ) {
     wrappedWriteAttributesCallback.onResponse(
-      AttributePath(endpointId.toUShort(), clusterId.toUInt(), attributeId.toUInt())
+      AttributePath(endpointId.toUShort(), clusterId.toUInt(), attributeId.toUInt()),
+      Status(status, clusterStatus)
     )
   }
 
diff --git a/src/controller/java/src/matter/controller/model/States.kt b/src/controller/java/src/matter/controller/model/States.kt
index c913b37..e7799f1 100644
--- a/src/controller/java/src/matter/controller/model/States.kt
+++ b/src/controller/java/src/matter/controller/model/States.kt
@@ -273,5 +273,3 @@
     return null
   }
 }
-
-data class Status(val status: Int, val clusterStatus: Int?)
diff --git a/src/controller/java/src/matter/controller/model/Status.kt b/src/controller/java/src/matter/controller/model/Status.kt
new file mode 100644
index 0000000..fa12f0b
--- /dev/null
+++ b/src/controller/java/src/matter/controller/model/Status.kt
@@ -0,0 +1,86 @@
+/*
+ *   Copyright (c) 2023 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 matter.controller.model
+
+/**
+ * Represents information about a node, including data on all available endpoints.
+ *
+ * @param endpoints A mapping of endpoint IDs with the associated cluster data.
+ */
+data class Status(val status: Int, val clusterStatus: Int?) {
+  enum class Code(val id: Int) {
+    SUCCESS(0X0),
+    FAILURE(0X01),
+    INVALID_SUSBSCRIPTION(0X7D),
+    UNSUPPORTED_ACCESS(0X7E),
+    UNSUPPORTED_ENDPOINT(0X7F),
+    INVALID_ACTION(0X80),
+    UNSUPPORTED_COMMAND(0X81),
+    DEPRECATED82(0X82),
+    DEPRECATED83(0X83),
+    DEPRECATED84(0X84),
+    INVALID_COMMAND(0X85),
+    UNSUPPORTED_ATTRIBUTE(0X86),
+    CONSTRAINT_ERROR(0X87),
+    UNSUPPORTED_WRITE(0X88),
+    RESOURCE_EXHAUSTED(0X89),
+    DEPRECATED8A(0X8A),
+    NOT_FOUND(0X8B),
+    UNREPORTABLE_ATTRIBUTE(0X8C),
+    INVALID_DATATYPE(0X8D),
+    DEPRECATED8E(0X8E),
+    UNSUPPORTED_READ(0X8F),
+    DEPRECATED90(0X90),
+    DEPRECATED91(0X91),
+    DATA_VERSION_MISMATCH(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),
+    UNSUPPORTED_CLUSTER(0XC3),
+    DEPRECATEDC4(0XC4),
+    NO_UPSTREAM_SUBSRICPTION(0XC5),
+    NEEDS_TIMED_INTERACTION(0XC6),
+    UNSUPPORTED_EVENT(0XC7),
+    PATH_EXHAUSTED(0XC8),
+    TIMED_REQUEST_MISMATCH(0XC9),
+    FAILSAFE_REQUIRED(0XCA),
+    INVALID_IN_STATE(0XCB),
+    NO_COMMAND_RESPONSE(0XCC),
+    WRITE_IGNORED(0XF0)
+  }
+
+  fun getCode(): Code? {
+    for (code in Code.values()) {
+      if (code.id == status) {
+        return code
+      }
+    }
+    return null
+  }
+
+  override fun toString(): String = "$status/$clusterStatus/"
+}
diff --git a/src/controller/python/chip/interaction_model/__init__.py b/src/controller/python/chip/interaction_model/__init__.py
index 61faa7f..ec10084 100644
--- a/src/controller/python/chip/interaction_model/__init__.py
+++ b/src/controller/python/chip/interaction_model/__init__.py
@@ -86,6 +86,7 @@
     FailsafeRequired = 0xca
     InvalidInState = 0xcb
     NoCommandResponse = 0xcc
+    WriteIgnored = 0xf0
 
 
 class InteractionModelError(ChipStackException):
diff --git a/src/protocols/interaction_model/StatusCodeList.h b/src/protocols/interaction_model/StatusCodeList.h
index 3b79e4a..5538478 100644
--- a/src/protocols/interaction_model/StatusCodeList.h
+++ b/src/protocols/interaction_model/StatusCodeList.h
@@ -22,7 +22,10 @@
  * include this file, then undefine the macro.
  */
 
-/// WARNING: If you touch this list, please also update src/controller/python/chip/interaction_model/__init__.py
+/// WARNING: If you touch this list,
+///          please update src/controller/python/chip/interaction_model/__init__.py
+///          please update src/controller/java/src/chip/devicecontroller/model/Status.java
+///          please update src/controller/java/src/matter/controller/model/Status.kt
 
 // clang-format off
 CHIP_IM_STATUS_CODE(Success               , SUCCESS                 , 0x0)