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