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");
+  }
+}