From e82fd5dd36a6484b3e924ded22f5d1d54fc651aa Mon Sep 17 00:00:00 2001 From: chrisdecenzo Date: Thu, 15 Feb 2024 21:42:59 -0800 Subject: [PATCH 1/6] sample app for java --- .../tv/server/service/MatterServant.java | 3 + examples/tv-app/android/BUILD.gn | 6 + .../tv-app/android/java/MessagesManager.cpp | 425 ++++++++++++++++++ .../tv-app/android/java/MessagesManager.h | 63 +++ examples/tv-app/android/java/TVApp-JNI.cpp | 6 + .../com/matter/tv/server/tvapp/Clusters.java | 2 +- .../com/matter/tv/server/tvapp/Message.java | 56 +++ .../server/tvapp/MessageResponseOption.java | 30 ++ .../tv/server/tvapp/MessagesManager.java | 36 ++ .../tv/server/tvapp/MessagesManagerStub.java | 72 +++ .../src/com/matter/tv/server/tvapp/TvApp.java | 2 + 11 files changed, 700 insertions(+), 1 deletion(-) create mode 100644 examples/tv-app/android/java/MessagesManager.cpp create mode 100644 examples/tv-app/android/java/MessagesManager.h create mode 100644 examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java create mode 100644 examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java create mode 100644 examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java create mode 100644 examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java index 79b02f01386769..540798aae913b7 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/service/MatterServant.java @@ -41,6 +41,7 @@ import com.matter.tv.server.tvapp.LowPowerManagerStub; import com.matter.tv.server.tvapp.MediaInputManagerStub; import com.matter.tv.server.tvapp.MediaPlaybackManagerStub; +import com.matter.tv.server.tvapp.MessagesManagerStub; import com.matter.tv.server.tvapp.OnOffManagerStub; import com.matter.tv.server.tvapp.TvApp; import com.matter.tv.server.tvapp.WakeOnLanManagerStub; @@ -96,6 +97,8 @@ public void init(@NonNull Context context) { app.setMediaPlaybackManager(endpoint, new MediaPlaybackManagerStub(endpoint)); } else if (clusterId == Clusters.ClusterId_Channel) { app.setChannelManager(endpoint, new ChannelManagerStub(endpoint)); + } else if (clusterId == Clusters.ClusterId_Messaging) { + app.setMessagesManager(endpoint, new MessagesManagerStub(endpoint)); } else if (clusterId == Clusters.ClusterId_OnOff) { mOnOffEndpoint = endpoint; app.setOnOffManager(endpoint, new OnOffManagerStub(endpoint)); diff --git a/examples/tv-app/android/BUILD.gn b/examples/tv-app/android/BUILD.gn index 63de5a515b0754..47157a271edfe8 100644 --- a/examples/tv-app/android/BUILD.gn +++ b/examples/tv-app/android/BUILD.gn @@ -69,6 +69,8 @@ shared_library("jni") { "java/MediaInputManager.h", "java/MediaPlaybackManager.cpp", "java/MediaPlaybackManager.h", + "java/MessagesManager.cpp", + "java/MessagesManager.h", "java/MyUserPrompter-JNI.cpp", "java/MyUserPrompter-JNI.h", "java/MyUserPrompterResolver-JNI.cpp", @@ -143,6 +145,10 @@ android_library("java") { "java/src/com/matter/tv/server/tvapp/MediaPlaybackManagerStub.java", "java/src/com/matter/tv/server/tvapp/MediaPlaybackPosition.java", "java/src/com/matter/tv/server/tvapp/MediaTrack.java", + "java/src/com/matter/tv/server/tvapp/Message.java", + "java/src/com/matter/tv/server/tvapp/MessageResponseOption.java", + "java/src/com/matter/tv/server/tvapp/MessagesManager.java", + "java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java", "java/src/com/matter/tv/server/tvapp/OnOffManager.java", "java/src/com/matter/tv/server/tvapp/OnOffManagerStub.java", "java/src/com/matter/tv/server/tvapp/TvApp.java", diff --git a/examples/tv-app/android/java/MessagesManager.cpp b/examples/tv-app/android/java/MessagesManager.cpp new file mode 100644 index 00000000000000..7e43237614a00b --- /dev/null +++ b/examples/tv-app/android/java/MessagesManager.cpp @@ -0,0 +1,425 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MessagesManager.h" +#include "TvApp-JNI.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters::Messages; +using namespace chip::Uint8; +using MessageResponseOption = chip::app::Clusters::Messages::Structs::MessageResponseOptionStruct::Type; + +/** @brief Messages 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 emberAfMessagesClusterInitCallback(EndpointId endpoint) +{ + ChipLogProgress(Zcl, "------------TV Android App: Messages::PostClusterInit"); + TvAppJNIMgr().PostClusterInit(chip::app::Clusters::Messages::Id, endpoint); +} + +void MessagesManager::NewManager(jint endpoint, jobject manager) +{ + ChipLogProgress(Zcl, "-----TV Android App: Messages::SetDefaultDelegate"); + MessagesManager * mgr = new MessagesManager(); + mgr->InitializeWithObjects(manager); + chip::app::Clusters::Messages::SetDefaultDelegate(static_cast(endpoint), mgr); +} + +void MessagesManager::InitializeWithObjects(jobject managerObject) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Failed to GetEnvForCurrentThread for MessagesManager")); + + VerifyOrReturn(mMessagesManagerObject.Init(managerObject) == CHIP_NO_ERROR, + ChipLogError(Zcl, "Failed to init mMessagesManagerObject")); + + jclass managerClass = env->GetObjectClass(managerObject); + VerifyOrReturn(managerClass != nullptr, ChipLogError(Zcl, "Failed to get MessagesManager Java class")); + + mGetMessagesMethod = env->GetMethodID(managerClass, "getMessages", "()[Lcom/matter/tv/server/tvapp/Message;"); + if (mGetMessagesMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MessagesManager 'getMessages' method"); + env->ExceptionClear(); + } + + mPresentMessagesMethod = env->GetMethodID( + managerClass, "presentMessages", + "(Ljava/lang/String;Lcom/matter/tv/server/tvapp/Message$PriorityType;IJILjava/lang/String;Ljava/util/Vector;)Z"); + if (mPresentMessagesMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MessagesManager 'presentMessages' method"); + env->ExceptionClear(); + } + + mCancelMessagesMethod = env->GetMethodID(managerClass, "cancelMessage", "(Ljava/lang/String;)Z"); + if (mCancelMessagesMethod == nullptr) + { + ChipLogError(Zcl, "Failed to access MessagesManager 'cancelMessage' method"); + env->ExceptionClear(); + } +} + +uint32_t MessagesManager::GetFeatureMap(chip::EndpointId endpoint) +{ + if (endpoint >= MATTER_DM_CONTENT_LAUNCHER_CLUSTER_SERVER_ENDPOINT_COUNT) + { + return kEndpointFeatureMap; + } + + BitMask FeatureMap; + FeatureMap.Set(Feature::kReceivedConfirmation); + FeatureMap.Set(Feature::kConfirmationResponse); + FeatureMap.Set(Feature::kConfirmationReply); + FeatureMap.Set(Feature::kProtectedMessages); + + uint32_t featureMap = FeatureMap.Raw(); + // forcing to all features since this implementation supports all + // Attributes::FeatureMap::Get(endpoint, &featureMap); + return featureMap; +} + +CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); + JniLocalReferenceScope scope(env); + + ChipLogProgress(Zcl, "Received MessagesManager::HandleGetMessages"); + VerifyOrExit(mMessagesManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mGetMessagesMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { + jobjectArray messagesList = (jobjectArray) env->CallObjectMethod(mMessagesManagerObject.ObjectRef(), mGetMessagesMethod); + if (env->ExceptionCheck()) + { + ChipLogError(Zcl, "Java exception in MessagesManager::HandleGetMessages"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INCORRECT_STATE; + } + + jint length = env->GetArrayLength(messagesList); + + for (jint i = 0; i < length; i++) + { + std::vector options; + uint8_t buf[kMessageIdLength]; + + chip::app::Clusters::Messages::Structs::MessageStruct::Type message; + jobject messageObject = env->GetObjectArrayElement(messagesList, i); + jclass messageClass = env->GetObjectClass(messageObject); + + jfieldID getMessageIdField = env->GetFieldID(messageClass, "messageId", "Ljava/lang/String;"); + jstring jmessageId = static_cast(env->GetObjectField(messageObject, getMessageIdField)); + JniUtfString messageId(env, jmessageId); + if (jmessageId != nullptr) + { + VerifyOrReturnValue(chip::Encoding::HexToBytes(messageId.charSpan().data(), messageId.charSpan().size(), buf, + sizeof(buf)) == sizeof(buf), + CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(Zcl, "HexToBytes failed")); + message.messageID = ByteSpan(buf, sizeof(buf)); + } + + jfieldID getMessageTextField = env->GetFieldID(messageClass, "messageText", "Ljava/lang/String;"); + jstring jmessageText = static_cast(env->GetObjectField(messageObject, getMessageTextField)); + JniUtfString messageText(env, jmessageText); + if (jmessageText != nullptr) + { + message.messageText = messageText.charSpan(); + } + + jfieldID messageControlField = env->GetFieldID(messageClass, "messageControl", "I"); + jint jmessageControl = env->GetIntField(messageObject, messageControlField); + message.messageControl = static_cast>(static_cast(jmessageControl)); + + jfieldID startTimeField = env->GetFieldID(messageClass, "startTime", "J"); + jint jstartTime = env->GetIntField(messageObject, startTimeField); + if (jstartTime >= 0) + { + message.startTime = DataModel::Nullable(static_cast(jstartTime)); + } + + jfieldID durationField = env->GetFieldID(messageClass, "duration", "I"); + jint jduration = env->GetIntField(messageObject, durationField); + if (jduration >= 0) + { + message.duration = DataModel::Nullable(static_cast(jduration)); + } + + jfieldID getResponseOptionsField = env->GetFieldID(messageClass, "responseOptions", "Ljava/lang/Vector;"); + + jobjectArray responsesArray = (jobjectArray) env->GetObjectField(messageObject, getResponseOptionsField); + jint size = env->GetArrayLength(responsesArray); + if (size > 0) + { + // MessageResponseOption * optionArray = new MessageResponseOption[static_cast(size)]; + // VerifyOrReturnError(optionArray != nullptr, CHIP_ERROR_NO_MEMORY, + // ChipLogProgress(Controller, "HandleGetMessages MessageResponseOption alloc failed")); + // optionToFree.push_back(optionArray); // TODO + + for (jint j = 0; j < size; j++) + { + jobject responseOptionObject = env->GetObjectArrayElement(responsesArray, j); + jclass responseOptionClass = env->GetObjectClass(responseOptionObject); + + jfieldID getLabelField = env->GetFieldID(responseOptionClass, "label", "Ljava/lang/String;"); + jstring jlabelText = static_cast(env->GetObjectField(responseOptionObject, getLabelField)); + JniUtfString label(env, jlabelText); + MessageResponseOption option; + if (jlabelText != nullptr) + { + option.label = Optional(label.charSpan()); + } + + jfieldID idField = env->GetFieldID(responseOptionClass, "id", "J"); + jint jid = env->GetIntField(responseOptionObject, idField); + option.messageResponseID = Optional(static_cast(jid)); + options.push_back(option); + } + + message.responses = Optional>( + DataModel::List(options.data(), options.size())); + } + ReturnErrorOnFailure(encoder.Encode(message)); + } + + return CHIP_NO_ERROR; + }); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "MessagesManager::HandleGetMessages status error: %s", err.AsString()); + } + return err; +} + +CHIP_ERROR MessagesManager::HandleGetActiveMessageIds(AttributeValueEncoder & aEncoder) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); + JniLocalReferenceScope scope(env); + + ChipLogProgress(Zcl, "Received MessagesManager::HandleGetActiveMessageIds"); + VerifyOrExit(mMessagesManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mGetMessagesMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { + jobjectArray messagesList = (jobjectArray) env->CallObjectMethod(mMessagesManagerObject.ObjectRef(), mGetMessagesMethod); + if (env->ExceptionCheck()) + { + ChipLogError(Zcl, "Java exception in MessagesManager::HandleGetActiveMessageIds"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INCORRECT_STATE; + } + + jint length = env->GetArrayLength(messagesList); + + for (jint i = 0; i < length; i++) + { + jobject messageObject = env->GetObjectArrayElement(messagesList, i); + jclass messageClass = env->GetObjectClass(messageObject); + + jfieldID getMessageIdField = env->GetFieldID(messageClass, "messageId", "Ljava/lang/String;"); + jstring jmessageId = static_cast(env->GetObjectField(messageObject, getMessageIdField)); + JniUtfString messageId(env, jmessageId); + if (jmessageId != nullptr) + { + uint8_t buf[kMessageIdLength]; + VerifyOrReturnValue(chip::Encoding::HexToBytes(messageId.charSpan().data(), messageId.charSpan().size(), buf, + sizeof(buf)) == sizeof(buf), + CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(Zcl, "HexToBytes failed")); + + ReturnErrorOnFailure(encoder.Encode(ByteSpan(buf, sizeof(buf)))); + } + } + + return CHIP_NO_ERROR; + }); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "MessagesManager::HandleGetMessages status error: %s", err.AsString()); + } + + return err; +} + +CHIP_ERROR MessagesManager::HandlePresentMessagesRequest( + const ByteSpan & messageId, const MessagePriorityEnum & priority, const BitMask & messageControl, + const DataModel::Nullable & startTime, const DataModel::Nullable & duration, const CharSpan & messageText, + const Optional> & responses) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); + JniLocalReferenceScope scope(env); + + ChipLogProgress(Zcl, "Received MessagesManager::HandlePresentMessagesRequest"); + VerifyOrReturnError(mMessagesManagerObject.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "Invalid mMessagesManagerObject")); + VerifyOrReturnError(mPresentMessagesMethod != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "mPresentMessagesMethod null")); + + env->ExceptionClear(); + { + char hex_buf[(kMessageIdLength * 2) + 1]; + VerifyOrReturnError( + CHIP_NO_ERROR == + chip::Encoding::BytesToUppercaseHexString(messageId.data(), messageId.size(), hex_buf, sizeof(hex_buf)), + CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "BytesToUppercaseHexString failed")); + + UtfString jIdentifier(env, hex_buf); + UtfString jMessageText(env, messageText); + + jint jcontrol = static_cast(messageControl.Raw()); + jint jduration = -1; + if (duration.IsNull()) + { + jduration = static_cast(duration.Value()); + } + jlong jstartTime = -1; + if (startTime.IsNull()) + { + jstartTime = static_cast(startTime.Value()); + } + + jint jniPriority = static_cast(priority); + jclass priorityTypeClass; + VerifyOrReturnError(CHIP_NO_ERROR != + chip::JniReferences::GetInstance().GetLocalClassRef( + env, "com/matter/tv/server/tvapp/Message$PriorityType", priorityTypeClass), + CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find class Message$PriorityType")); + jmethodID priorityTypeCtor = env->GetMethodID(priorityTypeClass, "", "(I)V"); + VerifyOrReturnError(priorityTypeCtor != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "Could not find Message$PriorityType constructor")); + jobject jpriority = env->NewObject(priorityTypeClass, priorityTypeCtor, jniPriority); + + jclass vectorClass = env->FindClass("java/util/Vector"); + VerifyOrReturnError(vectorClass != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find class Vector")); + jmethodID vectorCtor = env->GetMethodID(priorityTypeClass, "", "()V"); + VerifyOrReturnError(vectorCtor != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "Could not find Vector constructor")); + jobject joptions = env->NewObject(vectorClass, vectorCtor); + + jmethodID vectorAdd = env->GetMethodID(priorityTypeClass, "add", "(Ljava/lang/Object;)Z"); + + if (responses.HasValue()) + { + jclass messageResponseOptionClass; + VerifyOrReturnError(CHIP_NO_ERROR != + chip::JniReferences::GetInstance().GetLocalClassRef( + env, "com/matter/tv/server/tvapp/MessageResponseOption", messageResponseOptionClass), + CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find class MessageResponseOption")); + jmethodID messageResponseOptionCtor = env->GetMethodID(messageResponseOptionClass, "", "(JLjava/lang/String;)V"); + VerifyOrReturnError(messageResponseOptionCtor != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "Could not find MessageResponseOption constructor")); + + auto iter = responses.Value().begin(); + while (iter.Next()) + { + auto & response = iter.GetValue(); + + jlong jniid = static_cast(response.messageResponseID.Value()); + UtfString jlabel(env, response.label.Value()); + + jobject jmessageResponseOption = + env->NewObject(messageResponseOptionClass, messageResponseOptionCtor, jniid, jlabel.jniValue()); + + // add to vector + env->CallBooleanMethod(joptions, vectorAdd, jmessageResponseOption); + if (env->ExceptionCheck()) + { + ChipLogError(DeviceLayer, "Java exception in MessagesManager::HandlePresentMessagesRequest"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INTERNAL; + } + } + } + + env->CallBooleanMethod(mMessagesManagerObject.ObjectRef(), mPresentMessagesMethod, jIdentifier.jniValue(), jpriority, + jcontrol, jstartTime, jduration, jMessageText.jniValue(), joptions); + if (env->ExceptionCheck()) + { + ChipLogError(DeviceLayer, "Java exception in MessagesManager::HandlePresentMessagesRequest"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INTERNAL; + } + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR MessagesManager::HandleCancelMessagesRequest(const DataModel::DecodableList & messageIds) +{ + JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); + VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); + JniLocalReferenceScope scope(env); + + ChipLogProgress(Zcl, "Received MessagesManager::HandleCancelMessagesRequest"); + VerifyOrReturnError(mMessagesManagerObject.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "Invalid mMessagesManagerObject")); + VerifyOrReturnError(mCancelMessagesMethod != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "mCancelMessagesMethod null")); + + env->ExceptionClear(); + + auto iter = messageIds.begin(); + while (iter.Next()) + { + auto & id = iter.GetValue(); + + char hex_buf[(kMessageIdLength * 2) + 1]; + VerifyOrReturnError(CHIP_NO_ERROR == + chip::Encoding::BytesToUppercaseHexString(id.data(), id.size(), hex_buf, sizeof(hex_buf)), + CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "BytesToUppercaseHexString failed")); + + UtfString jIdentifier(env, hex_buf); + + env->CallBooleanMethod(mMessagesManagerObject.ObjectRef(), mCancelMessagesMethod, jIdentifier.jniValue()); + if (env->ExceptionCheck()) + { + ChipLogError(DeviceLayer, "Java exception in MessagesManager::HandleCancelMessagesRequest"); + env->ExceptionDescribe(); + env->ExceptionClear(); + return CHIP_ERROR_INTERNAL; + } + } + return CHIP_NO_ERROR; +} diff --git a/examples/tv-app/android/java/MessagesManager.h b/examples/tv-app/android/java/MessagesManager.h new file mode 100644 index 00000000000000..563192a542bdf6 --- /dev/null +++ b/examples/tv-app/android/java/MessagesManager.h @@ -0,0 +1,63 @@ +/** + * + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +#include +#include + +class MessagesManager : public chip::app::Clusters::Messages::Delegate +{ +public: + static void NewManager(jint endpoint, jobject manager); + void InitializeWithObjects(jobject managerObject); + + // Commands + CHIP_ERROR HandlePresentMessagesRequest( + const chip::ByteSpan & messageId, const chip::app::Clusters::Messages::MessagePriorityEnum & priority, + const chip::BitMask & messageControl, + const chip::app::DataModel::Nullable & startTime, const chip::app::DataModel::Nullable & duration, + const chip::CharSpan & messageText, + const chip::Optional< + chip::app::DataModel::DecodableList> & + responses) override; + CHIP_ERROR HandleCancelMessagesRequest(const chip::app::DataModel::DecodableList & messageIds) override; + + // Attributes + CHIP_ERROR HandleGetMessages(chip::app::AttributeValueEncoder & aEncoder) override; + CHIP_ERROR HandleGetActiveMessageIds(chip::app::AttributeValueEncoder & aEncoder) override; + + // Global Attributes + uint32_t GetFeatureMap(chip::EndpointId endpoint) override; + // uint16_t GetClusterRevision(chip::EndpointId endpoint) override; + +private: + chip::JniGlobalReference mMessagesManagerObject; + jmethodID mGetMessagesMethod = nullptr; + + jmethodID mPresentMessagesMethod = nullptr; + jmethodID mCancelMessagesMethod = nullptr; + + // TODO: set this based upon meta data from app + static constexpr uint32_t kEndpointFeatureMap = 15; + // static constexpr uint16_t kClusterRevision = 1; +}; diff --git a/examples/tv-app/android/java/TVApp-JNI.cpp b/examples/tv-app/android/java/TVApp-JNI.cpp index 6bbc35ed297415..72279c49dca9d7 100644 --- a/examples/tv-app/android/java/TVApp-JNI.cpp +++ b/examples/tv-app/android/java/TVApp-JNI.cpp @@ -27,6 +27,7 @@ #include "LowPowerManager.h" #include "MediaInputManager.h" #include "MediaPlaybackManager.h" +#include "MessagesManager.h" #include "MyUserPrompter-JNI.h" #include "OnOffManager.h" #include "WakeOnLanManager.h" @@ -137,6 +138,11 @@ JNI_METHOD(void, setMediaPlaybackManager)(JNIEnv *, jobject, jint endpoint, jobj MediaPlaybackManager::NewManager(endpoint, manager); } +JNI_METHOD(void, setMessagesManager)(JNIEnv *, jobject, jint endpoint, jobject manager) +{ + MessagesManager::NewManager(endpoint, manager); +} + JNI_METHOD(void, setChannelManager)(JNIEnv *, jobject, jint endpoint, jobject manager) { ChannelManager::NewManager(endpoint, manager); diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Clusters.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Clusters.java index d699ca68ea6365..5928c1b10181c7 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Clusters.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Clusters.java @@ -129,7 +129,7 @@ public class Clusters { public static final long ClusterId_ApplicationBasic = 0x0000050D; public static final long ClusterId_AccountLogin = 0x0000050E; public static final long ClusterId_TestCluster = 0xFFF1FC05; - public static final long ClusterId_Messaging = 0x00000703; + public static final long ClusterId_Messaging = 0x00000097; public static final long ClusterId_ApplianceIdentification = 0x00000B00; public static final long ClusterId_MeterIdentification = 0x00000B01; public static final long ClusterId_ApplianceEventsAndAlert = 0x00000B02; diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java new file mode 100644 index 00000000000000..e75a607d6d0a67 --- /dev/null +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.matter.tv.server.tvapp; + +import java.util.Vector; + +public class Message { + + public class PriorityType { + int priority; + public PriorityType(int priority) + { + this.priority = priority; + } + } + + public String messageId; + public PriorityType priority; + public int messageControl; + public long startTime; + public int duration; + public String messageText; + public Vector responseOptions; + + public Message(String messageId, + PriorityType priority, + int messageControl, + long startTime, + int duration, + String messageText, + Vector responseOptions) + { + this.messageId = messageId; + this.priority = priority; + this.messageControl = messageControl; + this.startTime = startTime; + this.duration = duration; + this.messageText = messageText; + this.responseOptions = responseOptions; + } +} diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java new file mode 100644 index 00000000000000..837297967c90ea --- /dev/null +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.matter.tv.server.tvapp; + +public class MessageResponseOption { + public long id; + public String label; + + public MessageResponseOption( + long id, + String label) { + this.id = id; + this.label = label; + } + } diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java new file mode 100644 index 00000000000000..5958707e8b3bf9 --- /dev/null +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java @@ -0,0 +1,36 @@ + /* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.matter.tv.server.tvapp; + +import java.util.Vector; +import com.matter.tv.server.tvapp.Message.PriorityType; + +public interface MessagesManager { + + Message[] getMessages(); + + boolean presentMessages(String messageId, + PriorityType priority, + int messageControl, + long startTime, + int duration, + String messageText, + Vector responseOptions); + + boolean cancelMessage(String messageId); +} diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java new file mode 100644 index 00000000000000..1703eb345158e7 --- /dev/null +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.matter.tv.server.tvapp; + +import android.util.Log; +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +import com.matter.tv.server.tvapp.Message.PriorityType; + +public class MessagesManagerStub implements MessagesManager { + private static final String TAG = MessagesManagerStub.class.getSimpleName(); + + private int endpoint; + + private Map messages = new HashMap(); + + public MessagesManagerStub(int endpoint) { + this.endpoint = endpoint; + Log.d(TAG, "MessagesManagerStub: at " + this.endpoint); + } + + @Override + public Message[] getMessages() { + Log.d(TAG, "getMessages: at " + this.endpoint); + return messages.values().toArray(new Message[0]); + } + + @Override + public boolean presentMessages(String messageId, + PriorityType priority, + int messageControl, + long startTime, + int duration, + String messageText, + Vector responseOptions) { + Log.d(TAG, "presentMessages: at " + this.endpoint + " id:" + messageId+ " text:"+messageText); + messages.put(messageId, new Message(messageId, + priority, + messageControl, + startTime, + duration, + messageText, + responseOptions)); + return true; + } + + @Override + public boolean cancelMessage(String messageId) + { + Log.d(TAG, "cancelMessage: at " + this.endpoint + " messageId:"+messageId); + messages.remove(messageId); + return true; // per spec, succeed unless error + } + +} diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java index d8bb564370afa4..eaf207e45f3618 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/TvApp.java @@ -57,6 +57,8 @@ private void postClusterInit(long clusterId, int endpoint) { public native void setMediaPlaybackManager(int endpoint, MediaPlaybackManager manager); + public native void setMessagesManager(int endpoint, MessagesManager manager); + public native void setChannelManager(int endpoint, ChannelManager manager); public native void setOnOffManager(int endpoint, OnOffManager manager); From ea479f357eba421b07a52a03ce3360636e4c7dcf Mon Sep 17 00:00:00 2001 From: chrisdecenzo Date: Sun, 18 Feb 2024 07:20:10 -0800 Subject: [PATCH 2/6] present and list messages --- .../tv-app/android/java/ChannelManager.cpp | 11 +- .../android/java/ContentLauncherManager.cpp | 7 ++ .../tv-app/android/java/MediaInputManager.cpp | 8 +- .../android/java/MediaPlaybackManager.cpp | 10 +- .../tv-app/android/java/MessagesManager.cpp | 109 +++++++++--------- .../com/matter/tv/server/tvapp/Message.java | 16 +-- .../tv/server/tvapp/MessagesManager.java | 7 +- .../tv/server/tvapp/MessagesManagerStub.java | 32 ++++- 8 files changed, 121 insertions(+), 79 deletions(-) diff --git a/examples/tv-app/android/java/ChannelManager.cpp b/examples/tv-app/android/java/ChannelManager.cpp index 3c0efcab9f8cdc..d2f239f503f8a6 100644 --- a/examples/tv-app/android/java/ChannelManager.cpp +++ b/examples/tv-app/android/java/ChannelManager.cpp @@ -66,6 +66,8 @@ CHIP_ERROR ChannelManager::HandleGetChannelList(AttributeValueEncoder & aEncoder VerifyOrExit(mChannelManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetChannelListMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { jobjectArray channelInfoList = (jobjectArray) env->CallObjectMethod(mChannelManagerObject.ObjectRef(), mGetChannelListMethod); @@ -144,6 +146,8 @@ CHIP_ERROR ChannelManager::HandleGetLineup(AttributeValueEncoder & aEncoder) VerifyOrExit(mChannelManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetLineupMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + { jobject channelLineupObject = env->CallObjectMethod(mChannelManagerObject.ObjectRef(), mGetLineupMethod); if (channelLineupObject != nullptr) @@ -207,6 +211,8 @@ CHIP_ERROR ChannelManager::HandleGetCurrentChannel(AttributeValueEncoder & aEnco VerifyOrExit(mChannelManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetCurrentChannelMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + { jobject channelInfoObject = env->CallObjectMethod(mChannelManagerObject.ObjectRef(), mGetCurrentChannelMethod); if (channelInfoObject != nullptr) @@ -282,9 +288,10 @@ void ChannelManager::HandleChangeChannel(CommandResponseHelperExceptionClear(); + { UtfString jniname(env, name.c_str()); - env->ExceptionClear(); jobject channelObject = env->CallObjectMethod(mChannelManagerObject.ObjectRef(), mChangeChannelMethod, jniname.jniValue()); if (env->ExceptionCheck()) { @@ -394,6 +401,8 @@ void ChannelManager::HandleGetProgramGuide( VerifyOrExit(mChannelManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetProgramGuideMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + { // NOTE: this example app does not pass the Data, PageToken, ChannelsArray or ExternalIdList through to the Java layer UtfString jData(env, ""); diff --git a/examples/tv-app/android/java/ContentLauncherManager.cpp b/examples/tv-app/android/java/ContentLauncherManager.cpp index caa14b04f9e938..503fb4a21240db 100644 --- a/examples/tv-app/android/java/ContentLauncherManager.cpp +++ b/examples/tv-app/android/java/ContentLauncherManager.cpp @@ -61,6 +61,7 @@ void ContentLauncherManager::HandleLaunchContent(CommandResponseHelperExceptionClear(); { UtfString jData(env, data); @@ -116,6 +117,8 @@ void ContentLauncherManager::HandleLaunchUrl(CommandResponseHelperExceptionClear(); + { UtfString jContentUrl(env, contentUrl); UtfString jDisplayString(env, displayString); @@ -170,6 +173,8 @@ CHIP_ERROR ContentLauncherManager::HandleGetAcceptHeaderList(AttributeValueEncod VerifyOrExit(mContentLauncherManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetAcceptHeaderMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { jobjectArray acceptedHeadersArray = (jobjectArray) env->CallObjectMethod(mContentLauncherManagerObject.ObjectRef(), mGetAcceptHeaderMethod); @@ -213,6 +218,8 @@ uint32_t ContentLauncherManager::HandleGetSupportedStreamingProtocols() VerifyOrExit(mContentLauncherManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetSupportedStreamingProtocolsMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + { jlong jSupportedStreamingProtocols = env->CallLongMethod(mContentLauncherManagerObject.ObjectRef(), mGetSupportedStreamingProtocolsMethod); diff --git a/examples/tv-app/android/java/MediaInputManager.cpp b/examples/tv-app/android/java/MediaInputManager.cpp index bbc575b6eab378..45dad793fc1b85 100644 --- a/examples/tv-app/android/java/MediaInputManager.cpp +++ b/examples/tv-app/android/java/MediaInputManager.cpp @@ -60,6 +60,8 @@ CHIP_ERROR MediaInputManager::HandleGetInputList(chip::app::AttributeValueEncode VerifyOrExit(mMediaInputManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetInputListMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { jobjectArray inputArray = (jobjectArray) env->CallObjectMethod(mMediaInputManagerObject.ObjectRef(), mGetInputListMethod); if (env->ExceptionCheck()) @@ -130,7 +132,8 @@ uint8_t MediaInputManager::HandleGetCurrentInput() ChipLogProgress(Zcl, "Received MediaInputManager::HandleGetCurrentInput"); VerifyOrExit(mMediaInputManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetCurrentInputMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); - VerifyOrExit(env != NULL, err = CHIP_JNI_ERROR_NO_ENV); + + env->ExceptionClear(); { index = env->CallIntMethod(mMediaInputManagerObject.ObjectRef(), mGetCurrentInputMethod); @@ -239,9 +242,10 @@ bool MediaInputManager::HandleRenameInput(const uint8_t index, const chip::CharS VerifyOrExit(mMediaInputManagerObject.HasValidObjectRef(), ChipLogError(Zcl, "mMediaInputManagerObject is not valid")); VerifyOrExit(mRenameInputMethod != nullptr, ChipLogError(Zcl, "mHideInputStatusMethod null")); + env->ExceptionClear(); + { UtfString jniInputname(env, inputname.data()); - env->ExceptionClear(); ret = env->CallBooleanMethod(mMediaInputManagerObject.ObjectRef(), mRenameInputMethod, static_cast(index), jniInputname.jniValue()); if (env->ExceptionCheck()) diff --git a/examples/tv-app/android/java/MediaPlaybackManager.cpp b/examples/tv-app/android/java/MediaPlaybackManager.cpp index 62abeb12ec30eb..4d2fd3450640c0 100644 --- a/examples/tv-app/android/java/MediaPlaybackManager.cpp +++ b/examples/tv-app/android/java/MediaPlaybackManager.cpp @@ -179,6 +179,8 @@ CHIP_ERROR MediaPlaybackManager::HandleGetAvailableTracks(bool audio, AttributeV VerifyOrExit(mMediaPlaybackManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetAvailableTracksMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + return aEncoder.EncodeList([this, env, audio](const auto & encoder) -> CHIP_ERROR { jobjectArray trackList = (jobjectArray) env->CallObjectMethod(mMediaPlaybackManagerObject.ObjectRef(), mGetAvailableTracksMethod, static_cast(audio)); @@ -328,9 +330,11 @@ bool MediaPlaybackManager::HandleActivateTrack(bool audio, const chip::CharSpan ChipLogProgress(Zcl, "MediaPlaybackManager::HandleActivateAudioTrack"); VerifyOrExit(mMediaPlaybackManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mActivateTrackMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + env->ExceptionClear(); + { UtfString jniid(env, id.c_str()); - env->ExceptionClear(); ret = env->CallIntMethod(mMediaPlaybackManagerObject.ObjectRef(), mActivateTrackMethod, static_cast(audio), jniid.jniValue()); if (env->ExceptionCheck()) @@ -450,6 +454,8 @@ uint64_t MediaPlaybackManager::HandleMediaRequestGetAttribute(MediaPlaybackReque VerifyOrExit(mMediaPlaybackManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetAttributeMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + jAttributeValue = env->CallLongMethod(mMediaPlaybackManagerObject.ObjectRef(), mGetAttributeMethod, static_cast(attribute)); if (env->ExceptionCheck()) @@ -491,6 +497,8 @@ long MediaPlaybackManager::HandleMediaRequestGetLongAttribute(MediaPlaybackReque VerifyOrExit(mMediaPlaybackManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetAttributeMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + jAttributeValue = env->CallLongMethod(mMediaPlaybackManagerObject.ObjectRef(), mGetAttributeMethod, static_cast(attribute)); if (env->ExceptionCheck()) diff --git a/examples/tv-app/android/java/MessagesManager.cpp b/examples/tv-app/android/java/MessagesManager.cpp index 7e43237614a00b..d65de16a99e4e5 100644 --- a/examples/tv-app/android/java/MessagesManager.cpp +++ b/examples/tv-app/android/java/MessagesManager.cpp @@ -74,9 +74,8 @@ void MessagesManager::InitializeWithObjects(jobject managerObject) env->ExceptionClear(); } - mPresentMessagesMethod = env->GetMethodID( - managerClass, "presentMessages", - "(Ljava/lang/String;Lcom/matter/tv/server/tvapp/Message$PriorityType;IJILjava/lang/String;Ljava/util/Vector;)Z"); + mPresentMessagesMethod = + env->GetMethodID(managerClass, "presentMessages", "(Ljava/lang/String;IIJILjava/lang/String;Ljava/util/HashMap;)Z"); if (mPresentMessagesMethod == nullptr) { ChipLogError(Zcl, "Failed to access MessagesManager 'presentMessages' method"); @@ -117,6 +116,8 @@ CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); JniLocalReferenceScope scope(env); + env->ExceptionClear(); + ChipLogProgress(Zcl, "Received MessagesManager::HandleGetMessages"); VerifyOrExit(mMessagesManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetMessagesMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); @@ -136,6 +137,7 @@ CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) for (jint i = 0; i < length; i++) { std::vector options; + std::vector optionLabels; uint8_t buf[kMessageIdLength]; chip::app::Clusters::Messages::Structs::MessageStruct::Type message; @@ -165,8 +167,15 @@ CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) jint jmessageControl = env->GetIntField(messageObject, messageControlField); message.messageControl = static_cast>(static_cast(jmessageControl)); + jfieldID priorityField = env->GetFieldID(messageClass, "priority", "I"); + jint jpriority = env->GetIntField(messageObject, priorityField); + if (jpriority >= 0) + { + message.priority = MessagePriorityEnum(static_cast(jpriority)); + } + jfieldID startTimeField = env->GetFieldID(messageClass, "startTime", "J"); - jint jstartTime = env->GetIntField(messageObject, startTimeField); + jlong jstartTime = env->GetLongField(messageObject, startTimeField); if (jstartTime >= 0) { message.startTime = DataModel::Nullable(static_cast(jstartTime)); @@ -179,34 +188,32 @@ CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) message.duration = DataModel::Nullable(static_cast(jduration)); } - jfieldID getResponseOptionsField = env->GetFieldID(messageClass, "responseOptions", "Ljava/lang/Vector;"); + jfieldID getResponseOptionsField = + env->GetFieldID(messageClass, "responseOptions", "[Lcom/matter/tv/server/tvapp/MessageResponseOption;"); jobjectArray responsesArray = (jobjectArray) env->GetObjectField(messageObject, getResponseOptionsField); jint size = env->GetArrayLength(responsesArray); if (size > 0) { - // MessageResponseOption * optionArray = new MessageResponseOption[static_cast(size)]; - // VerifyOrReturnError(optionArray != nullptr, CHIP_ERROR_NO_MEMORY, - // ChipLogProgress(Controller, "HandleGetMessages MessageResponseOption alloc failed")); - // optionToFree.push_back(optionArray); // TODO - for (jint j = 0; j < size; j++) { + MessageResponseOption option; + jobject responseOptionObject = env->GetObjectArrayElement(responsesArray, j); jclass responseOptionClass = env->GetObjectClass(responseOptionObject); + jfieldID idField = env->GetFieldID(responseOptionClass, "id", "J"); + jlong jid = env->GetLongField(responseOptionObject, idField); + option.messageResponseID = Optional(static_cast(jid)); + jfieldID getLabelField = env->GetFieldID(responseOptionClass, "label", "Ljava/lang/String;"); jstring jlabelText = static_cast(env->GetObjectField(responseOptionObject, getLabelField)); - JniUtfString label(env, jlabelText); - MessageResponseOption option; - if (jlabelText != nullptr) - { - option.label = Optional(label.charSpan()); - } + VerifyOrReturnValue(jlabelText != nullptr, CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(Zcl, "jlabelText null")); + JniUtfString * label = new JniUtfString(env, jlabelText); + optionLabels.push_back(label); + + option.label = Optional(label->charSpan()); - jfieldID idField = env->GetFieldID(responseOptionClass, "id", "J"); - jint jid = env->GetIntField(responseOptionObject, idField); - option.messageResponseID = Optional(static_cast(jid)); options.push_back(option); } @@ -214,6 +221,10 @@ CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) DataModel::List(options.data(), options.size())); } ReturnErrorOnFailure(encoder.Encode(message)); + for (JniUtfString * optionLabel : optionLabels) + { + delete optionLabel; + } } return CHIP_NO_ERROR; @@ -238,6 +249,8 @@ CHIP_ERROR MessagesManager::HandleGetActiveMessageIds(AttributeValueEncoder & aE VerifyOrExit(mMessagesManagerObject.HasValidObjectRef(), err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mGetMessagesMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + env->ExceptionClear(); + return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { jobjectArray messagesList = (jobjectArray) env->CallObjectMethod(mMessagesManagerObject.ObjectRef(), mGetMessagesMethod); if (env->ExceptionCheck()) @@ -309,60 +322,50 @@ CHIP_ERROR MessagesManager::HandlePresentMessagesRequest( jint jcontrol = static_cast(messageControl.Raw()); jint jduration = -1; - if (duration.IsNull()) + if (!duration.IsNull()) { jduration = static_cast(duration.Value()); } jlong jstartTime = -1; - if (startTime.IsNull()) + if (!startTime.IsNull()) { jstartTime = static_cast(startTime.Value()); } - jint jniPriority = static_cast(priority); - jclass priorityTypeClass; - VerifyOrReturnError(CHIP_NO_ERROR != - chip::JniReferences::GetInstance().GetLocalClassRef( - env, "com/matter/tv/server/tvapp/Message$PriorityType", priorityTypeClass), - CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find class Message$PriorityType")); - jmethodID priorityTypeCtor = env->GetMethodID(priorityTypeClass, "", "(I)V"); - VerifyOrReturnError(priorityTypeCtor != nullptr, CHIP_ERROR_INCORRECT_STATE, - ChipLogError(Zcl, "Could not find Message$PriorityType constructor")); - jobject jpriority = env->NewObject(priorityTypeClass, priorityTypeCtor, jniPriority); - - jclass vectorClass = env->FindClass("java/util/Vector"); - VerifyOrReturnError(vectorClass != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find class Vector")); - jmethodID vectorCtor = env->GetMethodID(priorityTypeClass, "", "()V"); - VerifyOrReturnError(vectorCtor != nullptr, CHIP_ERROR_INCORRECT_STATE, - ChipLogError(Zcl, "Could not find Vector constructor")); - jobject joptions = env->NewObject(vectorClass, vectorCtor); - - jmethodID vectorAdd = env->GetMethodID(priorityTypeClass, "add", "(Ljava/lang/Object;)Z"); + jint jpriority = static_cast(priority); + + jclass hashMapClass = env->FindClass("java/util/HashMap"); + VerifyOrReturnError(hashMapClass != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find class HashMap")); + jmethodID hashMapCtor = env->GetMethodID(hashMapClass, "", "()V"); + VerifyOrReturnError(hashMapCtor != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "Could not find HashMap constructor")); + jobject joptions = env->NewObject(hashMapClass, hashMapCtor); + VerifyOrReturnError(joptions != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not create HashMap")); if (responses.HasValue()) { - jclass messageResponseOptionClass; - VerifyOrReturnError(CHIP_NO_ERROR != - chip::JniReferences::GetInstance().GetLocalClassRef( - env, "com/matter/tv/server/tvapp/MessageResponseOption", messageResponseOptionClass), - CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find class MessageResponseOption")); - jmethodID messageResponseOptionCtor = env->GetMethodID(messageResponseOptionClass, "", "(JLjava/lang/String;)V"); - VerifyOrReturnError(messageResponseOptionCtor != nullptr, CHIP_ERROR_INCORRECT_STATE, - ChipLogError(Zcl, "Could not find MessageResponseOption constructor")); + jmethodID hashMapPut = + env->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + VerifyOrReturnError(hashMapPut != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find HashMap put")); + + jclass longClass = env->FindClass("java/lang/Long"); + VerifyOrReturnError(longClass != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not find class Long")); + jmethodID longCtor = env->GetMethodID(longClass, "", "(J)V"); + VerifyOrReturnError(longCtor != nullptr, CHIP_ERROR_INCORRECT_STATE, + ChipLogError(Zcl, "Could not find Long constructor")); auto iter = responses.Value().begin(); while (iter.Next()) { auto & response = iter.GetValue(); - jlong jniid = static_cast(response.messageResponseID.Value()); UtfString jlabel(env, response.label.Value()); - jobject jmessageResponseOption = - env->NewObject(messageResponseOptionClass, messageResponseOptionCtor, jniid, jlabel.jniValue()); + jobject jlong = env->NewObject(longClass, longCtor, response.messageResponseID.Value()); + VerifyOrReturnError(jlong != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not create Long")); - // add to vector - env->CallBooleanMethod(joptions, vectorAdd, jmessageResponseOption); + // add to HashMap + env->CallObjectMethod(joptions, hashMapPut, jlong, jlabel.jniValue()); if (env->ExceptionCheck()) { ChipLogError(DeviceLayer, "Java exception in MessagesManager::HandlePresentMessagesRequest"); diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java index e75a607d6d0a67..49faa3db4b82ba 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java @@ -21,29 +21,21 @@ public class Message { - public class PriorityType { - int priority; - public PriorityType(int priority) - { - this.priority = priority; - } - } - public String messageId; - public PriorityType priority; + public int priority; public int messageControl; public long startTime; public int duration; public String messageText; - public Vector responseOptions; + public MessageResponseOption responseOptions[]; public Message(String messageId, - PriorityType priority, + int priority, int messageControl, long startTime, int duration, String messageText, - Vector responseOptions) + MessageResponseOption responseOptions[]) { this.messageId = messageId; this.priority = priority; diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java index 5958707e8b3bf9..30ab402feea57a 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java @@ -17,20 +17,19 @@ */ package com.matter.tv.server.tvapp; -import java.util.Vector; -import com.matter.tv.server.tvapp.Message.PriorityType; +import java.util.HashMap; public interface MessagesManager { Message[] getMessages(); boolean presentMessages(String messageId, - PriorityType priority, + int priority, int messageControl, long startTime, int duration, String messageText, - Vector responseOptions); + HashMap responseOptions); boolean cancelMessage(String messageId); } diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java index 1703eb345158e7..1a422385f013f0 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java @@ -20,10 +20,9 @@ import android.util.Log; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.Vector; -import com.matter.tv.server.tvapp.Message.PriorityType; - public class MessagesManagerStub implements MessagesManager { private static final String TAG = MessagesManagerStub.class.getSimpleName(); @@ -34,6 +33,18 @@ public class MessagesManagerStub implements MessagesManager { public MessagesManagerStub(int endpoint) { this.endpoint = endpoint; Log.d(TAG, "MessagesManagerStub: at " + this.endpoint); + + HashMap responseOptions = new HashMap(); + responseOptions.put(new Long(1), "Yes"); + responseOptions.put(new Long(2), "No"); + presentMessages("31323334353637383930313233343536", + 1, + 1, + 30, + 60, + "TestMessage", + responseOptions); + Log.d(TAG, "MessagesManagerStub: added dummy message"); } @Override @@ -44,20 +55,29 @@ public Message[] getMessages() { @Override public boolean presentMessages(String messageId, - PriorityType priority, + int priority, int messageControl, long startTime, int duration, String messageText, - Vector responseOptions) { + HashMap responseOptions) { Log.d(TAG, "presentMessages: at " + this.endpoint + " id:" + messageId+ " text:"+messageText); - messages.put(messageId, new Message(messageId, + MessageResponseOption[] options = new MessageResponseOption[responseOptions.size()]; + int i=0; + + for (Map.Entry set : responseOptions.entrySet()) { + Log.d(TAG, "presentMessages option: key:"+set.getKey()+" value:"+set.getValue()); + options[i] = new MessageResponseOption(set.getKey().longValue(), set.getValue()); + i++; + } + + messages.put(messageId, new Message(messageId, priority, messageControl, startTime, duration, messageText, - responseOptions)); + options)); return true; } From d6e6041e3991b2a009c73b9769bbae290b2ea7e7 Mon Sep 17 00:00:00 2001 From: chrisdecenzo Date: Sun, 18 Feb 2024 08:18:55 -0800 Subject: [PATCH 3/6] address feedback --- .../tv-app/android/java/ChannelManager.cpp | 9 ++++ .../java/ContentAppAttributeDelegate.cpp | 2 + .../java/ContentAppCommandDelegate.cpp | 2 + .../android/java/ContentLauncherManager.cpp | 4 ++ .../android/java/KeypadInputManager.cpp | 1 + examples/tv-app/android/java/LevelManager.cpp | 1 + .../tv-app/android/java/LowPowerManager.cpp | 1 + .../tv-app/android/java/MediaInputManager.cpp | 6 +++ .../android/java/MediaPlaybackManager.cpp | 8 +++ .../tv-app/android/java/MessagesManager.cpp | 52 ++++++++++++++----- .../android/java/MyUserPrompter-JNI.cpp | 4 ++ examples/tv-app/android/java/OnOffManager.cpp | 1 + .../tv-app/android/java/WakeOnLanManager.cpp | 1 + .../server/tvapp/MessageResponseOption.java | 4 +- 14 files changed, 80 insertions(+), 16 deletions(-) diff --git a/examples/tv-app/android/java/ChannelManager.cpp b/examples/tv-app/android/java/ChannelManager.cpp index d2f239f503f8a6..c7067132e46e9d 100644 --- a/examples/tv-app/android/java/ChannelManager.cpp +++ b/examples/tv-app/android/java/ChannelManager.cpp @@ -57,6 +57,7 @@ void ChannelManager::NewManager(jint endpoint, jobject manager) CHIP_ERROR ChannelManager::HandleGetChannelList(AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -136,6 +137,7 @@ CHIP_ERROR ChannelManager::HandleGetChannelList(AttributeValueEncoder & aEncoder CHIP_ERROR ChannelManager::HandleGetLineup(AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; chip::app::Clusters::Channel::Structs::LineupInfoStruct::Type lineupInfo; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -201,6 +203,7 @@ CHIP_ERROR ChannelManager::HandleGetLineup(AttributeValueEncoder & aEncoder) CHIP_ERROR ChannelManager::HandleGetCurrentChannel(AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; chip::app::Clusters::Channel::Structs::ChannelInfoStruct::Type channelInfo; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -279,6 +282,7 @@ CHIP_ERROR ChannelManager::HandleGetCurrentChannel(AttributeValueEncoder & aEnco void ChannelManager::HandleChangeChannel(CommandResponseHelper & helper, const CharSpan & match) { + DeviceLayer::StackUnlock unlock; std::string name(match.data(), match.size()); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturn(env != nullptr, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -326,6 +330,7 @@ void ChannelManager::HandleChangeChannel(CommandResponseHelper> & externalIdList, const chip::Optional & data) { + DeviceLayer::StackUnlock unlock; ProgramGuideResponseType response; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -600,6 +607,7 @@ bool ChannelManager::HandleRecordProgram(const chip::CharSpan & programIdentifie const DataModel::DecodableList & externalIdList, const chip::ByteSpan & data) { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnValue(env != nullptr, false, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -637,6 +645,7 @@ bool ChannelManager::HandleCancelRecordProgram(const chip::CharSpan & programIde const DataModel::DecodableList & externalIdList, const chip::ByteSpan & data) { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnValue(env != nullptr, false, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); diff --git a/examples/tv-app/android/java/ContentAppAttributeDelegate.cpp b/examples/tv-app/android/java/ContentAppAttributeDelegate.cpp index 84e7d9933ad022..00b4ca7a225b2c 100644 --- a/examples/tv-app/android/java/ContentAppAttributeDelegate.cpp +++ b/examples/tv-app/android/java/ContentAppAttributeDelegate.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace chip { @@ -43,6 +44,7 @@ std::string ContentAppAttributeDelegate::Read(const chip::app::ConcreteReadAttri return ""; } + DeviceLayer::StackUnlock unlock; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); ChipLogProgress(Zcl, "ContentAppAttributeDelegate::Read being called for endpoint %d cluster %d attribute %d", aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId); diff --git a/examples/tv-app/android/java/ContentAppCommandDelegate.cpp b/examples/tv-app/android/java/ContentAppCommandDelegate.cpp index 3963140d1b5e65..2e5dcbe0f3b5e1 100644 --- a/examples/tv-app/android/java/ContentAppCommandDelegate.cpp +++ b/examples/tv-app/android/java/ContentAppCommandDelegate.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include namespace chip { @@ -50,6 +51,7 @@ void ContentAppCommandDelegate::InvokeCommand(CommandHandlerInterface::HandlerCo { if (handlerContext.mRequestPath.mEndpointId >= FIXED_ENDPOINT_COUNT) { + DeviceLayer::StackUnlock unlock; TLV::TLVReader readerForJson; readerForJson.Init(handlerContext.mPayload); diff --git a/examples/tv-app/android/java/ContentLauncherManager.cpp b/examples/tv-app/android/java/ContentLauncherManager.cpp index 503fb4a21240db..f68e1131fa6fb8 100644 --- a/examples/tv-app/android/java/ContentLauncherManager.cpp +++ b/examples/tv-app/android/java/ContentLauncherManager.cpp @@ -51,6 +51,7 @@ void ContentLauncherManager::HandleLaunchContent(CommandResponseHelper playbackPreferences, bool useCurrentContext) { + DeviceLayer::StackUnlock unlock; Commands::LauncherResponse::Type response; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -107,6 +108,7 @@ void ContentLauncherManager::HandleLaunchUrl(CommandResponseHelper acceptedHeadersList; @@ -208,6 +211,7 @@ CHIP_ERROR ContentLauncherManager::HandleGetAcceptHeaderList(AttributeValueEncod uint32_t ContentLauncherManager::HandleGetSupportedStreamingProtocols() { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); uint32_t supportedStreamingProtocols = 0; diff --git a/examples/tv-app/android/java/KeypadInputManager.cpp b/examples/tv-app/android/java/KeypadInputManager.cpp index a43a56cb860978..2382397fc351d9 100644 --- a/examples/tv-app/android/java/KeypadInputManager.cpp +++ b/examples/tv-app/android/java/KeypadInputManager.cpp @@ -44,6 +44,7 @@ void KeypadInputManager::NewManager(jint endpoint, jobject manager) void KeypadInputManager::HandleSendKey(CommandResponseHelper & helper, const CECKeyCodeEnum & keyCode) { + DeviceLayer::StackUnlock unlock; Commands::SendKeyResponse::Type response; jint ret = -1; diff --git a/examples/tv-app/android/java/LevelManager.cpp b/examples/tv-app/android/java/LevelManager.cpp index b79f150c7ae20e..f9be7578e830ab 100644 --- a/examples/tv-app/android/java/LevelManager.cpp +++ b/examples/tv-app/android/java/LevelManager.cpp @@ -112,6 +112,7 @@ CHIP_ERROR LevelManager::InitializeWithObjects(jobject managerObject) void LevelManager::HandleLevelChanged(uint8_t value) { + DeviceLayer::StackUnlock unlock; ChipLogProgress(Zcl, "LevelManager::HandleLevelChanged"); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); diff --git a/examples/tv-app/android/java/LowPowerManager.cpp b/examples/tv-app/android/java/LowPowerManager.cpp index 12e234964d4c5e..5c6906fcd1d659 100644 --- a/examples/tv-app/android/java/LowPowerManager.cpp +++ b/examples/tv-app/android/java/LowPowerManager.cpp @@ -64,6 +64,7 @@ void LowPowerManager::InitializeWithObjects(jobject managerObject) bool LowPowerManager::HandleSleep() { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); JniLocalReferenceScope scope(env); diff --git a/examples/tv-app/android/java/MediaInputManager.cpp b/examples/tv-app/android/java/MediaInputManager.cpp index 45dad793fc1b85..0f1c922243c2be 100644 --- a/examples/tv-app/android/java/MediaInputManager.cpp +++ b/examples/tv-app/android/java/MediaInputManager.cpp @@ -51,6 +51,7 @@ void MediaInputManager::NewManager(jint endpoint, jobject manager) CHIP_ERROR MediaInputManager::HandleGetInputList(chip::app::AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NO_ENV, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -123,6 +124,7 @@ CHIP_ERROR MediaInputManager::HandleGetInputList(chip::app::AttributeValueEncode uint8_t MediaInputManager::HandleGetCurrentInput() { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; jint index = -1; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -157,6 +159,7 @@ uint8_t MediaInputManager::HandleGetCurrentInput() bool MediaInputManager::HandleSelectInput(const uint8_t index) { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnValue(env != nullptr, false, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -182,6 +185,7 @@ bool MediaInputManager::HandleSelectInput(const uint8_t index) bool MediaInputManager::HandleShowInputStatus() { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnValue(env != nullptr, false, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -207,6 +211,7 @@ bool MediaInputManager::HandleShowInputStatus() bool MediaInputManager::HandleHideInputStatus() { + DeviceLayer::StackUnlock unlock; jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnValue(env != nullptr, false, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -232,6 +237,7 @@ bool MediaInputManager::HandleHideInputStatus() bool MediaInputManager::HandleRenameInput(const uint8_t index, const chip::CharSpan & name) { + DeviceLayer::StackUnlock unlock; std::string inputname(name.data(), name.size()); jboolean ret = JNI_FALSE; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); diff --git a/examples/tv-app/android/java/MediaPlaybackManager.cpp b/examples/tv-app/android/java/MediaPlaybackManager.cpp index 4d2fd3450640c0..667ab2ec41b382 100644 --- a/examples/tv-app/android/java/MediaPlaybackManager.cpp +++ b/examples/tv-app/android/java/MediaPlaybackManager.cpp @@ -97,6 +97,7 @@ CHIP_ERROR MediaPlaybackManager::HandleGetActiveAudioTrack(AttributeValueEncoder CHIP_ERROR MediaPlaybackManager::HandleGetActiveTrack(bool audio, AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; Structs::TrackStruct::Type response; Structs::TrackAttributesStruct::Type trackAttributes; response.trackAttributes = Nullable(trackAttributes); @@ -170,6 +171,7 @@ CHIP_ERROR MediaPlaybackManager::HandleGetAvailableAudioTracks(AttributeValueEnc CHIP_ERROR MediaPlaybackManager::HandleGetAvailableTracks(bool audio, AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -319,6 +321,7 @@ bool MediaPlaybackManager::HandleActivateAudioTrack(const chip::CharSpan & track bool MediaPlaybackManager::HandleActivateTrack(bool audio, const chip::CharSpan & trackId) { + DeviceLayer::StackUnlock unlock; std::string id(trackId.data(), trackId.size()); jint ret = -1; @@ -355,6 +358,7 @@ bool MediaPlaybackManager::HandleActivateTextTrack(const chip::CharSpan & trackI bool MediaPlaybackManager::HandleDeactivateTextTrack() { + DeviceLayer::StackUnlock unlock; jint ret = -1; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); @@ -443,6 +447,7 @@ void MediaPlaybackManager::InitializeWithObjects(jobject managerObject) uint64_t MediaPlaybackManager::HandleMediaRequestGetAttribute(MediaPlaybackRequestAttribute attribute) { + DeviceLayer::StackUnlock unlock; uint64_t ret = std::numeric_limits::max(); jlong jAttributeValue = -1; CHIP_ERROR err = CHIP_NO_ERROR; @@ -486,6 +491,7 @@ uint64_t MediaPlaybackManager::HandleMediaRequestGetAttribute(MediaPlaybackReque long MediaPlaybackManager::HandleMediaRequestGetLongAttribute(MediaPlaybackRequestAttribute attribute) { + DeviceLayer::StackUnlock unlock; long ret = 0; jlong jAttributeValue = -1; CHIP_ERROR err = CHIP_NO_ERROR; @@ -524,6 +530,7 @@ Commands::PlaybackResponse::Type MediaPlaybackManager::HandleMediaRequest(MediaP uint64_t deltaPositionMilliseconds) { + DeviceLayer::StackUnlock unlock; Commands::PlaybackResponse::Type response; jint ret = -1; @@ -561,6 +568,7 @@ Commands::PlaybackResponse::Type MediaPlaybackManager::HandleMediaRequest(MediaP CHIP_ERROR MediaPlaybackManager::HandleGetSampledPosition(AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; Structs::PlaybackPositionStruct::Type response; response.updatedAt = 0; response.position = Nullable(0); diff --git a/examples/tv-app/android/java/MessagesManager.cpp b/examples/tv-app/android/java/MessagesManager.cpp index d65de16a99e4e5..7d114711aca0e7 100644 --- a/examples/tv-app/android/java/MessagesManager.cpp +++ b/examples/tv-app/android/java/MessagesManager.cpp @@ -1,6 +1,6 @@ /** * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2024 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. @@ -39,8 +39,6 @@ using MessageResponseOption = chip::app::Clusters::Messages::Structs::MessageRes * 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 emberAfMessagesClusterInitCallback(EndpointId endpoint) { @@ -52,6 +50,7 @@ void MessagesManager::NewManager(jint endpoint, jobject manager) { ChipLogProgress(Zcl, "-----TV Android App: Messages::SetDefaultDelegate"); MessagesManager * mgr = new MessagesManager(); + VerifyOrReturn(mgr != nullptr, ChipLogError(Zcl, "Failed to create MessagesManager")); mgr->InitializeWithObjects(manager); chip::app::Clusters::Messages::SetDefaultDelegate(static_cast(endpoint), mgr); } @@ -111,6 +110,7 @@ uint32_t MessagesManager::GetFeatureMap(chip::EndpointId endpoint) CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -123,7 +123,8 @@ CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) VerifyOrExit(mGetMessagesMethod != nullptr, err = CHIP_ERROR_INCORRECT_STATE); return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { - jobjectArray messagesList = (jobjectArray) env->CallObjectMethod(mMessagesManagerObject.ObjectRef(), mGetMessagesMethod); + jobjectArray messagesList = + static_cast(env->CallObjectMethod(mMessagesManagerObject.ObjectRef(), mGetMessagesMethod)); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Java exception in MessagesManager::HandleGetMessages"); @@ -191,7 +192,7 @@ CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) jfieldID getResponseOptionsField = env->GetFieldID(messageClass, "responseOptions", "[Lcom/matter/tv/server/tvapp/MessageResponseOption;"); - jobjectArray responsesArray = (jobjectArray) env->GetObjectField(messageObject, getResponseOptionsField); + jobjectArray responsesArray = static_cast(env->GetObjectField(messageObject, getResponseOptionsField)); jint size = env->GetArrayLength(responsesArray); if (size > 0) { @@ -240,6 +241,7 @@ CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) CHIP_ERROR MessagesManager::HandleGetActiveMessageIds(AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); @@ -252,7 +254,8 @@ CHIP_ERROR MessagesManager::HandleGetActiveMessageIds(AttributeValueEncoder & aE env->ExceptionClear(); return aEncoder.EncodeList([this, env](const auto & encoder) -> CHIP_ERROR { - jobjectArray messagesList = (jobjectArray) env->CallObjectMethod(mMessagesManagerObject.ObjectRef(), mGetMessagesMethod); + jobjectArray messagesList = + static_cast(env->CallObjectMethod(mMessagesManagerObject.ObjectRef(), mGetMessagesMethod)); if (env->ExceptionCheck()) { ChipLogError(Zcl, "Java exception in MessagesManager::HandleGetActiveMessageIds"); @@ -299,6 +302,7 @@ CHIP_ERROR MessagesManager::HandlePresentMessagesRequest( const DataModel::Nullable & startTime, const DataModel::Nullable & duration, const CharSpan & messageText, const Optional> & responses) { + DeviceLayer::StackUnlock unlock; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); JniLocalReferenceScope scope(env); @@ -317,8 +321,18 @@ CHIP_ERROR MessagesManager::HandlePresentMessagesRequest( chip::Encoding::BytesToUppercaseHexString(messageId.data(), messageId.size(), hex_buf, sizeof(hex_buf)), CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "BytesToUppercaseHexString failed")); - UtfString jIdentifier(env, hex_buf); - UtfString jMessageText(env, messageText); + jstring jid = env->NewStringUTF(hex_buf); + if (jid == nullptr) + { + return CHIP_ERROR_INTERNAL; + } + + std::string smessageText(messageText.data(), messageText.size()); + jstring jmessageText = env->NewStringUTF(smessageText.c_str()); + if (jmessageText == nullptr) + { + return CHIP_ERROR_INTERNAL; + } jint jcontrol = static_cast(messageControl.Raw()); jint jduration = -1; @@ -359,13 +373,18 @@ CHIP_ERROR MessagesManager::HandlePresentMessagesRequest( { auto & response = iter.GetValue(); - UtfString jlabel(env, response.label.Value()); + std::string label(response.label.Value().data(), response.label.Value().size()); + jstring jlabel = env->NewStringUTF(label.c_str()); + if (jlabel == nullptr) + { + return CHIP_ERROR_INTERNAL; + } jobject jlong = env->NewObject(longClass, longCtor, response.messageResponseID.Value()); VerifyOrReturnError(jlong != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Could not create Long")); // add to HashMap - env->CallObjectMethod(joptions, hashMapPut, jlong, jlabel.jniValue()); + env->CallObjectMethod(joptions, hashMapPut, jlong, jlabel); if (env->ExceptionCheck()) { ChipLogError(DeviceLayer, "Java exception in MessagesManager::HandlePresentMessagesRequest"); @@ -376,8 +395,8 @@ CHIP_ERROR MessagesManager::HandlePresentMessagesRequest( } } - env->CallBooleanMethod(mMessagesManagerObject.ObjectRef(), mPresentMessagesMethod, jIdentifier.jniValue(), jpriority, - jcontrol, jstartTime, jduration, jMessageText.jniValue(), joptions); + env->CallBooleanMethod(mMessagesManagerObject.ObjectRef(), mPresentMessagesMethod, jid, jpriority, jcontrol, jstartTime, + jduration, jmessageText, joptions); if (env->ExceptionCheck()) { ChipLogError(DeviceLayer, "Java exception in MessagesManager::HandlePresentMessagesRequest"); @@ -391,6 +410,7 @@ CHIP_ERROR MessagesManager::HandlePresentMessagesRequest( CHIP_ERROR MessagesManager::HandleCancelMessagesRequest(const DataModel::DecodableList & messageIds) { + DeviceLayer::StackUnlock unlock; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NULL_OBJECT, ChipLogError(Zcl, "Could not get JNIEnv for current thread")); JniLocalReferenceScope scope(env); @@ -413,9 +433,13 @@ CHIP_ERROR MessagesManager::HandleCancelMessagesRequest(const DataModel::Decodab chip::Encoding::BytesToUppercaseHexString(id.data(), id.size(), hex_buf, sizeof(hex_buf)), CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "BytesToUppercaseHexString failed")); - UtfString jIdentifier(env, hex_buf); + jstring jid = env->NewStringUTF(hex_buf); + if (jid == nullptr) + { + return CHIP_ERROR_INTERNAL; + } - env->CallBooleanMethod(mMessagesManagerObject.ObjectRef(), mCancelMessagesMethod, jIdentifier.jniValue()); + env->CallBooleanMethod(mMessagesManagerObject.ObjectRef(), mCancelMessagesMethod, jid); if (env->ExceptionCheck()) { ChipLogError(DeviceLayer, "Java exception in MessagesManager::HandleCancelMessagesRequest"); diff --git a/examples/tv-app/android/java/MyUserPrompter-JNI.cpp b/examples/tv-app/android/java/MyUserPrompter-JNI.cpp index d2c83b28a1ce8f..82b06e210d7853 100644 --- a/examples/tv-app/android/java/MyUserPrompter-JNI.cpp +++ b/examples/tv-app/android/java/MyUserPrompter-JNI.cpp @@ -78,6 +78,7 @@ JNIMyUserPrompter::JNIMyUserPrompter(jobject provider) */ void JNIMyUserPrompter::PromptForCommissionOKPermission(uint16_t vendorId, uint16_t productId, const char * commissioneeName) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); std::string stringCommissioneeName(commissioneeName); @@ -119,6 +120,7 @@ void JNIMyUserPrompter::PromptForCommissionOKPermission(uint16_t vendorId, uint1 void JNIMyUserPrompter::PromptForCommissionPasscode(uint16_t vendorId, uint16_t productId, const char * commissioneeName, uint16_t pairingHint, const char * pairingInstruction) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); std::string stringCommissioneeName(commissioneeName); @@ -198,6 +200,7 @@ void JNIMyUserPrompter::PromptCommissioningStarted(uint16_t vendorId, uint16_t p */ void JNIMyUserPrompter::PromptCommissioningSucceeded(uint16_t vendorId, uint16_t productId, const char * commissioneeName) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); std::string stringCommissioneeName(commissioneeName); @@ -234,6 +237,7 @@ void JNIMyUserPrompter::PromptCommissioningSucceeded(uint16_t vendorId, uint16_t */ void JNIMyUserPrompter::PromptCommissioningFailed(const char * commissioneeName, CHIP_ERROR error) { + DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); std::string stringCommissioneeName(commissioneeName); diff --git a/examples/tv-app/android/java/OnOffManager.cpp b/examples/tv-app/android/java/OnOffManager.cpp index 9a330754aa4a16..db694748e8a11b 100644 --- a/examples/tv-app/android/java/OnOffManager.cpp +++ b/examples/tv-app/android/java/OnOffManager.cpp @@ -113,6 +113,7 @@ CHIP_ERROR OnOffManager::InitializeWithObjects(jobject managerObject) void OnOffManager::HandleOnOffChanged(bool value) { + DeviceLayer::StackUnlock unlock; ChipLogProgress(Zcl, "OnOffManager::HandleOnOffChanged"); JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); diff --git a/examples/tv-app/android/java/WakeOnLanManager.cpp b/examples/tv-app/android/java/WakeOnLanManager.cpp index 5a3093aca53332..a50ddca72bbb3e 100644 --- a/examples/tv-app/android/java/WakeOnLanManager.cpp +++ b/examples/tv-app/android/java/WakeOnLanManager.cpp @@ -51,6 +51,7 @@ void WakeOnLanManager::NewManager(jint endpoint, jobject manager) CHIP_ERROR WakeOnLanManager::HandleGetMacAddress(chip::app::AttributeValueEncoder & aEncoder) { + DeviceLayer::StackUnlock unlock; jobject javaMac; CHIP_ERROR err = CHIP_NO_ERROR; JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java index 837297967c90ea..750f57907b6eb0 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java @@ -18,8 +18,8 @@ package com.matter.tv.server.tvapp; public class MessageResponseOption { - public long id; - public String label; + public long id = -1; + public String label = "na"; public MessageResponseOption( long id, From b74113bb7381da0629ffcf61d3145ba2a425e8ce Mon Sep 17 00:00:00 2001 From: "restyled-io[bot]" <32688539+restyled-io[bot]@users.noreply.github.com> Date: Sun, 18 Feb 2024 09:39:26 -0800 Subject: [PATCH 4/6] Restyle [in-dev] Messages cluster sample app for android (#32163) * Restyled by whitespace * Restyled by google-java-format --------- Co-authored-by: Restyled.io --- .../com/matter/tv/server/tvapp/Message.java | 47 ++++++------- .../server/tvapp/MessageResponseOption.java | 14 ++-- .../tv/server/tvapp/MessagesManager.java | 23 +++--- .../tv/server/tvapp/MessagesManagerStub.java | 70 ++++++++----------- 4 files changed, 71 insertions(+), 83 deletions(-) diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java index 49faa3db4b82ba..8f15b73b00a185 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java @@ -17,32 +17,31 @@ */ package com.matter.tv.server.tvapp; -import java.util.Vector; public class Message { - public String messageId; - public int priority; - public int messageControl; - public long startTime; - public int duration; - public String messageText; - public MessageResponseOption responseOptions[]; + public String messageId; + public int priority; + public int messageControl; + public long startTime; + public int duration; + public String messageText; + public MessageResponseOption responseOptions[]; - public Message(String messageId, - int priority, - int messageControl, - long startTime, - int duration, - String messageText, - MessageResponseOption responseOptions[]) - { - this.messageId = messageId; - this.priority = priority; - this.messageControl = messageControl; - this.startTime = startTime; - this.duration = duration; - this.messageText = messageText; - this.responseOptions = responseOptions; - } + public Message( + String messageId, + int priority, + int messageControl, + long startTime, + int duration, + String messageText, + MessageResponseOption responseOptions[]) { + this.messageId = messageId; + this.priority = priority; + this.messageControl = messageControl; + this.startTime = startTime; + this.duration = duration; + this.messageText = messageText; + this.responseOptions = responseOptions; + } } diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java index 750f57907b6eb0..5d8e77d1e91389 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessageResponseOption.java @@ -18,13 +18,11 @@ package com.matter.tv.server.tvapp; public class MessageResponseOption { - public long id = -1; - public String label = "na"; + public long id = -1; + public String label = "na"; - public MessageResponseOption( - long id, - String label) { - this.id = id; - this.label = label; - } + public MessageResponseOption(long id, String label) { + this.id = id; + this.label = label; } +} diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java index 30ab402feea57a..0a5680866714c6 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManager.java @@ -1,4 +1,4 @@ - /* +/* * Copyright (c) 2024 Project CHIP Authors * All rights reserved. * @@ -21,15 +21,16 @@ public interface MessagesManager { - Message[] getMessages(); + Message[] getMessages(); - boolean presentMessages(String messageId, - int priority, - int messageControl, - long startTime, - int duration, - String messageText, - HashMap responseOptions); - - boolean cancelMessage(String messageId); + boolean presentMessages( + String messageId, + int priority, + int messageControl, + long startTime, + int duration, + String messageText, + HashMap responseOptions); + + boolean cancelMessage(String messageId); } diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java index 1a422385f013f0..a2d95b9b8bd2cc 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java @@ -20,30 +20,23 @@ import android.util.Log; import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; -import java.util.Vector; public class MessagesManagerStub implements MessagesManager { private static final String TAG = MessagesManagerStub.class.getSimpleName(); private int endpoint; - private Map messages = new HashMap(); + private Map messages = new HashMap(); public MessagesManagerStub(int endpoint) { this.endpoint = endpoint; Log.d(TAG, "MessagesManagerStub: at " + this.endpoint); - HashMap responseOptions = new HashMap(); + HashMap responseOptions = new HashMap(); responseOptions.put(new Long(1), "Yes"); responseOptions.put(new Long(2), "No"); - presentMessages("31323334353637383930313233343536", - 1, - 1, - 30, - 60, - "TestMessage", - responseOptions); + presentMessages( + "31323334353637383930313233343536", 1, 1, 30, 60, "TestMessage", responseOptions); Log.d(TAG, "MessagesManagerStub: added dummy message"); } @@ -54,39 +47,36 @@ public Message[] getMessages() { } @Override - public boolean presentMessages(String messageId, - int priority, - int messageControl, - long startTime, - int duration, - String messageText, - HashMap responseOptions) { - Log.d(TAG, "presentMessages: at " + this.endpoint + " id:" + messageId+ " text:"+messageText); - MessageResponseOption[] options = new MessageResponseOption[responseOptions.size()]; - int i=0; + public boolean presentMessages( + String messageId, + int priority, + int messageControl, + long startTime, + int duration, + String messageText, + HashMap responseOptions) { + Log.d( + TAG, "presentMessages: at " + this.endpoint + " id:" + messageId + " text:" + messageText); + MessageResponseOption[] options = new MessageResponseOption[responseOptions.size()]; + int i = 0; - for (Map.Entry set : responseOptions.entrySet()) { - Log.d(TAG, "presentMessages option: key:"+set.getKey()+" value:"+set.getValue()); - options[i] = new MessageResponseOption(set.getKey().longValue(), set.getValue()); - i++; - } - - messages.put(messageId, new Message(messageId, - priority, - messageControl, - startTime, - duration, - messageText, - options)); - return true; + for (Map.Entry set : responseOptions.entrySet()) { + Log.d(TAG, "presentMessages option: key:" + set.getKey() + " value:" + set.getValue()); + options[i] = new MessageResponseOption(set.getKey().longValue(), set.getValue()); + i++; } - + + messages.put( + messageId, + new Message( + messageId, priority, messageControl, startTime, duration, messageText, options)); + return true; + } + @Override - public boolean cancelMessage(String messageId) - { - Log.d(TAG, "cancelMessage: at " + this.endpoint + " messageId:"+messageId); + public boolean cancelMessage(String messageId) { + Log.d(TAG, "cancelMessage: at " + this.endpoint + " messageId:" + messageId); messages.remove(messageId); return true; // per spec, succeed unless error } - } From 8a82ad3a7f02aa4332bacb4df04a2094ea36d6bd Mon Sep 17 00:00:00 2001 From: "restyled-io[bot]" <32688539+restyled-io[bot]@users.noreply.github.com> Date: Mon, 19 Feb 2024 02:18:37 -0800 Subject: [PATCH 5/6] Restyled by google-java-format (#32195) Co-authored-by: Restyled.io --- .../android/java/src/com/matter/tv/server/tvapp/Message.java | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java index 8f15b73b00a185..c194ffb44f9ee1 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/Message.java @@ -17,7 +17,6 @@ */ package com.matter.tv.server.tvapp; - public class Message { public String messageId; From e00fbf1ad2208c096703ffbc27f9e530dfe8951f Mon Sep 17 00:00:00 2001 From: chrisdecenzo Date: Tue, 20 Feb 2024 05:06:42 -0800 Subject: [PATCH 6/6] address feedback --- examples/tv-app/android/java/MessagesManager.cpp | 2 ++ .../src/com/matter/tv/server/tvapp/MessagesManagerStub.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/tv-app/android/java/MessagesManager.cpp b/examples/tv-app/android/java/MessagesManager.cpp index 7d114711aca0e7..9203d7b54510f5 100644 --- a/examples/tv-app/android/java/MessagesManager.cpp +++ b/examples/tv-app/android/java/MessagesManager.cpp @@ -211,6 +211,8 @@ CHIP_ERROR MessagesManager::HandleGetMessages(AttributeValueEncoder & aEncoder) jstring jlabelText = static_cast(env->GetObjectField(responseOptionObject, getLabelField)); VerifyOrReturnValue(jlabelText != nullptr, CHIP_ERROR_INVALID_ARGUMENT, ChipLogError(Zcl, "jlabelText null")); JniUtfString * label = new JniUtfString(env, jlabelText); + VerifyOrReturnValue(label != nullptr, CHIP_ERROR_NO_MEMORY, ChipLogError(Zcl, "label null")); + optionLabels.push_back(label); option.label = Optional(label->charSpan()); diff --git a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java index 1a422385f013f0..0ccb0e0d322e0b 100644 --- a/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java +++ b/examples/tv-app/android/java/src/com/matter/tv/server/tvapp/MessagesManagerStub.java @@ -26,7 +26,7 @@ public class MessagesManagerStub implements MessagesManager { private static final String TAG = MessagesManagerStub.class.getSimpleName(); - private int endpoint; + private int endpoint = -1; private Map messages = new HashMap();