* Copyright (c) 2023-2025 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 "adapter/android/entrance/java/jni/udmf/udmf_impl.h"
#include <cstdint>
#include <iostream>
#include <memory>
#include <unordered_map>
#include <mutex>
#include <string>
#include "application_defined_record.h"
#include "error_code.h"
#include "js_native_api_types.h"
#include "native_engine/native_engine.h"
#include "plain_text.h"
#include "summary_napi.h"
#include "unified_data_napi.h"
#include "base/utils/utils.h"
#include "bridge/common/utils/engine_helper.h"
#include "bridge/common/utils/utils.h"
#include "bridge/js_frontend/engine/common/js_engine.h"
#include "core/common/udmf/unified_data.h"
const std::string UNIFIED_KEY_SCHEMA = "udmf://";
const std::string UNIFIED_INTENTION = "drag";
namespace OHOS::Ace {
std::mutex UdmfClientImpl::unifiedDataLock_;
std::map<std::string, RefPtr<UnifiedData>> UdmfClientImpl::unifiedDataMap_;
int32_t UdmfClientImpl::groupId_ = 0;
UdmfClient* UdmfClient::GetInstance()
{
static UdmfClientImpl instance;
return &instance;
}
RefPtr<UnifiedData> UdmfClientImpl::TransformUnifiedData(napi_value napiValue)
{
auto engine = EngineHelper::GetCurrentEngine();
CHECK_NULL_RETURN(engine, nullptr);
NativeEngine* nativeEngine = engine->GetNativeEngine();
napi_env env = reinterpret_cast<napi_env>(nativeEngine);
void* native = nullptr;
napi_unwrap(env, napiValue, &native);
auto* unifiedData = reinterpret_cast<UDMF::UnifiedDataNapi*>(native);
CHECK_NULL_RETURN(unifiedData, nullptr);
CHECK_NULL_RETURN(unifiedData->value_, nullptr);
auto udData = AceType::MakeRefPtr<UnifiedDataImpl>();
udData->SetUnifiedData(unifiedData->value_);
return udData;
}
RefPtr<UnifiedData> UdmfClientImpl::TransformUnifiedDataForNative(void* rawData)
{
return nullptr;
}
RefPtr<DataLoadParams> UdmfClientImpl::TransformDataLoadParamsForNative(void* rawData)
{
return nullptr;
}
RefPtr<UnifiedData> UdmfClientImpl::TransformUnifiedDataFromANI(void* rawData)
{
return nullptr;
}
void UdmfClientImpl::TransformSummaryANI(std::map<std::string, int64_t>& summary, std::shared_ptr<void> summaryPtr)
{}
RefPtr<DataLoadParams> UdmfClientImpl::TransformDataLoadParamsFromANI(void* rawData)
{
return nullptr;
}
void* UdmfClientImpl::TransformUnifiedDataPtr(RefPtr<UnifiedData>& unifiedData)
{
return nullptr;
}
std::shared_ptr<void> UdmfClientImpl::TransformUnifiedDataSharedPtr(RefPtr<UnifiedData>& unifiedDataImpl)
{
CHECK_NULL_RETURN(unifiedDataImpl, nullptr);
return AceType::DynamicCast<UnifiedDataImpl>(unifiedDataImpl)->GetUnifiedData();
}
RefPtr<DataLoadParams> UdmfClientImpl::TransformDataLoadParams(napi_env env, napi_value napiValue)
{
return nullptr;
}
int32_t UdmfClientImpl::SetDelayInfo(RefPtr<DataLoadParams> dataLoadParams, std::string& key)
{
return -1;
}
napi_value UdmfClientImpl::TransformUdmfUnifiedData(RefPtr<UnifiedData>& UnifiedData)
{
auto engine = EngineHelper::GetCurrentEngine();
CHECK_NULL_RETURN(engine, nullptr);
NativeEngine* nativeEngine = engine->GetNativeEngine();
napi_env env = reinterpret_cast<napi_env>(nativeEngine);
auto unifiedData = AceType::DynamicCast<UnifiedDataImpl>(UnifiedData)->GetUnifiedData();
CHECK_NULL_RETURN(unifiedData, nullptr);
napi_value dataVal = nullptr;
UDMF::UnifiedDataNapi::NewInstance(env, unifiedData, dataVal);
CHECK_NULL_RETURN(dataVal, nullptr);
return dataVal;
}
napi_value UdmfClientImpl::TransformSummary(std::map<std::string, int64_t>& summary)
{
auto engine = EngineHelper::GetCurrentEngine();
CHECK_NULL_RETURN(engine, nullptr);
NativeEngine* nativeEngine = engine->GetNativeEngine();
napi_env env = reinterpret_cast<napi_env>(nativeEngine);
std::shared_ptr<UDMF::Summary> udmfSummary = std::make_shared<UDMF::Summary>();
CHECK_NULL_RETURN(udmfSummary, nullptr);
udmfSummary->totalSize = 0;
for (auto element : summary) {
udmfSummary->totalSize += element.second;
}
udmfSummary->summary = std::move(summary);
napi_value dataVal = nullptr;
UDMF::SummaryNapi::NewInstance(env, udmfSummary, dataVal);
CHECK_NULL_RETURN(dataVal, nullptr);
return dataVal;
}
RefPtr<UnifiedData> UdmfClientImpl::CreateUnifiedData()
{
return AceType::DynamicCast<UnifiedData>(AceType::MakeRefPtr<UnifiedDataImpl>());
}
int32_t UdmfClientImpl::SetData(const RefPtr<UnifiedData>& unifiedData, std::string& key)
{
CHECK_NULL_RETURN(unifiedData, UDMF::E_INVALID_PARAMETERS);
std::lock_guard<std::mutex> lock(unifiedDataLock_);
std::string groupIdStr = std::to_string(getGroupId());
std::string* keyRef_ = (std::string*)&key;
*keyRef_ = UNIFIED_KEY_SCHEMA + UNIFIED_INTENTION + groupIdStr;
RefPtr<UnifiedData>& udRef_ = const_cast<RefPtr<UnifiedData>&>(unifiedData);
unifiedDataMap_[*keyRef_] = udRef_;
return UDMF::E_OK;
}
int32_t UdmfClientImpl::GetData(const RefPtr<UnifiedData>& unifiedData, const std::string& key)
{
if (key.empty()) {
LOGE("GetData Failed, Invalid key");
return UDMF::E_INVALID_PARAMETERS;
}
std::lock_guard<std::mutex> lock(unifiedDataLock_);
RefPtr<UnifiedData>& udRef = const_cast<RefPtr<UnifiedData>&>(unifiedData);
auto iter = unifiedDataMap_.find(key);
if (iter == unifiedDataMap_.end()) {
LOGE("GetData Failed, Data is empty");
return UDMF::E_NOT_FOUND;
}
udRef = iter->second;
unifiedDataMap_.erase(iter);
return UDMF::E_OK;
}
int32_t UdmfClientImpl::GetSummary(std::string& key, DragSummaryInfo& dragSummaryInfo)
{
if (key.empty()) {
LOGE("GetSummary Failed, Invalid key");
return UDMF::E_INVALID_PARAMETERS;
}
std::lock_guard<std::mutex> lock(unifiedDataLock_);
auto iter = unifiedDataMap_.find(key);
if (iter == unifiedDataMap_.end()) {
LOGE("GetSummary Failed, Data is empty");
return UDMF::E_NOT_FOUND;
}
RefPtr<UnifiedData>& unifiedData = iter->second;
UDMF::Summary summary;
for (const auto& record : AceType::DynamicCast<UnifiedDataImpl>(unifiedData)->GetUnifiedData()->GetRecords()) {
int64_t recordSize = record->GetSize();
auto udType = UDMF::UtdUtils::GetUtdIdFromUtdEnum(record->GetType());
auto it = summary.summary.find(udType);
if (it == summary.summary.end()) {
summary.summary[udType] = recordSize;
} else {
summary.summary[udType] += recordSize;
}
summary.totalSize += recordSize;
}
dragSummaryInfo.summary = summary.summary;
dragSummaryInfo.detailedSummary = summary.specificSummary;
dragSummaryInfo.summaryFormat = summary.summaryFormat;
dragSummaryInfo.version = summary.version;
dragSummaryInfo.totalSize = summary.totalSize;
return UDMF::E_OK;
}
bool UdmfClientImpl::GetRemoteStatus(std::string& key)
{
return false;
}
void UdmfClientImpl::AddFormRecord(
const RefPtr<UnifiedData>& unifiedData, int32_t formId, const RequestFormInfo& cardInfo)
{}
void UdmfClientImpl::AddLinkRecord(
const RefPtr<UnifiedData>& unifiedData, const std::string& url, const std::string& description)
{}
void UdmfClientImpl::GetLinkRecord(const RefPtr<UnifiedData>& unifiedData, std::string& url, std::string& description)
{}
bool UdmfClientImpl::GetFileUriRecord(const RefPtr<UnifiedData>& unifiedData, std::vector<std::string>& uri)
{
return false;
}
bool UdmfClientImpl::AddFileUriRecord(const RefPtr<UnifiedData>& unifiedData, std::vector<std::string>& uri)
{
return false;
}
void UdmfClientImpl::AddHtmlRecord(
const RefPtr<UnifiedData>& unifiedData, const std::string& htmlContent, const std::string& plainContent)
{}
void UdmfClientImpl::GetHtmlRecord(
const RefPtr<UnifiedData>& unifiedData, std::string& htmlContent, std::string& plainContent)
{}
void UdmfClientImpl::AddPixelMapRecord(
const RefPtr<UnifiedData>& unifiedData, std::vector<uint8_t>& data, PixelMapRecordDetails& details)
{}
void UdmfClientImpl::AddImageRecord(const RefPtr<UnifiedData>& unifiedData, const std::string& uri) {}
void UdmfClientImpl::AddPlainTextRecord(const RefPtr<UnifiedData>& unifiedData, const std::string& selectedStr)
{
auto record = std::make_shared<UDMF::PlainText>(selectedStr, "");
auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
CHECK_NULL_VOID(udData);
CHECK_NULL_VOID(udData->GetUnifiedData());
udData->GetUnifiedData()->AddRecord(record);
}
std::string UdmfClientImpl::GetSinglePlainTextRecord(const RefPtr<UnifiedData>& unifiedData)
{
return "";
}
std::vector<std::string> UdmfClientImpl::GetPlainTextRecords(const RefPtr<UnifiedData>& unifiedData)
{
std::vector<std::string> textRecords;
auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
CHECK_NULL_RETURN(udData, textRecords);
CHECK_NULL_RETURN(udData->GetUnifiedData(), textRecords);
auto records = udData->GetUnifiedData()->GetRecords();
for (const auto& record : records) {
UDMF::UDType type = record->GetType();
if (type == UDMF::UDType::PLAIN_TEXT) {
UDMF::PlainText* plainText = reinterpret_cast<UDMF::PlainText*>(record.get());
std::string str = plainText->GetContent();
textRecords.emplace_back(str);
}
}
return textRecords;
}
int32_t UdmfClientImpl::GetVideoRecordUri(const RefPtr<UnifiedData>& unifiedData, std::string& uri)
{
return -1;
}
std::pair<int32_t, std::string> UdmfClientImpl::GetErrorInfo(int32_t errorCode)
{
switch (errorCode) {
case UDMF::E_NOT_FOUND:
return { ERROR_CODE_DRAG_DATA_NOT_FOUND, "GetData failed, data not found." };
default:
return { ERROR_CODE_DRAG_DATA_ERROR, "GetData failed, data error." };
}
}
std::shared_ptr<UDMF::UnifiedData> UnifiedDataImpl::GetUnifiedData()
{
if (unifiedData_ == nullptr) {
unifiedData_ = std::make_shared<UDMF::UnifiedData>();
}
return unifiedData_;
}
void UnifiedDataImpl::SetUnifiedData(std::shared_ptr<UDMF::UnifiedData> unifiedData)
{
unifiedData_ = unifiedData;
}
int64_t UnifiedDataImpl::GetSize()
{
CHECK_NULL_RETURN(unifiedData_, 0);
return unifiedData_->GetRecords().size();
}
int32_t UdmfClientImpl::getGroupId()
{
return groupId_++;
}
void UdmfClientImpl::AddSpanStringRecord(
const RefPtr<UnifiedData>& unifiedData, std::vector<uint8_t>& data)
{
auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
CHECK_NULL_VOID(udData);
CHECK_NULL_VOID(udData->GetUnifiedData());
auto record = std::make_shared<UDMF::ApplicationDefinedRecord>("OPENHARMONY_STYLED_STRING_UDMF", data);
udData->GetUnifiedData()->AddRecord(record);
}
std::vector<uint8_t> UdmfClientImpl::GetSpanStringRecord(const RefPtr<UnifiedData>& unifiedData)
{
std::vector<uint8_t> arr;
auto udData = AceType::DynamicCast<UnifiedDataImpl>(unifiedData);
CHECK_NULL_RETURN(udData, arr);
CHECK_NULL_RETURN(udData->GetUnifiedData(), arr);
auto records = udData->GetUnifiedData()->GetRecords();
for (auto record: records) {
UDMF::UDType type = record->GetType();
if (type == UDMF::UDType::APPLICATION_DEFINED_RECORD) {
UDMF::ApplicationDefinedRecord* app = reinterpret_cast<UDMF::ApplicationDefinedRecord*>(record.get());
if (app->GetApplicationDefinedType() == "OPENHARMONY_STYLED_STRING_UDMF") {
arr = app->GetRawData();
return arr;
}
}
}
return arr;
}
int32_t UdmfClientImpl::StartAsyncDataRetrieval(napi_env env, napi_value napiValue, const std::string& key)
{
return -1;
}
int32_t UdmfClientImpl::Cancel(const std::string& key)
{
return -1;
}
void UdmfClientImpl::SetTagProperty(const RefPtr<UnifiedData>& unifiedData, const std::string& tag) {}
std::string UdmfClientImpl::GetPlainTextEntry(const RefPtr<UnifiedData>& unifiedData)
{
return "";
}
void UdmfClientImpl::GetHtmlEntry(
const RefPtr<UnifiedData>& unifiedData, std::string& htmlContent, std::string& plainContent)
{}
void UdmfClientImpl::GetLinkEntry(const RefPtr<UnifiedData>& unifiedData, std::string& url, std::string& description) {}
bool UdmfClientImpl::GetFileUriEntry(const RefPtr<UnifiedData>& unifiedData, std::vector<std::string>& uri)
{
return false;
}
std::vector<uint8_t> UdmfClientImpl::GetSpanStringEntry(const RefPtr<UnifiedData>& unifiedData)
{
return {};
}
bool UdmfClientImpl::IsAppropriateType(DragSummaryInfo& dragSummaryInfo, const std::set<std::string>& allowTypes)
{
std::vector<std::string> allowTypesArr(allowTypes.begin(), allowTypes.end());
for (const auto& allowType : allowTypes) {
if (dragSummaryInfo.summary.find(allowType) != dragSummaryInfo.summary.end() ||
dragSummaryInfo.detailedSummary.find(allowType) != dragSummaryInfo.detailedSummary.end()) {
return true;
}
}
return false;
}
}