From d88e7c9edea2e9af0ddcea468995d024d996cc40 Mon Sep 17 00:00:00 2001 From: "Hui.Li-TCL" Date: Thu, 25 Nov 2021 02:03:36 +0800 Subject: [PATCH] Wakeonlan and media input cluster to android (#12142) * added WakeOnLanManager into java * added MediaInputManager into java * fix GetCurrentInput encode error * Restyled by whitespace * Restyled by google-java-format * Restyled by clang-format * Restyled by gn * fix rebase issue Co-authored-by: Restyled.io --- examples/tv-app/android/App/app/build.gradle | 2 +- .../tcl/chip/chiptvserver/MainActivity.java | 4 + examples/tv-app/android/BUILD.gn | 13 +- .../tv-app/android/include/cluster-init.cpp | 55 --- .../include/media-input/MediaInputManager.cpp | 80 ---- .../include/media-input/MediaInputManager.h | 32 -- .../include/wake-on-lan/WakeOnLanManager.cpp | 73 ---- .../tv-app/android/java/MediaInputManager.cpp | 352 ++++++++++++++++++ .../tv-app/android/java/MediaInputManager.h | 52 +++ examples/tv-app/android/java/TVApp-JNI.cpp | 12 + .../tv-app/android/java/WakeOnLanManager.cpp | 104 ++++++ .../wake-on-lan => java}/WakeOnLanManager.h | 25 +- .../com/tcl/chip/tvapp/MediaInputInfo.java | 51 +++ .../com/tcl/chip/tvapp/MediaInputManager.java | 49 +++ .../tcl/chip/tvapp/MediaInputManagerStub.java | 71 ++++ .../java/src/com/tcl/chip/tvapp/TvApp.java | 4 + .../com/tcl/chip/tvapp/WakeOnLanManager.java | 28 ++ .../tcl/chip/tvapp/WakeOnLanManagerStub.java | 14 + scripts/examples/gn_android_example.sh | 2 +- 19 files changed, 765 insertions(+), 258 deletions(-) delete mode 100644 examples/tv-app/android/include/media-input/MediaInputManager.cpp delete mode 100644 examples/tv-app/android/include/media-input/MediaInputManager.h delete mode 100644 examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.cpp create mode 100644 examples/tv-app/android/java/MediaInputManager.cpp create mode 100644 examples/tv-app/android/java/MediaInputManager.h create mode 100644 examples/tv-app/android/java/WakeOnLanManager.cpp rename examples/tv-app/android/{include/wake-on-lan => java}/WakeOnLanManager.h (66%) create mode 100755 examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputInfo.java create mode 100755 examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputManager.java create mode 100755 examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputManagerStub.java create mode 100644 examples/tv-app/android/java/src/com/tcl/chip/tvapp/WakeOnLanManager.java create mode 100644 examples/tv-app/android/java/src/com/tcl/chip/tvapp/WakeOnLanManagerStub.java diff --git a/examples/tv-app/android/App/app/build.gradle b/examples/tv-app/android/App/app/build.gradle index 8c66ebcb42b815..128e1438b79bb1 100644 --- a/examples/tv-app/android/App/app/build.gradle +++ b/examples/tv-app/android/App/app/build.gradle @@ -46,6 +46,7 @@ android { // 'src/main/java', // '../../third_party/connectedhomeip/src/setup_payload/java/src', // '../../third_party/connectedhomeip/src/platform/android/java', +// '../../third_party/connectedhomeip/src/app/server/java/src/', // '../../java/src', // ] } @@ -57,7 +58,6 @@ dependencies { 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' diff --git a/examples/tv-app/android/App/app/src/main/java/com/tcl/chip/chiptvserver/MainActivity.java b/examples/tv-app/android/App/app/src/main/java/com/tcl/chip/chiptvserver/MainActivity.java index 53177ccd8ef420..9d51e2ff71492e 100644 --- a/examples/tv-app/android/App/app/src/main/java/com/tcl/chip/chiptvserver/MainActivity.java +++ b/examples/tv-app/android/App/app/src/main/java/com/tcl/chip/chiptvserver/MainActivity.java @@ -16,7 +16,9 @@ import chip.setuppayload.SetupPayload; import chip.setuppayload.SetupPayloadParser; import com.tcl.chip.tvapp.KeypadInputManagerStub; +import com.tcl.chip.tvapp.MediaInputManagerStub; import com.tcl.chip.tvapp.TvApp; +import com.tcl.chip.tvapp.WakeOnLanManagerStub; import java.util.HashSet; public class MainActivity extends AppCompatActivity { @@ -34,6 +36,8 @@ protected void onCreate(Bundle savedInstanceState) { mManualPairingCodeTxt = findViewById(R.id.manualPairingCodeTxt); TvApp tvApp = new TvApp(); tvApp.setKeypadInputManager(new KeypadInputManagerStub()); + tvApp.setWakeOnLanManager(new WakeOnLanManagerStub()); + tvApp.setMediaInputManager(new MediaInputManagerStub()); AndroidChipPlatform chipPlatform = new AndroidChipPlatform( diff --git a/examples/tv-app/android/BUILD.gn b/examples/tv-app/android/BUILD.gn index d18ec637558f2b..c7da6f1190a258 100644 --- a/examples/tv-app/android/BUILD.gn +++ b/examples/tv-app/android/BUILD.gn @@ -40,19 +40,19 @@ shared_library("jni") { "include/endpoint-configuration/EndpointConfigurationStorage.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", "java/KeypadInputManager.cpp", "java/KeypadInputManager.h", + "java/MediaInputManager.cpp", + "java/MediaInputManager.h", "java/TVApp-JNI.cpp", + "java/WakeOnLanManager.cpp", + "java/WakeOnLanManager.h", ] deps = [ @@ -85,7 +85,12 @@ android_library("java") { sources = [ "java/src/com/tcl/chip/tvapp/KeypadInputManager.java", "java/src/com/tcl/chip/tvapp/KeypadInputManagerStub.java", + "java/src/com/tcl/chip/tvapp/MediaInputInfo.java", + "java/src/com/tcl/chip/tvapp/MediaInputManager.java", + "java/src/com/tcl/chip/tvapp/MediaInputManagerStub.java", "java/src/com/tcl/chip/tvapp/TvApp.java", + "java/src/com/tcl/chip/tvapp/WakeOnLanManager.java", + "java/src/com/tcl/chip/tvapp/WakeOnLanManagerStub.java", ] javac_flags = [ "-Xlint:deprecation" ] diff --git a/examples/tv-app/android/include/cluster-init.cpp b/examples/tv-app/android/include/cluster-init.cpp index aba5cafad51f2e..2ef9a280110e15 100644 --- a/examples/tv-app/android/include/cluster-init.cpp +++ b/examples/tv-app/android/include/cluster-init.cpp @@ -20,10 +20,8 @@ #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 @@ -80,32 +78,6 @@ void emberAfApplicationBasicClusterInitCallback(chip::EndpointId endpoint) } } -/** @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 - 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; diff --git a/examples/tv-app/android/include/media-input/MediaInputManager.cpp b/examples/tv-app/android/include/media-input/MediaInputManager.cpp deleted file mode 100644 index bb8dbf2f255a31..00000000000000 --- a/examples/tv-app/android/include/media-input/MediaInputManager.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/** - * - * 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 deleted file mode 100644 index 6a88c3b032b44b..00000000000000 --- a/examples/tv-app/android/include/media-input/MediaInputManager.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * - * 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/wake-on-lan/WakeOnLanManager.cpp b/examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.cpp deleted file mode 100644 index 3072b0e3928f30..00000000000000 --- a/examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * 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/java/MediaInputManager.cpp b/examples/tv-app/android/java/MediaInputManager.cpp new file mode 100644 index 00000000000000..9c3e2bcab8bdbf --- /dev/null +++ b/examples/tv-app/android/java/MediaInputManager.cpp @@ -0,0 +1,352 @@ +/** + * + * 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 +#include +#include +#include +#include +#include + +using namespace chip; + +MediaInputManager MediaInputManager::sInstance; + +class MediaInputAttrAccess : public app::AttributeAccessInterface +{ +public: + MediaInputAttrAccess() : app::AttributeAccessInterface(Optional::Missing(), app::Clusters::MediaInput::Id) {} + + CHIP_ERROR Read(const app::ConcreteReadAttributePath & aPath, app::AttributeValueEncoder & aEncoder) override + { + if (aPath.mAttributeId == app::Clusters::MediaInput::Attributes::MediaInputList::Id) + { + return MediaInputMgr().GetInputList(aEncoder); + } + else if (aPath.mAttributeId == app::Clusters::MediaInput::Attributes::CurrentMediaInput::Id) + { + return MediaInputMgr().GetCurrentInput(aEncoder); + } + + return CHIP_NO_ERROR; + } +}; + +MediaInputAttrAccess gMediaInputAttrAccess; + +/** @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; + } +} + +bool mediaInputClusterSelectInput(uint8_t input) +{ + return MediaInputMgr().SelectInput(input); +} + +bool mediaInputClusterShowInputStatus() +{ + return MediaInputMgr().ShowInputStatus(); +} + +bool mediaInputClusterHideInputStatus() +{ + return MediaInputMgr().HideInputStatus(); +} + +bool mediaInputClusterRenameInput(uint8_t input, std::string name) +{ + return MediaInputMgr().RenameInput(input, name); +} + +CHIP_ERROR MediaInputManager::GetInputList(app::AttributeValueEncoder & aEncoder) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + ChipLogProgress(Zcl, "Received MediaInputManager::GetInputList"); + VerifyOrExit(mMediaInputManagerObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mGetInputListMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); + + return aEncoder.EncodeList([this, env](const app::TagBoundEncoder & encoder) -> CHIP_ERROR { + jobjectArray inputArray = (jobjectArray) env->CallObjectMethod(mMediaInputManagerObject, mGetInputListMethod); + if (env->ExceptionCheck()) + { + ChipLogError(AppServer, "Java exception in MediaInputManager::GetInputList"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INCORRECT_STATE; + } + + jint size = env->GetArrayLength(inputArray); + for (int i = 0; i < size; i++) + { + app::Clusters::MediaInput::Structs::MediaInputInfo::Type mediaInput; + + jobject inputObj = env->GetObjectArrayElement(inputArray, i); + jclass inputClass = env->GetObjectClass(inputObj); + + jfieldID indexId = env->GetFieldID(inputClass, "index", "I"); + jint index = env->GetIntField(inputObj, indexId); + mediaInput.index = static_cast(index); + + jfieldID typeId = env->GetFieldID(inputClass, "type", "I"); + jint type = env->GetIntField(inputObj, typeId); + mediaInput.inputType = static_cast(type); + + jfieldID nameId = env->GetFieldID(inputClass, "name", "Ljava/lang/String;"); + jstring jname = static_cast(env->GetObjectField(inputObj, nameId)); + + if (jname != NULL) + { + JniUtfString name(env, jname); + mediaInput.name = name.charSpan(); + } + + jfieldID descriptionId = env->GetFieldID(inputClass, "description", "Ljava/lang/String;"); + jstring jdescription = static_cast(env->GetObjectField(inputObj, descriptionId)); + + if (jdescription != NULL) + { + JniUtfString description(env, jdescription); + mediaInput.description = description.charSpan(); + } + + ReturnErrorOnFailure(encoder.Encode(mediaInput)); + } + + return CHIP_NO_ERROR; + }); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "MediaInputManager::GetInputList status error: %s", err.AsString()); + } + + return err; +} + +CHIP_ERROR MediaInputManager::GetCurrentInput(chip::app::AttributeValueEncoder & aEncoder) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + jint index = -1; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + ChipLogProgress(Zcl, "Received MediaInputManager::GetInputList"); + VerifyOrExit(mMediaInputManagerObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mGetCurrentInputMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); + + index = env->CallIntMethod(mMediaInputManagerObject, mGetCurrentInputMethod); + if (env->ExceptionCheck()) + { + ChipLogError(AppServer, "Java exception in MediaInputManager::GetCurrentInput"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INCORRECT_STATE; + } + + ChipLogProgress(Zcl, "GetCurrentInput = %d", index); + if (index >= 0) + { + err = aEncoder.Encode(uint8_t(index)); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "MediaInputManager::GetCurrentInput status error: %s", err.AsString()); + } + + return err; +} + +bool MediaInputManager::SelectInput(uint8_t index) +{ + jboolean ret = JNI_FALSE; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + ChipLogProgress(Zcl, "Received MediaInputManager::SelectInput %d", index); + VerifyOrExit(mMediaInputManagerObject != nullptr, ChipLogError(Zcl, "mMediaInputManagerObject null")); + VerifyOrExit(mSelectInputMethod != nullptr, ChipLogError(Zcl, "mSelectInputMethod null")); + VerifyOrExit(env != NULL, ChipLogError(Zcl, "env null")); + + env->ExceptionClear(); + ret = env->CallBooleanMethod(mMediaInputManagerObject, mSelectInputMethod, static_cast(index)); + if (env->ExceptionCheck()) + { + ChipLogError(DeviceLayer, "Java exception in MediaInputManager::selectInput"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return false; + } + +exit: + return static_cast(ret); +} + +bool MediaInputManager::ShowInputStatus() +{ + jboolean ret = JNI_FALSE; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + ChipLogProgress(Zcl, "Received MediaInputManager::ShowInputStatus"); + VerifyOrExit(mMediaInputManagerObject != nullptr, ChipLogError(Zcl, "mMediaInputManagerObject null")); + VerifyOrExit(mShowInputStatusMethod != nullptr, ChipLogError(Zcl, "mShowInputStatusMethod null")); + VerifyOrExit(env != NULL, ChipLogError(Zcl, "env null")); + + env->ExceptionClear(); + ret = env->CallBooleanMethod(mMediaInputManagerObject, mShowInputStatusMethod); + if (env->ExceptionCheck()) + { + ChipLogError(DeviceLayer, "Java exception in MediaInputManager::showInputStatus"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return false; + } + +exit: + return static_cast(ret); +} + +bool MediaInputManager::HideInputStatus() +{ + jboolean ret = JNI_FALSE; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + ChipLogProgress(Zcl, "Received MediaInputManager::HideInputStatus"); + VerifyOrExit(mMediaInputManagerObject != nullptr, ChipLogError(Zcl, "mMediaInputManagerObject null")); + VerifyOrExit(mHideInputStatusMethod != nullptr, ChipLogError(Zcl, "mHideInputStatusMethod null")); + VerifyOrExit(env != NULL, ChipLogError(Zcl, "env null")); + + env->ExceptionClear(); + ret = env->CallBooleanMethod(mMediaInputManagerObject, mHideInputStatusMethod); + if (env->ExceptionCheck()) + { + ChipLogError(DeviceLayer, "Java exception in MediaInputManager::HideInputStatus"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return false; + } + +exit: + return static_cast(ret); +} + +bool MediaInputManager::RenameInput(uint8_t index, std::string name) +{ + jboolean ret = JNI_FALSE; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + ChipLogProgress(Zcl, "Received MediaInputManager::RenameInput %d to %s", index, name.c_str()); + VerifyOrExit(mMediaInputManagerObject != nullptr, ChipLogError(Zcl, "mMediaInputManagerObject null")); + VerifyOrExit(mRenameInputMethod != nullptr, ChipLogError(Zcl, "mHideInputStatusMethod null")); + VerifyOrExit(env != NULL, ChipLogError(Zcl, "env null")); + + { + UtfString jniInputname(env, name.c_str()); + env->ExceptionClear(); + ret = + env->CallBooleanMethod(mMediaInputManagerObject, mRenameInputMethod, static_cast(index), jniInputname.jniValue()); + if (env->ExceptionCheck()) + { + ChipLogError(DeviceLayer, "Java exception in MediaInputManager::RenameInput"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return false; + } + } + +exit: + return static_cast(ret); +} + +void MediaInputManager::InitializeWithObjects(jobject managerObject) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for MediaInputManager")); + + mMediaInputManagerObject = env->NewGlobalRef(managerObject); + VerifyOrReturn(mMediaInputManagerObject != nullptr, ChipLogError(Zcl, "Failed to NewGlobalRef MediaInputManager")); + + jclass MediaInputManagerClass = env->GetObjectClass(managerObject); + VerifyOrReturn(MediaInputManagerClass != nullptr, ChipLogError(Zcl, "Failed to get MediaInputManager Java class")); + + mGetInputListMethod = env->GetMethodID(MediaInputManagerClass, "getInputList", "()[Lcom/tcl/chip/tvapp/MediaInputInfo;"); + if (mGetInputListMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MediaInputManager 'getInputList' method"); + env->ExceptionClear(); + } + + mGetCurrentInputMethod = env->GetMethodID(MediaInputManagerClass, "getCurrentInput", "()I"); + if (mGetCurrentInputMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MediaInputManager 'getCurrentInput' method"); + env->ExceptionClear(); + } + + mSelectInputMethod = env->GetMethodID(MediaInputManagerClass, "selectInput", "(I)Z"); + if (mSelectInputMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MediaInputManager 'selectInput' method"); + env->ExceptionClear(); + } + + mShowInputStatusMethod = env->GetMethodID(MediaInputManagerClass, "showInputStatus", "()Z"); + if (mShowInputStatusMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MediaInputManager 'showInputStatus' method"); + env->ExceptionClear(); + } + + mHideInputStatusMethod = env->GetMethodID(MediaInputManagerClass, "hideInputStatus", "()Z"); + if (mHideInputStatusMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MediaInputManager 'hideInputStatus' method"); + env->ExceptionClear(); + } + + mRenameInputMethod = env->GetMethodID(MediaInputManagerClass, "renameInput", "(ILjava/lang/String;)Z"); + if (mRenameInputMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MediaInputManager 'renameInput' method"); + env->ExceptionClear(); + } +} diff --git a/examples/tv-app/android/java/MediaInputManager.h b/examples/tv-app/android/java/MediaInputManager.h new file mode 100644 index 00000000000000..8a031fa0efcd57 --- /dev/null +++ b/examples/tv-app/android/java/MediaInputManager.h @@ -0,0 +1,52 @@ +/* + * + * 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 MediaInputManager +{ +public: + void InitializeWithObjects(jobject managerObject); + CHIP_ERROR GetInputList(chip::app::AttributeValueEncoder & aEncoder); + CHIP_ERROR GetCurrentInput(chip::app::AttributeValueEncoder & aEncoder); + bool SelectInput(uint8_t index); + bool ShowInputStatus(); + bool HideInputStatus(); + bool RenameInput(uint8_t index, std::string name); + +private: + friend MediaInputManager & MediaInputMgr(); + + static MediaInputManager sInstance; + jobject mMediaInputManagerObject = nullptr; + jmethodID mGetInputListMethod = nullptr; + jmethodID mGetCurrentInputMethod = nullptr; + jmethodID mSelectInputMethod = nullptr; + jmethodID mShowInputStatusMethod = nullptr; + jmethodID mHideInputStatusMethod = nullptr; + jmethodID mRenameInputMethod = nullptr; +}; + +inline class MediaInputManager & MediaInputMgr() +{ + return MediaInputManager::sInstance; +} diff --git a/examples/tv-app/android/java/TVApp-JNI.cpp b/examples/tv-app/android/java/TVApp-JNI.cpp index 9cbb0461ce9d86..6b7b5310645d3d 100644 --- a/examples/tv-app/android/java/TVApp-JNI.cpp +++ b/examples/tv-app/android/java/TVApp-JNI.cpp @@ -17,6 +17,8 @@ */ #include "KeypadInputManager.h" +#include "MediaInputManager.h" +#include "WakeOnLanManager.h" #include #include #include @@ -38,3 +40,13 @@ JNI_METHOD(void, setKeypadInputManager)(JNIEnv *, jobject, jobject manager) { KeypadInputMgr().InitializeWithObjects(manager); } + +JNI_METHOD(void, setWakeOnLanManager)(JNIEnv *, jobject, jobject manager) +{ + WakeOnLanMgr().InitializeWithObjects(manager); +} + +JNI_METHOD(void, setMediaInputManager)(JNIEnv *, jobject, jobject manager) +{ + MediaInputMgr().InitializeWithObjects(manager); +} diff --git a/examples/tv-app/android/java/WakeOnLanManager.cpp b/examples/tv-app/android/java/WakeOnLanManager.cpp new file mode 100644 index 00000000000000..60b59c957b134d --- /dev/null +++ b/examples/tv-app/android/java/WakeOnLanManager.cpp @@ -0,0 +1,104 @@ +/* + * + * 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 +#include + +using namespace chip; +using namespace chip::app::Clusters; + +WakeOnLanManager WakeOnLanManager::sInstance; + +/** @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) +{ + WakeOnLanMgr().InitWakeOnLanCluster(endpoint); +} + +void WakeOnLanManager::InitWakeOnLanCluster(chip::EndpointId endpoint) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + ChipLogProgress(Zcl, "Received WakeOnLanManager::InitWakeOnLanCluster %d", endpoint); + VerifyOrReturn(mWakeOnLanManagerObject != nullptr, ChipLogError(Zcl, "mWakeOnLanManagerObject null")); + VerifyOrReturn(mGetMacMethod != nullptr, ChipLogError(Zcl, "mGetMacMethod null")); + VerifyOrReturn(env != NULL, ChipLogError(Zcl, "env null")); + + env->ExceptionClear(); + jobject javaMac = env->CallObjectMethod(mWakeOnLanManagerObject, mGetMacMethod, static_cast(endpoint)); + if (env->ExceptionCheck()) + { + ChipLogError(DeviceLayer, "Java exception in WakeOnLanManager::getMac"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return; + } + chip::JniUtfString macValue(env, static_cast(javaMac)); + + uint8_t bufferMemory[32]; + MutableByteSpan zclString(bufferMemory); + MakeZclCharString(zclString, macValue.c_str()); + + 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::InitializeWithObjects(jobject managerObject) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for WakeOnLanManager")); + + mWakeOnLanManagerObject = env->NewGlobalRef(managerObject); + VerifyOrReturn(mWakeOnLanManagerObject != nullptr, ChipLogError(Zcl, "Failed to NewGlobalRef WakeOnLanManager")); + + jclass WakeOnLanManagerClass = env->GetObjectClass(managerObject); + VerifyOrReturn(WakeOnLanManagerClass != nullptr, ChipLogError(Zcl, "Failed to get WakeOnLanManager Java class")); + + mGetMacMethod = env->GetMethodID(WakeOnLanManagerClass, "getMac", "(I)Ljava/lang/String;"); + if (mGetMacMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access WakeOnLanManager 'getMac' method"); + env->ExceptionClear(); + } +} diff --git a/examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.h b/examples/tv-app/android/java/WakeOnLanManager.h similarity index 66% rename from examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.h rename to examples/tv-app/android/java/WakeOnLanManager.h index 2f0cca32df737e..da622a8f54e873 100644 --- a/examples/tv-app/android/include/wake-on-lan/WakeOnLanManager.h +++ b/examples/tv-app/android/java/WakeOnLanManager.h @@ -19,23 +19,24 @@ #pragma once #include +#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; - } + void InitializeWithObjects(jobject managerObject); + void InitWakeOnLanCluster(chip::EndpointId endpoint); private: - EndpointConfigurationStorage * es = nullptr; + friend WakeOnLanManager & WakeOnLanMgr(); + + static WakeOnLanManager sInstance; + jobject mWakeOnLanManagerObject = nullptr; + jmethodID mGetMacMethod = nullptr; }; + +inline WakeOnLanManager & WakeOnLanMgr() +{ + return WakeOnLanManager::sInstance; +} diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputInfo.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputInfo.java new file mode 100755 index 00000000000000..8a9d1df972bed0 --- /dev/null +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputInfo.java @@ -0,0 +1,51 @@ +/* + * 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 com.tcl.chip.tvapp; + +public class MediaInputInfo { + + public static final int INPUT_TYPE_INTERNAL = 0; + public static final int INPUT_TYPE_AUX = 1; + public static final int INPUT_TYPE_COAX = 2; + public static final int INPUT_TYPE_COMPOSITE = 3; + public static final int INPUT_TYPE_HDMI = 4; + public static final int INPUT_TYPE_INPUT = 5; + public static final int INPUT_TYPE_LINE = 6; + public static final int INPUT_TYPE_OPTICAL = 7; + public static final int INPUT_TYPE_VIDEO = 8; + public static final int INPUT_TYPE_SCART = 9; + public static final int INPUT_TYPE_USB = 10; + public static final int INPUT_TYPE_OTHER = 11; + + /** The unique index into the list of Inputs. */ + public int index; + + /** The type of input in INPUT_TYPE_XXX */ + public int type; + + /** + * The input name, such as "HDMI 1". This field may be blank, but SHOULD be provided when known. + */ + public String name; + + /** + * The user editable input description, such as "Living room Playstation". This field may be + * blank, but SHOULD be provided when known. + */ + public String description; +} diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputManager.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputManager.java new file mode 100755 index 00000000000000..aef5e32e6da093 --- /dev/null +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputManager.java @@ -0,0 +1,49 @@ +/* + * 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 com.tcl.chip.tvapp; + +public interface MediaInputManager { + + /** Return media inputs supported by the device */ + MediaInputInfo[] getInputList(); + + /** @return The index field of the currently selected {@link MediaInputInfo} */ + int getCurrentInput(); + + /** + * change the media input on the device to the input at a specific index in the Input List. + * + * @param index The index in {@link MediaInputInfo} + */ + boolean selectInput(int index); + + /** Display the active status of the input list on screen. */ + boolean showInputStatus(); + + /** Hide the input list from the screen. */ + boolean hideInputStatus(); + + /** + * Rename the input at a specific index in the Input List. Updates to the input name SHALL appear + * in the device's settings menus. + * + * @param index The index in {@link MediaInputInfo} + * @param name The new input name + */ + boolean renameInput(int index, String name); +} diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputManagerStub.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputManagerStub.java new file mode 100755 index 00000000000000..e3c2919e36c512 --- /dev/null +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaInputManagerStub.java @@ -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. + * + */ +package com.tcl.chip.tvapp; + +import android.util.Log; + +public class MediaInputManagerStub implements MediaInputManager { + + private final String TAG = MediaInputManagerStub.class.getSimpleName(); + + @Override + public MediaInputInfo[] getInputList() { + MediaInputInfo[] info = new MediaInputInfo[2]; + info[0] = new MediaInputInfo(); + info[0].name = "HDMI 1"; + info[0].description = "Living room Playstation"; + info[0].index = 0; + info[0].type = MediaInputInfo.INPUT_TYPE_HDMI; + + info[1] = new MediaInputInfo(); + info[1].index = 1; + info[1].type = MediaInputInfo.INPUT_TYPE_HDMI; + + return info; + } + + @Override + public int getCurrentInput() { + Log.d(TAG, "getCurrentInput"); + return 1; + } + + @Override + public boolean selectInput(int index) { + Log.d(TAG, "selectInput:" + index); + return true; + } + + @Override + public boolean showInputStatus() { + Log.d(TAG, "showInputStatus"); + return true; + } + + @Override + public boolean hideInputStatus() { + Log.d(TAG, "hideInputStatus"); + return true; + } + + @Override + public boolean renameInput(int index, String name) { + Log.d(TAG, "renameInput index:" + index + " name:" + name); + return true; + } +} diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvApp.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvApp.java index 52c48fab24767b..9bb52cc1305014 100644 --- a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvApp.java +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvApp.java @@ -22,6 +22,10 @@ public TvApp() {} public native void setKeypadInputManager(KeypadInputManager manager); + public native void setWakeOnLanManager(WakeOnLanManager manager); + + public native void setMediaInputManager(MediaInputManager manager); + static { System.loadLibrary("TvApp"); } diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/WakeOnLanManager.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/WakeOnLanManager.java new file mode 100644 index 00000000000000..315408f164181a --- /dev/null +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/WakeOnLanManager.java @@ -0,0 +1,28 @@ +/* + * 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 com.tcl.chip.tvapp; + +public interface WakeOnLanManager { + + /** + * Get Wake On Lan Mac address for endpoint + * + * @return Mac address in AA:BB:CC:DD:EE + */ + String getMac(int endpoint); +} diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/WakeOnLanManagerStub.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/WakeOnLanManagerStub.java new file mode 100644 index 00000000000000..24017e912900bb --- /dev/null +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/WakeOnLanManagerStub.java @@ -0,0 +1,14 @@ +package com.tcl.chip.tvapp; + +import android.util.Log; + +public class WakeOnLanManagerStub implements WakeOnLanManager { + + private final String TAG = WakeOnLanManagerStub.class.getSimpleName(); + + @Override + public String getMac(int endpoint) { + Log.d(TAG, "getMac for endpoint=" + endpoint); + return "AA:BB:CC:DD:EE"; + } +} diff --git a/scripts/examples/gn_android_example.sh b/scripts/examples/gn_android_example.sh index cbf301ee06bb76..5952eff0f0e8a8 100755 --- a/scripts/examples/gn_android_example.sh +++ b/scripts/examples/gn_android_example.sh @@ -74,7 +74,7 @@ gn gen --check --fail-on-unused-args --root="$EXAMPLE_DIR" "$OUTPUT_DIR" --args= ninja -C "$OUTPUT_DIR" "${NINJA_ARGS[@]}" -cp -rf "$OUTPUT_DIR/lib/jni/" "$EXAMPLE_DIR/App/app/libs/jniLibs/" +cp -rf "$OUTPUT_DIR/lib/jni/." "$EXAMPLE_DIR/App/app/libs/jniLibs/" cp -f "$OUTPUT_DIR/lib/third_party/connectedhomeip/src/platform/android/AndroidPlatform.jar" "$EXAMPLE_DIR/App/app/libs/" cp -f "$OUTPUT_DIR/lib/third_party/connectedhomeip/src/app/server/java/CHIPAppServer.jar" "$EXAMPLE_DIR/App/app/libs/" cp -f "$OUTPUT_DIR/lib/third_party/connectedhomeip/src/setup_payload/java/SetupPayloadParser.jar" "$EXAMPLE_DIR/App/app/libs/"