From 14104847e42c2bd855a867cfc38059a2133702ae Mon Sep 17 00:00:00 2001 From: "Hui.Li-TCL" Date: Wed, 12 Jan 2022 07:22:47 +0800 Subject: [PATCH] Android java endpoint and fix memory errors (#13398) * added endpoint support in Java * fix jni sign error * fix memory error in media input cluster on android * fix restyled-io and ci errors * fix memory issus in channel cluster * fix memory issus in content launcher cluster * fix memory issue in wake up on lan launcher cluster * fix media playback cluster issue in last PR * fix restyled-io and ci errors * fix CI issue --- .../chiptvserver/service/MatterServant.java | 36 +++- examples/tv-app/android/BUILD.gn | 3 + .../tv-app/android/java/ChannelManager.cpp | 114 ++++++----- examples/tv-app/android/java/ChannelManager.h | 19 +- .../android/java/ContentLauncherManager.cpp | 77 ++++---- .../android/java/ContentLauncherManager.h | 25 +-- .../android/java/KeypadInputManager.cpp | 27 +-- .../tv-app/android/java/KeypadInputManager.h | 10 +- .../tv-app/android/java/LowPowerManager.cpp | 24 ++- .../tv-app/android/java/LowPowerManager.h | 10 +- .../tv-app/android/java/MediaInputManager.cpp | 42 ++-- .../tv-app/android/java/MediaInputManager.h | 13 +- .../android/java/MediaPlaybackManager.cpp | 184 +++++++++++++----- .../android/java/MediaPlaybackManager.h | 29 ++- examples/tv-app/android/java/TVApp-JNI.cpp | 73 +++++-- examples/tv-app/android/java/TvApp-JNI.h | 40 ++++ .../tv-app/android/java/WakeOnLanManager.cpp | 45 ++--- .../tv-app/android/java/WakeOnLanManager.h | 12 +- .../src/com/tcl/chip/tvapp/ChannelInfo.java | 25 ++- .../tcl/chip/tvapp/ChannelManagerStub.java | 47 ++++- .../java/src/com/tcl/chip/tvapp/Clusters.java | 138 +++++++++++++ .../tcl/chip/tvapp/ContentLaunchManager.java | 6 +- .../chip/tvapp/ContentLaunchManagerStub.java | 34 ++-- .../chip/tvapp/KeypadInputManagerStub.java | 11 +- .../tcl/chip/tvapp/LowPowerManagerStub.java | 8 +- .../tcl/chip/tvapp/MediaInputManagerStub.java | 24 ++- .../tcl/chip/tvapp/MediaPlaybackManager.java | 15 +- .../chip/tvapp/MediaPlaybackManagerStub.java | 54 ++--- .../tcl/chip/tvapp/MediaPlaybackPosition.java | 13 ++ .../java/src/com/tcl/chip/tvapp/TvApp.java | 33 +++- .../src/com/tcl/chip/tvapp/TvAppCallback.java | 21 ++ .../com/tcl/chip/tvapp/WakeOnLanManager.java | 2 +- .../tcl/chip/tvapp/WakeOnLanManagerStub.java | 8 +- .../linux/include/channel/ChannelManager.cpp | 48 +++-- .../linux/include/channel/ChannelManager.h | 10 +- .../ContentLauncherManager.cpp | 37 ++-- .../content-launcher/ContentLauncherManager.h | 21 +- .../include/media-input/MediaInputManager.cpp | 29 +-- .../include/media-input/MediaInputManager.h | 3 +- .../include/wake-on-lan/WakeOnLanManager.cpp | 4 +- .../include/wake-on-lan/WakeOnLanManager.h | 2 +- examples/tv-app/linux/main.cpp | 3 +- src/app/BUILD.gn | 1 + src/app/CommandResponseHelper.h | 61 ++++++ .../channel-server/channel-delegate.h | 18 +- .../channel-server/channel-server.cpp | 32 ++- .../content-launch-delegate.h | 14 +- .../content-launch-server.cpp | 32 ++- .../media-input-server/media-input-delegate.h | 15 +- .../media-input-server/media-input-server.cpp | 9 +- .../wake-on-lan-server/wake-on-lan-delegate.h | 3 +- .../wake-on-lan-server/wake-on-lan-server.cpp | 3 +- src/lib/support/JniTypeWrappers.h | 8 +- 53 files changed, 1076 insertions(+), 499 deletions(-) create mode 100644 examples/tv-app/android/java/TvApp-JNI.h create mode 100644 examples/tv-app/android/java/src/com/tcl/chip/tvapp/Clusters.java create mode 100644 examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackPosition.java create mode 100644 examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvAppCallback.java create mode 100644 src/app/CommandResponseHelper.h diff --git a/examples/tv-app/android/App/app/src/main/java/com/tcl/chip/chiptvserver/service/MatterServant.java b/examples/tv-app/android/App/app/src/main/java/com/tcl/chip/chiptvserver/service/MatterServant.java index fffb60be46040b..d6798354058b93 100644 --- a/examples/tv-app/android/App/app/src/main/java/com/tcl/chip/chiptvserver/service/MatterServant.java +++ b/examples/tv-app/android/App/app/src/main/java/com/tcl/chip/chiptvserver/service/MatterServant.java @@ -10,6 +10,7 @@ import chip.platform.PreferencesConfigurationManager; import chip.platform.PreferencesKeyValueStoreManager; import com.tcl.chip.tvapp.ChannelManagerStub; +import com.tcl.chip.tvapp.Clusters; import com.tcl.chip.tvapp.ContentLaunchManagerStub; import com.tcl.chip.tvapp.KeypadInputManagerStub; import com.tcl.chip.tvapp.LowPowerManagerStub; @@ -33,14 +34,33 @@ public static MatterServant get() { } public void init(@NonNull Context context) { - TvApp tvApp = new TvApp(); - tvApp.setKeypadInputManager(new KeypadInputManagerStub()); - tvApp.setWakeOnLanManager(new WakeOnLanManagerStub()); - tvApp.setMediaInputManager(new MediaInputManagerStub()); - tvApp.setContentLaunchManager(new ContentLaunchManagerStub()); - tvApp.setLowPowerManager(new LowPowerManagerStub()); - tvApp.setMediaPlaybackManager(new MediaPlaybackManagerStub()); - tvApp.setChannelManager(new ChannelManagerStub()); + TvApp tvApp = + new TvApp( + (app, clusterId, endpoint) -> { + switch (clusterId) { + case Clusters.ClusterId_KeypadInput: + app.setKeypadInputManager(endpoint, new KeypadInputManagerStub(endpoint)); + break; + case Clusters.ClusterId_WakeOnLan: + app.setWakeOnLanManager(endpoint, new WakeOnLanManagerStub(endpoint)); + break; + case Clusters.ClusterId_MediaInput: + app.setMediaInputManager(endpoint, new MediaInputManagerStub(endpoint)); + break; + case Clusters.ClusterId_ContentLauncher: + app.setContentLaunchManager(endpoint, new ContentLaunchManagerStub(endpoint)); + break; + case Clusters.ClusterId_LowPower: + app.setLowPowerManager(endpoint, new LowPowerManagerStub(endpoint)); + break; + case Clusters.ClusterId_MediaPlayback: + app.setMediaPlaybackManager(endpoint, new MediaPlaybackManagerStub(endpoint)); + break; + case Clusters.ClusterId_Channel: + app.setChannelManager(endpoint, new ChannelManagerStub(endpoint)); + break; + } + }); Context applicationContext = context.getApplicationContext(); AndroidChipPlatform chipPlatform = diff --git a/examples/tv-app/android/BUILD.gn b/examples/tv-app/android/BUILD.gn index d77831c649d5fa..da112196c57e6a 100644 --- a/examples/tv-app/android/BUILD.gn +++ b/examples/tv-app/android/BUILD.gn @@ -87,6 +87,7 @@ android_library("java") { "java/src/com/tcl/chip/tvapp/ChannelLineupInfo.java", "java/src/com/tcl/chip/tvapp/ChannelManager.java", "java/src/com/tcl/chip/tvapp/ChannelManagerStub.java", + "java/src/com/tcl/chip/tvapp/Clusters.java", "java/src/com/tcl/chip/tvapp/ContentLaunchBrandingInformation.java", "java/src/com/tcl/chip/tvapp/ContentLaunchManager.java", "java/src/com/tcl/chip/tvapp/ContentLaunchManagerStub.java", @@ -101,7 +102,9 @@ android_library("java") { "java/src/com/tcl/chip/tvapp/MediaInputManagerStub.java", "java/src/com/tcl/chip/tvapp/MediaPlaybackManager.java", "java/src/com/tcl/chip/tvapp/MediaPlaybackManagerStub.java", + "java/src/com/tcl/chip/tvapp/MediaPlaybackPosition.java", "java/src/com/tcl/chip/tvapp/TvApp.java", + "java/src/com/tcl/chip/tvapp/TvAppCallback.java", "java/src/com/tcl/chip/tvapp/WakeOnLanManager.java", "java/src/com/tcl/chip/tvapp/WakeOnLanManagerStub.java", ] diff --git a/examples/tv-app/android/java/ChannelManager.cpp b/examples/tv-app/android/java/ChannelManager.cpp index cd0b2f79fd4a0c..fa4969e489b2c8 100644 --- a/examples/tv-app/android/java/ChannelManager.cpp +++ b/examples/tv-app/android/java/ChannelManager.cpp @@ -16,6 +16,9 @@ */ #include "ChannelManager.h" +#include "TvApp-JNI.h" +#include +#include #include #include #include @@ -24,13 +27,31 @@ using namespace chip; using namespace chip::app::Clusters::Channel; -namespace { -static ChannelManager channelManager; -} // namespace +/** @brief 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 emberAfChannelClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Android App: Channel::PostClusterInit"); + TvAppJNIMgr().PostClusterInit(chip::app::Clusters::Channel::Id, endpoint); +} -std::list ChannelManager::HandleGetChannelList() +void ChannelManager::NewManager(jint endpoint, jobject manager) +{ + ChipLogProgress(Zcl, "TV Android App: Channel::SetDefaultDelegate"); + ChannelManager * mgr = new ChannelManager(); + mgr->InitializeWithObjects(manager); + chip::app::Clusters::Channel::SetDefaultDelegate(static_cast(endpoint), mgr); +} + +CHIP_ERROR ChannelManager::HandleGetChannelList(chip::app::AttributeValueEncoder & aEncoder) { - std::list list; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -39,9 +60,17 @@ std::list ChannelManag VerifyOrExit(mGetChannelListMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); - { + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { jobjectArray channelInfoList = (jobjectArray) env->CallObjectMethod(mChannelManagerObject, mGetChannelListMethod); - jint length = env->GetArrayLength(channelInfoList); + if (env->ExceptionCheck()) + { + ChipLogError(Zcl, "Java exception in ChannelManager::HandleGetChannelList"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INCORRECT_STATE; + } + + jint length = env->GetArrayLength(channelInfoList); for (jint i = 0; i < length; i++) { @@ -62,7 +91,7 @@ std::list ChannelManag if (jname != NULL) { JniUtfString name(env, jname); - channelInfo.callSign = name.charSpan(); + channelInfo.name = name.charSpan(); } jfieldID getJaffiliateCallSignField = env->GetFieldID(channelClass, "affiliateCallSign", "Ljava/lang/String;"); @@ -70,7 +99,7 @@ std::list ChannelManag if (jaffiliateCallSign != NULL) { JniUtfString affiliateCallSign(env, jaffiliateCallSign); - channelInfo.callSign = affiliateCallSign.charSpan(); + channelInfo.affiliateCallSign = affiliateCallSign.charSpan(); } jfieldID majorNumField = env->GetFieldID(channelClass, "majorNumber", "I"); @@ -79,10 +108,13 @@ std::list ChannelManag jfieldID minorNumField = env->GetFieldID(channelClass, "minorNumber", "I"); jint jminorNum = env->GetIntField(channelObject, minorNumField); - channelInfo.majorNumber = static_cast(jminorNum); - list.push_back(channelInfo); + channelInfo.minorNumber = static_cast(jminorNum); + + ReturnErrorOnFailure(encoder.Encode(channelInfo)); } - } + + return CHIP_NO_ERROR; + }); exit: if (err != CHIP_NO_ERROR) @@ -90,10 +122,10 @@ std::list ChannelManag ChipLogError(Zcl, "ChannelManager::getChannelList status error: %s", err.AsString()); } - return list; + return err; } -chip::app::Clusters::Channel::Structs::LineupInfo::Type ChannelManager::HandleGetLineup() +CHIP_ERROR ChannelManager::HandleGetLineup(chip::app::AttributeValueEncoder & aEncoder) { chip::app::Clusters::Channel::Structs::LineupInfo::Type lineupInfo; CHIP_ERROR err = CHIP_NO_ERROR; @@ -135,6 +167,8 @@ chip::app::Clusters::Channel::Structs::LineupInfo::Type ChannelManager::HandleGe jfieldID lineupInfoTypeFild = env->GetFieldID(channelLineupClazz, "lineupInfoTypeEnum", "I"); jint jlineupInfoType = (env->GetIntField(channelLineupObject, lineupInfoTypeFild)); lineupInfo.lineupInfoType = static_cast(jlineupInfoType); + + err = aEncoder.Encode(lineupInfo); } exit: @@ -143,10 +177,10 @@ chip::app::Clusters::Channel::Structs::LineupInfo::Type ChannelManager::HandleGe ChipLogError(Zcl, "ChannelManager::getChannelLineup status error: %s", err.AsString()); } - return lineupInfo; + return err; } -chip::app::Clusters::Channel::Structs::ChannelInfo::Type ChannelManager::HandleGetCurrentChannel() +CHIP_ERROR ChannelManager::HandleGetCurrentChannel(chip::app::AttributeValueEncoder & aEncoder) { chip::app::Clusters::Channel::Structs::ChannelInfo::Type channelInfo; CHIP_ERROR err = CHIP_NO_ERROR; @@ -173,7 +207,7 @@ chip::app::Clusters::Channel::Structs::ChannelInfo::Type ChannelManager::HandleG if (jname != NULL) { JniUtfString name(env, jname); - channelInfo.callSign = name.charSpan(); + channelInfo.name = name.charSpan(); } jfieldID getJaffiliateCallSignField = env->GetFieldID(channelClass, "affiliateCallSign", "Ljava/lang/String;"); @@ -181,7 +215,7 @@ chip::app::Clusters::Channel::Structs::ChannelInfo::Type ChannelManager::HandleG if (jaffiliateCallSign != NULL) { JniUtfString affiliateCallSign(env, jaffiliateCallSign); - channelInfo.callSign = affiliateCallSign.charSpan(); + channelInfo.affiliateCallSign = affiliateCallSign.charSpan(); } jfieldID majorNumField = env->GetFieldID(channelClass, "majorNumber", "I"); @@ -190,7 +224,9 @@ chip::app::Clusters::Channel::Structs::ChannelInfo::Type ChannelManager::HandleG jfieldID minorNumField = env->GetFieldID(channelClass, "minorNumber", "I"); jint jminorNum = env->GetIntField(channelInfoObject, minorNumField); - channelInfo.majorNumber = static_cast(jminorNum); + channelInfo.minorNumber = static_cast(jminorNum); + + err = aEncoder.Encode(channelInfo); } exit: @@ -199,10 +235,12 @@ chip::app::Clusters::Channel::Structs::ChannelInfo::Type ChannelManager::HandleG ChipLogError(Zcl, "ChannelManager::HandleGetCurrentChannel status error: %s", err.AsString()); } - return channelInfo; + return err; } -Commands::ChangeChannelResponse::Type ChannelManager::HandleChangeChannel(const chip::CharSpan & match) +void ChannelManager::HandleChangeChannel( + const chip::CharSpan & match, + chip::app::CommandResponseHelper & responser) { std::string name(match.data(), match.size()); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -225,11 +263,15 @@ Commands::ChangeChannelResponse::Type ChannelManager::HandleChangeChannel(const ChipLogError(DeviceLayer, "Java exception in ChannelManager::HandleChangeChannel"); env->ExceptionDescribe(); env->ExceptionClear(); - return response; + goto exit; } jclass channelClass = env->GetObjectClass(channelObject); + jfieldID getErrorTypeField = env->GetFieldID(channelClass, "errorType", "I"); + jint jerrorType = env->GetIntField(channelObject, getErrorTypeField); + response.errorType = static_cast(jerrorType); + jfieldID getCallSignField = env->GetFieldID(channelClass, "callSign", "Ljava/lang/String;"); jstring jcallSign = static_cast(env->GetObjectField(channelObject, getCallSignField)); if (jcallSign != NULL) @@ -243,14 +285,14 @@ Commands::ChangeChannelResponse::Type ChannelManager::HandleChangeChannel(const if (jname != NULL) { JniUtfString junitname(env, jname); - response.channelMatch.callSign = junitname.charSpan(); + response.channelMatch.name = junitname.charSpan(); } jfieldID getJaffiliateCallSignField = env->GetFieldID(channelClass, "affiliateCallSign", "Ljava/lang/String;"); jstring jaffiliateCallSign = static_cast(env->GetObjectField(channelObject, getJaffiliateCallSignField)); if (jaffiliateCallSign != NULL) { JniUtfString affiliateCallSign(env, jaffiliateCallSign); - response.channelMatch.callSign = affiliateCallSign.charSpan(); + response.channelMatch.affiliateCallSign = affiliateCallSign.charSpan(); } jfieldID majorNumField = env->GetFieldID(channelClass, "majorNumber", "I"); @@ -259,12 +301,13 @@ Commands::ChangeChannelResponse::Type ChannelManager::HandleChangeChannel(const jfieldID minorNumField = env->GetFieldID(channelClass, "minorNumber", "I"); jint jminorNum = env->GetIntField(channelObject, minorNumField); - response.channelMatch.majorNumber = static_cast(jminorNum); + response.channelMatch.minorNumber = static_cast(jminorNum); + + responser.Success(response); } exit: - - return response; + return; } bool ChannelManager::HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) @@ -372,20 +415,3 @@ void ChannelManager::InitializeWithObjects(jobject managerObject) env->ExceptionClear(); } } - -ChannelManager ChannelManager::sInstance; - -/** @brief 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 emberAfChannelClusterInitCallback(EndpointId endpoint) -{ - ChipLogProgress(Zcl, "TV Android App: Channel::SetDefaultDelegate"); - chip::app::Clusters::Channel::SetDefaultDelegate(endpoint, &channelManager); -} diff --git a/examples/tv-app/android/java/ChannelManager.h b/examples/tv-app/android/java/ChannelManager.h index 0ed1659d7e51e8..e898c56c7e5093 100644 --- a/examples/tv-app/android/java/ChannelManager.h +++ b/examples/tv-app/android/java/ChannelManager.h @@ -23,20 +23,20 @@ class ChannelManager : public chip::app::Clusters::Channel::Delegate { public: + static void NewManager(jint endpoint, jobject manager); void InitializeWithObjects(jobject managerObject); - std::list HandleGetChannelList() override; - chip::app::Clusters::Channel::Structs::LineupInfo::Type HandleGetLineup() override; - chip::app::Clusters::Channel::Structs::ChannelInfo::Type HandleGetCurrentChannel() override; + virtual CHIP_ERROR HandleGetChannelList(chip::app::AttributeValueEncoder & aEncoder) override; + virtual CHIP_ERROR HandleGetLineup(chip::app::AttributeValueEncoder & aEncoder) override; + virtual CHIP_ERROR HandleGetCurrentChannel(chip::app::AttributeValueEncoder & aEncoder) override; - chip::app::Clusters::Channel::Commands::ChangeChannelResponse::Type HandleChangeChannel(const chip::CharSpan & match) override; + virtual void HandleChangeChannel( + const chip::CharSpan & match, + chip::app::CommandResponseHelper & responser) override; bool HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) override; bool HandleSkipChannel(const uint16_t & count) override; private: - friend ChannelManager & ChannelMgr(); - - static ChannelManager sInstance; jobject mChannelManagerObject = nullptr; jmethodID mGetChannelListMethod = nullptr; jmethodID mGetLineupMethod = nullptr; @@ -46,8 +46,3 @@ class ChannelManager : public chip::app::Clusters::Channel::Delegate jmethodID mChangeChannelByNumberMethod = nullptr; jmethodID mSkipChannelMethod = nullptr; }; - -inline class ChannelManager & ChannelMgr() -{ - return ChannelManager::sInstance; -} diff --git a/examples/tv-app/android/java/ContentLauncherManager.cpp b/examples/tv-app/android/java/ContentLauncherManager.cpp index 4298fe24c1d364..e5fa67e9d6916b 100644 --- a/examples/tv-app/android/java/ContentLauncherManager.cpp +++ b/examples/tv-app/android/java/ContentLauncherManager.cpp @@ -17,7 +17,8 @@ */ #include "ContentLauncherManager.h" - +#include "TvApp-JNI.h" +#include #include #include #include @@ -28,21 +29,23 @@ using namespace std; using namespace chip; using namespace chip::app::Clusters::ContentLauncher; -ContentLauncherManager ContentLauncherManager::sInstance; - -namespace { -static ContentLauncherManager contentLauncherManager; -} // namespace - void emberAfContentLauncherClusterInitCallback(EndpointId endpoint) { - ChipLogProgress(Zcl, "TV Linux App: ContentLauncher::SetDelegate"); - chip::app::Clusters::ContentLauncher::SetDelegate(endpoint, &contentLauncherManager); + ChipLogProgress(Zcl, "TV Android App: ContentLauncher::PostClusterInit"); + TvAppJNIMgr().PostClusterInit(chip::app::Clusters::ContentLauncher::Id, endpoint); +} + +void ContentLauncherManager::NewManager(jint endpoint, jobject manager) +{ + ChipLogProgress(Zcl, "TV Android App: ContentLauncher::SetDefaultDelegate"); + ContentLauncherManager * mgr = new ContentLauncherManager(); + mgr->InitializeWithObjects(manager); + chip::app::Clusters::ContentLauncher::SetDelegate(static_cast(endpoint), mgr); } -Commands::LaunchResponse::Type ContentLauncherManager::HandleLaunchContent(chip::EndpointId endpointId, - const std::list & parameterList, - bool autoplay, const chip::CharSpan & data) +void ContentLauncherManager::HandleLaunchContent( + const std::list & parameterList, bool autoplay, const chip::CharSpan & data, + chip::app::CommandResponseHelper & responser) { Commands::LaunchResponse::Type response; CHIP_ERROR err = CHIP_NO_ERROR; @@ -59,8 +62,8 @@ Commands::LaunchResponse::Type ContentLauncherManager::HandleLaunchContent(chip: // Todo: make parameterList java jobjectArray parameterArray = nullptr; - jobject resp = - env->CallObjectMethod(mContentLauncherManagerObject, mLaunchContentMethod, parameterArray, autoplay, jData.jniValue()); + jobject resp = env->CallObjectMethod(mContentLauncherManagerObject, mLaunchContentMethod, parameterArray, + static_cast(autoplay), jData.jniValue()); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Java exception in ContentLauncherManager::LaunchContent"); @@ -83,6 +86,8 @@ Commands::LaunchResponse::Type ContentLauncherManager::HandleLaunchContent(chip: response.status = static_cast(status); response.data = dataStr.charSpan(); + + err = responser.Success(response); } exit: @@ -90,13 +95,12 @@ Commands::LaunchResponse::Type ContentLauncherManager::HandleLaunchContent(chip: { ChipLogError(Zcl, "ContentLauncherManager::LaunchContent status error: %s", err.AsString()); } - - return response; } -Commands::LaunchResponse::Type ContentLauncherManager::HandleLaunchUrl(const chip::CharSpan & contentUrl, - const chip::CharSpan & displayString, - const std::list & brandingInformation) +void ContentLauncherManager::HandleLaunchUrl( + const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, + const std::list & brandingInformation, + chip::app::CommandResponseHelper & responser) { Commands::LaunchResponse::Type response; CHIP_ERROR err = CHIP_NO_ERROR; @@ -138,6 +142,8 @@ Commands::LaunchResponse::Type ContentLauncherManager::HandleLaunchUrl(const chi response.status = static_cast(status); response.data = dataStr.charSpan(); + + err = responser.Success(response); } exit: @@ -145,11 +151,9 @@ Commands::LaunchResponse::Type ContentLauncherManager::HandleLaunchUrl(const chi { ChipLogError(Zcl, "ContentLauncherManager::LaunchUrl status error: %s", err.AsString()); } - - return response; } -std::list ContentLauncherManager::HandleGetAcceptHeaderList() +CHIP_ERROR ContentLauncherManager::HandleGetAcceptHeaderList(chip::app::AttributeValueEncoder & aEncoder) { CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -160,7 +164,7 @@ std::list ContentLauncherManager::HandleGetAcceptHeaderList() VerifyOrExit(mGetAcceptHeaderMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); - { + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { jobjectArray acceptedHeadersArray = (jobjectArray) env->CallObjectMethod(mContentLauncherManagerObject, mGetAcceptHeaderMethod); if (env->ExceptionCheck()) @@ -168,20 +172,19 @@ std::list ContentLauncherManager::HandleGetAcceptHeaderList() ChipLogError(Zcl, "Java exception in ContentLauncherManager::GetAcceptHeader"); env->ExceptionDescribe(); env->ExceptionClear(); - err = CHIP_ERROR_INCORRECT_STATE; - goto exit; + return CHIP_ERROR_INCORRECT_STATE; } jint size = env->GetArrayLength(acceptedHeadersArray); for (int i = 0; i < size; i++) { - - jstring jAcceptedHeader = (jstring) env->GetObjectArrayElement(acceptedHeadersArray, i); - const char * convertedValue = (env)->GetStringUTFChars(jAcceptedHeader, JNI_FALSE); - std::string acceptedHeader = std::string(convertedValue, strlen(convertedValue)); - acceptedHeadersList.push_front(acceptedHeader); + jstring jAcceptedHeader = (jstring) env->GetObjectArrayElement(acceptedHeadersArray, i); + JniUtfString acceptedHeader(env, jAcceptedHeader); + ReturnErrorOnFailure(encoder.Encode(acceptedHeader.charSpan())); } - } + + return CHIP_NO_ERROR; + }); exit: if (err != CHIP_NO_ERROR) @@ -189,7 +192,7 @@ std::list ContentLauncherManager::HandleGetAcceptHeaderList() ChipLogError(Zcl, "ContentLauncherManager::GetAcceptHeader status error: %s", err.AsString()); } - return acceptedHeadersList; + return err; } uint32_t ContentLauncherManager::HandleGetSupportedStreamingProtocols() @@ -204,8 +207,8 @@ uint32_t ContentLauncherManager::HandleGetSupportedStreamingProtocols() VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); { - jint jSupportedStreamingProtocols = - env->CallIntMethod(mContentLauncherManagerObject, mGetSupportedStreamingProtocolsMethod); + jlong jSupportedStreamingProtocols = + env->CallLongMethod(mContentLauncherManagerObject, mGetSupportedStreamingProtocolsMethod); supportedStreamingProtocols = (uint32_t) jSupportedStreamingProtocols; if (env->ExceptionCheck()) { @@ -244,7 +247,7 @@ void ContentLauncherManager::InitializeWithObjects(jobject managerObject) env->ExceptionClear(); } - mGetSupportedStreamingProtocolsMethod = env->GetMethodID(ContentLauncherClass, "getSupportedStreamingProtocols", "()[I"); + mGetSupportedStreamingProtocolsMethod = env->GetMethodID(ContentLauncherClass, "getSupportedStreamingProtocols", "()J"); if (mGetSupportedStreamingProtocolsMethod == nullptr) { ChipLogError(Zcl, "Failed to access ContentLauncherManager 'getSupportedStreamingProtocols' method"); @@ -253,7 +256,7 @@ void ContentLauncherManager::InitializeWithObjects(jobject managerObject) mLaunchContentMethod = env->GetMethodID( ContentLauncherClass, "launchContent", - "([Lcom/tcl/chip/tvapp/ContentLaunchSearchParameter;ZLjava/lang/String;)Lcom/tcl/chip/tvapp/LaunchResponse;"); + "([Lcom/tcl/chip/tvapp/ContentLaunchSearchParameter;ZLjava/lang/String;)Lcom/tcl/chip/tvapp/ContentLaunchResponse;"); if (mLaunchContentMethod == nullptr) { ChipLogError(Zcl, "Failed to access ContentLauncherManager 'launchContent' method"); @@ -262,7 +265,7 @@ void ContentLauncherManager::InitializeWithObjects(jobject managerObject) mLaunchUrlMethod = env->GetMethodID(ContentLauncherClass, "launchUrl", "(Ljava/lang/String;Ljava/lang/String;Lcom/tcl/chip/tvapp/" - "ContentLaunchBrandingInformation;)Lcom/tcl/chip/tvapp/LaunchResponse;"); + "ContentLaunchBrandingInformation;)Lcom/tcl/chip/tvapp/ContentLaunchResponse;"); if (mLaunchUrlMethod == nullptr) { ChipLogError(AppServer, "Failed to access 'launchUrl' method"); diff --git a/examples/tv-app/android/java/ContentLauncherManager.h b/examples/tv-app/android/java/ContentLauncherManager.h index 8ef2bc0fa8287d..22d4a099f58144 100644 --- a/examples/tv-app/android/java/ContentLauncherManager.h +++ b/examples/tv-app/android/java/ContentLauncherManager.h @@ -29,29 +29,24 @@ class ContentLauncherManager : public chip::app::Clusters::ContentLauncher::Delegate { public: + static void NewManager(jint endpoint, jobject manager); void InitializeWithObjects(jobject managerObject); - chip::app::Clusters::ContentLauncher::Commands::LaunchResponse::Type - HandleLaunchContent(chip::EndpointId endpointId, const std::list & parameterList, bool autoplay, - const chip::CharSpan & data) override; - chip::app::Clusters::ContentLauncher::Commands::LaunchResponse::Type - HandleLaunchUrl(const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, - const std::list & brandingInformation) override; - std::list HandleGetAcceptHeaderList() override; + void + HandleLaunchContent(const std::list & parameterList, bool autoplay, const chip::CharSpan & data, + chip::app::CommandResponseHelper & + responser) override; + void HandleLaunchUrl(const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, + const std::list & brandingInformation, + chip::app::CommandResponseHelper & + responser) override; + CHIP_ERROR HandleGetAcceptHeaderList(chip::app::AttributeValueEncoder & aEncoder) override; uint32_t HandleGetSupportedStreamingProtocols() override; private: - friend ContentLauncherManager & ContentLauncherMgr(); - - static ContentLauncherManager sInstance; jobject mContentLauncherManagerObject = nullptr; jmethodID mGetAcceptHeaderMethod = nullptr; jmethodID mGetSupportedStreamingProtocolsMethod = nullptr; jmethodID mLaunchContentMethod = nullptr; jmethodID mLaunchUrlMethod = nullptr; }; - -inline ContentLauncherManager & ContentLauncherMgr() -{ - return ContentLauncherManager::sInstance; -} diff --git a/examples/tv-app/android/java/KeypadInputManager.cpp b/examples/tv-app/android/java/KeypadInputManager.cpp index 40dc3a31132ad2..dbe9db273bb392 100644 --- a/examples/tv-app/android/java/KeypadInputManager.cpp +++ b/examples/tv-app/android/java/KeypadInputManager.cpp @@ -17,18 +17,27 @@ */ #include "KeypadInputManager.h" - +#include "TvApp-JNI.h" +#include #include #include using namespace chip; using namespace chip::app::Clusters::KeypadInput; -KeypadInputManager KeypadInputManager::sInstance; +void emberAfKeypadInputClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Android App: KeypadInput::PostClusterInit"); + TvAppJNIMgr().PostClusterInit(chip::app::Clusters::KeypadInput::Id, endpoint); +} -namespace { -static KeypadInputManager keypadInputManager; -} // namespace +void KeypadInputManager::NewManager(jint endpoint, jobject manager) +{ + ChipLogProgress(Zcl, "TV Android App: KeypadInput::SetDefaultDelegate"); + KeypadInputManager * mgr = new KeypadInputManager(); + mgr->InitializeWithObjects(manager); + chip::app::Clusters::KeypadInput::SetDefaultDelegate(static_cast(endpoint), mgr); +} Commands::SendKeyResponse::Type KeypadInputManager::HandleSendKey(const CecKeyCode & keyCode) { @@ -50,7 +59,7 @@ Commands::SendKeyResponse::Type KeypadInputManager::HandleSendKey(const CecKeyCo exit: if (err != CHIP_NO_ERROR) { - response.status = chip::app::Clusters::KeypadInput::StatusEnum::kSuccess; + response.status = chip::app::Clusters::KeypadInput::StatusEnum::kInvalidKeyInCurrentState; } else { @@ -77,9 +86,3 @@ void KeypadInputManager::InitializeWithObjects(jobject managerObject) env->ExceptionClear(); } } - -void emberAfKeypadInputClusterInitCallback(EndpointId endpoint) -{ - ChipLogProgress(Zcl, "TV Android App: KeypadInput::SetDefaultDelegate"); - chip::app::Clusters::KeypadInput::SetDefaultDelegate(endpoint, &keypadInputManager); -} diff --git a/examples/tv-app/android/java/KeypadInputManager.h b/examples/tv-app/android/java/KeypadInputManager.h index cb90df01c04e28..a623a5e335e46c 100644 --- a/examples/tv-app/android/java/KeypadInputManager.h +++ b/examples/tv-app/android/java/KeypadInputManager.h @@ -24,19 +24,13 @@ class KeypadInputManager : public chip::app::Clusters::KeypadInput::Delegate { public: + static void NewManager(jint endpoint, jobject manager); void InitializeWithObjects(jobject managerObject); + chip::app::Clusters::KeypadInput::Commands::SendKeyResponse::Type HandleSendKey(const chip::app::Clusters::KeypadInput::CecKeyCode & keyCode) override; private: - friend KeypadInputManager & KeypadInputMgr(); - - static KeypadInputManager sInstance; jobject mKeypadInputManagerObject = nullptr; jmethodID mSendKeyMethod = nullptr; }; - -inline KeypadInputManager & KeypadInputMgr() -{ - return KeypadInputManager::sInstance; -} diff --git a/examples/tv-app/android/java/LowPowerManager.cpp b/examples/tv-app/android/java/LowPowerManager.cpp index 741c0e6437d82e..b7f8f56a40b93a 100644 --- a/examples/tv-app/android/java/LowPowerManager.cpp +++ b/examples/tv-app/android/java/LowPowerManager.cpp @@ -17,6 +17,8 @@ */ #include "LowPowerManager.h" +#include "TvApp-JNI.h" +#include #include #include #include @@ -26,11 +28,19 @@ using namespace chip; using namespace chip::app::Clusters::LowPower; -LowPowerManager LowPowerManager::sInstance; +void emberAfLowPowerClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Android App: LowPower::PostClusterInit"); + TvAppJNIMgr().PostClusterInit(chip::app::Clusters::LowPower::Id, endpoint); +} -namespace { -static LowPowerManager lowPowerManager; -} // namespace +void LowPowerManager::NewManager(jint endpoint, jobject manager) +{ + ChipLogProgress(Zcl, "TV Android App: LowPower::SetDefaultDelegate"); + LowPowerManager * mgr = new LowPowerManager(); + mgr->InitializeWithObjects(manager); + chip::app::Clusters::LowPower::SetDefaultDelegate(static_cast(endpoint), mgr); +} void LowPowerManager::InitializeWithObjects(jobject managerObject) { @@ -74,9 +84,3 @@ bool LowPowerManager::HandleSleep() exit: return static_cast(ret); } - -void emberAfLowPowerClusterInitCallback(EndpointId endpoint) -{ - ChipLogProgress(Zcl, "TV Android App: LowPower::SetDefaultDelegate"); - chip::app::Clusters::LowPower::SetDefaultDelegate(endpoint, &lowPowerManager); -} diff --git a/examples/tv-app/android/java/LowPowerManager.h b/examples/tv-app/android/java/LowPowerManager.h index 24e00fe8f2bd54..df191be746b7d8 100644 --- a/examples/tv-app/android/java/LowPowerManager.h +++ b/examples/tv-app/android/java/LowPowerManager.h @@ -26,18 +26,12 @@ class LowPowerManager : public chip::app::Clusters::LowPower::Delegate { public: + static void NewManager(jint endpoint, jobject manager); void InitializeWithObjects(jobject managerObject); + bool HandleSleep() override; private: - friend LowPowerManager & LowPowerMgr(); - - static LowPowerManager sInstance; jobject mLowPowerManagerObject = nullptr; jmethodID mSleepMethod = nullptr; }; - -inline LowPowerManager & LowPowerMgr() -{ - return LowPowerManager::sInstance; -} diff --git a/examples/tv-app/android/java/MediaInputManager.cpp b/examples/tv-app/android/java/MediaInputManager.cpp index 6ee85c2e259074..8076ff100ef6f3 100644 --- a/examples/tv-app/android/java/MediaInputManager.cpp +++ b/examples/tv-app/android/java/MediaInputManager.cpp @@ -16,7 +16,8 @@ */ #include "MediaInputManager.h" - +#include "TvApp-JNI.h" +#include #include #include #include @@ -25,12 +26,6 @@ using namespace chip; using namespace chip::app::Clusters::MediaInput; -MediaInputManager MediaInputManager::sInstance; - -namespace { -static MediaInputManager mediaInputManager; -} // namespace - /** @brief Media Input Cluster Init * * This function is called when a specific cluster is initialized. It gives the @@ -41,14 +36,21 @@ static MediaInputManager mediaInputManager; * */ void emberAfMediaInputClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Android App: MediaInput::PostClusterInit"); + TvAppJNIMgr().PostClusterInit(chip::app::Clusters::MediaInput::Id, endpoint); +} + +void MediaInputManager::NewManager(jint endpoint, jobject manager) { ChipLogProgress(Zcl, "TV Android App: MediaInput::SetDefaultDelegate"); - chip::app::Clusters::MediaInput::SetDefaultDelegate(endpoint, &mediaInputManager); + MediaInputManager * mgr = new MediaInputManager(); + mgr->InitializeWithObjects(manager); + chip::app::Clusters::MediaInput::SetDefaultDelegate(static_cast(endpoint), mgr); } -std::list MediaInputManager::HandleGetInputList() +CHIP_ERROR MediaInputManager::HandleGetInputList(chip::app::AttributeValueEncoder & aEncoder) { - std::list list; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -57,14 +59,14 @@ std::list MediaInputM VerifyOrExit(mGetInputListMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); - { + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { jobjectArray inputArray = (jobjectArray) env->CallObjectMethod(mMediaInputManagerObject, mGetInputListMethod); if (env->ExceptionCheck()) { ChipLogError(AppServer, "Java exception in MediaInputManager::HandleGetInputList"); env->ExceptionDescribe(); env->ExceptionClear(); - return list; + return CHIP_ERROR_INCORRECT_STATE; } jint size = env->GetArrayLength(inputArray); @@ -86,32 +88,34 @@ std::list MediaInputM jfieldID nameId = env->GetFieldID(inputClass, "name", "Ljava/lang/String;"); jstring jname = static_cast(env->GetObjectField(inputObj, nameId)); + JniUtfString name(env, jname); 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)); + JniUtfString description(env, jdescription); if (jdescription != NULL) { - JniUtfString description(env, jdescription); mediaInput.description = description.charSpan(); } - list.push_back(mediaInput); + ReturnErrorOnFailure(encoder.Encode(mediaInput)); } - } + + return CHIP_NO_ERROR; + }); exit: if (err != CHIP_NO_ERROR) { - ChipLogError(Zcl, "MediaInputManager::HandleGetInputList status error: %s", err.AsString()); + ChipLogError(Zcl, "MediaInputManager::GetInputList status error: %s", err.AsString()); } - return list; + return err; } uint8_t MediaInputManager::HandleGetCurrentInput() @@ -256,7 +260,7 @@ void MediaInputManager::InitializeWithObjects(jobject managerObject) 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/InputInfo;"); + mGetInputListMethod = env->GetMethodID(MediaInputManagerClass, "getInputList", "()[Lcom/tcl/chip/tvapp/MediaInputInfo;"); if (mGetInputListMethod == nullptr) { ChipLogError(Zcl, "Failed to access MediaInputManager 'getInputList' method"); diff --git a/examples/tv-app/android/java/MediaInputManager.h b/examples/tv-app/android/java/MediaInputManager.h index 8651e3321cecc6..e93e956c249e07 100644 --- a/examples/tv-app/android/java/MediaInputManager.h +++ b/examples/tv-app/android/java/MediaInputManager.h @@ -18,14 +18,17 @@ #pragma once +#include #include #include class MediaInputManager : public chip::app::Clusters::MediaInput::Delegate { public: + static void NewManager(jint endpoint, jobject manager); void InitializeWithObjects(jobject managerObject); - std::list HandleGetInputList() override; + + CHIP_ERROR HandleGetInputList(chip::app::AttributeValueEncoder & aEncoder) override; uint8_t HandleGetCurrentInput() override; bool HandleSelectInput(const uint8_t index) override; bool HandleShowInputStatus() override; @@ -33,9 +36,6 @@ class MediaInputManager : public chip::app::Clusters::MediaInput::Delegate bool HandleRenameInput(const uint8_t index, const chip::CharSpan & name) override; private: - friend MediaInputManager & MediaInputMgr(); - - static MediaInputManager sInstance; jobject mMediaInputManagerObject = nullptr; jmethodID mGetInputListMethod = nullptr; jmethodID mGetCurrentInputMethod = nullptr; @@ -44,8 +44,3 @@ class MediaInputManager : public chip::app::Clusters::MediaInput::Delegate jmethodID mHideInputStatusMethod = nullptr; jmethodID mRenameInputMethod = nullptr; }; - -inline class MediaInputManager & MediaInputMgr() -{ - return MediaInputManager::sInstance; -} diff --git a/examples/tv-app/android/java/MediaPlaybackManager.cpp b/examples/tv-app/android/java/MediaPlaybackManager.cpp index 8e3d6b6a12222d..02e6707bdf2628 100644 --- a/examples/tv-app/android/java/MediaPlaybackManager.cpp +++ b/examples/tv-app/android/java/MediaPlaybackManager.cpp @@ -16,6 +16,10 @@ */ #include "MediaPlaybackManager.h" +#include "TvApp-JNI.h" +#include +#include +#include #include #include #include @@ -25,12 +29,6 @@ using namespace chip; using namespace chip::app::Clusters::MediaPlayback; -MediaPlaybackManager MediaPlaybackManager::sInstance; - -namespace { -static MediaPlaybackManager mediaPlaybackManager; -} // namespace - /** @brief Media PlayBack Cluster Init * * This function is called when a specific cluster is initialized. It gives the @@ -41,106 +39,182 @@ static MediaPlaybackManager mediaPlaybackManager; * */ void emberAfMediaPlaybackClusterInitCallback(chip::EndpointId endpoint) +{ + ChipLogProgress(Zcl, "TV Android App: MediaPlayback::PostClusterInit"); + TvAppJNIMgr().PostClusterInit(chip::app::Clusters::MediaPlayback::Id, endpoint); +} + +void MediaPlaybackManager::NewManager(jint endpoint, jobject manager) { ChipLogProgress(Zcl, "TV Android App: MediaPlayback::SetDefaultDelegate"); - chip::app::Clusters::MediaPlayback::SetDefaultDelegate(endpoint, &mediaPlaybackManager); + MediaPlaybackManager * mgr = new MediaPlaybackManager(); + mgr->InitializeWithObjects(manager); + chip::app::Clusters::MediaPlayback::SetDefaultDelegate(static_cast(endpoint), mgr); } PlaybackStateEnum MediaPlaybackManager::HandleGetCurrentState() { - return PlaybackStateEnum::kPlaying; + uint64_t ret = HandleMediaRequestGetAttribute(MEDIA_PLAYBACK_ATTRIBUTE_PLAYBACK_STATE); + return static_cast(ret); } uint64_t MediaPlaybackManager::HandleGetStartTime() { - return 0; + return HandleMediaRequestGetAttribute(MEDIA_PLAYBACK_ATTRIBUTE_START_TIME); } uint64_t MediaPlaybackManager::HandleGetDuration() { - return 0; -} - -Structs::PlaybackPosition::Type MediaPlaybackManager::HandleGetSampledPosition() -{ - Structs::PlaybackPosition::Type sampledPosition; - sampledPosition.updatedAt = 0; - sampledPosition.position = 0; - return sampledPosition; + return HandleMediaRequestGetAttribute(MEDIA_PLAYBACK_ATTRIBUTE_DURATION); } float MediaPlaybackManager::HandleGetPlaybackSpeed() { - return 0; + uint64_t ret = HandleMediaRequestGetAttribute(MEDIA_PLAYBACK_ATTRIBUTE_SPEED); + return static_cast(ret) / 10000.0f; } uint64_t MediaPlaybackManager::HandleGetSeekRangeStart() { - return 0; + return HandleMediaRequestGetAttribute(MEDIA_PLAYBACK_ATTRIBUTE_SEEK_RANGE_START); } uint64_t MediaPlaybackManager::HandleGetSeekRangeEnd() { - return 0; + return HandleMediaRequestGetAttribute(MEDIA_PLAYBACK_ATTRIBUTE_SEEK_RANGE_END); } Commands::PlaybackResponse::Type MediaPlaybackManager::HandlePlay() { - return MediaPlaybackMgr().HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_PLAY, 0); + return HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_PLAY, 0); } Commands::PlaybackResponse::Type MediaPlaybackManager::HandlePause() { - return MediaPlaybackMgr().HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_PAUSE, 0); + return HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_PAUSE, 0); } Commands::PlaybackResponse::Type MediaPlaybackManager::HandleStop() { - return MediaPlaybackMgr().HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_STOP, 0); + return HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_STOP, 0); } Commands::PlaybackResponse::Type MediaPlaybackManager::HandleFastForward() { - return MediaPlaybackMgr().HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_FAST_FORWARD, 0); + return HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_FAST_FORWARD, 0); } Commands::PlaybackResponse::Type MediaPlaybackManager::HandlePrevious() { - return MediaPlaybackMgr().HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_PREVIOUS, 0); + return HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_PREVIOUS, 0); } Commands::PlaybackResponse::Type MediaPlaybackManager::HandleRewind() { - return MediaPlaybackMgr().HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_REWIND, 0); + return HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_REWIND, 0); } Commands::PlaybackResponse::Type MediaPlaybackManager::HandleSkipBackward(const uint64_t & deltaPositionMilliseconds) { - return MediaPlaybackMgr().HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_SKIP_BACKWARD, deltaPositionMilliseconds); + return HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_SKIP_BACKWARD, deltaPositionMilliseconds); } Commands::PlaybackResponse::Type MediaPlaybackManager::HandleSkipForward(const uint64_t & deltaPositionMilliseconds) { - return MediaPlaybackMgr().HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_SKIP_FORWARD, deltaPositionMilliseconds); + return HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_SKIP_FORWARD, deltaPositionMilliseconds); } Commands::PlaybackResponse::Type MediaPlaybackManager::HandleSeekRequest(const uint64_t & positionMilliseconds) { - return MediaPlaybackMgr().HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_SEEK, positionMilliseconds); + return HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_SEEK, positionMilliseconds); } Commands::PlaybackResponse::Type MediaPlaybackManager::HandleNext() { - return MediaPlaybackMgr().HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_NEXT, 0); + return HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_NEXT, 0); } Commands::PlaybackResponse::Type MediaPlaybackManager::HandleStartOverRequest() { - return MediaPlaybackMgr().HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_START_OVER, 0); + return HandleMediaRequest(MEDIA_PLAYBACK_REQUEST_START_OVER, 0); +} + +void MediaPlaybackManager::InitializeWithObjects(jobject managerObject) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for MediaPlaybackManager")); + + mMediaPlaybackManagerObject = env->NewGlobalRef(managerObject); + VerifyOrReturn(mMediaPlaybackManagerObject != nullptr, ChipLogError(Zcl, "Failed to NewGlobalRef MediaPlaybackManager")); + + jclass mMediaPlaybackManagerClass = env->GetObjectClass(managerObject); + VerifyOrReturn(mMediaPlaybackManagerClass != nullptr, ChipLogError(Zcl, "Failed to get MediaPlaybackManager Java class")); + + mGetAttributeMethod = env->GetMethodID(mMediaPlaybackManagerClass, "getAttributes", "(I)J"); + if (mGetAttributeMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MediaPlaybackManager 'getAttributes' method"); + env->ExceptionClear(); + } + + mRequestMethod = env->GetMethodID(mMediaPlaybackManagerClass, "request", "(IJ)I"); + if (mRequestMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MediaPlaybackManager 'request' method"); + env->ExceptionClear(); + } + + mGetPositionMethod = + env->GetMethodID(mMediaPlaybackManagerClass, "getPosition", "()[Lcom/tcl/chip/tvapp/MediaPlaybackPosition;"); + if (mGetPositionMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MediaPlaybackManager 'getPosition' method"); + env->ExceptionClear(); + } +} + +uint64_t MediaPlaybackManager::HandleMediaRequestGetAttribute(MediaPlaybackRequestAttribute attribute) +{ + uint64_t ret = std::numeric_limits::max(); + jlong jAttributeValue = -1; + CHIP_ERROR err = CHIP_NO_ERROR; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + + ChipLogProgress(Zcl, "Received MediaPlaybackManager::HandleMediaRequestGetAttribute:%d", attribute); + VerifyOrExit(mMediaPlaybackManagerObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mGetAttributeMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); + + jAttributeValue = env->CallLongMethod(mMediaPlaybackManagerObject, mGetAttributeMethod, static_cast(attribute)); + if (env->ExceptionCheck()) + { + ChipLogError(AppServer, "Java exception in MediaPlaybackManager::GetAttribute"); + env->ExceptionDescribe(); + env->ExceptionClear(); + goto exit; + } + + if (jAttributeValue >= 0) + { + ret = static_cast(jAttributeValue); + } + else + { + err = CHIP_ERROR_INCORRECT_STATE; + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "MediaPlaybackManager::GetAttribute status error: %s", err.AsString()); + } + + return ret; } Commands::PlaybackResponse::Type MediaPlaybackManager::HandleMediaRequest(MediaPlaybackRequest mediaPlaybackRequest, uint64_t deltaPositionMilliseconds) + { Commands::PlaybackResponse::Type response; @@ -164,38 +238,56 @@ Commands::PlaybackResponse::Type MediaPlaybackManager::HandleMediaRequest(MediaP env->ExceptionClear(); response.status = StatusEnum::kInvalidStateForCommand; } + response.status = static_cast(ret); exit: if (err != CHIP_NO_ERROR) { response.status = StatusEnum::kInvalidStateForCommand; + ChipLogError(Zcl, "MediaPlaybackManager::HandleMediaRequest status error: %s", err.AsString()); } return response; } -void MediaPlaybackManager::InitializeWithObjects(jobject managerObject) +Structs::PlaybackPosition::Type MediaPlaybackManager::HandleGetSampledPosition() { - JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); - VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for MediaPlaybackManager")); + Structs::PlaybackPosition::Type response; + response.updatedAt = 0; + response.position = 0; - mMediaPlaybackManagerObject = env->NewGlobalRef(managerObject); - VerifyOrReturn(mMediaPlaybackManagerObject != nullptr, ChipLogError(Zcl, "Failed to NewGlobalRef MediaPlaybackManager")); + jobject positionObj; + CHIP_ERROR err = CHIP_NO_ERROR; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); - jclass mMediaPlaybackManagerClass = env->GetObjectClass(managerObject); - VerifyOrReturn(mMediaPlaybackManagerClass != nullptr, ChipLogError(Zcl, "Failed to get MediaPlaybackManager Java class")); + ChipLogProgress(Zcl, "MediaPlaybackManager::HandleGetSampledPosition"); + VerifyOrExit(mMediaPlaybackManagerObject != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mGetPositionMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); - mGetAttributeMethod = env->GetMethodID(mMediaPlaybackManagerClass, "getAttributes", "(I)J"); - if (mGetAttributeMethod == nullptr) + env->ExceptionClear(); + positionObj = env->CallObjectMethod(mMediaPlaybackManagerObject, mGetPositionMethod); + if (env->ExceptionCheck()) { - ChipLogError(Zcl, "Failed to access MediaPlaybackManager 'getMediaPlaybackAttribute' method"); + ChipLogError(AppServer, "Java exception in MediaPlaybackManager::HandleGetSampledPosition"); + env->ExceptionDescribe(); env->ExceptionClear(); + goto exit; } - mRequestMethod = env->GetMethodID(mMediaPlaybackManagerClass, "request", "(IJ)I"); - if (mRequestMethod == nullptr) { - ChipLogError(Zcl, "Failed to access MediaPlaybackManager 'proxyMediaPlaybackRequest' method"); - env->ExceptionClear(); + jclass inputClass = env->GetObjectClass(positionObj); + jfieldID positionId = env->GetFieldID(inputClass, "position", "J"); + jfieldID updatedAtId = env->GetFieldID(inputClass, "updatedAt", "J"); + response.position = static_cast(env->GetIntField(positionObj, positionId)); + response.updatedAt = static_cast(env->GetIntField(positionObj, updatedAtId)); } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "MediaPlaybackManager::GetAttribute status error: %s", err.AsString()); + } + + return response; } diff --git a/examples/tv-app/android/java/MediaPlaybackManager.h b/examples/tv-app/android/java/MediaPlaybackManager.h index 12aaeab077bfa0..a9479011294c26 100644 --- a/examples/tv-app/android/java/MediaPlaybackManager.h +++ b/examples/tv-app/android/java/MediaPlaybackManager.h @@ -19,8 +19,20 @@ #pragma once #include +#include #include +enum MediaPlaybackRequestAttribute : uint8_t +{ + MEDIA_PLAYBACK_ATTRIBUTE_PLAYBACK_STATE = 0, + MEDIA_PLAYBACK_ATTRIBUTE_START_TIME = 1, + MEDIA_PLAYBACK_ATTRIBUTE_DURATION = 2, + MEDIA_PLAYBACK_ATTRIBUTE_SPEED = 3, + MEDIA_PLAYBACK_ATTRIBUTE_SEEK_RANGE_END = 4, + MEDIA_PLAYBACK_ATTRIBUTE_SEEK_RANGE_START = 5, + MEDIA_PLAYBACK_ATTRIBUTE_COUNT, +}; + enum MediaPlaybackRequest : uint8_t { MEDIA_PLAYBACK_REQUEST_PLAY = 0, @@ -39,7 +51,9 @@ enum MediaPlaybackRequest : uint8_t class MediaPlaybackManager : public chip::app::Clusters::MediaPlayback::Delegate { public: + static void NewManager(jint endpoint, jobject manager); void InitializeWithObjects(jobject managerObject); + chip::app::Clusters::MediaPlayback::PlaybackStateEnum HandleGetCurrentState() override; uint64_t HandleGetStartTime() override; uint64_t HandleGetDuration() override; @@ -62,19 +76,14 @@ class MediaPlaybackManager : public chip::app::Clusters::MediaPlayback::Delegate HandleSeekRequest(const uint64_t & positionMilliseconds) override; chip::app::Clusters::MediaPlayback::Commands::PlaybackResponse::Type HandleNext() override; chip::app::Clusters::MediaPlayback::Commands::PlaybackResponse::Type HandleStartOverRequest() override; - chip::app::Clusters::MediaPlayback::Commands::PlaybackResponse::Type - HandleMediaRequest(MediaPlaybackRequest mediaPlaybackRequest, uint64_t deltaPositionMilliseconds); private: - friend MediaPlaybackManager & MediaPlaybackMgr(); - - static MediaPlaybackManager sInstance; jobject mMediaPlaybackManagerObject = nullptr; jmethodID mRequestMethod = nullptr; jmethodID mGetAttributeMethod = nullptr; -}; + jmethodID mGetPositionMethod = nullptr; -inline MediaPlaybackManager & MediaPlaybackMgr() -{ - return MediaPlaybackManager::sInstance; -} + uint64_t HandleMediaRequestGetAttribute(MediaPlaybackRequestAttribute attribute); + chip::app::Clusters::MediaPlayback::Commands::PlaybackResponse::Type + HandleMediaRequest(MediaPlaybackRequest mediaPlaybackRequest, uint64_t deltaPositionMilliseconds); +}; diff --git a/examples/tv-app/android/java/TVApp-JNI.cpp b/examples/tv-app/android/java/TVApp-JNI.cpp index 6a637c0e168688..f8a1100f5f11ba 100644 --- a/examples/tv-app/android/java/TVApp-JNI.cpp +++ b/examples/tv-app/android/java/TVApp-JNI.cpp @@ -16,6 +16,7 @@ * */ +#include "TvApp-JNI.h" #include "ChannelManager.h" #include "ContentLauncherManager.h" #include "KeypadInputManager.h" @@ -27,9 +28,48 @@ #include #include #include +#include + +using namespace chip; #define JNI_METHOD(RETURN, METHOD_NAME) extern "C" JNIEXPORT RETURN JNICALL Java_com_tcl_chip_tvapp_TvApp_##METHOD_NAME +TvAppJNI TvAppJNI::sInstance; + +void TvAppJNI::InitializeWithObjects(jobject app) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for TvAppJNI")); + + mTvAppObject = env->NewGlobalRef(app); + VerifyOrReturn(mTvAppObject != nullptr, ChipLogError(Zcl, "Failed to NewGlobalRef TvAppJNI")); + + jclass managerClass = env->GetObjectClass(mTvAppObject); + VerifyOrReturn(managerClass != nullptr, ChipLogError(Zcl, "Failed to get TvAppJNI Java class")); + + mPostClusterInitMethod = env->GetMethodID(managerClass, "postClusterInit", "(II)V"); + if (mPostClusterInitMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access ChannelManager 'postClusterInit' method"); + env->ExceptionClear(); + } +} + +void TvAppJNI::PostClusterInit(int clusterId, int endpoint) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for TvAppJNI::PostClusterInit")); + VerifyOrReturn(mTvAppObject != nullptr, ChipLogError(Zcl, "TvAppJNI::mTvAppObject null")); + VerifyOrReturn(mPostClusterInitMethod != nullptr, ChipLogError(Zcl, "TvAppJNI::mPostClusterInitMethod null")); + + env->CallVoidMethod(mTvAppObject, mPostClusterInitMethod, static_cast(clusterId), static_cast(endpoint)); + if (env->ExceptionCheck()) + { + ChipLogError(Zcl, "Failed to call TvAppJNI 'postClusterInit' method"); + env->ExceptionClear(); + } +} + jint JNI_OnLoad(JavaVM * jvm, void * reserved) { return AndroidAppServerJNI_OnLoad(jvm, reserved); @@ -40,37 +80,42 @@ void JNI_OnUnload(JavaVM * jvm, void * reserved) return AndroidAppServerJNI_OnUnload(jvm, reserved); } -JNI_METHOD(void, setKeypadInputManager)(JNIEnv *, jobject, jobject manager) +JNI_METHOD(void, nativeInit)(JNIEnv *, jobject app) +{ + TvAppJNIMgr().InitializeWithObjects(app); +} + +JNI_METHOD(void, setKeypadInputManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { - KeypadInputMgr().InitializeWithObjects(manager); + KeypadInputManager::NewManager(endpoint, manager); } -JNI_METHOD(void, setWakeOnLanManager)(JNIEnv *, jobject, jobject manager) +JNI_METHOD(void, setWakeOnLanManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { - WakeOnLanMgr().InitializeWithObjects(manager); + WakeOnLanManager::NewManager(endpoint, manager); } -JNI_METHOD(void, setMediaInputManager)(JNIEnv *, jobject, jobject manager) +JNI_METHOD(void, setMediaInputManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { - MediaInputMgr().InitializeWithObjects(manager); + MediaInputManager::NewManager(endpoint, manager); } -JNI_METHOD(void, setContentLaunchManager)(JNIEnv *, jobject, jobject manager) +JNI_METHOD(void, setContentLaunchManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { - ContentLauncherMgr().InitializeWithObjects(manager); + ContentLauncherManager::NewManager(endpoint, manager); } -JNI_METHOD(void, setLowPowerManager)(JNIEnv *, jobject, jobject manager) +JNI_METHOD(void, setLowPowerManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { - LowPowerMgr().InitializeWithObjects(manager); + LowPowerManager::NewManager(endpoint, manager); } -JNI_METHOD(void, setMediaPlaybackManager)(JNIEnv *, jobject, jobject manager) +JNI_METHOD(void, setMediaPlaybackManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { - MediaPlaybackMgr().InitializeWithObjects(manager); + MediaPlaybackManager::NewManager(endpoint, manager); } -JNI_METHOD(void, setChannelManager)(JNIEnv *, jobject, jobject manager) +JNI_METHOD(void, setChannelManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { - ChannelMgr().InitializeWithObjects(manager); + ChannelManager::NewManager(endpoint, manager); } diff --git a/examples/tv-app/android/java/TvApp-JNI.h b/examples/tv-app/android/java/TvApp-JNI.h new file mode 100644 index 00000000000000..36033727a42817 --- /dev/null +++ b/examples/tv-app/android/java/TvApp-JNI.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 + +class TvAppJNI +{ +public: + void InitializeWithObjects(jobject app); + void PostClusterInit(int clusterId, int endpoint); + +private: + friend TvAppJNI & TvAppJNIMgr(); + + static TvAppJNI sInstance; + jobject mTvAppObject = nullptr; + jmethodID mPostClusterInitMethod = nullptr; +}; + +inline class TvAppJNI & TvAppJNIMgr() +{ + return TvAppJNI::sInstance; +} diff --git a/examples/tv-app/android/java/WakeOnLanManager.cpp b/examples/tv-app/android/java/WakeOnLanManager.cpp index 8c9c7f26bbace1..99b4dc089dc250 100644 --- a/examples/tv-app/android/java/WakeOnLanManager.cpp +++ b/examples/tv-app/android/java/WakeOnLanManager.cpp @@ -17,7 +17,8 @@ */ #include "WakeOnLanManager.h" - +#include "TvApp-JNI.h" +#include #include #include #include @@ -25,12 +26,6 @@ using namespace chip; using namespace chip::app::Clusters::WakeOnLan; -WakeOnLanManager WakeOnLanManager::sInstance; - -namespace { -static WakeOnLanManager wakeOnLanManager; -} // namespace - /** @brief Wake On LAN Cluster Init * * This function is called when a specific cluster is initialized. It gives the @@ -42,13 +37,21 @@ static WakeOnLanManager wakeOnLanManager; */ void emberAfWakeOnLanClusterInitCallback(chip::EndpointId endpoint) { - ChipLogProgress(Zcl, "TV Android App: WakeOnLan::SetDefaultDelegate"); - chip::app::Clusters::WakeOnLan::SetDefaultDelegate(endpoint, &wakeOnLanManager); + ChipLogProgress(Zcl, "TV Android App: WakeOnLan::PostClusterInit"); + TvAppJNIMgr().PostClusterInit(chip::app::Clusters::WakeOnLan::Id, endpoint); } -chip::CharSpan WakeOnLanManager::HandleGetMacAddress() +void WakeOnLanManager::NewManager(jint endpoint, jobject manager) { + ChipLogProgress(Zcl, "TV Android App: WakeOnLan::SetDefaultDelegate"); + WakeOnLanManager * mgr = new WakeOnLanManager(); + mgr->InitializeWithObjects(manager); + chip::app::Clusters::WakeOnLan::SetDefaultDelegate(static_cast(endpoint), mgr); +} +CHIP_ERROR WakeOnLanManager::HandleGetMacAddress(chip::app::AttributeValueEncoder & aEncoder) +{ + jobject javaMac; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); chip::CharSpan macValue; @@ -58,27 +61,25 @@ chip::CharSpan WakeOnLanManager::HandleGetMacAddress() VerifyOrExit(mGetMacMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); + env->ExceptionClear(); + javaMac = env->CallObjectMethod(mWakeOnLanManagerObject, mGetMacMethod); + if (env->ExceptionCheck()) { + ChipLogError(DeviceLayer, "Java exception in WakeOnLanManager::getMac"); + env->ExceptionDescribe(); env->ExceptionClear(); - jobject javaMac = env->CallObjectMethod(mWakeOnLanManagerObject, mGetMacMethod, static_cast(1)); - if (env->ExceptionCheck()) - { - ChipLogError(DeviceLayer, "Java exception in WakeOnLanManager::getMac"); - env->ExceptionDescribe(); - env->ExceptionClear(); - return macValue; - } - - macValue = chip::JniUtfString(env, static_cast(javaMac)).charSpan(); + goto exit; } + macValue = chip::JniUtfString(env, static_cast(javaMac)).charSpan(); + exit: if (err != CHIP_NO_ERROR) { ChipLogError(Zcl, "WakeOnLanManager::HandleGetMacAddress status error: %s", err.AsString()); } - return macValue; + return aEncoder.Encode(macValue); } void WakeOnLanManager::InitializeWithObjects(jobject managerObject) @@ -92,7 +93,7 @@ void WakeOnLanManager::InitializeWithObjects(jobject managerObject) 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;"); + mGetMacMethod = env->GetMethodID(WakeOnLanManagerClass, "getMac", "()Ljava/lang/String;"); if (mGetMacMethod == nullptr) { ChipLogError(Zcl, "Failed to access WakeOnLanManager 'getMac' method"); diff --git a/examples/tv-app/android/java/WakeOnLanManager.h b/examples/tv-app/android/java/WakeOnLanManager.h index 69327737a45335..f837572c377168 100644 --- a/examples/tv-app/android/java/WakeOnLanManager.h +++ b/examples/tv-app/android/java/WakeOnLanManager.h @@ -24,18 +24,12 @@ class WakeOnLanManager : public chip::app::Clusters::WakeOnLan::Delegate { public: + static void NewManager(jint endpoint, jobject manager); void InitializeWithObjects(jobject managerObject); - chip::CharSpan HandleGetMacAddress() override; -private: - friend WakeOnLanManager & WakeOnLanMgr(); + CHIP_ERROR HandleGetMacAddress(chip::app::AttributeValueEncoder & aEncoder) override; - static WakeOnLanManager sInstance; +private: 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/ChannelInfo.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ChannelInfo.java index b383b789a9d78c..b291deb7e6f488 100644 --- a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ChannelInfo.java +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ChannelInfo.java @@ -18,16 +18,21 @@ package com.tcl.chip.tvapp; public class ChannelInfo { - public int majorNumber; - public int minorNumber; - public String name; - public String callSign; - public String affiliateCallSign; - public ChannelInfo() {} + public static final int kNoError = -1; // todo: what will be the value of no error? + public static final int kMultipleMatches = 0; + public static final int kNoMatches = 1; + + private int errorType; + private int majorNumber; + private int minorNumber; + private String name; + private String callSign; + private String affiliateCallSign; public ChannelInfo( int majorNumber, int minorNumber, String name, String callSign, String affiliateCallSign) { + this.errorType = kNoError; this.majorNumber = majorNumber; this.minorNumber = minorNumber; this.name = name; @@ -35,10 +40,16 @@ public ChannelInfo( this.affiliateCallSign = affiliateCallSign; } + public ChannelInfo(int errorType) { + this.errorType = errorType; + } + @Override public String toString() { return "ChannelInfo{" - + "majorNumber=" + + "errorType=" + + errorType + + ", majorNumber=" + majorNumber + ", minorNumber=" + minorNumber diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ChannelManagerStub.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ChannelManagerStub.java index 2b76098750595b..c1ed8d0e07f8a5 100644 --- a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ChannelManagerStub.java +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ChannelManagerStub.java @@ -20,46 +20,73 @@ import android.util.Log; public class ChannelManagerStub implements ChannelManager { - private static final String TAG = "ChannelManagerStub"; + private static final String TAG = ChannelManagerStub.class.getSimpleName(); + + private int endpoint; + + public ChannelManagerStub(int endpoint) { + this.endpoint = endpoint; + } @Override public ChannelInfo[] getChannelList() { - ChannelInfo ChannelInfo1 = new ChannelInfo(1, 1, "HDMI1", "callSign1", "affiliateCallSign1"); - ChannelInfo ChannelInfo2 = new ChannelInfo(2, 2, "HDMI2", "callSign2", "affiliateCallSign2"); - Log.d(TAG, "getChannelList"); + ChannelInfo ChannelInfo1 = new ChannelInfo(1, 11, "HDMI1", "callSign1", "affiliateCallSign1"); + ChannelInfo ChannelInfo2 = new ChannelInfo(2, 22, "HDMI2", "callSign2", "affiliateCallSign2"); + Log.d(TAG, "getChannelList at " + endpoint); return new ChannelInfo[] {ChannelInfo1, ChannelInfo2}; } @Override public ChannelLineupInfo getLineup() { ChannelLineupInfo lineupInfo = new ChannelLineupInfo("operator", "lineup", "postalCode"); - Log.d(TAG, "getChannelLineup: " + lineupInfo); + Log.d(TAG, "getChannelLineup: " + lineupInfo + " at " + endpoint); return lineupInfo; } @Override public ChannelInfo getCurrentChannel() { - Log.d(TAG, "getCurrentChannel: "); + Log.d(TAG, "getCurrentChannel: at " + endpoint); return new ChannelInfo(1, 1, "HDMI", "callSign", "affiliateCallSign"); } @Override public ChannelInfo changeChannel(String match) { - Log.d(TAG, "changeChannel: " + match); - return new ChannelInfo(1, 1, "HDMI", "callSign", "affiliateCallSign"); + Log.d(TAG, "changeChannel: " + match + " at " + endpoint); + if ("no".equals(match)) { + return new ChannelInfo(ChannelInfo.kNoMatches); + } else if ("multiple".equals(match)) { + return new ChannelInfo(ChannelInfo.kMultipleMatches); + } else { + return new ChannelInfo(1, 1, "HDMI", "callSign", "affiliateCallSign"); + } } @Override public boolean changeChannelByNumber(int majorNumber, int minorNumber) { Log.d( TAG, - "changeChannelByNumber: majorNumber = " + majorNumber + " minorNumber = " + minorNumber); + "changeChannelByNumber: majorNumber = " + + majorNumber + + " minorNumber = " + + minorNumber + + " at " + + endpoint); + + // for failed test + if (majorNumber == 1 && minorNumber == 1) { + return false; + } return true; } @Override public boolean skipChannel(int count) { - Log.d(TAG, "skipChannel: count = " + count); + Log.d(TAG, "skipChannel: count = " + count + " at " + endpoint); + + // for failed test + if (count == 100) { + return false; + } return true; } } diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/Clusters.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/Clusters.java new file mode 100644 index 00000000000000..37fd495fcff7e6 --- /dev/null +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/Clusters.java @@ -0,0 +1,138 @@ +/* + * + * 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. + */ +package com.tcl.chip.tvapp; + +public class Clusters { + + public static final int ClusterId_PowerConfiguration = 0x00000001; + public static final int ClusterId_DeviceTemperatureConfiguration = 0x00000002; + public static final int ClusterId_Identify = 0x00000003; + public static final int ClusterId_Groups = 0x00000004; + public static final int ClusterId_Scenes = 0x00000005; + public static final int ClusterId_OnOff = 0x00000006; + public static final int ClusterId_OnOffSwitchConfiguration = 0x00000007; + public static final int ClusterId_LevelControl = 0x00000008; + public static final int ClusterId_Alarms = 0x00000009; + public static final int ClusterId_Time = 0x0000000A; + public static final int ClusterId_BinaryInputBasic = 0x0000000F; + public static final int ClusterId_PowerProfile = 0x0000001A; + public static final int ClusterId_ApplianceControl = 0x0000001B; + public static final int ClusterId_PulseWidthModulation = 0x0000001C; + public static final int ClusterId_Descriptor = 0x0000001D; + public static final int ClusterId_Binding = 0x0000001E; + public static final int ClusterId_AccessControl = 0x0000001F; + public static final int ClusterId_PollControl = 0x00000020; + public static final int ClusterId_BridgedActions = 0x00000025; + public static final int ClusterId_Basic = 0x00000028; + public static final int ClusterId_OtaSoftwareUpdateProvider = 0x00000029; + public static final int ClusterId_OtaSoftwareUpdateRequestor = 0x0000002A; + public static final int ClusterId_LocalizationConfiguration = 0x0000002B; + public static final int ClusterId_LocalizationTimeFormat = 0x0000002C; + public static final int ClusterId_LocalizationUnit = 0x0000002D; + public static final int ClusterId_PowerSourceConfiguration = 0x0000002E; + public static final int ClusterId_PowerSource = 0x0000002F; + public static final int ClusterId_GeneralCommissioning = 0x00000030; + public static final int ClusterId_NetworkCommissioning = 0x00000031; + public static final int ClusterId_DiagnosticLogs = 0x00000032; + public static final int ClusterId_GeneralDiagnostics = 0x00000033; + public static final int ClusterId_SoftwareDiagnostics = 0x00000034; + public static final int ClusterId_ThreadNetworkDiagnostics = 0x00000035; + public static final int ClusterId_WiFiNetworkDiagnostics = 0x00000036; + public static final int ClusterId_EthernetNetworkDiagnostics = 0x00000037; + public static final int ClusterId_TimeSynchronization = 0x00000038; + public static final int ClusterId_BridgedDeviceBasic = 0x00000039; + public static final int ClusterId_Switch = 0x0000003B; + public static final int ClusterId_AdministratorCommissioning = 0x0000003C; + public static final int ClusterId_OperationalCredentials = 0x0000003E; + public static final int ClusterId_GroupKeyManagement = 0x0000003F; + public static final int ClusterId_FixedLabel = 0x00000040; + public static final int ClusterId_UserLabel = 0x00000041; + public static final int ClusterId_ProxyConfiguration = 0x00000042; + public static final int ClusterId_ProxyDiscovery = 0x00000043; + public static final int ClusterId_ProxyValid = 0x00000044; + public static final int ClusterId_BooleanState = 0x00000045; + public static final int ClusterId_ModeSelect = 0x00000050; + public static final int ClusterId_ShadeConfiguration = 0x00000100; + public static final int ClusterId_DoorLock = 0x00000101; + public static final int ClusterId_WindowCovering = 0x00000102; + public static final int ClusterId_BarrierControl = 0x00000103; + public static final int ClusterId_PumpConfigurationAndControl = 0x00000200; + public static final int ClusterId_Thermostat = 0x00000201; + public static final int ClusterId_FanControl = 0x00000202; + public static final int ClusterId_DehumidificationControl = 0x00000203; + public static final int ClusterId_ThermostatUserInterfaceConfiguration = 0x00000204; + public static final int ClusterId_ColorControl = 0x00000300; + public static final int ClusterId_BallastConfiguration = 0x00000301; + public static final int ClusterId_IlluminanceMeasurement = 0x00000400; + public static final int ClusterId_TemperatureMeasurement = 0x00000402; + public static final int ClusterId_PressureMeasurement = 0x00000403; + public static final int ClusterId_FlowMeasurement = 0x00000404; + public static final int ClusterId_RelativeHumidityMeasurement = 0x00000405; + public static final int ClusterId_OccupancySensing = 0x00000406; + public static final int ClusterId_CarbonMonoxideConcentrationMeasurement = 0x0000040C; + public static final int ClusterId_CarbonDioxideConcentrationMeasurement = 0x0000040D; + public static final int ClusterId_EthyleneConcentrationMeasurement = 0x0000040E; + public static final int ClusterId_EthyleneOxideConcentrationMeasurement = 0x0000040F; + public static final int ClusterId_HydrogenConcentrationMeasurement = 0x00000410; + public static final int ClusterId_HydrogenSulphideConcentrationMeasurement = 0x00000411; + public static final int ClusterId_NitricOxideConcentrationMeasurement = 0x00000412; + public static final int ClusterId_NitrogenDioxideConcentrationMeasurement = 0x00000413; + public static final int ClusterId_OxygenConcentrationMeasurement = 0x00000414; + public static final int ClusterId_OzoneConcentrationMeasurement = 0x00000415; + public static final int ClusterId_SulfurDioxideConcentrationMeasurement = 0x00000416; + public static final int ClusterId_DissolvedOxygenConcentrationMeasurement = 0x00000417; + public static final int ClusterId_BromateConcentrationMeasurement = 0x00000418; + public static final int ClusterId_ChloraminesConcentrationMeasurement = 0x00000419; + public static final int ClusterId_ChlorineConcentrationMeasurement = 0x0000041A; + public static final int ClusterId_FecalColiformAndEColiConcentrationMeasurement = 0x0000041B; + public static final int ClusterId_FluorideConcentrationMeasurement = 0x0000041C; + public static final int ClusterId_HaloaceticAcidsConcentrationMeasurement = 0x0000041D; + public static final int ClusterId_TotalTrihalomethanesConcentrationMeasurement = 0x0000041E; + public static final int ClusterId_TotalColiformBacteriaConcentrationMeasurement = 0x0000041F; + public static final int ClusterId_TurbidityConcentrationMeasurement = 0x00000420; + public static final int ClusterId_CopperConcentrationMeasurement = 0x00000421; + public static final int ClusterId_LeadConcentrationMeasurement = 0x00000422; + public static final int ClusterId_ManganeseConcentrationMeasurement = 0x00000423; + public static final int ClusterId_SulfateConcentrationMeasurement = 0x00000424; + public static final int ClusterId_BromodichloromethaneConcentrationMeasurement = 0x00000425; + public static final int ClusterId_BromoformConcentrationMeasurement = 0x00000426; + public static final int ClusterId_ChlorodibromomethaneConcentrationMeasurement = 0x00000427; + public static final int ClusterId_ChloroformConcentrationMeasurement = 0x00000428; + public static final int ClusterId_SodiumConcentrationMeasurement = 0x00000429; + public static final int ClusterId_IasZone = 0x00000500; + public static final int ClusterId_IasAce = 0x00000501; + public static final int ClusterId_IasWd = 0x00000502; + public static final int ClusterId_WakeOnLan = 0x00000503; + public static final int ClusterId_Channel = 0x00000504; + public static final int ClusterId_TargetNavigator = 0x00000505; + public static final int ClusterId_MediaPlayback = 0x00000506; + public static final int ClusterId_MediaInput = 0x00000507; + public static final int ClusterId_LowPower = 0x00000508; + public static final int ClusterId_KeypadInput = 0x00000509; + public static final int ClusterId_ContentLauncher = 0x0000050A; + public static final int ClusterId_AudioOutput = 0x0000050B; + public static final int ClusterId_ApplicationLauncher = 0x0000050C; + public static final int ClusterId_ApplicationBasic = 0x0000050D; + public static final int ClusterId_AccountLogin = 0x0000050E; + public static final int ClusterId_TestCluster = 0x0000050F; + public static final int ClusterId_Messaging = 0x00000703; + public static final int ClusterId_ApplianceIdentification = 0x00000B00; + public static final int ClusterId_MeterIdentification = 0x00000B01; + public static final int ClusterId_ApplianceEventsAndAlert = 0x00000B02; + public static final int ClusterId_ApplianceStatistics = 0x00000B03; + public static final int ClusterId_ElectricalMeasurement = 0x00000B04; +} diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ContentLaunchManager.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ContentLaunchManager.java index fe50a7a8420d0d..be39112f59602d 100755 --- a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ContentLaunchManager.java +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ContentLaunchManager.java @@ -20,8 +20,8 @@ public interface ContentLaunchManager { - int STREAMING_TYPE_DASH = 0; - int STREAMING_TYPE_HLS = 1; + int STREAMING_TYPE_DASH = 1; + int STREAMING_TYPE_HLS = 2; /** * @return The list of content types supported by the Video Player or Content App in the form of @@ -30,7 +30,7 @@ public interface ContentLaunchManager { String[] getAcceptHeader(); /** @return The list information about supported streaming protocols in STREAMING_TYPE_XXX. */ - int[] getSupportedStreamingProtocols(); + long getSupportedStreamingProtocols(); /** * Launch the specified content with optional search criteria. diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ContentLaunchManagerStub.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ContentLaunchManagerStub.java index 347b670cc58acf..8bf1628296157a 100644 --- a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ContentLaunchManagerStub.java +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/ContentLaunchManagerStub.java @@ -6,6 +6,12 @@ public class ContentLaunchManagerStub implements ContentLaunchManager { private final String TAG = ContentLaunchManagerStub.class.getSimpleName(); + private int endpoint; + + public ContentLaunchManagerStub(int endpoint) { + this.endpoint = endpoint; + } + @Override public String[] getAcceptHeader() { String[] headers = @@ -17,26 +23,32 @@ public String[] getAcceptHeader() { } @Override - public int[] getSupportedStreamingProtocols() { - int[] types = new int[] {STREAMING_TYPE_DASH, STREAMING_TYPE_HLS}; - return types; + public long getSupportedStreamingProtocols() { + long protocols = STREAMING_TYPE_DASH | STREAMING_TYPE_HLS; + return protocols; } @Override public ContentLaunchResponse launchContent( ContentLaunchSearchParameter[] search, boolean autoplay, String data) { - Log.d(TAG, "launchContent:" + data + " autoplay=" + autoplay); - ContentLaunchResponse resp = - new ContentLaunchResponse(ContentLaunchResponse.STATUS_SUCCESS, "Example data in Java"); - return resp; + Log.d(TAG, "launchContent:" + data + " autoplay=" + autoplay + " at " + endpoint); + + if ("err".equals(data)) { + return new ContentLaunchResponse( + ContentLaunchResponse.STATUS_URL_NOT_AVAILABLE, "Error data in Java"); + } + return new ContentLaunchResponse(ContentLaunchResponse.STATUS_SUCCESS, "Example data in Java"); } @Override public ContentLaunchResponse launchUrl( String url, String display, ContentLaunchBrandingInformation branding) { - Log.d(TAG, "launchUrl:" + url + " display=" + display); - ContentLaunchResponse resp = - new ContentLaunchResponse(ContentLaunchResponse.STATUS_SUCCESS, "Example data in Java"); - return resp; + Log.d(TAG, "launchUrl:" + url + " display=" + display + " at " + endpoint); + + if ("err".equals(display)) { + return new ContentLaunchResponse( + ContentLaunchResponse.STATUS_URL_NOT_AVAILABLE, "Error data in Java"); + } + return new ContentLaunchResponse(ContentLaunchResponse.STATUS_SUCCESS, "Example data in Java"); } } diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/KeypadInputManagerStub.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/KeypadInputManagerStub.java index 0c5d2f9734efaf..c25acd003dc9f8 100644 --- a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/KeypadInputManagerStub.java +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/KeypadInputManagerStub.java @@ -23,10 +23,19 @@ public class KeypadInputManagerStub implements KeypadInputManager { private final String TAG = KeypadInputManagerStub.class.getSimpleName(); + private int endpoint; + + public KeypadInputManagerStub(int endpoint) { + this.endpoint = endpoint; + } @Override public int sendKey(int keyCode) { - Log.d(TAG, "sendKey:" + keyCode); + Log.d(TAG, "sendKey:" + keyCode + " at " + endpoint); + + if (keyCode == KeypadInputManager.KEY_CODE_F4_YELLOW) { + return KEY_STATUS_UNSUPPORTED_KEY; + } return KEY_STATUS_SUCCESS; } } diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/LowPowerManagerStub.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/LowPowerManagerStub.java index 8dd9e2f8caab87..1885dc2f82cedf 100644 --- a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/LowPowerManagerStub.java +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/LowPowerManagerStub.java @@ -6,9 +6,15 @@ public class LowPowerManagerStub implements LowPowerManager { private final String TAG = LowPowerManagerStub.class.getSimpleName(); + private int endpoint; + + public LowPowerManagerStub(int endpoint) { + this.endpoint = endpoint; + } + @Override public boolean sleep() { - Log.d(TAG, "sleep"); + Log.d(TAG, "sleep at " + endpoint); return true; } } 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 index e3c2919e36c512..a3ffc0a995717a 100755 --- 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 @@ -23,9 +23,15 @@ public class MediaInputManagerStub implements MediaInputManager { private final String TAG = MediaInputManagerStub.class.getSimpleName(); + private int endpoint; + + public MediaInputManagerStub(int endpoint) { + this.endpoint = endpoint; + } + @Override public MediaInputInfo[] getInputList() { - MediaInputInfo[] info = new MediaInputInfo[2]; + MediaInputInfo[] info = new MediaInputInfo[3]; info[0] = new MediaInputInfo(); info[0].name = "HDMI 1"; info[0].description = "Living room Playstation"; @@ -33,39 +39,45 @@ public MediaInputInfo[] getInputList() { info[0].type = MediaInputInfo.INPUT_TYPE_HDMI; info[1] = new MediaInputInfo(); + info[1].name = "HDMI 2"; + info[1].description = "Living room XBox"; info[1].index = 1; info[1].type = MediaInputInfo.INPUT_TYPE_HDMI; + info[2] = new MediaInputInfo(); + info[2].index = 2; + info[2].type = MediaInputInfo.INPUT_TYPE_HDMI; + return info; } @Override public int getCurrentInput() { - Log.d(TAG, "getCurrentInput"); + Log.d(TAG, "getCurrentInput at " + endpoint); return 1; } @Override public boolean selectInput(int index) { - Log.d(TAG, "selectInput:" + index); + Log.d(TAG, "selectInput:" + index + " at " + endpoint); return true; } @Override public boolean showInputStatus() { - Log.d(TAG, "showInputStatus"); + Log.d(TAG, "showInputStatus at " + endpoint); return true; } @Override public boolean hideInputStatus() { - Log.d(TAG, "hideInputStatus"); + Log.d(TAG, "hideInputStatus at " + endpoint); return true; } @Override public boolean renameInput(int index, String name) { - Log.d(TAG, "renameInput index:" + index + " name:" + name); + Log.d(TAG, "renameInput index:" + index + " name:" + name + " at " + endpoint); return true; } } diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackManager.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackManager.java index 7972a49d93bffd..4a1b347b1b0d6b 100755 --- a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackManager.java +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackManager.java @@ -29,23 +29,17 @@ public interface MediaPlaybackManager { /** The duration, in milliseconds or 0 if the duration is not applicable */ int ATTRIBUTE_PLAYBACK_DURATION = 0x0002; - /** The position of playback (Position field) at the time (UpdateAt field) in milliseconds. */ - int ATTRIBUTE_PLAYBACK_POSITION_UPDATED_AT = 0x0003; - - /** The position of playback (Position field) at the time (UpdateAt field) in milliseconds. */ - int ATTRIBUTE_PLAYBACK_POSITION = 0x0004; - /** * The speed at which the current media is being played. 10000 means 1X, 5000 means 0.5X and 20000 * means 2X */ - int ATTRIBUTE_PLAYBACK_SPEED = 0x0005; + int ATTRIBUTE_PLAYBACK_SPEED = 0x0003; /** The earliest valid position to which a client MAY seek back, in milliseconds */ - int ATTRIBUTE_PLAYBACK_SEEK_RANGE_END = 0x0006; + int ATTRIBUTE_PLAYBACK_SEEK_RANGE_END = 0x0004; /** The furthest forward valid position to which a client MAY seek forward, in milliseconds */ - int ATTRIBUTE_PLAYBACK_SEEK_RANGE_START = 0x0007; + int ATTRIBUTE_PLAYBACK_SEEK_RANGE_START = 0x0005; int PLAYBACK_STATE_PLAYING = 0; int PLAYBACK_STATE_PAUSED = 1; @@ -122,4 +116,7 @@ public interface MediaPlaybackManager { * @return the response status defined in RESPONSE_STATUS_XXX */ int request(int cmd, long parameter); + + /** Get the position of playback (Position field) at the time (UpdateAt field) specified */ + MediaPlaybackPosition getPosition(); } diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackManagerStub.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackManagerStub.java index d4fb7552935e10..9e7c1d7bdca3ba 100755 --- a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackManagerStub.java +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackManagerStub.java @@ -19,46 +19,43 @@ package com.tcl.chip.tvapp; import android.util.Log; -import java.util.Date; /** Stub implement of MediaPlaybackManager, TV manufacture should have there own implements */ public class MediaPlaybackManagerStub implements MediaPlaybackManager { private final String TAG = MediaPlaybackManagerStub.class.getSimpleName(); + private int endpoint; + + public MediaPlaybackManagerStub(int endpoint) { + this.endpoint = endpoint; + } + @Override public long getAttributes(int attributesId) { switch (attributesId) { case ATTRIBUTE_PLAYBACK_STATE: - Log.d(TAG, "getAttributes CurrentState"); + Log.d(TAG, "getAttributes CurrentState at " + endpoint); return PLAYBACK_STATE_PLAYING; case ATTRIBUTE_PLAYBACK_START_TIME: - Log.d(TAG, "getAttributes StartTime"); + Log.d(TAG, "getAttributes StartTime at " + endpoint); return 100; case ATTRIBUTE_PLAYBACK_DURATION: - Log.d(TAG, "getAttributes Duration"); + Log.d(TAG, "getAttributes Duration at " + endpoint); return 5 * 60 * 1000; - case ATTRIBUTE_PLAYBACK_POSITION_UPDATED_AT: - Log.d(TAG, "getAttributes SampledPosition UpdatedAt"); - return new Date().getTime() * 1000; - - case ATTRIBUTE_PLAYBACK_POSITION: - Log.d(TAG, "getAttributes SampledPosition Position"); - return 3 * 60 * 1000; - case ATTRIBUTE_PLAYBACK_SPEED: - Log.d(TAG, "getAttributes SampledPosition PlaybackSpeed"); + Log.d(TAG, "getAttributes SampledPosition PlaybackSpeed at " + endpoint); return 10000; case ATTRIBUTE_PLAYBACK_SEEK_RANGE_END: - Log.d(TAG, "getAttributes SampledPosition SeekRangeEnd"); + Log.d(TAG, "getAttributes SampledPosition SeekRangeEnd at " + endpoint); return 5 * 60 * 1000; case ATTRIBUTE_PLAYBACK_SEEK_RANGE_START: - Log.d(TAG, "getAttributes SampledPosition SeekRangeStart"); + Log.d(TAG, "getAttributes SampledPosition SeekRangeStart at " + endpoint); return 200; } @@ -69,50 +66,55 @@ public long getAttributes(int attributesId) { public int request(int cmd, long parameter) { switch (cmd) { case REQUEST_PLAY: - Log.d(TAG, "request Play"); + Log.d(TAG, "request Play at " + endpoint); return RESPONSE_STATUS_SUCCESS; case REQUEST_PAUSE: - Log.d(TAG, "request pause"); + Log.d(TAG, "request pause at " + endpoint); return RESPONSE_STATUS_SUCCESS; case REQUEST_STOP: - Log.d(TAG, "request stop"); + Log.d(TAG, "request stop at " + endpoint); return RESPONSE_STATUS_SUCCESS; case REQUEST_START_OVER: - Log.d(TAG, "request start over"); + Log.d(TAG, "request start over at " + endpoint); return RESPONSE_STATUS_SUCCESS; case REQUEST_PREVIOUS: - Log.d(TAG, "request previous"); + Log.d(TAG, "request previous at " + endpoint); return RESPONSE_STATUS_SUCCESS; case REQUEST_NEXT: - Log.d(TAG, "request next"); + Log.d(TAG, "request next at " + endpoint); return RESPONSE_STATUS_SUCCESS; case REQUEST_REWIND: - Log.d(TAG, "request rewind"); + Log.d(TAG, "request rewind at " + endpoint); return RESPONSE_STATUS_SUCCESS; case REQUEST_FAST_FORWARD: - Log.d(TAG, "request fast forward"); + Log.d(TAG, "request fast forward at " + endpoint); return RESPONSE_STATUS_SUCCESS; case REQUEST_SKIP_FORWARD: - Log.d(TAG, "request skip forward " + parameter + " milliseconds"); + Log.d(TAG, "request skip forward " + parameter + " milliseconds at " + endpoint); return RESPONSE_STATUS_SUCCESS; case REQUEST_SKIP_BACKWARD: - Log.d(TAG, "request skip backward " + parameter + " milliseconds"); + Log.d(TAG, "request skip backward " + parameter + " milliseconds at " + endpoint); return RESPONSE_STATUS_SUCCESS; case REQUEST_SEEK: - Log.d(TAG, "request seek to " + parameter + " milliseconds"); + Log.d(TAG, "request seek to " + parameter + " milliseconds at " + endpoint); return RESPONSE_STATUS_SUCCESS; } return RESPONSE_STATUS_NOT_ALLOWED; } + + @Override + public MediaPlaybackPosition getPosition() { + return new MediaPlaybackPosition(3 * 60 * 1000); + } } diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackPosition.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackPosition.java new file mode 100644 index 00000000000000..0e8f8de2724d9e --- /dev/null +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/MediaPlaybackPosition.java @@ -0,0 +1,13 @@ +package com.tcl.chip.tvapp; + +import java.util.Date; + +public class MediaPlaybackPosition { + private long updatedAt; + private long position; + + public MediaPlaybackPosition(long position) { + this.position = position; + this.updatedAt = new Date().getTime() * 1000; + } +} 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 521a1c1dee70d7..71cc923a36f1b6 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 @@ -17,22 +17,39 @@ */ package com.tcl.chip.tvapp; +import android.util.Log; + public class TvApp { - public TvApp() {} + private TvAppCallback mCallback; + private static final String TAG = "TvApp"; + + public TvApp(TvAppCallback callback) { + mCallback = callback; + nativeInit(); + } + + private void postClusterInit(int clusterId, int endpoint) { + Log.d(TAG, "postClusterInit for " + clusterId + " at " + endpoint); + if (mCallback != null) { + mCallback.onClusterInit(this, clusterId, endpoint); + } + } + + public native void nativeInit(); - public native void setKeypadInputManager(KeypadInputManager manager); + public native void setKeypadInputManager(int endpoint, KeypadInputManager manager); - public native void setWakeOnLanManager(WakeOnLanManager manager); + public native void setWakeOnLanManager(int endpoint, WakeOnLanManager manager); - public native void setMediaInputManager(MediaInputManager manager); + public native void setMediaInputManager(int endpoint, MediaInputManager manager); - public native void setContentLaunchManager(ContentLaunchManager manager); + public native void setContentLaunchManager(int endpoint, ContentLaunchManager manager); - public native void setLowPowerManager(LowPowerManager manager); + public native void setLowPowerManager(int endpoint, LowPowerManager manager); - public native void setMediaPlaybackManager(MediaPlaybackManager manager); + public native void setMediaPlaybackManager(int endpoint, MediaPlaybackManager manager); - public native void setChannelManager(ChannelManager manager); + public native void setChannelManager(int endpoint, ChannelManager manager); static { System.loadLibrary("TvApp"); diff --git a/examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvAppCallback.java b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvAppCallback.java new file mode 100644 index 00000000000000..47fff94e1dadcc --- /dev/null +++ b/examples/tv-app/android/java/src/com/tcl/chip/tvapp/TvAppCallback.java @@ -0,0 +1,21 @@ +/* + * + * 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. + */ +package com.tcl.chip.tvapp; + +public interface TvAppCallback { + void onClusterInit(TvApp app, int clusterId, int endpoint); +} 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 index 315408f164181a..ab2b45935bf5a7 100644 --- 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 @@ -24,5 +24,5 @@ public interface WakeOnLanManager { * * @return Mac address in AA:BB:CC:DD:EE */ - String getMac(int endpoint); + String getMac(); } 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 index 24017e912900bb..4d7b17c5a75230 100644 --- 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 @@ -6,8 +6,14 @@ public class WakeOnLanManagerStub implements WakeOnLanManager { private final String TAG = WakeOnLanManagerStub.class.getSimpleName(); + private int endpoint; + + public WakeOnLanManagerStub(int endpoint) { + this.endpoint = endpoint; + } + @Override - public String getMac(int endpoint) { + public String getMac() { Log.d(TAG, "getMac for endpoint=" + endpoint); return "AA:BB:CC:DD:EE"; } diff --git a/examples/tv-app/linux/include/channel/ChannelManager.cpp b/examples/tv-app/linux/include/channel/ChannelManager.cpp index 066476c57c759e..64052dbec76d4c 100644 --- a/examples/tv-app/linux/include/channel/ChannelManager.cpp +++ b/examples/tv-app/linux/include/channel/ChannelManager.cpp @@ -20,36 +20,40 @@ using namespace chip; using namespace chip::app::Clusters::Channel; -std::list ChannelManager::HandleGetChannelList() +CHIP_ERROR ChannelManager::HandleGetChannelList(chip::app::AttributeValueEncoder & aEncoder) { - std::list list; // TODO: Insert code here - int maximumVectorSize = 2; + return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { + int maximumVectorSize = 2; - for (int i = 0; i < maximumVectorSize; ++i) - { - chip::app::Clusters::Channel::Structs::ChannelInfo::Type channelInfo; - channelInfo.affiliateCallSign = chip::CharSpan("exampleASign", strlen("exampleASign")); - channelInfo.callSign = chip::CharSpan("exampleCSign", strlen("exampleCSign")); - channelInfo.name = chip::CharSpan("exampleName", strlen("exampleName")); - channelInfo.majorNumber = static_cast(1 + i); - channelInfo.minorNumber = static_cast(2 + i); - list.push_back(channelInfo); - } - return list; + for (int i = 0; i < maximumVectorSize; ++i) + { + chip::app::Clusters::Channel::Structs::ChannelInfo::Type channelInfo; + channelInfo.affiliateCallSign = chip::CharSpan("exampleASign", strlen("exampleASign")); + channelInfo.callSign = chip::CharSpan("exampleCSign", strlen("exampleCSign")); + channelInfo.name = chip::CharSpan("exampleName", strlen("exampleName")); + channelInfo.majorNumber = static_cast(1 + i); + channelInfo.minorNumber = static_cast(2 + i); + + ReturnErrorOnFailure(encoder.Encode(channelInfo)); + } + + return CHIP_NO_ERROR; + }); } -chip::app::Clusters::Channel::Structs::LineupInfo::Type ChannelManager::HandleGetLineup() +CHIP_ERROR ChannelManager::HandleGetLineup(chip::app::AttributeValueEncoder & aEncoder) { chip::app::Clusters::Channel::Structs::LineupInfo::Type lineup; lineup.operatorName = chip::CharSpan("operatorName", strlen("operatorName")); lineup.lineupName = chip::CharSpan("lineupName", strlen("lineupName")); lineup.postalCode = chip::CharSpan("postalCode", strlen("postalCode")); lineup.lineupInfoType = chip::app::Clusters::Channel::LineupInfoTypeEnum::kMso; - return lineup; + + return aEncoder.Encode(lineup); } -chip::app::Clusters::Channel::Structs::ChannelInfo::Type ChannelManager::HandleGetCurrentChannel() +CHIP_ERROR ChannelManager::HandleGetCurrentChannel(chip::app::AttributeValueEncoder & aEncoder) { chip::app::Clusters::Channel::Structs::ChannelInfo::Type currentChannel; currentChannel.affiliateCallSign = chip::CharSpan("exampleASign", strlen("exampleASign")); @@ -57,10 +61,13 @@ chip::app::Clusters::Channel::Structs::ChannelInfo::Type ChannelManager::HandleG currentChannel.name = chip::CharSpan("exampleName", strlen("exampleName")); currentChannel.majorNumber = 1; currentChannel.minorNumber = 0; - return currentChannel; + + return aEncoder.Encode(currentChannel); } -Commands::ChangeChannelResponse::Type ChannelManager::HandleChangeChannel(const chip::CharSpan & match) +void ChannelManager::HandleChangeChannel( + const chip::CharSpan & match, + chip::app::CommandResponseHelper & responser) { Commands::ChangeChannelResponse::Type response; response.channelMatch.majorNumber = 1; @@ -69,7 +76,8 @@ Commands::ChangeChannelResponse::Type ChannelManager::HandleChangeChannel(const response.channelMatch.callSign = chip::CharSpan("callSign", strlen("callSign")); response.channelMatch.affiliateCallSign = chip::CharSpan("affiliateCallSign", strlen("affiliateCallSign")); response.errorType = chip::app::Clusters::Channel::ErrorTypeEnum::kMultipleMatches; - return response; + + responser.Success(response); } bool ChannelManager::HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) diff --git a/examples/tv-app/linux/include/channel/ChannelManager.h b/examples/tv-app/linux/include/channel/ChannelManager.h index f090b18150de27..372523fe9f426e 100644 --- a/examples/tv-app/linux/include/channel/ChannelManager.h +++ b/examples/tv-app/linux/include/channel/ChannelManager.h @@ -22,11 +22,13 @@ class ChannelManager : public chip::app::Clusters::Channel::Delegate { public: - std::list HandleGetChannelList() override; - chip::app::Clusters::Channel::Structs::LineupInfo::Type HandleGetLineup() override; - chip::app::Clusters::Channel::Structs::ChannelInfo::Type HandleGetCurrentChannel() override; + virtual CHIP_ERROR HandleGetChannelList(chip::app::AttributeValueEncoder & aEncoder) override; + virtual CHIP_ERROR HandleGetLineup(chip::app::AttributeValueEncoder & aEncoder) override; + virtual CHIP_ERROR HandleGetCurrentChannel(chip::app::AttributeValueEncoder & aEncoder) override; - chip::app::Clusters::Channel::Commands::ChangeChannelResponse::Type HandleChangeChannel(const chip::CharSpan & match) override; + virtual void HandleChangeChannel( + const chip::CharSpan & match, + chip::app::CommandResponseHelper & responser) override; bool HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) override; bool HandleSkipChannel(const uint16_t & count) override; }; diff --git a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp index 33891a9f9bbfa7..54ff9f3d8dd94a 100644 --- a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp +++ b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.cpp @@ -23,31 +23,35 @@ using namespace std; using namespace chip::app::Clusters::ContentLauncher; using namespace chip::AppPlatform; -Commands::LaunchResponse::Type ContentLauncherManager::HandleLaunchContent(chip::EndpointId endpointId, - const std::list & parameterList, - bool autoplay, const chip::CharSpan & data) +void ContentLauncherManager::HandleLaunchContent( + const std::list & parameterList, bool autoplay, const chip::CharSpan & data, + chip::app::CommandResponseHelper & responser) { - ChipLogProgress(Zcl, "ContentLauncherManager::HandleLaunchContent"); + ChipLogProgress(Zcl, "ContentLauncherManager::HandleLaunchContent for endpoint %d", mEndpointId); string dataString(data.data(), data.size()); + Commands::LaunchResponse::Type response; + #if CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED - ContentApp * app = chip::AppPlatform::AppPlatform::GetInstance().GetContentAppByEndpointId(endpointId); + ContentApp * app = chip::AppPlatform::AppPlatform::GetInstance().GetContentAppByEndpointId(mEndpointId); if (app != NULL) { - return app->GetContentLauncher()->LaunchContent(parameterList, autoplay, dataString); + response = app->GetContentLauncher()->LaunchContent(parameterList, autoplay, dataString); + responser.Success(response); + return; } #endif // CHIP_DEVICE_CONFIG_APP_PLATFORM_ENABLED // TODO: Insert code here - Commands::LaunchResponse::Type response; response.data = chip::CharSpan("exampleData", strlen("exampleData")); response.status = chip::app::Clusters::ContentLauncher::StatusEnum::kSuccess; - return response; + responser.Success(response); } -Commands::LaunchResponse::Type ContentLauncherManager::HandleLaunchUrl(const chip::CharSpan & contentUrl, - const chip::CharSpan & displayString, - const std::list & brandingInformation) +void ContentLauncherManager::HandleLaunchUrl( + const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, + const std::list & brandingInformation, + chip::app::CommandResponseHelper & responser) { ChipLogProgress(Zcl, "ContentLauncherManager::HandleLaunchUrl"); @@ -58,13 +62,18 @@ Commands::LaunchResponse::Type ContentLauncherManager::HandleLaunchUrl(const chi Commands::LaunchResponse::Type response; response.data = chip::CharSpan("exampleData", strlen("exampleData")); response.status = chip::app::Clusters::ContentLauncher::StatusEnum::kSuccess; - return response; + responser.Success(response); } -std::list ContentLauncherManager::HandleGetAcceptHeaderList() +CHIP_ERROR ContentLauncherManager::HandleGetAcceptHeaderList(chip::app::AttributeValueEncoder & aEncoder) { ChipLogProgress(Zcl, "ContentLauncherManager::HandleGetAcceptHeaderList"); - return { "example", "example" }; + return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { + chip::CharSpan data = chip::CharSpan("example", strlen("example")); + ReturnErrorOnFailure(encoder.Encode(data)); + ReturnErrorOnFailure(encoder.Encode(data)); + return CHIP_NO_ERROR; + }); } uint32_t ContentLauncherManager::HandleGetSupportedStreamingProtocols() diff --git a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h index 132afeb37a9812..0429c945548b8f 100644 --- a/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h +++ b/examples/tv-app/linux/include/content-launcher/ContentLauncherManager.h @@ -23,12 +23,19 @@ class ContentLauncherManager : public chip::app::Clusters::ContentLauncher::Delegate { public: - chip::app::Clusters::ContentLauncher::Commands::LaunchResponse::Type - HandleLaunchContent(chip::EndpointId endpointId, const std::list & parameterList, bool autoplay, - const chip::CharSpan & data) override; - chip::app::Clusters::ContentLauncher::Commands::LaunchResponse::Type - HandleLaunchUrl(const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, - const std::list & brandingInformation) override; - std::list HandleGetAcceptHeaderList() override; + ContentLauncherManager(chip::EndpointId endpointId) : mEndpointId(endpointId) {} + + void + HandleLaunchContent(const std::list & parameterList, bool autoplay, const chip::CharSpan & data, + chip::app::CommandResponseHelper & + responser) override; + void HandleLaunchUrl(const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, + const std::list & brandingInformation, + chip::app::CommandResponseHelper & + responser) override; + CHIP_ERROR HandleGetAcceptHeaderList(chip::app::AttributeValueEncoder & aEncoder) override; uint32_t HandleGetSupportedStreamingProtocols() override; + +private: + chip::EndpointId mEndpointId; }; diff --git a/examples/tv-app/linux/include/media-input/MediaInputManager.cpp b/examples/tv-app/linux/include/media-input/MediaInputManager.cpp index 4b654d0b838d87..b4128403672d50 100644 --- a/examples/tv-app/linux/include/media-input/MediaInputManager.cpp +++ b/examples/tv-app/linux/include/media-input/MediaInputManager.cpp @@ -20,22 +20,25 @@ using namespace chip; using namespace chip::app::Clusters::MediaInput; -std::list MediaInputManager::HandleGetInputList() +CHIP_ERROR MediaInputManager::HandleGetInputList(chip::app::AttributeValueEncoder & aEncoder) { - std::list list; // TODO: Insert code here - int maximumVectorSize = 2; - for (int i = 0; i < maximumVectorSize; ++i) - { - chip::app::Clusters::MediaInput::Structs::InputInfo::Type inputInfo; - inputInfo.description = chip::CharSpan("exampleDescription", strlen("exampleDescription")); - inputInfo.name = chip::CharSpan("exampleName", strlen("exampleName")); - inputInfo.inputType = chip::app::Clusters::MediaInput::InputTypeEnum::kHdmi; - inputInfo.index = static_cast(1 + i); - list.push_back(inputInfo); - } - return list; + return aEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { + int maximumVectorSize = 2; + for (int i = 0; i < maximumVectorSize; ++i) + { + chip::app::Clusters::MediaInput::Structs::InputInfo::Type inputInfo; + inputInfo.description = chip::CharSpan("exampleDescription", strlen("exampleDescription")); + inputInfo.name = chip::CharSpan("exampleName", strlen("exampleName")); + inputInfo.inputType = chip::app::Clusters::MediaInput::InputTypeEnum::kHdmi; + inputInfo.index = static_cast(1 + i); + + ReturnErrorOnFailure(encoder.Encode(inputInfo)); + } + + return CHIP_NO_ERROR; + }); } uint8_t MediaInputManager::HandleGetCurrentInput() diff --git a/examples/tv-app/linux/include/media-input/MediaInputManager.h b/examples/tv-app/linux/include/media-input/MediaInputManager.h index 84e0114f43c3f3..b2fa47c1013750 100644 --- a/examples/tv-app/linux/include/media-input/MediaInputManager.h +++ b/examples/tv-app/linux/include/media-input/MediaInputManager.h @@ -18,12 +18,13 @@ #pragma once +#include #include class MediaInputManager : public chip::app::Clusters::MediaInput::Delegate { public: - std::list HandleGetInputList() override; + CHIP_ERROR HandleGetInputList(chip::app::AttributeValueEncoder & aEncoder) override; uint8_t HandleGetCurrentInput() override; bool HandleSelectInput(const uint8_t index) override; bool HandleShowInputStatus() override; diff --git a/examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.cpp b/examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.cpp index 291c2951c221f8..1191612b84e2c4 100644 --- a/examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.cpp +++ b/examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.cpp @@ -21,7 +21,7 @@ using namespace chip; using namespace chip::app::Clusters::WakeOnLan; -chip::CharSpan WakeOnLanManager::HandleGetMacAddress() +CHIP_ERROR WakeOnLanManager::HandleGetMacAddress(chip::app::AttributeValueEncoder & aEncoder) { - return chip::CharSpan("00:00:00:00:00", strlen("00:00:00:00:00")); + return aEncoder.Encode(chip::CharSpan("00:00:00:00:00", strlen("00:00:00:00:00"))); } diff --git a/examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.h b/examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.h index ba4a6964a5bfc8..63217020e9ab11 100644 --- a/examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.h +++ b/examples/tv-app/linux/include/wake-on-lan/WakeOnLanManager.h @@ -23,5 +23,5 @@ class WakeOnLanManager : public chip::app::Clusters::WakeOnLan::Delegate { public: - chip::CharSpan HandleGetMacAddress() override; + CHIP_ERROR HandleGetMacAddress(chip::app::AttributeValueEncoder & aEncoder) override; }; diff --git a/examples/tv-app/linux/main.cpp b/examples/tv-app/linux/main.cpp index e0549f20559cd9..f6133e5217dda2 100644 --- a/examples/tv-app/linux/main.cpp +++ b/examples/tv-app/linux/main.cpp @@ -57,7 +57,6 @@ bool emberAfBasicClusterMfgSpecificPingCallback(chip::app::CommandHandler * comm } namespace { -static ContentLauncherManager contentLauncherManager; static AccountLoginManager accountLoginManager; static ApplicationBasicManager applicationBasicManager; static ApplicationLauncherManager applicationLauncherManager; @@ -101,7 +100,7 @@ int main(int argc, char * argv[]) void emberAfContentLauncherClusterInitCallback(EndpointId endpoint) { ChipLogProgress(Zcl, "TV Linux App: ContentLauncher::SetDelegate"); - chip::app::Clusters::ContentLauncher::SetDelegate(endpoint, &contentLauncherManager); + chip::app::Clusters::ContentLauncher::SetDelegate(endpoint, new ContentLauncherManager(endpoint)); } void emberAfAccountLoginClusterInitCallback(EndpointId endpoint) diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index 01506f2c38036e..4cdbe5d86e1dd3 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -49,6 +49,7 @@ static_library("app") { "CASESessionManager.cpp", "CASESessionManager.h", "CommandHandler.cpp", + "CommandResponseHelper.h", "CommandSender.cpp", "DefaultAttributePersistenceProvider.cpp", "DeviceProxy.cpp", diff --git a/src/app/CommandResponseHelper.h b/src/app/CommandResponseHelper.h new file mode 100644 index 00000000000000..840a8a590fc5ff --- /dev/null +++ b/src/app/CommandResponseHelper.h @@ -0,0 +1,61 @@ +/* + * + * 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 + +namespace chip { +namespace app { + +template +class CommandResponseHelper +{ +public: + CommandResponseHelper(app::CommandHandler * command, const app::ConcreteCommandPath & commandPath) : + mCommand(command), mCommandPath(commandPath), responsed(false) + {} + + CHIP_ERROR Success(const CommandData & response) + { + CHIP_ERROR err = mCommand->AddResponseData(mCommandPath, response); + if (err == CHIP_NO_ERROR) + { + responsed = true; + } + return err; + }; + + void Response(EmberAfStatus status) + { + emberAfSendImmediateDefaultResponse(status); + responsed = true; + } + + bool IsResponsed() { return responsed; } + +private: + app::CommandHandler * mCommand; + app::ConcreteCommandPath mCommandPath; + bool responsed; +}; + +} // namespace app +} // namespace chip diff --git a/src/app/clusters/channel-server/channel-delegate.h b/src/app/clusters/channel-server/channel-delegate.h index 0195c1004389b7..6c382bb83dd09b 100644 --- a/src/app/clusters/channel-server/channel-delegate.h +++ b/src/app/clusters/channel-server/channel-delegate.h @@ -19,7 +19,8 @@ #pragma once #include - +#include +#include #include #include @@ -34,13 +35,14 @@ namespace Channel { class Delegate { public: - virtual std::list HandleGetChannelList() = 0; - virtual chip::app::Clusters::Channel::Structs::LineupInfo::Type HandleGetLineup() = 0; - virtual chip::app::Clusters::Channel::Structs::ChannelInfo::Type HandleGetCurrentChannel() = 0; - - virtual Commands::ChangeChannelResponse::Type HandleChangeChannel(const chip::CharSpan & match) = 0; - virtual bool HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) = 0; - virtual bool HandleSkipChannel(const uint16_t & count) = 0; + virtual CHIP_ERROR HandleGetChannelList(app::AttributeValueEncoder & aEncoder) = 0; + virtual CHIP_ERROR HandleGetLineup(app::AttributeValueEncoder & aEncoder) = 0; + virtual CHIP_ERROR HandleGetCurrentChannel(app::AttributeValueEncoder & aEncoder) = 0; + + virtual void HandleChangeChannel(const chip::CharSpan & match, + CommandResponseHelper & responser) = 0; + virtual bool HandleChangeChannelByNumber(const uint16_t & majorNumber, const uint16_t & minorNumber) = 0; + virtual bool HandleSkipChannel(const uint16_t & count) = 0; virtual ~Delegate() = default; }; diff --git a/src/app/clusters/channel-server/channel-server.cpp b/src/app/clusters/channel-server/channel-server.cpp index c5f08c427a750d..bc68441b9389fe 100644 --- a/src/app/clusters/channel-server/channel-server.cpp +++ b/src/app/clusters/channel-server/channel-server.cpp @@ -38,12 +38,11 @@ ******************************************************************************* ******************************************************************************/ -#include -#include - #include #include #include +#include +#include #include #include @@ -149,26 +148,17 @@ CHIP_ERROR ChannelAttrAccess::Read(const app::ConcreteReadAttributePath & aPath, CHIP_ERROR ChannelAttrAccess::ReadChannelListAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate) { - std::list channelList = delegate->HandleGetChannelList(); - return aEncoder.EncodeList([channelList](const auto & encoder) -> CHIP_ERROR { - for (const auto & channel : channelList) - { - ReturnErrorOnFailure(encoder.Encode(channel)); - } - return CHIP_NO_ERROR; - }); + return delegate->HandleGetChannelList(aEncoder); } CHIP_ERROR ChannelAttrAccess::ReadLineupAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate) { - Structs::LineupInfo::Type lineup = delegate->HandleGetLineup(); - return aEncoder.Encode(lineup); + return delegate->HandleGetLineup(aEncoder); } CHIP_ERROR ChannelAttrAccess::ReadCurrentChannelAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate) { - Structs::ChannelInfo::Type currentChannel = delegate->HandleGetCurrentChannel(); - return aEncoder.Encode(currentChannel); + return delegate->HandleGetCurrentChannel(aEncoder); } } // anonymous namespace @@ -184,20 +174,26 @@ bool emberAfChannelClusterChangeChannelRequestCallback(app::CommandHandler * com auto & match = commandData.match; + app::CommandResponseHelper responser(command, commandPath); + Delegate * delegate = GetDelegate(endpoint); VerifyOrExit(isDelegateNull(delegate, endpoint) != true, err = CHIP_ERROR_INCORRECT_STATE); { - Commands::ChangeChannelResponse::Type response = delegate->HandleChangeChannel(match); - err = command->AddResponseData(commandPath, response); - SuccessOrExit(err); + delegate->HandleChangeChannel(match, responser); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Zcl, "emberAfChannelClusterChangeChannelRequestCallback error: %s", err.AsString()); + } + + // If isDelegateNull, no one will call responser, so IsResponsed will be false + if (!responser.IsResponsed()) + { emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_FAILURE); } + return true; } diff --git a/src/app/clusters/content-launch-server/content-launch-delegate.h b/src/app/clusters/content-launch-server/content-launch-delegate.h index 0ac1da2bf96a0a..766f8aff26907a 100644 --- a/src/app/clusters/content-launch-server/content-launch-delegate.h +++ b/src/app/clusters/content-launch-server/content-launch-delegate.h @@ -21,6 +21,8 @@ #include #include +#include +#include #include #include @@ -35,14 +37,14 @@ namespace ContentLauncher { class Delegate { public: - virtual Commands::LaunchResponse::Type HandleLaunchContent(chip::EndpointId endpointId, - const std::list & parameterList, bool autoplay, - const chip::CharSpan & data) = 0; + virtual void HandleLaunchContent(const std::list & parameterList, bool autoplay, const chip::CharSpan & data, + CommandResponseHelper & responser) = 0; - virtual Commands::LaunchResponse::Type HandleLaunchUrl(const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, - const std::list & brandingInformation) = 0; + virtual void HandleLaunchUrl(const chip::CharSpan & contentUrl, const chip::CharSpan & displayString, + const std::list & brandingInformation, + CommandResponseHelper & responser) = 0; - virtual std::list HandleGetAcceptHeaderList() = 0; + virtual CHIP_ERROR HandleGetAcceptHeaderList(app::AttributeValueEncoder & aEncoder) = 0; virtual uint32_t HandleGetSupportedStreamingProtocols() = 0; diff --git a/src/app/clusters/content-launch-server/content-launch-server.cpp b/src/app/clusters/content-launch-server/content-launch-server.cpp index 286e141bd324b1..079f459eb974eb 100644 --- a/src/app/clusters/content-launch-server/content-launch-server.cpp +++ b/src/app/clusters/content-launch-server/content-launch-server.cpp @@ -149,15 +149,7 @@ CHIP_ERROR ContentLauncherAttrAccess::Read(const app::ConcreteReadAttributePath CHIP_ERROR ContentLauncherAttrAccess::ReadAcceptHeaderAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate) { - std::list acceptHeaderList = delegate->HandleGetAcceptHeaderList(); - return aEncoder.EncodeList([acceptHeaderList](const auto & encoder) -> CHIP_ERROR { - for (const auto & acceptedHeader : acceptHeaderList) - { - CharSpan span(acceptedHeader.c_str(), acceptedHeader.length()); - ReturnErrorOnFailure(encoder.Encode(span)); - } - return CHIP_NO_ERROR; - }); + return delegate->HandleGetAcceptHeaderList(aEncoder); } CHIP_ERROR ContentLauncherAttrAccess::ReadSupportedStreamingProtocolsAttribute(app::AttributeValueEncoder & aEncoder, @@ -185,20 +177,23 @@ bool emberAfContentLauncherClusterLaunchContentRequestCallback( // auto searchIterator = commandData.search.begin(); std::list parameterList; + app::CommandResponseHelper responser(commandObj, commandPath); + Delegate * delegate = GetDelegate(endpoint); VerifyOrExit(isDelegateNull(delegate, endpoint) != true, err = CHIP_ERROR_INCORRECT_STATE); - { - Commands::LaunchResponse::Type response = delegate->HandleLaunchContent(endpoint, parameterList, autoplay, data); - err = commandObj->AddResponseData(commandPath, response); - SuccessOrExit(err); + delegate->HandleLaunchContent(parameterList, autoplay, data, responser); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Zcl, "emberAfContentLauncherClusterLaunchContentRequestCallback error: %s", err.AsString()); + } + // If isDelegateNull, no one will call responser, so IsResponsed will be false + if (!responser.IsResponsed()) + { emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_FAILURE); } @@ -218,20 +213,23 @@ bool emberAfContentLauncherClusterLaunchURLRequestCallback( // auto brandingInformationIterator = commandData.brandingInformation.begin(); std::list brandingInformationList; + app::CommandResponseHelper responser(commandObj, commandPath); + Delegate * delegate = GetDelegate(endpoint); VerifyOrExit(isDelegateNull(delegate, endpoint) != true, err = CHIP_ERROR_INCORRECT_STATE); - { - Commands::LaunchResponse::Type response = delegate->HandleLaunchUrl(contentUrl, displayString, brandingInformationList); - err = commandObj->AddResponseData(commandPath, response); - SuccessOrExit(err); + delegate->HandleLaunchUrl(contentUrl, displayString, brandingInformationList, responser); } exit: if (err != CHIP_NO_ERROR) { ChipLogError(Zcl, "emberAfContentLauncherClusterLaunchURLCallback error: %s", err.AsString()); + } + // If isDelegateNull, no one will call responser, so IsResponsed will be false + if (!responser.IsResponsed()) + { emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_FAILURE); } diff --git a/src/app/clusters/media-input-server/media-input-delegate.h b/src/app/clusters/media-input-server/media-input-delegate.h index b596a9c5e58b2f..862298b9352777 100644 --- a/src/app/clusters/media-input-server/media-input-delegate.h +++ b/src/app/clusters/media-input-server/media-input-delegate.h @@ -19,7 +19,7 @@ #pragma once #include - +#include #include #include @@ -34,12 +34,13 @@ namespace MediaInput { class Delegate { public: - virtual std::list HandleGetInputList() = 0; - virtual uint8_t HandleGetCurrentInput() = 0; - virtual bool HandleSelectInput(const uint8_t index) = 0; - virtual bool HandleShowInputStatus() = 0; - virtual bool HandleHideInputStatus() = 0; - virtual bool HandleRenameInput(const uint8_t index, const chip::CharSpan & name) = 0; + // no easy way to handle the return memory of app::Clusters::MediaInput::Structs::InputInfo::Type list, so encoder is used + virtual CHIP_ERROR HandleGetInputList(app::AttributeValueEncoder & aEncoder) = 0; + virtual uint8_t HandleGetCurrentInput() = 0; + virtual bool HandleSelectInput(const uint8_t index) = 0; + virtual bool HandleShowInputStatus() = 0; + virtual bool HandleHideInputStatus() = 0; + virtual bool HandleRenameInput(const uint8_t index, const chip::CharSpan & name) = 0; virtual ~Delegate() = default; }; diff --git a/src/app/clusters/media-input-server/media-input-server.cpp b/src/app/clusters/media-input-server/media-input-server.cpp index 896a759ba0a758..a1b72a6dd0c23a 100644 --- a/src/app/clusters/media-input-server/media-input-server.cpp +++ b/src/app/clusters/media-input-server/media-input-server.cpp @@ -129,14 +129,7 @@ CHIP_ERROR MediaInputAttrAccess::Read(const app::ConcreteReadAttributePath & aPa CHIP_ERROR MediaInputAttrAccess::ReadInputListAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate) { - std::list inputList = delegate->HandleGetInputList(); - return aEncoder.EncodeList([inputList](const auto & encoder) -> CHIP_ERROR { - for (const auto & input : inputList) - { - ReturnErrorOnFailure(encoder.Encode(input)); - } - return CHIP_NO_ERROR; - }); + return delegate->HandleGetInputList(aEncoder); } CHIP_ERROR MediaInputAttrAccess::ReadCurrentInputAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate) diff --git a/src/app/clusters/wake-on-lan-server/wake-on-lan-delegate.h b/src/app/clusters/wake-on-lan-server/wake-on-lan-delegate.h index 400dda253a867d..1f4bed9177733a 100644 --- a/src/app/clusters/wake-on-lan-server/wake-on-lan-delegate.h +++ b/src/app/clusters/wake-on-lan-server/wake-on-lan-delegate.h @@ -19,6 +19,7 @@ #pragma once #include +#include namespace chip { namespace app { @@ -31,7 +32,7 @@ namespace WakeOnLan { class Delegate { public: - virtual chip::CharSpan HandleGetMacAddress() = 0; + virtual CHIP_ERROR HandleGetMacAddress(app::AttributeValueEncoder & aEncoder) = 0; virtual ~Delegate() = default; }; diff --git a/src/app/clusters/wake-on-lan-server/wake-on-lan-server.cpp b/src/app/clusters/wake-on-lan-server/wake-on-lan-server.cpp index 9b6e5d20e9634a..658430cc873c1b 100644 --- a/src/app/clusters/wake-on-lan-server/wake-on-lan-server.cpp +++ b/src/app/clusters/wake-on-lan-server/wake-on-lan-server.cpp @@ -126,8 +126,7 @@ CHIP_ERROR WakeOnLanAttrAccess::Read(const app::ConcreteReadAttributePath & aPat CHIP_ERROR WakeOnLanAttrAccess::ReadMacAddressAttribute(app::AttributeValueEncoder & aEncoder, Delegate * delegate) { - chip::CharSpan macAddress = delegate->HandleGetMacAddress(); - return aEncoder.Encode(macAddress); + return delegate->HandleGetMacAddress(aEncoder); } } // anonymous namespace diff --git a/src/lib/support/JniTypeWrappers.h b/src/lib/support/JniTypeWrappers.h index 64d03301333b5a..ced71bb0e1b793 100644 --- a/src/lib/support/JniTypeWrappers.h +++ b/src/lib/support/JniTypeWrappers.h @@ -37,7 +37,13 @@ class JniUtfString mChars = env->GetStringUTFChars(string, 0); mDataLength = env->GetStringUTFLength(string); } - ~JniUtfString() { mEnv->ReleaseStringUTFChars(mString, mChars); } + ~JniUtfString() + { + if (mString != nullptr) + { + mEnv->ReleaseStringUTFChars(mString, mChars); + } + } const char * c_str() const { return mChars; }