Add Android tv server (#11245)
* added app server jni
* added getQrCodeFromPayload in SetupPayloadParser
* added TVServer app for android
* fix BLE error
* fix ci issue
* fix restyled errors
* fix ci issue
* fix Tests / Test Suites - Linux (tsan) ci issue
* fix zap issue, we should not add unneed functions in zap but fix undefined issue
diff --git a/BUILD.gn b/BUILD.gn
index 3753f04..57d4f38 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -125,6 +125,7 @@
if (current_os == "android") {
deps += [
+ "${chip_root}/src/app/server/java",
"${chip_root}/src/controller/java",
"${chip_root}/src/platform/android:java",
"${chip_root}/src/setup_payload/java",
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 9101fbb..d26edeb 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -435,6 +435,11 @@
"-ffunction-sections",
"-fdata-sections",
]
+
+ # do not export functions in jni, or --gc-sections will not work and will be some undefined issues
+ if (current_os == "android") {
+ cflags += [ "-fvisibility=hidden" ]
+ }
}
config("stack_protector_default") {
diff --git a/examples/tv-app/android/BUILD.gn b/examples/tv-app/android/BUILD.gn
new file mode 100644
index 0000000..d071cdc
--- /dev/null
+++ b/examples/tv-app/android/BUILD.gn
@@ -0,0 +1,61 @@
+# Copyright (c) 2021 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("${chip_root}/build/chip/tools.gni")
+
+# Todo: copy from examples/tv-app/linux but later will be moved to jni and upto java workd
+source_set("android-tv-app") {
+ sources = [
+ "${chip_root}/examples/tv-app/tv-common/include/CHIPProjectAppConfig.h",
+ "include/account-login/AccountLoginManager.cpp",
+ "include/account-login/AccountLoginManager.h",
+ "include/application-basic/ApplicationBasicManager.cpp",
+ "include/application-basic/ApplicationBasicManager.h",
+ "include/application-launcher/ApplicationLauncherManager.cpp",
+ "include/application-launcher/ApplicationLauncherManager.h",
+ "include/audio-output/AudioOutputManager.cpp",
+ "include/audio-output/AudioOutputManager.h",
+ "include/cluster-change-attribute.cpp",
+ "include/cluster-init.cpp",
+ "include/content-launcher/ContentLauncherManager.cpp",
+ "include/content-launcher/ContentLauncherManager.h",
+ "include/endpoint-configuration/EndpointConfigurationStorage.cpp",
+ "include/endpoint-configuration/EndpointConfigurationStorage.h",
+ "include/keypad-input/KeypadInputManager.cpp",
+ "include/keypad-input/KeypadInputManager.h",
+ "include/low-power/LowPowerManager.cpp",
+ "include/low-power/LowPowerManager.h",
+ "include/media-input/MediaInputManager.cpp",
+ "include/media-input/MediaInputManager.h",
+ "include/media-playback/MediaPlaybackManager.cpp",
+ "include/media-playback/MediaPlaybackManager.h",
+ "include/target-navigator/TargetNavigatorManager.cpp",
+ "include/target-navigator/TargetNavigatorManager.h",
+ "include/tv-channel/TvChannelManager.cpp",
+ "include/tv-channel/TvChannelManager.h",
+ "include/wake-on-lan/WakeOnLanManager.cpp",
+ "include/wake-on-lan/WakeOnLanManager.h",
+ ]
+
+ deps = [
+ "${chip_root}/examples/tv-app/tv-common",
+ "${chip_root}/src/lib",
+ "${chip_root}/third_party/inipp",
+ ]
+
+ cflags = [ "-Wconversion" ]
+}
diff --git a/examples/tv-app/android/include/account-login/AccountLoginManager.cpp b/examples/tv-app/android/include/account-login/AccountLoginManager.cpp
new file mode 100644
index 0000000..f599b71
--- /dev/null
+++ b/examples/tv-app/android/include/account-login/AccountLoginManager.cpp
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "AccountLoginManager.h"
+#include <app-common/zap-generated/attribute-id.h>
+#include <app-common/zap-generated/attribute-type.h>
+#include <app-common/zap-generated/cluster-id.h>
+#include <app-common/zap-generated/command-id.h>
+#include <app-common/zap-generated/enums.h>
+#include <app/Command.h>
+#include <app/util/af.h>
+
+using namespace std;
+
+bool AccountLoginManager::isUserLoggedIn(string requestTempAccountIdentifier, string requestSetupPin)
+{
+ // TODO: Fix hardcoding length of strings
+ requestTempAccountIdentifier = requestTempAccountIdentifier.substr(0, 4);
+ requestSetupPin = requestSetupPin.substr(0, 10);
+ for (auto it = accounts.cbegin(); it != accounts.cend(); ++it)
+ {
+ ChipLogProgress(Zcl, "temporary account id: %s", it->first.c_str());
+ ChipLogProgress(Zcl, "setup pin %s", it->second.c_str());
+ }
+
+ if (accounts.find(requestTempAccountIdentifier) != accounts.end())
+ {
+ bool found = accounts[requestTempAccountIdentifier] == requestSetupPin;
+ if (!found)
+ {
+ ChipLogError(Zcl, "User is not logged in, failed to match request setup pin.");
+ }
+ return found;
+ }
+ else
+ {
+ ChipLogError(Zcl, "User is not logged in, failed to find temp account identifier.");
+ return false;
+ }
+}
+
+void AccountLoginManager::setTempAccountIdentifierForPin(string tempAccountIdentifier, string setupPin)
+{
+ // TODO: Fix hardcoding length of strings
+ string tempId = tempAccountIdentifier.substr(0, 4);
+ accounts[tempId] = setupPin;
+}
+
+string AccountLoginManager::proxySetupPinRequest(string requestTempAccountIdentifier, chip::EndpointId endpoint)
+{
+ // TODO: Insert your code here to send temp account identifier request
+ return "tempPin123";
+}
+
+bool accountLoginClusterIsUserLoggedIn(std::string requestTempAccountIdentifier, std::string requestSetupPin)
+{
+ return AccountLoginManager().GetInstance().isUserLoggedIn(requestTempAccountIdentifier, requestSetupPin);
+}
+
+std::string accountLoginClusterGetSetupPin(std::string requestTempAccountIdentifier, chip::EndpointId endpoint)
+{
+ string responseSetupPin = AccountLoginManager().proxySetupPinRequest(requestTempAccountIdentifier, endpoint);
+ AccountLoginManager().GetInstance().setTempAccountIdentifierForPin(requestTempAccountIdentifier, responseSetupPin);
+ return responseSetupPin;
+}
diff --git a/examples/tv-app/android/include/account-login/AccountLoginManager.h b/examples/tv-app/android/include/account-login/AccountLoginManager.h
new file mode 100644
index 0000000..7e1be63
--- /dev/null
+++ b/examples/tv-app/android/include/account-login/AccountLoginManager.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app/util/af-types.h>
+#include <lib/core/CHIPError.h>
+#include <map>
+#include <string>
+
+class AccountLoginManager
+{
+public:
+ bool isUserLoggedIn(std::string requestTempAccountIdentifier, std::string requestSetupPin);
+ std::string proxySetupPinRequest(std::string requestTempAccountIdentifier, chip::EndpointId endpoint);
+ void setTempAccountIdentifierForPin(std::string requestTempAccountIdentifier, std::string requestSetupPin);
+
+ static AccountLoginManager & GetInstance()
+ {
+ static AccountLoginManager instance;
+ return instance;
+ }
+
+private:
+ std::map<std::string, std::string> accounts;
+};
diff --git a/examples/tv-app/android/include/application-basic/Application.h b/examples/tv-app/android/include/application-basic/Application.h
new file mode 100644
index 0000000..bdea7a7
--- /dev/null
+++ b/examples/tv-app/android/include/application-basic/Application.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app-common/zap-generated/enums.h>
+
+struct Application
+{
+ char vendorName[32] = "";
+ char name[32] = "";
+ char id[32] = "";
+ uint16_t vendorId = 0;
+ uint16_t productId = 0;
+ uint16_t catalogVendorId = 0;
+ EmberAfApplicationBasicStatus status = EMBER_ZCL_APPLICATION_BASIC_STATUS_STOPPED;
+};
diff --git a/examples/tv-app/android/include/application-basic/ApplicationBasicManager.cpp b/examples/tv-app/android/include/application-basic/ApplicationBasicManager.cpp
new file mode 100644
index 0000000..e3c893f
--- /dev/null
+++ b/examples/tv-app/android/include/application-basic/ApplicationBasicManager.cpp
@@ -0,0 +1,161 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "ApplicationBasicManager.h"
+#include <app-common/zap-generated/attribute-id.h>
+#include <app-common/zap-generated/attribute-type.h>
+#include <app-common/zap-generated/cluster-id.h>
+#include <app-common/zap-generated/command-id.h>
+#include <app-common/zap-generated/enums.h>
+#include <app/Command.h>
+#include <app/util/af.h>
+#include <app/util/basic-types.h>
+#include <lib/support/ZclString.h>
+
+#include <inipp/inipp.h>
+
+using namespace chip;
+
+CHIP_ERROR ApplicationBasicManager::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ EndpointConfigurationStorage & endpointConfiguration = EndpointConfigurationStorage::GetInstance();
+ err = endpointConfiguration.Init();
+ SuccessOrExit(err);
+ es = &endpointConfiguration;
+exit:
+ return err;
+}
+
+void ApplicationBasicManager::store(chip::EndpointId endpoint, Application * application)
+{
+ uint8_t bufferMemory[64];
+ MutableByteSpan zclString(bufferMemory);
+
+ MakeZclCharString(zclString, application->vendorName);
+ EmberAfStatus vendorNameStatus =
+ emberAfWriteServerAttribute(endpoint, ZCL_APPLICATION_BASIC_CLUSTER_ID, ZCL_APPLICATION_VENDOR_NAME_ATTRIBUTE_ID,
+ zclString.data(), ZCL_CHAR_STRING_ATTRIBUTE_TYPE);
+ if (vendorNameStatus != EMBER_ZCL_STATUS_SUCCESS)
+ {
+ ChipLogError(Zcl, "Failed to store vendor name attribute.");
+ }
+
+ EmberAfStatus vendorIdStatus =
+ emberAfWriteServerAttribute(endpoint, ZCL_APPLICATION_BASIC_CLUSTER_ID, ZCL_APPLICATION_VENDOR_ID_ATTRIBUTE_ID,
+ (uint8_t *) &application->vendorId, ZCL_INT16U_ATTRIBUTE_TYPE);
+ if (vendorIdStatus != EMBER_ZCL_STATUS_SUCCESS)
+ {
+ ChipLogError(Zcl, "Failed to store vendor id attribute.");
+ }
+
+ MakeZclCharString(zclString, application->name);
+ EmberAfStatus nameStatus =
+ emberAfWriteServerAttribute(endpoint, ZCL_APPLICATION_BASIC_CLUSTER_ID, ZCL_APPLICATION_NAME_ATTRIBUTE_ID, zclString.data(),
+ ZCL_CHAR_STRING_ATTRIBUTE_TYPE);
+ if (nameStatus != EMBER_ZCL_STATUS_SUCCESS)
+ {
+ ChipLogError(Zcl, "Failed to store name attribute.");
+ }
+
+ EmberAfStatus productIdStatus =
+ emberAfWriteServerAttribute(endpoint, ZCL_APPLICATION_BASIC_CLUSTER_ID, ZCL_APPLICATION_PRODUCT_ID_ATTRIBUTE_ID,
+ (uint8_t *) &application->productId, ZCL_INT16U_ATTRIBUTE_TYPE);
+ if (productIdStatus != EMBER_ZCL_STATUS_SUCCESS)
+ {
+ ChipLogError(Zcl, "Failed to store product id attribute.");
+ }
+
+ MakeZclCharString(zclString, application->id);
+ EmberAfStatus idStatus =
+ emberAfWriteServerAttribute(endpoint, ZCL_APPLICATION_BASIC_CLUSTER_ID, ZCL_APPLICATION_ID_ATTRIBUTE_ID, zclString.data(),
+ ZCL_CHAR_STRING_ATTRIBUTE_TYPE);
+ if (idStatus != EMBER_ZCL_STATUS_SUCCESS)
+ {
+ ChipLogError(Zcl, "Failed to store id attribute.");
+ }
+
+ EmberAfStatus catalogVendorIdStatus =
+ emberAfWriteServerAttribute(endpoint, ZCL_APPLICATION_BASIC_CLUSTER_ID, ZCL_CATALOG_VENDOR_ID_ATTRIBUTE_ID,
+ (uint8_t *) &application->catalogVendorId, ZCL_INT16U_ATTRIBUTE_TYPE);
+ if (catalogVendorIdStatus != EMBER_ZCL_STATUS_SUCCESS)
+ {
+ ChipLogError(Zcl, "Failed to store catalog vendor id attribute.");
+ }
+
+ EmberAfStatus applicationStatus =
+ emberAfWriteServerAttribute(endpoint, ZCL_APPLICATION_BASIC_CLUSTER_ID, ZCL_APPLICATION_STATUS_ATTRIBUTE_ID,
+ (uint8_t *) &application->status, ZCL_ENUM8_ATTRIBUTE_TYPE);
+ if (applicationStatus != EMBER_ZCL_STATUS_SUCCESS)
+ {
+ ChipLogError(Zcl, "Failed to store status attribute.");
+ }
+}
+
+Application ApplicationBasicManager::getApplicationForEndpoint(chip::EndpointId endpoint)
+{
+ Application app = {};
+ uint16_t size = static_cast<uint16_t>(sizeof(app.name));
+
+ std::string section = "endpoint" + std::to_string(endpoint);
+
+ CHIP_ERROR err = es->get(section, "name", app.name, size);
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(Zcl, "Failed to get app name. Error:%s", chip::ErrorStr(err));
+ }
+
+ err = es->get(section, "vendorName", app.vendorName, size);
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(Zcl, "Failed to get app vendor name. Error:%s", chip::ErrorStr(err));
+ }
+
+ err = es->get(section, "id", app.id, size);
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(Zcl, "Failed to get app id. Error:%s", chip::ErrorStr(err));
+ }
+
+ err = es->get(section, "catalogVendorId", app.catalogVendorId);
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(Zcl, "Failed to get app catalog vendor id. Error:%s", chip::ErrorStr(err));
+ }
+
+ err = es->get(section, "productId", app.productId);
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(Zcl, "Failed to get app product id. Error:%s", chip::ErrorStr(err));
+ }
+
+ err = es->get(section, "vendorId", app.vendorId);
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(Zcl, "Failed to get app vendor id. Error:%s", chip::ErrorStr(err));
+ }
+
+ return app;
+}
+
+bool applicationBasicClusterChangeApplicationStatus(EmberAfApplicationBasicStatus status, chip::EndpointId endpoint)
+{
+ // TODO: Insert code here
+ ChipLogProgress(Zcl, "Sent an application status change request %d for endpoint %d", status, endpoint);
+ return true;
+}
diff --git a/examples/tv-app/android/include/application-basic/ApplicationBasicManager.h b/examples/tv-app/android/include/application-basic/ApplicationBasicManager.h
new file mode 100644
index 0000000..d8c8d21
--- /dev/null
+++ b/examples/tv-app/android/include/application-basic/ApplicationBasicManager.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app/util/af-types.h>
+#include <lib/core/CHIPError.h>
+
+#include "../endpoint-configuration/EndpointConfigurationStorage.h"
+#include "Application.h"
+#include <vector>
+
+class ApplicationBasicManager
+{
+public:
+ CHIP_ERROR Init();
+ void store(chip::EndpointId endpoint, Application * application);
+ Application getApplicationForEndpoint(chip::EndpointId endpoint);
+
+ static ApplicationBasicManager & GetInstance()
+ {
+ static ApplicationBasicManager instance;
+ return instance;
+ }
+
+private:
+ EndpointConfigurationStorage * es = nullptr;
+};
diff --git a/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.cpp b/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.cpp
new file mode 100644
index 0000000..f193ce3
--- /dev/null
+++ b/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.cpp
@@ -0,0 +1,58 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "ApplicationLauncherManager.h"
+#include <app-common/zap-generated/af-structs.h>
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app/clusters/application-launcher-server/application-launcher-server.h>
+#include <app/util/af.h>
+#include <app/util/basic-types.h>
+
+using namespace std;
+
+CHIP_ERROR ApplicationLauncherManager::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ SuccessOrExit(err);
+exit:
+ return err;
+}
+
+CHIP_ERROR ApplicationLauncherManager::proxyGetApplicationList(chip::app::AttributeValueEncoder & aEncoder)
+{
+ return aEncoder.EncodeList([](const chip::app::TagBoundEncoder & encoder) -> CHIP_ERROR {
+ ReturnErrorOnFailure(encoder.Encode(123u));
+ ReturnErrorOnFailure(encoder.Encode(456u));
+ return CHIP_NO_ERROR;
+ });
+}
+
+ApplicationLauncherResponse applicationLauncherClusterLaunchApp(ApplicationLauncherApp application, std::string data)
+{
+ // TODO: Insert your code
+ ApplicationLauncherResponse response;
+ const char * testData = "data";
+ response.data = (uint8_t *) testData;
+ response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS;
+ // TODO: Update once storing a structure attribute is supported
+ // emberAfWriteServerAttribute(endpoint, ZCL_APPLICATION_LAUNCH_CLUSTER_ID, ZCL_APPLICATION_LAUNCHER_CURRENT_APP_APPLICATION_ID,
+ // (uint8_t *) &application, ZCL_STRUCT_ATTRIBUTE_TYPE);
+
+ return response;
+}
diff --git a/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.h b/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.h
new file mode 100644
index 0000000..718321e
--- /dev/null
+++ b/examples/tv-app/android/include/application-launcher/ApplicationLauncherManager.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app/AttributeAccessInterface.h>
+#include <lib/core/CHIPError.h>
+
+#include <string>
+#include <vector>
+
+class ApplicationLauncherManager
+{
+public:
+ CHIP_ERROR Init();
+ CHIP_ERROR proxyGetApplicationList(chip::app::AttributeValueEncoder & aEncoder);
+};
diff --git a/examples/tv-app/android/include/audio-output/AudioOutputManager.cpp b/examples/tv-app/android/include/audio-output/AudioOutputManager.cpp
new file mode 100644
index 0000000..61018e7
--- /dev/null
+++ b/examples/tv-app/android/include/audio-output/AudioOutputManager.cpp
@@ -0,0 +1,71 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "AudioOutputManager.h"
+
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app/util/af.h>
+#include <app/util/basic-types.h>
+#include <lib/core/CHIPSafeCasts.h>
+#include <lib/support/CodeUtils.h>
+
+#include <map>
+#include <string>
+
+using namespace std;
+
+CHIP_ERROR AudioOutputManager::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ // TODO: Store feature map once it is supported
+ map<string, bool> featureMap;
+ featureMap["NU"] = true;
+
+ return err;
+}
+
+CHIP_ERROR AudioOutputManager::proxyGetListOfAudioOutputInfo(chip::app::AttributeValueEncoder & aEncoder)
+{
+ return aEncoder.EncodeList([](const chip::app::TagBoundEncoder & encoder) -> CHIP_ERROR {
+ // TODO: Insert code here
+ int maximumVectorSize = 3;
+ char name[] = "exampleName";
+
+ for (int i = 0; i < maximumVectorSize; ++i)
+ {
+ chip::app::Clusters::AudioOutput::Structs::AudioOutputInfo::Type audioOutputInfo;
+ audioOutputInfo.outputType = EMBER_ZCL_AUDIO_OUTPUT_TYPE_HDMI;
+ audioOutputInfo.name = chip::CharSpan(name, sizeof(name) - 1);
+ audioOutputInfo.index = static_cast<uint8_t>(1 + i);
+ ReturnErrorOnFailure(encoder.Encode(audioOutputInfo));
+ }
+ return CHIP_NO_ERROR;
+ });
+}
+
+bool audioOutputClusterSelectOutput(uint8_t index)
+{
+ // TODO: Insert code here
+ return true;
+}
+bool audioOutputClusterRenameOutput(uint8_t index, const chip::CharSpan & name)
+{
+ // TODO: Insert code here
+ return true;
+}
diff --git a/examples/tv-app/android/include/audio-output/AudioOutputManager.h b/examples/tv-app/android/include/audio-output/AudioOutputManager.h
new file mode 100644
index 0000000..63d4554
--- /dev/null
+++ b/examples/tv-app/android/include/audio-output/AudioOutputManager.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app/AttributeAccessInterface.h>
+
+#include <lib/core/CHIPError.h>
+#include <vector>
+class AudioOutputManager
+{
+public:
+ CHIP_ERROR Init();
+ CHIP_ERROR proxyGetListOfAudioOutputInfo(chip::app::AttributeValueEncoder & aEncoder);
+};
diff --git a/examples/tv-app/android/include/cluster-change-attribute.cpp b/examples/tv-app/android/include/cluster-change-attribute.cpp
new file mode 100644
index 0000000..b82682e
--- /dev/null
+++ b/examples/tv-app/android/include/cluster-change-attribute.cpp
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include <app-common/zap-generated/ids/Attributes.h>
+#include <app-common/zap-generated/ids/Clusters.h>
+#include <app/ConcreteAttributePath.h>
+#include <lib/support/logging/CHIPLogging.h>
+
+using namespace chip;
+using namespace ::chip::app::Clusters;
+
+enum TvCommand
+{
+ PowerToggle,
+ MuteToggle
+};
+
+void runTvCommand(TvCommand command)
+{
+ switch (command)
+ {
+ case PowerToggle:
+ // TODO: Insert your code here to send power toggle command
+ break;
+ case MuteToggle:
+ // TODO: Insert your code here to send mute toggle command
+ break;
+
+ default:
+ break;
+ }
+}
+
+void MatterAfPostAttributeChangeCallback(const app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type,
+ uint16_t size, uint8_t * value)
+{
+ if (attributePath.mClusterId == OnOff::Id && attributePath.mAttributeId == OnOff::Attributes::OnOff::Id)
+ {
+ ChipLogProgress(Zcl, "Received on/off command for cluster id: " ChipLogFormatMEI, ChipLogValueMEI(OnOff::Id));
+
+ if (attributePath.mEndpointId == 0)
+ {
+ ChipLogProgress(Zcl, "Execute POWER_TOGGLE");
+ runTvCommand(PowerToggle);
+ }
+ else if (attributePath.mEndpointId == 1)
+ {
+ ChipLogProgress(Zcl, "Execute MUTE_TOGGLE");
+ runTvCommand(MuteToggle);
+ }
+ }
+}
diff --git a/examples/tv-app/android/include/cluster-init.cpp b/examples/tv-app/android/include/cluster-init.cpp
new file mode 100644
index 0000000..3d7bee4
--- /dev/null
+++ b/examples/tv-app/android/include/cluster-init.cpp
@@ -0,0 +1,289 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "application-basic/ApplicationBasicManager.h"
+#include "application-launcher/ApplicationLauncherManager.h"
+#include "audio-output/AudioOutputManager.h"
+#include "content-launcher/ContentLauncherManager.h"
+#include "media-input/MediaInputManager.h"
+#include "target-navigator/TargetNavigatorManager.h"
+#include "tv-channel/TvChannelManager.h"
+#include "wake-on-lan/WakeOnLanManager.h"
+
+#include <app-common/zap-generated/attribute-id.h>
+#include <app-common/zap-generated/cluster-id.h>
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app-common/zap-generated/ids/Attributes.h>
+#include <app-common/zap-generated/ids/Clusters.h>
+#include <app/AttributeAccessInterface.h>
+#include <app/util/attribute-storage.h>
+
+using namespace chip;
+
+namespace {
+template <typename Manager, typename AttrTypeInfo, CHIP_ERROR (Manager::*Getter)(app::AttributeValueEncoder &)>
+class TvAttrAccess : public app::AttributeAccessInterface
+{
+public:
+ TvAttrAccess() : app::AttributeAccessInterface(Optional<EndpointId>::Missing(), AttrTypeInfo::GetClusterId()) {}
+
+ CHIP_ERROR Read(const app::ConcreteAttributePath & aPath, app::AttributeValueEncoder & aEncoder) override
+ {
+ if (aPath.mAttributeId == AttrTypeInfo::GetAttributeId())
+ {
+ return (Manager().*Getter)(aEncoder);
+ }
+
+ return CHIP_NO_ERROR;
+ }
+};
+
+} // anonymous namespace
+
+/** @brief Application Basic Cluster Init
+ *
+ * This function is called when a specific cluster is initialized. It gives the
+ * application an opportunity to take care of cluster initialization procedures.
+ * It is called exactly once for each endpoint where cluster is present.
+ *
+ * @param endpoint Ver.: always
+ *
+ */
+void emberAfApplicationBasicClusterInitCallback(chip::EndpointId endpoint)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ ApplicationBasicManager & aManager = ApplicationBasicManager::GetInstance();
+ err = aManager.Init();
+ if (CHIP_NO_ERROR == err)
+ {
+ Application application = aManager.getApplicationForEndpoint(endpoint);
+ aManager.store(endpoint, &application);
+ }
+ else
+ {
+ ChipLogError(Zcl, "Failed to store application for endpoint: %d. Error:%s", endpoint, chip::ErrorStr(err));
+ }
+}
+
+/** @brief Wake On LAN Cluster Init
+ *
+ * This function is called when a specific cluster is initialized. It gives the
+ * application an opportunity to take care of cluster initialization procedures.
+ * It is called exactly once for each endpoint where cluster is present.
+ *
+ * @param endpoint Ver.: always
+ *
+ */
+void emberAfWakeOnLanClusterInitCallback(chip::EndpointId endpoint)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ WakeOnLanManager & wolManager = WakeOnLanManager::GetInstance();
+ err = wolManager.Init();
+ if (CHIP_NO_ERROR == err)
+ {
+ char macAddress[32] = "";
+ wolManager.setMacAddress(endpoint, macAddress);
+ wolManager.store(endpoint, macAddress);
+ }
+ else
+ {
+ ChipLogError(Zcl, "Failed to store mac address for endpoint: %d. Error:%s", endpoint, chip::ErrorStr(err));
+ }
+}
+
+namespace {
+
+TvAttrAccess<TvChannelManager, app::Clusters::TvChannel::Attributes::TvChannelList::TypeInfo,
+ &TvChannelManager::proxyGetTvChannelList>
+ gTvChannelAttrAccess;
+
+} // anonymous namespace
+
+/** @brief Tv Channel Cluster Init
+ *
+ * This function is called when a specific cluster is initialized. It gives the
+ * application an opportunity to take care of cluster initialization procedures.
+ * It is called exactly once for each endpoint where cluster is present.
+ *
+ * @param endpoint Ver.: always
+ *
+ */
+void emberAfTvChannelClusterInitCallback(EndpointId endpoint)
+{
+ static bool attrAccessRegistered = false;
+ if (!attrAccessRegistered)
+ {
+ registerAttributeAccessOverride(&gTvChannelAttrAccess);
+ attrAccessRegistered = true;
+ }
+}
+
+namespace {
+
+TvAttrAccess<ApplicationLauncherManager, app::Clusters::ApplicationLauncher::Attributes::ApplicationLauncherList::TypeInfo,
+ &ApplicationLauncherManager::proxyGetApplicationList>
+ gApplicationLauncherAttrAccess;
+
+} // anonymous namespace
+
+/** @brief Application Launcher Cluster Init
+ *
+ * This function is called when a specific cluster is initialized. It gives the
+ * application an opportunity to take care of cluster initialization procedures.
+ * It is called exactly once for each endpoint where cluster is present.
+ *
+ * @param endpoint Ver.: always
+ *
+ */
+void emberAfApplicationLauncherClusterInitCallback(EndpointId endpoint)
+{
+ static bool attrAccessRegistered = false;
+ if (!attrAccessRegistered)
+ {
+ registerAttributeAccessOverride(&gApplicationLauncherAttrAccess);
+ attrAccessRegistered = true;
+ }
+}
+
+namespace {
+
+TvAttrAccess<AudioOutputManager, app::Clusters::AudioOutput::Attributes::AudioOutputList::TypeInfo,
+ &AudioOutputManager::proxyGetListOfAudioOutputInfo>
+ gAudioOutputAttrAccess;
+
+} // anonymous namespace
+
+/** @brief Audio Output Cluster Init
+ *
+ * This function is called when a specific cluster is initialized. It gives the
+ * application an opportunity to take care of cluster initialization procedures.
+ * It is called exactly once for each endpoint where cluster is present.
+ *
+ * @param endpoint Ver.: always
+ *
+ */
+void emberAfAudioOutputClusterInitCallback(EndpointId endpoint)
+{
+ static bool attrAccessRegistered = false;
+ if (!attrAccessRegistered)
+ {
+ registerAttributeAccessOverride(&gAudioOutputAttrAccess);
+ attrAccessRegistered = true;
+ }
+}
+
+namespace {
+
+class ContentLauncherAttrAccess : public app::AttributeAccessInterface
+{
+public:
+ ContentLauncherAttrAccess() : app::AttributeAccessInterface(Optional<EndpointId>::Missing(), app::Clusters::ContentLauncher::Id)
+ {}
+
+ CHIP_ERROR Read(const app::ConcreteAttributePath & aPath, app::AttributeValueEncoder & aEncoder) override
+ {
+ if (aPath.mAttributeId == app::Clusters::ContentLauncher::Attributes::AcceptsHeaderList::Id)
+ {
+ return ContentLauncherManager().proxyGetAcceptsHeader(aEncoder);
+ }
+
+ if (aPath.mAttributeId == app::Clusters::ContentLauncher::Attributes::SupportedStreamingTypes::Id)
+ {
+ return ContentLauncherManager().proxyGetSupportedStreamingTypes(aEncoder);
+ }
+
+ return CHIP_NO_ERROR;
+ }
+};
+
+ContentLauncherAttrAccess gContentLauncherAttrAccess;
+
+} // anonymous namespace
+
+/** @brief Content Launch Cluster Init
+ *
+ * This function is called when a specific cluster is initialized. It gives the
+ * application an opportunity to take care of cluster initialization procedures.
+ * It is called exactly once for each endpoint where cluster is present.
+ *
+ * @param endpoint Ver.: always
+ *
+ */
+void emberAfContentLauncherClusterInitCallback(EndpointId endpoint)
+{
+ static bool attrAccessRegistered = false;
+ if (!attrAccessRegistered)
+ {
+ registerAttributeAccessOverride(&gContentLauncherAttrAccess);
+ attrAccessRegistered = true;
+ }
+}
+
+namespace {
+
+TvAttrAccess<MediaInputManager, app::Clusters::MediaInput::Attributes::MediaInputList::TypeInfo,
+ &MediaInputManager::proxyGetInputList>
+ gMediaInputAttrAccess;
+
+} // anonymous namespace
+
+/** @brief Media Input Cluster Init
+ *
+ * This function is called when a specific cluster is initialized. It gives the
+ * application an opportunity to take care of cluster initialization procedures.
+ * It is called exactly once for each endpoint where cluster is present.
+ *
+ * @param endpoint Ver.: always
+ *
+ */
+void emberAfMediaInputClusterInitCallback(EndpointId endpoint)
+{
+ static bool attrAccessRegistered = false;
+ if (!attrAccessRegistered)
+ {
+ registerAttributeAccessOverride(&gMediaInputAttrAccess);
+ attrAccessRegistered = true;
+ }
+}
+
+namespace {
+
+TvAttrAccess<TargetNavigatorManager, app::Clusters::TargetNavigator::Attributes::TargetNavigatorList::TypeInfo,
+ &TargetNavigatorManager::proxyGetTargetInfoList>
+ gTargetNavigatorAttrAccess;
+
+} // anonymous namespace
+
+/** @brief Target Navigator Cluster Init
+ *
+ * This function is called when a specific cluster is initialized. It gives the
+ * application an opportunity to take care of cluster initialization procedures.
+ * It is called exactly once for each endpoint where cluster is present.
+ *
+ * @param endpoint Ver.: always
+ *
+ */
+void emberAfTargetNavigatorClusterInitCallback(EndpointId endpoint)
+{
+ static bool attrAccessRegistered = false;
+ if (!attrAccessRegistered)
+ {
+ registerAttributeAccessOverride(&gTargetNavigatorAttrAccess);
+ attrAccessRegistered = true;
+ }
+}
diff --git a/examples/tv-app/android/include/content-launcher/ContentLauncherManager.cpp b/examples/tv-app/android/include/content-launcher/ContentLauncherManager.cpp
new file mode 100644
index 0000000..001fe84
--- /dev/null
+++ b/examples/tv-app/android/include/content-launcher/ContentLauncherManager.cpp
@@ -0,0 +1,138 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "ContentLauncherManager.h"
+
+#include <app-common/zap-generated/attribute-id.h>
+#include <app-common/zap-generated/attribute-type.h>
+#include <app-common/zap-generated/cluster-id.h>
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app-common/zap-generated/command-id.h>
+
+#include <app/Command.h>
+#include <app/CommandHandler.h>
+#include <app/ConcreteCommandPath.h>
+#include <app/util/af.h>
+#include <app/util/basic-types.h>
+#include <lib/core/CHIPSafeCasts.h>
+#include <lib/support/CodeUtils.h>
+
+#include <map>
+
+using namespace std;
+
+CHIP_ERROR ContentLauncherManager::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ // TODO: Store feature map once it is supported
+ map<string, bool> featureMap;
+ featureMap["CS"] = true;
+ featureMap["UP"] = true;
+ featureMap["WA"] = true;
+
+ SuccessOrExit(err);
+exit:
+ return err;
+}
+
+CHIP_ERROR ContentLauncherManager::proxyGetAcceptsHeader(chip::app::AttributeValueEncoder & aEncoder)
+{
+ return aEncoder.EncodeList([](const chip::app::TagBoundEncoder & encoder) -> CHIP_ERROR {
+ // TODO: Insert code here
+ char headerExample[] = "exampleHeader";
+ int maximumVectorSize = 1;
+
+ for (uint16_t i = 0; i < maximumVectorSize; ++i)
+ {
+ ReturnErrorOnFailure(encoder.Encode(chip::ByteSpan(chip::Uint8::from_char(headerExample), sizeof(headerExample) - 1)));
+ }
+ return CHIP_NO_ERROR;
+ });
+}
+
+CHIP_ERROR ContentLauncherManager::proxyGetSupportedStreamingTypes(chip::app::AttributeValueEncoder & aEncoder)
+{
+ return aEncoder.EncodeList([](const chip::app::TagBoundEncoder & encoder) -> CHIP_ERROR {
+ // TODO: Insert code here
+ ReturnErrorOnFailure(encoder.Encode(EMBER_ZCL_CONTENT_LAUNCH_STREAMING_TYPE_DASH));
+ ReturnErrorOnFailure(encoder.Encode(EMBER_ZCL_CONTENT_LAUNCH_STREAMING_TYPE_HLS));
+ return CHIP_NO_ERROR;
+ });
+}
+
+ContentLaunchResponse ContentLauncherManager::proxyLaunchContentRequest(list<ContentLaunchParamater> parameterList, bool autoplay,
+ string data)
+{
+ // TODO: Insert code here
+ ContentLaunchResponse response;
+ response.data = "Example data";
+ response.status = EMBER_ZCL_CONTENT_LAUNCH_STATUS_SUCCESS;
+ return response;
+}
+ContentLaunchResponse ContentLauncherManager::proxyLaunchUrlRequest(string contentUrl, string displayString,
+ ContentLaunchBrandingInformation brandingInformation)
+{
+ // TODO: Insert code here
+ ContentLaunchResponse response;
+ response.data = "Example data";
+ response.status = EMBER_ZCL_CONTENT_LAUNCH_STATUS_SUCCESS;
+ return response;
+}
+
+static void sendResponse(const char * responseName, ContentLaunchResponse launchResponse, chip::CommandId commandId)
+{
+ emberAfFillExternalBuffer((ZCL_CLUSTER_SPECIFIC_COMMAND | ZCL_FRAME_CONTROL_SERVER_TO_CLIENT), ZCL_CONTENT_LAUNCH_CLUSTER_ID,
+ commandId, "us", launchResponse.status, &launchResponse.data);
+
+ EmberStatus status = emberAfSendResponse();
+ if (status != EMBER_SUCCESS)
+ {
+ ChipLogError(Zcl, "Failed to send %s. Error:%d", responseName, static_cast<int>(status));
+ }
+}
+
+bool emberAfContentLauncherClusterLaunchContentCallback(
+ chip::app::CommandHandler * command, const chip::app::ConcreteCommandPath & commandPath,
+ const chip::app::Clusters::ContentLauncher::Commands::LaunchContent::DecodableType & commandData)
+{
+ auto & autoplay = commandData.autoPlay;
+ auto & data = commandData.data;
+
+ string dataString(data.data(), data.size());
+ list<ContentLaunchParamater> parameterList;
+ ContentLaunchResponse response = ContentLauncherManager().proxyLaunchContentRequest(parameterList, autoplay, dataString);
+ sendResponse("LaunchContent", response, ZCL_LAUNCH_CONTENT_RESPONSE_COMMAND_ID);
+ return true;
+}
+
+bool emberAfContentLauncherClusterLaunchURLCallback(
+ chip::app::CommandHandler * command, const chip::app::ConcreteCommandPath & commandPath,
+ const chip::app::Clusters::ContentLauncher::Commands::LaunchURL::DecodableType & commandData)
+{
+ auto & contentUrl = commandData.contentURL;
+ auto & displayString = commandData.displayString;
+
+ string contentUrlString(contentUrl.data(), contentUrl.size());
+ string displayStringString(displayString.data(), displayString.size());
+ ContentLaunchBrandingInformation brandingInformation;
+ ContentLaunchResponse response =
+ ContentLauncherManager().proxyLaunchUrlRequest(contentUrlString, displayStringString, brandingInformation);
+ sendResponse("LaunchURL", response, ZCL_LAUNCH_URL_RESPONSE_COMMAND_ID);
+ return true;
+}
diff --git a/examples/tv-app/android/include/content-launcher/ContentLauncherManager.h b/examples/tv-app/android/include/content-launcher/ContentLauncherManager.h
new file mode 100644
index 0000000..285e521
--- /dev/null
+++ b/examples/tv-app/android/include/content-launcher/ContentLauncherManager.h
@@ -0,0 +1,44 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app-common/zap-generated/af-structs.h>
+#include <app/AttributeAccessInterface.h>
+
+#include <lib/core/CHIPError.h>
+#include <list>
+#include <string>
+#include <vector>
+struct ContentLaunchResponse
+{
+ EmberAfContentLaunchStatus status;
+ std::string data;
+};
+
+class ContentLauncherManager
+{
+public:
+ CHIP_ERROR Init();
+ CHIP_ERROR proxyGetAcceptsHeader(chip::app::AttributeValueEncoder & aEncoder);
+ CHIP_ERROR proxyGetSupportedStreamingTypes(chip::app::AttributeValueEncoder & aEncoder);
+ ContentLaunchResponse proxyLaunchContentRequest(std::list<ContentLaunchParamater> parameterList, bool autoplay,
+ std::string data);
+ ContentLaunchResponse proxyLaunchUrlRequest(std::string contentUrl, std::string displayString,
+ ContentLaunchBrandingInformation brandingInformation);
+};
diff --git a/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.cpp b/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.cpp
new file mode 100644
index 0000000..af4eb31
--- /dev/null
+++ b/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.cpp
@@ -0,0 +1,75 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+#include "EndpointConfigurationStorage.h"
+#include <fstream>
+#include <lib/support/CodeUtils.h>
+
+constexpr const char kEndpointConfigurationPath[] = "/tmp/chip_tv_config.ini";
+
+CHIP_ERROR EndpointConfigurationStorage::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ std::ifstream ifs;
+ ifs.open(kEndpointConfigurationPath, std::ifstream::in);
+ if (!ifs.good())
+ {
+ ifs.open(kEndpointConfigurationPath, std::ifstream::in);
+ }
+ VerifyOrExit(ifs.is_open(), err = CHIP_ERROR_OPEN_FAILED);
+
+ endpointConfig.parse(ifs);
+ ifs.close();
+
+exit:
+ return err;
+}
+
+CHIP_ERROR EndpointConfigurationStorage::get(std::string sectionName, const char * key, char * value, uint16_t & size)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ std::string iniValue;
+ size_t iniValueLength = 0;
+
+ auto section = endpointConfig.sections[sectionName];
+ auto it = section.find(key);
+ VerifyOrExit(it != section.end(), err = CHIP_ERROR_KEY_NOT_FOUND);
+ VerifyOrExit(inipp::extract(section[key], iniValue), err = CHIP_ERROR_INVALID_ARGUMENT);
+
+ iniValueLength = iniValue.size();
+ VerifyOrExit(iniValueLength <= static_cast<size_t>(size) - 1, err = CHIP_ERROR_BUFFER_TOO_SMALL);
+
+ iniValueLength = iniValue.copy(value, iniValueLength);
+ value[iniValueLength] = '\0';
+
+exit:
+ return err;
+}
+
+CHIP_ERROR EndpointConfigurationStorage::get(std::string sectionName, const char * key, uint16_t & value)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ auto section = endpointConfig.sections[sectionName];
+ auto it = section.find(key);
+ VerifyOrExit(it != section.end(), err = CHIP_ERROR_KEY_NOT_FOUND);
+ VerifyOrExit(inipp::extract(section[key], value), err = CHIP_ERROR_INVALID_ARGUMENT);
+
+exit:
+ return err;
+}
diff --git a/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.h b/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.h
new file mode 100644
index 0000000..cea787b
--- /dev/null
+++ b/examples/tv-app/android/include/endpoint-configuration/EndpointConfigurationStorage.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <inipp/inipp.h>
+#include <lib/core/CHIPCore.h>
+#include <string>
+
+class EndpointConfigurationStorage
+{
+public:
+ CHIP_ERROR Init();
+ CHIP_ERROR get(std::string sectionName, const char * key, char * value, uint16_t & size);
+ CHIP_ERROR get(std::string sectionName, const char * key, uint16_t & value);
+
+ static EndpointConfigurationStorage & GetInstance()
+ {
+ static EndpointConfigurationStorage instance;
+ return instance;
+ }
+
+private:
+ inipp::Ini<char> endpointConfig;
+};
diff --git a/examples/tv-app/android/include/endpoint-configuration/chip_tv_config.ini b/examples/tv-app/android/include/endpoint-configuration/chip_tv_config.ini
new file mode 100644
index 0000000..7cca745
--- /dev/null
+++ b/examples/tv-app/android/include/endpoint-configuration/chip_tv_config.ini
@@ -0,0 +1,42 @@
+[endpoint1]
+type=videoPlayer
+macAddress=00:00:00:00:00
+
+[endpoint2]
+type=speaker
+
+[endpoint3]
+type=app
+vendorName=exampleVendorName1
+vendorId=1
+name=exampleName1
+productId=1
+id=1
+catalogVendorId=1
+
+[endpoint4]
+type=app
+vendorName=exampleVendorName2
+vendorId=2
+name=exampleName2
+productId=2
+id=2
+catalogVendorId=2
+
+[endpoint5]
+type=app
+vendorName=exampleVendorName3
+vendorId=3
+name=exampleName3
+productId=3
+id= 3
+catalogVendorId=3
+
+[endpoint6]
+type=app
+vendorName=exampleVendorName4
+vendorId=4
+name=exampleName4
+productId=4
+id=4
+catalogVendorId=4
\ No newline at end of file
diff --git a/examples/tv-app/android/include/keypad-input/KeypadInputManager.cpp b/examples/tv-app/android/include/keypad-input/KeypadInputManager.cpp
new file mode 100644
index 0000000..58a39ab
--- /dev/null
+++ b/examples/tv-app/android/include/keypad-input/KeypadInputManager.cpp
@@ -0,0 +1,48 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "KeypadInputManager.h"
+
+#include <app/util/af.h>
+#include <app/util/basic-types.h>
+
+#include <map>
+#include <string>
+
+using namespace std;
+
+CHIP_ERROR KeypadInputManager::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ // TODO: Store feature map once it is supported
+ map<string, bool> featureMap;
+ featureMap["NV"] = true;
+ featureMap["LK"] = true;
+ featureMap["NK"] = true;
+
+ SuccessOrExit(err);
+exit:
+ return err;
+}
+
+EmberAfKeypadInputStatus keypadInputClusterSendKey(EmberAfKeypadInputCecKeyCode keyCode)
+{
+ // TODO: Insert code here
+ return EMBER_ZCL_KEYPAD_INPUT_STATUS_SUCCESS;
+}
diff --git a/examples/tv-app/android/include/keypad-input/KeypadInputManager.h b/examples/tv-app/android/include/keypad-input/KeypadInputManager.h
new file mode 100644
index 0000000..d55161a
--- /dev/null
+++ b/examples/tv-app/android/include/keypad-input/KeypadInputManager.h
@@ -0,0 +1,30 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app-common/zap-generated/af-structs.h>
+
+#include <lib/core/CHIPError.h>
+#include <list>
+
+class KeypadInputManager
+{
+public:
+ CHIP_ERROR Init();
+};
diff --git a/examples/tv-app/android/include/level-control/LevelControl.cpp b/examples/tv-app/android/include/level-control/LevelControl.cpp
new file mode 100644
index 0000000..2b53d45
--- /dev/null
+++ b/examples/tv-app/android/include/level-control/LevelControl.cpp
@@ -0,0 +1,180 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include <app/util/af.h>
+
+#include <app-common/zap-generated/af-structs.h>
+#include <app-common/zap-generated/attribute-id.h>
+#include <app-common/zap-generated/attribute-type.h>
+#include <app-common/zap-generated/cluster-id.h>
+#include <app-common/zap-generated/command-id.h>
+
+using namespace chip;
+
+#define MAX_LEVEL 99
+#define MIN_LEVEL 1
+
+typedef struct
+{
+ CommandId commandId;
+ uint16_t storedLevel;
+ bool increasing;
+} EmberAfLevelControlState;
+
+static EmberAfLevelControlState stateTable[EMBER_AF_LEVEL_CONTROL_CLUSTER_SERVER_ENDPOINT_COUNT];
+
+static EmberAfLevelControlState * getState(EndpointId endpoint)
+{
+ uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_LEVEL_CONTROL_CLUSTER_ID);
+ return (ep == 0xFF ? NULL : &stateTable[ep]);
+}
+
+static void stepHandler(CommandId commandId, uint8_t stepMode, uint8_t stepSize, uint16_t transitionTimeDs, uint8_t optionMask,
+ uint8_t optionOverride)
+{
+
+ EndpointId endpoint = emberAfCurrentEndpoint();
+ EmberAfLevelControlState * state = getState(endpoint);
+ EmberAfStatus status;
+ uint8_t currentLevel;
+
+ status = emberAfReadServerAttribute(endpoint, ZCL_LEVEL_CONTROL_CLUSTER_ID, ZCL_CURRENT_LEVEL_ATTRIBUTE_ID,
+ (uint8_t *) ¤tLevel, sizeof(currentLevel));
+
+ if (status != EMBER_ZCL_STATUS_SUCCESS)
+ {
+ emberAfLevelControlClusterPrintln("ERR: reading current level %x", status);
+ goto send_default_response;
+ }
+
+ switch (stepMode)
+ {
+ case EMBER_ZCL_STEP_MODE_UP:
+ state->increasing = true;
+ if (MAX_LEVEL >= currentLevel + stepSize)
+ {
+ currentLevel = currentLevel + stepSize;
+ }
+ break;
+ case EMBER_ZCL_STEP_MODE_DOWN:
+ state->increasing = false;
+ if (MIN_LEVEL <= currentLevel - stepSize)
+ {
+ currentLevel = currentLevel - stepSize;
+ }
+ break;
+ default:
+ status = EMBER_ZCL_STATUS_INVALID_FIELD;
+ goto send_default_response;
+ }
+
+ if (currentLevel != state->storedLevel)
+ {
+ int volumeIncrementCount = abs(currentLevel - state->storedLevel);
+ for (int i = 0; i < volumeIncrementCount; ++i)
+ {
+ if (state->increasing)
+ {
+ ChipLogProgress(Zcl, "Volume UP");
+ // TODO: Insert your code here to send volume up command
+ }
+ else
+ {
+ ChipLogProgress(Zcl, "Volume DOWN");
+ // TODO: Insert your code here to send volume down command
+ }
+ }
+ status = emberAfWriteServerAttribute(endpoint, ZCL_LEVEL_CONTROL_CLUSTER_ID, ZCL_CURRENT_LEVEL_ATTRIBUTE_ID,
+ (uint8_t *) ¤tLevel, ZCL_INT8U_ATTRIBUTE_TYPE);
+ state->storedLevel = currentLevel;
+ ChipLogProgress(Zcl, "Setting volume to new level %d", state->storedLevel);
+ }
+
+send_default_response:
+ if (emberAfCurrentCommand()->apsFrame->clusterId == ZCL_LEVEL_CONTROL_CLUSTER_ID)
+ {
+ emberAfSendImmediateDefaultResponse(status);
+ }
+}
+
+bool emberAfLevelControlClusterStepCallback(uint8_t stepMode, uint8_t stepSize, uint16_t transitionTime, uint8_t optionMask,
+ uint8_t optionOverride)
+{
+ stepHandler(ZCL_STEP_COMMAND_ID, stepMode, stepSize, transitionTime, optionMask, optionOverride);
+ return true;
+}
+
+bool emberAfLevelControlClusterMoveCallback(unsigned char, unsigned char, unsigned char, unsigned char)
+{
+ ChipLogProgress(Zcl, "Not supported");
+ return true;
+}
+
+bool emberAfLevelControlClusterMoveToLevelCallback(unsigned char, unsigned short, unsigned char, unsigned char)
+{
+ ChipLogProgress(Zcl, "Not supported");
+ return true;
+}
+
+bool emberAfLevelControlClusterMoveToLevelWithOnOffCallback(unsigned char, unsigned short)
+{
+ ChipLogProgress(Zcl, "Not supported");
+ return true;
+}
+
+bool emberAfLevelControlClusterMoveWithOnOffCallback(unsigned char, unsigned char)
+{
+ ChipLogProgress(Zcl, "Not supported");
+ return true;
+}
+
+bool emberAfLevelControlClusterStopCallback(unsigned char, unsigned char)
+{
+ ChipLogProgress(Zcl, "Not supported");
+ return true;
+}
+
+bool emberAfLevelControlClusterStopWithOnOffCallback()
+{
+ ChipLogProgress(Zcl, "Not supported");
+ return true;
+}
+
+bool emberAfOnOffClusterLevelControlEffectCallback(unsigned char, bool)
+{
+ ChipLogProgress(Zcl, "Not supported");
+ return true;
+}
+
+bool emberAfLevelControlClusterServerInitCallback(unsigned char)
+{
+ ChipLogProgress(Zcl, "Not supported");
+ return true;
+}
+
+bool emberAfLevelControlClusterStepWithOnOffCallback(unsigned char, unsigned char, unsigned short)
+{
+ ChipLogProgress(Zcl, "Not supported");
+ return true;
+}
+
+bool emberAfLevelControlClusterServerTickCallback(unsigned char)
+{
+ ChipLogProgress(Zcl, "Not supported");
+ return true;
+}
diff --git a/examples/tv-app/android/include/low-power/LowPowerManager.cpp b/examples/tv-app/android/include/low-power/LowPowerManager.cpp
new file mode 100644
index 0000000..97016d4
--- /dev/null
+++ b/examples/tv-app/android/include/low-power/LowPowerManager.cpp
@@ -0,0 +1,25 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "LowPowerManager.h"
+
+bool lowPowerClusterSleep()
+{
+ // TODO: Insert code here
+ return true;
+}
diff --git a/examples/tv-app/android/include/low-power/LowPowerManager.h b/examples/tv-app/android/include/low-power/LowPowerManager.h
new file mode 100644
index 0000000..75d500c
--- /dev/null
+++ b/examples/tv-app/android/include/low-power/LowPowerManager.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <lib/core/CHIPError.h>
+
+class LowPowerManager
+{
+public:
+};
diff --git a/examples/tv-app/android/include/media-input/MediaInputManager.cpp b/examples/tv-app/android/include/media-input/MediaInputManager.cpp
new file mode 100644
index 0000000..bb8dbf2
--- /dev/null
+++ b/examples/tv-app/android/include/media-input/MediaInputManager.cpp
@@ -0,0 +1,80 @@
+/**
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "MediaInputManager.h"
+
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app/util/af.h>
+#include <lib/core/CHIPSafeCasts.h>
+#include <lib/support/CodeUtils.h>
+#include <map>
+#include <string>
+
+CHIP_ERROR MediaInputManager::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ // TODO: Store feature map once it is supported
+ std::map<std::string, bool> featureMap;
+ featureMap["NU"] = true;
+ SuccessOrExit(err);
+exit:
+ return err;
+}
+
+CHIP_ERROR MediaInputManager::proxyGetInputList(chip::app::AttributeValueEncoder & aEncoder)
+{
+ return aEncoder.EncodeList([](const chip::app::TagBoundEncoder & encoder) -> CHIP_ERROR {
+ // TODO: Insert code here
+ int maximumVectorSize = 2;
+ char description[] = "exampleDescription";
+ char name[] = "exampleName";
+
+ for (int i = 0; i < maximumVectorSize; ++i)
+ {
+ chip::app::Clusters::MediaInput::Structs::MediaInputInfo::Type mediaInput;
+ mediaInput.description = chip::CharSpan(description, sizeof(description) - 1);
+ mediaInput.name = chip::CharSpan(name, sizeof(name) - 1);
+ mediaInput.inputType = EMBER_ZCL_MEDIA_INPUT_TYPE_HDMI;
+ mediaInput.index = static_cast<uint8_t>(1 + i);
+ ReturnErrorOnFailure(encoder.Encode(mediaInput));
+ }
+
+ return CHIP_NO_ERROR;
+ });
+}
+
+bool mediaInputClusterSelectInput(uint8_t input)
+{
+ // TODO: Insert code here
+ return true;
+}
+bool mediaInputClusterShowInputStatus()
+{
+ // TODO: Insert code here
+ return true;
+}
+bool mediaInputClusterHideInputStatus()
+{
+ // TODO: Insert code here
+ return true;
+}
+bool mediaInputClusterRenameInput(uint8_t input, std::string name)
+{
+ // TODO: Insert code here
+ return true;
+}
diff --git a/examples/tv-app/android/include/media-input/MediaInputManager.h b/examples/tv-app/android/include/media-input/MediaInputManager.h
new file mode 100644
index 0000000..6a88c3b
--- /dev/null
+++ b/examples/tv-app/android/include/media-input/MediaInputManager.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app/AttributeAccessInterface.h>
+
+#include <lib/core/CHIPError.h>
+#include <string>
+#include <vector>
+
+class MediaInputManager
+{
+public:
+ CHIP_ERROR Init();
+ CHIP_ERROR proxyGetInputList(chip::app::AttributeValueEncoder & aEncoder);
+};
diff --git a/examples/tv-app/android/include/media-playback/MediaPlaybackManager.cpp b/examples/tv-app/android/include/media-playback/MediaPlaybackManager.cpp
new file mode 100644
index 0000000..3146f0c
--- /dev/null
+++ b/examples/tv-app/android/include/media-playback/MediaPlaybackManager.cpp
@@ -0,0 +1,79 @@
+/**
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "MediaPlaybackManager.h"
+#include <app/Command.h>
+#include <app/util/af.h>
+#include <iostream>
+
+#include <map>
+#include <string>
+
+using namespace std;
+
+CHIP_ERROR MediaPlaybackManager::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ // TODO: Store feature map once it is supported
+ map<string, bool> featureMap;
+ featureMap["AS"] = true;
+
+ SuccessOrExit(err);
+exit:
+ return err;
+}
+
+EmberAfMediaPlaybackStatus MediaPlaybackManager::proxyMediaPlaybackRequest(MediaPlaybackRequest mediaPlaybackRequest,
+ uint64_t deltaPositionMilliseconds)
+{
+ switch (mediaPlaybackRequest)
+ {
+ case MEDIA_PLAYBACK_REQUEST_PLAY:
+ // TODO: Insert code here
+ case MEDIA_PLAYBACK_REQUEST_PAUSE:
+ // TODO: Insert code here
+ case MEDIA_PLAYBACK_REQUEST_STOP:
+ // TODO: Insert code here
+ case MEDIA_PLAYBACK_REQUEST_START_OVER:
+ // TODO: Insert code here
+ case MEDIA_PLAYBACK_REQUEST_PREVIOUS:
+ // TODO: Insert code here
+ case MEDIA_PLAYBACK_REQUEST_NEXT:
+ // TODO: Insert code here
+ case MEDIA_PLAYBACK_REQUEST_REWIND:
+ // TODO: Insert code here
+ case MEDIA_PLAYBACK_REQUEST_FAST_FORWARD:
+ // TODO: Insert code here
+ case MEDIA_PLAYBACK_REQUEST_SKIP_FORWARD:
+ // TODO: Insert code here
+ case MEDIA_PLAYBACK_REQUEST_SKIP_BACKWARD:
+ // TODO: Insert code here
+ case MEDIA_PLAYBACK_REQUEST_SEEK:
+ return EMBER_ZCL_MEDIA_PLAYBACK_STATUS_SUCCESS;
+ break;
+ default: {
+ return EMBER_ZCL_MEDIA_PLAYBACK_STATUS_SUCCESS;
+ }
+ }
+}
+
+EmberAfMediaPlaybackStatus mediaPlaybackClusterSendMediaPlaybackRequest(MediaPlaybackRequest mediaPlaybackRequest,
+ uint64_t deltaPositionMilliseconds)
+{
+ return MediaPlaybackManager().proxyMediaPlaybackRequest(mediaPlaybackRequest, deltaPositionMilliseconds);
+}
diff --git a/examples/tv-app/android/include/media-playback/MediaPlaybackManager.h b/examples/tv-app/android/include/media-playback/MediaPlaybackManager.h
new file mode 100644
index 0000000..e90601e
--- /dev/null
+++ b/examples/tv-app/android/include/media-playback/MediaPlaybackManager.h
@@ -0,0 +1,37 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app-common/zap-generated/enums.h>
+#include <app/clusters/media-playback-server/media-playback-server.h>
+#include <app/util/af-types.h>
+
+#include <lib/core/CHIPError.h>
+
+class MediaPlaybackManager
+{
+public:
+ CHIP_ERROR Init();
+ void storeNewPlaybackState(chip::EndpointId endpoint, uint8_t newPlaybackState);
+ EmberAfMediaPlaybackStatus proxyMediaPlaybackRequest(MediaPlaybackRequest mediaPlaybackRequest,
+ uint64_t deltaPositionMilliseconds);
+
+private:
+ uint8_t oldPlaybackState;
+};
diff --git a/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.cpp b/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.cpp
new file mode 100644
index 0000000..bb15476
--- /dev/null
+++ b/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.cpp
@@ -0,0 +1,66 @@
+/**
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "TargetNavigatorManager.h"
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app/clusters/target-navigator-server/target-navigator-server.h>
+#include <app/util/af.h>
+#include <app/util/basic-types.h>
+#include <lib/core/CHIPSafeCasts.h>
+#include <lib/support/CodeUtils.h>
+
+#include <map>
+#include <string>
+
+using namespace std;
+
+CHIP_ERROR TargetNavigatorManager::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ SuccessOrExit(err);
+exit:
+ return err;
+}
+
+CHIP_ERROR TargetNavigatorManager::proxyGetTargetInfoList(chip::app::AttributeValueEncoder & aEncoder)
+{
+ return aEncoder.EncodeList([](const chip::app::TagBoundEncoder & encoder) -> CHIP_ERROR {
+ // TODO: Insert code here
+ int maximumVectorSize = 2;
+ char name[] = "exampleName";
+
+ for (int i = 0; i < maximumVectorSize; ++i)
+ {
+ chip::app::Clusters::TargetNavigator::Structs::NavigateTargetTargetInfo::Type targetInfo;
+ targetInfo.name = chip::CharSpan(name, sizeof(name) - 1);
+ targetInfo.identifier = static_cast<uint8_t>(1 + i);
+ ReturnErrorOnFailure(encoder.Encode(targetInfo));
+ }
+ return CHIP_NO_ERROR;
+ });
+}
+
+TargetNavigatorResponse targetNavigatorClusterNavigateTarget(uint8_t target, std::string data)
+{
+ // TODO: Insert code here
+ TargetNavigatorResponse response;
+ const char * testData = "data response";
+ response.data = (uint8_t *) testData;
+ response.status = EMBER_ZCL_APPLICATION_LAUNCHER_STATUS_SUCCESS;
+ return response;
+}
diff --git a/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.h b/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.h
new file mode 100644
index 0000000..2aa6046
--- /dev/null
+++ b/examples/tv-app/android/include/target-navigator/TargetNavigatorManager.h
@@ -0,0 +1,31 @@
+/**
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app/AttributeAccessInterface.h>
+
+#include <lib/core/CHIPError.h>
+#include <string>
+#include <vector>
+
+class TargetNavigatorManager
+{
+public:
+ CHIP_ERROR Init();
+ CHIP_ERROR proxyGetTargetInfoList(chip::app::AttributeValueEncoder & aEncoder);
+};
diff --git a/examples/tv-app/android/include/tv-channel/TvChannelManager.cpp b/examples/tv-app/android/include/tv-channel/TvChannelManager.cpp
new file mode 100644
index 0000000..5d5a1ea
--- /dev/null
+++ b/examples/tv-app/android/include/tv-channel/TvChannelManager.cpp
@@ -0,0 +1,84 @@
+/**
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "TvChannelManager.h"
+#include <app-common/zap-generated/af-structs.h>
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app/util/af.h>
+#include <app/util/attribute-storage.h>
+#include <lib/core/CHIPSafeCasts.h>
+#include <lib/support/CodeUtils.h>
+#include <lib/support/logging/CHIPLogging.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+using namespace chip;
+
+CHIP_ERROR TvChannelManager::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ // TODO: Store feature map once it is supported
+ std::map<std::string, bool> featureMap;
+ featureMap["CL"] = true;
+ featureMap["LI"] = true;
+
+ SuccessOrExit(err);
+exit:
+ return err;
+}
+
+CHIP_ERROR TvChannelManager::proxyGetTvChannelList(chip::app::AttributeValueEncoder & aEncoder)
+{
+ return aEncoder.EncodeList([](const chip::app::TagBoundEncoder & encoder) -> CHIP_ERROR {
+ // TODO: Insert code here
+ int maximumVectorSize = 2;
+ char affiliateCallSign[] = "exampleASign";
+ char callSign[] = "exampleCSign";
+ char name[] = "exampleName";
+
+ for (int i = 0; i < maximumVectorSize; ++i)
+ {
+ chip::app::Clusters::TvChannel::Structs::TvChannelInfo::Type channelInfo;
+ channelInfo.affiliateCallSign = CharSpan(affiliateCallSign, sizeof(affiliateCallSign) - 1);
+ channelInfo.callSign = CharSpan(callSign, sizeof(callSign) - 1);
+ channelInfo.name = CharSpan(name, sizeof(name) - 1);
+ channelInfo.majorNumber = static_cast<uint8_t>(1 + i);
+ channelInfo.minorNumber = static_cast<uint16_t>(2 + i);
+ ReturnErrorOnFailure(encoder.Encode(channelInfo));
+ }
+ return CHIP_NO_ERROR;
+ });
+}
+
+TvChannelInfo tvChannelClusterChangeChannel(std::string match)
+{
+ // TODO: Insert code here
+ TvChannelInfo channel = {};
+ return channel;
+}
+bool tvChannelClusterChangeChannelByNumber(uint16_t majorNumber, uint16_t minorNumber)
+{
+ // TODO: Insert code here
+ return true;
+}
+bool tvChannelClusterSkipChannel(uint16_t count)
+{
+ // TODO: Insert code here
+ return true;
+}
diff --git a/examples/tv-app/android/include/tv-channel/TvChannelManager.h b/examples/tv-app/android/include/tv-channel/TvChannelManager.h
new file mode 100644
index 0000000..aaf78b8
--- /dev/null
+++ b/examples/tv-app/android/include/tv-channel/TvChannelManager.h
@@ -0,0 +1,31 @@
+/**
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app/AttributeAccessInterface.h>
+
+#include <lib/core/CHIPError.h>
+#include <string>
+#include <vector>
+
+class TvChannelManager
+{
+public:
+ CHIP_ERROR Init();
+ CHIP_ERROR proxyGetTvChannelList(chip::app::AttributeValueEncoder & aEncoder);
+};
diff --git a/examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.cpp b/examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.cpp
new file mode 100644
index 0000000..3072b0e
--- /dev/null
+++ b/examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.cpp
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "WakeOnLanManager.h"
+
+#include <app-common/zap-generated/attribute-type.h>
+#include <app-common/zap-generated/ids/Attributes.h>
+#include <app-common/zap-generated/ids/Clusters.h>
+#include <app/util/af.h>
+#include <app/util/attribute-storage.h>
+#include <app/util/basic-types.h>
+#include <lib/support/ZclString.h>
+
+#include <inipp/inipp.h>
+
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+using namespace chip;
+using namespace chip::app::Clusters;
+
+CHIP_ERROR WakeOnLanManager::Init()
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ EndpointConfigurationStorage & endpointConfiguration = EndpointConfigurationStorage::GetInstance();
+ err = endpointConfiguration.Init();
+ SuccessOrExit(err);
+ es = &endpointConfiguration;
+exit:
+ return err;
+}
+
+void WakeOnLanManager::store(chip::EndpointId endpoint, char macAddress[32])
+{
+ uint8_t bufferMemory[32];
+ MutableByteSpan zclString(bufferMemory);
+ MakeZclCharString(zclString, macAddress);
+ EmberAfStatus macAddressStatus = emberAfWriteServerAttribute(
+ endpoint, WakeOnLan::Id, WakeOnLan::Attributes::WakeOnLanMacAddress::Id, zclString.data(), ZCL_CHAR_STRING_ATTRIBUTE_TYPE);
+ if (macAddressStatus != EMBER_ZCL_STATUS_SUCCESS)
+ {
+ ChipLogError(Zcl, "Failed to store mac address attribute.");
+ }
+}
+
+void WakeOnLanManager::setMacAddress(chip::EndpointId endpoint, char * macAddress)
+{
+ char address[18];
+ uint16_t size = static_cast<uint16_t>(sizeof(address));
+
+ std::string section = "endpoint" + std::to_string(endpoint);
+ CHIP_ERROR err = es->get(section, "macAddress", macAddress, size);
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogError(Zcl, "Failed to get mac address. Error:%s", chip::ErrorStr(err));
+ }
+}
diff --git a/examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.h b/examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.h
new file mode 100644
index 0000000..2f0cca3
--- /dev/null
+++ b/examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+
+#include <app/util/af-types.h>
+#include <lib/core/CHIPError.h>
+
+#include "../endpoint-configuration/EndpointConfigurationStorage.h"
+
+class WakeOnLanManager
+{
+public:
+ CHIP_ERROR Init();
+ void store(chip::EndpointId endpoint, char macAddress[32]);
+ void setMacAddress(chip::EndpointId endpoint, char * macAddress);
+
+ static WakeOnLanManager & GetInstance()
+ {
+ static WakeOnLanManager instance;
+ return instance;
+ }
+
+private:
+ EndpointConfigurationStorage * es = nullptr;
+};
diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py
index c11fe42..d839e7c 100644
--- a/scripts/build/build/targets.py
+++ b/scripts/build/build/targets.py
@@ -190,6 +190,7 @@
yield target.Extend('androidstudio-arm64-chip-tool', board=AndroidBoard.AndroidStudio_ARM64, app=AndroidApp.CHIP_TOOL)
yield target.Extend('androidstudio-x86-chip-tool', board=AndroidBoard.AndroidStudio_X86, app=AndroidApp.CHIP_TOOL)
yield target.Extend('androidstudio-x64-chip-tool', board=AndroidBoard.AndroidStudio_X64, app=AndroidApp.CHIP_TOOL)
+ yield target.Extend('arm64-chip-tvserver', board=AndroidBoard.ARM64, app=AndroidApp.CHIP_TVServer)
def MbedTargets():
diff --git a/scripts/build/builders/android.py b/scripts/build/builders/android.py
index cc2901b..74d47e4 100644
--- a/scripts/build/builders/android.py
+++ b/scripts/build/builders/android.py
@@ -65,15 +65,24 @@
class AndroidApp(Enum):
CHIP_TOOL = auto()
CHIP_TEST = auto()
+ CHIP_TVServer = auto()
def AppName(self):
if self == AndroidApp.CHIP_TOOL:
return "CHIPTool"
elif self == AndroidApp.CHIP_TEST:
return "CHIPTest"
+ elif self == AndroidApp.CHIP_TVServer:
+ return "CHIPTVServer"
else:
raise Exception('Unknown app type: %r' % self)
+ def AppGnArgs(self):
+ gn_args = {}
+ if self == AndroidApp.CHIP_TVServer:
+ gn_args['chip_config_network_layer_ble'] = False
+ return gn_args
+
class AndroidBuilder(Builder):
@@ -130,12 +139,19 @@
gn_args['target_cpu'] = self.board.TargetCpuName()
gn_args['android_ndk_root'] = os.environ['ANDROID_NDK_HOME']
gn_args['android_sdk_root'] = os.environ['ANDROID_HOME']
- gn_args['chip_use_clusters_for_ip_commissioning'] = 'true'
+ gn_args['chip_use_clusters_for_ip_commissioning'] = True
+ gn_args.update(self.app.AppGnArgs())
- args = '--args=%s' % (' '.join([
- '%s="%s"' % (key, shlex.quote(value))
- for key, value in gn_args.items()
- ]))
+ args_str = ""
+ for key, value in gn_args.items():
+ if type(value) == bool:
+ if value:
+ args_str += '%s=true ' % (key)
+ else:
+ args_str += '%s=false ' % (key)
+ else:
+ args_str += '%s="%s" ' % (key, shlex.quote(value))
+ args = '--args=%s' % (args_str)
gn_gen = [
'gn', 'gen', '--check', '--fail-on-unused-args', self.output_dir, args,
@@ -193,16 +209,17 @@
#
# If we unify the JNI libraries, libc++_shared.so may not be needed anymore, which could
# be another path of resolving this inconsistency.
- for libName in ['libSetupPayloadParser.so', 'libCHIPController.so', 'libc++_shared.so']:
+ for libName in ['libSetupPayloadParser.so', 'libCHIPController.so', 'libc++_shared.so', 'libCHIPAppServer.so']:
self._Execute(['cp', os.path.join(self.output_dir, 'lib', 'jni', self.board.AbiName(
), libName), os.path.join(jnilibs_dir, libName)])
jars = {
'CHIPController.jar': 'src/controller/java/CHIPController.jar',
'SetupPayloadParser.jar': 'src/setup_payload/java/SetupPayloadParser.jar',
- 'AndroidPlatform.jar': 'src/platform/android/AndroidPlatform.jar'
-
+ 'AndroidPlatform.jar': 'src/platform/android/AndroidPlatform.jar',
+ 'CHIPAppServer.jar': 'src/app/server/java/CHIPAppServer.jar',
}
+
for jarName in jars.keys():
self._Execute(['cp', os.path.join(
self.output_dir, 'lib', jars[jarName]), os.path.join(libs_dir, jarName)])
diff --git a/scripts/build/testdata/all_targets_except_host.txt b/scripts/build/testdata/all_targets_except_host.txt
index 03c247d..275483b 100644
--- a/scripts/build/testdata/all_targets_except_host.txt
+++ b/scripts/build/testdata/all_targets_except_host.txt
@@ -6,6 +6,7 @@
android-arm-chip-tool
android-arm64-chip-test
android-arm64-chip-tool
+android-arm64-chip-tvserver
android-x64-chip-tool
android-x86-chip-tool
efr32-brd4161a-light
diff --git a/scripts/build/testdata/build_all_except_host.txt b/scripts/build/testdata/build_all_except_host.txt
index 3f785fb..182bc63 100644
--- a/scripts/build/testdata/build_all_except_host.txt
+++ b/scripts/build/testdata/build_all_except_host.txt
@@ -11,7 +11,7 @@
python3 third_party/android_deps/set_up_android_deps.py
# Generating android-androidstudio-arm-chip-tool
-gn gen --check --fail-on-unused-args {out}/android-androidstudio-arm-chip-tool '--args=target_os="android" target_cpu="arm" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"' --ide=json --json-ide-script=//scripts/examples/gn_to_cmakelists.py
+gn gen --check --fail-on-unused-args {out}/android-androidstudio-arm-chip-tool '--args=target_os="android" target_cpu="arm" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning=true ' --ide=json --json-ide-script=//scripts/examples/gn_to_cmakelists.py
# Accepting NDK licenses
bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null'
@@ -23,7 +23,7 @@
python3 third_party/android_deps/set_up_android_deps.py
# Generating android-androidstudio-arm64-chip-tool
-gn gen --check --fail-on-unused-args {out}/android-androidstudio-arm64-chip-tool '--args=target_os="android" target_cpu="arm64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"' --ide=json --json-ide-script=//scripts/examples/gn_to_cmakelists.py
+gn gen --check --fail-on-unused-args {out}/android-androidstudio-arm64-chip-tool '--args=target_os="android" target_cpu="arm64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning=true ' --ide=json --json-ide-script=//scripts/examples/gn_to_cmakelists.py
# Accepting NDK licenses
bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null'
@@ -35,7 +35,7 @@
python3 third_party/android_deps/set_up_android_deps.py
# Generating android-androidstudio-x64-chip-tool
-gn gen --check --fail-on-unused-args {out}/android-androidstudio-x64-chip-tool '--args=target_os="android" target_cpu="x64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"' --ide=json --json-ide-script=//scripts/examples/gn_to_cmakelists.py
+gn gen --check --fail-on-unused-args {out}/android-androidstudio-x64-chip-tool '--args=target_os="android" target_cpu="x64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning=true ' --ide=json --json-ide-script=//scripts/examples/gn_to_cmakelists.py
# Accepting NDK licenses
bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null'
@@ -47,7 +47,7 @@
python3 third_party/android_deps/set_up_android_deps.py
# Generating android-androidstudio-x86-chip-tool
-gn gen --check --fail-on-unused-args {out}/android-androidstudio-x86-chip-tool '--args=target_os="android" target_cpu="x86" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"' --ide=json --json-ide-script=//scripts/examples/gn_to_cmakelists.py
+gn gen --check --fail-on-unused-args {out}/android-androidstudio-x86-chip-tool '--args=target_os="android" target_cpu="x86" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning=true ' --ide=json --json-ide-script=//scripts/examples/gn_to_cmakelists.py
# Accepting NDK licenses
bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null'
@@ -59,7 +59,7 @@
python3 third_party/android_deps/set_up_android_deps.py
# Generating android-arm-chip-tool
-gn gen --check --fail-on-unused-args {out}/android-arm-chip-tool '--args=target_os="android" target_cpu="arm" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"'
+gn gen --check --fail-on-unused-args {out}/android-arm-chip-tool '--args=target_os="android" target_cpu="arm" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning=true '
# Accepting NDK licenses
bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null'
@@ -71,7 +71,7 @@
python3 third_party/android_deps/set_up_android_deps.py
# Generating android-arm64-chip-test
-gn gen --check --fail-on-unused-args {out}/android-arm64-chip-test '--args=target_os="android" target_cpu="arm64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"'
+gn gen --check --fail-on-unused-args {out}/android-arm64-chip-test '--args=target_os="android" target_cpu="arm64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning=true '
# Accepting NDK licenses
bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null'
@@ -83,7 +83,19 @@
python3 third_party/android_deps/set_up_android_deps.py
# Generating android-arm64-chip-tool
-gn gen --check --fail-on-unused-args {out}/android-arm64-chip-tool '--args=target_os="android" target_cpu="arm64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"'
+gn gen --check --fail-on-unused-args {out}/android-arm64-chip-tool '--args=target_os="android" target_cpu="arm64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning=true '
+
+# Accepting NDK licenses
+bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null'
+
+# Generating JARs for Java build rules test
+python3 build/chip/java/tests/generate_jars_for_test.py
+
+# Setting up Android deps through Gradle
+python3 third_party/android_deps/set_up_android_deps.py
+
+# Generating android-arm64-chip-tvserver
+gn gen --check --fail-on-unused-args {out}/android-arm64-chip-tvserver '--args=target_os="android" target_cpu="arm64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning=true chip_config_network_layer_ble=false '
# Accepting NDK licenses
bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null'
@@ -95,7 +107,7 @@
python3 third_party/android_deps/set_up_android_deps.py
# Generating android-x64-chip-tool
-gn gen --check --fail-on-unused-args {out}/android-x64-chip-tool '--args=target_os="android" target_cpu="x64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"'
+gn gen --check --fail-on-unused-args {out}/android-x64-chip-tool '--args=target_os="android" target_cpu="x64" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning=true '
# Accepting NDK licenses
bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null'
@@ -107,7 +119,7 @@
python3 third_party/android_deps/set_up_android_deps.py
# Generating android-x86-chip-tool
-gn gen --check --fail-on-unused-args {out}/android-x86-chip-tool '--args=target_os="android" target_cpu="x86" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning="true"'
+gn gen --check --fail-on-unused-args {out}/android-x86-chip-tool '--args=target_os="android" target_cpu="x86" android_ndk_root="TEST_ANDROID_NDK_HOME" android_sdk_root="TEST_ANDROID_HOME" chip_use_clusters_for_ip_commissioning=true '
# Accepting NDK licenses
bash -c 'yes | TEST_ANDROID_HOME/tools/bin/sdkmanager --licenses >/dev/null'
@@ -444,12 +456,16 @@
cp {out}/android-arm-chip-tool/lib/jni/armeabi-v7a/libc++_shared.so {root}/src/android/CHIPTool/app/libs/jniLibs/armeabi-v7a/libc++_shared.so
+cp {out}/android-arm-chip-tool/lib/jni/armeabi-v7a/libCHIPAppServer.so {root}/src/android/CHIPTool/app/libs/jniLibs/armeabi-v7a/libCHIPAppServer.so
+
cp {out}/android-arm-chip-tool/lib/src/controller/java/CHIPController.jar {root}/src/android/CHIPTool/app/libs/CHIPController.jar
cp {out}/android-arm-chip-tool/lib/src/setup_payload/java/SetupPayloadParser.jar {root}/src/android/CHIPTool/app/libs/SetupPayloadParser.jar
cp {out}/android-arm-chip-tool/lib/src/platform/android/AndroidPlatform.jar {root}/src/android/CHIPTool/app/libs/AndroidPlatform.jar
+cp {out}/android-arm-chip-tool/lib/src/app/server/java/CHIPAppServer.jar {root}/src/android/CHIPTool/app/libs/CHIPAppServer.jar
+
# Building APP android-arm-chip-tool
{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PmatterBuildSrcDir={out}/android-arm-chip-tool -PmatterSdkSourceBuild=false -PbuildDir={out}/android-arm-chip-tool assembleDebug
@@ -465,12 +481,16 @@
cp {out}/android-arm64-chip-test/lib/jni/arm64-v8a/libc++_shared.so {root}/src/android/CHIPTest/app/libs/jniLibs/arm64-v8a/libc++_shared.so
+cp {out}/android-arm64-chip-test/lib/jni/arm64-v8a/libCHIPAppServer.so {root}/src/android/CHIPTest/app/libs/jniLibs/arm64-v8a/libCHIPAppServer.so
+
cp {out}/android-arm64-chip-test/lib/src/controller/java/CHIPController.jar {root}/src/android/CHIPTest/app/libs/CHIPController.jar
cp {out}/android-arm64-chip-test/lib/src/setup_payload/java/SetupPayloadParser.jar {root}/src/android/CHIPTest/app/libs/SetupPayloadParser.jar
cp {out}/android-arm64-chip-test/lib/src/platform/android/AndroidPlatform.jar {root}/src/android/CHIPTest/app/libs/AndroidPlatform.jar
+cp {out}/android-arm64-chip-test/lib/src/app/server/java/CHIPAppServer.jar {root}/src/android/CHIPTest/app/libs/CHIPAppServer.jar
+
# Building APP android-arm64-chip-test
{root}/src/android/CHIPTest/gradlew -p {root}/src/android/CHIPTest -PmatterBuildSrcDir={out}/android-arm64-chip-test -PmatterSdkSourceBuild=false -PbuildDir={out}/android-arm64-chip-test assembleDebug
@@ -486,15 +506,44 @@
cp {out}/android-arm64-chip-tool/lib/jni/arm64-v8a/libc++_shared.so {root}/src/android/CHIPTool/app/libs/jniLibs/arm64-v8a/libc++_shared.so
+cp {out}/android-arm64-chip-tool/lib/jni/arm64-v8a/libCHIPAppServer.so {root}/src/android/CHIPTool/app/libs/jniLibs/arm64-v8a/libCHIPAppServer.so
+
cp {out}/android-arm64-chip-tool/lib/src/controller/java/CHIPController.jar {root}/src/android/CHIPTool/app/libs/CHIPController.jar
cp {out}/android-arm64-chip-tool/lib/src/setup_payload/java/SetupPayloadParser.jar {root}/src/android/CHIPTool/app/libs/SetupPayloadParser.jar
cp {out}/android-arm64-chip-tool/lib/src/platform/android/AndroidPlatform.jar {root}/src/android/CHIPTool/app/libs/AndroidPlatform.jar
+cp {out}/android-arm64-chip-tool/lib/src/app/server/java/CHIPAppServer.jar {root}/src/android/CHIPTool/app/libs/CHIPAppServer.jar
+
# Building APP android-arm64-chip-tool
{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PmatterBuildSrcDir={out}/android-arm64-chip-tool -PmatterSdkSourceBuild=false -PbuildDir={out}/android-arm64-chip-tool assembleDebug
+# Building JNI android-arm64-chip-tvserver
+ninja -C {out}/android-arm64-chip-tvserver
+
+# Prepare Native libs android-arm64-chip-tvserver
+mkdir -p {root}/src/android/CHIPTVServer/app/libs/jniLibs/arm64-v8a
+
+cp {out}/android-arm64-chip-tvserver/lib/jni/arm64-v8a/libSetupPayloadParser.so {root}/src/android/CHIPTVServer/app/libs/jniLibs/arm64-v8a/libSetupPayloadParser.so
+
+cp {out}/android-arm64-chip-tvserver/lib/jni/arm64-v8a/libCHIPController.so {root}/src/android/CHIPTVServer/app/libs/jniLibs/arm64-v8a/libCHIPController.so
+
+cp {out}/android-arm64-chip-tvserver/lib/jni/arm64-v8a/libc++_shared.so {root}/src/android/CHIPTVServer/app/libs/jniLibs/arm64-v8a/libc++_shared.so
+
+cp {out}/android-arm64-chip-tvserver/lib/jni/arm64-v8a/libCHIPAppServer.so {root}/src/android/CHIPTVServer/app/libs/jniLibs/arm64-v8a/libCHIPAppServer.so
+
+cp {out}/android-arm64-chip-tvserver/lib/src/controller/java/CHIPController.jar {root}/src/android/CHIPTVServer/app/libs/CHIPController.jar
+
+cp {out}/android-arm64-chip-tvserver/lib/src/setup_payload/java/SetupPayloadParser.jar {root}/src/android/CHIPTVServer/app/libs/SetupPayloadParser.jar
+
+cp {out}/android-arm64-chip-tvserver/lib/src/platform/android/AndroidPlatform.jar {root}/src/android/CHIPTVServer/app/libs/AndroidPlatform.jar
+
+cp {out}/android-arm64-chip-tvserver/lib/src/app/server/java/CHIPAppServer.jar {root}/src/android/CHIPTVServer/app/libs/CHIPAppServer.jar
+
+# Building APP android-arm64-chip-tvserver
+{root}/src/android/CHIPTVServer/gradlew -p {root}/src/android/CHIPTVServer -PmatterBuildSrcDir={out}/android-arm64-chip-tvserver -PmatterSdkSourceBuild=false -PbuildDir={out}/android-arm64-chip-tvserver assembleDebug
+
# Building JNI android-x64-chip-tool
ninja -C {out}/android-x64-chip-tool
@@ -507,12 +556,16 @@
cp {out}/android-x64-chip-tool/lib/jni/x86_64/libc++_shared.so {root}/src/android/CHIPTool/app/libs/jniLibs/x86_64/libc++_shared.so
+cp {out}/android-x64-chip-tool/lib/jni/x86_64/libCHIPAppServer.so {root}/src/android/CHIPTool/app/libs/jniLibs/x86_64/libCHIPAppServer.so
+
cp {out}/android-x64-chip-tool/lib/src/controller/java/CHIPController.jar {root}/src/android/CHIPTool/app/libs/CHIPController.jar
cp {out}/android-x64-chip-tool/lib/src/setup_payload/java/SetupPayloadParser.jar {root}/src/android/CHIPTool/app/libs/SetupPayloadParser.jar
cp {out}/android-x64-chip-tool/lib/src/platform/android/AndroidPlatform.jar {root}/src/android/CHIPTool/app/libs/AndroidPlatform.jar
+cp {out}/android-x64-chip-tool/lib/src/app/server/java/CHIPAppServer.jar {root}/src/android/CHIPTool/app/libs/CHIPAppServer.jar
+
# Building APP android-x64-chip-tool
{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PmatterBuildSrcDir={out}/android-x64-chip-tool -PmatterSdkSourceBuild=false -PbuildDir={out}/android-x64-chip-tool assembleDebug
@@ -528,12 +581,16 @@
cp {out}/android-x86-chip-tool/lib/jni/x86/libc++_shared.so {root}/src/android/CHIPTool/app/libs/jniLibs/x86/libc++_shared.so
+cp {out}/android-x86-chip-tool/lib/jni/x86/libCHIPAppServer.so {root}/src/android/CHIPTool/app/libs/jniLibs/x86/libCHIPAppServer.so
+
cp {out}/android-x86-chip-tool/lib/src/controller/java/CHIPController.jar {root}/src/android/CHIPTool/app/libs/CHIPController.jar
cp {out}/android-x86-chip-tool/lib/src/setup_payload/java/SetupPayloadParser.jar {root}/src/android/CHIPTool/app/libs/SetupPayloadParser.jar
cp {out}/android-x86-chip-tool/lib/src/platform/android/AndroidPlatform.jar {root}/src/android/CHIPTool/app/libs/AndroidPlatform.jar
+cp {out}/android-x86-chip-tool/lib/src/app/server/java/CHIPAppServer.jar {root}/src/android/CHIPTool/app/libs/CHIPAppServer.jar
+
# Building APP android-x86-chip-tool
{root}/src/android/CHIPTool/gradlew -p {root}/src/android/CHIPTool -PmatterBuildSrcDir={out}/android-x86-chip-tool -PmatterSdkSourceBuild=false -PbuildDir={out}/android-x86-chip-tool assembleDebug
diff --git a/scripts/build/testdata/glob_star_targets_except_host.txt b/scripts/build/testdata/glob_star_targets_except_host.txt
index a5e973a..de84e94 100644
--- a/scripts/build/testdata/glob_star_targets_except_host.txt
+++ b/scripts/build/testdata/glob_star_targets_except_host.txt
@@ -6,6 +6,7 @@
android-arm-chip-tool
android-arm64-chip-test
android-arm64-chip-tool
+android-arm64-chip-tvserver
android-x64-chip-tool
android-x86-chip-tool
efr32-brd4161a-light
diff --git a/src/android/CHIPTVServer/.gitignore b/src/android/CHIPTVServer/.gitignore
new file mode 100644
index 0000000..d59e52c
--- /dev/null
+++ b/src/android/CHIPTVServer/.gitignore
@@ -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
diff --git a/src/android/CHIPTVServer/.idea/.gitignore b/src/android/CHIPTVServer/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/src/android/CHIPTVServer/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/src/android/CHIPTVServer/.idea/compiler.xml b/src/android/CHIPTVServer/.idea/compiler.xml
new file mode 100644
index 0000000..fb7f4a8
--- /dev/null
+++ b/src/android/CHIPTVServer/.idea/compiler.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="CompilerConfiguration">
+ <bytecodeTargetLevel target="11" />
+ </component>
+</project>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/.idea/gradle.xml b/src/android/CHIPTVServer/.idea/gradle.xml
new file mode 100644
index 0000000..526b4c2
--- /dev/null
+++ b/src/android/CHIPTVServer/.idea/gradle.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="GradleMigrationSettings" migrationVersion="1" />
+ <component name="GradleSettings">
+ <option name="linkedExternalProjectsSettings">
+ <GradleProjectSettings>
+ <option name="testRunner" value="GRADLE" />
+ <option name="distributionType" value="DEFAULT_WRAPPED" />
+ <option name="externalProjectPath" value="$PROJECT_DIR$" />
+ <option name="modules">
+ <set>
+ <option value="$PROJECT_DIR$" />
+ <option value="$PROJECT_DIR$/app" />
+ </set>
+ </option>
+ <option name="resolveModulePerSourceSet" value="false" />
+ </GradleProjectSettings>
+ </option>
+ </component>
+</project>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/.idea/misc.xml b/src/android/CHIPTVServer/.idea/misc.xml
new file mode 100644
index 0000000..2a4d5b5
--- /dev/null
+++ b/src/android/CHIPTVServer/.idea/misc.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/build/classes" />
+ </component>
+ <component name="ProjectType">
+ <option name="id" value="Android" />
+ </component>
+</project>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/.idea/runConfigurations.xml b/src/android/CHIPTVServer/.idea/runConfigurations.xml
new file mode 100644
index 0000000..797acea
--- /dev/null
+++ b/src/android/CHIPTVServer/.idea/runConfigurations.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="RunConfigurationProducerService">
+ <option name="ignoredProducers">
+ <set>
+ <option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
+ </set>
+ </option>
+ </component>
+</project>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/.idea/vcs.xml b/src/android/CHIPTVServer/.idea/vcs.xml
new file mode 100644
index 0000000..c2365ab
--- /dev/null
+++ b/src/android/CHIPTVServer/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="VcsDirectoryMappings">
+ <mapping directory="$PROJECT_DIR$/../../.." vcs="Git" />
+ </component>
+</project>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/.gitignore b/src/android/CHIPTVServer/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/src/android/CHIPTVServer/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/build.gradle b/src/android/CHIPTVServer/app/build.gradle
new file mode 100644
index 0000000..9217e72
--- /dev/null
+++ b/src/android/CHIPTVServer/app/build.gradle
@@ -0,0 +1,56 @@
+plugins {
+ id 'com.android.application'
+}
+
+android {
+ compileSdk 30
+
+ defaultConfig {
+ applicationId "com.tcl.chip.chiptvserver"
+ minSdk 24
+ targetSdk 30
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ externalNativeBuild {
+ cmake {
+ targets "default"
+ }
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+
+ sourceSets {
+ main {
+ jniLibs.srcDirs = ['libs/jniLibs']
+ }
+ }
+
+
+
+
+}
+
+dependencies {
+ implementation fileTree(dir: "libs", include: ["*.jar","*.so"])
+ implementation 'androidx.appcompat:appcompat:1.3.1'
+ implementation 'com.google.android.material:material:1.4.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
+ implementation files('libs/AndroidPlatform.jar')
+ testImplementation 'junit:junit:4.+'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+ implementation 'com.google.zxing:core:3.3.0'
+}
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/libs/README.md b/src/android/CHIPTVServer/app/libs/README.md
new file mode 100644
index 0000000..e99f165
--- /dev/null
+++ b/src/android/CHIPTVServer/app/libs/README.md
@@ -0,0 +1,2 @@
+This directory will contain any .jar files required by the CHIPTool demo app for
+Android.
diff --git a/src/android/CHIPTVServer/app/libs/jniLibs/README.md b/src/android/CHIPTVServer/app/libs/jniLibs/README.md
new file mode 100644
index 0000000..c35dd62
--- /dev/null
+++ b/src/android/CHIPTVServer/app/libs/jniLibs/README.md
@@ -0,0 +1,3 @@
+This directory will contain .so files required by CHIPTool demo app for Android.
+The .so files must be organized into folders by the name of the corresponding
+Android architecture for which they are built, eg. arm64-v8a, x86, x86_64, etc.
diff --git a/src/android/CHIPTVServer/app/proguard-rules.pro b/src/android/CHIPTVServer/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/src/android/CHIPTVServer/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/src/androidTest/java/com/tcl/chip/chiptvserver/ExampleInstrumentedTest.java b/src/android/CHIPTVServer/app/src/androidTest/java/com/tcl/chip/chiptvserver/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..9bd1c27
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/androidTest/java/com/tcl/chip/chiptvserver/ExampleInstrumentedTest.java
@@ -0,0 +1,24 @@
+package com.tcl.chip.chiptvserver;
+
+import static org.junit.Assert.*;
+
+import android.content.Context;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.tcl.chip.chiptvslave", appContext.getPackageName());
+ }
+}
diff --git a/src/android/CHIPTVServer/app/src/main/AndroidManifest.xml b/src/android/CHIPTVServer/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..383830a
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.tcl.chip.chiptvserver">
+
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.NFC" />
+ <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
+
+ <application
+ android:allowBackup="true"
+ android:extractNativeLibs="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.CHIPTVSlave">
+ <activity android:name=".MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/src/main/java/com/tcl/chip/chiptvserver/MainActivity.java b/src/android/CHIPTVServer/app/src/main/java/com/tcl/chip/chiptvserver/MainActivity.java
new file mode 100644
index 0000000..6fcde19
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/java/com/tcl/chip/chiptvserver/MainActivity.java
@@ -0,0 +1,68 @@
+package com.tcl.chip.chiptvserver;
+
+import android.graphics.Bitmap;
+import android.os.Bundle;
+import android.widget.ImageView;
+import android.widget.TextView;
+import androidx.appcompat.app.AppCompatActivity;
+import chip.appserver.ChipAppServer;
+import chip.platform.AndroidBleManager;
+import chip.platform.AndroidChipPlatform;
+import chip.platform.ChipMdnsCallbackImpl;
+import chip.platform.NsdManagerServiceResolver;
+import chip.platform.PreferencesConfigurationManager;
+import chip.platform.PreferencesKeyValueStoreManager;
+import chip.setuppayload.DiscoveryCapability;
+import chip.setuppayload.SetupPayload;
+import chip.setuppayload.SetupPayloadParser;
+import java.util.HashSet;
+
+public class MainActivity extends AppCompatActivity {
+
+ private ImageView mQrCodeImg;
+ private TextView mQrCodeTxt;
+ private TextView mManualPairingCodeTxt;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ mQrCodeImg = findViewById(R.id.qrCodeImg);
+ mQrCodeTxt = findViewById(R.id.qrCodeTxt);
+ mManualPairingCodeTxt = findViewById(R.id.manualPairingCodeTxt);
+ ChipAppServer chipAppServer = new ChipAppServer();
+ AndroidChipPlatform chipPlatform =
+ new AndroidChipPlatform(
+ new AndroidBleManager(),
+ new PreferencesKeyValueStoreManager(this),
+ new PreferencesConfigurationManager(this),
+ new NsdManagerServiceResolver(this),
+ new ChipMdnsCallbackImpl());
+
+ // TODO: Get these parameters from PreferencesConfigurationManager
+ HashSet<DiscoveryCapability> discoveryCapabilities = new HashSet<>();
+ discoveryCapabilities.add(DiscoveryCapability.ON_NETWORK);
+ SetupPayload payload =
+ new SetupPayload(0, 9050, 65279, 0, discoveryCapabilities, 3840, 20202021);
+
+ SetupPayloadParser parser = new SetupPayloadParser();
+ try {
+ String qrCode = parser.getQrCodeFromPayload(payload);
+ mQrCodeTxt.setText(qrCode);
+
+ Bitmap qrCodeBitmap = QRUtils.createQRCodeBitmap(qrCode, 800, 800);
+ mQrCodeImg.setImageBitmap(qrCodeBitmap);
+ } catch (SetupPayloadParser.SetupPayloadException e) {
+ e.printStackTrace();
+ }
+
+ try {
+ String manualPairingCode = parser.getManualEntryCodeFromPayload(payload);
+ mManualPairingCodeTxt.setText("ManualPairingCode:" + manualPairingCode);
+ } catch (SetupPayloadParser.SetupPayloadException e) {
+ e.printStackTrace();
+ }
+
+ chipAppServer.startApp();
+ }
+}
diff --git a/src/android/CHIPTVServer/app/src/main/java/com/tcl/chip/chiptvserver/QRUtils.java b/src/android/CHIPTVServer/app/src/main/java/com/tcl/chip/chiptvserver/QRUtils.java
new file mode 100644
index 0000000..7a408c2
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/java/com/tcl/chip/chiptvserver/QRUtils.java
@@ -0,0 +1,29 @@
+package com.tcl.chip.chiptvserver;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.QRCodeWriter;
+
+public class QRUtils {
+ public static Bitmap createQRCodeBitmap(String content, int width, int height) {
+ try {
+ BitMatrix bitMatrix =
+ new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height);
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+
+ for (int y = 0; y < bitMatrix.getHeight(); y++) {
+ for (int x = 0; x < bitMatrix.getWidth(); x++) {
+ if (bitMatrix.get(x, y)) {
+ bitmap.setPixel(x, y, Color.BLACK);
+ }
+ }
+ }
+ return bitmap;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/src/android/CHIPTVServer/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/src/android/CHIPTVServer/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="85.84757"
+ android:endY="92.4963"
+ android:startX="42.9492"
+ android:startY="49.59793"
+ android:type="linear">
+ <item
+ android:color="#44000000"
+ android:offset="0.0" />
+ <item
+ android:color="#00000000"
+ android:offset="1.0" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:fillColor="#FFFFFF"
+ android:fillType="nonZero"
+ android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+ android:strokeWidth="1"
+ android:strokeColor="#00000000" />
+</vector>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/src/main/res/drawable/ic_launcher_background.xml b/src/android/CHIPTVServer/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillColor="#3DDC84"
+ android:pathData="M0,0h108v108h-108z" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M9,0L9,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,0L19,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,0L29,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,0L39,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,0L49,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,0L59,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,0L69,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,0L79,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M89,0L89,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M99,0L99,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,9L108,9"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,19L108,19"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,29L108,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,39L108,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,49L108,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,59L108,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,69L108,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,79L108,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,89L108,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,99L108,99"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,29L89,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,39L89,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,49L89,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,59L89,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,69L89,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,79L89,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,19L29,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,19L39,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,19L49,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,19L59,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,19L69,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,19L79,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/src/android/CHIPTVServer/app/src/main/res/layout/activity_main.xml b/src/android/CHIPTVServer/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..65b4ee5
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <TextView
+ android:id="@+id/qrCodeTxt"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ android:layout_marginTop="20dp" />
+
+ <ImageView
+ android:id="@+id/qrCodeImg"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintTop_toBottomOf="@+id/qrCodeTxt"
+ android:layout_marginTop="20dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <TextView
+ android:id="@+id/manualPairingCodeTxt"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintTop_toBottomOf="@+id/qrCodeImg"
+ android:layout_marginTop="20dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/src/android/CHIPTVServer/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/src/android/CHIPTVServer/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/src/android/CHIPTVServer/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-hdpi/ic_launcher.webp
Binary files differ
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/src/android/CHIPTVServer/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Binary files differ
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/src/android/CHIPTVServer/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-mdpi/ic_launcher.webp
Binary files differ
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/src/android/CHIPTVServer/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Binary files differ
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/src/android/CHIPTVServer/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Binary files differ
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/src/android/CHIPTVServer/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
Binary files differ
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Binary files differ
diff --git a/src/android/CHIPTVServer/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
Binary files differ
diff --git a/src/android/CHIPTVServer/app/src/main/res/values-night/themes.xml b/src/android/CHIPTVServer/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..da91ed1
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,16 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <!-- Base application theme. -->
+ <style name="Theme.CHIPTVSlave" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+ <!-- Primary brand color. -->
+ <item name="colorPrimary">@color/purple_200</item>
+ <item name="colorPrimaryVariant">@color/purple_700</item>
+ <item name="colorOnPrimary">@color/black</item>
+ <!-- Secondary brand color. -->
+ <item name="colorSecondary">@color/teal_200</item>
+ <item name="colorSecondaryVariant">@color/teal_200</item>
+ <item name="colorOnSecondary">@color/black</item>
+ <!-- Status bar color. -->
+ <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
+ <!-- Customize your theme here. -->
+ </style>
+</resources>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/src/main/res/values/colors.xml b/src/android/CHIPTVServer/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..f8c6127
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="purple_200">#FFBB86FC</color>
+ <color name="purple_500">#FF6200EE</color>
+ <color name="purple_700">#FF3700B3</color>
+ <color name="teal_200">#FF03DAC5</color>
+ <color name="teal_700">#FF018786</color>
+ <color name="black">#FF000000</color>
+ <color name="white">#FFFFFFFF</color>
+</resources>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/src/main/res/values/strings.xml b/src/android/CHIPTVServer/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..a2cc2fe
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">CHIPTVServer</string>
+</resources>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/src/main/res/values/themes.xml b/src/android/CHIPTVServer/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..3e95998
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/main/res/values/themes.xml
@@ -0,0 +1,16 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <!-- Base application theme. -->
+ <style name="Theme.CHIPTVSlave" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
+ <!-- Primary brand color. -->
+ <item name="colorPrimary">@color/purple_500</item>
+ <item name="colorPrimaryVariant">@color/purple_700</item>
+ <item name="colorOnPrimary">@color/white</item>
+ <!-- Secondary brand color. -->
+ <item name="colorSecondary">@color/teal_200</item>
+ <item name="colorSecondaryVariant">@color/teal_700</item>
+ <item name="colorOnSecondary">@color/black</item>
+ <!-- Status bar color. -->
+ <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
+ <!-- Customize your theme here. -->
+ </style>
+</resources>
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/app/src/test/java/com/tcl/chip/chiptvslave/ExampleUnitTest.java b/src/android/CHIPTVServer/app/src/test/java/com/tcl/chip/chiptvslave/ExampleUnitTest.java
new file mode 100644
index 0000000..6ee6449
--- /dev/null
+++ b/src/android/CHIPTVServer/app/src/test/java/com/tcl/chip/chiptvslave/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.tcl.chip.chiptvserver;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
diff --git a/src/android/CHIPTVServer/build.gradle b/src/android/CHIPTVServer/build.gradle
new file mode 100644
index 0000000..79c656c
--- /dev/null
+++ b/src/android/CHIPTVServer/build.gradle
@@ -0,0 +1,25 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:4.2.2'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ jcenter() // Warning: this repository is going to shut down soon
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/src/android/CHIPTVServer/gradle.properties b/src/android/CHIPTVServer/gradle.properties
new file mode 100644
index 0000000..e94cae8
--- /dev/null
+++ b/src/android/CHIPTVServer/gradle.properties
@@ -0,0 +1,27 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app"s APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
+
+# Build SDK from source code and debug in Android Stduio. Must also set matterBuildSrcDir.
+matterSdkSourceBuild=false
+# Point to the SDK build dir without quotes (out/android-arm64-chip-test for
+# example) to build SDK from source code and debug in Android Studio.
+# Set to blank to use the SDK prebuilt by scripts/build/build_examples.py.
+matterBuildSrcDir=out/android-arm64-chip-tvserver
+
diff --git a/src/android/CHIPTVServer/gradle/wrapper/gradle-wrapper.jar b/src/android/CHIPTVServer/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
--- /dev/null
+++ b/src/android/CHIPTVServer/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/src/android/CHIPTVServer/gradle/wrapper/gradle-wrapper.properties b/src/android/CHIPTVServer/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..da67dc8
--- /dev/null
+++ b/src/android/CHIPTVServer/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Oct 26 11:10:18 CST 2021
+distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/src/android/CHIPTVServer/gradlew b/src/android/CHIPTVServer/gradlew
new file mode 100755
index 0000000..180cdce
--- /dev/null
+++ b/src/android/CHIPTVServer/gradlew
@@ -0,0 +1,184 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or 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
+#
+# https://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.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ]; do
+ ls=$(ls -ld "$PRG")
+ link=$(expr "$ls" : '.*-> \(.*\)$')
+ if expr "$link" : '/.*' >/dev/null; then
+ PRG="$link"
+ else
+ PRG=$(dirname "$PRG")"/$link"
+ fi
+done
+SAVED="$PWD"
+cd "$(dirname "$PRG")" >/dev/null
+APP_HOME="$(pwd -P)"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=$(basename "$0")
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn() {
+ echo "$*"
+}
+
+die() {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$(uname)" in
+ CYGWIN*)
+ cygwin=true
+ ;;
+ Darwin*)
+ darwin=true
+ ;;
+ MINGW*)
+ msys=true
+ ;;
+ NONSTOP*)
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ]; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ]; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ]; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ]; then
+ MAX_FD_LIMIT=$(ulimit -H -n)
+ if [ $? -eq 0 ]; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ]; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n "$MAX_FD"
+ if [ $? -ne 0 ]; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if "$darwin"; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ]; then
+ APP_HOME=$(cygpath --path --mixed "$APP_HOME")
+ CLASSPATH=$(cygpath --path --mixed "$CLASSPATH")
+
+ JAVACMD=$(cygpath --unix "$JAVACMD")
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=$(find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null)
+ SEP=""
+ for dir in "$ROOTDIRSRAW"; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ]; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@"; do
+ CHECK=$(echo "$arg" | egrep -c "$OURCYGPATTERN" -)
+ CHECK2=$(echo "$arg" | egrep -c "^-") ### Determine if an option
+
+ if [ "$CHECK" -ne 0 ] && [ "$CHECK2" -eq 0 ]; then ### Added a condition
+ eval "$(echo args"$i")=$(cygpath --path --ignore --mixed "$arg")"
+ else
+ eval "$(echo args"$i")=\"$arg\""
+ fi
+ i=$(expr "$i" + 1)
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save() {
+ for i; do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- "$DEFAULT_JVM_OPTS" "$JAVA_OPTS" "$GRADLE_OPTS" "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/src/android/CHIPTVServer/gradlew.bat b/src/android/CHIPTVServer/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/src/android/CHIPTVServer/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/src/android/CHIPTVServer/settings.gradle b/src/android/CHIPTVServer/settings.gradle
new file mode 100644
index 0000000..8392989
--- /dev/null
+++ b/src/android/CHIPTVServer/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = "CHIPTVServer"
+include ':app'
diff --git a/src/app/server/java/AppMain.cpp b/src/app/server/java/AppMain.cpp
new file mode 100644
index 0000000..18f1c2c
--- /dev/null
+++ b/src/app/server/java/AppMain.cpp
@@ -0,0 +1,67 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#include "AppMain.h"
+#include <app/server/OnboardingCodesUtil.h>
+#include <app/server/Server.h>
+#include <credentials/DeviceAttestationCredsProvider.h>
+#include <credentials/examples/DeviceAttestationCredsExample.h>
+#include <iostream>
+#include <lib/core/CHIPError.h>
+#include <lib/support/CHIPMem.h>
+#include <lib/support/JniTypeWrappers.h>
+#include <lib/support/ScopedBuffer.h>
+#include <platform/CHIPDeviceLayer.h>
+#include <platform/PlatformManager.h>
+#include <setup_payload/QRCodeSetupPayloadGenerator.h>
+#include <setup_payload/SetupPayload.h>
+#include <thread>
+
+using namespace chip;
+using namespace chip::Credentials;
+using namespace chip::Inet;
+using namespace chip::Transport;
+using namespace chip::DeviceLayer;
+
+CHIP_ERROR ChipAndroidAppInit(void)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+
+ err = chip::Platform::MemoryInit();
+ SuccessOrExit(err);
+
+ err = chip::DeviceLayer::PlatformMgr().InitChipStack();
+ SuccessOrExit(err);
+
+ ConfigurationMgr().LogDeviceConfig();
+
+ // Init ZCL Data Model and CHIP App Server
+ err = chip::Server::GetInstance().Init(nullptr, CHIP_PORT, CHIP_UDC_PORT);
+ SuccessOrExit(err);
+
+ // TODO: move load DAC to java
+ SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider());
+
+exit:
+ if (err != CHIP_NO_ERROR)
+ {
+ ChipLogProgress(NotSpecified, "Failed to run ChipAndroidAppInit: %s ", ErrorStr(err));
+ return err;
+ }
+ return err;
+}
diff --git a/src/app/server/java/AppMain.h b/src/app/server/java/AppMain.h
new file mode 100644
index 0000000..ae54475
--- /dev/null
+++ b/src/app/server/java/AppMain.h
@@ -0,0 +1,22 @@
+/*
+ *
+ * Copyright (c) 2021 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.
+ */
+
+#pragma once
+#include <lib/core/CHIPError.h>
+
+CHIP_ERROR ChipAndroidAppInit(void);
diff --git a/src/app/server/java/BUILD.gn b/src/app/server/java/BUILD.gn
new file mode 100644
index 0000000..d4170c2
--- /dev/null
+++ b/src/app/server/java/BUILD.gn
@@ -0,0 +1,76 @@
+# Copyright (c) 2021 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}/src/app/common_flags.gni")
+import("${chip_root}/src/lib/lib.gni")
+
+shared_library("jni") {
+ output_name = "libCHIPAppServer"
+
+ sources = [
+ "AppMain.cpp",
+ "AppMain.h",
+ "CHIPAppServer-JNI.cpp",
+ ]
+
+ deps = [
+ "${chip_root}/examples/tv-app/android:android-tv-app",
+ "${chip_root}/examples/tv-app/tv-common",
+ "${chip_root}/src/app/server",
+ "${chip_root}/src/inet",
+ "${chip_root}/src/lib",
+ "${chip_root}/src/platform",
+ "${chip_root}/src/platform/android",
+ "${chip_root}/third_party/inipp",
+ ]
+
+ public_configs = [ "${chip_root}/src:includes" ]
+
+ output_dir = "${root_out_dir}/lib/jni/${android_abi}"
+
+ ldflags = [ "-Wl,--gc-sections" ]
+}
+
+android_library("java") {
+ output_name = "CHIPAppServer.jar"
+
+ deps = [
+ ":android",
+ "${chip_root}/third_party/android_deps:annotation",
+ ]
+
+ data_deps = [
+ ":jni",
+ "${chip_root}/build/chip/java:shared_cpplib",
+ ]
+
+ sources = [
+ "src/chip/appserver/ChipAppServer.java",
+ "src/chip/appserver/ChipAppServerException.java",
+ ]
+
+ javac_flags = [ "-Xlint:deprecation" ]
+
+ # TODO: add classpath support (we likely need to add something like
+ # ..../platforms/android-21/android.jar to access BLE items)
+}
+
+java_prebuilt("android") {
+ jar_path = "${android_sdk_root}/platforms/android-21/android.jar"
+}
diff --git a/src/app/server/java/CHIPAppServer-JNI.cpp b/src/app/server/java/CHIPAppServer-JNI.cpp
new file mode 100644
index 0000000..777a475
--- /dev/null
+++ b/src/app/server/java/CHIPAppServer-JNI.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2021 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.
+ *
+ */
+
+/**
+ * @file
+ * Implementation of JNI bridge for CHIP App Server for Android TV apps
+ *
+ */
+#include "AppMain.h"
+#include <jni.h>
+#include <lib/core/CHIPError.h>
+#include <lib/support/CHIPJNIError.h>
+#include <lib/support/CHIPMem.h>
+#include <lib/support/CodeUtils.h>
+#include <lib/support/JniReferences.h>
+#include <lib/support/JniTypeWrappers.h>
+#include <platform/CHIPDeviceConfig.h>
+#include <platform/ConfigurationManager.h>
+#include <platform/ConnectivityManager.h>
+#include <platform/KeyValueStoreManager.h>
+#include <platform/android/AndroidChipPlatform-JNI.h>
+#include <platform/internal/BLEManager.h>
+
+using namespace chip;
+using namespace chip::DeviceLayer;
+
+#define JNI_METHOD(RETURN, METHOD_NAME) extern "C" JNIEXPORT RETURN JNICALL Java_chip_appserver_ChipAppServer_##METHOD_NAME
+
+#ifndef PTHREAD_NULL
+#define PTHREAD_NULL 0
+#endif // PTHREAD_NULL
+
+static void * IOThreadAppMain(void * arg);
+
+namespace {
+JavaVM * sJVM;
+pthread_t sIOThread = PTHREAD_NULL;
+jclass sChipAppServerExceptionCls = NULL;
+} // namespace
+
+jint JNI_OnLoad(JavaVM * jvm, void * reserved)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ JNIEnv * env;
+
+ ChipLogProgress(AppServer, "JNI_OnLoad() called");
+
+ chip::Platform::MemoryInit();
+
+ // Save a reference to the JVM. Will need this to call back into Java.
+ JniReferences::GetInstance().SetJavaVm(jvm, "chip/appserver/ChipAppServer");
+ sJVM = jvm;
+
+ // Get a JNI environment object.
+ env = JniReferences::GetInstance().GetEnvForCurrentThread();
+ VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV);
+
+ ChipLogProgress(AppServer, "Loading Java class references.");
+
+ // Get various class references need by the API.
+ err = JniReferences::GetInstance().GetClassRef(env, "chip/appserver/ChipAppServerException", sChipAppServerExceptionCls);
+ SuccessOrExit(err);
+ ChipLogProgress(AppServer, "Java class references loaded.");
+
+ err = AndroidChipPlatformJNI_OnLoad(jvm, reserved);
+ SuccessOrExit(err);
+
+exit:
+ if (err != CHIP_NO_ERROR)
+ {
+ JniReferences::GetInstance().ThrowError(env, sChipAppServerExceptionCls, err);
+ chip::DeviceLayer::StackUnlock unlock;
+ JNI_OnUnload(jvm, reserved);
+ }
+
+ return (err == CHIP_NO_ERROR) ? JNI_VERSION_1_6 : JNI_ERR;
+}
+
+void JNI_OnUnload(JavaVM * jvm, void * reserved)
+{
+ chip::DeviceLayer::StackLock lock;
+ ChipLogProgress(AppServer, "JNI_OnUnload() called");
+
+ // If the IO thread has been started, shut it down and wait for it to exit.
+ if (sIOThread != PTHREAD_NULL)
+ {
+ chip::DeviceLayer::PlatformMgr().StopEventLoopTask();
+
+ chip::DeviceLayer::StackUnlock unlock;
+ pthread_join(sIOThread, NULL);
+ }
+
+ sJVM = NULL;
+
+ chip::Platform::MemoryShutdown();
+}
+
+JNI_METHOD(jboolean, startApp)(JNIEnv * env, jobject self)
+{
+ chip::DeviceLayer::StackLock lock;
+
+ CHIP_ERROR err = ChipAndroidAppInit();
+ SuccessOrExit(err);
+
+ if (sIOThread == PTHREAD_NULL)
+ {
+ pthread_create(&sIOThread, NULL, IOThreadAppMain, NULL);
+ }
+
+exit:
+ if (err != CHIP_NO_ERROR)
+ {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+void * IOThreadAppMain(void * arg)
+{
+ JNIEnv * env;
+ JavaVMAttachArgs attachArgs;
+
+ // Attach the IO thread to the JVM as a daemon thread.
+ // This allows the JVM to shutdown without waiting for this thread to exit.
+ attachArgs.version = JNI_VERSION_1_6;
+ attachArgs.name = (char *) "CHIP AppServer IO Thread";
+ attachArgs.group = NULL;
+#ifdef __ANDROID__
+ sJVM->AttachCurrentThreadAsDaemon(&env, (void *) &attachArgs);
+#else
+ sJVM->AttachCurrentThreadAsDaemon((void **) &env, (void *) &attachArgs);
+#endif
+
+ ChipLogProgress(AppServer, "IO thread starting");
+ chip::DeviceLayer::PlatformMgr().RunEventLoop();
+ ChipLogProgress(AppServer, "IO thread ending");
+
+ // Detach the thread from the JVM.
+ sJVM->DetachCurrentThread();
+
+ return NULL;
+}
diff --git a/src/app/server/java/src/chip/appserver/ChipAppServer.java b/src/app/server/java/src/chip/appserver/ChipAppServer.java
new file mode 100644
index 0000000..6d9bb3a
--- /dev/null
+++ b/src/app/server/java/src/chip/appserver/ChipAppServer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2021 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.appserver;
+
+/** Controller to interact with the CHIP device. */
+public class ChipAppServer {
+ private static final String TAG = ChipAppServer.class.getSimpleName();
+
+ static {
+ System.loadLibrary("CHIPAppServer");
+ }
+
+ public native boolean startApp();
+}
diff --git a/src/app/server/java/src/chip/appserver/ChipAppServerException.java b/src/app/server/java/src/chip/appserver/ChipAppServerException.java
new file mode 100644
index 0000000..08e11d1
--- /dev/null
+++ b/src/app/server/java/src/chip/appserver/ChipAppServerException.java
@@ -0,0 +1,14 @@
+package chip.appserver;
+
+public class ChipAppServerException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public int errorCode;
+
+ public ChipAppServerException() {}
+
+ public ChipAppServerException(int errorCode, String message) {
+ super(message != null ? message : String.format("Error Code %d", errorCode));
+ this.errorCode = errorCode;
+ }
+}
diff --git a/src/controller/CHIPDevice.h b/src/controller/CHIPDevice.h
index f1f0fc3..408d199 100644
--- a/src/controller/CHIPDevice.h
+++ b/src/controller/CHIPDevice.h
@@ -105,7 +105,7 @@
typedef void (*OnDeviceConnectionFailure)(void * context, NodeId deviceId, CHIP_ERROR error);
typedef void (*OnOpenCommissioningWindow)(void * context, NodeId deviceId, CHIP_ERROR status, SetupPayload payload);
-class DLL_EXPORT Device : public Messaging::ExchangeDelegate, public SessionEstablishmentDelegate
+class Device : public Messaging::ExchangeDelegate, public SessionEstablishmentDelegate
{
public:
~Device();
@@ -588,7 +588,7 @@
* Device when a new message or status update is received from the corresponding
* CHIP device.
*/
-class DLL_EXPORT DeviceStatusDelegate
+class DeviceStatusDelegate
{
public:
virtual ~DeviceStatusDelegate() {}
diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp
index d293fb0..7a5c78e 100644
--- a/src/controller/java/AndroidDeviceControllerWrapper.cpp
+++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp
@@ -213,7 +213,9 @@
initParams.inetLayer = inetLayer;
initParams.fabricStorage = wrapper.get();
// move bleLayer into platform/android to share with app server
- initParams.bleLayer = DeviceLayer::ConnectivityMgr().GetBleLayer();
+#if CONFIG_NETWORK_LAYER_BLE
+ initParams.bleLayer = DeviceLayer::ConnectivityMgr().GetBleLayer();
+#endif
initParams.listenPort = CHIP_PORT + 1;
setupParams.storageDelegate = wrapper.get();
setupParams.pairingDelegate = wrapper.get();
diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn
index 6bd7248..f627e30 100644
--- a/src/controller/java/BUILD.gn
+++ b/src/controller/java/BUILD.gn
@@ -42,6 +42,8 @@
public_configs = [ "${chip_root}/src:includes" ]
output_dir = "${root_out_dir}/lib/jni/${android_abi}"
+
+ ldflags = [ "-Wl,--gc-sections" ]
}
android_library("java") {
diff --git a/src/controller/java/CHIPDeviceController-JNI.cpp b/src/controller/java/CHIPDeviceController-JNI.cpp
index 8540976..4d087be 100644
--- a/src/controller/java/CHIPDeviceController-JNI.cpp
+++ b/src/controller/java/CHIPDeviceController-JNI.cpp
@@ -59,9 +59,7 @@
#define CDC_JNI_CALLBACK_LOCAL_REF_COUNT 256
-static void ThrowError(JNIEnv * env, CHIP_ERROR errToThrow);
static void * IOThreadMain(void * arg);
-static CHIP_ERROR N2J_Error(JNIEnv * env, CHIP_ERROR inErr, jthrowable & outEx);
static CHIP_ERROR N2J_PaseVerifierParams(JNIEnv * env, jlong setupPincode, jint passcodeId, jbyteArray pakeVerifier,
jobject & outParams);
@@ -112,7 +110,7 @@
exit:
if (err != CHIP_NO_ERROR)
{
- ThrowError(env, err);
+ JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err);
chip::DeviceLayer::StackUnlock unlock;
JNI_OnUnload(jvm, reserved);
}
@@ -175,7 +173,7 @@
if (err != CHIP_JNI_ERROR_EXCEPTION_THROWN)
{
- ThrowError(env, err);
+ JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err);
}
}
@@ -193,7 +191,9 @@
RendezvousParameters params = RendezvousParameters()
.SetSetupPINCode(pinCode)
+#if CONFIG_NETWORK_LAYER_BLE
.SetConnectionObject(reinterpret_cast<BLE_CONNECTION_OBJECT>(connObj))
+#endif
.SetPeerAddress(Transport::PeerAddress::BLE());
if (csrNonce != nullptr)
{
@@ -205,7 +205,7 @@
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to pair the device.");
- ThrowError(env, err);
+ JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err);
}
}
@@ -222,7 +222,8 @@
Inet::IPAddress addr;
JniUtfString addrJniString(env, address);
VerifyOrReturn(Inet::IPAddress::FromString(addrJniString.c_str(), addr),
- ChipLogError(Controller, "Failed to parse IP address."), ThrowError(env, CHIP_ERROR_INVALID_ARGUMENT));
+ ChipLogError(Controller, "Failed to parse IP address."),
+ JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, CHIP_ERROR_INVALID_ARGUMENT));
RendezvousParameters params = RendezvousParameters()
.SetDiscriminator(discriminator)
@@ -238,7 +239,7 @@
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to pair the device.");
- ThrowError(env, err);
+ JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err);
}
}
@@ -255,7 +256,7 @@
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to unpair the device.");
- ThrowError(env, err);
+ JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err);
}
}
@@ -272,7 +273,7 @@
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to unpair the device.");
- ThrowError(env, err);
+ JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err);
}
}
@@ -321,7 +322,7 @@
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to get device address.");
- ThrowError(env, err);
+ JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err);
}
addr.ToString(addrStr);
@@ -347,7 +348,7 @@
if (err != CHIP_NO_ERROR)
{
ChipLogError(Controller, "Failed to update device");
- ThrowError(env, err);
+ JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err);
}
}
@@ -451,7 +452,7 @@
exit:
if (err != CHIP_NO_ERROR)
{
- ThrowError(env, err);
+ JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err);
}
return nullptr;
}
@@ -482,18 +483,6 @@
return NULL;
}
-void ThrowError(JNIEnv * env, CHIP_ERROR errToThrow)
-{
- CHIP_ERROR err = CHIP_NO_ERROR;
- jthrowable ex;
-
- err = N2J_Error(env, errToThrow, ex);
- if (err == CHIP_NO_ERROR)
- {
- env->Throw(ex);
- }
-}
-
CHIP_ERROR N2J_PaseVerifierParams(JNIEnv * env, jlong setupPincode, jint passcodeId, jbyteArray paseVerifier, jobject & outParams)
{
CHIP_ERROR err = CHIP_NO_ERROR;
@@ -514,43 +503,3 @@
exit:
return err;
}
-
-CHIP_ERROR N2J_Error(JNIEnv * env, CHIP_ERROR inErr, jthrowable & outEx)
-{
- CHIP_ERROR err = CHIP_NO_ERROR;
- const char * errStr = NULL;
- jstring errStrObj = NULL;
- jmethodID constructor;
-
- env->ExceptionClear();
- constructor = env->GetMethodID(sChipDeviceControllerExceptionCls, "<init>", "(ILjava/lang/String;)V");
- VerifyOrExit(constructor != NULL, err = CHIP_JNI_ERROR_METHOD_NOT_FOUND);
-
- switch (inErr.AsInteger())
- {
- case CHIP_JNI_ERROR_TYPE_NOT_FOUND.AsInteger():
- errStr = "CHIP Device Controller Error: JNI type not found";
- break;
- case CHIP_JNI_ERROR_METHOD_NOT_FOUND.AsInteger():
- errStr = "CHIP Device Controller Error: JNI method not found";
- break;
- case CHIP_JNI_ERROR_FIELD_NOT_FOUND.AsInteger():
- errStr = "CHIP Device Controller Error: JNI field not found";
- break;
- case CHIP_JNI_ERROR_DEVICE_NOT_FOUND.AsInteger():
- errStr = "CHIP Device Controller Error: Device not found";
- break;
- default:
- errStr = ErrorStr(inErr);
- break;
- }
- errStrObj = (errStr != NULL) ? env->NewStringUTF(errStr) : NULL;
-
- outEx = (jthrowable) env->NewObject(sChipDeviceControllerExceptionCls, constructor, static_cast<jint>(inErr.AsInteger()),
- errStrObj);
- VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
-
-exit:
- env->DeleteLocalRef(errStrObj);
- return err;
-}
diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
index 69156a3..3b5c367 100644
--- a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
+++ b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp
@@ -56,8 +56,6 @@
template <class ImplClass>
CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_InitChipStack()
{
- mChipStackLock = PTHREAD_MUTEX_INITIALIZER;
-
// Call up to the base class _InitChipStack() to perform the bulk of the initialization.
ReturnErrorOnFailure(GenericPlatformManagerImpl<ImplClass>::_InitChipStack());
@@ -104,6 +102,10 @@
void GenericPlatformManagerImpl_POSIX<ImplClass>::_UnlockChipStack()
{
#if CHIP_STACK_LOCK_TRACKING_ENABLED
+ if (!mChipStackIsLocked)
+ {
+ ChipLogError(DeviceLayer, "_UnlockChipStack may error status");
+ }
mChipStackIsLocked = false;
#endif
diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.h b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.h
index e2d5fee..a791c67 100644
--- a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.h
+++ b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.h
@@ -53,7 +53,7 @@
{
protected:
// OS-specific members (pthread)
- pthread_mutex_t mChipStackLock;
+ pthread_mutex_t mChipStackLock = PTHREAD_MUTEX_INITIALIZER;
enum TaskType
{
diff --git a/src/lib/support/JniReferences.cpp b/src/lib/support/JniReferences.cpp
index d1190fa..a8c43d3 100644
--- a/src/lib/support/JniReferences.cpp
+++ b/src/lib/support/JniReferences.cpp
@@ -15,6 +15,7 @@
* limitations under the License.
*/
+#include <jni.h>
#include <lib/support/CHIPJNIError.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/JniReferences.h>
@@ -169,4 +170,17 @@
}
}
+void JniReferences::ThrowError(JNIEnv * env, jclass exceptionCls, CHIP_ERROR errToThrow)
+{
+ env->ExceptionClear();
+ jmethodID constructor = env->GetMethodID(exceptionCls, "<init>", "(ILjava/lang/String;)V");
+ VerifyOrReturn(constructor != NULL);
+
+ jstring jerrStr = env->NewStringUTF(ErrorStr(errToThrow));
+
+ jthrowable outEx = (jthrowable) env->NewObject(exceptionCls, constructor, static_cast<jint>(errToThrow.AsInteger()), jerrStr);
+ VerifyOrReturn(!env->ExceptionCheck());
+ env->Throw(outEx);
+}
+
} // namespace chip
diff --git a/src/lib/support/JniReferences.h b/src/lib/support/JniReferences.h
index 5e8cbe6..ed0ede5 100644
--- a/src/lib/support/JniReferences.h
+++ b/src/lib/support/JniReferences.h
@@ -78,6 +78,8 @@
void ReportError(JNIEnv * env, CHIP_ERROR cbErr, const char * functName);
+ void ThrowError(JNIEnv * env, jclass exceptionCls, CHIP_ERROR errToThrow);
+
private:
JniReferences() {}
diff --git a/src/platform/android/AndroidChipPlatform-JNI.cpp b/src/platform/android/AndroidChipPlatform-JNI.cpp
index bd1bbca..785ed89 100644
--- a/src/platform/android/AndroidChipPlatform-JNI.cpp
+++ b/src/platform/android/AndroidChipPlatform-JNI.cpp
@@ -43,9 +43,9 @@
#define JNI_MDNSCALLBACK_METHOD(RETURN, METHOD_NAME) \
extern "C" JNIEXPORT RETURN JNICALL Java_chip_platform_ChipMdnsCallbackImpl_##METHOD_NAME
-static void ThrowError(JNIEnv * env, CHIP_ERROR errToThrow);
-static CHIP_ERROR N2J_Error(JNIEnv * env, CHIP_ERROR inErr, jthrowable & outEx);
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
static bool JavaBytesToUUID(JNIEnv * env, jbyteArray value, chip::Ble::ChipBleUUID & uuid);
+#endif
namespace {
JavaVM * sJVM;
@@ -83,7 +83,7 @@
exit:
if (err != CHIP_NO_ERROR)
{
- ThrowError(env, err);
+ JniReferences::GetInstance().ThrowError(env, sAndroidChipPlatformExceptionCls, err);
JNI_OnUnload(jvm, reserved);
}
@@ -108,6 +108,7 @@
JNI_METHOD(void, handleWriteConfirmation)
(JNIEnv * env, jobject self, jint conn, jbyteArray svcId, jbyteArray charId)
{
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
chip::DeviceLayer::StackLock lock;
BLE_CONNECTION_OBJECT const connObj = reinterpret_cast<BLE_CONNECTION_OBJECT>(conn);
@@ -119,11 +120,13 @@
ChipLogError(DeviceLayer, "handleWriteConfirmation() called with invalid characteristic ID"));
chip::DeviceLayer::Internal::BLEMgrImpl().HandleWriteConfirmation(connObj, &svcUUID, &charUUID);
+#endif
}
JNI_METHOD(void, handleIndicationReceived)
(JNIEnv * env, jobject self, jint conn, jbyteArray svcId, jbyteArray charId, jbyteArray value)
{
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
chip::DeviceLayer::StackLock lock;
BLE_CONNECTION_OBJECT const connObj = reinterpret_cast<BLE_CONNECTION_OBJECT>(conn);
const auto valueBegin = env->GetByteArrayElements(value, nullptr);
@@ -144,11 +147,13 @@
chip::DeviceLayer::Internal::BLEMgrImpl().HandleIndicationReceived(connObj, &svcUUID, &charUUID, std::move(buffer));
exit:
env->ReleaseByteArrayElements(value, valueBegin, 0);
+#endif
}
JNI_METHOD(void, handleSubscribeComplete)
(JNIEnv * env, jobject self, jint conn, jbyteArray svcId, jbyteArray charId)
{
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
chip::DeviceLayer::StackLock lock;
BLE_CONNECTION_OBJECT const connObj = reinterpret_cast<BLE_CONNECTION_OBJECT>(conn);
@@ -160,11 +165,13 @@
ChipLogError(DeviceLayer, "handleSubscribeComplete() called with invalid characteristic ID"));
chip::DeviceLayer::Internal::BLEMgrImpl().HandleSubscribeComplete(connObj, &svcUUID, &charUUID);
+#endif
}
JNI_METHOD(void, handleUnsubscribeComplete)
(JNIEnv * env, jobject self, jint conn, jbyteArray svcId, jbyteArray charId)
{
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
chip::DeviceLayer::StackLock lock;
BLE_CONNECTION_OBJECT const connObj = reinterpret_cast<BLE_CONNECTION_OBJECT>(conn);
@@ -176,14 +183,17 @@
ChipLogError(DeviceLayer, "handleUnsubscribeComplete() called with invalid characteristic ID"));
chip::DeviceLayer::Internal::BLEMgrImpl().HandleUnsubscribeComplete(connObj, &svcUUID, &charUUID);
+#endif
}
JNI_METHOD(void, handleConnectionError)(JNIEnv * env, jobject self, jint conn)
{
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
chip::DeviceLayer::StackLock lock;
BLE_CONNECTION_OBJECT const connObj = reinterpret_cast<BLE_CONNECTION_OBJECT>(conn);
chip::DeviceLayer::Internal::BLEMgrImpl().HandleConnectionError(connObj, BLE_ERROR_APP_CLOSED_CONNECTION);
+#endif
}
// for KeyValueStoreManager
@@ -215,58 +225,7 @@
HandleResolve(instanceName, serviceType, address, port, callbackHandle, contextHandle);
}
-void ThrowError(JNIEnv * env, CHIP_ERROR errToThrow)
-{
- CHIP_ERROR err = CHIP_NO_ERROR;
- jthrowable ex;
-
- err = N2J_Error(env, errToThrow, ex);
- if (err == CHIP_NO_ERROR)
- {
- env->Throw(ex);
- }
-}
-
-CHIP_ERROR N2J_Error(JNIEnv * env, CHIP_ERROR inErr, jthrowable & outEx)
-{
- CHIP_ERROR err = CHIP_NO_ERROR;
- const char * errStr = NULL;
- jstring errStrObj = NULL;
- jmethodID constructor;
-
- env->ExceptionClear();
- constructor = env->GetMethodID(sAndroidChipPlatformExceptionCls, "<init>", "(ILjava/lang/String;)V");
- VerifyOrExit(constructor != NULL, err = CHIP_JNI_ERROR_METHOD_NOT_FOUND);
-
- switch (inErr.AsInteger())
- {
- case CHIP_JNI_ERROR_TYPE_NOT_FOUND.AsInteger():
- errStr = "CHIP Device Controller Error: JNI type not found";
- break;
- case CHIP_JNI_ERROR_METHOD_NOT_FOUND.AsInteger():
- errStr = "CHIP Device Controller Error: JNI method not found";
- break;
- case CHIP_JNI_ERROR_FIELD_NOT_FOUND.AsInteger():
- errStr = "CHIP Device Controller Error: JNI field not found";
- break;
- case CHIP_JNI_ERROR_DEVICE_NOT_FOUND.AsInteger():
- errStr = "CHIP Device Controller Error: Device not found";
- break;
- default:
- errStr = ErrorStr(inErr);
- break;
- }
- errStrObj = (errStr != NULL) ? env->NewStringUTF(errStr) : NULL;
-
- outEx =
- (jthrowable) env->NewObject(sAndroidChipPlatformExceptionCls, constructor, static_cast<jint>(inErr.AsInteger()), errStrObj);
- VerifyOrExit(!env->ExceptionCheck(), err = CHIP_JNI_ERROR_EXCEPTION_THROWN);
-
-exit:
- env->DeleteLocalRef(errStrObj);
- return err;
-}
-
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
static bool JavaBytesToUUID(JNIEnv * env, jbyteArray value, chip::Ble::ChipBleUUID & uuid)
{
const auto valueBegin = env->GetByteArrayElements(value, nullptr);
@@ -280,3 +239,4 @@
env->ReleaseByteArrayElements(value, valueBegin, 0);
return result;
}
+#endif
diff --git a/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java b/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java
index b086865..f5bb855 100644
--- a/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java
+++ b/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java
@@ -149,12 +149,12 @@
@Override
public void onServiceRegistered(NsdServiceInfo serviceInfo) {
- Log.i(TAG, "service " + serviceInfo.getServiceName() + " onServiceRegistered:");
+ Log.i(TAG, "service " + serviceInfo.getServiceName() + " onServiceRegistered");
}
@Override
public void onServiceUnregistered(NsdServiceInfo serviceInfo) {
- Log.i(TAG, "service " + serviceInfo.getServiceName() + " onServiceRegistered:");
+ Log.i(TAG, "service " + serviceInfo.getServiceName() + " onServiceRegistered");
}
};
registrationListeners.add(registrationListener);
diff --git a/src/setup_payload/java/SetupPayloadParser-JNI.cpp b/src/setup_payload/java/SetupPayloadParser-JNI.cpp
index 5821aa1..0cc1010 100644
--- a/src/setup_payload/java/SetupPayloadParser-JNI.cpp
+++ b/src/setup_payload/java/SetupPayloadParser-JNI.cpp
@@ -1,8 +1,13 @@
+#include "lib/core/CHIPError.h"
+#include "lib/support/JniTypeWrappers.h"
+#include <setup_payload/ManualSetupPayloadGenerator.h>
#include <setup_payload/ManualSetupPayloadParser.h>
+#include <setup_payload/QRCodeSetupPayloadGenerator.h>
#include <setup_payload/QRCodeSetupPayloadParser.h>
#include <lib/support/CHIPMem.h>
#include <lib/support/CodeUtils.h>
+#include <lib/support/JniReferences.h>
#include <lib/support/logging/CHIPLogging.h>
#include <vector>
@@ -23,6 +28,8 @@
static jobject TransformSetupPayload(JNIEnv * env, SetupPayload & payload);
static jobject CreateCapabilitiesHashSet(JNIEnv * env, RendezvousInformationFlags flags);
+static void TransformSetupPayloadFromJobject(JNIEnv * env, jobject jPayload, SetupPayload & payload);
+static void CreateCapabilitiesFromHashSet(JNIEnv * env, jobject discoveryCapabilitiesObj, RendezvousInformationFlags & flags);
static CHIP_ERROR ThrowUnrecognizedQRCodeException(JNIEnv * env, jstring qrCodeObj);
static CHIP_ERROR ThrowInvalidEntryCodeFormatException(JNIEnv * env, jstring entryCodeObj);
@@ -196,6 +203,100 @@
return capabilitiesHashSet;
}
+JNI_METHOD(jstring, getQrCodeFromPayload)(JNIEnv * env, jobject self, jobject setupPayload)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ SetupPayload payload;
+ std::string qrString;
+
+ TransformSetupPayloadFromJobject(env, setupPayload, payload);
+
+ err = QRCodeSetupPayloadGenerator(payload).payloadBase38Representation(qrString);
+ if (err != CHIP_NO_ERROR)
+ {
+ jclass exceptionCls = env->FindClass("chip/setuppayload/SetupPayloadParser$SetupPayloadException");
+ JniReferences::GetInstance().ThrowError(env, exceptionCls, err);
+ return nullptr;
+ }
+
+ return env->NewStringUTF(qrString.c_str());
+}
+
+JNI_METHOD(jstring, getManualEntryCodeFromPayload)(JNIEnv * env, jobject self, jobject setupPayload)
+{
+ CHIP_ERROR err = CHIP_NO_ERROR;
+ SetupPayload payload;
+ std::string outDecimalString;
+
+ TransformSetupPayloadFromJobject(env, setupPayload, payload);
+
+ err = ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(outDecimalString);
+ if (err != CHIP_NO_ERROR)
+ {
+ jclass exceptionCls = env->FindClass("chip/setuppayload/SetupPayloadParser$SetupPayloadException");
+ JniReferences::GetInstance().ThrowError(env, exceptionCls, err);
+ return nullptr;
+ }
+
+ return env->NewStringUTF(outDecimalString.c_str());
+}
+
+void TransformSetupPayloadFromJobject(JNIEnv * env, jobject jPayload, SetupPayload & payload)
+{
+ jclass setupPayloadClass = env->FindClass("chip/setuppayload/SetupPayload");
+
+ jfieldID version = env->GetFieldID(setupPayloadClass, "version", "I");
+ jfieldID vendorId = env->GetFieldID(setupPayloadClass, "vendorId", "I");
+ jfieldID productId = env->GetFieldID(setupPayloadClass, "productId", "I");
+ jfieldID commissioningFlow = env->GetFieldID(setupPayloadClass, "commissioningFlow", "I");
+ jfieldID discriminator = env->GetFieldID(setupPayloadClass, "discriminator", "I");
+ jfieldID setUpPinCode = env->GetFieldID(setupPayloadClass, "setupPinCode", "J");
+ jfieldID discoveryCapabilities = env->GetFieldID(setupPayloadClass, "discoveryCapabilities", "Ljava/util/Set;");
+
+ payload.version = env->GetIntField(jPayload, version);
+ payload.vendorID = env->GetIntField(jPayload, vendorId);
+ payload.productID = env->GetIntField(jPayload, productId);
+ payload.commissioningFlow = static_cast<CommissioningFlow>(env->GetIntField(jPayload, commissioningFlow));
+ payload.discriminator = env->GetIntField(jPayload, discriminator);
+ payload.setUpPINCode = env->GetLongField(jPayload, setUpPinCode);
+
+ jobject discoveryCapabilitiesObj = env->GetObjectField(jPayload, discoveryCapabilities);
+ CreateCapabilitiesFromHashSet(env, discoveryCapabilitiesObj, payload.rendezvousInformation);
+}
+
+void CreateCapabilitiesFromHashSet(JNIEnv * env, jobject discoveryCapabilitiesObj, RendezvousInformationFlags & flags)
+{
+ jclass hashSetClass = env->FindClass("java/util/HashSet");
+ jmethodID hashSetContainsMethod = env->GetMethodID(hashSetClass, "contains", "(Ljava/lang/Object;)Z");
+
+ jboolean contains;
+ jclass capabilityEnum = env->FindClass("chip/setuppayload/DiscoveryCapability");
+
+ jfieldID bleCapability = env->GetStaticFieldID(capabilityEnum, "BLE", "Lchip/setuppayload/DiscoveryCapability;");
+ jobject bleObj = env->GetStaticObjectField(capabilityEnum, bleCapability);
+ contains = env->CallBooleanMethod(discoveryCapabilitiesObj, hashSetContainsMethod, bleObj);
+ if (contains)
+ {
+ flags.Set(chip::RendezvousInformationFlag::kBLE);
+ }
+
+ jfieldID softApCapability = env->GetStaticFieldID(capabilityEnum, "SOFT_AP", "Lchip/setuppayload/DiscoveryCapability;");
+ jobject softApObj = env->GetStaticObjectField(capabilityEnum, softApCapability);
+ contains = env->CallBooleanMethod(discoveryCapabilitiesObj, hashSetContainsMethod, softApObj);
+ if (contains)
+ {
+ flags.Set(chip::RendezvousInformationFlag::kSoftAP);
+ }
+
+ jfieldID onNetworkCapability = env->GetStaticFieldID(capabilityEnum, "ON_NETWORK", "Lchip/setuppayload/DiscoveryCapability;");
+ jobject onNetworkObj = env->GetStaticObjectField(capabilityEnum, onNetworkCapability);
+ contains = env->CallBooleanMethod(discoveryCapabilitiesObj, hashSetContainsMethod, onNetworkObj);
+ if (contains)
+ {
+ flags.Set(chip::RendezvousInformationFlag::kOnNetwork);
+ }
+}
+
CHIP_ERROR ThrowUnrecognizedQRCodeException(JNIEnv * env, jstring qrCodeObj)
{
jclass exceptionCls = nullptr;
diff --git a/src/setup_payload/java/src/chip/setuppayload/SetupPayloadParser.java b/src/setup_payload/java/src/chip/setuppayload/SetupPayloadParser.java
index 1277408..b1ba720 100644
--- a/src/setup_payload/java/src/chip/setuppayload/SetupPayloadParser.java
+++ b/src/setup_payload/java/src/chip/setuppayload/SetupPayloadParser.java
@@ -14,6 +14,13 @@
return fetchPayloadFromManualEntryCode(entryCodeString);
}
+ /** Get QR code string from {@link SetupPayload}. */
+ public native String getQrCodeFromPayload(SetupPayload payload) throws SetupPayloadException;
+
+ /** Get manual entry code string from {@link SetupPayload}. */
+ public native String getManualEntryCodeFromPayload(SetupPayload payload)
+ throws SetupPayloadException;
+
private native SetupPayload fetchPayloadFromQrCode(String qrCodeString)
throws UnrecognizedQrCodeException;
@@ -39,4 +46,14 @@
super(String.format("Invalid format for entry code string: %s", entryCode), null);
}
}
+
+ public static class SetupPayloadException extends Exception {
+ private static final long serialVersionUID = 1L;
+ public int errorCode;
+
+ public SetupPayloadException(int errorCode, String message) {
+ super(message != null ? message : String.format("Error Code %d", errorCode));
+ this.errorCode = errorCode;
+ }
+ }
}