Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the initial skeleton of Matter Controller Java CLI App #23048

Merged
merged 3 commits into from
Oct 13, 2022
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions build/chip/java/rules.gni
Original file line number Diff line number Diff line change
@@ -176,6 +176,161 @@ template("java_library") {
}
}

# Declare a java binary target
#
# sources: List of .java files included in this binary. Mutually exclusive with jar_path.
#
# jar_path: A path to an existing JAR. Mutually exclusive with sources.
#
# output_name: File name for the output .jar (not including extension).
# Defaults to the input .jar file name.
#
# javac_flags: additional flags to pass to the javac compiler
#
template("java_binary") {
# Figure out the output name
_jar_name = target_name
if (defined(invoker.output_name)) {
_jar_name = invoker.output_name
} else {
_jar_name += ".jar"
}

_deps = []
if (defined(invoker.deps)) {
_deps = invoker.deps
}

# What files will be compiled
_java_files = []
if (defined(invoker.sources)) {
_java_files = invoker.sources
}

_is_prebuilt = defined(invoker.jar_path)

_jar_output = ""
_target_dir_name = get_label_info(":$target_name", "dir")
if (_is_prebuilt) {
assert(_java_files == [])
_jar_output = "$root_out_dir/bin/$_target_dir_name/" +
get_path_info(invoker.jar_path, "name") + ".jar"
} else {
_jar_output = "$root_out_dir/bin/$_target_dir_name/$_jar_name"
}

# Generate a list containing the expected build_config filepath of every dependency.
_deps_configs = []
foreach(_dep, _deps) {
_dep_gen_dir = get_label_info(_dep, "target_gen_dir")
_dep_name = get_label_info(_dep, "name")
_dep_config = "$_dep_gen_dir/$_dep_name.json"
_deps_configs += [ _dep_config ]
}
_rebased_deps_configs = rebase_path(_deps_configs, root_build_dir)

# Create the name for this target's build_config.
_library_target_name = target_name
_build_config = "$target_gen_dir/$_library_target_name.json"
_rebased_build_config = rebase_path(_build_config, root_build_dir)

# Write the build_config file for this target.
_config_target_name = target_name + "_config"
action(_config_target_name) {
script = write_build_config

deps = _deps

outputs = [ _build_config ]
args = [
"--jar-path",
rebase_path(_jar_output, root_build_dir),
"--build-config",
_rebased_build_config,
"--deps-configs=$_rebased_deps_configs",
]
}

# Building from sources - perform Java compilation and JAR creation.
if (!_is_prebuilt) {
# Additional flags
_javac_flags = [
"-Werror",
"-Xlint:all",
]
if (defined(invoker.javac_flags)) {
_javac_flags += invoker.javac_flags
}

# Data deps
_data_deps = []
if (defined(invoker.data_deps)) {
_data_deps = invoker.data_deps
}

# Generates a .java file containing all sources to be compiled
_java_sources_file = "$target_gen_dir/$target_name.sources"
if (defined(invoker.java_sources_file)) {
_java_sources_file = invoker.java_sources_file
}
write_file(_java_sources_file, rebase_path(_java_files, root_build_dir))

# Compiles the given files into a directory and generates a 'class list'
_javac_target_name = target_name + "__javac"
_class_dir = rebase_path(target_out_dir, root_build_dir) + "/classes"
_class_list_file = "$target_gen_dir/$target_name.classlist"
action(_javac_target_name) {
sources = _java_files
deps = [ ":$_config_target_name" ]

outputs = [ _class_list_file ]

script = javac_runner

args = [
"--classdir",
_class_dir,
"--outfile",
rebase_path(_class_list_file, root_build_dir),
"--build-config",
_rebased_build_config,
"--",
"-d",
_class_dir,
"@" + rebase_path(_java_sources_file, root_build_dir),
] + _javac_flags
}

# Bundles all files within the 'class directory' into a jar file
action(target_name) {
deps = [ ":$_javac_target_name" ] + _deps

data_deps = _data_deps

outputs = [ _jar_output ]

script = jar_runner

args = [
"cfm",
rebase_path(_jar_output, root_build_dir),
"Manifest.txt",
"-C",
_class_dir,
".",
]
}
} else {
# Using pre-specified JAR instead of building from sources - simply copy the JAR to the output directory.
_original_jar_path = invoker.jar_path
copy(target_name) {
sources = [ _original_jar_path ]
outputs = [ _jar_output ]
deps = [ ":$_config_target_name" ] + _deps
}
}
}

template("android_library") {
java_library(target_name) {
forward_variables_from(invoker, "*")
@@ -194,6 +349,24 @@ template("android_library") {
}
}

template("android_binary") {
java_binary(target_name) {
forward_variables_from(invoker, "*")

if (!defined(javac_flags)) {
javac_flags = []
}

javac_flags += [
"-Xlint:-options",
"-source",
"8",
"-target",
"8",
]
}
}

template("java_prebuilt") {
java_library(target_name) {
forward_variables_from(invoker, "*")
20 changes: 20 additions & 0 deletions examples/java-matter-controller/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

# Shared libs & JAR libs (those libs are copied into source tree for easy Android build).
*.so
*.jar
*.map
25 changes: 25 additions & 0 deletions examples/java-matter-controller/.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright (c) 2020-2022 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.
# 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.

import("//build_overrides/build.gni")

# The location of the build configuration file.
buildconfig = "${build_root}/config/BUILDCONFIG.gn"

# CHIP uses angle bracket includes.
check_system_includes = true

default_args = {
import("//args.gni")
}
43 changes: 43 additions & 0 deletions examples/java-matter-controller/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright (c) 2022 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.
# 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.

import("//build_overrides/build.gni")
import("//build_overrides/chip.gni")

import("${build_root}/config/android_abi.gni")
import("${chip_root}/build/chip/java/rules.gni")
import("${chip_root}/build/chip/tools.gni")

android_binary("java-matter-controller") {
output_name = "java-matter-controller"

deps = [
":android",
"${chip_root}/src/controller/java",
"${chip_root}/src/setup_payload/java",
"${chip_root}/third_party/android_deps:annotation",
]

sources = [ "java/src/com/matter/controller/Main.java" ]

javac_flags = [ "-Xlint:deprecation" ]
}

java_prebuilt("android") {
jar_path = "${android_sdk_root}/platforms/android-21/android.jar"
}

group("default") {
deps = [ ":java-matter-controller" ]
}
2 changes: 2 additions & 0 deletions examples/java-matter-controller/Manifest.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Main-Class: com.matter.controller.Main

67 changes: 67 additions & 0 deletions examples/java-matter-controller/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Matter Controller Java App Example

This is a Matter Controller Java app that can be used to uses Matter to send
messages to a Matter server.

<hr>

- [Matter Controller Java App Example](#matter-controller-java-app-example)
- [Requirements for building](#requirements-for-building)
- [Gradle & JDK Version](#gradle--jdk-version)
- [Preparing for build](#preparing-for-build)
- [Building & Running the app](#building--running-the-app)

<hr>

<a name="requirements"></a>

## Requirements for building

You need Android SDK 21 & NDK downloaded to your machine. Set the
`$ANDROID_HOME` environment variable to where the SDK is downloaded and the
`$ANDROID_NDK_HOME` environment variable to point to where the NDK package is
downloaded.

<a name="jdk"></a>

### Gradle & JDK Version

We are using Gradle 7.1.1 for all android project which does not support Java 17
(https://docs.gradle.org/current/userguide/compatibility.html) while the default
JDK version on MacOS for Apple Silicon is 'openjdk 17.0.1' or above.

Using JDK bundled with Android Studio will help with that.

```shell
export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jre/Contents/Home/
```

<hr>

<a name="preparing"></a>

## Preparing for build

Complete the following steps to prepare the Matter build:

1. Check out the Matter repository.

2. Run bootstrap (**only required first time**)

```shell
source scripts/bootstrap.sh
```

<a name="building-running"></a>

## Building & Running the app

This is the simplest option. In the command line, run the following command from
the top Matter directory:

```shell
./scripts/build/build_examples.py --target android-x86-java-matter-controller build
```

The Java executable file `java-matter-controller` will be generated at
`out/android-x86-java-matter-controller/bin/`
25 changes: 25 additions & 0 deletions examples/java-matter-controller/args.gni
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright (c) 2020-2022 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.
# 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.

import("//build_overrides/chip.gni")

import("${chip_root}/config/standalone/args.gni")

chip_device_project_config_include = "<CHIPProjectAppConfig.h>"
chip_project_config_include = "<CHIPProjectAppConfig.h>"
chip_system_project_config_include = "<SystemProjectConfig.h>"

chip_project_config_include_dirs =
[ "${chip_root}/examples/java-matter-controller/include" ]
chip_project_config_include_dirs += [ "${chip_root}/config/standalone" ]
1 change: 1 addition & 0 deletions examples/java-matter-controller/build_overrides
65 changes: 65 additions & 0 deletions examples/java-matter-controller/include/CHIPProjectAppConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
*
* Copyright (c) 2020-2022 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.
* 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.
*/

/**
* @file
* Project configuration for Matter Controller.
*
*/
#ifndef CHIPPROJECTCONFIG_H
#define CHIPPROJECTCONFIG_H

#define CHIP_CONFIG_MAX_FABRICS 17

#define CHIP_CONFIG_EVENT_LOGGING_NUM_EXTERNAL_CALLBACKS 2

#define CHIP_CONFIG_EVENT_LOGGING_EXTERNAL_EVENT_SUPPORT 1

// Enable support functions for parsing command-line arguments
#define CHIP_CONFIG_ENABLE_ARG_PARSER 1

// Use a default pairing code if one hasn't been provisioned in flash.
#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021
#define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00

// Enable reading DRBG seed data from /dev/(u)random.
// This is needed for test applications and the CHIP device manager to function
// properly when CHIP_CONFIG_RNG_IMPLEMENTATION_CHIPDRBG is enabled.
#define CHIP_CONFIG_DEV_RANDOM_DRBG_SEED 1

// For convenience, Chip Security Test Mode can be enabled and the
// requirement for authentication in various protocols can be disabled.
//
// WARNING: These options make it possible to circumvent basic Chip security functionality,
// including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS.
//
#define CHIP_CONFIG_SECURITY_TEST_MODE 0

#define CHIP_CONFIG_ENABLE_UPDATE 1

#define CHIP_SYSTEM_CONFIG_PACKETBUFFER_POOL_SIZE 0

#define CHIP_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL 1

#define CHIP_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY 1

#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY 1

// Enable some test-only interaction model APIs.
#define CONFIG_BUILD_FOR_HOST_UNIT_TEST 1

#endif /* CHIPPROJECTCONFIG_H */
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2022 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 com.matter.controller;

public class Main {
public static void main(String[] args) {
System.out.println("Hello Matter Controller!");

for (String s : args) {
System.out.println(s);
}
}
}
1 change: 1 addition & 0 deletions scripts/build/build/targets.py
Original file line number Diff line number Diff line change
@@ -266,6 +266,7 @@ def BuildAndroidTarget():
TargetPart('chip-test', app=AndroidApp.CHIP_TEST),
TargetPart('tv-server', app=AndroidApp.TV_SERVER),
TargetPart('tv-casting-app', app=AndroidApp.TV_CASTING_APP),
TargetPart('java-matter-controller', app=AndroidApp.JAVA_MATTER_CONTROLLER),
])

return target
134 changes: 103 additions & 31 deletions scripts/build/builders/android.py
Original file line number Diff line number Diff line change
@@ -70,6 +70,7 @@ class AndroidApp(Enum):
CHIP_TEST = auto()
TV_SERVER = auto()
TV_CASTING_APP = auto()
JAVA_MATTER_CONTROLLER = auto()

def AppName(self):
if self == AndroidApp.CHIP_TOOL:
@@ -80,6 +81,8 @@ def AppName(self):
return "tv-server"
elif self == AndroidApp.TV_CASTING_APP:
return "tv-casting"
elif self == AndroidApp.JAVA_MATTER_CONTROLLER:
return "java-matter-controller"
else:
raise Exception("Unknown app type: %r" % self)

@@ -96,6 +99,8 @@ def ExampleName(self):
return "tv-app"
elif self == AndroidApp.TV_CASTING_APP:
return "tv-casting-app"
elif self == AndroidApp.JAVA_MATTER_CONTROLLER:
return "java-matter-controller"
else:
return None

@@ -216,25 +221,11 @@ def copyToSrcAndroid(self):
]
)

def copyToExampleAndroid(self):
jnilibs_dir = os.path.join(
self.root,
"examples",
self.app.ExampleName(),
"android/App/app/libs/jniLibs",
self.board.AbiName(),
)
libs_dir = os.path.join(
self.root, "examples", self.app.ExampleName(), "android/App/app/libs"
)
def copyToExampleApp(self, jnilibs_dir, libs_dir, libs, jars):
self._Execute(
["mkdir", "-p", jnilibs_dir], title="Prepare Native libs " + self.identifier
)

if self.app.ExampleName() == "tv-casting-app":
libs = ["libc++_shared.so", "libTvCastingApp.so"]
else:
libs = ["libSetupPayloadParser.so", "libc++_shared.so", "libTvApp.so"]
for libName in libs:
self._Execute(
[
@@ -246,19 +237,6 @@ def copyToExampleAndroid(self):
]
)

if self.app.ExampleName() == "tv-casting-app":
jars = {
"AndroidPlatform.jar": "third_party/connectedhomeip/src/platform/android/AndroidPlatform.jar",
"CHIPAppServer.jar": "third_party/connectedhomeip/src/app/server/java/CHIPAppServer.jar",
"TvCastingApp.jar": "TvCastingApp.jar",
}
else:
jars = {
"SetupPayloadParser.jar": "third_party/connectedhomeip/src/setup_payload/java/SetupPayloadParser.jar",
"AndroidPlatform.jar": "third_party/connectedhomeip/src/platform/android/AndroidPlatform.jar",
"CHIPAppServer.jar": "third_party/connectedhomeip/src/app/server/java/CHIPAppServer.jar",
"TvApp.jar": "TvApp.jar",
}
for jarName in jars.keys():
self._Execute(
[
@@ -316,6 +294,16 @@ def gradlewBuildExampleAndroid(self):
title="Building Example " + self.identifier,
)

def createJavaExecutable(self, java_program):
self._Execute(
[
"chmod",
"+x",
"%s/bin/%s" % (self.output_dir, java_program),
],
title="Make Java program executable",
)

def generate(self):
self._Execute(
["python3", "third_party/android_deps/set_up_android_deps.py"],
@@ -356,7 +344,10 @@ def generate(self):

exampleName = self.app.ExampleName()
if exampleName is not None:
gn_gen += ["--root=%s/examples/%s/android/" % (self.root, exampleName)]
if exampleName == "java-matter-controller":
gn_gen += ["--root=%s/examples/%s/" % (self.root, exampleName)]
else:
gn_gen += ["--root=%s/examples/%s/android/" % (self.root, exampleName)]

if self.board.IsIde():
gn_gen += [
@@ -387,6 +378,17 @@ def generate(self):
title="Accepting NDK licenses @ tools",
)

app_dir = os.path.join(self.root, "examples/", self.app.AppName())
if exampleName == "java-matter-controller":
self._Execute(
[
"cp",
os.path.join(app_dir, "Manifest.txt"),
self.output_dir,
],
title="Copying Manifest.txt to " + self.output_dir,
)

def _build(self):
if self.board.IsIde():
# App compilation IDE
@@ -413,8 +415,78 @@ def _build(self):
if exampleName is None:
self.copyToSrcAndroid()
self.gradlewBuildSrcAndroid()
else:
self.copyToExampleAndroid()
elif exampleName == "java-matter-controller":
jnilibs_dir = os.path.join(
self.root,
"examples/",
self.app.ExampleName(),
"app/libs/jniLibs",
self.board.AbiName(),
)

libs_dir = os.path.join(
self.root, "examples/", self.app.ExampleName(), "app/libs"
)

libs = [
"libSetupPayloadParser.so",
"libCHIPController.so",
"libc++_shared.so",
]

jars = {
"CHIPController.jar": "third_party/connectedhomeip/src/controller/java/CHIPController.jar",
"SetupPayloadParser.jar": "third_party/connectedhomeip/src/setup_payload/java/SetupPayloadParser.jar",
}

self.copyToExampleApp(jnilibs_dir, libs_dir, libs, jars)
self.createJavaExecutable("java-matter-controller")
elif exampleName == "tv-casting-app":
jnilibs_dir = os.path.join(
self.root,
"examples/",
self.app.ExampleName(),
"android/App/app/libs/jniLibs",
self.board.AbiName(),
)

libs_dir = os.path.join(
self.root, "examples/", self.app.ExampleName(), "android/App/app/libs"
)

libs = ["libc++_shared.so", "libTvCastingApp.so"]

jars = {
"AndroidPlatform.jar": "third_party/connectedhomeip/src/platform/android/AndroidPlatform.jar",
"CHIPAppServer.jar": "third_party/connectedhomeip/src/app/server/java/CHIPAppServer.jar",
"TvCastingApp.jar": "TvCastingApp.jar",
}

self.copyToExampleApp(jnilibs_dir, libs_dir, libs, jars)
self.gradlewBuildExampleAndroid()
elif exampleName == "tv-app":
jnilibs_dir = os.path.join(
self.root,
"examples/",
self.app.ExampleName(),
"android/App/app/libs/jniLibs",
self.board.AbiName(),
)

libs_dir = os.path.join(
self.root, "examples/", self.app.ExampleName(), "android/App/app/libs"
)

libs = ["libSetupPayloadParser.so", "libc++_shared.so", "libTvApp.so"]

jars = {
"SetupPayloadParser.jar": "third_party/connectedhomeip/src/setup_payload/java/SetupPayloadParser.jar",
"AndroidPlatform.jar": "third_party/connectedhomeip/src/platform/android/AndroidPlatform.jar",
"CHIPAppServer.jar": "third_party/connectedhomeip/src/app/server/java/CHIPAppServer.jar",
"TvApp.jar": "TvApp.jar",
}

self.copyToExampleApp(jnilibs_dir, libs_dir, libs, jars)
self.gradlewBuildExampleAndroid()

def build_outputs(self):