[Android]add json support for invoke and write using latest json/tlv conversion (#28759)

diff --git a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImInvokeCommand.kt b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImInvokeCommand.kt
index 79592ae..73eab9e 100644
--- a/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImInvokeCommand.kt
+++ b/examples/java-matter-controller/java/src/com/matter/controller/commands/pairing/PairOnNetworkLongImInvokeCommand.kt
@@ -50,16 +50,28 @@
   private inner class InternalInvokeCallback : InvokeCallback {
     override fun onError(e: Exception) {
       logger.log(Level.INFO, "Invoke receive onError" + e.message)
-      setFailure("write failure")
+      setFailure("invoke failure")
     }
 
     override fun onResponse(element: InvokeElement?, successCode: Long) {
       logger.log(Level.INFO, "Invoke receive OnResponse on ")
       if (element != null) {
-        logger.log(Level.INFO, element.toString())
+        logger.log(Level.INFO, element.toString() + element.getJsonString())
+        val clusterId = element.getClusterId().getId()
+        if (clusterId == CLUSTER_ID_IDENTIFY) {
+          logger.log(Level.INFO, "success code is $successCode")
+          setSuccess()
+          return
+        } else if (
+          clusterId == CLUSTER_ID_TEST && element.getJsonString().equals("""{"0:UINT":2}""")
+        ) {
+          logger.log(Level.INFO, "success code is $successCode")
+          setSuccess()
+          return
+        }
       }
-      logger.log(Level.INFO, "success code is$successCode")
-      setSuccess()
+
+      setFailure("invoke failure")
     }
   }
 
@@ -76,20 +88,44 @@
 
   override fun runCommand() {
     val number: UShort = 1u
-    val tlvWriter = TlvWriter()
-    tlvWriter.startStructure(AnonymousTag)
-    tlvWriter.put(ContextSpecificTag(0), number)
-    tlvWriter.endStructure()
+    val tlvWriter1 = TlvWriter()
+    tlvWriter1.startStructure(AnonymousTag)
+    tlvWriter1.put(ContextSpecificTag(0), number)
+    tlvWriter1.endStructure()
 
-    val element: InvokeElement =
+    val element1: InvokeElement =
       InvokeElement.newInstance(
         /* endpointId= */ 0,
         CLUSTER_ID_IDENTIFY,
         IDENTIFY_COMMAND,
-        tlvWriter.getEncoded(),
+        tlvWriter1.getEncoded(),
         null
       )
 
+    val tlvWriter2 = TlvWriter()
+    tlvWriter2.startStructure(AnonymousTag)
+    tlvWriter2.put(ContextSpecificTag(0), number)
+    tlvWriter2.put(ContextSpecificTag(1), number)
+    tlvWriter2.endStructure()
+
+    val element2: InvokeElement =
+      InvokeElement.newInstance(
+        /* endpointId= */ 1,
+        CLUSTER_ID_TEST,
+        TEST_ADD_ARGUMENT_COMMAND,
+        tlvWriter2.getEncoded(),
+        null
+      )
+
+    val element3: InvokeElement =
+      InvokeElement.newInstance(
+        /* endpointId= */ 1,
+        CLUSTER_ID_IDENTIFY,
+        IDENTIFY_COMMAND,
+        null,
+        """{"0:UINT":1}"""
+      )
+
     currentCommissioner()
       .pairDeviceWithAddress(
         getNodeId(),
@@ -104,7 +140,13 @@
     currentCommissioner()
       .getConnectedDevicePointer(getNodeId(), InternalGetConnectedDeviceCallback())
     clear()
-    currentCommissioner().invoke(InternalInvokeCallback(), devicePointer, element, 0, 0)
+    currentCommissioner().invoke(InternalInvokeCallback(), devicePointer, element1, 0, 0)
+    waitCompleteMs(getTimeoutMillis())
+    clear()
+    currentCommissioner().invoke(InternalInvokeCallback(), devicePointer, element2, 0, 0)
+    waitCompleteMs(getTimeoutMillis())
+    clear()
+    currentCommissioner().invoke(InternalInvokeCallback(), devicePointer, element3, 0, 0)
     waitCompleteMs(getTimeoutMillis())
   }
 
@@ -114,5 +156,7 @@
     private const val MATTER_PORT = 5540
     private const val CLUSTER_ID_IDENTIFY = 0x0003L
     private const val IDENTIFY_COMMAND = 0L
+    private const val CLUSTER_ID_TEST = 0xFFF1FC05L
+    private const val TEST_ADD_ARGUMENT_COMMAND = 0X04L
   }
 }
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 1492950..10945a4 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
@@ -52,7 +52,7 @@
     }
 
     override fun onResponse(attributePath: ChipAttributePath?) {
-      logger.log(Level.INFO, "Write receve OnResponse on ")
+      logger.log(Level.INFO, "Write receive OnResponse on ")
       if (attributePath != null) {
         logger.log(Level.INFO, attributePath.toString())
       }
@@ -72,15 +72,25 @@
   }
 
   override fun runCommand() {
-    val tlvWriter = TlvWriter()
-    tlvWriter.put(AnonymousTag, true)
-    val attributeList =
+    val tlvWriter1 = TlvWriter()
+    tlvWriter1.put(AnonymousTag, true)
+    val attributeList1 =
       listOf(
         AttributeWriteRequest.newInstance(
           /* endpointId= */ 0,
           CLUSTER_ID_BASIC,
           ATTR_ID_LOCAL_CONFIG_DISABLED,
-          tlvWriter.getEncoded(),
+          tlvWriter1.getEncoded()
+        )
+      )
+
+    val attributeList2 =
+      listOf(
+        AttributeWriteRequest.newInstance(
+          /* endpointId= */ 0,
+          CLUSTER_ID_BASIC,
+          ATTR_ID_LOCAL_CONFIG_DISABLED,
+          """{"40:BOOL":false}"""
         )
       )
 
@@ -99,7 +109,11 @@
       .getConnectedDevicePointer(getNodeId(), InternalGetConnectedDeviceCallback())
     clear()
     currentCommissioner()
-      .write(InternalWriteAttributesCallback(), devicePointer, attributeList, 0, 0)
+      .write(InternalWriteAttributesCallback(), devicePointer, attributeList1, 0, 0)
+    waitCompleteMs(getTimeoutMillis())
+    clear()
+    currentCommissioner()
+      .write(InternalWriteAttributesCallback(), devicePointer, attributeList2, 0, 0)
     waitCompleteMs(getTimeoutMillis())
   }
 
diff --git a/src/controller/java/AndroidCallbacks.cpp b/src/controller/java/AndroidCallbacks.cpp
index f6d9499..daa7f9e 100644
--- a/src/controller/java/AndroidCallbacks.cpp
+++ b/src/controller/java/AndroidCallbacks.cpp
@@ -1,6 +1,6 @@
 /*
  *
- *    Copyright (c) 2020-2021 Project CHIP Authors
+ *    Copyright (c) 2020-2023 Project CHIP Authors
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
@@ -28,7 +28,9 @@
 #include <lib/support/ErrorStr.h>
 #include <lib/support/JniReferences.h>
 #include <lib/support/JniTypeWrappers.h>
+#include <lib/support/jsontlv/JsonToTlv.h>
 #include <lib/support/jsontlv/TlvJson.h>
+#include <lib/support/jsontlv/TlvToJson.h>
 #include <lib/support/logging/CHIPLogging.h>
 #include <platform/PlatformManager.h>
 #include <type_traits>
@@ -488,15 +490,12 @@
         TLV::TLVReader readerForJavaTLV;
         TLV::TLVReader readerForJson;
         readerForJavaTLV.Init(*apData);
-        readerForJson.Init(*apData);
 
         // Create TLV byte array to pass to Java layer
         size_t bufferLen                  = readerForJavaTLV.GetRemainingLength() + readerForJavaTLV.GetLengthRead();
         std::unique_ptr<uint8_t[]> buffer = std::unique_ptr<uint8_t[]>(new uint8_t[bufferLen]);
         uint32_t size                     = 0;
-        // The TLVReader's read head is not pointing to the first element in the container, instead of the container itself, use
-        // a TLVWriter to get a TLV with a normalized TLV buffer (Wrapped with an anonymous tag, no extra "end of container" tag
-        // at the end.)
+
         TLV::TLVWriter writer;
         writer.Init(buffer.get(), bufferLen);
         err = writer.CopyElement(TLV::AnonymousTag(), readerForJavaTLV);
@@ -505,11 +504,13 @@
         chip::ByteArray jniByteArray(env, reinterpret_cast<jbyte *>(buffer.get()), size);
 
         // Convert TLV to JSON
-        Json::Value json;
+        std::string json;
+        readerForJson.Init(buffer.get(), size);
+        err = readerForJson.Next();
+        ReturnErrorOnFailure(err);
         err = TlvToJson(readerForJson, json);
         ReturnErrorOnFailure(err);
-
-        UtfString jsonString(env, JsonToString(json).c_str());
+        UtfString jsonString(env, json.c_str());
         outObj = env->CallStaticObjectMethod(invokeElementCls, invokeElementCtor, static_cast<jint>(aPath.mEndpointId),
                                              static_cast<jlong>(aPath.mClusterId), static_cast<jlong>(aPath.mCommandId),
                                              jniByteArray.jniValue(), jsonString.jniValue());
@@ -614,6 +615,7 @@
     CHIP_ERROR err = CHIP_NO_ERROR;
     JNIEnv * env   = JniReferences::GetInstance().GetEnvForCurrentThread();
 
+    ChipLogError(Controller, "ReportCallback::ReportError is called with %u", errorCode);
     jthrowable exception;
     err = AndroidControllerExceptions::GetInstance().CreateAndroidControllerException(env, message, errorCode, exception);
     VerifyOrReturn(
@@ -722,7 +724,7 @@
     CHIP_ERROR err = CHIP_NO_ERROR;
     JNIEnv * env   = JniReferences::GetInstance().GetEnvForCurrentThread();
 
-    ChipLogError(Controller, "WriteAttributesCallback ReportError is called");
+    ChipLogError(Controller, "WriteAttributesCallback::ReportError is called with %u", errorCode);
     jthrowable exception;
     err = AndroidControllerExceptions::GetInstance().CreateAndroidControllerException(env, message, errorCode, exception);
     VerifyOrReturn(err == CHIP_NO_ERROR,
@@ -825,7 +827,7 @@
     CHIP_ERROR err = CHIP_NO_ERROR;
     JNIEnv * env   = JniReferences::GetInstance().GetEnvForCurrentThread();
 
-    ChipLogError(Controller, "InvokeCallback ReportError is called");
+    ChipLogError(Controller, "InvokeCallback::ReportError is called with %u", errorCode);
     jthrowable exception;
     err = AndroidControllerExceptions::GetInstance().CreateAndroidControllerException(env, message, errorCode, exception);
     VerifyOrReturn(
diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp
index 5d93b30..be7bfa6 100644
--- a/src/controller/java/CHIPDeviceController-JNI.cpp
+++ b/src/controller/java/CHIPDeviceController-JNI.cpp
@@ -46,6 +46,8 @@
 #include <lib/support/ErrorStr.h>
 #include <lib/support/SafeInt.h>
 #include <lib/support/ThreadOperationalDataset.h>
+#include <lib/support/jsontlv/JsonToTlv.h>
+#include <lib/support/jsontlv/TlvToJson.h>
 #include <lib/support/logging/CHIPLogging.h>
 #include <platform/KeyValueStoreManager.h>
 #include <protocols/Protocols.h>
@@ -1864,6 +1866,8 @@
     auto callback                           = reinterpret_cast<WriteAttributesCallback *>(callbackHandle);
     app::WriteClient * writeClient          = nullptr;
     uint16_t convertedTimedRequestTimeoutMs = static_cast<uint16_t>(timedRequestTimeoutMs);
+    bool hasValidTlv                        = false;
+    bool hasValidJson                       = false;
 
     ChipLogDetail(Controller, "IM write() called");
 
@@ -1889,15 +1893,15 @@
         jmethodID hasDataVersionMethod    = nullptr;
         jmethodID getDataVersionMethod    = nullptr;
         jmethodID getTlvByteArrayMethod   = nullptr;
+        jmethodID getJsonStringMethod     = nullptr;
         jobject endpointIdObj             = nullptr;
         jobject clusterIdObj              = nullptr;
         jobject attributeIdObj            = nullptr;
         jbyteArray tlvBytesObj            = nullptr;
         bool hasDataVersion               = false;
         Optional<DataVersion> dataVersion = Optional<DataVersion>();
-        ;
-        jbyte * tlvBytesObjBytes = nullptr;
-        jsize length             = 0;
+        uint8_t * tlvBytes                = nullptr;
+        size_t length                     = 0;
         TLV::TLVReader reader;
 
         SuccessOrExit(err = JniReferences::GetInstance().GetListItem(attributeList, i, attributeItem));
@@ -1942,14 +1946,47 @@
 
         tlvBytesObj = static_cast<jbyteArray>(env->CallObjectMethod(attributeItem, getTlvByteArrayMethod));
         VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
-        VerifyOrExit(tlvBytesObj != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
+        if (tlvBytesObj != nullptr)
+        {
+            jbyte * tlvBytesObjBytes = env->GetByteArrayElements(tlvBytesObj, nullptr);
+            VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
+            length = static_cast<size_t>(env->GetArrayLength(tlvBytesObj));
+            VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
+            tlvBytes    = reinterpret_cast<uint8_t *>(tlvBytesObjBytes);
+            hasValidTlv = true;
+        }
+        else
+        {
+            SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, attributeItem, "getJsonString", "()Ljava/lang/String;",
+                                                                        &getJsonStringMethod));
+            jstring jsonJniString = static_cast<jstring>(env->CallObjectMethod(attributeItem, getJsonStringMethod));
+            VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
+            if (jsonJniString != nullptr)
+            {
+                JniUtfString jsonUtfJniString(env, jsonJniString);
+                uint8_t bufWithStruct[chip::app::kMaxSecureSduLengthBytes] = { 0 };
+                uint8_t buf[chip::app::kMaxSecureSduLengthBytes]           = { 0 };
+                TLV::TLVReader tlvReader;
+                TLV::TLVWriter tlvWrite;
+                TLV::TLVType outerContainer = TLV::kTLVType_Structure;
+                MutableByteSpan dataWithStruct{ bufWithStruct };
+                MutableByteSpan data{ buf };
+                SuccessOrExit(err = JsonToTlv(std::string(jsonUtfJniString.c_str(), jsonUtfJniString.size()), dataWithStruct));
+                tlvReader.Init(dataWithStruct);
+                SuccessOrExit(err = tlvReader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag()));
+                SuccessOrExit(err = tlvReader.EnterContainer(outerContainer));
+                SuccessOrExit(err = tlvReader.Next());
+                tlvWrite.Init(data);
+                SuccessOrExit(err = tlvWrite.CopyElement(TLV::AnonymousTag(), tlvReader));
+                SuccessOrExit(err = tlvWrite.Finalize());
+                tlvBytes     = buf;
+                length       = tlvWrite.GetLengthWritten();
+                hasValidJson = true;
+            }
+        }
+        VerifyOrExit(hasValidTlv || hasValidJson, err = CHIP_ERROR_INVALID_ARGUMENT);
 
-        tlvBytesObjBytes = env->GetByteArrayElements(tlvBytesObj, nullptr);
-        VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
-        length = env->GetArrayLength(tlvBytesObj);
-        VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
-
-        reader.Init(reinterpret_cast<const uint8_t *>(tlvBytesObjBytes), static_cast<size_t>(length));
+        reader.Init(tlvBytes, length);
         reader.Next();
         SuccessOrExit(
             err = writeClient->PutPreencodedAttribute(
@@ -1964,7 +2001,6 @@
     callback->mWriteClient = writeClient;
 
 exit:
-
     if (err != CHIP_NO_ERROR)
     {
         ChipLogError(Controller, "JNI IM Write Error: %s", err.AsString());
@@ -2000,14 +2036,17 @@
     jmethodID getClusterIdMethod       = nullptr;
     jmethodID getCommandIdMethod       = nullptr;
     jmethodID getTlvByteArrayMethod    = nullptr;
+    jmethodID getJsonStringMethod      = nullptr;
     jobject endpointIdObj              = nullptr;
     jobject clusterIdObj               = nullptr;
     jobject commandIdObj               = nullptr;
     jbyteArray tlvBytesObj             = nullptr;
-    jbyte * tlvBytesObjBytes           = nullptr;
-    jsize length                       = 0;
     TLV::TLVReader reader;
     TLV::TLVWriter * writer                 = nullptr;
+    uint8_t * tlvBytes                      = nullptr;
+    size_t length                           = 0;
+    bool hasValidTlv                        = false;
+    bool hasValidJson                       = false;
     uint16_t convertedTimedRequestTimeoutMs = static_cast<uint16_t>(timedRequestTimeoutMs);
 
     ChipLogDetail(Controller, "IM invoke() called");
@@ -2045,12 +2084,34 @@
 
     tlvBytesObj = static_cast<jbyteArray>(env->CallObjectMethod(invokeElement, getTlvByteArrayMethod));
     VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
-    VerifyOrExit(tlvBytesObj != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT);
+    if (tlvBytesObj != nullptr)
+    {
+        jbyte * tlvBytesObjBytes = env->GetByteArrayElements(tlvBytesObj, nullptr);
+        VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
+        length = static_cast<size_t>(env->GetArrayLength(tlvBytesObj));
+        VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
+        tlvBytes    = reinterpret_cast<uint8_t *>(tlvBytesObjBytes);
+        hasValidTlv = true;
+    }
+    else
+    {
+        SuccessOrExit(err = JniReferences::GetInstance().FindMethod(env, invokeElement, "getJsonString", "()Ljava/lang/String;",
+                                                                    &getJsonStringMethod));
+        jstring jsonJniString = static_cast<jstring>(env->CallObjectMethod(invokeElement, getJsonStringMethod));
+        VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
+        if (jsonJniString != nullptr)
+        {
+            JniUtfString jsonUtfJniString(env, jsonJniString);
+            uint8_t buf[chip::app::kMaxSecureSduLengthBytes] = { 0 };
+            MutableByteSpan tlvEncodingLocal{ buf };
+            SuccessOrExit(err = JsonToTlv(std::string(jsonUtfJniString.c_str(), jsonUtfJniString.size()), tlvEncodingLocal));
+            tlvBytes     = tlvEncodingLocal.data();
+            length       = tlvEncodingLocal.size();
+            hasValidJson = true;
+        }
+    }
+    VerifyOrExit(hasValidTlv || hasValidJson, err = CHIP_ERROR_INVALID_ARGUMENT);
 
-    tlvBytesObjBytes = env->GetByteArrayElements(tlvBytesObj, nullptr);
-    VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
-    length = env->GetArrayLength(tlvBytesObj);
-    VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
     SuccessOrExit(err = commandSender->PrepareCommand(app::CommandPathParams(static_cast<EndpointId>(endpointId), /* group id */ 0,
                                                                              static_cast<ClusterId>(clusterId),
                                                                              static_cast<CommandId>(commandId),
@@ -2059,7 +2120,7 @@
 
     writer = commandSender->GetCommandDataIBTLVWriter();
     VerifyOrExit(writer != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
-    reader.Init(reinterpret_cast<const uint8_t *>(tlvBytesObjBytes), static_cast<size_t>(length));
+    reader.Init(tlvBytes, static_cast<size_t>(length));
     reader.Next();
     SuccessOrExit(err = writer->CopyContainer(TLV::ContextTag(app::CommandDataIB::Tag::kFields), reader));
     SuccessOrExit(err = commandSender->FinishCommand(convertedTimedRequestTimeoutMs != 0