• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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