[Android] Implement Java TLV Decoder API (#27586)

* Implement Android TLV Decoder

* Restyled by google-java-format

* Restyled by clang-format

* fix merge conflict

* restyle

---------

Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: Andrei Litvin <andy314@gmail.com>
diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt
index 734ce12..b14f4a5 100644
--- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt
+++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt
@@ -8,6 +8,8 @@
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.lifecycleScope
 import chip.devicecontroller.ChipDeviceController
+import chip.devicecontroller.ChipStructs
+import chip.devicecontroller.ChipTLVValueDecoder
 import chip.devicecontroller.ClusterIDMapping.OperationalCredentials
 import chip.devicecontroller.InvokeCallback
 import chip.devicecontroller.ReportCallback
@@ -120,8 +122,37 @@
                 ?.getAttributeState(attributeId)
                 ?.value
                 ?: "null"
-            Log.i(TAG, "OpCred $attributeName value: $value")
-            showMessage("OpCred $attributeName value: $value")
+            val tlv =
+              nodeState
+                ?.getEndpointState(endpointId)
+                ?.getClusterState(clusterId)
+                ?.getAttributeState(attributeId)
+                ?.tlv
+
+            if (tlv == null) {
+              Log.i(TAG, "OpCred $attributeName value: $value")
+              showMessage("OpCred $attributeName value: $value")
+              return
+            }
+
+            val attributePath = ChipAttributePath.newInstance(endpointId, clusterId, attributeId)
+            when (attribute) {
+              OperationalCredentials.Attribute.Fabrics -> {
+                val ret =
+                  ChipTLVValueDecoder.decodeAttributeValue<
+                    List<ChipStructs.OperationalCredentialsClusterFabricDescriptorStruct>
+                  >(
+                    attributePath,
+                    tlv
+                  )
+                Log.i(TAG, "OpCred $attributeName value: $value")
+                showMessage(ret.toString())
+              }
+              else -> {
+                Log.i(TAG, "OpCred $attributeName value: $value")
+                showMessage("OpCred $attributeName value: $value")
+              }
+            }
           }
         },
         devicePtr,
diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn
index 22e3cc4..d6c7819 100644
--- a/src/controller/java/BUILD.gn
+++ b/src/controller/java/BUILD.gn
@@ -56,6 +56,7 @@
     "CHIPDefaultCallbacks.cpp",
     "CHIPDefaultCallbacks.h",
     "CHIPDeviceController-JNI.cpp",
+    "CHIPTLVValueDecoder-JNI.cpp",
     "DeviceAttestationDelegateBridge.cpp",
     "DeviceAttestationDelegateBridge.h",
     "zap-generated/CHIPAttributeTLVValueDecoder.cpp",
@@ -328,6 +329,7 @@
     "src/chip/devicecontroller/ChipDeviceController.java",
     "src/chip/devicecontroller/ChipDeviceControllerException.java",
     "src/chip/devicecontroller/ChipIdLookup.java",
+    "src/chip/devicecontroller/ChipTLVValueDecoder.java",
     "src/chip/devicecontroller/ControllerParams.java",
     "src/chip/devicecontroller/DeviceAttestationDelegate.java",
     "src/chip/devicecontroller/DiscoveredDevice.java",
diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp
index 1e6fedc..64c7dac 100644
--- a/src/controller/java/CHIPDeviceController-JNI.cpp
+++ b/src/controller/java/CHIPDeviceController-JNI.cpp
@@ -81,11 +81,11 @@
 static CHIP_ERROR GetChipPathIdValue(jobject chipPathId, uint32_t wildcardValue, uint32_t & outValue);
 static CHIP_ERROR ParseAttributePathList(jobject attributePathList,
                                          std::vector<app::AttributePathParams> & outAttributePathParamsList);
-static CHIP_ERROR ParseAttributePath(jobject attributePath, EndpointId & outEndpointId, ClusterId & outClusterId,
-                                     AttributeId & outAttributeId);
+CHIP_ERROR ParseAttributePath(jobject attributePath, EndpointId & outEndpointId, ClusterId & outClusterId,
+                              AttributeId & outAttributeId);
 static CHIP_ERROR ParseEventPathList(jobject eventPathList, std::vector<app::EventPathParams> & outEventPathParamsList);
-static CHIP_ERROR ParseEventPath(jobject eventPath, EndpointId & outEndpointId, ClusterId & outClusterId, EventId & outEventId,
-                                 bool & outIsUrgent);
+CHIP_ERROR ParseEventPath(jobject eventPath, EndpointId & outEndpointId, ClusterId & outClusterId, EventId & outEventId,
+                          bool & outIsUrgent);
 static CHIP_ERROR IsWildcardChipPathId(jobject chipPathId, bool & isWildcard);
 
 namespace {
diff --git a/src/controller/java/CHIPTLVValueDecoder-JNI.cpp b/src/controller/java/CHIPTLVValueDecoder-JNI.cpp
new file mode 100644
index 0000000..26604b2
--- /dev/null
+++ b/src/controller/java/CHIPTLVValueDecoder-JNI.cpp
@@ -0,0 +1,83 @@
+#include "lib/core/CHIPError.h"
+#include "lib/support/JniTypeWrappers.h"
+
+// #include <lib/support/CHIPMem.h>
+// #include <lib/support/CodeUtils.h>
+#include <lib/support/JniReferences.h>
+#include <lib/support/logging/CHIPLogging.h>
+
+#include "CHIPAttributeTLVValueDecoder.h"
+#include "CHIPEventTLVValueDecoder.h"
+
+#include <jni.h>
+
+using namespace chip;
+
+#define JNI_METHOD(RETURN, METHOD_NAME)                                                                                            \
+    extern "C" JNIEXPORT RETURN JNICALL Java_chip_devicecontroller_ChipTLVValueDecoder_##METHOD_NAME
+
+extern CHIP_ERROR ParseAttributePath(jobject attributePath, EndpointId & outEndpointId, ClusterId & outClusterId,
+                                     AttributeId & outAttributeId);
+extern CHIP_ERROR ParseEventPath(jobject eventPath, EndpointId & outEndpointId, ClusterId & outClusterId, EventId & outEventId,
+                                 bool & outIsUrgent);
+
+JNI_METHOD(jobject, decodeAttributeValue)(JNIEnv * env, jclass clazz, jobject attributePath, jbyteArray jTlv)
+{
+    EndpointId endpointId;
+    ClusterId clusterId;
+    AttributeId attributeId;
+    CHIP_ERROR err = ParseAttributePath(attributePath, endpointId, clusterId, attributeId);
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogProgress(Controller, "decode error attributePath");
+        return nullptr;
+    }
+
+    JniByteArray tlv(env, jTlv);
+
+    chip::app::ConcreteAttributePath path(endpointId, clusterId, attributeId);
+
+    chip::TLV::TLVReader reader;
+    reader.Init(tlv.byteSpan());
+    reader.Next();
+
+    jobject ret = DecodeAttributeValue(path, reader, &err);
+
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogProgress(Controller, "decode error attributeValue");
+        return nullptr;
+    }
+
+    return ret;
+}
+
+JNI_METHOD(jobject, decodeEventValue)(JNIEnv * env, jclass clazz, jobject eventPath, jbyteArray jTlv)
+{
+    EndpointId endpointId;
+    ClusterId clusterId;
+    EventId eventId;
+    bool isUrgent;
+    CHIP_ERROR err = ParseEventPath(eventPath, endpointId, clusterId, eventId, isUrgent);
+    if (err != CHIP_NO_ERROR)
+    {
+        return nullptr;
+    }
+
+    JniByteArray tlv(env, jTlv);
+
+    chip::app::ConcreteEventPath path(endpointId, clusterId, eventId);
+    chip::TLV::TLVReader reader;
+
+    reader.Init(tlv.byteSpan());
+    reader.Next();
+
+    jobject ret = DecodeEventValue(path, reader, &err);
+
+    if (err != CHIP_NO_ERROR)
+    {
+        return nullptr;
+    }
+
+    return ret;
+}
diff --git a/src/controller/java/src/chip/devicecontroller/ChipTLVValueDecoder.java b/src/controller/java/src/chip/devicecontroller/ChipTLVValueDecoder.java
new file mode 100644
index 0000000..86c375b
--- /dev/null
+++ b/src/controller/java/src/chip/devicecontroller/ChipTLVValueDecoder.java
@@ -0,0 +1,28 @@
+/*
+ *   Copyright (c) 2020-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 chip.devicecontroller;
+
+import chip.devicecontroller.model.ChipAttributePath;
+import chip.devicecontroller.model.ChipEventPath;
+
+public class ChipTLVValueDecoder {
+  public static native <T> T decodeAttributeValue(ChipAttributePath attributePath, byte[] tlv);
+
+  public static native <T> T decodeEventValue(ChipEventPath eventPath, byte[] tlv);
+}