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