diff --git a/interfaces/innerkits/wm/data_handler_interface.h b/interfaces/innerkits/wm/data_handler_interface.h index 52c30ef4df815e7f56aa9a9e706f80c00d04b22c..57d585df3d6aaccad70b2656ee2f06922e277b1b 100644 --- a/interfaces/innerkits/wm/data_handler_interface.h +++ b/interfaces/innerkits/wm/data_handler_interface.h @@ -47,7 +47,7 @@ enum class DataHandlerErr : uint32_t { }; using DataConsumeCallback = - std::function reply)>; + std::function& reply)>; /** * @class IDataHandler @@ -67,32 +67,32 @@ public: * * @param subSystemId The identifier of the target subsystem. * @param customId A custom identifier for the data being sent. - * @param data The Want object containing the data to be sent. + * @param toSend The Want object containing the data to be sent. * @param reply A reference to a Want object that will be filled with the reply data. * @return DataHandlerErr::OK if the data was successfully sent and a reply was received, other errcode otherwise. */ - virtual DataHandlerErr SendDataSync(SubSystemId subSystemId, uint32_t customId, AAFwk::Want& data, - AAFwk::Want& reply) = 0; + virtual DataHandlerErr SendDataSync(SubSystemId subSystemId, uint32_t customId, const AAFwk::Want& toSend, + AAFwk::Want& reply) = 0; /** * @brief Sends data synchronously to a specified subsystem without reply. * * @param subSystemId The identifier of the target subsystem. * @param customId A custom identifier for the data being sent. - * @param data The Want object containing the data to be sent. + * @param toSend The Want object containing the data to be sent. * @return DataHandlerErr::OK if the data was successfully sent, other errcode otherwise. */ - virtual DataHandlerErr SendDataSync(SubSystemId subSystemId, uint32_t customId, AAFwk::Want& data) = 0; + virtual DataHandlerErr SendDataSync(SubSystemId subSystemId, uint32_t customId, const AAFwk::Want& toSend) = 0; /** * @brief Sends data asynchronously to a specified subsystem without reply. * * @param subSystemId The identifier of the target subsystem. * @param customId A custom identifier for the data being sent. - * @param data The Want object containing the data to be sent. + * @param toSend The Want object containing the data to be sent. * @return DataHandlerErr::OK if the data was successfully sent, other errcode otherwise. */ - virtual DataHandlerErr SendDataAsync(SubSystemId subSystemId, uint32_t customId, AAFwk::Want& data) = 0; + virtual DataHandlerErr SendDataAsync(SubSystemId subSystemId, uint32_t customId, const AAFwk::Want& toSend) = 0; /** * @brief Registers a data consumer for a specific subsystemId. diff --git a/window_scene/common/BUILD.gn b/window_scene/common/BUILD.gn index 513787407c063841408e1eacc2dcab1081f5fada..2b04ddc9af6e1284d375156d2a92a272a0987c4e 100644 --- a/window_scene/common/BUILD.gn +++ b/window_scene/common/BUILD.gn @@ -23,6 +23,7 @@ config("window_scene_common_public_config") { "${window_base_path}/utils/include", "${window_base_path}/interfaces/innerkits/wm", "${window_base_path}/interfaces/innerkits/dm", + "${window_base_path}/interfaces/innerkits/extension", ] } @@ -36,6 +37,7 @@ ohos_shared_library("window_scene_common") { debug = false } sources = [ + "src/extension_data_handler.cpp", "src/session_permission.cpp", "src/task_scheduler.cpp", "src/window_session_property.cpp", diff --git a/window_scene/common/include/extension_data_handler.h b/window_scene/common/include/extension_data_handler.h index c8c9ed8d3a0c5ade5a8ba145c2306da5b5e53ef6..4c0e9d6ac11c237659d9568d1e9bdcd24f792916 100644 --- a/window_scene/common/include/extension_data_handler.h +++ b/window_scene/common/include/extension_data_handler.h @@ -43,28 +43,34 @@ using Task = std::function; class DataHandler : public IDataHandler { public: - explicit DataHandler(const std::shared_ptr& eventHandler) : eventHandler_(eventHandler) {} + DataHandler() = default; virtual ~DataHandler() = default; - DataHandlerErr SendDataSync(SubSystemId subSystemId, uint32_t customId, AAFwk::Want& data, - AAFwk::Want& reply) override; - DataHandlerErr SendDataSync(SubSystemId subSystemId, uint32_t customId, AAFwk::Want& data) override; - DataHandlerErr SendDataAsync(SubSystemId subSystemId, uint32_t customId, AAFwk::Want& data) override; - DataHandlerErr RegisterDataConsumer(SubSystemId dataId, DataConsumeCallback&& callback) override; - void UnregisterDataConsumer(SubSystemId dataId) override; - DataHandlerErr NotifyDataConsumer(AAFwk::Want&& data, std::optional reply, - const DataTransferConfig& config); + DataHandlerErr SendDataSync(SubSystemId subSystemId, uint32_t customId, const AAFwk::Want& toSend, + AAFwk::Want& reply) override; + DataHandlerErr SendDataSync(SubSystemId subSystemId, uint32_t customId, const AAFwk::Want& toSend) override; + DataHandlerErr SendDataAsync(SubSystemId subSystemId, uint32_t customId, const AAFwk::Want& toSend) override; + DataHandlerErr RegisterDataConsumer(SubSystemId subSystemId, DataConsumeCallback&& callback) override; + void UnregisterDataConsumer(SubSystemId subSystemId) override; + void NotifyDataConsumer(MessageParcel& recieved, MessageParcel& reply); + void SetEventHandler(const std::shared_ptr& eventHandler); + void SetRemoteProxyObject(const sptr& remoteObject); protected: - virtual DataHandlerErr SendData(AAFwk::Want& data, AAFwk::Want& reply, const DataTransferConfig& config) = 0; - DataHandlerErr PrepareData(MessageParcel& data, AAFwk::Want& toSend, const DataTransferConfig& config); - DataHandlerErr ParseReply(MessageParcel& data, AAFwk::Want& reply, const DataTransferConfig& config); + DataHandlerErr NotifyDataConsumer(AAFwk::Want&& data, std::optional& reply, + const DataTransferConfig& config); + virtual DataHandlerErr SendData(const AAFwk::Want& toSend, AAFwk::Want& reply, + const DataTransferConfig& config) = 0; + DataHandlerErr PrepareSendData(MessageParcel& data, const DataTransferConfig& config, const AAFwk::Want& toSend); + virtual bool WriteInterfaceToken(MessageParcel& data) = 0; + DataHandlerErr ParseReply(MessageParcel& recieved, AAFwk::Want& reply, const DataTransferConfig& config); void PostAsyncTask(Task&& task, const std::string& name, int64_t delayTime); protected: mutable std::mutex mutex_; std::unordered_map consumers_; std::shared_ptr eventHandler_; + sptr remoteProxy_; }; } // namespace OHOS::Rosen::Extension diff --git a/window_scene/common/src/extension_data_handler.cpp b/window_scene/common/src/extension_data_handler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8de635177efca732985484a55a82852b4818f048 --- /dev/null +++ b/window_scene/common/src/extension_data_handler.cpp @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * 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 "common/include/extension_data_handler.h" + +#include + +#include +#include +#include +#include +#include + +#include "window_manager_hilog.h" + +namespace OHOS::Rosen::Extension { + +bool DataTransferConfig::Marshalling(Parcel& parcel) const +{ + return parcel.WriteUint8(static_cast(subSystemId)) && parcel.WriteUint32(customId) && + parcel.WriteBool(needReply) && parcel.WriteBool(needSyncSend); +} + +DataTransferConfig* DataTransferConfig::Unmarshalling(Parcel& parcel) +{ + auto config = new DataTransferConfig(); + uint8_t subSystemIdValue = static_cast(SubSystemId::INVALID); + if (!parcel.ReadUint8(subSystemIdValue) || subSystemIdValue >= static_cast(SubSystemId::INVALID)) { + delete config; + return nullptr; + } + if (!parcel.ReadUint32(config->customId) || !parcel.ReadBool(config->needReply) || + !parcel.ReadBool(config->needSyncSend)) { + delete config; + return nullptr; + } + config->subSystemId = static_cast(subSystemIdValue); + return config; +} + +std::string DataTransferConfig::ToString() const +{ + std::string str; + constexpr int BUFFER_SIZE = 128; + char buffer[BUFFER_SIZE] = { 0 }; + if (snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, + "subSystemId: %hhu, customId: %u, needReply: %d, needSyncSend: %d", subSystemId, customId, needReply, + needSyncSend) > 0) { + str.append(buffer); + } + return str; +} + +DataHandlerErr DataHandler::RegisterDataConsumer(SubSystemId subSystemId, DataConsumeCallback&& callback) +{ + std::lock_guard lock(mutex_); + if (consumers_.find(subSystemId) != consumers_.end()) { + // A consumer already exists for this subSystemId + TLOGE(WmsLogTag::WMS_UIEXT, "Consumer already exists for subSystemId: %{public}hhu", subSystemId); + return DataHandlerErr::DUPLICATE_REGISTRATION; + } + consumers_.emplace(subSystemId, std::move(callback)); + return DataHandlerErr::OK; +} + +void DataHandler::UnregisterDataConsumer(SubSystemId subSystemId) +{ + std::lock_guard lock(mutex_); + consumers_.erase(subSystemId); + TLOGI(WmsLogTag::WMS_UIEXT, "Unregister consumer for subSystemId: %{public}hhu", subSystemId); +} + +DataHandlerErr DataHandler::PrepareSendData(MessageParcel& data, const DataTransferConfig& config, + const AAFwk::Want& toSend) +{ + if (!WriteInterfaceToken(data)) { + TLOGE(WmsLogTag::WMS_UIEXT, "write interface token failed, %{public}s", config.ToString().c_str()); + return DataHandlerErr::WRITE_PARCEL_ERROR; + } + + if (!data.WriteParcelable(&config)) { + TLOGE(WmsLogTag::WMS_UIEXT, "write config failed, %{public}s", config.ToString().c_str()); + return DataHandlerErr::WRITE_PARCEL_ERROR; + } + + if (!data.WriteParcelable(&toSend)) { + TLOGE(WmsLogTag::WMS_UIEXT, "write toSend failed, %{public}s", config.ToString().c_str()); + return DataHandlerErr::WRITE_PARCEL_ERROR; + } + return DataHandlerErr::OK; +} + +DataHandlerErr DataHandler::ParseReply(MessageParcel& replyParcel, AAFwk::Want& reply, const DataTransferConfig& config) +{ + if (!config.needReply) { + return DataHandlerErr::OK; + } + + uint32_t replyCode = 0; + if (!replyParcel.ReadUint32(replyCode)) { + TLOGE(WmsLogTag::WMS_UIEXT, "read replyCode failed, %{public}s", config.ToString().c_str()); + return DataHandlerErr::READ_PARCEL_ERROR; + } + + if (config.needReply) { + sptr response = replyParcel.ReadParcelable(); + if (!response) { + TLOGE(WmsLogTag::WMS_UIEXT, "read response failed, %{public}s", config.ToString().c_str()); + return DataHandlerErr::READ_PARCEL_ERROR; + } + reply = std::move(*response); + } + + return static_cast(replyCode); +} + +// process data from peer +void DataHandler::NotifyDataConsumer(MessageParcel& recieved, MessageParcel& reply) +{ + sptr config = recieved.ReadParcelable(); + if (config == nullptr) { + TLOGE(WmsLogTag::WMS_UIEXT, "read config failed"); + reply.WriteUint32(static_cast(DataHandlerErr::READ_PARCEL_ERROR)); + return; + } + + sptr sendWant = recieved.ReadParcelable(); + if (sendWant == nullptr) { + TLOGE(WmsLogTag::WMS_UIEXT, "read want failed"); + reply.WriteUint32(static_cast(DataHandlerErr::READ_PARCEL_ERROR)); + return; + } + + std::optional replyWant; + if (config->needReply) { + replyWant = std::make_optional(); + } + + auto ret = NotifyDataConsumer(std::move(*sendWant), replyWant, *config); + reply.WriteUint32(static_cast(ret)); + if (config->needReply) { + reply.WriteParcelable(&(replyWant.value())); + } +} + +void DataHandler::SetEventHandler(const std::shared_ptr& eventHandler) +{ + eventHandler_ = eventHandler; +} + +void DataHandler::SetRemoteProxyObject(const sptr& remoteObject) +{ + if (!remoteObject || !remoteObject->IsProxyObject()) { + TLOGE(WmsLogTag::WMS_UIEXT, "failed, not proxy object"); + return; + } + + std::lock_guard lock(mutex_); + remoteProxy_ = remoteObject; +} + +DataHandlerErr DataHandler::SendDataSync(SubSystemId subSystemId, uint32_t customId, const AAFwk::Want& toSend, + AAFwk::Want& reply) +{ + DataTransferConfig config; + config.needSyncSend = true; + config.needReply = true; + config.subSystemId = subSystemId; + config.customId = customId; + return SendData(toSend, reply, config); +} + +DataHandlerErr DataHandler::SendDataSync(SubSystemId subSystemId, uint32_t customId, const AAFwk::Want& toSend) +{ + DataTransferConfig config; + config.needSyncSend = true; + config.subSystemId = subSystemId; + config.customId = customId; + AAFwk::Want reply; + return SendData(toSend, reply, config); +} + +DataHandlerErr DataHandler::SendDataAsync(SubSystemId subSystemId, uint32_t customId, const AAFwk::Want& toSend) +{ + DataTransferConfig config; + config.subSystemId = subSystemId; + config.customId = customId; + AAFwk::Want reply; + return SendData(toSend, reply, config); +} + +DataHandlerErr DataHandler::NotifyDataConsumer(AAFwk::Want&& data, std::optional& reply, + const DataTransferConfig& config) +{ + DataConsumeCallback callback; + { + std::lock_guard lock(mutex_); + auto it = consumers_.find(config.subSystemId); + if (it == consumers_.end()) { + TLOGE(WmsLogTag::WMS_UIEXT, "not found, %{public}s", config.ToString().c_str()); + return DataHandlerErr::NO_CONSUME_CALLBACK; + } + callback = it->second; + } + + if (!callback) { + TLOGE(WmsLogTag::WMS_UIEXT, "not callable, %{public}s", config.ToString().c_str()); + return DataHandlerErr::INVALID_CALLBACK; + } + + // sync mode + if (config.needSyncSend) { + auto ret = callback(config.subSystemId, config.customId, std::move(data), reply); + TLOGI(WmsLogTag::WMS_UIEXT, "subSystemId: %{public}hhu, customId: %{public}u, ret: %{public}d", + config.subSystemId, config.customId, ret); + return DataHandlerErr::OK; + } + + // async mode + auto task = [input = std::move(data), subSystemId = config.subSystemId, customId = config.customId, + func = std::move(callback)]() mutable { + std::optional reply; + auto ret = func(subSystemId, customId, std::move(input), reply); + TLOGNI(WmsLogTag::WMS_UIEXT, "subSystemId: %{public}hhu, customId: %{public}u, ret: %{public}d", subSystemId, + customId, ret); + }; + + std::ostringstream oss; + oss << "NotifyDataConsumer_" << static_cast(config.subSystemId) << "_" << config.customId; + PostAsyncTask(std::move(task), oss.str(), 0); + return DataHandlerErr::OK; +} + +void DataHandler::PostAsyncTask(Task&& task, const std::string& name, int64_t delayTime) +{ + if (!eventHandler_) { + HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "uiext:%s", name.c_str()); + task(); + return; + } + + if (auto runner = eventHandler_->GetEventRunner(); !runner || runner->IsCurrentRunnerThread()) { + HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "uiext:%s", name.c_str()); + task(); + return; + } + + auto localTask = [task = std::move(task), name] { + HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "uiext:%s", name.c_str()); + task(); + }; + + auto ret = eventHandler_->PostTask(std::move(localTask), "uiext:" + name, delayTime, + AppExecFwk::EventQueue::Priority::IMMEDIATE); + if (!ret) { + TLOGE(WmsLogTag::WMS_UIEXT, "Post task failed, name: %{public}s", name.c_str()); + } +} +} // namespace OHOS::Rosen::Extension \ No newline at end of file diff --git a/window_scene/session/container/include/zidl/session_stage_proxy.h b/window_scene/session/container/include/zidl/session_stage_proxy.h index 3732aa171ee583a02ad63729efa3f145b240a8f4..61935f295247587533f8119d3e52869c98d318fd 100644 --- a/window_scene/session/container/include/zidl/session_stage_proxy.h +++ b/window_scene/session/container/include/zidl/session_stage_proxy.h @@ -73,7 +73,11 @@ public: WSError NotifyCompatibleModeEnableInPad(bool enable) override; void SetUniqueVirtualPixelRatio(bool useUniqueDensity, float virtualPixelRatio) override; void NotifySessionFullScreen(bool fullScreen) override; + + // UIExtension WSError NotifyDumpInfo(const std::vector& params, std::vector& info) override; + WSError SendExtensionData(MessageParcel& data, MessageParcel& reply, MessageOption& option); + WSError SetSplitButtonVisible(bool isVisible) override; WSError SetEnableDragBySystem(bool dragEnable) override; WSError SetFullScreenWaterfallMode(bool isWaterfallMode) override; diff --git a/window_scene/session/container/include/zidl/session_stage_stub.h b/window_scene/session/container/include/zidl/session_stage_stub.h index 29152e8068e495ed8516215d49fb7635a36e6c41..9c2f766b6517341015c4b0f8e40499c34407f660 100644 --- a/window_scene/session/container/include/zidl/session_stage_stub.h +++ b/window_scene/session/container/include/zidl/session_stage_stub.h @@ -74,6 +74,8 @@ private: int HandleSetUniqueVirtualPixelRatio(MessageParcel& data, MessageParcel& reply); int HandleNotifySessionFullScreen(MessageParcel& data, MessageParcel& reply); int HandleNotifyDumpInfo(MessageParcel& data, MessageParcel& reply); + int HandleExtensionHostData(MessageParcel& data, MessageParcel& reply); + virtual void NotifyExtensionDataConsumer(MessageParcel& data, MessageParcel& reply) {} int HandleSetSplitButtonVisible(MessageParcel& data, MessageParcel& reply); int HandleSetEnableDragBySystem(MessageParcel& data, MessageParcel& reply); int HandleSetFullScreenWaterfallMode(MessageParcel& data, MessageParcel& reply); diff --git a/window_scene/session/container/src/zidl/session_stage_proxy.cpp b/window_scene/session/container/src/zidl/session_stage_proxy.cpp index e4350f5c3b81884b52f9e25bdc2770e93ba7b0c4..97fbaf28a49f08d61e29eff92fdf5a816204a449 100644 --- a/window_scene/session/container/src/zidl/session_stage_proxy.cpp +++ b/window_scene/session/container/src/zidl/session_stage_proxy.cpp @@ -1320,6 +1320,23 @@ WSError SessionStageProxy::NotifyDumpInfo(const std::vector& params return static_cast(ret); } +WSError SessionStageProxy::SendExtensionData(MessageParcel& data, MessageParcel& reply, MessageOption& option) +{ + sptr remote = Remote(); + if (remote == nullptr) { + TLOGE(WmsLogTag::WMS_UIEXT, "remote is nullptr"); + return WSError::WS_ERROR_NULLPTR; + } + + auto ret = remote->SendRequest(static_cast(SessionStageInterfaceCode::TRANS_ID_SEND_EXTENSION_DATA), data, + reply, option); + if (ret != ERR_NONE) { + TLOGE(WmsLogTag::WMS_UIEXT, "SendRequest failed, ret: %{public}d", ret); + return WSError::WS_ERROR_IPC_FAILED; + } + return WSError::WS_OK; +} + WSError SessionStageProxy::SetSplitButtonVisible(bool isVisible) { MessageParcel data; diff --git a/window_scene/session/container/src/zidl/session_stage_stub.cpp b/window_scene/session/container/src/zidl/session_stage_stub.cpp index e40a886364c28c3eba7a9403bbb84e85af70967a..d3f27e94d0883d5c7e81d3ec587b173b313f526e 100644 --- a/window_scene/session/container/src/zidl/session_stage_stub.cpp +++ b/window_scene/session/container/src/zidl/session_stage_stub.cpp @@ -184,6 +184,8 @@ int SessionStageStub::OnRemoteRequest(uint32_t code, MessageParcel& data, Messag return HandleSetFullScreenWaterfallMode(data, reply); case static_cast(SessionStageInterfaceCode::TRANS_ID_SET_SUPPORT_ENTER_WATERFALL_MODE): return HandleSetSupportEnterWaterfallMode(data, reply); + case static_cast(SessionStageInterfaceCode::TRANS_ID_SEND_EXTENSION_DATA): + return HandleExtensionHostData(data, reply); default: WLOGFE("Failed to find function handler!"); return IPCObjectStub::OnRemoteRequest(code, data, reply, option); @@ -703,4 +705,11 @@ int SessionStageStub::HandleNotifyDumpInfo(MessageParcel& data, MessageParcel& r return ERR_NONE; } + +int SessionStageStub::HandleExtensionHostData(MessageParcel& data, MessageParcel& reply) +{ + TLOGD(WmsLogTag::WMS_UIEXT, "in"); + NotifyExtensionDataConsumer(data, reply); + return ERR_NONE; +} } // namespace OHOS::Rosen diff --git a/window_scene/session/host/include/zidl/session_proxy.h b/window_scene/session/host/include/zidl/session_proxy.h index 5a853ab1d94fd3023cd11061e34479adcf2eb520..cc2f2c62b66ac0b2f7b2d8a7a52b69956d46bbca 100644 --- a/window_scene/session/host/include/zidl/session_proxy.h +++ b/window_scene/session/host/include/zidl/session_proxy.h @@ -73,6 +73,9 @@ public: WSError RaiseAboveTarget(int32_t subWindowId) override; WSError RaiseAppMainWindowToTop() override; + /* + * UIExtension + */ WSError TransferAbilityResult(uint32_t resultCode, const AAFwk::Want& want) override; WSError TransferExtensionData(const AAFwk::WantParams& wantParams) override; WSError TransferAccessibilityEvent(const Accessibility::AccessibilityEventInfo& info, @@ -83,6 +86,7 @@ public: void NotifyExtensionTimeout(int32_t errorCode) override; void TriggerBindModalUIExtension() override; void NotifyExtensionEventAsync(uint32_t notifyEvent) override; + WSError SendExtensionData(MessageParcel& data, MessageParcel& reply, MessageOption& option); void NotifyPiPWindowPrepareClose() override; WSError UpdatePiPRect(const Rect& rect, SizeChangeReason reason) override; diff --git a/window_scene/session/host/include/zidl/session_stub.h b/window_scene/session/host/include/zidl/session_stub.h index 882dd65e14a12ae59ad58facc5870c2984036035..d65aabcf6023e8f87c9b669a587e31d2f3fb618a 100644 --- a/window_scene/session/host/include/zidl/session_stub.h +++ b/window_scene/session/host/include/zidl/session_stub.h @@ -99,6 +99,8 @@ private: int HandleTransferAccessibilityEvent(MessageParcel& data, MessageParcel& reply); int HandleNotifyExtensionEventAsync(MessageParcel& data, MessageParcel& reply); int HandleNotifyExtensionDetachToDisplay(MessageParcel& data, MessageParcel& reply); + int HandleExtensionProviderData(MessageParcel& data, MessageParcel& reply); + virtual void NotifyExtensionDataConsumer(MessageParcel& data, MessageParcel& reply) {} // PictureInPicture int HandleNotifyPiPWindowPrepareClose(MessageParcel& data, MessageParcel& reply); diff --git a/window_scene/session/host/src/zidl/session_proxy.cpp b/window_scene/session/host/src/zidl/session_proxy.cpp index 808510d4b0a64b77199cb280f2da9b33d53f642a..ecb3bab9be7cc8fceeff369a4671e7894191d790 100644 --- a/window_scene/session/host/src/zidl/session_proxy.cpp +++ b/window_scene/session/host/src/zidl/session_proxy.cpp @@ -2032,6 +2032,24 @@ void SessionProxy::NotifyExtensionEventAsync(uint32_t notifyEvent) } } +WSError SessionProxy::SendExtensionData(MessageParcel& data, MessageParcel& reply, MessageOption& option) +{ + sptr remote = Remote(); + if (remote == nullptr) { + TLOGE(WmsLogTag::WMS_UIEXT, "remote is null"); + return WSError::WS_ERROR_IPC_FAILED; + } + + auto ret = remote->SendRequest(static_cast(SessionInterfaceCode::TRANS_ID_SEND_EXTENSION_DATA), data, + reply, option); + if (ret != ERR_NONE) { + TLOGE(WmsLogTag::WMS_UIEXT, "SendRequest failed, ret code: %{public}u", ret); + return WSError::WS_ERROR_IPC_FAILED; + } + + return WSError::WS_OK; +} + WSError SessionProxy::RequestFocus(bool isFocused) { MessageParcel data; diff --git a/window_scene/session/host/src/zidl/session_stub.cpp b/window_scene/session/host/src/zidl/session_stub.cpp index 42bbd2f16923bd2caa10e7690301b680989f9876..46c8a4aedf8c61863c20e5b60aa13458b90ed5d0 100644 --- a/window_scene/session/host/src/zidl/session_stub.cpp +++ b/window_scene/session/host/src/zidl/session_stub.cpp @@ -230,6 +230,8 @@ int SessionStub::ProcessRemoteRequest(uint32_t code, MessageParcel& data, Messag return HandleNotifyExtensionDetachToDisplay(data, reply); case static_cast(SessionInterfaceCode::TRANS_ID_SET_SUPPORT_WINDOW_MODES): return HandleSetSupportWindowModes(data, reply); + case static_cast(SessionInterfaceCode::TRANS_ID_SEND_EXTENSION_DATA): + return HandleExtensionProviderData(data, reply); default: WLOGFE("Failed to find function handler!"); return IPCObjectStub::OnRemoteRequest(code, data, reply, option); @@ -1281,6 +1283,13 @@ int SessionStub::HandleNotifyExtensionDetachToDisplay(MessageParcel& data, Messa return ERR_NONE; } +int SessionStub::HandleExtensionProviderData(MessageParcel& data, MessageParcel& reply) +{ + TLOGD(WmsLogTag::WMS_UIEXT, "in"); + NotifyExtensionDataConsumer(data, reply); + return ERR_NONE; +} + int SessionStub::HandleRequestFocus(MessageParcel& data, MessageParcel& reply) { TLOGD(WmsLogTag::WMS_FOCUS, "in"); diff --git a/window_scene/test/unittest/BUILD.gn b/window_scene/test/unittest/BUILD.gn index 29ce45aa975ac4bfa57416745492da54bfc3594a..3e0e9d09fc11d087bdf949d08fac1b1519648d39 100644 --- a/window_scene/test/unittest/BUILD.gn +++ b/window_scene/test/unittest/BUILD.gn @@ -101,6 +101,7 @@ group("unittest") { ":ws_window_event_channel_test", ":ws_window_scene_config_test", ":ws_window_session_property_test", + "ui_extension:unittest", "window_pattern:window_pattern_snapshot_test", ] @@ -1668,6 +1669,7 @@ config("ws_unittest_common_public_config") { ohos_static_library("ws_unittest_common") { visibility = [ ":*", + "ui_extension:*", "window_pattern:*", ] testonly = true diff --git a/window_scene/test/unittest/ui_extension/BUILD.gn b/window_scene/test/unittest/ui_extension/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..0a2943989e65a880d7bfab685fd0dcb735eeaad3 --- /dev/null +++ b/window_scene/test/unittest/ui_extension/BUILD.gn @@ -0,0 +1,31 @@ +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") +import("../../../../windowmanager_aafwk.gni") + +group("unittest") { + testonly = true + deps = [ ":extension_data_handler_test" ] +} + +module_out_path = "window_manager/window_scene/ui_extension" +ws_unittest_common = "../:ws_unittest_common" + +ohos_unittest("extension_data_handler_test") { + module_out_path = module_out_path + sources = [ "data_handler/extension_data_handler_test.cpp" ] + include_dirs = [ "${window_base_path}/window_scene/session/host/include" ] + deps = [ ws_unittest_common ] + external_deps = [ "c_utils:utils" ] +} diff --git a/window_scene/test/unittest/ui_extension/data_handler/extension_data_handler_mock.h b/window_scene/test/unittest/ui_extension/data_handler/extension_data_handler_mock.h new file mode 100644 index 0000000000000000000000000000000000000000..c73ea9d925f43658b190c20ba0e75f5dd556f6da --- /dev/null +++ b/window_scene/test/unittest/ui_extension/data_handler/extension_data_handler_mock.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * 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. + */ + +#ifndef OHOS_ROSEN_EXTENSION_DATA_HANDLE_MOCK_H +#define OHOS_ROSEN_EXTENSION_DATA_HANDLE_MOCK_H + +#include + +#include "common/include/extension_data_handler.h" + +namespace OHOS::Rosen::Extension { +class MockDataHandler : public DataHandler { +public: + MockDataHandler() = default; + ~MockDataHandler() override = default; + + MOCK_METHOD(DataHandlerErr, SendData, + (const AAFwk::Want& data, AAFwk::Want& reply, const DataTransferConfig& config), (override)); + MOCK_METHOD(bool, WriteInterfaceToken, (MessageParcel& data), (override)); + + // Helper methods to expose protected methods for testing + using DataHandler::NotifyDataConsumer; +}; +} // namespace OHOS::Rosen::Extension +#endif // OHOS_ROSEN_EXTENSION_DATA_HANDLE_MOCK_H diff --git a/window_scene/test/unittest/ui_extension/data_handler/extension_data_handler_test.cpp b/window_scene/test/unittest/ui_extension/data_handler/extension_data_handler_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe9b6427cd72c90a9de0bb91679724e997136385 --- /dev/null +++ b/window_scene/test/unittest/ui_extension/data_handler/extension_data_handler_test.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * 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 "common/include/extension_data_handler.h" + +#include +#include +#include + +#include "extension_data_handler_mock.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS::Rosen::Extension { +class ExtensionDataHandlerTest : public testing::Test { +public: + static void SetUpTestCase() {} + static void TearDownTestCase() {} + void SetUp() override {} + void TearDown() override {} +}; + +/** + * @tc.name: DataTransferConfigMarshalling01 + * @tc.desc: Test DataTransferConfig Marshalling with valid data + * @tc.type: FUNC + */ +HWTEST_F(ExtensionDataHandlerTest, DataTransferConfigMarshalling01, Function | SmallTest | Level2) +{ + DataTransferConfig config; + config.subSystemId = SubSystemId::WM_UIEXT; + config.customId = 123; + config.needReply = true; + config.needSyncSend = false; + + MessageParcel parcel; + ASSERT_TRUE(config.Marshalling(parcel)); +} + +/** + * @tc.name: DataTransferConfigUnmarshalling01 + * @tc.desc: Test DataTransferConfig Unmarshalling with valid data + * @tc.type: FUNC + */ +HWTEST_F(ExtensionDataHandlerTest, DataTransferConfigUnmarshalling01, Function | SmallTest | Level2) +{ + MessageParcel parcel; + parcel.WriteUint8(static_cast(SubSystemId::WM_UIEXT)); + parcel.WriteUint32(123); + parcel.WriteBool(true); + parcel.WriteBool(false); + + auto config = DataTransferConfig::Unmarshalling(parcel); + ASSERT_NE(nullptr, config); + ASSERT_EQ(SubSystemId::WM_UIEXT, config->subSystemId); + ASSERT_EQ(123u, config->customId); + ASSERT_TRUE(config->needReply); + ASSERT_FALSE(config->needSyncSend); + delete config; +} + +/** + * @tc.name: DataTransferConfigUnmarshalling02 + * @tc.desc: Test DataTransferConfig Unmarshalling with invalid subSystemId + * @tc.type: FUNC + */ +HWTEST_F(ExtensionDataHandlerTest, DataTransferConfigUnmarshalling02, Function | SmallTest | Level2) +{ + MessageParcel parcel; + parcel.WriteUint8(static_cast(SubSystemId::INVALID)); + parcel.WriteUint32(123); + parcel.WriteBool(true); + parcel.WriteBool(false); + + auto config = DataTransferConfig::Unmarshalling(parcel); + ASSERT_EQ(nullptr, config); +} + +/** + * @tc.name: RegisterDataConsumer01 + * @tc.desc: Test RegisterDataConsumer with valid callback + * @tc.type: FUNC + */ +HWTEST_F(ExtensionDataHandlerTest, RegisterDataConsumer01, Function | SmallTest | Level2) +{ + MockDataHandler handler; + auto callback = [](SubSystemId id, uint32_t customId, AAFwk::Want&& data, + std::optional& reply) -> int32_t { + return 0; + }; + + auto ret = handler.RegisterDataConsumer(SubSystemId::WM_UIEXT, std::move(callback)); + ASSERT_EQ(DataHandlerErr::OK, ret); +} + +/** + * @tc.name: RegisterDataConsumer02 + * @tc.desc: Test RegisterDataConsumer with duplicate registration + * @tc.type: FUNC + */ +HWTEST_F(ExtensionDataHandlerTest, RegisterDataConsumer02, Function | SmallTest | Level2) +{ + MockDataHandler handler; + auto callback = [](SubSystemId id, uint32_t customId, AAFwk::Want&& data, + std::optional& reply) -> int32_t { + return 0; + }; + auto callback1 = callback; + auto ret = handler.RegisterDataConsumer(SubSystemId::WM_UIEXT, std::move(callback)); + ASSERT_EQ(ret, DataHandlerErr::OK); + + ret = handler.RegisterDataConsumer(SubSystemId::WM_UIEXT, std::move(callback1)); + ASSERT_EQ(ret, DataHandlerErr::DUPLICATE_REGISTRATION); +} + +/** + * @tc.name: UnregisterDataConsumer01 + * @tc.desc: Test UnregisterDataConsumer with registered consumer + * @tc.type: FUNC + */ +HWTEST_F(ExtensionDataHandlerTest, UnregisterDataConsumer01, Function | SmallTest | Level2) +{ + MockDataHandler handler; + auto callback = [](SubSystemId id, uint32_t customId, AAFwk::Want&& data, + std::optional& reply) -> int32_t { + return 0; + }; + auto callback1 = callback; + + ASSERT_EQ(DataHandlerErr::OK, handler.RegisterDataConsumer(SubSystemId::WM_UIEXT, std::move(callback))); + handler.UnregisterDataConsumer(SubSystemId::WM_UIEXT); + + // Verify unregistration by trying to register again + ASSERT_EQ(DataHandlerErr::OK, handler.RegisterDataConsumer(SubSystemId::WM_UIEXT, std::move(callback1))); +} + +/** + * @tc.name: SendDataTest01 + * @tc.desc: Test SendDataSync with mocked behavior + * @tc.type: FUNC + */ +HWTEST_F(ExtensionDataHandlerTest, SendDataTest01, Function | SmallTest | Level2) +{ + MockDataHandler handler; + AAFwk::Want data; + AAFwk::Want reply; + + // Set up expectations + EXPECT_CALL(handler, SendData(testing::_, testing::_, testing::_)).WillOnce(testing::Return(DataHandlerErr::OK)); + + // Test SendDataSync + ASSERT_EQ(DataHandlerErr::OK, handler.SendDataSync(SubSystemId::WM_UIEXT, 123, data, reply)); +} + +/** + * @tc.name: NotifyDataConsumer01 + * @tc.desc: Test NotifyDataConsumer with sync mode and valid callback + * @tc.type: FUNC + */ +HWTEST_F(ExtensionDataHandlerTest, NotifyDataConsumer01, Function | SmallTest | Level2) +{ + MockDataHandler handler; + bool callbackCalled = false; + + auto callback = [&callbackCalled](SubSystemId id, uint32_t customId, AAFwk::Want&& data, + std::optional& reply) -> int32_t { + callbackCalled = true; + EXPECT_EQ(SubSystemId::WM_UIEXT, id); + EXPECT_EQ(123u, customId); + if (reply.has_value()) { + reply->SetParam("test", 1); + } + return 0; + }; + + // Register consumer + auto ret = handler.RegisterDataConsumer(SubSystemId::WM_UIEXT, std::move(callback)); + ASSERT_EQ(DataHandlerErr::OK, ret); + + // Prepare test data + AAFwk::Want data; + std::optional reply = std::make_optional(); + DataTransferConfig config; + config.needSyncSend = true; + config.needReply = true; + config.subSystemId = SubSystemId::WM_UIEXT; + config.customId = 123; + + // Test NotifyDataConsumer + ret = handler.NotifyDataConsumer(std::move(data), reply, config); + ASSERT_EQ(DataHandlerErr::OK, ret); + ASSERT_TRUE(callbackCalled); + ASSERT_TRUE(reply.has_value()); + ASSERT_EQ(1, reply->GetIntParam("test", 0)); +} + +/** + * @tc.name: NotifyDataConsumer02 + * @tc.desc: Test NotifyDataConsumer with async mode + * @tc.type: FUNC + */ +HWTEST_F(ExtensionDataHandlerTest, NotifyDataConsumer02, Function | SmallTest | Level2) +{ + MockDataHandler handler; + bool callbackCalled = false; + + auto callback = [&callbackCalled](SubSystemId id, uint32_t customId, AAFwk::Want&& data, + std::optional& reply) -> int32_t { + callbackCalled = true; + EXPECT_EQ(SubSystemId::WM_UIEXT, id); + EXPECT_EQ(123u, customId); + return 0; + }; + + // Register consumer + ASSERT_EQ(DataHandlerErr::OK, handler.RegisterDataConsumer(SubSystemId::WM_UIEXT, std::move(callback))); + + // Prepare test data + AAFwk::Want data; + std::optional reply; + DataTransferConfig config; + config.needSyncSend = false; + config.subSystemId = SubSystemId::WM_UIEXT; + config.customId = 123; + + // Test NotifyDataConsumer + auto ret = handler.NotifyDataConsumer(std::move(data), reply, config); + ASSERT_EQ(DataHandlerErr::OK, ret); +} + +/** + * @tc.name: NotifyDataConsumer03 + * @tc.desc: Test NotifyDataConsumer with unregistered consumer + * @tc.type: FUNC + */ +HWTEST_F(ExtensionDataHandlerTest, NotifyDataConsumer03, Function | SmallTest | Level2) +{ + MockDataHandler handler; + AAFwk::Want data; + std::optional reply; + DataTransferConfig config; + config.subSystemId = SubSystemId::WM_UIEXT; + config.customId = 123; + + // Test NotifyDataConsumer without registering consumer + auto ret = handler.NotifyDataConsumer(std::move(data), reply, config); + ASSERT_EQ(DataHandlerErr::NO_CONSUME_CALLBACK, ret); +} +} // namespace OHOS::Rosen::Extension