Add JNI bridge for setup_payload (#1454)
Adding the JNI bridging C++ and Java code to setup_payload package for
use in Android apps.
diff --git a/configure.ac b/configure.ac
index ea193f5..9a82daa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2163,6 +2163,7 @@
src/system/Makefile
src/system/tests/Makefile
src/setup_payload/Makefile
+src/setup_payload/java/Makefile
src/setup_payload/tests/Makefile
src/inet/Makefile
src/inet/tests/Makefile
diff --git a/scripts/make/java.mk b/scripts/make/java.mk
new file mode 100644
index 0000000..091424c
--- /dev/null
+++ b/scripts/make/java.mk
@@ -0,0 +1,217 @@
+#
+# Copyright (c) 2014-2017 Nest Labs, Inc.
+# Copyright (c) 2018 Google LLC
+# Copyright (c) 2020 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.
+#
+
+#
+# Description:
+# This file contains make rules for compiling Java code and building jars.
+#
+
+#
+# Java Rules Usage
+# ================
+#
+# Projects wishing to build Java code should include this file at the *end*
+# of their Makefile.am files. Additionally, projects must declare a set of
+# automake local dependencies to cause Java code to be compile for standard
+# targets. E.g.:
+#
+# include $(abs_top_srcdir)/scripts/make/java.mk
+#
+# all-local: all-JARS
+# install-data-local: install-data-JARS
+# uninstall-local: uninstall-JARS
+# mostlyclean-local: mostlyclean-local-JARS
+#
+# Jars to be built must be declared in the JARS variable *before* java.mk is
+# included, e.g.:
+#
+# JARS = \
+# SetupPayloadParser.jar \
+# $(NULL)
+#
+# The building of individual jars is controlled by variables that begin
+# with the name of the jar file. E.g. SetupPayloadParser_jar_JFLAGS. These
+# variable are:
+#
+# <name>_JAVA_SRCS -- The list of java source files to be compile and
+# included in the jar. The file paths are relative to the "src"
+# subdirectory, which by default is located in the same directory as the
+# Makefile.am. E.g.:
+#
+# SetupPayloadParser_jar_JAVA_SRCS = \
+# chip/setuppayload/SetupPayloadParser.java \
+# chip/setuppayload/SetupPayload.java \
+# $(NULL)
+#
+# <name>_JFLAGS -- Flags to be passed to the Java compiler.
+#
+# <name>_JAVA_MAIN_CLASS -- Specifies the application entry point class
+# for the jar. Must be a fully qualified class name.
+#
+# <name>_JAVA_CLASSPATHS -- Additional class paths and/or jars to be passed
+# to the Java compiler. Multiple entries must be separated by colons.
+#
+# <name>_JAVA_EXTRA_SRC_DIRS -- Additional directories containing Java source
+# files that are used to satisfy references during compilation, but are
+# not included in the compile output. Multiple entries must be separated
+# by colons.
+#
+# <name>_JAVA_NATIVE_LIB -- The name of a native library to be included in a
+# platform-specific native subdirectory with the jar file. The name given
+# must be both a make target, on which the jar will depend, and the name
+# of a shared-library file located in the .libs subdirectory of the module's
+# build directory. This should typically be the name of a libtool .la file
+# which is built by other rules in the module's Makefile.am.
+#
+# <name>_JAVA_STRIP_NATIVE_LIB -- Set to "true" to cause the native library to
+# be stripped before being included in the jar file.
+#
+# <name>_JAVA_SRC_DIR -- The directory containing the Java source files.
+# Defaults to the global value $(JAVA_SRC_DIR), which in turn defaults to
+# the module's "src" directory, i.e. $(srcdir)/src.
+#
+# <name>_JAVA_BIN_DIR -- The directory into which the compile Java class files.
+# should be placed. Defaults to the global value $(JAVA_BIN_DIR), which in
+# turn defaults to the "bin" subdirectory in the module's build directory,
+# i.e. $(builddir)/bin.
+#
+# <name>_JAVA_INSTALL_DIR -- The directory into which the generated jar file is
+# installed. Defaults to the global value $(JAVA_INSTALL_DIR), which in turn
+# defaults to $(datadir)/java.
+#
+# <name>_MAVEN_PROJECT_FILE -- The name of a Maven project file (pom) to be
+# included in the jar file. The pom file will be scanned for groupId and
+# artifactId fields, which will be used to form the path of the pom file
+# within the jar file; i.e. META-INF/maven/<groupId>/<artifactId>/pom.xml.
+#
+
+AM_V_JAR = $(am__v_JAR_$(V))
+am__v_JAR_ = $(am__v_JAR_$(AM_DEFAULT_VERBOSITY))
+am__v_JAR_0 = @echo " JAR " $@;
+am__v_JAR_1 =
+
+AM_V_JAVAC = $(am__v_JAVAC_$(V))
+am__v_JAVAC_ = $(am__v_JAVAC_$(AM_DEFAULT_VERBOSITY))
+am__v_JAVAC_0 = @echo " JAVAC ";
+am__v_JAVAC_1 =
+
+JAVA_SRC_DIR ?= $(srcdir)/src
+
+JAVA_BIN_DIR ?= $(builddir)/bin
+
+JAVA_INSTALL_DIR ?= $(datadir)/java
+
+JAVA_NATIVE_LIB_HOST_OS = $(shell echo $(host_os) | sed -n -e 's/linux-gnu/linux/; s/darwin[0-9.]*/darwin/; p' )
+
+JAVA_NATIVE_LIB_HOST_CPU = $(host_cpu)
+
+JAVA_NATIVE_BIN_DIR ?= $(builddir)/bin/native/$(JAVA_NATIVE_LIB_HOST_OS)/$(JAVA_NATIVE_LIB_HOST_CPU)
+
+HOST_SHARED_LIB_EXT = $(shell $(LIBTOOL) --config | sed -n -e '/^shrext_cmds=/ { s/^shrext_cmds=/echo /; s/"//g; s/\\`/`/g; p; }' | sh )
+
+JAVA_STRIP_NATIVE_LIB = false
+
+ifeq ($(JAVA_NATIVE_LIB_HOST_OS),darwin)
+else
+endif
+
+define JarRules
+# Arguments:
+# $(1): jar variable prefix
+# $(2): jar file name
+
+$(1)_JAVA_SRC_DIR ?= $(JAVA_SRC_DIR)
+$(1)_JAVA_BIN_DIR ?= $(JAVA_BIN_DIR)
+$(1)_JAVA_INSTALL_DIR ?= $(JAVA_INSTALL_DIR)
+$(1)_JAVA_NATIVE_BIN_DIR ?= $(JAVA_NATIVE_BIN_DIR)
+
+ifeq ($(JAVA_NATIVE_LIB_HOST_OS),darwin)
+$(1)_JAVA_STRIP_NATIVE_LIB = false
+else
+$(1)_JAVA_STRIP_NATIVE_LIB ?= $(JAVA_STRIP_NATIVE_LIB)
+endif
+
+$(1)_JAVA_ABS_SRCS ?= $$(addprefix $$($(1)_JAVA_SRC_DIR)/,$$($(1)_JAVA_SRCS))
+
+ifdef $(1)_MAVEN_PROJECT_FILE
+$(1)_ABS_MAVEN_PROJECT_FILE := $$(addprefix $(srcdir)/,$$($(1)_MAVEN_PROJECT_FILE))
+$(1)_MAVEN_GROUP_ID ?= $$(shell sed -n -e '/<groupId>/ { s@.*<groupId>\(.*\)</groupId>.*@\1@; p; }' $$($(1)_ABS_MAVEN_PROJECT_FILE) )
+$(1)_MAVEN_ARTIFACT_ID ?= $$(shell sed -n -e '/<artifactId>/ { s@.*<artifactId>\(.*\)</artifactId>.*@\1@; p; }' $$($(1)_ABS_MAVEN_PROJECT_FILE) )
+endif
+
+# Compile Java source files
+$(2).classes.stamp: $$($(1)_JAVA_ABS_SRCS) | $$($(1)_JAVA_BIN_DIR)
+ $$(AM_V_JAVAC)$$(JAVAC) $$(JFLAGS) $$($(1)_JFLAGS) -d $$($(1)_JAVA_BIN_DIR) -cp :$$($(1)_JAVA_CLASSPATHS) -sourcepath $$($(1)_JAVA_SRC_DIR):$$($(1)_JAVA_EXTRA_SRC_DIRS) $$($(1)_JAVA_ABS_SRCS)
+ $$(AM_V_at)touch $$(@)
+
+# Create jar
+$(2): $(2).classes.stamp $$($(1)_JAVA_NATIVE_LIB) | $$(if $$($(1)_JAVA_NATIVE_LIB),$$($(1)_JAVA_NATIVE_BIN_DIR))
+ifdef $(1)_JAVA_NATIVE_LIB
+ cp .libs/$$(patsubst %.la,%$$(HOST_SHARED_LIB_EXT),$$($(1)_JAVA_NATIVE_LIB)) $$($(1)_JAVA_NATIVE_BIN_DIR)
+ if $$($(1)_JAVA_STRIP_NATIVE_LIB); then $(STRIP) $$($(1)_JAVA_NATIVE_BIN_DIR)/$$(patsubst %.la,%$$(HOST_SHARED_LIB_EXT),$$($(1)_JAVA_NATIVE_LIB)); fi
+endif
+ifdef $(1)_MAVEN_PROJECT_FILE
+ mkdir -p $$($(1)_JAVA_BIN_DIR)/META-INF/maven/$$($(1)_MAVEN_GROUP_ID)/$$($(1)_MAVEN_ARTIFACT_ID)
+ cp $$($(1)_ABS_MAVEN_PROJECT_FILE) $$($(1)_JAVA_BIN_DIR)/META-INF/maven/$$($(1)_MAVEN_GROUP_ID)/$$($(1)_MAVEN_ARTIFACT_ID)/pom.xml
+endif
+ $$(AM_V_JAR)$$(JAR) c$$(if $$($(1)_JAVA_MAIN_CLASS),e)f $$($(1)_JAVA_MAIN_CLASS) $$(@) -C $$($(1)_JAVA_BIN_DIR) .
+
+# Create bin directory
+$$($(1)_JAVA_BIN_DIR):
+ $$(create-directory)
+
+# Create native bin directory
+$$($(1)_JAVA_NATIVE_BIN_DIR):
+ $$(create-directory)
+
+# Create install directory
+$$(DESTDIR)$$($(1)_JAVA_INSTALL_DIR):
+ $$(create-directory)
+
+.PHONY: all-JARS install-data-JARS install-data-$(1) \
+ uinstall-data-JARS uninstall-data-$(1) \
+ mostlyclean-local-JARS mostlyclean-local-$(1)
+
+# Install jar
+install-data-$(1): $(2) | $$(DESTDIR)$$($(1)_JAVA_INSTALL_DIR)
+ @$$(NORMAL_INSTALL)
+ echo " INSTALL $(2)"; \
+ $$(INSTALL_DATA) "$(2)" "$$(DESTDIR)$$($(1)_JAVA_INSTALL_DIR)/$(2)"; \
+
+# Uninstall jar
+uninstall-data-$(1):
+ @$$(NORMAL_UNINSTALL)
+ rm -f "$$(DESTDIR)$$($(1)_JAVA_INSTALL_DIR)/$(2)"; \
+
+# Clean
+mostlyclean-local-$(1):
+ -$$(AM_V_at)rm -rf $$($(1)_JAVA_BIN_DIR) $(2) $(2).classes.stamp
+
+all-JARS: $(2)
+
+install-data-JARS: install-data-$(1)
+
+uninstall-JARS: uninstall-data-$(1)
+
+mostlyclean-local-JARS: mostlyclean-local-$(1)
+
+endef # JarRules
+
+# Instantiate jar build rules for each declared jar.
+$(foreach jar,$(JARS),$(eval $(call JarRules,$(basename $(jar))_jar,$(jar))))
diff --git a/src/Makefile.am b/src/Makefile.am
index 2db8065..d7657a2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -56,6 +56,19 @@
$(NULL)
endif
+SETUP_PAYLOAD_SUBDIRS = \
+ setup_payload/java \
+ $(NULL)
+
+MAYBE_SETUP_PAYLOAD_SUBDIRS = \
+ $(NULL)
+
+if CHIP_WITH_ANDROID
+MAYBE_SETUP_PAYLOAD_SUBDIRS += \
+ $(SETUP_PAYLOAD_SUBDIRS) \
+ $(NULL)
+endif # CHIP_WITH_ANDROID
+
# Always package (e.g. for 'make dist') these subdirectories.
DIST_SUBDIRS = \
@@ -67,6 +80,7 @@
inet \
lib \
setup_payload \
+ $(SETUP_PAYLOAD_SUBDIRS) \
crypto \
platform \
qrcodetool \
@@ -83,6 +97,7 @@
inet \
lib \
setup_payload \
+ $(MAYBE_SETUP_PAYLOAD_SUBDIRS) \
crypto \
transport \
$(MAYBE_BLE_SUBDIRS) \
diff --git a/src/inet/IPAddress.h b/src/inet/IPAddress.h
index 5bcc66f..4bd6623 100644
--- a/src/inet/IPAddress.h
+++ b/src/inet/IPAddress.h
@@ -48,7 +48,6 @@
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
-#include <ifaddrs.h>
#include <net/if.h>
#include <netinet/in.h>
#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
diff --git a/src/inet/InetInterface.cpp b/src/inet/InetInterface.cpp
index 9473040..ffddfd3 100644
--- a/src/inet/InetInterface.cpp
+++ b/src/inet/InetInterface.cpp
@@ -224,6 +224,143 @@
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS
+#if __ANDROID__ && __ANDROID_API__ < 24
+
+static struct if_nameindex * backport_if_nameindex(void);
+static void backport_if_freenameindex(struct if_nameindex *);
+
+static void backport_if_freenameindex(struct if_nameindex * inArray)
+{
+ if (inArray == NULL)
+ {
+ return;
+ }
+
+ for (size_t i = 0; inArray[i].if_index != 0; i++)
+ {
+ if (inArray[i].if_name != NULL)
+ {
+ free(inArray[i].if_name);
+ }
+ }
+
+ free(inArray);
+}
+
+static struct if_nameindex * backport_if_nameindex(void)
+{
+ int err;
+ unsigned index;
+ size_t intfIter = 0;
+ size_t maxIntfNum = 0;
+ size_t numIntf = 0;
+ size_t numAddrs = 0;
+ struct if_nameindex * retval = NULL;
+ struct if_nameindex * tmpval = NULL;
+ struct ifaddrs * addrList = NULL;
+ struct ifaddrs * addrIter = NULL;
+ const char * lastIntfName = "";
+
+ err = getifaddrs(&addrList);
+ VerifyOrExit(err >= 0, );
+
+ // coalesce on consecutive interface names
+ for (addrIter = addrList; addrIter != NULL; addrIter = addrIter->ifa_next)
+ {
+ numAddrs++;
+ if (strcmp(addrIter->ifa_name, lastIntfName) == 0)
+ {
+ continue;
+ }
+ numIntf++;
+ lastIntfName = addrIter->ifa_name;
+ }
+
+ tmpval = (struct if_nameindex *) malloc((numIntf + 1) * sizeof(struct if_nameindex));
+ VerifyOrExit(tmpval != NULL, );
+ memset(tmpval, 0, (numIntf + 1) * sizeof(struct if_nameindex));
+
+ lastIntfName = "";
+ for (addrIter = addrList; addrIter != NULL; addrIter = addrIter->ifa_next)
+ {
+ if (strcmp(addrIter->ifa_name, lastIntfName) == 0)
+ {
+ continue;
+ }
+
+ index = if_nametoindex(addrIter->ifa_name);
+ if (index != 0)
+ {
+ tmpval[intfIter].if_index = index;
+ tmpval[intfIter].if_name = strdup(addrIter->ifa_name);
+ intfIter++;
+ }
+ lastIntfName = addrIter->ifa_name;
+ }
+
+ // coalesce on interface index
+ maxIntfNum = 0;
+ for (size_t i = 0; tmpval[i].if_index != 0; i++)
+ {
+ if (maxIntfNum < tmpval[i].if_index)
+ {
+ maxIntfNum = tmpval[i].if_index;
+ }
+ }
+
+ retval = (struct if_nameindex *) malloc((maxIntfNum + 1) * sizeof(struct if_nameindex));
+ VerifyOrExit(retval != NULL, );
+ memset(retval, 0, (maxIntfNum + 1) * sizeof(struct if_nameindex));
+
+ for (size_t i = 0; tmpval[i].if_index != 0; i++)
+ {
+ struct if_nameindex * intf = &tmpval[i];
+ if (retval[intf->if_index - 1].if_index == 0)
+ {
+ retval[intf->if_index - 1] = *intf;
+ }
+ else
+ {
+ free(intf->if_name);
+ intf->if_index = 0;
+ intf->if_name = 0;
+ }
+ }
+
+ intfIter = 0;
+
+ // coalesce potential gaps between indeces
+ for (size_t i = 0; i < maxIntfNum; i++)
+ {
+ if (retval[i].if_index != 0)
+ {
+ retval[intfIter] = retval[i];
+ intfIter++;
+ }
+ }
+
+ for (size_t i = intfIter; i < maxIntfNum; i++)
+ {
+ retval[i].if_index = 0;
+ retval[i].if_name = NULL;
+ }
+
+exit:
+ if (tmpval != NULL)
+ {
+ free(tmpval);
+ }
+
+ if (addrList != NULL)
+ {
+ freeifaddrs(addrList);
+ }
+
+ return retval;
+}
+
+#endif // __ANDROID__ && __ANDROID_API__ < 24
+
InterfaceIterator::InterfaceIterator(void)
{
mIntfArray = NULL;
@@ -249,7 +386,11 @@
{
if (mIntfArray != NULL)
{
+#if __ANDROID__ && __ANDROID_API__ < 24
+ backport_if_freenameindex(mIntfArray);
+#else
if_freenameindex(mIntfArray);
+#endif
mIntfArray = NULL;
}
}
@@ -300,7 +441,11 @@
if (mIntfArray == NULL)
{
+#if __ANDROID__ && __ANDROID_API__ < 24
+ mIntfArray = backport_if_nameindex();
+#else
mIntfArray = if_nameindex();
+#endif
}
else if (mIntfArray[mCurIntf].if_index != 0)
{
diff --git a/src/qrcodetool/Makefile.am b/src/qrcodetool/Makefile.am
index dfb4468..95d3b3d 100644
--- a/src/qrcodetool/Makefile.am
+++ b/src/qrcodetool/Makefile.am
@@ -23,6 +23,12 @@
$(NLFAULTINJECTION_LDFLAGS) $(NLFAULTINJECTION_LIBS) \
$(NULL)
+if CHIP_WITH_ANDROID
+qrcodetool_LDADD += \
+ -llog \
+ $(NULL)
+endif #CHIP_WITH_ANDROID
+
NLFOREIGN_FILE_DEPENDENCIES = \
$(top_builddir)/src/setup_payload/libSetupPayload.a \
$(top_builddir)/src/lib/libCHIP.a \
diff --git a/src/setup_payload/java/Makefile.am b/src/setup_payload/java/Makefile.am
new file mode 100644
index 0000000..335aa23
--- /dev/null
+++ b/src/setup_payload/java/Makefile.am
@@ -0,0 +1,106 @@
+#
+# Copyright (c) 2014-2017 Nest Labs, Inc.
+# Copyright (c) 2018 Google LLC
+# Copyright (c) 2020 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.
+#
+
+#
+# Description:
+# This file is the GNU automake template for the CHIP Setup Payload Parser.
+#
+
+include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
+
+#if CHIP_WITH_JAVA
+
+EXTRA_DIST = \
+ $(srcdir)/src \
+ $(NULL)
+
+lib_LTLIBRARIES = libSetupPayloadParser.la
+
+libSetupPayloadParser_la_CPPFLAGS = \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib/core \
+ -I$(top_srcdir)/src/setup_payload \
+ -I$(top_srcdir)/src/system \
+ -I$(top_srcdir)/src/include \
+ $(NLASSERT_CPPFLAGS) \
+ $(NLFAULTINJECTION_CPPFLAGS) \
+ $(NLIO_CPPFLAGS) \
+ $(JNI_CPPFLAGS) \
+ $(LWIP_CPPFLAGS) \
+ $(SOCKETS_CPPFLAGS) \
+ $(NULL)
+
+libSetupPayloadParser_la_CXXFLAGS = \
+ $(NULL)
+
+libSetupPayloadParser_la_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ -avoid-version \
+ -module \
+ -export-dynamic \
+ $(NULL)
+
+libSetupPayloadParser_la_SOURCES = \
+ SetupPayloadParser-JNI.cpp \
+ $(NULL)
+
+libSetupPayloadParser_la_LIBADD = \
+ -L$(top_builddir)/src/setup_payload -lSetupPayload \
+ -L$(top_builddir)/src/lib -lCHIP \
+ $(LWIP_LDFLAGS) $(LWIP_LIBS) \
+ $(SOCKETS_LDFLAGS) $(SOCKETS_LIBS) \
+ $(NULL)
+
+if CHIP_WITH_ANDROID
+libSetupPayloadParser_la_LIBADD += \
+ -llog \
+ $(NULL)
+endif # CHIP_WITH_ANDROID
+
+libSetupPayloadParser_la_DEPENDENCIES = \
+ $(top_builddir)/src/setup_payload/libSetupPayload.a \
+ $(top_builddir)/src/lib/libCHIP.a \
+ $(NULL)
+
+JARS = \
+ SetupPayloadParser.jar \
+ $(NULL)
+
+SetupPayloadParser_jar_JAVA_SRCS = \
+ chip/setuppayload/SetupPayload.java \
+ chip/setuppayload/SetupPayloadParser.java \
+ $(NULL)
+
+SetupPayloadParser_jar_JFLAGS = -source 8 -target 8
+
+if CHIP_WITH_ANDROID
+SetupPayloadParser_jar_JAVA_CLASSPATHS = $(ANDROID_HOME)/platforms/android-21/android.jar
+endif # CHIP_WITH_ANDROID
+
+include $(abs_top_srcdir)/scripts/make/java.mk
+
+all-local: all-JARS
+install-data-local: install-data-JARS
+uninstall-local: uninstall-JARS
+mostlyclean-local: mostlyclean-local-JARS
+
+#endif # CHIP_WITH_JAVA
+
+include $(abs_top_nlbuild_autotools_dir)/automake/post.am
diff --git a/src/setup_payload/java/SetupPayloadParser-JNI.cpp b/src/setup_payload/java/SetupPayloadParser-JNI.cpp
new file mode 100644
index 0000000..d917cc1
--- /dev/null
+++ b/src/setup_payload/java/SetupPayloadParser-JNI.cpp
@@ -0,0 +1,62 @@
+#include "ManualSetupPayloadParser.h"
+#include "QRCodeSetupPayloadParser.h"
+
+#include <jni.h>
+
+using namespace chip;
+
+#define JNI_METHOD(RETURN, METHOD_NAME) extern "C" JNIEXPORT RETURN JNICALL Java_chip_setuppayload_SetupPayloadParser_##METHOD_NAME
+
+static jobject TransformSetupPayload(JNIEnv * env, SetupPayload payload);
+
+JNI_METHOD(jobject, fetchPayloadFromQrCode)(JNIEnv * env, jobject self, jstring qrCodeObj)
+{
+ CHIP_ERROR err;
+ const char * qrString = NULL;
+ QRCodeSetupPayloadParser * qrPayloadParser = NULL;
+ SetupPayload payload;
+
+ qrString = env->GetStringUTFChars(qrCodeObj, 0);
+ qrPayloadParser = new QRCodeSetupPayloadParser(qrString);
+
+ err = qrPayloadParser->populatePayload(payload);
+
+ return TransformSetupPayload(env, payload);
+}
+
+JNI_METHOD(jobject, fetchPayloadFromManualEntryCode)(JNIEnv * env, jobject self, jstring entryCode)
+{
+ CHIP_ERROR err;
+ const char * entryCodeString = NULL;
+ ManualSetupPayloadParser * manualSetupPayloadParser = NULL;
+ SetupPayload payload;
+
+ entryCodeString = env->GetStringUTFChars(entryCode, 0);
+ manualSetupPayloadParser = new ManualSetupPayloadParser(entryCodeString);
+
+ err = manualSetupPayloadParser->populatePayload(payload);
+
+ return TransformSetupPayload(env, payload);
+}
+
+jobject TransformSetupPayload(JNIEnv * env, SetupPayload payload)
+{
+ jclass setupPayloadClass = env->FindClass("chip/setuppayload/SetupPayload");
+ jobject setupPayload = env->AllocObject(setupPayloadClass);
+
+ jfieldID version = env->GetFieldID(setupPayloadClass, "version", "I");
+ jfieldID vendorId = env->GetFieldID(setupPayloadClass, "vendorId", "I");
+ jfieldID productId = env->GetFieldID(setupPayloadClass, "productId", "I");
+ jfieldID requiresCustomFlow = env->GetFieldID(setupPayloadClass, "requiresCustomFlow", "Z");
+ jfieldID discriminator = env->GetFieldID(setupPayloadClass, "discriminator", "I");
+ jfieldID setUpPinCode = env->GetFieldID(setupPayloadClass, "setupPinCode", "J");
+
+ env->SetIntField(setupPayload, version, payload.version);
+ env->SetIntField(setupPayload, vendorId, payload.vendorID);
+ env->SetIntField(setupPayload, productId, payload.productID);
+ env->SetBooleanField(setupPayload, requiresCustomFlow, payload.requiresCustomFlow);
+ env->SetIntField(setupPayload, discriminator, payload.discriminator);
+ env->SetLongField(setupPayload, setUpPinCode, payload.setUpPINCode);
+
+ return setupPayload;
+}
diff --git a/src/setup_payload/java/src/chip/setuppayload/SetupPayload.java b/src/setup_payload/java/src/chip/setuppayload/SetupPayload.java
new file mode 100644
index 0000000..43de644
--- /dev/null
+++ b/src/setup_payload/java/src/chip/setuppayload/SetupPayload.java
@@ -0,0 +1,38 @@
+package chip.setuppayload;
+
+/** Class to hold the data from the scanned QR code or manual entry code. */
+public class SetupPayload {
+ /** Version info of the SetupPayload */
+ public int version;
+ /** The CHIP device vendor ID */
+ public int vendorId;
+ /** The CHIP device product ID */
+ public int productId;
+ /** Boolean indicating if the CHIP device needs custom flow */
+ public boolean requiresCustomFlow;
+ /** The CHIP device supported rendezvous flags */
+ public int rendezvousInformation;
+ /** The CHIP device discriminator */
+ public int discriminator;
+ /** The CHIP device manual setup code */
+ public long setupPinCode;
+
+ public SetupPayload() {}
+
+ public SetupPayload(
+ int version,
+ int vendorId,
+ int productId,
+ boolean requiresCustomFlow,
+ int rendezvousInfo,
+ int discriminator,
+ long setupPinCode) {
+ this.version = version;
+ this.vendorId = vendorId;
+ this.productId = productId;
+ this.requiresCustomFlow = requiresCustomFlow;
+ this.rendezvousInformation = rendezvousInfo;
+ this.discriminator = discriminator;
+ this.setupPinCode = setupPinCode;
+ }
+}
diff --git a/src/setup_payload/java/src/chip/setuppayload/SetupPayloadParser.java b/src/setup_payload/java/src/chip/setuppayload/SetupPayloadParser.java
new file mode 100644
index 0000000..cffdbef
--- /dev/null
+++ b/src/setup_payload/java/src/chip/setuppayload/SetupPayloadParser.java
@@ -0,0 +1,23 @@
+package chip.setuppayload;
+
+/** Parser for scanned QR code or manual entry code. */
+public class SetupPayloadParser {
+
+ /** Returns {@link SetupPayload} parsed from the QR code string. */
+ public SetupPayload parseQrCode(String qrCodeString) {
+ return fetchPayloadFromQrCode(qrCodeString);
+ }
+
+ /** Returns {@link SetupPayload} parsed from the manual entry code string. */
+ public SetupPayload parseManualEntryCode(String entryCodeString) {
+ return fetchPayloadFromManualEntryCode(entryCodeString);
+ }
+
+ private native SetupPayload fetchPayloadFromQrCode(String qrCodeString);
+
+ private native SetupPayload fetchPayloadFromManualEntryCode(String entryCodeString);
+
+ static {
+ System.loadLibrary("SetupPayloadParser");
+ }
+}