• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #define LOG_TAG "unifiedDataChannelANI"
16 #include "unifieddatachannel_ani.h"
17 #include "ani_utils.h"
18 #include "logger.h"
19 #include "ani_common_want.h"
20 #include "image_ani_utils.h"
21 
22 #include "unified_types.h"
23 #include "unified_meta.h"
24 
25 #include "plain_text.h"
26 #include "html.h"
27 #include "link.h"
28 #include "image.h"
29 #include "video.h"
30 #include "audio.h"
31 #include "folder.h"
32 #include "system_defined_appitem.h"
33 #include "system_defined_form.h"
34 #include "system_defined_pixelmap.h"
35 #include "application_defined_record.h"
36 
37 using namespace OHOS;
38 using namespace OHOS::UDMF;
39 
ParseANIRecordValueType(ani_env * env,const std::string type,ani_object unionValue)40 static UDMF::ValueType ParseANIRecordValueType(ani_env *env, const std::string type, ani_object unionValue)
41 {
42     UnionAccessor unionAccessor(env, unionValue);
43 
44     double doubleValue = 0.0;
45     if (unionAccessor.TryConvert<double>(doubleValue)) {
46         return doubleValue;
47     }
48 
49     std::string stringValue;
50     if (unionAccessor.TryConvert<std::string>(stringValue)) {
51         return stringValue;
52     }
53 
54     bool boolValue = false;
55     if (unionAccessor.TryConvert<bool>(boolValue)) {
56         return boolValue;
57     }
58 
59     int intValue = 0;
60     if (unionAccessor.TryConvert<int>(intValue)) {
61         return intValue;
62     }
63 
64     std::vector<uint8_t> arrayVect;
65     if (unionAccessor.TryConvertArray<uint8_t>(arrayVect)) {
66         return arrayVect;
67     }
68 
69     if (!unionAccessor.IsInstanceOf("Lstd/core/Object;")) {
70         LOG_DEBUG(UDMF_KITS_NAPI, "ParseANIRecordValueType default std::monostate");
71         return std::monostate();
72     }
73 
74     if (type == "openharmony.pixel-map") {
75         auto pixelMap = Media::ImageAniUtils::GetPixelMapFromEnv(env, unionValue);
76         if (pixelMap == nullptr) {
77             return std::shared_ptr<Media::PixelMap>(nullptr);
78         }
79         std::shared_ptr<Media::PixelMap> pixelMapSpr(pixelMap);
80         return pixelMapSpr;
81     } else if (type == "openharmony.want") {
82         AAFwk::Want wantObj;
83         AppExecFwk::UnwrapWant(env, unionValue, wantObj);
84         return std::make_shared<AAFwk::Want>(wantObj);
85     } else {
86         return std::make_shared<Object>();
87     }
88 }
89 
UnifiedRecordHolder(ani_env * env,const std::string type,ani_object unionValue)90 UnifiedRecordHolder::UnifiedRecordHolder(ani_env *env, const std::string type, ani_object unionValue)
91 {
92     if (type.empty() && unionValue == nullptr) {
93         object_ = std::make_shared<UnifiedRecord>();
94         return;
95     }
96 
97     UDType utdType = ENTITY;
98     if (UtdUtils::IsValidUtdId(type)) {
99         utdType = static_cast<UDType>(UtdUtils::GetUtdEnumFromUtdId(type));
100     }
101 
102     UDMF::ValueType value = ParseANIRecordValueType(env, type, unionValue);
103 
104     std::map<UDType, std::function<std::shared_ptr<UnifiedRecord>(UDType, ValueType)>> constructors = {
105         {TEXT, [](UDType type, ValueType value) { return std::make_shared<Text>(type, value); }},
106         {PLAIN_TEXT, [](UDType type, ValueType value) { return std::make_shared<PlainText>(type, value); }},
107         {HTML, [](UDType type, ValueType value) { return std::make_shared<Html>(type, value); }},
108         {HYPERLINK, [](UDType type, ValueType value) { return std::make_shared<Link>(type, value); }},
109         {UDType::FILE, [](UDType type, ValueType value) { return std::make_shared<File>(type, value); }},
110         {IMAGE, [](UDType type, ValueType value) { return std::make_shared<Image>(type, value); }},
111         {VIDEO, [](UDType type, ValueType value) { return std::make_shared<Video>(type, value); }},
112         {AUDIO, [](UDType type, ValueType value) { return std::make_shared<Audio>(type, value); }},
113         {FOLDER, [](UDType type, ValueType value) { return std::make_shared<Folder>(type, value); }},
114         {SYSTEM_DEFINED_RECORD, [](UDType type, ValueType value)
115             { return std::make_shared<SystemDefinedRecord>(type, value); }},
116         {SYSTEM_DEFINED_APP_ITEM, [](UDType type, ValueType value)
117             { return std::make_shared<SystemDefinedAppItem>(type, value); }},
118         {SYSTEM_DEFINED_FORM, [](UDType type, ValueType value)
119             { return std::make_shared<SystemDefinedForm>(type, value); }},
120         {SYSTEM_DEFINED_PIXEL_MAP, [](UDType type, ValueType value)
121             { return std::make_shared<SystemDefinedPixelMap>(type, value); }},
122         {APPLICATION_DEFINED_RECORD, [](UDType type, ValueType value)
123             { return std::make_shared<ApplicationDefinedRecord>(type, value); }},
124     };
125 
126     auto constructor = constructors.find(utdType);
127     if (constructor == constructors.end()) {
128         object_ = std::make_shared<UnifiedRecord>();
129         return;
130     }
131 
132     object_ = constructor->second(utdType, value);
133     if (utdType == APPLICATION_DEFINED_RECORD) {
134         std::shared_ptr<ApplicationDefinedRecord> applicationDefinedRecord =
135             std::static_pointer_cast<ApplicationDefinedRecord>(object_);
136         applicationDefinedRecord->SetApplicationDefinedType(type);
137     }
138 }
139 
Get()140 const std::shared_ptr<UnifiedRecord> UnifiedRecordHolder::Get()
141 {
142     if (object_ == nullptr) {
143         object_ = std::make_shared<UnifiedRecord>();
144     }
145     return object_;
146 }
147 
Set(ani_ref saveRemote)148 void UnifiedRecordHolder::Set(ani_ref saveRemote)
149 {
150     saveRemote_ = saveRemote;
151 }
152 
~UnifiedRecordHolder()153 UnifiedRecordHolder::~UnifiedRecordHolder()
154 {
155     LOG_DEBUG(UDMF_KITS_NAPI, "[ANI] enter UnifiedRecordHolder dtor ");
156 }
157 
158 
UnifiedDataHolder(UnifiedRecordHolder * recordHolder)159 UnifiedDataHolder::UnifiedDataHolder(UnifiedRecordHolder* recordHolder)
160 {
161     object_ = std::make_shared<UnifiedData>();
162 
163     if (recordHolder != nullptr) {
164         auto recordPtr = recordHolder->Get();
165         if (recordPtr != nullptr) {
166             object_->AddRecord(recordPtr);
167         }
168     }
169 }
170 
Get()171 std::shared_ptr<UnifiedData> UnifiedDataHolder::Get()
172 {
173     return object_;
174 }
175 
Set(ani_ref saveRemote)176 void UnifiedDataHolder::Set(ani_ref saveRemote)
177 {
178     saveRemote_ = saveRemote;
179 }
180 
~UnifiedDataHolder()181 UnifiedDataHolder::~UnifiedDataHolder()
182 {
183     LOG_DEBUG(UDMF_KITS_NAPI, "[ANI] enter UnifiedDataHolder dtor ");
184 }
185 
UnifiedRecodeValueTypeConstructor(ani_env * env,ani_object object,ani_string descriptor,ani_object unionValue)186 static void UnifiedRecodeValueTypeConstructor([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object,
187     ani_string descriptor, ani_object unionValue)
188 {
189     LOG_DEBUG(UDMF_KITS_NAPI, "[ANI] enter UnifiedRecodeValueTypeConstructor");
190 
191     ani_ref saveRemote = nullptr;
192     env->GlobalReference_Create(reinterpret_cast<ani_ref>(object), &saveRemote);
193 
194     auto type = AniStringUtils::ToStd(env, static_cast<ani_string>(descriptor));
195     auto objectRemoteHolder = new UnifiedRecordHolder(env, type, unionValue);
196     objectRemoteHolder->Set(saveRemote);
197     AniObjectUtils::Wrap<UnifiedRecordHolder>(env, object, objectRemoteHolder);
198 }
199 
UnifiedRecodeConstructor(ani_env * env,ani_object object)200 static void UnifiedRecodeConstructor([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object)
201 {
202     LOG_DEBUG(UDMF_KITS_NAPI, "[ANI] enter UnifiedRecodeConstructor");
203     if (env == nullptr) {
204         return;
205     }
206     ani_ref saveRemote = nullptr;
207     env->GlobalReference_Create(reinterpret_cast<ani_ref>(object), &saveRemote);
208 
209     auto objectRemoteHolder = new UnifiedRecordHolder(env, "", nullptr);
210     if (objectRemoteHolder == nullptr) {
211         return;
212     }
213     objectRemoteHolder->Set(saveRemote);
214     AniObjectUtils::Wrap<UnifiedRecordHolder>(env, object, objectRemoteHolder);
215 }
216 
UnifiedDataConstructor(ani_env * env,ani_object object,ani_object recordObj)217 static void UnifiedDataConstructor([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object,
218     ani_object recordObj)
219 {
220     LOG_DEBUG(UDMF_KITS_NAPI, "[ANI] enter UnifiedDataConstructor ");
221     auto recoderHolder = AniObjectUtils::Unwrap<UnifiedRecordHolder>(env, recordObj);
222 
223     ani_ref saveRemote = nullptr;
224     env->GlobalReference_Create(reinterpret_cast<ani_ref>(object), &saveRemote);
225 
226     auto objectHolder = new UnifiedDataHolder(recoderHolder);
227     objectHolder->Set(saveRemote);
228     AniObjectUtils::Wrap<UnifiedDataHolder>(env, object, objectHolder);
229 }
230 
initDataWithOutRecordConstructor(ani_env * env,ani_object object)231 static void initDataWithOutRecordConstructor([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object)
232 {
233     LOG_DEBUG(UDMF_KITS_NAPI, "[ANI] enter initDataWithOutRecordConstructor");
234     if (env == nullptr) {
235         return;
236     }
237     ani_ref saveRemote = nullptr;
238     env->GlobalReference_Create(reinterpret_cast<ani_ref>(object), &saveRemote);
239 
240     auto objectHolder = new UnifiedDataHolder(nullptr);
241     if (objectHolder == nullptr) {
242         return;
243     }
244     objectHolder->Set(saveRemote);
245     AniObjectUtils::Wrap<UnifiedDataHolder>(env, object, objectHolder);
246 }
247 
UnifiedRecordToObject(ani_env * env,std::shared_ptr<UnifiedRecord> record)248 static ani_object UnifiedRecordToObject(ani_env *env, std::shared_ptr<UnifiedRecord> record)
249 {
250     ani_object aniObject = nullptr;
251 
252     static const char *nameSpaceName = "L@ohos/data/unifiedDataChannel/unifiedDataChannel;";
253     ani_namespace ns;
254     if (ANI_OK != env->FindNamespace(nameSpaceName, &ns)) {
255         LOG_ERROR(UDMF_KITS_NAPI, "Not found namespace %{public}s", nameSpaceName);
256         return aniObject;
257     }
258 
259     static const char *recordclsName = "LUnifiedRecord;";
260     ani_class aniClass;
261     if (ANI_OK != env->Namespace_FindClass(ns, recordclsName, &aniClass)) {
262         LOG_ERROR(UDMF_KITS_NAPI, "Not found class %{public}s", recordclsName);
263         return aniObject;
264     }
265 
266     ani_method personInfoCtor;
267     if (ANI_OK != env->Class_FindMethod(aniClass, "setNativePtr", nullptr, &personInfoCtor)) {
268         LOG_ERROR(UDMF_KITS_NAPI, "Not found func setNativePtr");
269         return aniObject;
270     }
271 
272     if (ANI_OK != env->Object_New(aniClass, personInfoCtor, &aniObject, reinterpret_cast<ani_long>(record.get()))) {
273         LOG_ERROR(UDMF_KITS_NAPI, "Object_New Failed");
274         return aniObject;
275     }
276     return aniObject;
277 }
278 
GetRecords(ani_env * env,ani_object obj)279 static ani_object GetRecords([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object obj)
280 {
281     ani_object arrayObj = nullptr;
282     ani_class arrayCls = nullptr;
283     if (ANI_OK != env->FindClass("Lescompat/Array;", &arrayCls)) {
284         LOG_ERROR(UDMF_KITS_NAPI, "FindClass Lescompat/Array; Failed");
285         return arrayObj;
286     }
287 
288     ani_method arrayCtor;
289     if (ANI_OK != env->Class_FindMethod(arrayCls, "<ctor>", "I:V", &arrayCtor)) {
290         LOG_ERROR(UDMF_KITS_NAPI, "Class_FindMethod <ctor> Failed");
291         return arrayObj;
292     }
293 
294     auto dataHolder = AniObjectUtils::Unwrap<UnifiedDataHolder>(env, obj);
295     if (dataHolder == nullptr) {
296         LOG_ERROR(UDMF_KITS_NAPI, "UnifiedData unwrapp failed");
297         return arrayObj;
298     }
299 
300     auto dataObj = dataHolder->Get();
301     if (dataObj == nullptr) {
302         LOG_ERROR(UDMF_KITS_NAPI, "dataHolder get empty...");
303         return arrayObj;
304     }
305 
306     std::vector<std::shared_ptr<UnifiedRecord>> records = dataObj->GetRecords();
307     if (ANI_OK != env->Object_New(arrayCls, arrayCtor, &arrayObj, records.size())) {
308         LOG_ERROR(UDMF_KITS_NAPI, "Object_New Array Faild");
309         return arrayObj;
310     }
311 
312     ani_size index = 0;
313     for (const std::shared_ptr<UnifiedRecord> &recordPtr : records) {
314         auto aniRecord = UnifiedRecordToObject(env, recordPtr);
315         if (ANI_OK != env->Object_CallMethodByName_Void(arrayObj, "$_set", "ILstd/core/Object;:V", index, aniRecord)) {
316             LOG_ERROR(UDMF_KITS_NAPI, "Object_CallMethodByName_Void  $_set Faild");
317             break;
318         }
319         index++;
320     }
321 
322     LOG_DEBUG(UDMF_KITS_NAPI, "getRecords index:%{public}u", static_cast<uint32_t>(index));
323     return arrayObj;
324 }
325 
BindCleanerclassMethods(ani_env * env,ani_namespace & ns)326 static ani_status BindCleanerclassMethods(ani_env *env, ani_namespace &ns)
327 {
328     auto cleanerCls = AniTypeFinder(env).FindClass(ns, "LCleaner;");
329     return NativePtrCleaner(env).Bind(cleanerCls.value());
330 }
331 
LoadUnifiedRecord(ani_env * env,ani_namespace & ns)332 static ani_status LoadUnifiedRecord(ani_env *env, ani_namespace &ns)
333 {
334     if (env == nullptr) {
335         LOG_ERROR(UDMF_KITS_NAPI, "env is nullptr");
336         return ANI_ERROR;
337     }
338     static const char *recordclsName = "LUnifiedRecord;";
339     ani_class unifiedRecordClass;
340     if (ANI_OK != env->Namespace_FindClass(ns, recordclsName, &unifiedRecordClass)) {
341         LOG_ERROR(UDMF_KITS_NAPI, "Not found class %{public}s", recordclsName);
342         return ANI_NOT_FOUND;
343     }
344 
345     std::array methods = {
346         ani_native_function {"init", nullptr, reinterpret_cast<void *>(UnifiedRecodeValueTypeConstructor)},
347         ani_native_function {"initRecordWithOutTypeValue", nullptr, reinterpret_cast<void *>(UnifiedRecodeConstructor)},
348     };
349 
350     if (ANI_OK != env->Class_BindNativeMethods(unifiedRecordClass, methods.data(), methods.size())) {
351         LOG_ERROR(UDMF_KITS_NAPI, "Cannot bind native methods to %{public}s", recordclsName);
352         return ANI_ERROR;
353     }
354     return ANI_OK;
355 }
356 
LoadUnifiedData(ani_env * env,ani_namespace & ns)357 static ani_status LoadUnifiedData(ani_env *env, ani_namespace &ns)
358 {
359     if (env == nullptr) {
360         LOG_ERROR(UDMF_KITS_NAPI, "env is nullptr");
361         return ANI_ERROR;
362     }
363     static const char *dataclsName = "LUnifiedData;";
364     ani_class unifiedDataClass;
365     if (ANI_OK != env->Namespace_FindClass(ns, dataclsName, &unifiedDataClass)) {
366         LOG_ERROR(UDMF_KITS_NAPI, "Cannot find class %{public}s", dataclsName);
367         return ANI_NOT_FOUND;
368     }
369 
370     std::array datamethods = {
371         ani_native_function {"initData", nullptr, reinterpret_cast<void *>(UnifiedDataConstructor)},
372         ani_native_function {"initDataWithOutRecord", nullptr,
373             reinterpret_cast<void *>(initDataWithOutRecordConstructor)},
374         ani_native_function {"getRecords", nullptr, reinterpret_cast<void *>(GetRecords)},
375     };
376 
377     if (ANI_OK != env->Class_BindNativeMethods(unifiedDataClass, datamethods.data(), datamethods.size())) {
378         LOG_ERROR(UDMF_KITS_NAPI, "Cannot bind native methods to %{public}s", dataclsName);
379         return ANI_ERROR;
380     }
381     return ANI_OK;
382 }
383 
ANI_Constructor(ani_vm * vm,uint32_t * result)384 ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
385 {
386     LOG_DEBUG(UDMF_KITS_NAPI, "ANI_Constructor start...");
387 
388     ani_env *env;
389     if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) {
390         LOG_ERROR(UDMF_KITS_NAPI, "[ANI] Unsupported ANI_VERSION_1");
391         return ANI_ERROR;
392     }
393 
394     static const char *nameSpaceName = "L@ohos/data/unifiedDataChannel/unifiedDataChannel;";
395     ani_namespace ns;
396     if (ANI_OK != env->FindNamespace(nameSpaceName, &ns)) {
397         LOG_ERROR(UDMF_KITS_NAPI, "Not found namespace %{public}s", nameSpaceName);
398         return ANI_NOT_FOUND;
399     }
400 
401     if (ANI_OK != LoadUnifiedRecord(env, ns)) {
402         LOG_ERROR(UDMF_KITS_NAPI, "LoadUnifiedRecord ERROR");
403         return ANI_NOT_FOUND;
404     }
405 
406     if (ANI_OK != LoadUnifiedData(env, ns)) {
407         LOG_ERROR(UDMF_KITS_NAPI, "LoadUnifiedData ERROR");
408         return ANI_NOT_FOUND;
409     }
410 
411     if (result == nullptr) {
412         LOG_ERROR(UDMF_KITS_NAPI, "param result is null");
413         return ANI_ERROR;
414     }
415 
416     if (ANI_OK != BindCleanerclassMethods(env, ns)) {
417         LOG_ERROR(UDMF_KITS_NAPI, "[ANI] BindCleanerclassMethods failed");
418         return ANI_ERROR;
419     }
420     *result = ANI_VERSION_1;
421     LOG_DEBUG(UDMF_KITS_NAPI, "ANI_Constructor end...");
422     return ANI_OK;
423 }
424