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