1 /*
2 * Copyright (C) 2021-2023 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 #include "userfile_manager_types.h"
16 #define MLOG_TAG "FileAssetNapi"
17
18 #include "file_asset_napi.h"
19
20 #include <algorithm>
21 #include <cstring>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <sys/stat.h>
25
26 #include "abs_shared_result_set.h"
27 #include "access_token.h"
28 #include "accesstoken_kit.h"
29 #include "datashare_errno.h"
30 #include "datashare_predicates.h"
31 #include "datashare_result_set.h"
32 #include "datashare_values_bucket.h"
33 #include "hitrace_meter.h"
34 #include "fetch_result.h"
35 #include "file_uri.h"
36 #include "hilog/log.h"
37 #include "ipc_skeleton.h"
38 #include "iservice_registry.h"
39 #include "js_native_api.h"
40 #include "js_native_api_types.h"
41 #include "location_column.h"
42 #include "locale_config.h"
43 #include "media_asset_edit_data_napi.h"
44 #include "media_exif.h"
45 #include "media_column.h"
46 #include "media_file_utils.h"
47 #include "media_file_uri.h"
48 #include "media_smart_map_column.h"
49 #include "medialibrary_client_errno.h"
50 #include "medialibrary_db_const.h"
51 #include "medialibrary_errno.h"
52 #include "medialibrary_napi_log.h"
53 #include "medialibrary_napi_utils.h"
54 #include "medialibrary_tracer.h"
55 #include "nlohmann/json.hpp"
56 #include "post_proc.h"
57 #include "rdb_errno.h"
58 #include "sandbox_helper.h"
59 #include "string_ex.h"
60 #include "thumbnail_const.h"
61 #include "thumbnail_utils.h"
62 #include "unique_fd.h"
63 #include "userfile_client.h"
64 #include "userfilemgr_uri.h"
65 #include "vision_aesthetics_score_column.h"
66 #include "vision_album_column.h"
67 #include "vision_column_comm.h"
68 #include "vision_column.h"
69 #include "vision_composition_column.h"
70 #include "vision_face_tag_column.h"
71 #include "vision_head_column.h"
72 #include "vision_image_face_column.h"
73 #include "vision_label_column.h"
74 #include "vision_object_column.h"
75 #include "vision_ocr_column.h"
76 #include "vision_photo_map_column.h"
77 #include "vision_pose_column.h"
78 #include "vision_recommendation_column.h"
79 #include "vision_saliency_detect_column.h"
80 #include "vision_segmentation_column.h"
81 #include "vision_total_column.h"
82 #include "vision_video_label_column.h"
83 #include "vision_multi_crop_column.h"
84
85 using OHOS::HiviewDFX::HiLog;
86 using OHOS::HiviewDFX::HiLogLabel;
87 using namespace std;
88 using namespace OHOS::AppExecFwk;
89 using namespace OHOS::NativeRdb;
90 using namespace OHOS::DataShare;
91 using namespace OHOS::Security::AccessToken;
92 using std::string;
93
94 namespace OHOS {
95 namespace Media {
96 static const std::string MEDIA_FILEDESCRIPTOR = "fd";
97 static const std::string MEDIA_FILEMODE = "mode";
98 static const std::string ANALYSIS_NO_RESULTS = "[]";
99 static const std::string ANALYSIS_INIT_VALUE = "0";
100 static const std::string ANALYSIS_STATUS_ANALYZED = "Analyzed, no results";
101
102 const std::string LANGUAGE_ZH = "zh-Hans";
103 const std::string LANGUAGE_EN = "en-Latn-US";
104
105 std::mutex FileAssetNapi::mutex_;
106
107 thread_local napi_ref FileAssetNapi::sConstructor_ = nullptr;
108 thread_local std::shared_ptr<FileAsset> FileAssetNapi::sFileAsset_ = nullptr;
109 shared_ptr<ThumbnailManager> FileAssetNapi::thumbnailManager_ = nullptr;
110
111 constexpr int32_t IS_TRASH = 1;
112 constexpr int32_t NOT_TRASH = 0;
113
114 constexpr int32_t IS_FAV = 1;
115 constexpr int32_t NOT_FAV = 0;
116
117 constexpr int32_t IS_HIDDEN = 1;
118 constexpr int32_t NOT_HIDDEN = 0;
119
120 constexpr int32_t USER_COMMENT_MAX_LEN = 420;
121 constexpr int64_t SECONDS_LEVEL_LIMIT = 1e10;
122
123 using CompleteCallback = napi_async_complete_callback;
124
125 thread_local napi_ref FileAssetNapi::userFileMgrConstructor_ = nullptr;
126 thread_local napi_ref FileAssetNapi::photoAccessHelperConstructor_ = nullptr;
127
128 class TransferFileAsset {
129 public:
130 std::shared_ptr<FileAsset> fileAsset = nullptr;
131 ~TransferFileAsset() = default;
132 };
133
FileAssetNapi()134 FileAssetNapi::FileAssetNapi()
135 : env_(nullptr) {}
136
137 FileAssetNapi::~FileAssetNapi() = default;
138
FileAssetNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)139 void FileAssetNapi::FileAssetNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
140 {
141 FileAssetNapi *fileAssetObj = reinterpret_cast<FileAssetNapi*>(nativeObject);
142 if (fileAssetObj != nullptr) {
143 lock_guard<mutex> lockGuard(mutex_);
144 delete fileAssetObj;
145 fileAssetObj = nullptr;
146 }
147 }
148
GetExports(napi_env & env,napi_value & exports,napi_property_descriptor * file_asset_props,int32_t fileAssetPropsSize)149 napi_value FileAssetNapi::GetExports(napi_env &env, napi_value &exports, napi_property_descriptor *file_asset_props,
150 int32_t fileAssetPropsSize)
151 {
152 napi_status status;
153 napi_value ctorObj;
154 int32_t refCount = 1;
155 status = napi_define_class(env, FILE_ASSET_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, FileAssetNapiConstructor,
156 nullptr, fileAssetPropsSize, file_asset_props, &ctorObj);
157 if (status == napi_ok) {
158 status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
159 if (status == napi_ok) {
160 status = napi_set_named_property(env, exports, FILE_ASSET_NAPI_CLASS_NAME.c_str(), ctorObj);
161 if (status == napi_ok) {
162 return exports;
163 }
164 }
165 }
166 return nullptr;
167 }
168
Init(napi_env env,napi_value exports)169 napi_value FileAssetNapi::Init(napi_env env, napi_value exports)
170 {
171 napi_property_descriptor file_asset_props[] = {
172 DECLARE_NAPI_GETTER("id", JSGetFileId),
173 DECLARE_NAPI_GETTER("uri", JSGetFileUri),
174 DECLARE_NAPI_GETTER("mediaType", JSGetMediaType),
175 DECLARE_NAPI_GETTER_SETTER("displayName", JSGetFileDisplayName, JSSetFileDisplayName),
176 DECLARE_NAPI_GETTER_SETTER("relativePath", JSGetRelativePath, JSSetRelativePath),
177 DECLARE_NAPI_GETTER("parent", JSParent),
178 DECLARE_NAPI_GETTER("size", JSGetSize),
179 DECLARE_NAPI_GETTER("dateAdded", JSGetDateAdded),
180 DECLARE_NAPI_GETTER("dateTrashed", JSGetDateTrashed),
181 DECLARE_NAPI_GETTER("dateModified", JSGetDateModified),
182 DECLARE_NAPI_GETTER("dateTaken", JSGetDateTaken),
183 DECLARE_NAPI_GETTER("mimeType", JSGetMimeType),
184 DECLARE_NAPI_GETTER_SETTER("title", JSGetTitle, JSSetTitle),
185 DECLARE_NAPI_GETTER("artist", JSGetArtist),
186 DECLARE_NAPI_GETTER("audioAlbum", JSGetAlbum),
187 DECLARE_NAPI_GETTER("width", JSGetWidth),
188 DECLARE_NAPI_GETTER("height", JSGetHeight),
189 DECLARE_NAPI_GETTER_SETTER("orientation", JSGetOrientation, JSSetOrientation),
190 DECLARE_NAPI_GETTER("duration", JSGetDuration),
191 DECLARE_NAPI_GETTER("albumId", JSGetAlbumId),
192 DECLARE_NAPI_GETTER("albumUri", JSGetAlbumUri),
193 DECLARE_NAPI_GETTER("albumName", JSGetAlbumName),
194 DECLARE_NAPI_GETTER("count", JSGetCount),
195 DECLARE_NAPI_FUNCTION("isDirectory", JSIsDirectory),
196 DECLARE_NAPI_FUNCTION("commitModify", JSCommitModify),
197 DECLARE_NAPI_FUNCTION("open", JSOpen),
198 DECLARE_NAPI_FUNCTION("close", JSClose),
199 DECLARE_NAPI_FUNCTION("getThumbnail", JSGetThumbnail),
200 DECLARE_NAPI_FUNCTION("favorite", JSFavorite),
201 DECLARE_NAPI_FUNCTION("isFavorite", JSIsFavorite),
202 DECLARE_NAPI_FUNCTION("trash", JSTrash),
203 DECLARE_NAPI_FUNCTION("isTrash", JSIsTrash),
204 };
205 int32_t fileAssetPropsSize = sizeof(file_asset_props) / sizeof(file_asset_props[PARAM0]);
206 napi_value exportsValue = GetExports(env, exports, file_asset_props, fileAssetPropsSize);
207 if (exportsValue != nullptr) {
208 return exportsValue;
209 }
210 return nullptr;
211 }
212
UserFileMgrInit(napi_env env,napi_value exports)213 napi_value FileAssetNapi::UserFileMgrInit(napi_env env, napi_value exports)
214 {
215 NapiClassInfo info = {
216 .name = USERFILEMGR_FILEASSET_NAPI_CLASS_NAME,
217 .ref = &userFileMgrConstructor_,
218 .constructor = FileAssetNapiConstructor,
219 .props = {
220 DECLARE_NAPI_FUNCTION("get", UserFileMgrGet),
221 DECLARE_NAPI_FUNCTION("set", UserFileMgrSet),
222 DECLARE_NAPI_FUNCTION("open", UserFileMgrOpen),
223 DECLARE_NAPI_FUNCTION("close", UserFileMgrClose),
224 DECLARE_NAPI_FUNCTION("commitModify", UserFileMgrCommitModify),
225 DECLARE_NAPI_FUNCTION("favorite", UserFileMgrFavorite),
226 DECLARE_NAPI_GETTER("uri", JSGetFileUri),
227 DECLARE_NAPI_GETTER("fileType", JSGetMediaType),
228 DECLARE_NAPI_GETTER_SETTER("displayName", JSGetFileDisplayName, JSSetFileDisplayName),
229 DECLARE_NAPI_FUNCTION("getThumbnail", UserFileMgrGetThumbnail),
230 DECLARE_NAPI_FUNCTION("getReadOnlyFd", JSGetReadOnlyFd),
231 DECLARE_NAPI_FUNCTION("setHidden", UserFileMgrSetHidden),
232 DECLARE_NAPI_FUNCTION("setPending", UserFileMgrSetPending),
233 DECLARE_NAPI_FUNCTION("getExif", JSGetExif),
234 DECLARE_NAPI_FUNCTION("setUserComment", UserFileMgrSetUserComment),
235 DECLARE_NAPI_GETTER("count", JSGetCount),
236 DECLARE_NAPI_FUNCTION("getJson", UserFileMgrGetJson),
237 }
238 };
239 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
240
241 return exports;
242 }
243
PhotoAccessHelperInit(napi_env env,napi_value exports)244 napi_value FileAssetNapi::PhotoAccessHelperInit(napi_env env, napi_value exports)
245 {
246 NapiClassInfo info = {
247 .name = PHOTOACCESSHELPER_FILEASSET_NAPI_CLASS_NAME,
248 .ref = &photoAccessHelperConstructor_,
249 .constructor = FileAssetNapiConstructor,
250 .props = {
251 DECLARE_NAPI_FUNCTION("get", UserFileMgrGet),
252 DECLARE_NAPI_FUNCTION("set", UserFileMgrSet),
253 DECLARE_NAPI_FUNCTION("open", PhotoAccessHelperOpen),
254 DECLARE_NAPI_FUNCTION("close", PhotoAccessHelperClose),
255 DECLARE_NAPI_FUNCTION("clone", PhotoAccessHelperCloneAsset),
256 DECLARE_NAPI_FUNCTION("commitModify", PhotoAccessHelperCommitModify),
257 DECLARE_NAPI_FUNCTION("setFavorite", PhotoAccessHelperFavorite),
258 DECLARE_NAPI_GETTER("uri", JSGetFileUri),
259 DECLARE_NAPI_GETTER("photoType", JSGetMediaType),
260 DECLARE_NAPI_GETTER_SETTER("displayName", JSGetFileDisplayName, JSSetFileDisplayName),
261 DECLARE_NAPI_FUNCTION("getThumbnail", PhotoAccessHelperGetThumbnail),
262 DECLARE_NAPI_FUNCTION("getThumbnailData", PhotoAccessHelperGetThumbnailData),
263 DECLARE_NAPI_FUNCTION("getKeyFrameThumbnail", PhotoAccessHelperGetKeyFrameThumbnail),
264 DECLARE_NAPI_FUNCTION("getReadOnlyFd", JSGetReadOnlyFd),
265 DECLARE_NAPI_FUNCTION("setHidden", PhotoAccessHelperSetHidden),
266 DECLARE_NAPI_FUNCTION("setPending", PhotoAccessHelperSetPending),
267 DECLARE_NAPI_FUNCTION("getExif", JSGetExif),
268 DECLARE_NAPI_FUNCTION("setUserComment", PhotoAccessHelperSetUserComment),
269 DECLARE_NAPI_FUNCTION("requestPhoto", PhotoAccessHelperRequestPhoto),
270 DECLARE_NAPI_FUNCTION("cancelPhotoRequest", PhotoAccessHelperCancelPhotoRequest),
271 DECLARE_NAPI_FUNCTION("isEdited", PhotoAccessHelperIsEdited),
272 DECLARE_NAPI_FUNCTION("requestEditData", PhotoAccessHelperRequestEditData),
273 DECLARE_NAPI_FUNCTION("requestSource", PhotoAccessHelperRequestSource),
274 DECLARE_NAPI_FUNCTION("commitEditedAsset", PhotoAccessHelperCommitEditedAsset),
275 DECLARE_NAPI_FUNCTION("revertToOriginal", PhotoAccessHelperRevertToOriginal),
276 DECLARE_NAPI_FUNCTION("getAnalysisData", PhotoAccessHelperGetAnalysisData),
277 DECLARE_NAPI_FUNCTION("getEditData", PhotoAccessHelperGetEditData),
278 }
279 };
280 MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
281 return exports;
282 }
283
DetachFileAssetFunc(napi_env env,void * value,void *)284 inline void *DetachFileAssetFunc(napi_env env, void *value, void *)
285 {
286 if (value == nullptr) {
287 NAPI_ERR_LOG("detach value is null");
288 return nullptr;
289 }
290 auto fileAssetNapi = reinterpret_cast<FileAssetNapi*>(value);
291 std::shared_ptr<FileAsset> detachFileAsset = fileAssetNapi->GetFileAssetInstance();
292 TransferFileAsset *transferFileAsset = new TransferFileAsset();
293 transferFileAsset->fileAsset = detachFileAsset;
294 return transferFileAsset;
295 }
296
AttachFileAssetFunc(napi_env env,void * value,void *)297 napi_value AttachFileAssetFunc(napi_env env, void *value, void *)
298 {
299 if (value == nullptr) {
300 NAPI_ERR_LOG("attach value is null");
301 return nullptr;
302 }
303 auto transferFileAsset = reinterpret_cast<TransferFileAsset*>(value);
304 std::shared_ptr<FileAsset> fileAsset = std::move(transferFileAsset->fileAsset);
305 if (!transferFileAsset) {
306 delete transferFileAsset;
307 }
308 NAPI_ASSERT(env, fileAsset != nullptr, "AttachFileAssetFunc fileAsset is null");
309 napi_value result = FileAssetNapi::AttachCreateFileAsset(env, fileAsset);
310 NAPI_ASSERT(env, result != nullptr, "AttachFileAssetFunc result is null");
311 return result;
312 }
313
314 // Constructor callback
FileAssetNapiConstructor(napi_env env,napi_callback_info info)315 napi_value FileAssetNapi::FileAssetNapiConstructor(napi_env env, napi_callback_info info)
316 {
317 napi_status status;
318 napi_value result = nullptr;
319 napi_value thisVar = nullptr;
320
321 napi_get_undefined(env, &result);
322 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
323 if (status == napi_ok && thisVar != nullptr) {
324 std::unique_ptr<FileAssetNapi> obj = std::make_unique<FileAssetNapi>();
325 if (obj != nullptr) {
326 obj->env_ = env;
327 if (sFileAsset_ != nullptr) {
328 obj->UpdateFileAssetInfo();
329 }
330 napi_coerce_to_native_binding_object(
331 env, thisVar, DetachFileAssetFunc, AttachFileAssetFunc, obj.get(), nullptr);
332 status = napi_wrap_async_finalizer(env, thisVar, reinterpret_cast<void *>(obj.get()),
333 FileAssetNapi::FileAssetNapiDestructor, nullptr, nullptr, 0);
334 if (status == napi_ok) {
335 obj.release();
336 return thisVar;
337 } else {
338 NAPI_ERR_LOG("Failure wrapping js to native napi, status: %{public}d", status);
339 }
340 }
341 }
342
343 return result;
344 }
345
AttachCreateFileAsset(napi_env env,std::shared_ptr<FileAsset> & iAsset)346 napi_value FileAssetNapi::AttachCreateFileAsset(napi_env env, std::shared_ptr<FileAsset> &iAsset)
347 {
348 if (iAsset == nullptr) {
349 return nullptr;
350 }
351 napi_value constructor = nullptr;
352 napi_ref constructorRef = nullptr;
353 napi_value exports = nullptr;
354 if (iAsset->GetResultNapiType() == ResultNapiType::TYPE_USERFILE_MGR) {
355 if (userFileMgrConstructor_ == nullptr) {
356 NAPI_INFO_LOG("AttachCreateFileAsset userFileMgrConstructor_ is null");
357 napi_create_object(env, &exports);
358 FileAssetNapi::UserFileMgrInit(env, exports);
359 }
360 constructorRef = userFileMgrConstructor_;
361 } else if (iAsset->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
362 if (photoAccessHelperConstructor_ == nullptr) {
363 NAPI_INFO_LOG("AttachCreateFileAsset photoAccessHelperConstructor_ is null");
364 napi_create_object(env, &exports);
365 FileAssetNapi::PhotoAccessHelperInit(env, exports);
366 }
367 constructorRef = photoAccessHelperConstructor_;
368 }
369 if (constructorRef == nullptr) {
370 NAPI_ASSERT(env, false, "AttachCreateFileAsset constructorRef is null");
371 }
372 napi_status status = napi_get_reference_value(env, constructorRef, &constructor);
373 NAPI_ASSERT(env, status == napi_ok, "AttachCreateFileAsset napi_get_reference_value failed");
374 sFileAsset_ = iAsset;
375 napi_value result = nullptr;
376 status = napi_new_instance(env, constructor, 0, nullptr, &result);
377 NAPI_ASSERT(env, status == napi_ok, "AttachCreateFileAsset napi_new_instance failed");
378 sFileAsset_ = nullptr;
379 return result;
380 }
381
382
CreateFileAsset(napi_env env,unique_ptr<FileAsset> & iAsset)383 napi_value FileAssetNapi::CreateFileAsset(napi_env env, unique_ptr<FileAsset> &iAsset)
384 {
385 if (iAsset == nullptr) {
386 return nullptr;
387 }
388
389 napi_value constructor = nullptr;
390 napi_ref constructorRef;
391 if (iAsset->GetResultNapiType() == ResultNapiType::TYPE_USERFILE_MGR) {
392 constructorRef = userFileMgrConstructor_;
393 } else if (iAsset->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
394 constructorRef = photoAccessHelperConstructor_;
395 } else {
396 constructorRef = sConstructor_;
397 }
398
399 NAPI_CALL(env, napi_get_reference_value(env, constructorRef, &constructor));
400
401 sFileAsset_ = std::move(iAsset);
402 napi_value result = nullptr;
403 NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result));
404
405 sFileAsset_ = nullptr;
406 return result;
407 }
408
CreatePhotoAsset(napi_env env,shared_ptr<FileAsset> & fileAsset)409 napi_value FileAssetNapi::CreatePhotoAsset(napi_env env, shared_ptr<FileAsset> &fileAsset)
410 {
411 if (fileAsset == nullptr || fileAsset->GetResultNapiType() != ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
412 NAPI_ERR_LOG("Unsupported fileAsset");
413 return nullptr;
414 }
415
416 if (photoAccessHelperConstructor_ == nullptr) {
417 napi_value exports = nullptr;
418 napi_create_object(env, &exports);
419 FileAssetNapi::PhotoAccessHelperInit(env, exports);
420 }
421
422 napi_value constructor = nullptr;
423 napi_value result = nullptr;
424 NAPI_CALL(env, napi_get_reference_value(env, photoAccessHelperConstructor_, &constructor));
425 NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result));
426 CHECK_COND(env, result != nullptr, JS_INNER_FAIL);
427
428 FileAssetNapi* fileAssetNapi = nullptr;
429 CHECK_ARGS(env, napi_unwrap(env, result, reinterpret_cast<void**>(&fileAssetNapi)), JS_INNER_FAIL);
430 CHECK_COND(env, fileAssetNapi != nullptr, JS_INNER_FAIL);
431 fileAssetNapi->fileAssetPtr = fileAsset;
432 return result;
433 }
434
GetFileDisplayName() const435 std::string FileAssetNapi::GetFileDisplayName() const
436 {
437 return fileAssetPtr->GetDisplayName();
438 }
439
GetRelativePath() const440 std::string FileAssetNapi::GetRelativePath() const
441 {
442 return fileAssetPtr->GetRelativePath();
443 }
444
GetFilePath() const445 std::string FileAssetNapi::GetFilePath() const
446 {
447 return fileAssetPtr->GetPath();
448 }
449
GetTitle() const450 std::string FileAssetNapi::GetTitle() const
451 {
452 return fileAssetPtr->GetTitle();
453 }
454
GetFileUri() const455 std::string FileAssetNapi::GetFileUri() const
456 {
457 return fileAssetPtr->GetUri();
458 }
459
GetFileId() const460 int32_t FileAssetNapi::GetFileId() const
461 {
462 return fileAssetPtr->GetId();
463 }
464
GetUserId() const465 int32_t FileAssetNapi::GetUserId() const
466 {
467 return fileAssetPtr->GetUserId();
468 }
469
GetMediaType() const470 Media::MediaType FileAssetNapi::GetMediaType() const
471 {
472 return fileAssetPtr->GetMediaType();
473 }
474
GetOrientation() const475 int32_t FileAssetNapi::GetOrientation() const
476 {
477 return fileAssetPtr->GetOrientation();
478 }
479
GetNetworkId() const480 const std::string FileAssetNapi::GetNetworkId() const
481 {
482 return MediaFileUtils::GetNetworkIdFromUri(GetFileUri());
483 }
484
IsFavorite() const485 bool FileAssetNapi::IsFavorite() const
486 {
487 return fileAssetPtr->IsFavorite();
488 }
489
SetFavorite(bool isFavorite)490 void FileAssetNapi::SetFavorite(bool isFavorite)
491 {
492 fileAssetPtr->SetFavorite(isFavorite);
493 }
494
IsTrash() const495 bool FileAssetNapi::IsTrash() const
496 {
497 return (fileAssetPtr->GetIsTrash() != NOT_TRASH);
498 }
499
SetTrash(bool isTrash)500 void FileAssetNapi::SetTrash(bool isTrash)
501 {
502 int32_t trashFlag = (isTrash ? IS_TRASH : NOT_TRASH);
503 fileAssetPtr->SetIsTrash(trashFlag);
504 }
505
IsHidden() const506 bool FileAssetNapi::IsHidden() const
507 {
508 return fileAssetPtr->IsHidden();
509 }
510
SetHidden(bool isHidden)511 void FileAssetNapi::SetHidden(bool isHidden)
512 {
513 fileAssetPtr->SetHidden(isHidden);
514 }
515
GetAllExif() const516 std::string FileAssetNapi::GetAllExif() const
517 {
518 return fileAssetPtr->GetAllExif();
519 }
520
GetFrontCamera() const521 std::string FileAssetNapi::GetFrontCamera() const
522 {
523 return fileAssetPtr->GetFrontCamera();
524 }
525
GetUserComment() const526 std::string FileAssetNapi::GetUserComment() const
527 {
528 return fileAssetPtr->GetUserComment();
529 }
530
GetNapiObject(napi_env env,napi_callback_info info,FileAssetNapi ** obj)531 napi_status GetNapiObject(napi_env env, napi_callback_info info, FileAssetNapi **obj)
532 {
533 napi_value thisVar = nullptr;
534 CHECK_STATUS_RET(napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), "Failed to get cb info");
535 CHECK_STATUS_RET(napi_unwrap(env, thisVar, reinterpret_cast<void **>(obj)), "Failed to unwrap thisVar");
536 CHECK_COND_RET(*obj != nullptr, napi_invalid_arg, "Failed to get napi object!");
537 return napi_ok;
538 }
539
JSGetFileId(napi_env env,napi_callback_info info)540 napi_value FileAssetNapi::JSGetFileId(napi_env env, napi_callback_info info)
541 {
542 napi_status status;
543 napi_value jsResult = nullptr;
544 FileAssetNapi *obj = nullptr;
545 int32_t id;
546 napi_value thisVar = nullptr;
547
548 napi_get_undefined(env, &jsResult);
549 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
550 if (status != napi_ok || thisVar == nullptr) {
551 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
552 return jsResult;
553 }
554
555 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
556 if (status == napi_ok && obj != nullptr) {
557 id = obj->GetFileId();
558 #ifdef MEDIALIBRARY_COMPATIBILITY
559 int64_t virtualId = 0;
560 if (MediaFileUtils::IsFileTablePath(obj->GetFilePath())) {
561 virtualId = MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_FILE);
562 } else {
563 virtualId = MediaFileUtils::GetVirtualIdByType(id, obj->GetMediaType());
564 }
565 napi_create_int64(env, virtualId, &jsResult);
566 #else
567 napi_create_int32(env, id, &jsResult);
568 #endif
569 }
570
571 return jsResult;
572 }
573
JSGetFileUri(napi_env env,napi_callback_info info)574 napi_value FileAssetNapi::JSGetFileUri(napi_env env, napi_callback_info info)
575 {
576 FileAssetNapi *obj = nullptr;
577 CHECK_ARGS(env, GetNapiObject(env, info, &obj), JS_INNER_FAIL);
578
579 napi_value jsResult = nullptr;
580 CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetFileUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
581 JS_INNER_FAIL);
582 return jsResult;
583 }
584
JSGetFilePath(napi_env env,napi_callback_info info)585 napi_value FileAssetNapi::JSGetFilePath(napi_env env, napi_callback_info info)
586 {
587 napi_status status;
588 napi_value jsResult = nullptr;
589 FileAssetNapi *obj = nullptr;
590 string path = "";
591 napi_value thisVar = nullptr;
592
593 napi_get_undefined(env, &jsResult);
594 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
595 if (status != napi_ok || thisVar == nullptr) {
596 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
597 return jsResult;
598 }
599
600 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
601 if (status == napi_ok && obj != nullptr) {
602 path = obj->GetFilePath();
603 napi_create_string_utf8(env, path.c_str(), NAPI_AUTO_LENGTH, &jsResult);
604 }
605
606 return jsResult;
607 }
608
JSGetFileDisplayName(napi_env env,napi_callback_info info)609 napi_value FileAssetNapi::JSGetFileDisplayName(napi_env env, napi_callback_info info)
610 {
611 napi_status status;
612 napi_value jsResult = nullptr;
613 FileAssetNapi *obj = nullptr;
614 string displayName = "";
615 napi_value thisVar = nullptr;
616
617 napi_get_undefined(env, &jsResult);
618 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
619 if (status != napi_ok || thisVar == nullptr) {
620 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
621 return jsResult;
622 }
623
624 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
625 if (status == napi_ok && obj != nullptr) {
626 displayName = obj->GetFileDisplayName();
627 napi_create_string_utf8(env, displayName.c_str(), NAPI_AUTO_LENGTH, &jsResult);
628 }
629
630 return jsResult;
631 }
632
JSSetFileDisplayName(napi_env env,napi_callback_info info)633 napi_value FileAssetNapi::JSSetFileDisplayName(napi_env env, napi_callback_info info)
634 {
635 napi_status status;
636 napi_value undefinedResult = nullptr;
637 FileAssetNapi *obj = nullptr;
638 napi_valuetype valueType = napi_undefined;
639 size_t res = 0;
640 char buffer[FILENAME_MAX];
641 size_t argc = ARGS_ONE;
642 napi_value argv[ARGS_ONE] = {0};
643 napi_value thisVar = nullptr;
644
645 napi_get_undefined(env, &undefinedResult);
646
647 GET_JS_ARGS(env, info, argc, argv, thisVar);
648 NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
649
650 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
651 if (status == napi_ok && obj != nullptr) {
652 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
653 NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
654 return undefinedResult;
655 }
656 status = napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res);
657 if (status == napi_ok) {
658 string displayName = string(buffer);
659 obj->fileAssetPtr->SetDisplayName(displayName);
660 #ifdef MEDIALIBRARY_COMPATIBILITY
661 obj->fileAssetPtr->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
662 #endif
663 }
664 }
665
666 return undefinedResult;
667 }
668
JSGetMimeType(napi_env env,napi_callback_info info)669 napi_value FileAssetNapi::JSGetMimeType(napi_env env, napi_callback_info info)
670 {
671 napi_status status;
672 napi_value jsResult = nullptr;
673 FileAssetNapi *obj = nullptr;
674 string mimeType = "";
675 napi_value thisVar = nullptr;
676
677 napi_get_undefined(env, &jsResult);
678 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
679 if (status != napi_ok || thisVar == nullptr) {
680 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
681 return jsResult;
682 }
683
684 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
685 if (status == napi_ok && obj != nullptr) {
686 mimeType = obj->fileAssetPtr->GetMimeType();
687 napi_create_string_utf8(env, mimeType.c_str(), NAPI_AUTO_LENGTH, &jsResult);
688 }
689
690 return jsResult;
691 }
692
JSGetMediaType(napi_env env,napi_callback_info info)693 napi_value FileAssetNapi::JSGetMediaType(napi_env env, napi_callback_info info)
694 {
695 napi_status status;
696 napi_value jsResult = nullptr;
697 FileAssetNapi *obj = nullptr;
698 int32_t mediaType;
699 napi_value thisVar = nullptr;
700
701 napi_get_undefined(env, &jsResult);
702 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
703 if (status != napi_ok || thisVar == nullptr) {
704 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
705 return jsResult;
706 }
707
708 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
709 if (status == napi_ok && obj != nullptr) {
710 mediaType = static_cast<int32_t>(obj->GetMediaType());
711 napi_create_int32(env, mediaType, &jsResult);
712 }
713
714 return jsResult;
715 }
716
JSGetTitle(napi_env env,napi_callback_info info)717 napi_value FileAssetNapi::JSGetTitle(napi_env env, napi_callback_info info)
718 {
719 napi_status status;
720 napi_value jsResult = nullptr;
721 FileAssetNapi *obj = nullptr;
722 string title = "";
723 napi_value thisVar = nullptr;
724
725 napi_get_undefined(env, &jsResult);
726 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
727 if (status != napi_ok || thisVar == nullptr) {
728 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
729 return jsResult;
730 }
731
732 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
733 if (status == napi_ok && obj != nullptr) {
734 title = obj->GetTitle();
735 napi_create_string_utf8(env, title.c_str(), NAPI_AUTO_LENGTH, &jsResult);
736 }
737
738 return jsResult;
739 }
JSSetTitle(napi_env env,napi_callback_info info)740 napi_value FileAssetNapi::JSSetTitle(napi_env env, napi_callback_info info)
741 {
742 napi_status status;
743 napi_value undefinedResult = nullptr;
744 FileAssetNapi *obj = nullptr;
745 napi_valuetype valueType = napi_undefined;
746 size_t res = 0;
747 char buffer[FILENAME_MAX];
748 size_t argc = ARGS_ONE;
749 napi_value argv[ARGS_ONE] = {0};
750 napi_value thisVar = nullptr;
751 napi_get_undefined(env, &undefinedResult);
752 GET_JS_ARGS(env, info, argc, argv, thisVar);
753 NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
754 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
755 if (status == napi_ok && obj != nullptr) {
756 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
757 NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
758 return undefinedResult;
759 }
760 status = napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res);
761 if (status == napi_ok) {
762 string title = string(buffer);
763 obj->fileAssetPtr->SetTitle(title);
764 #ifdef MEDIALIBRARY_COMPATIBILITY
765 string oldDisplayName = obj->fileAssetPtr->GetDisplayName();
766 string ext = MediaFileUtils::SplitByChar(oldDisplayName, '.');
767 string newDisplayName = title + "." + ext;
768 obj->fileAssetPtr->SetDisplayName(newDisplayName);
769 #endif
770 }
771 }
772 return undefinedResult;
773 }
774
JSGetSize(napi_env env,napi_callback_info info)775 napi_value FileAssetNapi::JSGetSize(napi_env env, napi_callback_info info)
776 {
777 napi_status status;
778 napi_value jsResult = nullptr;
779 FileAssetNapi *obj = nullptr;
780 int64_t size;
781 napi_value thisVar = nullptr;
782
783 napi_get_undefined(env, &jsResult);
784 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
785 if (status != napi_ok || thisVar == nullptr) {
786 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
787 return jsResult;
788 }
789
790 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
791 if (status == napi_ok && obj != nullptr) {
792 size = obj->fileAssetPtr->GetSize();
793 napi_create_int64(env, size, &jsResult);
794 }
795
796 return jsResult;
797 }
798
JSGetAlbumId(napi_env env,napi_callback_info info)799 napi_value FileAssetNapi::JSGetAlbumId(napi_env env, napi_callback_info info)
800 {
801 napi_status status;
802 napi_value jsResult = nullptr;
803 FileAssetNapi *obj = nullptr;
804 int32_t albumId;
805 napi_value thisVar = nullptr;
806
807 napi_get_undefined(env, &jsResult);
808 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
809 if (status != napi_ok || thisVar == nullptr) {
810 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
811 return jsResult;
812 }
813
814 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
815 if (status == napi_ok && obj != nullptr) {
816 albumId = obj->fileAssetPtr->GetAlbumId();
817 napi_create_int32(env, albumId, &jsResult);
818 }
819
820 return jsResult;
821 }
822
JSGetAlbumName(napi_env env,napi_callback_info info)823 napi_value FileAssetNapi::JSGetAlbumName(napi_env env, napi_callback_info info)
824 {
825 napi_status status;
826 napi_value jsResult = nullptr;
827 FileAssetNapi *obj = nullptr;
828 string albumName = "";
829 napi_value thisVar = nullptr;
830
831 napi_get_undefined(env, &jsResult);
832 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
833 if (status != napi_ok || thisVar == nullptr) {
834 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
835 return jsResult;
836 }
837
838 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
839 if (status == napi_ok && obj != nullptr) {
840 albumName = obj->fileAssetPtr->GetAlbumName();
841 napi_create_string_utf8(env, albumName.c_str(), NAPI_AUTO_LENGTH, &jsResult);
842 }
843
844 return jsResult;
845 }
846
JSGetCount(napi_env env,napi_callback_info info)847 napi_value FileAssetNapi::JSGetCount(napi_env env, napi_callback_info info)
848 {
849 napi_status status;
850 napi_value jsResult = nullptr;
851 napi_value thisVar = nullptr;
852
853 napi_get_undefined(env, &jsResult);
854 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
855 if ((status != napi_ok) || (thisVar == nullptr)) {
856 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
857 return jsResult;
858 }
859
860 FileAssetNapi *obj = nullptr;
861 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
862 if ((status == napi_ok) && (obj != nullptr)) {
863 napi_create_int32(env, obj->fileAssetPtr->GetCount(), &jsResult);
864 }
865
866 return jsResult;
867 }
868
JSGetDateAdded(napi_env env,napi_callback_info info)869 napi_value FileAssetNapi::JSGetDateAdded(napi_env env, napi_callback_info info)
870 {
871 napi_status status;
872 napi_value jsResult = nullptr;
873 FileAssetNapi *obj = nullptr;
874 int64_t dateAdded;
875 napi_value thisVar = nullptr;
876
877 napi_get_undefined(env, &jsResult);
878 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
879 if (status != napi_ok || thisVar == nullptr) {
880 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
881 return jsResult;
882 }
883
884 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
885 if (status == napi_ok && obj != nullptr) {
886 dateAdded = obj->fileAssetPtr->GetDateAdded() / MSEC_TO_SEC;
887 napi_create_int64(env, dateAdded, &jsResult);
888 }
889
890 return jsResult;
891 }
892
JSGetDateTrashed(napi_env env,napi_callback_info info)893 napi_value FileAssetNapi::JSGetDateTrashed(napi_env env, napi_callback_info info)
894 {
895 napi_status status;
896 napi_value jsResult = nullptr;
897 FileAssetNapi *obj = nullptr;
898 int64_t dateTrashed;
899 napi_value thisVar = nullptr;
900
901 napi_get_undefined(env, &jsResult);
902 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
903 if (status != napi_ok || thisVar == nullptr) {
904 NAPI_ERR_LOG("Invalid arguments! status: %{private}d", status);
905 return jsResult;
906 }
907
908 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
909 if (status == napi_ok && obj != nullptr) {
910 dateTrashed = obj->fileAssetPtr->GetDateTrashed() / MSEC_TO_SEC;
911 napi_create_int64(env, dateTrashed, &jsResult);
912 }
913
914 return jsResult;
915 }
916
JSGetDateModified(napi_env env,napi_callback_info info)917 napi_value FileAssetNapi::JSGetDateModified(napi_env env, napi_callback_info info)
918 {
919 napi_status status;
920 napi_value jsResult = nullptr;
921 FileAssetNapi *obj = nullptr;
922 int64_t dateModified;
923 napi_value thisVar = nullptr;
924
925 napi_get_undefined(env, &jsResult);
926 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
927 if (status != napi_ok || thisVar == nullptr) {
928 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
929 return jsResult;
930 }
931
932 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
933 if (status == napi_ok && obj != nullptr) {
934 dateModified = obj->fileAssetPtr->GetDateModified() / MSEC_TO_SEC;
935 napi_create_int64(env, dateModified, &jsResult);
936 }
937
938 return jsResult;
939 }
940
JSGetOrientation(napi_env env,napi_callback_info info)941 napi_value FileAssetNapi::JSGetOrientation(napi_env env, napi_callback_info info)
942 {
943 napi_status status;
944 napi_value jsResult = nullptr;
945 FileAssetNapi *obj = nullptr;
946 int32_t orientation;
947 napi_value thisVar = nullptr;
948
949 napi_get_undefined(env, &jsResult);
950 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
951 if (status != napi_ok || thisVar == nullptr) {
952 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
953 return jsResult;
954 }
955
956 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
957 if (status == napi_ok && obj != nullptr) {
958 orientation = obj->GetOrientation();
959 napi_create_int32(env, orientation, &jsResult);
960 }
961
962 return jsResult;
963 }
JSSetOrientation(napi_env env,napi_callback_info info)964 napi_value FileAssetNapi::JSSetOrientation(napi_env env, napi_callback_info info)
965 {
966 napi_status status;
967 napi_value undefinedResult = nullptr;
968 FileAssetNapi *obj = nullptr;
969 napi_valuetype valueType = napi_undefined;
970 int32_t orientation;
971 size_t argc = ARGS_ONE;
972 napi_value argv[ARGS_ONE] = {0};
973 napi_value thisVar = nullptr;
974 napi_get_undefined(env, &undefinedResult);
975
976 GET_JS_ARGS(env, info, argc, argv, thisVar);
977 NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
978
979 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
980 if (status == napi_ok && obj != nullptr) {
981 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_number) {
982 NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
983 return undefinedResult;
984 }
985
986 status = napi_get_value_int32(env, argv[PARAM0], &orientation);
987 if (status == napi_ok) {
988 obj->fileAssetPtr->SetOrientation(orientation);
989 }
990 }
991
992 return undefinedResult;
993 }
994
JSGetWidth(napi_env env,napi_callback_info info)995 napi_value FileAssetNapi::JSGetWidth(napi_env env, napi_callback_info info)
996 {
997 napi_status status;
998 napi_value jsResult = nullptr;
999 FileAssetNapi *obj = nullptr;
1000 int32_t width;
1001 napi_value thisVar = nullptr;
1002
1003 napi_get_undefined(env, &jsResult);
1004 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1005 if (status != napi_ok || thisVar == nullptr) {
1006 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1007 return jsResult;
1008 }
1009
1010 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1011 if (status == napi_ok && obj != nullptr) {
1012 width = obj->fileAssetPtr->GetWidth();
1013 napi_create_int32(env, width, &jsResult);
1014 }
1015
1016 return jsResult;
1017 }
1018
JSGetHeight(napi_env env,napi_callback_info info)1019 napi_value FileAssetNapi::JSGetHeight(napi_env env, napi_callback_info info)
1020 {
1021 napi_status status;
1022 napi_value jsResult = nullptr;
1023 FileAssetNapi *obj = nullptr;
1024 int32_t height;
1025 napi_value thisVar = nullptr;
1026
1027 napi_get_undefined(env, &jsResult);
1028 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1029 if (status != napi_ok || thisVar == nullptr) {
1030 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1031 return jsResult;
1032 }
1033
1034 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1035 if (status == napi_ok && obj != nullptr) {
1036 height = obj->fileAssetPtr->GetHeight();
1037 napi_create_int32(env, height, &jsResult);
1038 }
1039
1040 return jsResult;
1041 }
1042
JSGetRelativePath(napi_env env,napi_callback_info info)1043 napi_value FileAssetNapi::JSGetRelativePath(napi_env env, napi_callback_info info)
1044 {
1045 napi_status status;
1046 napi_value jsResult = nullptr;
1047 FileAssetNapi *obj = nullptr;
1048 string relativePath = "";
1049 napi_value thisVar = nullptr;
1050
1051 napi_get_undefined(env, &jsResult);
1052 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1053 if (status != napi_ok || thisVar == nullptr) {
1054 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1055 return jsResult;
1056 }
1057
1058 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1059 if (status == napi_ok && obj != nullptr) {
1060 relativePath = obj->GetRelativePath();
1061 napi_create_string_utf8(env, relativePath.c_str(), NAPI_AUTO_LENGTH, &jsResult);
1062 }
1063
1064 return jsResult;
1065 }
1066
JSSetRelativePath(napi_env env,napi_callback_info info)1067 napi_value FileAssetNapi::JSSetRelativePath(napi_env env, napi_callback_info info)
1068 {
1069 napi_status status;
1070 napi_value undefinedResult = nullptr;
1071 FileAssetNapi *obj = nullptr;
1072 napi_valuetype valueType = napi_undefined;
1073 size_t res = 0;
1074 char buffer[ARG_BUF_SIZE];
1075 size_t argc = ARGS_ONE;
1076 napi_value argv[ARGS_ONE] = {0};
1077 napi_value thisVar = nullptr;
1078 napi_get_undefined(env, &undefinedResult);
1079 GET_JS_ARGS(env, info, argc, argv, thisVar);
1080 NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
1081 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1082 if (status == napi_ok && obj != nullptr) {
1083 if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
1084 NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
1085 return undefinedResult;
1086 }
1087 status = napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res);
1088 if (status == napi_ok) {
1089 obj->fileAssetPtr->SetRelativePath(string(buffer));
1090 }
1091 }
1092 return undefinedResult;
1093 }
JSGetAlbum(napi_env env,napi_callback_info info)1094 napi_value FileAssetNapi::JSGetAlbum(napi_env env, napi_callback_info info)
1095 {
1096 napi_status status;
1097 napi_value jsResult = nullptr;
1098 FileAssetNapi *obj = nullptr;
1099 string album = "";
1100 napi_value thisVar = nullptr;
1101
1102 napi_get_undefined(env, &jsResult);
1103 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1104 if (status != napi_ok || thisVar == nullptr) {
1105 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1106 return jsResult;
1107 }
1108
1109 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1110 if (status == napi_ok && obj != nullptr) {
1111 album = obj->fileAssetPtr->GetAlbum();
1112 napi_create_string_utf8(env, album.c_str(), NAPI_AUTO_LENGTH, &jsResult);
1113 }
1114
1115 return jsResult;
1116 }
1117
JSGetArtist(napi_env env,napi_callback_info info)1118 napi_value FileAssetNapi::JSGetArtist(napi_env env, napi_callback_info info)
1119 {
1120 napi_status status;
1121 napi_value jsResult = nullptr;
1122 FileAssetNapi *obj = nullptr;
1123 string artist = "";
1124 napi_value thisVar = nullptr;
1125
1126 napi_get_undefined(env, &jsResult);
1127 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1128 if (status != napi_ok || thisVar == nullptr) {
1129 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1130 return jsResult;
1131 }
1132
1133 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1134 if (status == napi_ok && obj != nullptr) {
1135 artist = obj->fileAssetPtr->GetArtist();
1136 napi_create_string_utf8(env, artist.c_str(), NAPI_AUTO_LENGTH, &jsResult);
1137 }
1138
1139 return jsResult;
1140 }
1141
JSGetDuration(napi_env env,napi_callback_info info)1142 napi_value FileAssetNapi::JSGetDuration(napi_env env, napi_callback_info info)
1143 {
1144 napi_status status;
1145 napi_value jsResult = nullptr;
1146 FileAssetNapi *obj = nullptr;
1147 int32_t duration;
1148 napi_value thisVar = nullptr;
1149
1150 napi_get_undefined(env, &jsResult);
1151 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1152 if (status != napi_ok || thisVar == nullptr) {
1153 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1154 return jsResult;
1155 }
1156
1157 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1158 if (status == napi_ok && obj != nullptr) {
1159 duration = obj->fileAssetPtr->GetDuration();
1160 napi_create_int32(env, duration, &jsResult);
1161 }
1162
1163 return jsResult;
1164 }
1165
JSParent(napi_env env,napi_callback_info info)1166 napi_value FileAssetNapi::JSParent(napi_env env, napi_callback_info info)
1167 {
1168 napi_status status;
1169 napi_value jsResult = nullptr;
1170 FileAssetNapi *obj = nullptr;
1171 int32_t parent;
1172 napi_value thisVar = nullptr;
1173 napi_get_undefined(env, &jsResult);
1174 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1175 if (status != napi_ok || thisVar == nullptr) {
1176 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1177 return jsResult;
1178 }
1179 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1180 if (status == napi_ok && obj != nullptr) {
1181 parent = obj->fileAssetPtr->GetParent();
1182 napi_create_int32(env, parent, &jsResult);
1183 }
1184 return jsResult;
1185 }
JSGetAlbumUri(napi_env env,napi_callback_info info)1186 napi_value FileAssetNapi::JSGetAlbumUri(napi_env env, napi_callback_info info)
1187 {
1188 napi_status status;
1189 napi_value jsResult = nullptr;
1190 FileAssetNapi *obj = nullptr;
1191 string albumUri = "";
1192 napi_value thisVar = nullptr;
1193 napi_get_undefined(env, &jsResult);
1194 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1195 if (status != napi_ok || thisVar == nullptr) {
1196 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1197 return jsResult;
1198 }
1199 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1200 if (status == napi_ok && obj != nullptr) {
1201 albumUri = obj->fileAssetPtr->GetAlbumUri();
1202 napi_create_string_utf8(env, albumUri.c_str(), NAPI_AUTO_LENGTH, &jsResult);
1203 }
1204 return jsResult;
1205 }
JSGetDateTaken(napi_env env,napi_callback_info info)1206 napi_value FileAssetNapi::JSGetDateTaken(napi_env env, napi_callback_info info)
1207 {
1208 napi_status status;
1209 napi_value jsResult = nullptr;
1210 FileAssetNapi *obj = nullptr;
1211 int64_t dateTaken;
1212 napi_value thisVar = nullptr;
1213 napi_get_undefined(env, &jsResult);
1214 GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1215 if (status != napi_ok || thisVar == nullptr) {
1216 NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1217 return jsResult;
1218 }
1219 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1220 if (status == napi_ok && obj != nullptr) {
1221 dateTaken = obj->fileAssetPtr->GetDateTaken() / MSEC_TO_SEC;
1222 napi_create_int64(env, dateTaken, &jsResult);
1223 }
1224 return jsResult;
1225 }
1226
BuildCommitModifyValuesBucket(FileAssetAsyncContext * context,DataShareValuesBucket & valuesBucket)1227 void BuildCommitModifyValuesBucket(FileAssetAsyncContext* context, DataShareValuesBucket &valuesBucket)
1228 {
1229 const auto fileAsset = context->objectPtr;
1230 if (context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1231 valuesBucket.Put(MediaColumn::MEDIA_TITLE, fileAsset->GetTitle());
1232 } else if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1233 valuesBucket.Put(MediaColumn::MEDIA_NAME, fileAsset->GetDisplayName());
1234 } else {
1235 #ifdef MEDIALIBRARY_COMPATIBILITY
1236 valuesBucket.Put(MEDIA_DATA_DB_TITLE, fileAsset->GetTitle());
1237 valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH,
1238 MediaFileUtils::AddDocsToRelativePath(fileAsset->GetRelativePath()));
1239 if (fileAsset->GetMediaType() != MediaType::MEDIA_TYPE_AUDIO) {
1240 // IMAGE, VIDEO AND FILES
1241 if (fileAsset->GetOrientation() >= 0) {
1242 valuesBucket.Put(MEDIA_DATA_DB_ORIENTATION, fileAsset->GetOrientation());
1243 }
1244 if ((fileAsset->GetMediaType() != MediaType::MEDIA_TYPE_IMAGE) &&
1245 (fileAsset->GetMediaType() != MediaType::MEDIA_TYPE_VIDEO)) {
1246 // ONLY FILES
1247 valuesBucket.Put(MEDIA_DATA_DB_URI, fileAsset->GetUri());
1248 valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileAsset->GetMediaType());
1249 }
1250 }
1251 #else
1252 valuesBucket.Put(MEDIA_DATA_DB_URI, fileAsset->GetUri());
1253 valuesBucket.Put(MEDIA_DATA_DB_TITLE, fileAsset->GetTitle());
1254
1255 if (fileAsset->GetOrientation() >= 0) {
1256 valuesBucket.Put(MEDIA_DATA_DB_ORIENTATION, fileAsset->GetOrientation());
1257 }
1258 valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, fileAsset->GetRelativePath());
1259 valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileAsset->GetMediaType());
1260 #endif
1261 valuesBucket.Put(MEDIA_DATA_DB_NAME, fileAsset->GetDisplayName());
1262 }
1263 }
1264
1265 #ifdef MEDIALIBRARY_COMPATIBILITY
BuildCommitModifyUriApi9(FileAssetAsyncContext * context,string & uri)1266 static void BuildCommitModifyUriApi9(FileAssetAsyncContext *context, string &uri)
1267 {
1268 if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
1269 context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
1270 uri = URI_UPDATE_PHOTO;
1271 } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
1272 uri = URI_UPDATE_AUDIO;
1273 } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_FILE) {
1274 uri = URI_UPDATE_FILE;
1275 }
1276 }
1277 #endif
1278
BuildCommitModifyUriApi10(FileAssetAsyncContext * context,string & uri)1279 static void BuildCommitModifyUriApi10(FileAssetAsyncContext *context, string &uri)
1280 {
1281 if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
1282 context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
1283 uri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ? UFM_UPDATE_PHOTO : PAH_UPDATE_PHOTO;
1284 } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
1285 uri = UFM_UPDATE_AUDIO;
1286 }
1287 }
1288
CheckDisplayNameInCommitModify(FileAssetAsyncContext * context)1289 static bool CheckDisplayNameInCommitModify(FileAssetAsyncContext *context)
1290 {
1291 if (context->resultNapiType != ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1292 if (context->objectPtr->GetPhotoSubType() == static_cast<int32_t>(PhotoSubType::BURST)) {
1293 context->error = JS_E_DISPLAYNAME;
1294 return false;
1295 }
1296 if (context->objectPtr->GetMediaType() != MediaType::MEDIA_TYPE_FILE) {
1297 if (MediaFileUtils::CheckDisplayName(context->objectPtr->GetDisplayName(), true) != E_OK) {
1298 context->error = JS_E_DISPLAYNAME;
1299 return false;
1300 }
1301 } else {
1302 if (MediaFileUtils::CheckFileDisplayName(context->objectPtr->GetDisplayName()) != E_OK) {
1303 context->error = JS_E_DISPLAYNAME;
1304 return false;
1305 }
1306 }
1307 } else {
1308 if (MediaFileUtils::CheckTitleCompatible(context->objectPtr->GetTitle()) != E_OK) {
1309 context->error = JS_E_DISPLAYNAME;
1310 return false;
1311 }
1312 }
1313 return true;
1314 }
1315
JSCommitModifyExecute(napi_env env,void * data)1316 static void JSCommitModifyExecute(napi_env env, void *data)
1317 {
1318 auto *context = static_cast<FileAssetAsyncContext*>(data);
1319 MediaLibraryTracer tracer;
1320 tracer.Start("JSCommitModifyExecute");
1321 if (!CheckDisplayNameInCommitModify(context)) {
1322 return;
1323 }
1324 string uri;
1325 if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1326 context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1327 BuildCommitModifyUriApi10(context, uri);
1328 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1329 } else {
1330 #ifdef MEDIALIBRARY_COMPATIBILITY
1331 BuildCommitModifyUriApi9(context, uri);
1332 #else
1333 uri = URI_UPDATE_FILE;
1334 #endif
1335 }
1336
1337 Uri updateAssetUri(uri);
1338 MediaType mediaType = context->objectPtr->GetMediaType();
1339 string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
1340 DataSharePredicates predicates;
1341 DataShareValuesBucket valuesBucket;
1342 BuildCommitModifyValuesBucket(context, valuesBucket);
1343 predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
1344 predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
1345
1346 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
1347 if (changedRows < 0) {
1348 context->SaveError(changedRows);
1349 NAPI_ERR_LOG("File asset modification failed, err: %{public}d", changedRows);
1350 } else {
1351 context->changedRows = changedRows;
1352 Uri modifyNotify(notifyUri);
1353 UserFileClient::NotifyChange(modifyNotify);
1354 }
1355 }
1356
JSCommitModifyCompleteCallback(napi_env env,napi_status status,void * data)1357 static void JSCommitModifyCompleteCallback(napi_env env, napi_status status, void *data)
1358 {
1359 FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
1360 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1361 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1362 jsContext->status = false;
1363
1364 MediaLibraryTracer tracer;
1365 tracer.Start("JSCommitModifyCompleteCallback");
1366
1367 if (context->error == ERR_DEFAULT) {
1368 if (context->changedRows < 0) {
1369 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
1370 "File asset modification failed");
1371 napi_get_undefined(env, &jsContext->data);
1372 } else {
1373 napi_create_int32(env, context->changedRows, &jsContext->data);
1374 jsContext->status = true;
1375 napi_get_undefined(env, &jsContext->error);
1376 }
1377 } else {
1378 NAPI_ERR_LOG("JSCommitModify fail %{public}d", context->error);
1379 context->HandleError(env, jsContext->error);
1380 napi_get_undefined(env, &jsContext->data);
1381 }
1382 tracer.Finish();
1383 if (context->work != nullptr) {
1384 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1385 context->work, *jsContext);
1386 }
1387 delete context;
1388 }
GetJSArgsForCommitModify(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)1389 napi_value GetJSArgsForCommitModify(napi_env env, size_t argc, const napi_value argv[],
1390 FileAssetAsyncContext &asyncContext)
1391 {
1392 const int32_t refCount = 1;
1393 napi_value result = nullptr;
1394 auto context = &asyncContext;
1395 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1396 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1397 for (size_t i = PARAM0; i < argc; i++) {
1398 napi_valuetype valueType = napi_undefined;
1399 napi_typeof(env, argv[i], &valueType);
1400 if (i == PARAM0 && valueType == napi_function) {
1401 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1402 break;
1403 } else {
1404 NAPI_ASSERT(env, false, "type mismatch");
1405 }
1406 }
1407 napi_get_boolean(env, true, &result);
1408 return result;
1409 }
1410
JSCommitModify(napi_env env,napi_callback_info info)1411 napi_value FileAssetNapi::JSCommitModify(napi_env env, napi_callback_info info)
1412 {
1413 napi_status status;
1414 napi_value result = nullptr;
1415 size_t argc = ARGS_ONE;
1416 napi_value argv[ARGS_ONE] = {0};
1417 napi_value thisVar = nullptr;
1418 MediaLibraryTracer tracer;
1419 tracer.Start("JSCommitModify");
1420
1421 GET_JS_ARGS(env, info, argc, argv, thisVar);
1422 NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameters maximum");
1423 napi_get_undefined(env, &result);
1424
1425 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1426 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1427 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1428 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1429 result = GetJSArgsForCommitModify(env, argc, argv, *asyncContext);
1430 ASSERT_NULLPTR_CHECK(env, result);
1431 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1432 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1433
1434 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
1435 JSCommitModifyCompleteCallback);
1436 }
1437
1438 return result;
1439 }
1440
JSOpenExecute(napi_env env,void * data)1441 static void JSOpenExecute(napi_env env, void *data)
1442 {
1443 MediaLibraryTracer tracer;
1444 tracer.Start("JSOpenExecute");
1445
1446 FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
1447 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1448
1449 bool isValid = false;
1450 string mode = context->valuesBucket.Get(MEDIA_FILEMODE, isValid);
1451 if (!isValid) {
1452 context->error = ERR_INVALID_OUTPUT;
1453 NAPI_ERR_LOG("getting mode invalid");
1454 return;
1455 }
1456 transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
1457
1458 string fileUri = context->objectPtr->GetUri();
1459 Uri openFileUri(fileUri);
1460 int32_t retVal = UserFileClient::OpenFile(openFileUri, mode);
1461 if (retVal <= 0) {
1462 context->SaveError(retVal);
1463 NAPI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
1464 } else {
1465 context->fd = retVal;
1466 if (mode.find('w') != string::npos) {
1467 context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
1468 } else {
1469 context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
1470 }
1471 }
1472 }
1473
JSOpenCompleteCallback(napi_env env,napi_status status,void * data)1474 static void JSOpenCompleteCallback(napi_env env, napi_status status, void *data)
1475 {
1476 FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
1477 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1478
1479 MediaLibraryTracer tracer;
1480 tracer.Start("JSOpenCompleteCallback");
1481
1482 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1483 jsContext->status = false;
1484
1485 if (context->error == ERR_DEFAULT) {
1486 NAPI_DEBUG_LOG("return fd = %{public}d", context->fd);
1487 napi_create_int32(env, context->fd, &jsContext->data);
1488 napi_get_undefined(env, &jsContext->error);
1489 jsContext->status = true;
1490 } else {
1491 context->HandleError(env, jsContext->error);
1492 napi_get_undefined(env, &jsContext->data);
1493 }
1494
1495 tracer.Finish();
1496 if (context->work != nullptr) {
1497 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1498 context->work, *jsContext);
1499 }
1500
1501 delete context;
1502 }
1503
GetJSArgsForOpen(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)1504 napi_value GetJSArgsForOpen(napi_env env, size_t argc, const napi_value argv[],
1505 FileAssetAsyncContext &asyncContext)
1506 {
1507 const int32_t refCount = 1;
1508 napi_value result = nullptr;
1509 auto context = &asyncContext;
1510 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1511 size_t res = 0;
1512 char buffer[ARG_BUF_SIZE];
1513
1514 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1515
1516 for (size_t i = PARAM0; i < argc; i++) {
1517 napi_valuetype valueType = napi_undefined;
1518 napi_typeof(env, argv[i], &valueType);
1519
1520 if (i == PARAM0 && valueType == napi_string) {
1521 napi_get_value_string_utf8(env, argv[i], buffer, ARG_BUF_SIZE, &res);
1522 } else if (i == PARAM1 && valueType == napi_function) {
1523 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1524 break;
1525 } else {
1526 NAPI_ASSERT(env, false, "type mismatch");
1527 }
1528 }
1529 context->valuesBucket.Put(MEDIA_FILEMODE, string(buffer));
1530 // Return true napi_value if params are successfully obtained
1531 napi_get_boolean(env, true, &result);
1532 return result;
1533 }
1534
JSOpen(napi_env env,napi_callback_info info)1535 napi_value FileAssetNapi::JSOpen(napi_env env, napi_callback_info info)
1536 {
1537 napi_status status;
1538 napi_value result = nullptr;
1539 size_t argc = ARGS_TWO;
1540 napi_value argv[ARGS_TWO] = {0};
1541 napi_value thisVar = nullptr;
1542
1543 MediaLibraryTracer tracer;
1544 tracer.Start("JSOpen");
1545
1546 GET_JS_ARGS(env, info, argc, argv, thisVar);
1547 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1548 napi_get_undefined(env, &result);
1549
1550 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1551 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1552 if ((status == napi_ok) && (asyncContext->objectInfo != nullptr)) {
1553 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1554 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1555 result = GetJSArgsForOpen(env, argc, argv, *asyncContext);
1556 ASSERT_NULLPTR_CHECK(env, result);
1557 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSOpen", JSOpenExecute,
1558 JSOpenCompleteCallback);
1559 }
1560
1561 return result;
1562 }
1563
CheckFileOpenStatus(FileAssetAsyncContext * context,int fd)1564 static bool CheckFileOpenStatus(FileAssetAsyncContext *context, int fd)
1565 {
1566 auto fileAssetPtr = context->objectPtr;
1567 int ret = fileAssetPtr->GetOpenStatus(fd);
1568 if (ret < 0) {
1569 NAPI_ERR_LOG("get fd openStatus is invalid");
1570 return false;
1571 }
1572 fileAssetPtr->RemoveOpenStatus(fd);
1573 if (ret == OPEN_TYPE_READONLY) {
1574 close(fd);
1575 return false;
1576 }
1577 return true;
1578 }
1579
JSCloseExecute(FileAssetAsyncContext * context)1580 static void JSCloseExecute(FileAssetAsyncContext *context)
1581 {
1582 MediaLibraryTracer tracer;
1583 tracer.Start("JSCloseExecute");
1584
1585 #ifdef MEDIALIBRARY_COMPATIBILITY
1586 string closeUri;
1587 if (MediaFileUtils::IsFileTablePath(context->objectPtr->GetPath()) ||
1588 MediaFileUtils::StartsWith(context->objectPtr->GetRelativePath(), DOCS_PATH + DOC_DIR_VALUES) ||
1589 MediaFileUtils::StartsWith(context->objectPtr->GetRelativePath(), DOCS_PATH + DOWNLOAD_DIR_VALUES)) {
1590 closeUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CLOSEASSET;
1591 } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
1592 context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
1593 closeUri = URI_CLOSE_PHOTO;
1594 } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
1595 closeUri = URI_CLOSE_AUDIO;
1596 } else {
1597 closeUri = URI_CLOSE_FILE;
1598 }
1599 #else
1600 string closeUri = URI_CLOSE_FILE;
1601 #endif
1602 Uri closeAssetUri(closeUri);
1603 bool isValid = false;
1604 int32_t mediaFd = context->valuesBucket.Get(MEDIA_FILEDESCRIPTOR, isValid);
1605 if (!isValid) {
1606 context->error = ERR_INVALID_OUTPUT;
1607 NAPI_ERR_LOG("getting fd is invalid");
1608 return;
1609 }
1610
1611 if (!CheckFileOpenStatus(context, mediaFd)) {
1612 return;
1613 }
1614 UniqueFd uniFd(mediaFd);
1615
1616 string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
1617 if (!isValid) {
1618 context->error = ERR_INVALID_OUTPUT;
1619 NAPI_ERR_LOG("getting file uri is invalid");
1620 return;
1621 }
1622 if (!MediaFileUtils::GetNetworkIdFromUri(fileUri).empty()) {
1623 return;
1624 }
1625
1626 auto retVal = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
1627 if (retVal != E_SUCCESS) {
1628 context->SaveError(retVal);
1629 NAPI_ERR_LOG("File close asset failed %{public}d", retVal);
1630 }
1631 }
1632
JSCloseCompleteCallback(napi_env env,napi_status status,FileAssetAsyncContext * context)1633 static void JSCloseCompleteCallback(napi_env env, napi_status status,
1634 FileAssetAsyncContext *context)
1635 {
1636 MediaLibraryTracer tracer;
1637 tracer.Start("JSCloseCompleteCallback");
1638
1639 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1640 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1641 jsContext->status = false;
1642
1643 if (context->error == ERR_DEFAULT) {
1644 napi_create_int32(env, E_SUCCESS, &jsContext->data);
1645 napi_get_undefined(env, &jsContext->error);
1646 jsContext->status = true;
1647 } else {
1648 context->HandleError(env, jsContext->error);
1649 napi_get_undefined(env, &jsContext->data);
1650 }
1651
1652 tracer.Finish();
1653 if (context->work != nullptr) {
1654 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1655 context->work, *jsContext);
1656 }
1657
1658 delete context;
1659 }
1660
GetJSArgsForClose(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)1661 napi_value GetJSArgsForClose(napi_env env, size_t argc, const napi_value argv[],
1662 FileAssetAsyncContext &asyncContext)
1663 {
1664 const int32_t refCount = 1;
1665 napi_value result = nullptr;
1666 auto context = &asyncContext;
1667 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1668 int32_t fd = 0;
1669
1670 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1671
1672 for (size_t i = PARAM0; i < argc; i++) {
1673 napi_valuetype valueType = napi_undefined;
1674 napi_typeof(env, argv[i], &valueType);
1675
1676 if (i == PARAM0 && valueType == napi_number) {
1677 napi_get_value_int32(env, argv[i], &fd);
1678 if (fd <= 0) {
1679 NAPI_ASSERT(env, false, "fd <= 0");
1680 }
1681 } else if (i == PARAM1 && valueType == napi_function) {
1682 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1683 break;
1684 } else {
1685 NAPI_ASSERT(env, false, "type mismatch");
1686 }
1687 }
1688 context->valuesBucket.Put(MEDIA_FILEDESCRIPTOR, fd);
1689 context->valuesBucket.Put(MEDIA_DATA_DB_URI, context->objectInfo->GetFileUri());
1690 // Return true napi_value if params are successfully obtained
1691 napi_get_boolean(env, true, &result);
1692 return result;
1693 }
1694
JSClose(napi_env env,napi_callback_info info)1695 napi_value FileAssetNapi::JSClose(napi_env env, napi_callback_info info)
1696 {
1697 napi_status status;
1698 napi_value result = nullptr;
1699 size_t argc = ARGS_TWO;
1700 napi_value argv[ARGS_TWO] = {0};
1701 napi_value thisVar = nullptr;
1702 napi_value resource = nullptr;
1703
1704 MediaLibraryTracer tracer;
1705 tracer.Start("JSClose");
1706
1707 GET_JS_ARGS(env, info, argc, argv, thisVar);
1708 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1709 napi_get_undefined(env, &result);
1710 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1711 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1712 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1713 result = GetJSArgsForClose(env, argc, argv, *asyncContext);
1714 ASSERT_NULLPTR_CHECK(env, result);
1715 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
1716 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSClose", asyncContext);
1717
1718 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1719 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1720
1721 status = napi_create_async_work(
1722 env, nullptr, resource, [](napi_env env, void *data) {
1723 auto context = static_cast<FileAssetAsyncContext*>(data);
1724 JSCloseExecute(context);
1725 },
1726 reinterpret_cast<CompleteCallback>(JSCloseCompleteCallback),
1727 static_cast<void *>(asyncContext.get()), &asyncContext->work);
1728 if (status != napi_ok) {
1729 napi_get_undefined(env, &result);
1730 } else {
1731 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
1732 asyncContext.release();
1733 }
1734 }
1735
1736 return result;
1737 }
1738
JSGetThumbnailDataExecute(napi_env env,FileAssetAsyncContext * context)1739 static void JSGetThumbnailDataExecute(napi_env env, FileAssetAsyncContext* context)
1740 {
1741 MediaLibraryTracer tracer;
1742 tracer.Start("JSGetThumbnailDataExecute");
1743
1744 string path = context->objectPtr->GetPath();
1745 #ifndef MEDIALIBRARY_COMPATIBILITY
1746 if (path.empty()
1747 && !context->objectPtr->GetRelativePath().empty() && !context->objectPtr->GetDisplayName().empty()) {
1748 path = ROOT_MEDIA_DIR + context->objectPtr->GetRelativePath() + context->objectPtr->GetDisplayName();
1749 }
1750 #endif
1751 context->path = path;
1752 }
1753
JSGetThumbnailExecute(FileAssetAsyncContext * context)1754 static void JSGetThumbnailExecute(FileAssetAsyncContext* context)
1755 {
1756 MediaLibraryTracer tracer;
1757 tracer.Start("JSGetThumbnailExecute");
1758
1759 string path = context->objectPtr->GetPath();
1760 #ifndef MEDIALIBRARY_COMPATIBILITY
1761 if (path.empty()
1762 && !context->objectPtr->GetRelativePath().empty() && !context->objectPtr->GetDisplayName().empty()) {
1763 path = ROOT_MEDIA_DIR + context->objectPtr->GetRelativePath() + context->objectPtr->GetDisplayName();
1764 }
1765 #endif
1766 context->pixelmap = ThumbnailManager::QueryThumbnail(context->objectPtr->GetUri(), context->size, path);
1767 }
1768
JSGetKeyFrameThumbnailExecute(FileAssetAsyncContext * context)1769 static void JSGetKeyFrameThumbnailExecute(FileAssetAsyncContext* context)
1770 {
1771 MediaLibraryTracer tracer;
1772 tracer.Start("JSGetKeyFrameThumbnailExecute");
1773
1774 string path = context->objectPtr->GetPath();
1775 #ifndef MEDIALIBRARY_COMPATIBILITY
1776 if (path.empty() && !context->objectPtr->GetRelativePath().empty() &&
1777 !context->objectPtr->GetDisplayName().empty()) {
1778 path = ROOT_MEDIA_DIR + context->objectPtr->GetRelativePath() + context->objectPtr->GetDisplayName();
1779 }
1780 #endif
1781
1782 context->pixelmap = ThumbnailManager::QueryKeyFrameThumbnail(context->objectPtr->GetUri(), context->beginStamp,
1783 context->type, path);
1784 }
1785
GetReference(napi_env env,napi_ref ref)1786 static napi_value GetReference(napi_env env, napi_ref ref)
1787 {
1788 napi_value obj = nullptr;
1789 napi_status status = napi_get_reference_value(env, ref, &obj);
1790 if (status != napi_ok) {
1791 napi_throw_error(env, nullptr, "napi_get_reference_value fail");
1792 return nullptr;
1793 }
1794 return obj;
1795 }
1796
JSGetThumbnailDataCompleteCallback(napi_env env,napi_status status,FileAssetAsyncContext * context)1797 static void JSGetThumbnailDataCompleteCallback(napi_env env, napi_status status,
1798 FileAssetAsyncContext* context)
1799 {
1800 MediaLibraryTracer tracer;
1801 tracer.Start("JSGetThumbnailDataCompleteCallback");
1802
1803 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1804
1805 context->napiArrayBufferRef = ThumbnailManager::QueryThumbnailData(
1806 env, context->objectPtr->GetUri(), context->type, context->path);
1807
1808 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1809 jsContext->status = false;
1810
1811 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
1812 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
1813 if (context->error == ERR_DEFAULT && context->napiArrayBufferRef != nullptr) {
1814 jsContext->data = GetReference(env, context->napiArrayBufferRef);
1815 jsContext->status = true;
1816 } else {
1817 if (context->napiArrayBufferRef == nullptr) {
1818 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_ERR_NO_SUCH_FILE,
1819 "File is not exist");
1820 NAPI_ERR_LOG("File is not exist");
1821 }
1822 context->HandleError(env, jsContext->error);
1823 }
1824
1825 tracer.Finish();
1826 if (context->work != nullptr) {
1827 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1828 context->work, *jsContext);
1829 }
1830
1831 napi_delete_reference(env, context->napiArrayBufferRef);
1832 delete context;
1833 }
1834
JSGetThumbnailCompleteCallback(napi_env env,napi_status status,FileAssetAsyncContext * context)1835 static void JSGetThumbnailCompleteCallback(napi_env env, napi_status status,
1836 FileAssetAsyncContext* context)
1837 {
1838 MediaLibraryTracer tracer;
1839 tracer.Start("JSGetThumbnailCompleteCallback");
1840
1841 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1842
1843 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1844 jsContext->status = false;
1845
1846 if (context->error == ERR_DEFAULT) {
1847 if (context->pixelmap != nullptr) {
1848 jsContext->data = Media::PixelMapNapi::CreatePixelMap(env, context->pixelmap);
1849 napi_get_undefined(env, &jsContext->error);
1850 jsContext->status = true;
1851 } else {
1852 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1853 "Get thumbnail failed");
1854 napi_get_undefined(env, &jsContext->data);
1855 }
1856 } else {
1857 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1858 "Ability helper or thumbnail helper is null");
1859 napi_get_undefined(env, &jsContext->data);
1860 }
1861
1862 tracer.Finish();
1863 if (context->work != nullptr) {
1864 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1865 context->work, *jsContext);
1866 }
1867
1868 delete context;
1869 }
1870
GetInt32InfoFromNapiObject(napi_env env,napi_value configObj,std::string type,int32_t & result)1871 static bool GetInt32InfoFromNapiObject(napi_env env, napi_value configObj, std::string type, int32_t &result)
1872 {
1873 napi_value item = nullptr;
1874 bool exist = false;
1875 napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist);
1876 if (status != napi_ok || !exist) {
1877 NAPI_ERR_LOG("can not find named property, status: %{public}d", status);
1878 return false;
1879 }
1880
1881 if (napi_get_named_property(env, configObj, type.c_str(), &item) != napi_ok) {
1882 NAPI_ERR_LOG("get named property fail");
1883 return false;
1884 }
1885
1886 if (napi_get_value_int32(env, item, &result) != napi_ok) {
1887 NAPI_ERR_LOG("get property value fail");
1888 return false;
1889 }
1890
1891 return true;
1892 }
1893
GetNapiObjectFromNapiObject(napi_env env,napi_value configObj,std::string type,napi_value * object)1894 static bool GetNapiObjectFromNapiObject(napi_env env, napi_value configObj, std::string type, napi_value *object)
1895 {
1896 bool exist = false;
1897 napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist);
1898 if (status != napi_ok || !exist) {
1899 NAPI_ERR_LOG("can not find named property, status: %{public}d", status);
1900 return false;
1901 }
1902
1903 if (napi_get_named_property(env, configObj, type.c_str(), object) != napi_ok) {
1904 NAPI_ERR_LOG("get named property fail");
1905 return false;
1906 }
1907
1908 return true;
1909 }
1910
CheckType(int32_t & type)1911 static napi_status CheckType(int32_t &type)
1912 {
1913 const int lcdType = 1;
1914 const int thmType = 2;
1915
1916 if (type == lcdType || type == thmType) {
1917 return napi_ok;
1918 }
1919 return napi_invalid_arg;
1920 }
1921
GetJSArgsForGetThumbnailData(napi_env env,size_t argc,const napi_value argv[],unique_ptr<FileAssetAsyncContext> & asyncContext)1922 napi_value GetJSArgsForGetThumbnailData(napi_env env, size_t argc, const napi_value argv[],
1923 unique_ptr<FileAssetAsyncContext> &asyncContext)
1924 {
1925 for (size_t i = PARAM0; i < argc; i++) {
1926 napi_valuetype valueType = napi_undefined;
1927 napi_typeof(env, argv[i], &valueType);
1928 if (i == PARAM0 && valueType == napi_number) {
1929 napi_get_value_int32(env, argv[PARAM0], &asyncContext->type);
1930 } else {
1931 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid parameter type");
1932 return nullptr;
1933 }
1934 }
1935
1936 CHECK_COND_WITH_MESSAGE(env, CheckType(asyncContext->type) == napi_ok, "Invalid parameter type");
1937
1938 napi_value result = nullptr;
1939 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1940 return result;
1941 }
1942
GetJSArgsForGetThumbnail(napi_env env,size_t argc,const napi_value argv[],unique_ptr<FileAssetAsyncContext> & asyncContext)1943 napi_value GetJSArgsForGetThumbnail(napi_env env, size_t argc, const napi_value argv[],
1944 unique_ptr<FileAssetAsyncContext> &asyncContext)
1945 {
1946 asyncContext->size.width = DEFAULT_THUMB_SIZE;
1947 asyncContext->size.height = DEFAULT_THUMB_SIZE;
1948
1949 if (argc == ARGS_ONE) {
1950 napi_valuetype valueType = napi_undefined;
1951 if (napi_typeof(env, argv[PARAM0], &valueType) == napi_ok &&
1952 (valueType == napi_undefined || valueType == napi_null)) {
1953 argc -= 1;
1954 }
1955 }
1956
1957 for (size_t i = PARAM0; i < argc; i++) {
1958 napi_valuetype valueType = napi_undefined;
1959 napi_typeof(env, argv[i], &valueType);
1960
1961 if (i == PARAM0 && valueType == napi_object) {
1962 GetInt32InfoFromNapiObject(env, argv[PARAM0], "width", asyncContext->size.width);
1963 GetInt32InfoFromNapiObject(env, argv[PARAM0], "height", asyncContext->size.height);
1964 } else if (i == PARAM0 && valueType == napi_function) {
1965 if (asyncContext->callbackRef == nullptr) {
1966 napi_create_reference(env, argv[i], NAPI_INIT_REF_COUNT, &asyncContext->callbackRef);
1967 }
1968 break;
1969 } else if (i == PARAM1 && valueType == napi_function) {
1970 if (asyncContext->callbackRef == nullptr) {
1971 napi_create_reference(env, argv[i], NAPI_INIT_REF_COUNT, &asyncContext->callbackRef);
1972 }
1973 break;
1974 } else {
1975 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid parameter type");
1976 return nullptr;
1977 }
1978 }
1979
1980 napi_value result = nullptr;
1981 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1982 return result;
1983 }
1984
GetJSArgsForGetKeyFrameThumbnail(napi_env env,size_t argc,const napi_value argv[],unique_ptr<FileAssetAsyncContext> & asyncContext)1985 napi_value GetJSArgsForGetKeyFrameThumbnail(napi_env env, size_t argc, const napi_value argv[],
1986 unique_ptr<FileAssetAsyncContext> &asyncContext)
1987 {
1988 for (size_t i = PARAM0; i < argc; i++) {
1989 napi_valuetype valueType = napi_undefined;
1990 napi_typeof(env, argv[i], &valueType);
1991 if (i == PARAM0 && valueType == napi_number) {
1992 napi_get_value_int32(env, argv[PARAM0], &asyncContext->beginStamp);
1993 } else if (i == PARAM1 && valueType == napi_number) {
1994 napi_get_value_int32(env, argv[PARAM1], &asyncContext->type);
1995 } else {
1996 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid parameter type");
1997 return nullptr;
1998 }
1999 }
2000
2001 napi_value result = nullptr;
2002 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
2003 return result;
2004 }
2005
GetPhotoRequestOption(napi_env env,napi_value object,unique_ptr<FileAssetAsyncContext> & asyncContext,RequestPhotoType & type)2006 static napi_value GetPhotoRequestOption(napi_env env, napi_value object,
2007 unique_ptr<FileAssetAsyncContext> &asyncContext, RequestPhotoType &type)
2008 {
2009 napi_value sizeObj;
2010 if (GetNapiObjectFromNapiObject(env, object, "size", &sizeObj)) {
2011 GetInt32InfoFromNapiObject(env, sizeObj, "width", asyncContext->size.width);
2012 GetInt32InfoFromNapiObject(env, sizeObj, "height", asyncContext->size.height);
2013 }
2014 int32_t requestType = 0;
2015 if (GetInt32InfoFromNapiObject(env, object, REQUEST_PHOTO_TYPE, requestType)) {
2016 if (requestType >= static_cast<int>(RequestPhotoType::REQUEST_TYPE_END)) {
2017 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid parameter type");
2018 return nullptr;
2019 }
2020 type = static_cast<RequestPhotoType>(requestType);
2021 } else {
2022 type = RequestPhotoType::REQUEST_ALL_THUMBNAILS;
2023 }
2024
2025 napi_value result = nullptr;
2026 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
2027 return result;
2028 }
2029
GetPhotoRequestArgs(napi_env env,size_t argc,const napi_value argv[],unique_ptr<FileAssetAsyncContext> & asyncContext,RequestPhotoType & type)2030 napi_value GetPhotoRequestArgs(napi_env env, size_t argc, const napi_value argv[],
2031 unique_ptr<FileAssetAsyncContext> &asyncContext, RequestPhotoType &type)
2032 {
2033 if (argc != ARGS_ONE && argc != ARGS_TWO) {
2034 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid parameter number " + to_string(argc));
2035 return nullptr;
2036 }
2037 asyncContext->size.width = DEFAULT_THUMB_SIZE;
2038 asyncContext->size.height = DEFAULT_THUMB_SIZE;
2039
2040 for (size_t i = PARAM0; i < argc; i++) {
2041 napi_valuetype valueType = napi_undefined;
2042 napi_typeof(env, argv[i], &valueType);
2043
2044 if (argc == PARAM1) {
2045 if (valueType == napi_function) {
2046 napi_create_reference(env, argv[i], NAPI_INIT_REF_COUNT, &asyncContext->callbackRef);
2047 break;
2048 } else {
2049 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid parameter type");
2050 return nullptr;
2051 }
2052 }
2053 if (i == PARAM0 && valueType == napi_object) {
2054 napi_value result = GetPhotoRequestOption(env, argv[i], asyncContext, type);
2055 ASSERT_NULLPTR_CHECK(env, result);
2056 } else if (i == PARAM1 && valueType == napi_function) {
2057 napi_create_reference(env, argv[i], NAPI_INIT_REF_COUNT, &asyncContext->callbackRef);
2058 break;
2059 } else {
2060 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Invalid parameter type");
2061 return nullptr;
2062 }
2063 }
2064
2065 napi_value result = nullptr;
2066 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
2067 return result;
2068 }
2069
JSGetThumbnail(napi_env env,napi_callback_info info)2070 napi_value FileAssetNapi::JSGetThumbnail(napi_env env, napi_callback_info info)
2071 {
2072 napi_status status;
2073 napi_value result = nullptr;
2074 size_t argc = ARGS_TWO;
2075 napi_value argv[ARGS_TWO] = {0};
2076 napi_value thisVar = nullptr;
2077 napi_value resource = nullptr;
2078
2079 MediaLibraryTracer tracer;
2080 tracer.Start("JSGetThumbnail");
2081
2082 GET_JS_ARGS(env, info, argc, argv, thisVar);
2083 NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE || argc == ARGS_TWO),
2084 "requires 2 parameters maximum");
2085 napi_get_undefined(env, &result);
2086 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2087 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2088 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2089 result = GetJSArgsForGetThumbnail(env, argc, argv, asyncContext);
2090 CHECK_NULLPTR_RET(result);
2091 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2092 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetThumbnail", asyncContext);
2093 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2094 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2095
2096 status = napi_create_async_work(
2097 env, nullptr, resource, [](napi_env env, void *data) {
2098 auto context = static_cast<FileAssetAsyncContext*>(data);
2099 JSGetThumbnailExecute(context);
2100 },
2101 reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback),
2102 static_cast<void *>(asyncContext.get()), &asyncContext->work);
2103 if (status != napi_ok) {
2104 napi_get_undefined(env, &result);
2105 } else {
2106 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
2107 asyncContext.release();
2108 }
2109 }
2110
2111 return result;
2112 }
2113
2114 static const map<int32_t, struct AnalysisSourceInfo> ANALYSIS_SOURCE_INFO_MAP = {
2115 { ANALYSIS_AESTHETICS_SCORE, { AESTHETICS_SCORE, PAH_QUERY_ANA_ATTS, { AESTHETICS_SCORE, PROB } } },
2116 { ANALYSIS_LABEL, { LABEL, PAH_QUERY_ANA_LABEL, { CATEGORY_ID, SUB_LABEL, PROB, FEATURE, SIM_RESULT,
2117 SALIENCY_SUB_PROB } } },
2118 { ANALYSIS_VIDEO_LABEL, { VIDEO_LABEL, PAH_QUERY_ANA_VIDEO_LABEL, { CATEGORY_ID, CONFIDENCE_PROBABILITY,
2119 SUB_CATEGORY, SUB_CONFIDENCE_PROB, SUB_LABEL, SUB_LABEL_PROB, SUB_LABEL_TYPE, TRACKS, VIDEO_PART_FEATURE,
2120 FILTER_TAG} } },
2121 { ANALYSIS_OCR, { OCR, PAH_QUERY_ANA_OCR, { OCR_TEXT, OCR_TEXT_MSG, OCR_WIDTH, OCR_HEIGHT } } },
2122 { ANALYSIS_FACE, { FACE, PAH_QUERY_ANA_FACE, { FACE_ID, TAG_ID, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT,
2123 LANDMARKS, PITCH, YAW, ROLL, PROB, TOTAL_FACES, FEATURES, FACE_OCCLUSION, BEAUTY_BOUNDER_X, BEAUTY_BOUNDER_Y,
2124 BEAUTY_BOUNDER_WIDTH, BEAUTY_BOUNDER_HEIGHT, FACE_AESTHETICS_SCORE} } },
2125 { ANALYSIS_OBJECT, { OBJECT, PAH_QUERY_ANA_OBJECT, { OBJECT_ID, OBJECT_LABEL, OBJECT_SCALE_X, OBJECT_SCALE_Y,
2126 OBJECT_SCALE_WIDTH, OBJECT_SCALE_HEIGHT, PROB, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT } } },
2127 { ANALYSIS_RECOMMENDATION, { RECOMMENDATION, PAH_QUERY_ANA_RECOMMENDATION, { RECOMMENDATION_ID,
2128 RECOMMENDATION_RESOLUTION, RECOMMENDATION_SCALE_X, RECOMMENDATION_SCALE_Y, RECOMMENDATION_SCALE_WIDTH,
2129 RECOMMENDATION_SCALE_HEIGHT, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT } } },
2130 { ANALYSIS_SEGMENTATION, { SEGMENTATION, PAH_QUERY_ANA_SEGMENTATION, { SEGMENTATION_AREA, SEGMENTATION_NAME,
2131 PROB } } },
2132 { ANALYSIS_COMPOSITION, { COMPOSITION, PAH_QUERY_ANA_COMPOSITION, { COMPOSITION_ID, COMPOSITION_RESOLUTION,
2133 CLOCK_STYLE, CLOCK_LOCATION_X, CLOCK_LOCATION_Y, CLOCK_COLOUR, COMPOSITION_SCALE_X, COMPOSITION_SCALE_Y,
2134 COMPOSITION_SCALE_WIDTH, COMPOSITION_SCALE_HEIGHT, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT } } },
2135 { ANALYSIS_SALIENCY, { SALIENCY, PAH_QUERY_ANA_SAL, { SALIENCY_X, SALIENCY_Y } } },
2136 { ANALYSIS_DETAIL_ADDRESS, { DETAIL_ADDRESS, PAH_QUERY_ANA_ADDRESS, { PhotoColumn::PHOTOS_TABLE + "." + LATITUDE,
2137 PhotoColumn::PHOTOS_TABLE + "." + LONGITUDE, LANGUAGE, COUNTRY, ADMIN_AREA, SUB_ADMIN_AREA, LOCALITY,
2138 SUB_LOCALITY, THOROUGHFARE, SUB_THOROUGHFARE, FEATURE_NAME, CITY_NAME, ADDRESS_DESCRIPTION, LOCATION_TYPE,
2139 AOI, POI, FIRST_AOI, FIRST_POI, LOCATION_VERSION, FIRST_AOI_CATEGORY, FIRST_POI_CATEGORY, FILE_ID} } },
2140 { ANALYSIS_HUMAN_FACE_TAG, { FACE_TAG, PAH_QUERY_ANA_FACE_TAG, { VISION_FACE_TAG_TABLE + "." + TAG_ID, TAG_NAME,
2141 USER_OPERATION, GROUP_TAG, RENAME_OPERATION, CENTER_FEATURES, USER_DISPLAY_LEVEL, TAG_ORDER, IS_ME, COVER_URI,
2142 COUNT, PORTRAIT_DATE_MODIFY, ALBUM_TYPE, IS_REMOVED } } },
2143 { ANALYSIS_HEAD_POSITION, { HEAD, PAH_QUERY_ANA_HEAD, { HEAD_ID, HEAD_LABEL, HEAD_SCALE_X, HEAD_SCALE_Y,
2144 HEAD_SCALE_WIDTH, HEAD_SCALE_HEIGHT, PROB, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT } } },
2145 { ANALYSIS_BONE_POSE, { POSE, PAH_QUERY_ANA_POSE, { POSE_ID, POSE_LANDMARKS, POSE_SCALE_X, POSE_SCALE_Y,
2146 POSE_SCALE_WIDTH, POSE_SCALE_HEIGHT, PROB, POSE_TYPE, SCALE_X, SCALE_Y, SCALE_WIDTH, SCALE_HEIGHT } } },
2147 { ANALYSIS_MULTI_CROP, { RECOMMENDATION, PAH_QUERY_ANA_RECOMMENDATION, { MOVEMENT_CROP, MOVEMENT_VERSION } } },
2148 };
2149
JSGetAnalysisDataExecute(FileAssetAsyncContext * context)2150 static void JSGetAnalysisDataExecute(FileAssetAsyncContext *context)
2151 {
2152 MediaLibraryTracer tracer;
2153 tracer.Start("JSGetThumbnailExecute");
2154 if (ANALYSIS_SOURCE_INFO_MAP.find(context->analysisType) == ANALYSIS_SOURCE_INFO_MAP.end()) {
2155 NAPI_ERR_LOG("Invalid analysisType");
2156 return;
2157 }
2158 auto &analysisInfo = ANALYSIS_SOURCE_INFO_MAP.at(context->analysisType);
2159 DataShare::DataSharePredicates predicates;
2160 if (context->analysisType == ANALYSIS_HUMAN_FACE_TAG) {
2161 string onClause = VISION_IMAGE_FACE_TABLE + "." + TAG_ID + " = " + VISION_FACE_TAG_TABLE + "." + TAG_ID;
2162 predicates.InnerJoin(VISION_IMAGE_FACE_TABLE)->On({ onClause });
2163 }
2164 string fileId = to_string(context->objectInfo->GetFileId());
2165 if (context->analysisType == ANALYSIS_DETAIL_ADDRESS) {
2166 string language = Global::I18n::LocaleConfig::GetSystemLanguage();
2167 //Chinese and English supported. Other languages English default.
2168 if (LANGUAGE_ZH != language) {
2169 language = LANGUAGE_ZH;
2170 }
2171 vector<string> onClause = { PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::MEDIA_ID + " = " +
2172 GEO_KNOWLEDGE_TABLE + "." + FILE_ID + " AND " +
2173 GEO_KNOWLEDGE_TABLE + "." + LANGUAGE + " = \'" + language + "\'" };
2174 predicates.LeftOuterJoin(GEO_KNOWLEDGE_TABLE)->On(onClause);
2175 predicates.EqualTo(PhotoColumn::PHOTOS_TABLE + "." + MediaColumn::MEDIA_ID, fileId);
2176 } else {
2177 predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
2178 }
2179 Uri uri(analysisInfo.uriStr);
2180 std::vector<std::string> fetchColumn = analysisInfo.fetchColumn;
2181 int errCode = 0;
2182 int userId = context->objectPtr != nullptr ? context->objectPtr->GetUserId() : -1;
2183 auto resultSet = UserFileClient::Query(uri, predicates, fetchColumn, errCode, userId);
2184 context->analysisData = context->analysisType == ANALYSIS_FACE ?
2185 MediaLibraryNapiUtils::ParseAnalysisFace2JsonStr(resultSet, fetchColumn) :
2186 MediaLibraryNapiUtils::ParseResultSet2JsonStr(resultSet, fetchColumn);
2187 if (context->analysisData == ANALYSIS_NO_RESULTS) {
2188 Uri uri(PAH_QUERY_ANA_TOTAL);
2189 DataShare::DataSharePredicates predicates;
2190 std::vector<std::string> fetchColumn = { analysisInfo.fieldStr };
2191 predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
2192 auto fieldValue = UserFileClient::Query(uri, predicates, fetchColumn, errCode, userId);
2193 string value = MediaLibraryNapiUtils::ParseResultSet2JsonStr(fieldValue, fetchColumn);
2194 if (strstr(value.c_str(), ANALYSIS_INIT_VALUE.c_str()) == NULL) {
2195 context->analysisData = ANALYSIS_STATUS_ANALYZED;
2196 }
2197 }
2198 }
2199
JSFavoriteCallbackComplete(napi_env env,napi_status status,void * data)2200 static void JSFavoriteCallbackComplete(napi_env env, napi_status status, void *data)
2201 {
2202 MediaLibraryTracer tracer;
2203 tracer.Start("JSFavoriteCallbackComplete");
2204
2205 FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2206 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2207 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2208 CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2209 jsContext->status = false;
2210 napi_get_undefined(env, &jsContext->data);
2211 if (context->error == ERR_DEFAULT) {
2212 jsContext->status = true;
2213 Media::MediaType mediaType = context->objectPtr->GetMediaType();
2214 string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
2215 Uri modifyNotify(notifyUri);
2216 UserFileClient::NotifyChange(modifyNotify);
2217 } else {
2218 context->HandleError(env, jsContext->error);
2219 napi_get_undefined(env, &jsContext->data);
2220 }
2221
2222 tracer.Finish();
2223 if (context->work != nullptr) {
2224 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2225 context->work, *jsContext);
2226 }
2227
2228 delete context;
2229 }
2230
GetIsDirectoryiteNative(napi_env env,const FileAssetAsyncContext & fileContext)2231 static bool GetIsDirectoryiteNative(napi_env env, const FileAssetAsyncContext &fileContext)
2232 {
2233 MediaLibraryTracer tracer;
2234 tracer.Start("GetIsDirectoryiteNative");
2235
2236 FileAssetAsyncContext *context = const_cast<FileAssetAsyncContext *>(&fileContext);
2237 if (context == nullptr) {
2238 NAPI_ERR_LOG("Async context is null");
2239 return false;
2240 }
2241
2242 #ifdef MEDIALIBRARY_COMPATIBILITY
2243 if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO) ||
2244 (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2245 (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
2246 context->status = true;
2247 return false;
2248 }
2249
2250 int64_t virtualId = MediaFileUtils::GetVirtualIdByType(context->objectPtr->GetId(), MediaType::MEDIA_TYPE_FILE);
2251 vector<string> selectionArgs = { to_string(virtualId) };
2252 #else
2253 vector<string> selectionArgs = { to_string(context->objectPtr->GetId()) };
2254 #endif
2255 vector<string> columns = { MEDIA_DATA_DB_MEDIA_TYPE };
2256 DataSharePredicates predicates;
2257 predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ?");
2258 predicates.SetWhereArgs(selectionArgs);
2259 string queryUri = MEDIALIBRARY_DATA_URI;
2260 Uri uri(queryUri);
2261 int errCode = 0;
2262 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2263 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
2264 NAPI_ERR_LOG("Query IsDirectory failed");
2265 return false;
2266 }
2267 int32_t index = 0;
2268 if (resultSet->GetColumnIndex(MEDIA_DATA_DB_MEDIA_TYPE, index) != NativeRdb::E_OK) {
2269 NAPI_ERR_LOG("Query Directory failed");
2270 return false;
2271 }
2272 int32_t mediaType = 0;
2273 if (resultSet->GetInt(index, mediaType) != NativeRdb::E_OK) {
2274 NAPI_ERR_LOG("Can not get file path");
2275 return false;
2276 }
2277 context->status = true;
2278 return mediaType == static_cast<int>(MediaType::MEDIA_TYPE_ALBUM);
2279 }
2280
JSIsDirectoryCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)2281 static void JSIsDirectoryCallbackComplete(napi_env env, napi_status status,
2282 FileAssetAsyncContext* context)
2283 {
2284 MediaLibraryTracer tracer;
2285 tracer.Start("JSIsDirectoryCallbackComplete");
2286
2287 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2288 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2289 CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2290 jsContext->status = false;
2291
2292 if (context->status) {
2293 napi_get_boolean(env, context->isDirectory, &jsContext->data);
2294 napi_get_undefined(env, &jsContext->error);
2295 jsContext->status = true;
2296 } else {
2297 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2298 "UserFileClient is invalid");
2299 napi_get_undefined(env, &jsContext->data);
2300 }
2301
2302 tracer.Finish();
2303 if (context->work != nullptr) {
2304 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2305 context->work, *jsContext);
2306 }
2307
2308 delete context;
2309 }
2310
GetJSArgsForIsDirectory(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2311 static napi_value GetJSArgsForIsDirectory(napi_env env, size_t argc, const napi_value argv[],
2312 FileAssetAsyncContext &asyncContext)
2313 {
2314 const int32_t refCount = 1;
2315 napi_value result;
2316 auto context = &asyncContext;
2317 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2318 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2319 for (size_t i = PARAM0; i < argc; i++) {
2320 napi_valuetype valueType = napi_undefined;
2321 napi_typeof(env, argv[i], &valueType);
2322 if (i == PARAM0 && valueType == napi_function) {
2323 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2324 break;
2325 } else {
2326 NAPI_ASSERT(env, false, "type mismatch");
2327 }
2328 }
2329 napi_get_boolean(env, true, &result);
2330 return result;
2331 }
2332
JSIsDirectory(napi_env env,napi_callback_info info)2333 napi_value FileAssetNapi::JSIsDirectory(napi_env env, napi_callback_info info)
2334 {
2335 size_t argc = ARGS_ONE;
2336 napi_value argv[ARGS_ONE] = {0};
2337 napi_value thisVar = nullptr;
2338 napi_value resource = nullptr;
2339
2340 MediaLibraryTracer tracer;
2341 tracer.Start("JSisDirectory");
2342
2343 GET_JS_ARGS(env, info, argc, argv, thisVar);
2344 NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 2 parameters maximum");
2345 napi_value result = nullptr;
2346 napi_get_undefined(env, &result);
2347 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2348 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2349 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2350 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2351 result = GetJSArgsForIsDirectory(env, argc, argv, *asyncContext);
2352 ASSERT_NULLPTR_CHECK(env, result);
2353 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2354 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsDirectory", asyncContext);
2355 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2356 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2357 status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
2358 FileAssetAsyncContext* context = static_cast<FileAssetAsyncContext*>(data);
2359 context->status = false;
2360 context->isDirectory = GetIsDirectoryiteNative(env, *context);
2361 },
2362 reinterpret_cast<CompleteCallback>(JSIsDirectoryCallbackComplete),
2363 static_cast<void *>(asyncContext.get()), &asyncContext->work);
2364 if (status != napi_ok) {
2365 napi_get_undefined(env, &result);
2366 } else {
2367 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
2368 asyncContext.release();
2369 }
2370 }
2371 return result;
2372 }
2373
JSIsFavoriteExecute(FileAssetAsyncContext * context)2374 static void JSIsFavoriteExecute(FileAssetAsyncContext* context)
2375 {
2376 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2377 context->isFavorite = context->objectPtr->IsFavorite();
2378 return;
2379 }
2380
JSIsFavoriteCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)2381 static void JSIsFavoriteCallbackComplete(napi_env env, napi_status status,
2382 FileAssetAsyncContext* context)
2383 {
2384 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2385 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2386 CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2387 jsContext->status = false;
2388 if (context->error == ERR_DEFAULT) {
2389 napi_get_boolean(env, context->isFavorite, &jsContext->data);
2390 napi_get_undefined(env, &jsContext->error);
2391 jsContext->status = true;
2392 } else {
2393 NAPI_ERR_LOG("Get IsFavorite failed, ret: %{public}d", context->error);
2394 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2395 "UserFileClient is invalid");
2396 napi_get_undefined(env, &jsContext->data);
2397 }
2398 if (context->work != nullptr) {
2399 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2400 context->work, *jsContext);
2401 }
2402 delete context;
2403 }
2404
GetJSArgsForFavorite(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2405 napi_value GetJSArgsForFavorite(napi_env env, size_t argc, const napi_value argv[],
2406 FileAssetAsyncContext &asyncContext)
2407 {
2408 const int32_t refCount = 1;
2409 napi_value result = nullptr;
2410 auto context = &asyncContext;
2411 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2412 bool isFavorite = false;
2413 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2414 for (size_t i = PARAM0; i < argc; i++) {
2415 napi_valuetype valueType = napi_undefined;
2416 napi_typeof(env, argv[i], &valueType);
2417 if (i == PARAM0 && valueType == napi_boolean) {
2418 napi_get_value_bool(env, argv[i], &isFavorite);
2419 } else if (i == PARAM1 && valueType == napi_function) {
2420 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2421 break;
2422 } else {
2423 NAPI_ASSERT(env, false, "type mismatch");
2424 }
2425 }
2426 context->isFavorite = isFavorite;
2427 napi_get_boolean(env, true, &result);
2428 return result;
2429 }
2430
2431 #ifdef MEDIALIBRARY_COMPATIBILITY
FavoriteByUpdate(FileAssetAsyncContext * context)2432 static void FavoriteByUpdate(FileAssetAsyncContext *context)
2433 {
2434 DataShareValuesBucket valuesBucket;
2435 string uriString;
2436 if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2437 (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
2438 uriString = URI_UPDATE_PHOTO;
2439 } else {
2440 uriString = URI_UPDATE_AUDIO;
2441 }
2442 valuesBucket.Put(MEDIA_DATA_DB_IS_FAV, (context->isFavorite ? IS_FAV : NOT_FAV));
2443 NAPI_INFO_LOG("Update asset %{public}d favorite to %{public}d", context->objectPtr->GetId(),
2444 context->isFavorite ? IS_FAV : NOT_FAV);
2445 DataSharePredicates predicates;
2446 int32_t fileId = context->objectPtr->GetId();
2447 predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
2448 predicates.SetWhereArgs({ to_string(fileId) });
2449 Uri uri(uriString);
2450 context->changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
2451 }
2452 #endif
2453
FavoriteByInsert(FileAssetAsyncContext * context)2454 static void FavoriteByInsert(FileAssetAsyncContext *context)
2455 {
2456 DataShareValuesBucket valuesBucket;
2457 string uriString = MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/";
2458 uriString += context->isFavorite ? MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM : MEDIA_SMARTALBUMMAPOPRN_REMOVESMARTALBUM;
2459 valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, FAVOURITE_ALBUM_ID_VALUES);
2460 valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, context->objectPtr->GetId());
2461 Uri uri(uriString);
2462 context->changedRows = UserFileClient::Insert(uri, valuesBucket);
2463 }
2464
JSFavouriteExecute(napi_env env,void * data)2465 static void JSFavouriteExecute(napi_env env, void *data)
2466 {
2467 MediaLibraryTracer tracer;
2468 tracer.Start("JSFavouriteExecute");
2469
2470 FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2471 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2472
2473 #ifdef MEDIALIBRARY_COMPATIBILITY
2474 string uriString = MEDIALIBRARY_DATA_URI + "/";
2475 if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2476 (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO) ||
2477 (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO)) {
2478 if (MediaFileUtils::IsFileTablePath(context->objectPtr->GetPath())) {
2479 FavoriteByInsert(context);
2480 } else {
2481 FavoriteByUpdate(context);
2482 }
2483 } else {
2484 FavoriteByInsert(context);
2485 }
2486 #else
2487 FavoriteByInsert(context);
2488 #endif
2489 if (context->changedRows >= 0) {
2490 context->objectPtr->SetFavorite(context->isFavorite);
2491 }
2492 context->SaveError(context->changedRows);
2493 }
2494
JSFavorite(napi_env env,napi_callback_info info)2495 napi_value FileAssetNapi::JSFavorite(napi_env env, napi_callback_info info)
2496 {
2497 size_t argc = ARGS_TWO;
2498 napi_value argv[ARGS_TWO] = {0};
2499 napi_value thisVar = nullptr;
2500
2501 MediaLibraryTracer tracer;
2502 tracer.Start("JSFavorite");
2503
2504 GET_JS_ARGS(env, info, argc, argv, thisVar);
2505 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2506 napi_value result = nullptr;
2507 napi_get_undefined(env, &result);
2508
2509 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2510 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2511 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
2512 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2513 if ((status != napi_ok) || (asyncContext->objectInfo == nullptr)) {
2514 NAPI_DEBUG_LOG("get this Var fail");
2515 return result;
2516 }
2517
2518 result = GetJSArgsForFavorite(env, argc, argv, *asyncContext);
2519 if (asyncContext->isFavorite == asyncContext->objectInfo->IsFavorite()) {
2520 NAPI_DEBUG_LOG("favorite state is the same");
2521 return result;
2522 }
2523 ASSERT_NULLPTR_CHECK(env, result);
2524 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2525 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2526
2527 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSFavorite", JSFavouriteExecute,
2528 JSFavoriteCallbackComplete);
2529 }
2530
GetJSArgsForIsFavorite(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2531 static napi_value GetJSArgsForIsFavorite(napi_env env, size_t argc, const napi_value argv[],
2532 FileAssetAsyncContext &asyncContext)
2533 {
2534 const int32_t refCount = 1;
2535 napi_value result;
2536 auto context = &asyncContext;
2537 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2538 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2539 for (size_t i = PARAM0; i < argc; i++) {
2540 napi_valuetype valueType = napi_undefined;
2541 napi_typeof(env, argv[i], &valueType);
2542 if (i == PARAM0 && valueType == napi_function) {
2543 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2544 break;
2545 } else {
2546 NAPI_ASSERT(env, false, "type mismatch");
2547 }
2548 }
2549 napi_get_boolean(env, true, &result);
2550 return result;
2551 }
2552
JSIsFavorite(napi_env env,napi_callback_info info)2553 napi_value FileAssetNapi::JSIsFavorite(napi_env env, napi_callback_info info)
2554 {
2555 MediaLibraryTracer tracer;
2556 tracer.Start("JSIsFavorite");
2557
2558 napi_status status;
2559 napi_value result = nullptr;
2560 size_t argc = ARGS_ONE;
2561 napi_value argv[ARGS_ONE] = {0};
2562 napi_value thisVar = nullptr;
2563 napi_value resource = nullptr;
2564 GET_JS_ARGS(env, info, argc, argv, thisVar);
2565 NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameters maximum");
2566 napi_get_undefined(env, &result);
2567 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2568 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2569 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2570 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2571 result = GetJSArgsForIsFavorite(env, argc, argv, *asyncContext);
2572 ASSERT_NULLPTR_CHECK(env, result);
2573 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2574 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsFavorite", asyncContext);
2575 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2576 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2577
2578 status = napi_create_async_work(
2579 env, nullptr, resource, [](napi_env env, void *data) {
2580 auto context = static_cast<FileAssetAsyncContext*>(data);
2581 JSIsFavoriteExecute(context);
2582 },
2583 reinterpret_cast<CompleteCallback>(JSIsFavoriteCallbackComplete),
2584 static_cast<void *>(asyncContext.get()), &asyncContext->work);
2585 if (status != napi_ok) {
2586 napi_get_undefined(env, &result);
2587 } else {
2588 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
2589 asyncContext.release();
2590 }
2591 }
2592 return result;
2593 }
2594
TrashByUpdate(FileAssetAsyncContext * context)2595 static void TrashByUpdate(FileAssetAsyncContext *context)
2596 {
2597 DataShareValuesBucket valuesBucket;
2598 string uriString;
2599 if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2600 (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
2601 uriString = URI_UPDATE_PHOTO;
2602 } else {
2603 uriString = URI_UPDATE_AUDIO;
2604 }
2605 valuesBucket.Put(MEDIA_DATA_DB_DATE_TRASHED,
2606 (context->isTrash ? MediaFileUtils::UTCTimeMilliSeconds() : NOT_TRASH));
2607 DataSharePredicates predicates;
2608 int32_t fileId = context->objectPtr->GetId();
2609 predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
2610 predicates.SetWhereArgs({ to_string(fileId) });
2611 Uri uri(uriString);
2612 context->changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
2613 }
2614
TrashByInsert(FileAssetAsyncContext * context)2615 static void TrashByInsert(FileAssetAsyncContext *context)
2616 {
2617 DataShareValuesBucket valuesBucket;
2618 string uriString = MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/";
2619 uriString += context->isTrash ? MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM : MEDIA_SMARTALBUMMAPOPRN_REMOVESMARTALBUM;
2620 valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, TRASH_ALBUM_ID_VALUES);
2621 valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, context->objectPtr->GetId());
2622 Uri uri(uriString);
2623 context->changedRows = UserFileClient::Insert(uri, valuesBucket);
2624 }
2625
JSTrashExecute(napi_env env,void * data)2626 static void JSTrashExecute(napi_env env, void *data)
2627 {
2628 MediaLibraryTracer tracer;
2629 tracer.Start("JSTrashExecute");
2630
2631 auto *context = static_cast<FileAssetAsyncContext*>(data);
2632
2633 #ifdef MEDIALIBRARY_COMPATIBILITY
2634 if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2635 (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO) ||
2636 (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO)) {
2637 if (MediaFileUtils::IsFileTablePath(context->objectPtr->GetPath())) {
2638 TrashByInsert(context);
2639 } else {
2640 TrashByUpdate(context);
2641 }
2642 } else {
2643 TrashByInsert(context);
2644 }
2645 #else
2646 TrashByInsert(context);
2647 #endif
2648 if (context->changedRows >= 0) {
2649 int32_t trashFlag = (context->isTrash ? IS_TRASH : NOT_TRASH);
2650 context->objectPtr->SetIsTrash(trashFlag);
2651 }
2652 context->SaveError(context->changedRows);
2653 }
2654
JSTrashCallbackComplete(napi_env env,napi_status status,void * data)2655 static void JSTrashCallbackComplete(napi_env env, napi_status status, void *data)
2656 {
2657 MediaLibraryTracer tracer;
2658 tracer.Start("JSTrashCallbackComplete");
2659
2660 FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2661 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2662 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2663 CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2664 jsContext->status = false;
2665 napi_get_undefined(env, &jsContext->data);
2666 if (context->error == ERR_DEFAULT) {
2667 jsContext->status = true;
2668 Media::MediaType mediaType = context->objectPtr->GetMediaType();
2669 string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
2670 Uri modifyNotify(notifyUri);
2671 UserFileClient::NotifyChange(modifyNotify);
2672 NAPI_DEBUG_LOG("JSTrashCallbackComplete success");
2673 } else {
2674 context->HandleError(env, jsContext->error);
2675 }
2676
2677 tracer.Finish();
2678 if (context->work != nullptr) {
2679 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2680 context->work, *jsContext);
2681 }
2682
2683 delete context;
2684 }
2685
GetJSArgsForTrash(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2686 napi_value GetJSArgsForTrash(napi_env env, size_t argc, const napi_value argv[],
2687 FileAssetAsyncContext &asyncContext)
2688 {
2689 const int32_t refCount = 1;
2690 napi_value result = nullptr;
2691 auto context = &asyncContext;
2692 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2693 bool isTrash = false;
2694 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2695 for (size_t i = PARAM0; i < argc; i++) {
2696 napi_valuetype valueType = napi_undefined;
2697 napi_typeof(env, argv[i], &valueType);
2698 if (i == PARAM0 && valueType == napi_boolean) {
2699 napi_get_value_bool(env, argv[i], &isTrash);
2700 } else if (i == PARAM1 && valueType == napi_function) {
2701 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2702 break;
2703 } else {
2704 NAPI_ASSERT(env, false, "type mismatch");
2705 }
2706 }
2707 context->isTrash = isTrash;
2708 napi_get_boolean(env, true, &result);
2709 return result;
2710 }
2711
JSTrash(napi_env env,napi_callback_info info)2712 napi_value FileAssetNapi::JSTrash(napi_env env, napi_callback_info info)
2713 {
2714 napi_status status;
2715 napi_value result = nullptr;
2716 size_t argc = ARGS_TWO;
2717 napi_value argv[ARGS_TWO] = {0};
2718 napi_value thisVar = nullptr;
2719
2720 MediaLibraryTracer tracer;
2721 tracer.Start("JSTrash");
2722
2723 GET_JS_ARGS(env, info, argc, argv, thisVar);
2724 NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2725
2726 napi_get_undefined(env, &result);
2727 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2728 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2729 asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
2730 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2731 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2732 result = GetJSArgsForTrash(env, argc, argv, *asyncContext);
2733 ASSERT_NULLPTR_CHECK(env, result);
2734 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2735 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2736 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSTrash", JSTrashExecute,
2737 JSTrashCallbackComplete);
2738 }
2739 return result;
2740 }
2741
JSIsTrashExecute(FileAssetAsyncContext * context)2742 static void JSIsTrashExecute(FileAssetAsyncContext* context)
2743 {
2744 MediaLibraryTracer tracer;
2745 tracer.Start("JSIsTrashExecute");
2746
2747 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2748 context->isTrash = (context->objectPtr->GetIsTrash() != NOT_TRASH);
2749 return;
2750 }
2751
JSIsTrashCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)2752 static void JSIsTrashCallbackComplete(napi_env env, napi_status status,
2753 FileAssetAsyncContext* context)
2754 {
2755 MediaLibraryTracer tracer;
2756 tracer.Start("JSIsTrashCallbackComplete");
2757
2758 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2759 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2760 CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2761 jsContext->status = false;
2762 if (context->error == ERR_DEFAULT) {
2763 napi_get_boolean(env, context->isTrash, &jsContext->data);
2764 napi_get_undefined(env, &jsContext->error);
2765 jsContext->status = true;
2766 } else {
2767 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2768 "UserFileClient is invalid");
2769 napi_get_undefined(env, &jsContext->data);
2770 }
2771
2772 tracer.Finish();
2773 if (context->work != nullptr) {
2774 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2775 context->work, *jsContext);
2776 }
2777
2778 delete context;
2779 }
2780
GetJSArgsForIsTrash(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2781 static napi_value GetJSArgsForIsTrash(napi_env env, size_t argc, const napi_value argv[],
2782 FileAssetAsyncContext &asyncContext)
2783 {
2784 const int32_t refCount = 1;
2785 napi_value result;
2786 auto context = &asyncContext;
2787 CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2788 NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2789 for (size_t i = PARAM0; i < argc; i++) {
2790 napi_valuetype valueType = napi_undefined;
2791 napi_typeof(env, argv[i], &valueType);
2792 if (i == PARAM0 && valueType == napi_function) {
2793 napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2794 break;
2795 } else {
2796 NAPI_ASSERT(env, false, "type mismatch");
2797 }
2798 }
2799 napi_get_boolean(env, true, &result);
2800 return result;
2801 }
2802
JSIsTrash(napi_env env,napi_callback_info info)2803 napi_value FileAssetNapi::JSIsTrash(napi_env env, napi_callback_info info)
2804 {
2805 napi_status status;
2806 napi_value result = nullptr;
2807 size_t argc = ARGS_ONE;
2808 napi_value argv[ARGS_ONE] = {0};
2809 napi_value thisVar = nullptr;
2810 napi_value resource = nullptr;
2811
2812 MediaLibraryTracer tracer;
2813 tracer.Start("JSIsTrash");
2814
2815 GET_JS_ARGS(env, info, argc, argv, thisVar);
2816 NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameters maximum");
2817 napi_get_undefined(env, &result);
2818 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2819 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2820 status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2821 if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2822 result = GetJSArgsForIsTrash(env, argc, argv, *asyncContext);
2823 ASSERT_NULLPTR_CHECK(env, result);
2824 NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2825 NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsTrash", asyncContext);
2826 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2827 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2828
2829 status = napi_create_async_work(
2830 env, nullptr, resource, [](napi_env env, void *data) {
2831 auto context = static_cast<FileAssetAsyncContext*>(data);
2832 JSIsTrashExecute(context);
2833 },
2834 reinterpret_cast<CompleteCallback>(JSIsTrashCallbackComplete),
2835 static_cast<void *>(asyncContext.get()), &asyncContext->work);
2836 if (status != napi_ok) {
2837 napi_get_undefined(env, &result);
2838 } else {
2839 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
2840 asyncContext.release();
2841 }
2842 }
2843
2844 return result;
2845 }
2846
UpdateFileAssetInfo()2847 void FileAssetNapi::UpdateFileAssetInfo()
2848 {
2849 fileAssetPtr = sFileAsset_;
2850 }
2851
GetFileAssetInstance() const2852 shared_ptr<FileAsset> FileAssetNapi::GetFileAssetInstance() const
2853 {
2854 return fileAssetPtr;
2855 }
2856
CheckSystemApiKeys(napi_env env,const string & key)2857 static int32_t CheckSystemApiKeys(napi_env env, const string &key)
2858 {
2859 static const set<string> SYSTEM_API_KEYS = {
2860 MediaColumn::MEDIA_DATE_TRASHED,
2861 MediaColumn::MEDIA_HIDDEN,
2862 PhotoColumn::PHOTO_USER_COMMENT,
2863 PhotoColumn::CAMERA_SHOT_KEY,
2864 PhotoColumn::MOVING_PHOTO_EFFECT_MODE,
2865 PhotoColumn::SUPPORTED_WATERMARK_TYPE,
2866 PhotoColumn::PHOTO_IS_AUTO,
2867 PhotoColumn::PHOTO_IS_RECENT_SHOW,
2868 PENDING_STATUS,
2869 MEDIA_DATA_DB_DATE_TRASHED_MS,
2870 };
2871
2872 if (SYSTEM_API_KEYS.find(key) != SYSTEM_API_KEYS.end() && !MediaLibraryNapiUtils::IsSystemApp()) {
2873 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This key can only be used by system apps");
2874 return E_CHECK_SYSTEMAPP_FAIL;
2875 }
2876 return E_SUCCESS;
2877 }
2878
IsSpecialKey(const string & key)2879 static bool IsSpecialKey(const string &key)
2880 {
2881 static const set<string> SPECIAL_KEY = {
2882 PENDING_STATUS
2883 };
2884
2885 if (SPECIAL_KEY.find(key) != SPECIAL_KEY.end()) {
2886 return true;
2887 }
2888 return false;
2889 }
2890
HandleGettingSpecialKey(napi_env env,const string & key,const shared_ptr<FileAsset> & fileAssetPtr)2891 static napi_value HandleGettingSpecialKey(napi_env env, const string &key, const shared_ptr<FileAsset> &fileAssetPtr)
2892 {
2893 napi_value jsResult = nullptr;
2894 if (key == PENDING_STATUS) {
2895 if (fileAssetPtr->GetTimePending() == 0) {
2896 napi_get_boolean(env, false, &jsResult);
2897 } else {
2898 napi_get_boolean(env, true, &jsResult);
2899 }
2900 }
2901
2902 return jsResult;
2903 }
2904
GetDateTakenFromResultSet(const shared_ptr<DataShare::DataShareResultSet> & resultSet,int64_t & dateTaken)2905 static bool GetDateTakenFromResultSet(const shared_ptr<DataShare::DataShareResultSet> &resultSet,
2906 int64_t &dateTaken)
2907 {
2908 if (resultSet == nullptr) {
2909 NAPI_ERR_LOG("ResultSet is null");
2910 return false;
2911 }
2912 int32_t count = 0;
2913 int32_t errCode = resultSet->GetRowCount(count);
2914 if (errCode != DataShare::E_OK) {
2915 NAPI_ERR_LOG("Can not get row count from resultSet, errCode=%{public}d", errCode);
2916 return false;
2917 }
2918 if (count == 0) {
2919 NAPI_ERR_LOG("Can not find photo edit time from database");
2920 return false;
2921 }
2922 errCode = resultSet->GoToFirstRow();
2923 if (errCode != DataShare::E_OK) {
2924 NAPI_ERR_LOG("ResultSet GotoFirstRow failed, errCode=%{public}d", errCode);
2925 return false;
2926 }
2927 int32_t index = 0;
2928 errCode = resultSet->GetColumnIndex(PhotoColumn::MEDIA_DATE_TAKEN, index);
2929 if (errCode != DataShare::E_OK) {
2930 NAPI_ERR_LOG("ResultSet GetColumnIndex failed, errCode=%{public}d", errCode);
2931 return false;
2932 }
2933 errCode = resultSet->GetLong(index, dateTaken);
2934 if (errCode != DataShare::E_OK) {
2935 NAPI_ERR_LOG("ResultSet GetLong failed, errCode=%{public}d", errCode);
2936 return false;
2937 }
2938 return true;
2939 }
2940
UpdateDetailTimeByDateTaken(napi_env env,const shared_ptr<FileAsset> & fileAssetPtr,const string & detailTime,int64_t & dateTaken)2941 static void UpdateDetailTimeByDateTaken(napi_env env, const shared_ptr<FileAsset> &fileAssetPtr,
2942 const string &detailTime, int64_t &dateTaken)
2943 {
2944 string uri = PAH_UPDATE_PHOTO;
2945 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2946 Uri updateAssetUri(uri);
2947 DataSharePredicates predicates;
2948 DataShareValuesBucket valuesBucket;
2949 valuesBucket.Put(PhotoColumn::PHOTO_DETAIL_TIME, detailTime);
2950 predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
2951 predicates.SetWhereArgs({ MediaFileUtils::GetIdFromUri(fileAssetPtr->GetUri()) });
2952 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
2953 if (changedRows <= 0) {
2954 NAPI_ERR_LOG("Failed to modify detail time, err: %{public}d", changedRows);
2955 NapiError::ThrowError(env, JS_INNER_FAIL);
2956 } else {
2957 NAPI_INFO_LOG("success to modify detial time, detailTime: %{public}s, dateTaken: %{public}" PRId64,
2958 detailTime.c_str(), dateTaken);
2959 }
2960 }
2961
HandleGettingDetailTimeKey(napi_env env,const shared_ptr<FileAsset> & fileAssetPtr)2962 static napi_value HandleGettingDetailTimeKey(napi_env env, const shared_ptr<FileAsset> &fileAssetPtr)
2963 {
2964 napi_value jsResult = nullptr;
2965 auto detailTimeValue = fileAssetPtr->GetMemberMap().at(PhotoColumn::PHOTO_DETAIL_TIME);
2966 if (detailTimeValue.index() == MEMBER_TYPE_STRING && !get<string>(detailTimeValue).empty()) {
2967 napi_create_string_utf8(env, get<string>(detailTimeValue).c_str(), NAPI_AUTO_LENGTH, &jsResult);
2968 } else {
2969 string fileId = MediaFileUtils::GetIdFromUri(fileAssetPtr->GetUri());
2970 string queryUriStr = PAH_QUERY_PHOTO;
2971 MediaLibraryNapiUtils::UriAppendKeyValue(queryUriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2972 Uri uri(queryUriStr);
2973 DataShare::DataSharePredicates predicates;
2974 predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
2975 DataShare::DataShareValuesBucket values;
2976 vector<string> columns = { MediaColumn::MEDIA_DATE_TAKEN };
2977 int32_t errCode = 0;
2978 int64_t dateTaken = 0;
2979 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2980 if (GetDateTakenFromResultSet(resultSet, dateTaken)) {
2981 if (dateTaken > SECONDS_LEVEL_LIMIT) {
2982 dateTaken = dateTaken / MSEC_TO_SEC;
2983 }
2984 string detailTime = MediaFileUtils::StrCreateTimeSafely(PhotoColumn::PHOTO_DETAIL_TIME_FORMAT, dateTaken);
2985 napi_create_string_utf8(env, detailTime.c_str(), NAPI_AUTO_LENGTH, &jsResult);
2986 UpdateDetailTimeByDateTaken(env, fileAssetPtr, detailTime, dateTaken);
2987 } else {
2988 NapiError::ThrowError(env, JS_INNER_FAIL);
2989 }
2990 }
2991 return jsResult;
2992 }
2993
HandleDateTransitionKey(napi_env env,const string & key,const shared_ptr<FileAsset> & fileAssetPtr)2994 static napi_value HandleDateTransitionKey(napi_env env, const string &key, const shared_ptr<FileAsset> &fileAssetPtr)
2995 {
2996 napi_value jsResult = nullptr;
2997 if (fileAssetPtr->GetMemberMap().count(key) == 0) {
2998 NapiError::ThrowError(env, JS_E_FILE_KEY);
2999 return jsResult;
3000 }
3001
3002 auto m = fileAssetPtr->GetMemberMap().at(key);
3003 if (m.index() == MEMBER_TYPE_INT64) {
3004 napi_create_int64(env, get<int64_t>(m), &jsResult);
3005 } else {
3006 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3007 return jsResult;
3008 }
3009 return jsResult;
3010 }
3011
GetCompatDate(const string inputKey,const int64_t date)3012 static inline int64_t GetCompatDate(const string inputKey, const int64_t date)
3013 {
3014 if (inputKey == MEDIA_DATA_DB_DATE_ADDED || inputKey == MEDIA_DATA_DB_DATE_MODIFIED ||
3015 inputKey == MEDIA_DATA_DB_DATE_TRASHED || inputKey == MEDIA_DATA_DB_DATE_TAKEN) {
3016 return date / MSEC_TO_SEC;
3017 }
3018 return date;
3019 }
3020
UserFileMgrGet(napi_env env,napi_callback_info info)3021 napi_value FileAssetNapi::UserFileMgrGet(napi_env env, napi_callback_info info)
3022 {
3023 napi_value ret = nullptr;
3024 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3025 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3026
3027 string inputKey;
3028 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, inputKey),
3029 JS_ERR_PARAMETER_INVALID);
3030
3031 if (CheckSystemApiKeys(env, inputKey) < 0) {
3032 return nullptr;
3033 }
3034
3035 napi_value jsResult = nullptr;
3036 auto obj = asyncContext->objectInfo;
3037 napi_get_undefined(env, &jsResult);
3038 if (DATE_TRANSITION_MAP.count(inputKey) != 0) {
3039 return HandleDateTransitionKey(env, DATE_TRANSITION_MAP.at(inputKey), obj->fileAssetPtr);
3040 }
3041
3042 if (obj->fileAssetPtr->GetMemberMap().count(inputKey) == 0) {
3043 // no exist throw error
3044 NapiError::ThrowError(env, JS_E_FILE_KEY);
3045 return jsResult;
3046 }
3047
3048 if (IsSpecialKey(inputKey)) {
3049 return HandleGettingSpecialKey(env, inputKey, obj->fileAssetPtr);
3050 }
3051 if (inputKey == PhotoColumn::PHOTO_DETAIL_TIME) {
3052 return HandleGettingDetailTimeKey(env, obj->fileAssetPtr);
3053 }
3054 auto m = obj->fileAssetPtr->GetMemberMap().at(inputKey);
3055 if (m.index() == MEMBER_TYPE_STRING) {
3056 napi_create_string_utf8(env, get<string>(m).c_str(), NAPI_AUTO_LENGTH, &jsResult);
3057 } else if (m.index() == MEMBER_TYPE_INT32) {
3058 napi_create_int32(env, get<int32_t>(m), &jsResult);
3059 } else if (m.index() == MEMBER_TYPE_INT64) {
3060 napi_create_int64(env, GetCompatDate(inputKey, get<int64_t>(m)), &jsResult);
3061 } else {
3062 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3063 return jsResult;
3064 }
3065 return jsResult;
3066 }
3067
HandleParamSet(const string & inputKey,const string & value,ResultNapiType resultNapiType)3068 bool FileAssetNapi::HandleParamSet(const string &inputKey, const string &value, ResultNapiType resultNapiType)
3069 {
3070 if (resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
3071 if (inputKey == MediaColumn::MEDIA_TITLE) {
3072 fileAssetPtr->SetTitle(value);
3073 } else {
3074 NAPI_ERR_LOG("invalid key %{private}s, no support key", inputKey.c_str());
3075 return false;
3076 }
3077 } else if (resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
3078 if (inputKey == MediaColumn::MEDIA_NAME) {
3079 fileAssetPtr->SetDisplayName(value);
3080 fileAssetPtr->SetTitle(MediaFileUtils::GetTitleFromDisplayName(value));
3081 } else if (inputKey == MediaColumn::MEDIA_TITLE) {
3082 fileAssetPtr->SetTitle(value);
3083 string displayName = fileAssetPtr->GetDisplayName();
3084 if (!displayName.empty()) {
3085 string extention = MediaFileUtils::SplitByChar(displayName, '.');
3086 fileAssetPtr->SetDisplayName(value + "." + extention);
3087 }
3088 } else {
3089 NAPI_ERR_LOG("invalid key %{private}s, no support key", inputKey.c_str());
3090 return false;
3091 }
3092 } else {
3093 NAPI_ERR_LOG("invalid resultNapiType");
3094 return false;
3095 }
3096 return true;
3097 }
3098
UserFileMgrSet(napi_env env,napi_callback_info info)3099 napi_value FileAssetNapi::UserFileMgrSet(napi_env env, napi_callback_info info)
3100 {
3101 MediaLibraryTracer tracer;
3102 tracer.Start("UserFileMgrSet");
3103
3104 napi_value ret = nullptr;
3105 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3106 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3107 string inputKey;
3108 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, inputKey),
3109 JS_ERR_PARAMETER_INVALID);
3110 string value;
3111 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[ARGS_ONE], value),
3112 JS_ERR_PARAMETER_INVALID);
3113 napi_value jsResult = nullptr;
3114 napi_get_undefined(env, &jsResult);
3115 auto obj = asyncContext->objectInfo;
3116 if (!obj->HandleParamSet(inputKey, value, obj->fileAssetPtr->GetResultNapiType())) {
3117 NapiError::ThrowError(env, JS_E_FILE_KEY);
3118 return jsResult;
3119 }
3120 return jsResult;
3121 }
3122
UserFileMgrCommitModify(napi_env env,napi_callback_info info)3123 napi_value FileAssetNapi::UserFileMgrCommitModify(napi_env env, napi_callback_info info)
3124 {
3125 MediaLibraryTracer tracer;
3126 tracer.Start("UserFileMgrCommitModify");
3127
3128 napi_value ret = nullptr;
3129 auto asyncContext = make_unique<FileAssetAsyncContext>();
3130 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3131 NAPI_ASSERT(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
3132 "Failed to parse js args");
3133 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3134 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
3135
3136 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCommitModify",
3137 JSCommitModifyExecute, JSCommitModifyCompleteCallback);
3138 }
3139
UserFileMgrFavoriteComplete(napi_env env,napi_status status,void * data)3140 static void UserFileMgrFavoriteComplete(napi_env env, napi_status status, void *data)
3141 {
3142 FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3143 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3144 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3145 jsContext->status = false;
3146
3147 if (context->error == ERR_DEFAULT) {
3148 napi_create_int32(env, context->changedRows, &jsContext->data);
3149 jsContext->status = true;
3150 napi_get_undefined(env, &jsContext->error);
3151 } else {
3152 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3153 "Failed to modify favorite state");
3154 napi_get_undefined(env, &jsContext->data);
3155 }
3156
3157 if (context->work != nullptr) {
3158 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3159 context->work, *jsContext);
3160 }
3161 delete context;
3162 }
3163
UserFileMgrFavoriteExecute(napi_env env,void * data)3164 static void UserFileMgrFavoriteExecute(napi_env env, void *data)
3165 {
3166 MediaLibraryTracer tracer;
3167 tracer.Start("UserFileMgrFavoriteExecute");
3168
3169 auto *context = static_cast<FileAssetAsyncContext *>(data);
3170
3171 string uri;
3172 if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3173 context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3174 uri = UFM_UPDATE_PHOTO;
3175 } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
3176 uri = UFM_UPDATE_AUDIO;
3177 }
3178
3179 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3180 Uri updateAssetUri(uri);
3181 DataSharePredicates predicates;
3182 DataShareValuesBucket valuesBucket;
3183 int32_t changedRows;
3184 valuesBucket.Put(MediaColumn::MEDIA_IS_FAV, context->isFavorite ? IS_FAV : NOT_FAV);
3185 NAPI_INFO_LOG("update asset %{public}d favorite to %{public}d", context->objectPtr->GetId(),
3186 context->isFavorite ? IS_FAV : NOT_FAV);
3187 predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3188 predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
3189
3190 changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3191 if (changedRows < 0) {
3192 context->SaveError(changedRows);
3193 NAPI_ERR_LOG("Failed to modify favorite state, err: %{public}d", changedRows);
3194 } else {
3195 context->objectPtr->SetFavorite(context->isFavorite);
3196 context->changedRows = changedRows;
3197 }
3198 }
3199
UserFileMgrFavorite(napi_env env,napi_callback_info info)3200 napi_value FileAssetNapi::UserFileMgrFavorite(napi_env env, napi_callback_info info)
3201 {
3202 auto asyncContext = make_unique<FileAssetAsyncContext>();
3203 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3204 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isFavorite),
3205 JS_ERR_PARAMETER_INVALID);
3206 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3207 CHECK_NULLPTR_RET(asyncContext->objectPtr);
3208
3209 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrFavorite",
3210 UserFileMgrFavoriteExecute, UserFileMgrFavoriteComplete);
3211 }
UserFileMgrGetThumbnail(napi_env env,napi_callback_info info)3212 napi_value FileAssetNapi::UserFileMgrGetThumbnail(napi_env env, napi_callback_info info)
3213 {
3214 MediaLibraryTracer tracer;
3215 tracer.Start("UserFileMgrGetThumbnail");
3216
3217 auto asyncContext = make_unique<FileAssetAsyncContext>();
3218 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_TWO),
3219 JS_INNER_FAIL);
3220 CHECK_NULLPTR_RET(GetJSArgsForGetThumbnail(env, asyncContext->argc, asyncContext->argv, asyncContext));
3221
3222 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3223 CHECK_NULLPTR_RET(asyncContext->objectPtr);
3224 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3225
3226 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetThumbnail",
3227 [](napi_env env, void *data) {
3228 auto context = static_cast<FileAssetAsyncContext*>(data);
3229 JSGetThumbnailExecute(context);
3230 },
3231 reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback));
3232 }
3233
ParseArgsUserFileMgrOpen(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context,bool isReadOnly)3234 static napi_value ParseArgsUserFileMgrOpen(napi_env env, napi_callback_info info,
3235 unique_ptr<FileAssetAsyncContext> &context, bool isReadOnly)
3236 {
3237 if (!isReadOnly && !MediaLibraryNapiUtils::IsSystemApp()) {
3238 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3239 return nullptr;
3240 }
3241
3242 size_t minArgs = ARGS_ZERO;
3243 size_t maxArgs = ARGS_ONE;
3244 if (!isReadOnly) {
3245 minArgs++;
3246 maxArgs++;
3247 }
3248 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3249 JS_ERR_PARAMETER_INVALID);
3250 auto fileUri = context->objectInfo->GetFileUri();
3251 MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3252 context->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
3253
3254 if (isReadOnly) {
3255 context->valuesBucket.Put(MEDIA_FILEMODE, MEDIA_FILEMODE_READONLY);
3256 } else {
3257 string mode;
3258 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], mode),
3259 JS_ERR_PARAMETER_INVALID);
3260 transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
3261 if (!MediaFileUtils::CheckMode(mode)) {
3262 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3263 return nullptr;
3264 }
3265 context->valuesBucket.Put(MEDIA_FILEMODE, mode);
3266 }
3267
3268 napi_value result = nullptr;
3269 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3270 return result;
3271 }
3272
UserFileMgrOpenExecute(napi_env env,void * data)3273 static void UserFileMgrOpenExecute(napi_env env, void *data)
3274 {
3275 MediaLibraryTracer tracer;
3276 tracer.Start("JSOpenExecute");
3277
3278 FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3279 bool isValid = false;
3280 string mode = context->valuesBucket.Get(MEDIA_FILEMODE, isValid);
3281 if (!isValid) {
3282 context->SaveError(-EINVAL);
3283 return;
3284 }
3285 string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
3286 if (!isValid) {
3287 context->SaveError(-EINVAL);
3288 return ;
3289 }
3290
3291 MediaFileUtils::UriAppendKeyValue(fileUri, MediaColumn::MEDIA_TIME_PENDING,
3292 to_string(context->objectPtr->GetTimePending()));
3293 Uri openFileUri(fileUri);
3294 int32_t retVal = UserFileClient::OpenFile(openFileUri, mode);
3295 if (retVal <= 0) {
3296 context->SaveError(retVal);
3297 NAPI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
3298 } else {
3299 context->fd = retVal;
3300 if (mode.find('w') != string::npos) {
3301 context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
3302 } else {
3303 context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
3304 }
3305 if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
3306 context->objectPtr->SetTimePending(UNCLOSE_FILE_TIMEPENDING);
3307 }
3308 }
3309 }
3310
UserFileMgrOpenCallbackComplete(napi_env env,napi_status status,void * data)3311 static void UserFileMgrOpenCallbackComplete(napi_env env, napi_status status, void *data)
3312 {
3313 MediaLibraryTracer tracer;
3314 tracer.Start("UserFileMgrOpenCallbackComplete");
3315
3316 auto *context = static_cast<FileAssetAsyncContext *>(data);
3317 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3318
3319 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3320 jsContext->status = false;
3321
3322 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3323 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3324 if (context->error == ERR_DEFAULT) {
3325 CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->fd, &jsContext->data), JS_INNER_FAIL);
3326 jsContext->status = true;
3327 } else {
3328 context->HandleError(env, jsContext->error);
3329 }
3330
3331 tracer.Finish();
3332 if (context->work != nullptr) {
3333 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3334 context->work, *jsContext);
3335 }
3336 delete context;
3337 }
3338
JSGetAnalysisDataCompleteCallback(napi_env env,napi_status status,void * data)3339 static void JSGetAnalysisDataCompleteCallback(napi_env env, napi_status status, void *data)
3340 {
3341 MediaLibraryTracer tracer;
3342 tracer.Start("JSGetAnalysisDataCompleteCallback");
3343
3344 auto *context = static_cast<FileAssetAsyncContext *>(data);
3345 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3346
3347 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3348 jsContext->status = false;
3349
3350 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3351 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3352 if (context->error == ERR_DEFAULT) {
3353 CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, context->analysisData.c_str(),
3354 NAPI_AUTO_LENGTH, &jsContext->data), JS_INNER_FAIL);
3355 jsContext->status = true;
3356 } else {
3357 context->HandleError(env, jsContext->error);
3358 }
3359
3360 tracer.Finish();
3361 if (context->work != nullptr) {
3362 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3363 context->work, *jsContext);
3364 }
3365 delete context;
3366 }
3367
UserFileMgrOpen(napi_env env,napi_callback_info info)3368 napi_value FileAssetNapi::UserFileMgrOpen(napi_env env, napi_callback_info info)
3369 {
3370 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3371 CHECK_NULLPTR_RET(ParseArgsUserFileMgrOpen(env, info, asyncContext, false));
3372 if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3373 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3374 return nullptr;
3375 }
3376 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3377
3378 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrOpen",
3379 UserFileMgrOpenExecute, UserFileMgrOpenCallbackComplete);
3380 }
3381
JSGetReadOnlyFd(napi_env env,napi_callback_info info)3382 napi_value FileAssetNapi::JSGetReadOnlyFd(napi_env env, napi_callback_info info)
3383 {
3384 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3385 CHECK_NULLPTR_RET(ParseArgsUserFileMgrOpen(env, info, asyncContext, true));
3386 if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3387 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3388 return nullptr;
3389 }
3390 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3391
3392 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets", UserFileMgrOpenExecute,
3393 UserFileMgrOpenCallbackComplete);
3394 }
3395
ParseArgsUserFileMgrClose(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context)3396 static napi_value ParseArgsUserFileMgrClose(napi_env env, napi_callback_info info,
3397 unique_ptr<FileAssetAsyncContext> &context)
3398 {
3399 size_t minArgs = ARGS_ONE;
3400 size_t maxArgs = ARGS_TWO;
3401 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3402 JS_ERR_PARAMETER_INVALID);
3403 context->valuesBucket.Put(MEDIA_DATA_DB_URI, context->objectInfo->GetFileUri());
3404
3405 int32_t fd = 0;
3406 CHECK_COND(env, MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], fd), JS_ERR_PARAMETER_INVALID);
3407 if (fd <= 0) {
3408 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3409 return nullptr;
3410 }
3411 context->fd = fd;
3412
3413 napi_value result = nullptr;
3414 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3415 return result;
3416 }
3417
UserFileMgrCloseExecute(napi_env env,void * data)3418 static void UserFileMgrCloseExecute(napi_env env, void *data)
3419 {
3420 MediaLibraryTracer tracer;
3421 tracer.Start("UserFileMgrCloseExecute");
3422
3423 auto *context = static_cast<FileAssetAsyncContext*>(data);
3424 int32_t mediaFd = context->fd;
3425 if (!CheckFileOpenStatus(context, mediaFd)) {
3426 return;
3427 }
3428 UniqueFd uniFd(mediaFd);
3429 string closeUri;
3430 if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3431 context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3432 closeUri = UFM_CLOSE_PHOTO;
3433 } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
3434 closeUri = UFM_CLOSE_AUDIO;
3435 } else {
3436 context->SaveError(-EINVAL);
3437 return;
3438 }
3439 MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3440 MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, MediaColumn::MEDIA_TIME_PENDING,
3441 to_string(context->objectPtr->GetTimePending()));
3442 Uri closeAssetUri(closeUri);
3443 int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
3444 if (ret != E_SUCCESS) {
3445 context->SaveError(ret);
3446 } else {
3447 if (context->objectPtr->GetTimePending() == UNCLOSE_FILE_TIMEPENDING) {
3448 context->objectPtr->SetTimePending(0);
3449 }
3450 }
3451 }
3452
UserFileMgrCloseCallbackComplete(napi_env env,napi_status status,void * data)3453 static void UserFileMgrCloseCallbackComplete(napi_env env, napi_status status, void *data)
3454 {
3455 MediaLibraryTracer tracer;
3456 tracer.Start("UserFileMgrCloseCallbackComplete");
3457
3458 auto context = static_cast<FileAssetAsyncContext *>(data);
3459 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3460
3461 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3462 jsContext->status = false;
3463
3464 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3465 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3466 if (context->error == ERR_DEFAULT) {
3467 CHECK_ARGS_RET_VOID(env, napi_create_int32(env, E_SUCCESS, &jsContext->data), JS_INNER_FAIL);
3468 jsContext->status = true;
3469 } else {
3470 context->HandleError(env, jsContext->error);
3471 }
3472
3473 tracer.Finish();
3474 if (context->work != nullptr) {
3475 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3476 context->work, *jsContext);
3477 }
3478 delete context;
3479 }
3480
UserFileMgrClose(napi_env env,napi_callback_info info)3481 napi_value FileAssetNapi::UserFileMgrClose(napi_env env, napi_callback_info info)
3482 {
3483 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3484 CHECK_NULLPTR_RET(ParseArgsUserFileMgrClose(env, info, asyncContext));
3485 if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3486 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3487 return nullptr;
3488 }
3489 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3490
3491 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets", UserFileMgrCloseExecute,
3492 UserFileMgrCloseCallbackComplete);
3493 }
3494
UserFileMgrSetHiddenExecute(napi_env env,void * data)3495 static void UserFileMgrSetHiddenExecute(napi_env env, void *data)
3496 {
3497 MediaLibraryTracer tracer;
3498 tracer.Start("UserFileMgrSetHiddenExecute");
3499
3500 auto *context = static_cast<FileAssetAsyncContext *>(data);
3501 if (context->objectPtr->GetMediaType() != MEDIA_TYPE_IMAGE &&
3502 context->objectPtr->GetMediaType() != MEDIA_TYPE_VIDEO) {
3503 context->SaveError(-EINVAL);
3504 return;
3505 }
3506
3507 string uri = UFM_HIDE_PHOTO;
3508 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3509 Uri updateAssetUri(uri);
3510 DataSharePredicates predicates;
3511 predicates.In(MediaColumn::MEDIA_ID, vector<string>({ context->objectPtr->GetUri() }));
3512 DataShareValuesBucket valuesBucket;
3513 valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, context->isHidden ? IS_HIDDEN : NOT_HIDDEN);
3514
3515 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3516 if (changedRows < 0) {
3517 context->SaveError(changedRows);
3518 NAPI_ERR_LOG("Failed to modify hidden state, err: %{public}d", changedRows);
3519 } else {
3520 context->objectPtr->SetHidden(context->isHidden);
3521 context->changedRows = changedRows;
3522 }
3523 }
3524
UserFileMgrSetHiddenComplete(napi_env env,napi_status status,void * data)3525 static void UserFileMgrSetHiddenComplete(napi_env env, napi_status status, void *data)
3526 {
3527 FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3528 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3529 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3530 jsContext->status = false;
3531
3532 if (context->error == ERR_DEFAULT) {
3533 napi_create_int32(env, context->changedRows, &jsContext->data);
3534 jsContext->status = true;
3535 napi_get_undefined(env, &jsContext->error);
3536 } else {
3537 context->HandleError(env, jsContext->error);
3538 napi_get_undefined(env, &jsContext->data);
3539 }
3540
3541 if (context->work != nullptr) {
3542 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3543 context->work, *jsContext);
3544 }
3545 delete context;
3546 }
3547
UserFileMgrSetHidden(napi_env env,napi_callback_info info)3548 napi_value FileAssetNapi::UserFileMgrSetHidden(napi_env env, napi_callback_info info)
3549 {
3550 MediaLibraryTracer tracer;
3551 tracer.Start("UserFileMgrSetHidden");
3552
3553 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3554 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3555 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isHidden),
3556 JS_ERR_PARAMETER_INVALID);
3557 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3558 CHECK_NULLPTR_RET(asyncContext->objectPtr);
3559
3560 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetHidden",
3561 UserFileMgrSetHiddenExecute, UserFileMgrSetHiddenComplete);
3562 }
3563
UserFileMgrSetPendingExecute(napi_env env,void * data)3564 static void UserFileMgrSetPendingExecute(napi_env env, void *data)
3565 {
3566 MediaLibraryTracer tracer;
3567 tracer.Start("UserFileMgrSetPendingExecute");
3568 auto *context = static_cast<FileAssetAsyncContext*>(data);
3569
3570 string uri = MEDIALIBRARY_DATA_URI + "/";
3571 if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3572 context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3573 uri += UFM_PHOTO + "/" + OPRN_PENDING;
3574 } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
3575 uri += UFM_AUDIO + "/" + OPRN_PENDING;
3576 } else {
3577 context->error = OHOS_INVALID_PARAM_CODE;
3578 return;
3579 }
3580
3581 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3582 Uri updateAssetUri(uri);
3583 DataSharePredicates predicates;
3584 DataShareValuesBucket valuesBucket;
3585 int32_t changedRows;
3586 valuesBucket.Put(MediaColumn::MEDIA_TIME_PENDING, context->isPending ? 1 : 0);
3587 predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3588 predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
3589
3590 changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3591 if (changedRows < 0) {
3592 context->SaveError(E_FAIL);
3593 NAPI_ERR_LOG("Failed to modify pending state, err: %{public}d", changedRows);
3594 } else {
3595 context->changedRows = changedRows;
3596 context->objectPtr->SetTimePending((context->isPending) ? 1 : 0);
3597 }
3598 }
3599
UserFileMgrSetPendingComplete(napi_env env,napi_status status,void * data)3600 static void UserFileMgrSetPendingComplete(napi_env env, napi_status status, void *data)
3601 {
3602 FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3603 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3604 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3605 jsContext->status = false;
3606
3607 if (context->error == ERR_DEFAULT) {
3608 napi_create_int32(env, context->changedRows, &jsContext->data);
3609 jsContext->status = true;
3610 napi_get_undefined(env, &jsContext->error);
3611 } else {
3612 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3613 "Failed to modify pending state");
3614 napi_get_undefined(env, &jsContext->data);
3615 }
3616
3617 if (context->work != nullptr) {
3618 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3619 context->work, *jsContext);
3620 }
3621 delete context;
3622 }
3623
UserFileMgrSetPending(napi_env env,napi_callback_info info)3624 napi_value FileAssetNapi::UserFileMgrSetPending(napi_env env, napi_callback_info info)
3625 {
3626 MediaLibraryTracer tracer;
3627 tracer.Start("UserFileMgrSetPending");
3628
3629 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3630 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3631 CHECK_ARGS_THROW_INVALID_PARAM(env,
3632 MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isPending));
3633 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3634 CHECK_NULLPTR_RET(asyncContext->objectPtr);
3635
3636 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetPending",
3637 UserFileMgrSetPendingExecute, UserFileMgrSetPendingComplete);
3638 }
3639
UserFileMgrGetExifExecute(napi_env env,void * data)3640 static void UserFileMgrGetExifExecute(napi_env env, void *data) {}
3641
CheckNapiCallerPermission(const std::string & permission)3642 static bool CheckNapiCallerPermission(const std::string &permission)
3643 {
3644 MediaLibraryTracer tracer;
3645 tracer.Start("CheckNapiCallerPermission");
3646
3647 AccessTokenID tokenCaller = IPCSkeleton::GetSelfTokenID();
3648 int res = AccessTokenKit::VerifyAccessToken(tokenCaller, permission);
3649 if (res != PermissionState::PERMISSION_GRANTED) {
3650 NAPI_ERR_LOG("Have no media permission: %{public}s", permission.c_str());
3651 return false;
3652 }
3653
3654 return true;
3655 }
3656
UserFileMgrGetExifComplete(napi_env env,napi_status status,void * data)3657 static void UserFileMgrGetExifComplete(napi_env env, napi_status status, void *data)
3658 {
3659 auto *context = static_cast<FileAssetAsyncContext*>(data);
3660 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3661 auto jsContext = make_unique<JSAsyncContextOutput>();
3662 jsContext->status = false;
3663
3664 auto *obj = context->objectInfo;
3665 nlohmann::json allExifJson;
3666 if (!obj->GetAllExif().empty() && nlohmann::json::accept(obj->GetAllExif())) {
3667 allExifJson = nlohmann::json::parse(obj->GetAllExif());
3668 }
3669 if (allExifJson.is_discarded() || obj->GetAllExif().empty()) {
3670 NAPI_ERR_LOG("parse json failed");
3671 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
3672 "parse json failed");
3673 napi_get_undefined(env, &jsContext->data);
3674 } else {
3675 const std::string PERMISSION_NAME_MEDIA_LOCATION = "ohos.permission.MEDIA_LOCATION";
3676 auto err = CheckNapiCallerPermission(PERMISSION_NAME_MEDIA_LOCATION);
3677 if (err == false) {
3678 allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LATITUDE);
3679 allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LONGITUDE);
3680 allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LATITUDE_REF);
3681 allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LONGITUDE_REF);
3682 }
3683 allExifJson[PHOTO_DATA_IMAGE_USER_COMMENT] = obj->GetUserComment();
3684 allExifJson[PHOTO_DATA_IMAGE_IMAGE_DESCRIPTION] =
3685 AppFileService::SandboxHelper::Decode(allExifJson[PHOTO_DATA_IMAGE_IMAGE_DESCRIPTION]);
3686 string allExifJsonStr = allExifJson.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
3687 napi_create_string_utf8(env, allExifJsonStr.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
3688 jsContext->status = true;
3689 napi_get_undefined(env, &jsContext->error);
3690 }
3691
3692 if (context->work != nullptr) {
3693 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3694 context->work, *jsContext);
3695 }
3696 delete context;
3697 }
3698
JSGetExif(napi_env env,napi_callback_info info)3699 napi_value FileAssetNapi::JSGetExif(napi_env env, napi_callback_info info)
3700 {
3701 MediaLibraryTracer tracer;
3702 tracer.Start("JSGetExif");
3703
3704 if (!MediaLibraryNapiUtils::IsSystemApp()) {
3705 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3706 return nullptr;
3707 }
3708
3709 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3710 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_ONE),
3711 JS_ERR_PARAMETER_INVALID);
3712 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3713 CHECK_NULLPTR_RET(asyncContext->objectPtr);
3714
3715 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetExif", UserFileMgrGetExifExecute,
3716 UserFileMgrGetExifComplete);
3717 }
3718
UserFileMgrSetUserCommentComplete(napi_env env,napi_status status,void * data)3719 static void UserFileMgrSetUserCommentComplete(napi_env env, napi_status status, void *data)
3720 {
3721 auto *context = static_cast<FileAssetAsyncContext*>(data);
3722 auto jsContext = make_unique<JSAsyncContextOutput>();
3723 jsContext->status = false;
3724
3725 if (context->error == ERR_DEFAULT) {
3726 napi_create_int32(env, context->changedRows, &jsContext->data);
3727 jsContext->status = true;
3728 napi_get_undefined(env, &jsContext->error);
3729 } else {
3730 context->HandleError(env, jsContext->error);
3731 napi_get_undefined(env, &jsContext->data);
3732 }
3733
3734 if (context->work != nullptr) {
3735 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3736 context->work, *jsContext);
3737 }
3738 delete context;
3739 }
3740
UserFileMgrSetUserCommentExecute(napi_env env,void * data)3741 static void UserFileMgrSetUserCommentExecute(napi_env env, void *data)
3742 {
3743 MediaLibraryTracer tracer;
3744 tracer.Start("UserFileMgrSetUserCommentExecute");
3745
3746 auto *context = static_cast<FileAssetAsyncContext *>(data);
3747 string uri = UFM_SET_USER_COMMENT;
3748 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3749 Uri editUserCommentUri(uri);
3750 DataSharePredicates predicates;
3751 DataShareValuesBucket valuesBucket;
3752 valuesBucket.Put(PhotoColumn::PHOTO_USER_COMMENT, context->userComment);
3753 predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3754 predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
3755 int32_t changedRows = UserFileClient::Update(editUserCommentUri, predicates, valuesBucket);
3756 if (changedRows < 0) {
3757 context->SaveError(changedRows);
3758 NAPI_ERR_LOG("Failed to modify user comment, err: %{public}d", changedRows);
3759 } else {
3760 context->objectPtr->SetUserComment(context->userComment);
3761 context->changedRows = changedRows;
3762 }
3763 }
3764
UserFileMgrSetUserComment(napi_env env,napi_callback_info info)3765 napi_value FileAssetNapi::UserFileMgrSetUserComment(napi_env env, napi_callback_info info)
3766 {
3767 MediaLibraryTracer tracer;
3768 tracer.Start("UserFileMgrSetUserComment");
3769
3770 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3771 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3772 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->userComment),
3773 JS_ERR_PARAMETER_INVALID);
3774 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3775 if (asyncContext->objectPtr == nullptr) {
3776 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3777 return nullptr;
3778 }
3779
3780 if (asyncContext->userComment.length() > USER_COMMENT_MAX_LEN) {
3781 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "user comment too long");
3782 return nullptr;
3783 }
3784
3785 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetUserComment",
3786 UserFileMgrSetUserCommentExecute, UserFileMgrSetUserCommentComplete);
3787 }
3788
ParseArgsPhotoAccessHelperOpen(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context,bool isReadOnly)3789 static napi_value ParseArgsPhotoAccessHelperOpen(napi_env env, napi_callback_info info,
3790 unique_ptr<FileAssetAsyncContext> &context, bool isReadOnly)
3791 {
3792 if (!isReadOnly && !MediaLibraryNapiUtils::IsSystemApp()) {
3793 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3794 return nullptr;
3795 }
3796 size_t minArgs = ARGS_ZERO;
3797 size_t maxArgs = ARGS_ONE;
3798 if (!isReadOnly) {
3799 minArgs++;
3800 maxArgs++;
3801 }
3802 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3803 JS_ERR_PARAMETER_INVALID);
3804 auto fileUri = context->objectInfo->GetFileUri();
3805 MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3806 context->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
3807
3808 if (isReadOnly) {
3809 context->valuesBucket.Put(MEDIA_FILEMODE, MEDIA_FILEMODE_READONLY);
3810 } else {
3811 string mode;
3812 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], mode),
3813 JS_ERR_PARAMETER_INVALID);
3814 transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
3815 if (!MediaFileUtils::CheckMode(mode)) {
3816 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3817 return nullptr;
3818 }
3819 context->valuesBucket.Put(MEDIA_FILEMODE, mode);
3820 }
3821
3822 napi_value result = nullptr;
3823 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3824 return result;
3825 }
3826
PhotoAccessHelperOpenExecute(napi_env env,void * data)3827 static void PhotoAccessHelperOpenExecute(napi_env env, void *data)
3828 {
3829 MediaLibraryTracer tracer;
3830 tracer.Start("PhotoAccessHelperOpenExecute");
3831
3832 auto *context = static_cast<FileAssetAsyncContext*>(data);
3833 bool isValid = false;
3834 string mode = context->valuesBucket.Get(MEDIA_FILEMODE, isValid);
3835 if (!isValid) {
3836 context->SaveError(-EINVAL);
3837 return;
3838 }
3839 string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
3840 if (!isValid) {
3841 context->SaveError(-EINVAL);
3842 return ;
3843 }
3844
3845 if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
3846 MediaFileUtils::UriAppendKeyValue(fileUri, MediaColumn::MEDIA_TIME_PENDING,
3847 to_string(context->objectPtr->GetTimePending()));
3848 }
3849 Uri openFileUri(fileUri);
3850 int32_t retVal = UserFileClient::OpenFile(openFileUri, mode, context->objectPtr->GetUserId());
3851 if (retVal <= 0) {
3852 context->SaveError(retVal);
3853 NAPI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
3854 } else {
3855 context->fd = retVal;
3856 if (mode.find('w') != string::npos) {
3857 context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
3858 } else {
3859 context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
3860 }
3861 if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
3862 context->objectPtr->SetTimePending(UNCLOSE_FILE_TIMEPENDING);
3863 }
3864 }
3865 }
3866
PhotoAccessHelperOpenCallbackComplete(napi_env env,napi_status status,void * data)3867 static void PhotoAccessHelperOpenCallbackComplete(napi_env env, napi_status status, void *data)
3868 {
3869 MediaLibraryTracer tracer;
3870 tracer.Start("PhotoAccessHelperOpenCallbackComplete");
3871
3872 auto context = static_cast<FileAssetAsyncContext *>(data);
3873 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3874
3875 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3876 jsContext->status = false;
3877
3878 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3879 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3880 if (context->error == ERR_DEFAULT) {
3881 CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->fd, &jsContext->data), JS_INNER_FAIL);
3882 jsContext->status = true;
3883 } else {
3884 context->HandleError(env, jsContext->error);
3885 }
3886
3887 tracer.Finish();
3888 if (context->work != nullptr) {
3889 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3890 context->work, *jsContext);
3891 }
3892 delete context;
3893 }
3894
PhotoAccessHelperOpen(napi_env env,napi_callback_info info)3895 napi_value FileAssetNapi::PhotoAccessHelperOpen(napi_env env, napi_callback_info info)
3896 {
3897 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3898 CHECK_NULLPTR_RET(ParseArgsPhotoAccessHelperOpen(env, info, asyncContext, false));
3899 if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3900 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3901 return nullptr;
3902 }
3903 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3904 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperOpen",
3905 PhotoAccessHelperOpenExecute, PhotoAccessHelperOpenCallbackComplete);
3906 }
3907
ParseArgsPhotoAccessHelperClose(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context)3908 static napi_value ParseArgsPhotoAccessHelperClose(napi_env env, napi_callback_info info,
3909 unique_ptr<FileAssetAsyncContext> &context)
3910 {
3911 size_t minArgs = ARGS_ONE;
3912 size_t maxArgs = ARGS_TWO;
3913 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3914 JS_ERR_PARAMETER_INVALID);
3915 context->valuesBucket.Put(MEDIA_DATA_DB_URI, context->objectInfo->GetFileUri());
3916
3917 int32_t fd = 0;
3918 CHECK_COND(env, MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], fd), JS_ERR_PARAMETER_INVALID);
3919 if (fd <= 0) {
3920 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3921 return nullptr;
3922 }
3923 context->fd = fd;
3924
3925 napi_value result = nullptr;
3926 CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3927 return result;
3928 }
3929
PhotoAccessHelperCloseExecute(napi_env env,void * data)3930 static void PhotoAccessHelperCloseExecute(napi_env env, void *data)
3931 {
3932 MediaLibraryTracer tracer;
3933 tracer.Start("PhotoAccessHelperCloseExecute");
3934
3935 auto *context = static_cast<FileAssetAsyncContext*>(data);
3936 int32_t mediaFd = context->fd;
3937 if (!CheckFileOpenStatus(context, mediaFd)) {
3938 return;
3939 }
3940 UniqueFd uniFd(mediaFd);
3941 string closeUri;
3942 if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3943 context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3944 closeUri = PAH_CLOSE_PHOTO;
3945 } else {
3946 context->SaveError(-EINVAL);
3947 return;
3948 }
3949 MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3950 MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, MediaColumn::MEDIA_TIME_PENDING,
3951 to_string(context->objectPtr->GetTimePending()));
3952 Uri closeAssetUri(closeUri);
3953 int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
3954 if (ret != E_SUCCESS) {
3955 context->SaveError(ret);
3956 } else {
3957 if (context->objectPtr->GetTimePending() == UNCLOSE_FILE_TIMEPENDING) {
3958 context->objectPtr->SetTimePending(0);
3959 }
3960 }
3961 }
3962
PhotoAccessHelperCloseCallbackComplete(napi_env env,napi_status status,void * data)3963 static void PhotoAccessHelperCloseCallbackComplete(napi_env env, napi_status status, void *data)
3964 {
3965 MediaLibraryTracer tracer;
3966 tracer.Start("PhotoAccessHelperCloseCallbackComplete");
3967
3968 auto context = static_cast<FileAssetAsyncContext *>(data);
3969 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3970
3971 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3972 jsContext->status = false;
3973
3974 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3975 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3976 if (context->error == ERR_DEFAULT) {
3977 CHECK_ARGS_RET_VOID(env, napi_create_int32(env, E_SUCCESS, &jsContext->data), JS_INNER_FAIL);
3978 jsContext->status = true;
3979 } else {
3980 context->HandleError(env, jsContext->error);
3981 }
3982
3983 tracer.Finish();
3984 if (context->work != nullptr) {
3985 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3986 context->work, *jsContext);
3987 }
3988 delete context;
3989 }
3990
PhotoAccessHelperClose(napi_env env,napi_callback_info info)3991 napi_value FileAssetNapi::PhotoAccessHelperClose(napi_env env, napi_callback_info info)
3992 {
3993 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3994 CHECK_NULLPTR_RET(ParseArgsPhotoAccessHelperClose(env, info, asyncContext));
3995 if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3996 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3997 return nullptr;
3998 }
3999 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4000
4001 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperClose",
4002 PhotoAccessHelperCloseExecute, PhotoAccessHelperCloseCallbackComplete);
4003 }
4004
getFileAsset(const std::string fileAssetId,const int32_t userId)4005 static shared_ptr<FileAsset> getFileAsset(const std::string fileAssetId, const int32_t userId)
4006 {
4007 DataSharePredicates predicates;
4008 predicates.EqualTo(MediaColumn::MEDIA_ID, fileAssetId);
4009 vector<string> columns = { MediaColumn::MEDIA_ID, MediaColumn::MEDIA_NAME, MediaColumn::MEDIA_FILE_PATH,
4010 MediaColumn::MEDIA_TITLE, MediaColumn::MEDIA_TYPE };
4011 int32_t errCode = 0;
4012 Uri uri(PAH_QUERY_PHOTO_MAP);
4013 auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode, userId);
4014 if (resultSet == nullptr) {
4015 NAPI_INFO_LOG("Failed to get file asset, err: %{public}d", errCode);
4016 return nullptr;
4017 }
4018 auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
4019 shared_ptr<FileAsset> newFileAsset = fetchResult->GetFirstObject();
4020 string newFileAssetUri = MediaFileUtils::GetFileAssetUri(newFileAsset->GetPath(), newFileAsset->GetDisplayName(),
4021 newFileAsset->GetId());
4022 newFileAsset->SetUri(newFileAssetUri);
4023 NAPI_INFO_LOG("New asset, file_id: %{public}d, uri:%{private}s", newFileAsset->GetId(),
4024 newFileAsset->GetUri().c_str());
4025 return newFileAsset;
4026 }
4027
CloneAssetHandlerCompleteCallback(napi_env env,napi_status status,void * data)4028 static void CloneAssetHandlerCompleteCallback(napi_env env, napi_status status, void* data)
4029 {
4030 auto* context = static_cast<FileAssetAsyncContext*>(data);
4031 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4032 auto jsContext = make_unique<JSAsyncContextOutput>();
4033 jsContext->status = false;
4034 int32_t userId = -1;
4035 if (context->error == ERR_DEFAULT) {
4036 napi_value jsFileAsset = nullptr;
4037 int64_t assetId = context->assetId;
4038 userId = context->objectInfo != nullptr ? context->objectInfo->GetFileAssetInstance()->GetUserId() : userId;
4039 if (assetId == 0) {
4040 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
4041 "Clone file asset failed");
4042 napi_get_undefined(env, &jsContext->data);
4043 } else {
4044 shared_ptr<FileAsset> newFileAsset = getFileAsset(to_string(assetId), userId);
4045 CHECK_NULL_PTR_RETURN_VOID(newFileAsset, "newFileAset is null.");
4046
4047 newFileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
4048 jsFileAsset = FileAssetNapi::CreatePhotoAsset(env, newFileAsset);
4049 if (jsFileAsset == nullptr) {
4050 NAPI_ERR_LOG("Failed to clone file asset napi object");
4051 napi_get_undefined(env, &jsContext->data);
4052 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL, "System inner fail");
4053 } else {
4054 NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback jsFileAsset != nullptr");
4055 jsContext->data = jsFileAsset;
4056 napi_get_undefined(env, &jsContext->error);
4057 jsContext->status = true;
4058 }
4059 }
4060 } else {
4061 context->HandleError(env, jsContext->error);
4062 napi_get_undefined(env, &jsContext->data);
4063 }
4064
4065 if (context->work != nullptr) {
4066 MediaLibraryNapiUtils::InvokeJSAsyncMethod(
4067 env, context->deferred, context->callbackRef, context->work, *jsContext);
4068 }
4069 delete context;
4070 }
4071
CloneAssetHandlerExecute(napi_env env,void * data)4072 static void CloneAssetHandlerExecute(napi_env env, void *data)
4073 {
4074 MediaLibraryTracer tracer;
4075 tracer.Start("CloneAssetHandlerExecute");
4076
4077 auto* context = static_cast<FileAssetAsyncContext*>(data);
4078 auto fileAsset = context->objectInfo->GetFileAssetInstance();
4079 if (fileAsset == nullptr) {
4080 context->SaveError(E_FAIL);
4081 NAPI_ERR_LOG("fileAsset is null");
4082 return;
4083 }
4084
4085 DataShare::DataShareValuesBucket valuesBucket;
4086 string uri = PAH_CLONE_ASSET;
4087 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4088 valuesBucket.Put(MediaColumn::MEDIA_ID, fileAsset->GetId());
4089 valuesBucket.Put(MediaColumn::MEDIA_TITLE, context->title);
4090 Uri cloneAssetUri(uri);
4091 int32_t newAssetId = UserFileClient::Insert(cloneAssetUri, valuesBucket);
4092 if (newAssetId < 0) {
4093 context->SaveError(newAssetId);
4094 NAPI_ERR_LOG("Failed to clone asset, ret: %{public}d", newAssetId);
4095 return;
4096 }
4097 context->assetId = newAssetId;
4098 }
4099
PhotoAccessHelperCloneAsset(napi_env env,napi_callback_info info)4100 napi_value FileAssetNapi::PhotoAccessHelperCloneAsset(napi_env env, napi_callback_info info)
4101 {
4102 NAPI_INFO_LOG("PhotoAccessHelperCloneAsset in");
4103
4104 auto asyncContext = make_unique<FileAssetAsyncContext>();
4105 CHECK_COND_WITH_MESSAGE(env,
4106 MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok,
4107 "Failed to get object info");
4108
4109 auto changeRequest = asyncContext->objectInfo;
4110 auto fileAsset = changeRequest->GetFileAssetInstance();
4111 CHECK_COND(env, fileAsset != nullptr, JS_INNER_FAIL);
4112
4113 string title;
4114 MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[ARGS_ZERO], title);
4115
4116 string extension = MediaFileUtils::SplitByChar(fileAsset->GetDisplayName(), '.');
4117 string displayName = title + "." + extension;
4118 CHECK_COND_WITH_MESSAGE(env, MediaFileUtils::CheckDisplayName(displayName, true) == E_OK, "Input title is invalid");
4119
4120 asyncContext->title = title;
4121 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CloneAssetHandlerExecute",
4122 CloneAssetHandlerExecute, CloneAssetHandlerCompleteCallback);
4123 }
4124
PhotoAccessHelperCommitModify(napi_env env,napi_callback_info info)4125 napi_value FileAssetNapi::PhotoAccessHelperCommitModify(napi_env env, napi_callback_info info)
4126 {
4127 MediaLibraryTracer tracer;
4128 tracer.Start("PhotoAccessHelperCommitModify");
4129
4130 napi_value ret = nullptr;
4131 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4132 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4133 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4134 NAPI_ASSERT(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4135 "Failed to parse js args");
4136 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4137 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
4138
4139 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCommitModify",
4140 JSCommitModifyExecute, JSCommitModifyCompleteCallback);
4141 }
4142
PhotoAccessHelperFavoriteComplete(napi_env env,napi_status status,void * data)4143 static void PhotoAccessHelperFavoriteComplete(napi_env env, napi_status status, void *data)
4144 {
4145 FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
4146 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4147 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4148 jsContext->status = false;
4149
4150 if (context->error == ERR_DEFAULT) {
4151 napi_create_int32(env, context->changedRows, &jsContext->data);
4152 jsContext->status = true;
4153 napi_get_undefined(env, &jsContext->error);
4154 } else {
4155 context->HandleError(env, jsContext->error);
4156 napi_get_undefined(env, &jsContext->data);
4157 }
4158
4159 if (context->work != nullptr) {
4160 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4161 context->work, *jsContext);
4162 }
4163 delete context;
4164 }
4165
PhotoAccessHelperFavoriteExecute(napi_env env,void * data)4166 static void PhotoAccessHelperFavoriteExecute(napi_env env, void *data)
4167 {
4168 MediaLibraryTracer tracer;
4169 tracer.Start("PhotoAccessHelperFavoriteExecute");
4170
4171 auto *context = static_cast<FileAssetAsyncContext *>(data);
4172 string uri;
4173 if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
4174 context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
4175 uri = PAH_UPDATE_PHOTO;
4176 } else {
4177 context->SaveError(-EINVAL);
4178 return;
4179 }
4180
4181 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4182 Uri updateAssetUri(uri);
4183 DataSharePredicates predicates;
4184 DataShareValuesBucket valuesBucket;
4185 int32_t changedRows = 0;
4186 valuesBucket.Put(MediaColumn::MEDIA_IS_FAV, context->isFavorite ? IS_FAV : NOT_FAV);
4187 NAPI_INFO_LOG("update asset %{public}d favorite to %{public}d", context->objectPtr->GetId(),
4188 context->isFavorite ? IS_FAV : NOT_FAV);
4189 predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
4190 predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
4191
4192 changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
4193 if (changedRows < 0) {
4194 context->SaveError(changedRows);
4195 NAPI_ERR_LOG("Failed to modify favorite state, err: %{public}d", changedRows);
4196 } else {
4197 context->objectPtr->SetFavorite(context->isFavorite);
4198 context->changedRows = changedRows;
4199 }
4200 }
4201
PhotoAccessHelperFavorite(napi_env env,napi_callback_info info)4202 napi_value FileAssetNapi::PhotoAccessHelperFavorite(napi_env env, napi_callback_info info)
4203 {
4204 MediaLibraryTracer tracer;
4205 tracer.Start("PhotoAccessHelperFavorite");
4206
4207 if (!MediaLibraryNapiUtils::IsSystemApp()) {
4208 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4209 return nullptr;
4210 }
4211
4212 napi_value ret = nullptr;
4213 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4214 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4215 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4216 NAPI_ASSERT(
4217 env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isFavorite) == napi_ok,
4218 "Failed to parse js args");
4219 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4220 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
4221
4222 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperFavorite",
4223 PhotoAccessHelperFavoriteExecute, PhotoAccessHelperFavoriteComplete);
4224 }
4225
PhotoAccessHelperGetThumbnailData(napi_env env,napi_callback_info info)4226 napi_value FileAssetNapi::PhotoAccessHelperGetThumbnailData(napi_env env, napi_callback_info info)
4227 {
4228 MediaLibraryTracer tracer;
4229 tracer.Start("PhotoAccessHelperGetThumbnailData");
4230 if (!MediaLibraryNapiUtils::IsSystemApp()) {
4231 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4232 return nullptr;
4233 }
4234 napi_value result = nullptr;
4235 NAPI_CALL(env, napi_get_undefined(env, &result));
4236 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4237 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
4238 CHECK_COND_RET(MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_TWO) ==
4239 napi_ok, result, "Failed to get object info");
4240 result = GetJSArgsForGetThumbnailData(env, asyncContext->argc, asyncContext->argv, asyncContext);
4241 ASSERT_NULLPTR_CHECK(env, result);
4242 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4243 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
4244 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4245 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetThumbnailData",
4246 [](napi_env env, void *data) {
4247 auto context = static_cast<FileAssetAsyncContext*>(data);
4248 JSGetThumbnailDataExecute(env, context);
4249 },
4250 reinterpret_cast<CompleteCallback>(JSGetThumbnailDataCompleteCallback));
4251
4252 return result;
4253 }
4254
PhotoAccessHelperGetThumbnail(napi_env env,napi_callback_info info)4255 napi_value FileAssetNapi::PhotoAccessHelperGetThumbnail(napi_env env, napi_callback_info info)
4256 {
4257 MediaLibraryTracer tracer;
4258 tracer.Start("PhotoAccessHelperGetThumbnail");
4259
4260 napi_value result = nullptr;
4261 NAPI_CALL(env, napi_get_undefined(env, &result));
4262 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4263 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
4264
4265 CHECK_COND_RET(MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_TWO) ==
4266 napi_ok, result, "Failed to get object info");
4267 result = GetJSArgsForGetThumbnail(env, asyncContext->argc, asyncContext->argv, asyncContext);
4268 ASSERT_NULLPTR_CHECK(env, result);
4269 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4270 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
4271 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4272 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetThumbnail",
4273 [](napi_env env, void *data) {
4274 auto context = static_cast<FileAssetAsyncContext*>(data);
4275 JSGetThumbnailExecute(context);
4276 },
4277 reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback));
4278
4279 return result;
4280 }
4281
PhotoAccessHelperGetKeyFrameThumbnail(napi_env env,napi_callback_info info)4282 napi_value FileAssetNapi::PhotoAccessHelperGetKeyFrameThumbnail(napi_env env, napi_callback_info info)
4283 {
4284 MediaLibraryTracer tracer;
4285 tracer.Start("PhotoAccessHelperGetKeyFrameThumbnail");
4286 if (!MediaLibraryNapiUtils::IsSystemApp()) {
4287 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4288 return nullptr;
4289 }
4290 napi_value result = nullptr;
4291 NAPI_CALL(env, napi_get_undefined(env, &result));
4292 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4293 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
4294 CHECK_COND_RET(MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_TWO) ==
4295 napi_ok, result, "Failed to get object info");
4296 result = GetJSArgsForGetKeyFrameThumbnail(env, asyncContext->argc, asyncContext->argv, asyncContext);
4297 ASSERT_NULLPTR_CHECK(env, result);
4298 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4299 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
4300 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4301 result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetKeyFrameThumbnail",
4302 [](napi_env env, void *data) {
4303 auto context = static_cast<FileAssetAsyncContext*>(data);
4304 JSGetKeyFrameThumbnailExecute(context);
4305 },
4306 reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback));
4307
4308 return result;
4309 }
4310
PhotoAccessHelperRequestPhoto(napi_env env,napi_callback_info info)4311 napi_value FileAssetNapi::PhotoAccessHelperRequestPhoto(napi_env env, napi_callback_info info)
4312 {
4313 MediaLibraryTracer tracer;
4314 tracer.Start("PhotoAccessHelperRequestPhoto");
4315
4316 // request Photo function in API11 is system api, maybe public soon
4317 if (!MediaLibraryNapiUtils::IsSystemApp()) {
4318 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4319 return nullptr;
4320 }
4321
4322 napi_value result = nullptr;
4323 NAPI_CALL(env, napi_get_undefined(env, &result));
4324 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4325 CHECK_COND_WITH_MESSAGE(env, asyncContext != nullptr, "asyncContext context is null");
4326 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext,
4327 ARGS_ONE, ARGS_TWO) == napi_ok, "Failed to get object info");
4328 if (asyncContext->callbackRef == nullptr) {
4329 NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Can not get callback function");
4330 return nullptr;
4331 }
4332 // use current parse args function temporary
4333 RequestPhotoType type = RequestPhotoType::REQUEST_ALL_THUMBNAILS;
4334 result = GetPhotoRequestArgs(env, asyncContext->argc, asyncContext->argv, asyncContext, type);
4335 ASSERT_NULLPTR_CHECK(env, result);
4336 auto obj = asyncContext->objectInfo;
4337 napi_value ret = nullptr;
4338 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectInfo, ret, "FileAsset is nullptr");
4339
4340 RequestPhotoParams params = {
4341 .uri = obj->fileAssetPtr->GetUri(),
4342 .path = obj->fileAssetPtr->GetFilePath(),
4343 .size = asyncContext->size,
4344 .type = type
4345 };
4346 static std::once_flag onceFlag;
4347 std::call_once(onceFlag, []() mutable {
4348 thumbnailManager_ = ThumbnailManager::GetInstance();
4349 if (thumbnailManager_ != nullptr) {
4350 thumbnailManager_->Init();
4351 }
4352 });
4353 string requestId;
4354 if (thumbnailManager_ != nullptr) {
4355 requestId = thumbnailManager_->AddPhotoRequest(params, env, asyncContext->callbackRef);
4356 }
4357 napi_create_string_utf8(env, requestId.c_str(), NAPI_AUTO_LENGTH, &result);
4358 return result;
4359 }
4360
PhotoAccessHelperCancelPhotoRequest(napi_env env,napi_callback_info info)4361 napi_value FileAssetNapi::PhotoAccessHelperCancelPhotoRequest(napi_env env, napi_callback_info info)
4362 {
4363 MediaLibraryTracer tracer;
4364 tracer.Start("PhotoAccessHelperCancelPhotoRequest");
4365
4366 // request Photo function in API11 is system api, maybe public soon
4367 if (!MediaLibraryNapiUtils::IsSystemApp()) {
4368 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4369 return nullptr;
4370 }
4371
4372 napi_value ret = nullptr;
4373 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4374 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4375
4376 string requestKey;
4377 CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ONE,
4378 ARGS_ONE), OHOS_INVALID_PARAM_CODE);
4379 CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[ARGS_ZERO], requestKey),
4380 OHOS_INVALID_PARAM_CODE);
4381 napi_value jsResult = nullptr;
4382 napi_get_undefined(env, &jsResult);
4383
4384 if (thumbnailManager_ != nullptr) {
4385 thumbnailManager_->RemovePhotoRequest(requestKey);
4386 }
4387 return jsResult;
4388 }
4389
PhotoAccessHelperSetHiddenExecute(napi_env env,void * data)4390 static void PhotoAccessHelperSetHiddenExecute(napi_env env, void *data)
4391 {
4392 MediaLibraryTracer tracer;
4393 tracer.Start("PhotoAccessHelperSetHiddenExecute");
4394
4395 auto *context = static_cast<FileAssetAsyncContext *>(data);
4396 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4397 if (context->objectPtr->GetMediaType() != MEDIA_TYPE_IMAGE &&
4398 context->objectPtr->GetMediaType() != MEDIA_TYPE_VIDEO) {
4399 context->SaveError(-EINVAL);
4400 return;
4401 }
4402
4403 string uri = PAH_HIDE_PHOTOS;
4404 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4405 Uri updateAssetUri(uri);
4406 DataSharePredicates predicates;
4407 predicates.In(MediaColumn::MEDIA_ID, vector<string>({ context->objectPtr->GetUri() }));
4408 DataShareValuesBucket valuesBucket;
4409 valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, context->isHidden ? IS_HIDDEN : NOT_HIDDEN);
4410
4411 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
4412 if (changedRows < 0) {
4413 context->SaveError(changedRows);
4414 NAPI_ERR_LOG("Failed to modify hidden state, err: %{public}d", changedRows);
4415 } else {
4416 context->objectPtr->SetHidden(context->isHidden);
4417 context->changedRows = changedRows;
4418 }
4419 }
4420
PhotoAccessHelperSetHiddenComplete(napi_env env,napi_status status,void * data)4421 static void PhotoAccessHelperSetHiddenComplete(napi_env env, napi_status status, void *data)
4422 {
4423 auto *context = static_cast<FileAssetAsyncContext*>(data);
4424 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4425 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4426 jsContext->status = false;
4427
4428 if (context->error == ERR_DEFAULT) {
4429 napi_create_int32(env, context->changedRows, &jsContext->data);
4430 jsContext->status = true;
4431 napi_get_undefined(env, &jsContext->error);
4432 } else {
4433 context->HandleError(env, jsContext->error);
4434 napi_get_undefined(env, &jsContext->data);
4435 }
4436
4437 if (context->work != nullptr) {
4438 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4439 context->work, *jsContext);
4440 }
4441 delete context;
4442 }
4443
PhotoAccessHelperSetHidden(napi_env env,napi_callback_info info)4444 napi_value FileAssetNapi::PhotoAccessHelperSetHidden(napi_env env, napi_callback_info info)
4445 {
4446 MediaLibraryTracer tracer;
4447 tracer.Start("PhotoAccessHelperSetHidden");
4448
4449 if (!MediaLibraryNapiUtils::IsSystemApp()) {
4450 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4451 return nullptr;
4452 }
4453
4454 napi_value ret = nullptr;
4455 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4456 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4457 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4458 NAPI_ASSERT(
4459 env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isHidden) == napi_ok,
4460 "Failed to parse js args");
4461 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4462 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
4463
4464 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetHidden",
4465 PhotoAccessHelperSetHiddenExecute, PhotoAccessHelperSetHiddenComplete);
4466 }
4467
PhotoAccessHelperSetPendingExecute(napi_env env,void * data)4468 static void PhotoAccessHelperSetPendingExecute(napi_env env, void *data)
4469 {
4470 MediaLibraryTracer tracer;
4471 tracer.Start("PhotoAccessHelperSetPendingExecute");
4472
4473 auto *context = static_cast<FileAssetAsyncContext *>(data);
4474 string uri = MEDIALIBRARY_DATA_URI + "/";
4475 if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
4476 context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
4477 uri += PAH_PHOTO + "/" + OPRN_PENDING;
4478 } else {
4479 context->SaveError(-EINVAL);
4480 return;
4481 }
4482
4483 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4484 Uri updateAssetUri(uri);
4485 DataSharePredicates predicates;
4486 DataShareValuesBucket valuesBucket;
4487 int32_t changedRows = 0;
4488 valuesBucket.Put(MediaColumn::MEDIA_TIME_PENDING, context->isPending ? 1 : 0);
4489 predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
4490 predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
4491
4492 changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
4493 if (changedRows < 0) {
4494 if (changedRows == E_PERMISSION_DENIED) {
4495 context->error = OHOS_PERMISSION_DENIED_CODE;
4496 } else {
4497 context->SaveError(changedRows);
4498 }
4499
4500 NAPI_ERR_LOG("Failed to modify pending state, err: %{public}d", changedRows);
4501 } else {
4502 context->changedRows = changedRows;
4503 context->objectPtr->SetTimePending((context->isPending) ? 1 : 0);
4504 }
4505 }
4506
PhotoAccessHelperSetPendingComplete(napi_env env,napi_status status,void * data)4507 static void PhotoAccessHelperSetPendingComplete(napi_env env, napi_status status, void *data)
4508 {
4509 auto *context = static_cast<FileAssetAsyncContext*>(data);
4510 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4511 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4512 jsContext->status = false;
4513
4514 if (context->error == ERR_DEFAULT) {
4515 napi_create_int32(env, context->changedRows, &jsContext->data);
4516 jsContext->status = true;
4517 napi_get_undefined(env, &jsContext->error);
4518 } else {
4519 context->HandleError(env, jsContext->error);
4520 napi_get_undefined(env, &jsContext->data);
4521 }
4522
4523 if (context->work != nullptr) {
4524 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4525 context->work, *jsContext);
4526 }
4527 delete context;
4528 }
4529
PhotoAccessHelperSetPending(napi_env env,napi_callback_info info)4530 napi_value FileAssetNapi::PhotoAccessHelperSetPending(napi_env env, napi_callback_info info)
4531 {
4532 MediaLibraryTracer tracer;
4533 tracer.Start("PhotoAccessHelperSetPending");
4534
4535 if (!MediaLibraryNapiUtils::IsSystemApp()) {
4536 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4537 return nullptr;
4538 }
4539
4540 napi_value ret = nullptr;
4541 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4542 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4543 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4544 CHECK_COND_WITH_MESSAGE(env,
4545 MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isPending) == napi_ok,
4546 "Failed to parse js args");
4547 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4548 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
4549
4550 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetPending",
4551 PhotoAccessHelperSetPendingExecute, PhotoAccessHelperSetPendingComplete);
4552 }
4553
PhotoAccessHelperSetUserCommentComplete(napi_env env,napi_status status,void * data)4554 static void PhotoAccessHelperSetUserCommentComplete(napi_env env, napi_status status, void *data)
4555 {
4556 auto *context = static_cast<FileAssetAsyncContext*>(data);
4557 auto jsContext = make_unique<JSAsyncContextOutput>();
4558 jsContext->status = false;
4559
4560 if (context->error == ERR_DEFAULT) {
4561 napi_create_int32(env, context->changedRows, &jsContext->data);
4562 jsContext->status = true;
4563 napi_get_undefined(env, &jsContext->error);
4564 } else {
4565 context->HandleError(env, jsContext->error);
4566 napi_get_undefined(env, &jsContext->data);
4567 }
4568
4569 if (context->work != nullptr) {
4570 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4571 context->work, *jsContext);
4572 }
4573 delete context;
4574 }
4575
UserFileMgrGetJsonComplete(napi_env env,napi_status status,void * data)4576 static void UserFileMgrGetJsonComplete(napi_env env, napi_status status, void *data)
4577 {
4578 MediaLibraryTracer tracer;
4579 tracer.Start("UserFileMgrGetJsonComplete");
4580 auto *context = static_cast<FileAssetAsyncContext *>(data);
4581 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4582 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4583 jsContext->status = false;
4584 if (context->error == ERR_DEFAULT) {
4585 napi_create_string_utf8(env, context->jsonStr.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
4586 napi_get_undefined(env, &jsContext->error);
4587 jsContext->status = true;
4588 } else {
4589 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4590 "UserFileClient is invalid");
4591 napi_get_undefined(env, &jsContext->data);
4592 }
4593
4594 tracer.Finish();
4595 if (context->work != nullptr) {
4596 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4597 context->work, *jsContext);
4598 }
4599 delete context;
4600 }
4601
PhotoAccessHelperSetUserCommentExecute(napi_env env,void * data)4602 static void PhotoAccessHelperSetUserCommentExecute(napi_env env, void *data)
4603 {
4604 MediaLibraryTracer tracer;
4605 tracer.Start("PhotoAccessHelperSetUserCommentExecute");
4606
4607 auto *context = static_cast<FileAssetAsyncContext *>(data);
4608
4609 string uri = PAH_EDIT_USER_COMMENT_PHOTO;
4610 MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4611 Uri editUserCommentUri(uri);
4612 DataSharePredicates predicates;
4613 DataShareValuesBucket valuesBucket;
4614 valuesBucket.Put(PhotoColumn::PHOTO_USER_COMMENT, context->userComment);
4615 predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
4616 predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
4617 int32_t changedRows = UserFileClient::Update(editUserCommentUri, predicates, valuesBucket);
4618 if (changedRows < 0) {
4619 context->SaveError(changedRows);
4620 NAPI_ERR_LOG("Failed to modify user comment, err: %{public}d", changedRows);
4621 } else {
4622 context->objectPtr->SetUserComment(context->userComment);
4623 context->changedRows = changedRows;
4624 }
4625 }
4626
PhotoAccessHelperSetUserComment(napi_env env,napi_callback_info info)4627 napi_value FileAssetNapi::PhotoAccessHelperSetUserComment(napi_env env, napi_callback_info info)
4628 {
4629 MediaLibraryTracer tracer;
4630 tracer.Start("PhotoAccessHelperSetUserComment");
4631
4632 if (!MediaLibraryNapiUtils::IsSystemApp()) {
4633 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4634 return nullptr;
4635 }
4636
4637 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4638 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4639 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->userComment),
4640 JS_ERR_PARAMETER_INVALID);
4641 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4642 if (asyncContext->objectPtr == nullptr) {
4643 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
4644 return nullptr;
4645 }
4646
4647 if (asyncContext->userComment.length() > USER_COMMENT_MAX_LEN) {
4648 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "user comment too long");
4649 return nullptr;
4650 }
4651
4652 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetUserComment",
4653 PhotoAccessHelperSetUserCommentExecute, PhotoAccessHelperSetUserCommentComplete);
4654 }
4655
PhotoAccessHelperGetAnalysisData(napi_env env,napi_callback_info info)4656 napi_value FileAssetNapi::PhotoAccessHelperGetAnalysisData(napi_env env, napi_callback_info info)
4657 {
4658 MediaLibraryTracer tracer;
4659 tracer.Start("PhotoAccessHelperGetAnalysisData");
4660
4661 napi_value result = nullptr;
4662 NAPI_CALL(env, napi_get_undefined(env, &result));
4663 unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4664 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
4665 CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext, asyncContext->analysisType),
4666 JS_ERR_PARAMETER_INVALID);
4667 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4668 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
4669 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4670 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetAnalysisData",
4671 [](napi_env env, void *data) {
4672 auto context = static_cast<FileAssetAsyncContext*>(data);
4673 JSGetAnalysisDataExecute(context);
4674 },
4675 reinterpret_cast<CompleteCallback>(JSGetAnalysisDataCompleteCallback));
4676 }
4677
UserFileMgrGetJsonExecute(napi_env env,void * data)4678 static void UserFileMgrGetJsonExecute(napi_env env, void *data)
4679 {
4680 MediaLibraryTracer tracer;
4681 tracer.Start("UserFileMgrGetJsonExecute");
4682 auto *context = static_cast<FileAssetAsyncContext *>(data);
4683 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4684 context->jsonStr = context->objectPtr->GetAssetJson();
4685 return;
4686 }
4687
UserFileMgrGetJson(napi_env env,napi_callback_info info)4688 napi_value FileAssetNapi::UserFileMgrGetJson(napi_env env, napi_callback_info info)
4689 {
4690 MediaLibraryTracer tracer;
4691 tracer.Start("UserFileMgrGetJson");
4692 auto asyncContext = make_unique<FileAssetAsyncContext>();
4693 asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4694 NAPI_ASSERT(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4695 "Failed to parse js args");
4696 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4697 napi_value ret = nullptr;
4698 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
4699 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetJson",
4700 UserFileMgrGetJsonExecute, UserFileMgrGetJsonComplete);
4701 }
4702
GetEditTimeFromResultSet(const shared_ptr<DataShare::DataShareResultSet> & resultSet,int64_t & editTime)4703 static bool GetEditTimeFromResultSet(const shared_ptr<DataShare::DataShareResultSet> &resultSet,
4704 int64_t &editTime)
4705 {
4706 if (resultSet == nullptr) {
4707 NAPI_ERR_LOG("ResultSet is null");
4708 return false;
4709 }
4710 int32_t count = 0;
4711 int32_t errCode = resultSet->GetRowCount(count);
4712 if (errCode != DataShare::E_OK) {
4713 NAPI_ERR_LOG("Can not get row count from resultSet, errCode=%{public}d", errCode);
4714 return false;
4715 }
4716 if (count == 0) {
4717 NAPI_ERR_LOG("Can not find photo edit time from database");
4718 return false;
4719 }
4720 errCode = resultSet->GoToFirstRow();
4721 if (errCode != DataShare::E_OK) {
4722 NAPI_ERR_LOG("ResultSet GotoFirstRow failed, errCode=%{public}d", errCode);
4723 return false;
4724 }
4725 int32_t index = 0;
4726 errCode = resultSet->GetColumnIndex(PhotoColumn::PHOTO_EDIT_TIME, index);
4727 if (errCode != DataShare::E_OK) {
4728 NAPI_ERR_LOG("ResultSet GetColumnIndex failed, errCode=%{public}d", errCode);
4729 return false;
4730 }
4731 errCode = resultSet->GetLong(index, editTime);
4732 if (errCode != DataShare::E_OK) {
4733 NAPI_ERR_LOG("ResultSet GetLong failed, errCode=%{public}d", errCode);
4734 return false;
4735 }
4736 return true;
4737 }
4738
PhotoAccessHelperIsEditedExecute(napi_env env,void * data)4739 static void PhotoAccessHelperIsEditedExecute(napi_env env, void *data)
4740 {
4741 MediaLibraryTracer tracer;
4742 tracer.Start("PhotoAccessHelperIsEditedExecute");
4743 auto *context = static_cast<FileAssetAsyncContext *>(data);
4744 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4745 int32_t fileId = context->objectPtr->GetId();
4746 string queryUriStr = PAH_QUERY_PHOTO;
4747 MediaLibraryNapiUtils::UriAppendKeyValue(queryUriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4748 Uri uri(queryUriStr);
4749 DataShare::DataSharePredicates predicates;
4750 predicates.EqualTo(MediaColumn::MEDIA_ID, to_string(fileId));
4751 DataShare::DataShareValuesBucket values;
4752 vector<string> columns = { PhotoColumn::PHOTO_EDIT_TIME };
4753 int32_t errCode = 0;
4754 int64_t editTime = 0;
4755 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
4756 if (!GetEditTimeFromResultSet(resultSet, editTime)) {
4757 if (errCode == E_PERMISSION_DENIED) {
4758 context->error = OHOS_PERMISSION_DENIED_CODE;
4759 } else {
4760 context->SaveError(E_FAIL);
4761 }
4762 } else {
4763 if (editTime == 0) {
4764 context->hasEdit = false;
4765 } else {
4766 context->hasEdit = true;
4767 }
4768 }
4769 }
4770
PhotoAccessHelperIsEditedComplete(napi_env env,napi_status status,void * data)4771 static void PhotoAccessHelperIsEditedComplete(napi_env env, napi_status status, void *data)
4772 {
4773 auto *context = static_cast<FileAssetAsyncContext *>(data);
4774 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4775
4776 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4777 jsContext->status = false;
4778 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4779 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4780
4781 if (context->error == ERR_DEFAULT) {
4782 CHECK_ARGS_RET_VOID(env, napi_get_boolean(env, context->hasEdit, &jsContext->data), JS_INNER_FAIL);
4783 jsContext->status = true;
4784 } else {
4785 context->HandleError(env, jsContext->error);
4786 }
4787
4788 if (context->work != nullptr) {
4789 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4790 context->work, *jsContext);
4791 }
4792 delete context;
4793 }
4794
PhotoAccessHelperIsEdited(napi_env env,napi_callback_info info)4795 napi_value FileAssetNapi::PhotoAccessHelperIsEdited(napi_env env, napi_callback_info info)
4796 {
4797 MediaLibraryTracer tracer;
4798 tracer.Start("PhotoAccessHelperIsEdited");
4799
4800 // edit function in API11 is system api, maybe public soon
4801 if (!MediaLibraryNapiUtils::IsSystemApp()) {
4802 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4803 return nullptr;
4804 }
4805
4806 auto asyncContext = make_unique<FileAssetAsyncContext>();
4807 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4808 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4809 "Failed to parse js args");
4810 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4811 napi_value ret = nullptr;
4812 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
4813 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperIsEdited",
4814 PhotoAccessHelperIsEditedExecute, PhotoAccessHelperIsEditedComplete);
4815 }
4816
QueryPhotoEditDataExists(int32_t fileId,int32_t & hasEditData)4817 static void QueryPhotoEditDataExists(int32_t fileId, int32_t &hasEditData)
4818 {
4819 DataShare::DataSharePredicates predicates;
4820 predicates.EqualTo(MediaColumn::MEDIA_ID, to_string(fileId));
4821 vector<string> columns;
4822 Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_QUERYOPRN_QUERYEDITDATA + "/" + MEDIA_QUERYOPRN_QUERYEDITDATA);
4823 int errCode = 0;
4824 shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
4825 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
4826 NAPI_ERR_LOG("Query failed");
4827 return;
4828 }
4829 if (resultSet->GetInt(0, hasEditData) != NativeRdb::E_OK) {
4830 NAPI_ERR_LOG("Can not get hasEditData");
4831 return;
4832 }
4833 }
4834
ProcessEditData(FileAssetAsyncContext * context,const UniqueFd & uniqueFd)4835 static void ProcessEditData(FileAssetAsyncContext *context, const UniqueFd &uniqueFd)
4836 {
4837 if (context == nullptr) {
4838 NAPI_ERR_LOG("context nullptr");
4839 return;
4840 }
4841 struct stat fileInfo;
4842 if (fstat(uniqueFd.Get(), &fileInfo) == 0) {
4843 off_t fileSize = fileInfo.st_size;
4844 if (fileSize < 0 || fileSize + 1 < 0) {
4845 NAPI_ERR_LOG("fileBuffer error : %{public}ld", static_cast<long>(fileSize));
4846 context->SaveError(E_FAIL);
4847 return;
4848 }
4849 context->editDataBuffer = static_cast<char *>(malloc(fileSize + 1));
4850 if (!context->editDataBuffer) {
4851 NAPI_ERR_LOG("Photo request edit data failed, fd: %{public}d", uniqueFd.Get());
4852 context->SaveError(E_FAIL);
4853 return;
4854 }
4855 ssize_t bytes = read(uniqueFd.Get(), context->editDataBuffer, fileSize);
4856 if (bytes < 0) {
4857 NAPI_ERR_LOG("Read edit data failed, errno: %{public}d", errno);
4858 free(context->editDataBuffer);
4859 context->editDataBuffer = nullptr;
4860 context->SaveError(E_FAIL);
4861 return;
4862 }
4863 context->editDataBuffer[bytes] = '\0';
4864 } else {
4865 NAPI_ERR_LOG("can not get stat errno:%{public}d", errno);
4866 context->SaveError(E_FAIL);
4867 }
4868 }
4869
PhotoAccessHelperRequestEditDataExecute(napi_env env,void * data)4870 static void PhotoAccessHelperRequestEditDataExecute(napi_env env, void *data)
4871 {
4872 MediaLibraryTracer tracer;
4873 tracer.Start("PhotoAccessHelperRequestEditDataExecute");
4874 auto *context = static_cast<FileAssetAsyncContext *>(data);
4875 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4876 int32_t hasEditData = 0;
4877 QueryPhotoEditDataExists(context->objectPtr->GetId(), hasEditData);
4878 if (hasEditData == 0) {
4879 context->editDataBuffer = static_cast<char*>(malloc(1));
4880 if (context->editDataBuffer == nullptr) {
4881 NAPI_ERR_LOG("malloc edit data buffer failed");
4882 context->SaveError(E_FAIL);
4883 return;
4884 }
4885 context->editDataBuffer[0] = '\0';
4886 return;
4887 }
4888 bool isValid = false;
4889 string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
4890 if (!isValid) {
4891 context->error = OHOS_INVALID_PARAM_CODE;
4892 return;
4893 }
4894 MediaFileUtils::UriAppendKeyValue(fileUri, MEDIA_OPERN_KEYWORD, EDIT_DATA_REQUEST);
4895 Uri uri(fileUri);
4896 UniqueFd uniqueFd(UserFileClient::OpenFile(uri, "r"));
4897 if (uniqueFd.Get() <= 0) {
4898 if (uniqueFd.Get() == E_PERMISSION_DENIED) {
4899 context->error = OHOS_PERMISSION_DENIED_CODE;
4900 } else {
4901 context->SaveError(uniqueFd.Get());
4902 }
4903 NAPI_ERR_LOG("Photo request edit data failed, ret: %{public}d", uniqueFd.Get());
4904 } else {
4905 ProcessEditData(context, uniqueFd);
4906 }
4907 }
4908
GetEditDataString(char * editDataBuffer,string & result)4909 static void GetEditDataString(char* editDataBuffer, string& result)
4910 {
4911 if (editDataBuffer == nullptr) {
4912 result = "";
4913 NAPI_WARN_LOG("editDataBuffer is nullptr");
4914 return;
4915 }
4916
4917 string editDataStr(editDataBuffer);
4918 if (!nlohmann::json::accept(editDataStr)) {
4919 result = editDataStr;
4920 return;
4921 }
4922
4923 nlohmann::json editDataJson = nlohmann::json::parse(editDataStr);
4924 if (editDataJson.contains(COMPATIBLE_FORMAT) && editDataJson.contains(FORMAT_VERSION) &&
4925 editDataJson.contains(EDIT_DATA) && editDataJson.contains(APP_ID)) {
4926 // edit data saved by media change request
4927 result = editDataJson.at(EDIT_DATA);
4928 } else {
4929 // edit data saved by commitEditedAsset
4930 result = editDataStr;
4931 }
4932 }
4933
GetEditDataObject(napi_env env,char * editDataBuffer)4934 static napi_value GetEditDataObject(napi_env env, char* editDataBuffer)
4935 {
4936 if (editDataBuffer == nullptr) {
4937 NAPI_WARN_LOG("editDataBuffer is nullptr");
4938 return MediaAssetEditDataNapi::CreateMediaAssetEditData(env, "", "", "");
4939 }
4940
4941 string editDataStr(editDataBuffer);
4942 if (!nlohmann::json::accept(editDataStr)) {
4943 return MediaAssetEditDataNapi::CreateMediaAssetEditData(env, "", "", editDataStr);
4944 }
4945
4946 nlohmann::json editDataJson = nlohmann::json::parse(editDataStr);
4947 if (editDataJson.contains(COMPATIBLE_FORMAT) && editDataJson.contains(FORMAT_VERSION) &&
4948 editDataJson.contains(EDIT_DATA) && editDataJson.contains(APP_ID)) {
4949 // edit data saved by media change request
4950 return MediaAssetEditDataNapi::CreateMediaAssetEditData(env,
4951 editDataJson.at(COMPATIBLE_FORMAT), editDataJson.at(FORMAT_VERSION), editDataJson.at(EDIT_DATA));
4952 }
4953
4954 // edit data saved by commitEditedAsset
4955 return MediaAssetEditDataNapi::CreateMediaAssetEditData(env, "", "", editDataStr);
4956 }
4957
PhotoAccessHelperRequestEditDataComplete(napi_env env,napi_status status,void * data)4958 static void PhotoAccessHelperRequestEditDataComplete(napi_env env, napi_status status, void *data)
4959 {
4960 auto *context = static_cast<FileAssetAsyncContext *>(data);
4961 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4962
4963 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4964 jsContext->status = false;
4965 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4966 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4967
4968 if (context->error == ERR_DEFAULT) {
4969 string editDataStr;
4970 GetEditDataString(context->editDataBuffer, editDataStr);
4971 CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, editDataStr.c_str(),
4972 NAPI_AUTO_LENGTH, &jsContext->data), JS_INNER_FAIL);
4973 jsContext->status = true;
4974 } else {
4975 context->HandleError(env, jsContext->error);
4976 }
4977
4978 if (context->work != nullptr) {
4979 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4980 context->work, *jsContext);
4981 }
4982 if (context->editDataBuffer != nullptr) {
4983 free(context->editDataBuffer);
4984 }
4985 delete context;
4986 }
4987
PhotoAccessHelperGetEditDataComplete(napi_env env,napi_status status,void * data)4988 static void PhotoAccessHelperGetEditDataComplete(napi_env env, napi_status status, void* data)
4989 {
4990 auto* context = static_cast<FileAssetAsyncContext*>(data);
4991 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4992
4993 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4994 jsContext->status = false;
4995 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4996 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4997 if (context->error == ERR_DEFAULT) {
4998 jsContext->data = GetEditDataObject(env, context->editDataBuffer);
4999 jsContext->status = true;
5000 } else {
5001 context->HandleError(env, jsContext->error);
5002 }
5003
5004 if (context->work != nullptr) {
5005 MediaLibraryNapiUtils::InvokeJSAsyncMethod(
5006 env, context->deferred, context->callbackRef, context->work, *jsContext);
5007 }
5008 if (context->editDataBuffer != nullptr) {
5009 free(context->editDataBuffer);
5010 }
5011 delete context;
5012 }
5013
PhotoAccessHelperRequestEditData(napi_env env,napi_callback_info info)5014 napi_value FileAssetNapi::PhotoAccessHelperRequestEditData(napi_env env, napi_callback_info info)
5015 {
5016 MediaLibraryTracer tracer;
5017 tracer.Start("PhotoAccessHelperRequestEditData");
5018
5019 // edit function in API11 is system api, maybe public soon
5020 if (!MediaLibraryNapiUtils::IsSystemApp()) {
5021 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5022 return nullptr;
5023 }
5024
5025 auto asyncContext = make_unique<FileAssetAsyncContext>();
5026 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5027 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
5028 "Failed to parse js args");
5029 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
5030 napi_value ret = nullptr;
5031 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
5032 auto fileUri = asyncContext->objectInfo->GetFileUri();
5033 MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5034 asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
5035 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperRequestEditData",
5036 PhotoAccessHelperRequestEditDataExecute, PhotoAccessHelperRequestEditDataComplete);
5037 }
5038
PhotoAccessHelperGetEditData(napi_env env,napi_callback_info info)5039 napi_value FileAssetNapi::PhotoAccessHelperGetEditData(napi_env env, napi_callback_info info)
5040 {
5041 MediaLibraryTracer tracer;
5042 tracer.Start("PhotoAccessHelperGetEditData");
5043
5044 if (!MediaLibraryNapiUtils::IsSystemApp()) {
5045 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5046 return nullptr;
5047 }
5048
5049 auto asyncContext = make_unique<FileAssetAsyncContext>();
5050 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5051 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
5052 "Failed to parse js args");
5053 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
5054 napi_value ret = nullptr;
5055 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is null");
5056 auto fileUri = asyncContext->objectInfo->GetFileUri();
5057 MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5058 asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
5059 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetEditData",
5060 PhotoAccessHelperRequestEditDataExecute, PhotoAccessHelperGetEditDataComplete);
5061 }
5062
PhotoAccessHelperRequestSourceExecute(napi_env env,void * data)5063 static void PhotoAccessHelperRequestSourceExecute(napi_env env, void *data)
5064 {
5065 MediaLibraryTracer tracer;
5066 tracer.Start("PhotoAccessHelperRequestSourceExecute");
5067 auto *context = static_cast<FileAssetAsyncContext *>(data);
5068 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5069 bool isValid = false;
5070 string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
5071 if (!isValid) {
5072 context->error = OHOS_INVALID_PARAM_CODE;
5073 return;
5074 }
5075 MediaFileUtils::UriAppendKeyValue(fileUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
5076 Uri uri(fileUri);
5077 int32_t retVal = UserFileClient::OpenFile(uri, "r");
5078 if (retVal <= 0) {
5079 if (retVal == E_PERMISSION_DENIED) {
5080 context->error = OHOS_PERMISSION_DENIED_CODE;
5081 } else {
5082 context->SaveError(retVal);
5083 }
5084 NAPI_ERR_LOG("Photo request edit data failed, ret: %{public}d", retVal);
5085 } else {
5086 context->fd = retVal;
5087 context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
5088 }
5089 }
5090
PhotoAccessHelperRequestSourceComplete(napi_env env,napi_status status,void * data)5091 static void PhotoAccessHelperRequestSourceComplete(napi_env env, napi_status status, void *data)
5092 {
5093 auto *context = static_cast<FileAssetAsyncContext *>(data);
5094 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5095
5096 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
5097 jsContext->status = false;
5098
5099 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5100 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5101 if (context->error == ERR_DEFAULT) {
5102 CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->fd, &jsContext->data), JS_INNER_FAIL);
5103 jsContext->status = true;
5104 } else {
5105 context->HandleError(env, jsContext->error);
5106 }
5107
5108 if (context->work != nullptr) {
5109 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5110 context->work, *jsContext);
5111 }
5112 delete context;
5113 }
5114
PhotoAccessHelperRequestSource(napi_env env,napi_callback_info info)5115 napi_value FileAssetNapi::PhotoAccessHelperRequestSource(napi_env env, napi_callback_info info)
5116 {
5117 MediaLibraryTracer tracer;
5118 tracer.Start("PhotoAccessHelperRequestSource");
5119
5120 // edit function in API11 is system api, maybe public soon
5121 if (!MediaLibraryNapiUtils::IsSystemApp()) {
5122 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5123 return nullptr;
5124 }
5125
5126 auto asyncContext = make_unique<FileAssetAsyncContext>();
5127 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5128 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
5129 "Failed to parse js args");
5130 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
5131 napi_value ret = nullptr;
5132 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
5133 auto fileUri = asyncContext->objectInfo->GetFileUri();
5134 MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5135 asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
5136 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperRequestSource",
5137 PhotoAccessHelperRequestSourceExecute, PhotoAccessHelperRequestSourceComplete);
5138 }
5139
GetFileUriFd(FileAssetAsyncContext * context)5140 static int32_t GetFileUriFd(FileAssetAsyncContext *context)
5141 {
5142 string uriRealPath = AppFileService::ModuleFileUri::FileUri(context->uri).GetRealPath();
5143 if (uriRealPath.empty()) {
5144 NAPI_ERR_LOG("Can not get file in path by uri %{private}s", context->uri.c_str());
5145 context->SaveError(E_FAIL);
5146 return E_FAIL;
5147 }
5148 int32_t fd = open(uriRealPath.c_str(), O_RDONLY);
5149 if (fd < 0) {
5150 NAPI_ERR_LOG("Can not open fileUri, ret: %{public}d, errno:%{public}d", fd, errno);
5151 context->SaveError(E_FAIL);
5152 return E_FAIL;
5153 }
5154 return fd;
5155 }
5156
PhotoAccessHelperCommitEditExecute(napi_env env,void * data)5157 static void PhotoAccessHelperCommitEditExecute(napi_env env, void *data)
5158 {
5159 MediaLibraryTracer tracer;
5160 tracer.Start("PhotoAccessHelperCommitEditExecute");
5161 auto *context = static_cast<FileAssetAsyncContext *>(data);
5162 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5163 UniqueFd uriFd(GetFileUriFd(context));
5164 CHECK_IF_EQUAL(uriFd.Get() > 0, "Can not open fileUri");
5165
5166 bool isValid = false;
5167 string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
5168 if (!isValid) {
5169 context->error = OHOS_INVALID_PARAM_CODE;
5170 return;
5171 }
5172 MediaFileUtils::UriAppendKeyValue(fileUri, MEDIA_OPERN_KEYWORD, COMMIT_REQUEST);
5173 Uri uri(fileUri);
5174 UniqueFd fd(UserFileClient::OpenFile(uri, "rw"));
5175 if (fd.Get() <= 0) {
5176 if (fd.Get() == E_PERMISSION_DENIED) {
5177 context->error = OHOS_PERMISSION_DENIED_CODE;
5178 } else {
5179 context->SaveError(fd.Get());
5180 }
5181 NAPI_ERR_LOG("File request edit data failed, ret: %{public}d", fd.Get());
5182 } else {
5183 if (ftruncate(fd.Get(), 0) == -1) {
5184 NAPI_ERR_LOG("Can not erase content from old file, errno:%{public}d", errno);
5185 context->SaveError(E_FAIL);
5186 return;
5187 }
5188 if (!MediaFileUtils::CopyFile(uriFd.Get(), fd.Get())) {
5189 NAPI_ERR_LOG("Failed to copy file: rfd:%{public}d, wfd:%{public}d, errno:%{public}d",
5190 uriFd.Get(), fd.Get(), errno);
5191 context->SaveError(E_FAIL);
5192 return;
5193 }
5194 NAPI_INFO_LOG("commit edit asset copy file finished, fileUri:%{public}s", fileUri.c_str());
5195 string insertUriStr = PAH_COMMIT_EDIT_PHOTOS;
5196 MediaLibraryNapiUtils::UriAppendKeyValue(insertUriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5197 Uri insertUri(insertUriStr);
5198 int32_t ret = UserFileClient::Insert(insertUri, context->valuesBucket);
5199 if (ret != E_SUCCESS) {
5200 if (ret == E_PERMISSION_DENIED) {
5201 context->error = OHOS_PERMISSION_DENIED_CODE;
5202 } else {
5203 context->SaveError(ret);
5204 }
5205 NAPI_ERR_LOG("File commit edit execute failed");
5206 }
5207 }
5208 }
5209
PhotoAccessHelperCommitEditComplete(napi_env env,napi_status status,void * data)5210 static void PhotoAccessHelperCommitEditComplete(napi_env env, napi_status status, void *data)
5211 {
5212 auto *context = static_cast<FileAssetAsyncContext *>(data);
5213 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5214
5215 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
5216 jsContext->status = false;
5217
5218 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5219 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5220 if (context->error == ERR_DEFAULT) {
5221 jsContext->status = true;
5222 } else {
5223 context->HandleError(env, jsContext->error);
5224 }
5225
5226 if (context->work != nullptr) {
5227 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5228 context->work, *jsContext);
5229 }
5230 delete context;
5231 }
5232
PhotoAccessHelperCommitEditedAsset(napi_env env,napi_callback_info info)5233 napi_value FileAssetNapi::PhotoAccessHelperCommitEditedAsset(napi_env env, napi_callback_info info)
5234 {
5235 MediaLibraryTracer tracer;
5236 tracer.Start("PhotoAccessHelperCommitEditedAsset");
5237
5238 // edit function in API11 is system api, maybe public soon
5239 if (!MediaLibraryNapiUtils::IsSystemApp()) {
5240 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5241 return nullptr;
5242 }
5243
5244 auto asyncContext = make_unique<FileAssetAsyncContext>();
5245 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5246 CHECK_ARGS_THROW_INVALID_PARAM(env,
5247 MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_TWO, ARGS_THREE));
5248 string editData;
5249 const static int32_t EDIT_DATA_MAX_LENGTH = 5 * 1024 * 1024;
5250 CHECK_ARGS_THROW_INVALID_PARAM(env,
5251 MediaLibraryNapiUtils::GetParamStringWithLength(env, asyncContext->argv[0], EDIT_DATA_MAX_LENGTH, editData));
5252 CHECK_ARGS_THROW_INVALID_PARAM(env,
5253 MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[1], asyncContext->uri));
5254 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
5255 napi_value ret = nullptr;
5256 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
5257 auto fileUri = asyncContext->objectInfo->GetFileUri();
5258 MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5259 asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
5260 asyncContext->valuesBucket.Put(EDIT_DATA, editData);
5261 asyncContext->valuesBucket.Put(MediaColumn::MEDIA_ID, asyncContext->objectPtr->GetId());
5262 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCommitEditedAsset",
5263 PhotoAccessHelperCommitEditExecute, PhotoAccessHelperCommitEditComplete);
5264 }
5265
PhotoAccessHelperRevertToOriginalExecute(napi_env env,void * data)5266 static void PhotoAccessHelperRevertToOriginalExecute(napi_env env, void *data)
5267 {
5268 MediaLibraryTracer tracer;
5269 tracer.Start("PhotoAccessHelperRevertToOriginalExecute");
5270 auto *context = static_cast<FileAssetAsyncContext *>(data);
5271 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5272 string uriString = PAH_REVERT_EDIT_PHOTOS;
5273 MediaFileUtils::UriAppendKeyValue(uriString, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5274 Uri uri(uriString);
5275 int32_t ret = UserFileClient::Insert(uri, context->valuesBucket);
5276 if (ret < 0) {
5277 if (ret == E_PERMISSION_DENIED) {
5278 context->error = OHOS_PERMISSION_DENIED_CODE;
5279 } else {
5280 context->SaveError(ret);
5281 }
5282 NAPI_ERR_LOG("Photo revert edit data failed, ret: %{public}d", ret);
5283 }
5284 }
5285
PhotoAccessHelperRevertToOriginalComplete(napi_env env,napi_status status,void * data)5286 static void PhotoAccessHelperRevertToOriginalComplete(napi_env env, napi_status status, void *data)
5287 {
5288 auto *context = static_cast<FileAssetAsyncContext *>(data);
5289 CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5290
5291 unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
5292 jsContext->status = false;
5293 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5294 CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5295
5296 if (context->error == ERR_DEFAULT) {
5297 jsContext->status = true;
5298 } else {
5299 context->HandleError(env, jsContext->error);
5300 }
5301
5302 if (context->work != nullptr) {
5303 MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5304 context->work, *jsContext);
5305 }
5306 delete context;
5307 }
5308
PhotoAccessHelperRevertToOriginal(napi_env env,napi_callback_info info)5309 napi_value FileAssetNapi::PhotoAccessHelperRevertToOriginal(napi_env env, napi_callback_info info)
5310 {
5311 MediaLibraryTracer tracer;
5312 tracer.Start("PhotoAccessHelperRevertToOriginal");
5313
5314 // edit function in API11 is system api, maybe public soon
5315 if (!MediaLibraryNapiUtils::IsSystemApp()) {
5316 NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5317 return nullptr;
5318 }
5319
5320 auto asyncContext = make_unique<FileAssetAsyncContext>();
5321 asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5322 CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
5323 "Failed to parse js args");
5324 asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
5325 napi_value ret = nullptr;
5326 CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
5327 asyncContext->valuesBucket.Put(MediaColumn::MEDIA_ID, asyncContext->objectPtr->GetId());
5328 return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperRevertToOriginal",
5329 PhotoAccessHelperRevertToOriginalExecute, PhotoAccessHelperRevertToOriginalComplete);
5330 }
5331 } // namespace Media
5332 } // namespace OHOS
5333