diff --git a/BUILD.gn b/BUILD.gn index 3753f041730c4a..57d4f38b76ce10 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -125,6 +125,7 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") { 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 9101fbb69746ae..d26edebaf3a929 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn @@ -435,6 +435,11 @@ config("size_default") { "-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 00000000000000..d071cdc16769d8 --- /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 00000000000000..f599b71645b8cc --- /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 +#include +#include +#include +#include +#include +#include + +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 00000000000000..7e1be63107c061 --- /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 +#include +#include +#include + +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 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 00000000000000..bdea7a71c2b6f3 --- /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 + +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 00000000000000..e3c893f40f8ad1 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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(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 00000000000000..d8c8d21a51031a --- /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 +#include + +#include "../endpoint-configuration/EndpointConfigurationStorage.h" +#include "Application.h" +#include + +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 00000000000000..f193ce3d6895f6 --- /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 +#include +#include +#include +#include + +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 00000000000000..718321e16b5ce0 --- /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 +#include + +#include +#include + +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 00000000000000..61018e7417424d --- /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 +#include +#include +#include +#include + +#include +#include + +using namespace std; + +CHIP_ERROR AudioOutputManager::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // TODO: Store feature map once it is supported + map 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(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 00000000000000..63d455427e68ae --- /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 + +#include +#include +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 00000000000000..b82682e4ea9e9f --- /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 +#include +#include +#include + +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 00000000000000..3d7bee4a9cfb48 --- /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 +#include +#include +#include +#include +#include +#include + +using namespace chip; + +namespace { +template +class TvAttrAccess : public app::AttributeAccessInterface +{ +public: + TvAttrAccess() : app::AttributeAccessInterface(Optional::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 + 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 + 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 + 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::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 + 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 + 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 00000000000000..001fe840623d32 --- /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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace std; + +CHIP_ERROR ContentLauncherManager::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // TODO: Store feature map once it is supported + map 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 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(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 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 00000000000000..285e521e889934 --- /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 +#include + +#include +#include +#include +#include +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 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 00000000000000..af4eb313573713 --- /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 +#include + +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) - 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 00000000000000..cea787b1bdda0c --- /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 +#include +#include + +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 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 00000000000000..7cca7457aa40f6 --- /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 00000000000000..58a39ab91bb6b4 --- /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 +#include + +#include +#include + +using namespace std; + +CHIP_ERROR KeypadInputManager::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // TODO: Store feature map once it is supported + map 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 00000000000000..d55161a5e1cad4 --- /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 + +#include +#include + +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 00000000000000..2b53d45a7f737e --- /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 + +#include +#include +#include +#include +#include + +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 00000000000000..97016d4b01a74f --- /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 00000000000000..75d500ca12de74 --- /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 + +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 00000000000000..bb8dbf2f255a31 --- /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 +#include +#include +#include +#include +#include + +CHIP_ERROR MediaInputManager::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // TODO: Store feature map once it is supported + std::map 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(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 00000000000000..6a88c3b032b44b --- /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 + +#include +#include +#include + +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 00000000000000..3146f0c3d79036 --- /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 +#include +#include + +#include +#include + +using namespace std; + +CHIP_ERROR MediaPlaybackManager::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // TODO: Store feature map once it is supported + map 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 00000000000000..e90601e6d6a99c --- /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 +#include +#include + +#include + +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 00000000000000..bb15476209d9b6 --- /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 +#include +#include +#include +#include +#include + +#include +#include + +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(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 00000000000000..2aa604611f740d --- /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 + +#include +#include +#include + +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 00000000000000..5d5a1ead456e6d --- /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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace chip; + +CHIP_ERROR TvChannelManager::Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + // TODO: Store feature map once it is supported + std::map 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(1 + i); + channelInfo.minorNumber = static_cast(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 00000000000000..aaf78b8deec744 --- /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 + +#include +#include +#include + +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 00000000000000..3072b0e3928f30 --- /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 +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +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(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 00000000000000..2f0cca32df737e --- /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 +#include + +#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 c11fe42ee13791..d839e7c5bbf513 100644 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -190,6 +190,7 @@ def AndroidTargets(): 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 cc2901b59980fc..74d47e44850045 100644 --- a/scripts/build/builders/android.py +++ b/scripts/build/builders/android.py @@ -65,15 +65,24 @@ def IsIde(self): 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 @@ def generate(self): 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' - - args = '--args=%s' % (' '.join([ - '%s="%s"' % (key, shlex.quote(value)) - for key, value in gn_args.items() - ])) + gn_args['chip_use_clusters_for_ip_commissioning'] = True + gn_args.update(self.app.AppGnArgs()) + + 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 @@ def _build(self): # # 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 03c247dc42e7b0..275483b51aeccd 100644 --- a/scripts/build/testdata/all_targets_except_host.txt +++ b/scripts/build/testdata/all_targets_except_host.txt @@ -6,6 +6,7 @@ android-androidstudio-x86-chip-tool 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 3f785fbe107712..182bc6305d9efa 100644 --- a/scripts/build/testdata/build_all_except_host.txt +++ b/scripts/build/testdata/build_all_except_host.txt @@ -11,7 +11,7 @@ python3 build/chip/java/tests/generate_jars_for_test.py 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 build/chip/java/tests/generate_jars_for_test.py 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 build/chip/java/tests/generate_jars_for_test.py 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 build/chip/java/tests/generate_jars_for_test.py 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 build/chip/java/tests/generate_jars_for_test.py 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 build/chip/java/tests/generate_jars_for_test.py 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 build/chip/java/tests/generate_jars_for_test.py 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 build/chip/java/tests/generate_jars_for_test.py 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 build/chip/java/tests/generate_jars_for_test.py 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/libCHIPController.so {root}/s 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/libCHIPController.so {root}/s 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/libCHIPController.so {root}/s 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/libCHIPController.so {root}/src/an 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/libCHIPController.so {root}/src/andro 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 a5e973ae56bad5..de84e94876a792 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-androidstudio-x86-chip-tool 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 00000000000000..d59e52c6fd3f22 --- /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 00000000000000..26d33521af10bc --- /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 00000000000000..fb7f4a8a465d42 --- /dev/null +++ b/src/android/CHIPTVServer/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ 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 00000000000000..526b4c25c6813e --- /dev/null +++ b/src/android/CHIPTVServer/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ 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 00000000000000..2a4d5b521db9a0 --- /dev/null +++ b/src/android/CHIPTVServer/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ 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 00000000000000..797acea53eb091 --- /dev/null +++ b/src/android/CHIPTVServer/.idea/runConfigurations.xml @@ -0,0 +1,10 @@ + + + + + + \ 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 00000000000000..c2365ab11f9ba6 --- /dev/null +++ b/src/android/CHIPTVServer/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ 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 00000000000000..42afabfd2abebf --- /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 00000000000000..9217e7226246ce --- /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 00000000000000..e99f16575f4f27 --- /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 00000000000000..c35dd628b566c2 --- /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 00000000000000..481bb434814107 --- /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 00000000000000..9bd1c270ec6c1a --- /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 Testing documentation + */ +@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 00000000000000..383830aaf0b8b9 --- /dev/null +++ b/src/android/CHIPTVServer/app/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + \ 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 00000000000000..6fcde199cc60c0 --- /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 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 00000000000000..7a408c233fd2fa --- /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 00000000000000..2b068d11462a4b --- /dev/null +++ b/src/android/CHIPTVServer/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ 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 00000000000000..07d5da9cbf1419 --- /dev/null +++ b/src/android/CHIPTVServer/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 00000000000000..65b4ee55984ea5 --- /dev/null +++ b/src/android/CHIPTVServer/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,35 @@ + + + + + + + + + + \ 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 00000000000000..eca70cfe52eac1 --- /dev/null +++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ 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 00000000000000..eca70cfe52eac1 --- /dev/null +++ b/src/android/CHIPTVServer/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ 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 00000000000000..c209e78ecd3723 Binary files /dev/null and b/src/android/CHIPTVServer/app/src/main/res/mipmap-hdpi/ic_launcher.webp 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 00000000000000..b2dfe3d1ba5cf3 Binary files /dev/null and b/src/android/CHIPTVServer/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp 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 00000000000000..4f0f1d64e58ba6 Binary files /dev/null and b/src/android/CHIPTVServer/app/src/main/res/mipmap-mdpi/ic_launcher.webp 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 00000000000000..62b611da081676 Binary files /dev/null and b/src/android/CHIPTVServer/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp 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 00000000000000..948a3070fe34c6 Binary files /dev/null and b/src/android/CHIPTVServer/app/src/main/res/mipmap-xhdpi/ic_launcher.webp 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 00000000000000..1b9a6956b3acdc Binary files /dev/null and b/src/android/CHIPTVServer/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp 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 00000000000000..28d4b77f9f036a Binary files /dev/null and b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp 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 00000000000000..9287f5083623b3 Binary files /dev/null and b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp 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 00000000000000..aa7d6427e6fa10 Binary files /dev/null and b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp 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 00000000000000..9126ae37cbc358 Binary files /dev/null and b/src/android/CHIPTVServer/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp 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 00000000000000..da91ed13dc5579 --- /dev/null +++ b/src/android/CHIPTVServer/app/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ 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 00000000000000..f8c6127d327620 --- /dev/null +++ b/src/android/CHIPTVServer/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ 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 00000000000000..a2cc2fe8dff5fe --- /dev/null +++ b/src/android/CHIPTVServer/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + CHIPTVServer + \ 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 00000000000000..3e95998b6438ba --- /dev/null +++ b/src/android/CHIPTVServer/app/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ 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 00000000000000..6ee6449bb56acc --- /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 Testing documentation + */ +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 00000000000000..79c656c2ab4cc1 --- /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 00000000000000..e94cae88f85eaa --- /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 00000000000000..e708b1c023ec8b Binary files /dev/null and b/src/android/CHIPTVServer/gradle/wrapper/gradle-wrapper.jar 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 00000000000000..da67dc800c423c --- /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 00000000000000..180cdce0308183 --- /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 00000000000000..f9553162f122c7 --- /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 00000000000000..8392989d7bc70a --- /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 00000000000000..18f1c2c019761b --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 00000000000000..ae544754e2bdb3 --- /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 + +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 00000000000000..d4170c2f6f1d93 --- /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 00000000000000..777a4755794ea8 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 00000000000000..6d9bb3a884bddb --- /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 00000000000000..08e11d15fce99a --- /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 f1f0fc327a8db9..408d199d09b3b7 100644 --- a/src/controller/CHIPDevice.h +++ b/src/controller/CHIPDevice.h @@ -105,7 +105,7 @@ typedef void (*OnDeviceConnected)(void * context, Device * device); 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 @@ class DLL_EXPORT Device : public Messaging::ExchangeDelegate, public SessionEsta * 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 d293fb0ace44b5..7a5c78e20560c9 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.cpp +++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp @@ -213,7 +213,9 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(Jav 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 6bd724813d9ae8..f627e30b3f70f9 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -42,6 +42,8 @@ shared_library("jni") { 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 85409763484244..4d087beff445f0 100644 --- a/src/controller/java/CHIPDeviceController-JNI.cpp +++ b/src/controller/java/CHIPDeviceController-JNI.cpp @@ -59,9 +59,7 @@ using namespace chip::Controller; #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 @@ jint JNI_OnLoad(JavaVM * jvm, void * reserved) 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 @@ JNI_METHOD(jlong, newDeviceController)(JNIEnv * env, jobject self) if (err != CHIP_JNI_ERROR_EXCEPTION_THROWN) { - ThrowError(env, err); + JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } @@ -193,7 +191,9 @@ JNI_METHOD(void, pairDevice) RendezvousParameters params = RendezvousParameters() .SetSetupPINCode(pinCode) +#if CONFIG_NETWORK_LAYER_BLE .SetConnectionObject(reinterpret_cast(connObj)) +#endif .SetPeerAddress(Transport::PeerAddress::BLE()); if (csrNonce != nullptr) { @@ -205,7 +205,7 @@ JNI_METHOD(void, pairDevice) 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 @@ JNI_METHOD(void, pairDeviceWithAddress) 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 @@ JNI_METHOD(void, pairDeviceWithAddress) 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 @@ JNI_METHOD(void, unpairDevice)(JNIEnv * env, jobject self, jlong handle, jlong d 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 @@ JNI_METHOD(void, stopDevicePairing)(JNIEnv * env, jobject self, jlong handle, jl 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 @@ JNI_METHOD(jstring, getIpAddress)(JNIEnv * env, jobject self, jlong handle, jlon 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 @@ JNI_METHOD(void, updateDevice)(JNIEnv * env, jobject self, jlong handle, jlong f if (err != CHIP_NO_ERROR) { ChipLogError(Controller, "Failed to update device"); - ThrowError(env, err); + JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } } @@ -451,7 +452,7 @@ JNI_METHOD(jobject, computePaseVerifier) exit: if (err != CHIP_NO_ERROR) { - ThrowError(env, err); + JniReferences::GetInstance().ThrowError(env, sChipDeviceControllerExceptionCls, err); } return nullptr; } @@ -482,18 +483,6 @@ void * IOThreadMain(void * arg) 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 @@ CHIP_ERROR N2J_PaseVerifierParams(JNIEnv * env, jlong setupPincode, jint passcod 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, "", "(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(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 69156a38dd5477..3b5c367ab67499 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp +++ b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.cpp @@ -56,8 +56,6 @@ System::LayerSocketsLoop & SystemLayerSocketsLoop() template CHIP_ERROR GenericPlatformManagerImpl_POSIX::_InitChipStack() { - mChipStackLock = PTHREAD_MUTEX_INITIALIZER; - // Call up to the base class _InitChipStack() to perform the bulk of the initialization. ReturnErrorOnFailure(GenericPlatformManagerImpl::_InitChipStack()); @@ -104,6 +102,10 @@ template void GenericPlatformManagerImpl_POSIX::_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 e2d5fee518eae5..a791c67a953527 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.h +++ b/src/include/platform/internal/GenericPlatformManagerImpl_POSIX.h @@ -53,7 +53,7 @@ class GenericPlatformManagerImpl_POSIX : public GenericPlatformManagerImpl #include #include #include @@ -169,4 +170,17 @@ void JniReferences::ReportError(JNIEnv * env, CHIP_ERROR cbErr, const char * fun } } +void JniReferences::ThrowError(JNIEnv * env, jclass exceptionCls, CHIP_ERROR errToThrow) +{ + env->ExceptionClear(); + jmethodID constructor = env->GetMethodID(exceptionCls, "", "(ILjava/lang/String;)V"); + VerifyOrReturn(constructor != NULL); + + jstring jerrStr = env->NewStringUTF(ErrorStr(errToThrow)); + + jthrowable outEx = (jthrowable) env->NewObject(exceptionCls, constructor, static_cast(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 5e8cbe6f319200..ed0ede5970ae88 100644 --- a/src/lib/support/JniReferences.h +++ b/src/lib/support/JniReferences.h @@ -78,6 +78,8 @@ class JniReferences 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 bd1bbca4ac7a80..785ed89cb42638 100644 --- a/src/platform/android/AndroidChipPlatform-JNI.cpp +++ b/src/platform/android/AndroidChipPlatform-JNI.cpp @@ -43,9 +43,9 @@ using namespace chip; #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 @@ CHIP_ERROR AndroidChipPlatformJNI_OnLoad(JavaVM * jvm, void * reserved) 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, nativeSetBLEManager)(JNIEnv *, jobject, jobject manager) 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(conn); @@ -119,11 +120,13 @@ JNI_METHOD(void, handleWriteConfirmation) 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(conn); const auto valueBegin = env->GetByteArrayElements(value, nullptr); @@ -144,11 +147,13 @@ JNI_METHOD(void, handleIndicationReceived) 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(conn); @@ -160,11 +165,13 @@ JNI_METHOD(void, handleSubscribeComplete) 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(conn); @@ -176,14 +183,17 @@ JNI_METHOD(void, handleUnsubscribeComplete) 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(conn); chip::DeviceLayer::Internal::BLEMgrImpl().HandleConnectionError(connObj, BLE_ERROR_APP_CLOSED_CONNECTION); +#endif } // for KeyValueStoreManager @@ -215,58 +225,7 @@ JNI_MDNSCALLBACK_METHOD(void, handleServiceResolve) 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, "", "(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(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 @@ static bool JavaBytesToUUID(JNIEnv * env, jbyteArray value, chip::Ble::ChipBleUU 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 b08686580fac02..f5bb8553466d4e 100644 --- a/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java +++ b/src/platform/android/java/chip/platform/NsdManagerServiceResolver.java @@ -149,12 +149,12 @@ public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode) { @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 5821aa1c87e95a..0cc1010ae8a1b6 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 #include +#include #include #include #include +#include #include #include @@ -23,6 +28,8 @@ using namespace chip; 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 @@ jobject CreateCapabilitiesHashSet(JNIEnv * env, RendezvousInformationFlags flags 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(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 12774081447f5d..b1ba72090c5ab2 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 @@ public SetupPayload parseManualEntryCode(String entryCodeString) 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 @@ public InvalidEntryCodeFormatException(String entryCode) { 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; + } + } }