• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "userfile_manager_types.h"
16 #define MLOG_TAG "FileAssetNapi"
17 
18 #include "file_asset_napi.h"
19 
20 #include <algorithm>
21 #include <cstring>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <sys/stat.h>
25 
26 #include "abs_shared_result_set.h"
27 #include "access_token.h"
28 #include "accesstoken_kit.h"
29 #include "datashare_errno.h"
30 #include "datashare_predicates.h"
31 #include "datashare_result_set.h"
32 #include "datashare_values_bucket.h"
33 #include "hitrace_meter.h"
34 #include "fetch_result.h"
35 #include "file_uri.h"
36 #include "hilog/log.h"
37 #include "ipc_skeleton.h"
38 #include "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 
JSGetAnalysisDataExecute(FileAssetAsyncContext * context)1995 static void JSGetAnalysisDataExecute(FileAssetAsyncContext *context)
1996 {
1997     MediaLibraryTracer tracer;
1998     tracer.Start("JSGetThumbnailExecute");
1999     if (ANALYSIS_SOURCE_INFO_MAP.find(context->analysisType) == ANALYSIS_SOURCE_INFO_MAP.end()) {
2000         NAPI_ERR_LOG("Invalid analysisType");
2001         return;
2002     }
2003     auto &analysisInfo = ANALYSIS_SOURCE_INFO_MAP.at(context->analysisType);
2004     DataShare::DataSharePredicates predicates;
2005     if (context->analysisType == ANALYSIS_HUMAN_FACE_TAG) {
2006         string onClause = VISION_IMAGE_FACE_TABLE + "." + TAG_ID + " = " + VISION_FACE_TAG_TABLE + "." + TAG_ID;
2007         predicates.InnerJoin(VISION_IMAGE_FACE_TABLE)->On({ onClause });
2008     }
2009     string fileId = to_string(context->objectInfo->GetFileId());
2010     if (context->analysisType == ANALYSIS_DETAIL_ADDRESS) {
2011         string language = Global::I18n::LocaleConfig::GetSystemLanguage();
2012         vector<string> onClause = { PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::MEDIA_ID + " = " +
2013             GEO_KNOWLEDGE_TABLE + "." + FILE_ID + " AND " +
2014             GEO_KNOWLEDGE_TABLE + "." + LANGUAGE + " = \'" + language + "\'" };
2015         predicates.LeftOuterJoin(GEO_KNOWLEDGE_TABLE)->On(onClause);
2016         predicates.EqualTo(PhotoColumn::PHOTOS_TABLE + "." + MediaColumn::MEDIA_ID, fileId);
2017     } else {
2018         predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
2019     }
2020     Uri uri(analysisInfo.uriStr);
2021     std::vector<std::string> fetchColumn = analysisInfo.fetchColumn;
2022     int errCode = 0;
2023     auto resultSet = UserFileClient::Query(uri, predicates, fetchColumn, errCode);
2024     context->analysisData = context->analysisType == ANALYSIS_FACE ?
2025         MediaLibraryNapiUtils::ParseAnalysisFace2JsonStr(resultSet, fetchColumn) :
2026         MediaLibraryNapiUtils::ParseResultSet2JsonStr(resultSet, fetchColumn);
2027     if (context->analysisData == ANALYSIS_NO_RESULTS) {
2028         Uri uri(PAH_QUERY_ANA_TOTAL);
2029         DataShare::DataSharePredicates predicates;
2030         std::vector<std::string> fetchColumn = { analysisInfo.fieldStr };
2031         predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
2032         auto fieldValue = UserFileClient::Query(uri, predicates, fetchColumn, errCode);
2033         string value = MediaLibraryNapiUtils::ParseResultSet2JsonStr(fieldValue, fetchColumn);
2034         if (strstr(value.c_str(), ANALYSIS_INIT_VALUE.c_str()) == NULL) {
2035             context->analysisData = ANALYSIS_STATUS_ANALYZED;
2036         }
2037     }
2038 }
2039 
JSFavoriteCallbackComplete(napi_env env,napi_status status,void * data)2040 static void JSFavoriteCallbackComplete(napi_env env, napi_status status, void *data)
2041 {
2042     MediaLibraryTracer tracer;
2043     tracer.Start("JSFavoriteCallbackComplete");
2044 
2045     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2046     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2047     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2048     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2049     jsContext->status = false;
2050     napi_get_undefined(env, &jsContext->data);
2051     if (context->error == ERR_DEFAULT) {
2052         jsContext->status = true;
2053         Media::MediaType mediaType = context->objectPtr->GetMediaType();
2054         string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
2055         Uri modifyNotify(notifyUri);
2056         UserFileClient::NotifyChange(modifyNotify);
2057     } else {
2058         context->HandleError(env, jsContext->error);
2059         napi_get_undefined(env, &jsContext->data);
2060     }
2061 
2062     tracer.Finish();
2063     if (context->work != nullptr) {
2064         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2065                                                    context->work, *jsContext);
2066     }
2067 
2068     delete context;
2069 }
2070 
GetIsDirectoryiteNative(napi_env env,const FileAssetAsyncContext & fileContext)2071 static bool GetIsDirectoryiteNative(napi_env env, const FileAssetAsyncContext &fileContext)
2072 {
2073     MediaLibraryTracer tracer;
2074     tracer.Start("GetIsDirectoryiteNative");
2075 
2076     FileAssetAsyncContext *context = const_cast<FileAssetAsyncContext *>(&fileContext);
2077     if (context == nullptr) {
2078         NAPI_ERR_LOG("Async context is null");
2079         return false;
2080     }
2081 
2082 #ifdef MEDIALIBRARY_COMPATIBILITY
2083     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO) ||
2084         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2085         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
2086         context->status = true;
2087         return false;
2088     }
2089 
2090     int64_t virtualId = MediaFileUtils::GetVirtualIdByType(context->objectPtr->GetId(), MediaType::MEDIA_TYPE_FILE);
2091     vector<string> selectionArgs = { to_string(virtualId) };
2092 #else
2093     vector<string> selectionArgs = { to_string(context->objectPtr->GetId()) };
2094 #endif
2095     vector<string> columns = { MEDIA_DATA_DB_MEDIA_TYPE };
2096     DataSharePredicates predicates;
2097     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ?");
2098     predicates.SetWhereArgs(selectionArgs);
2099     string queryUri = MEDIALIBRARY_DATA_URI;
2100     Uri uri(queryUri);
2101     int errCode = 0;
2102     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2103     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
2104         NAPI_ERR_LOG("Query IsDirectory failed");
2105         return false;
2106     }
2107     int32_t index = 0;
2108     if (resultSet->GetColumnIndex(MEDIA_DATA_DB_MEDIA_TYPE, index) != NativeRdb::E_OK) {
2109         NAPI_ERR_LOG("Query Directory failed");
2110         return false;
2111     }
2112     int32_t mediaType = 0;
2113     if (resultSet->GetInt(index, mediaType) != NativeRdb::E_OK) {
2114         NAPI_ERR_LOG("Can not get file path");
2115         return false;
2116     }
2117     context->status = true;
2118     return  mediaType == static_cast<int>(MediaType::MEDIA_TYPE_ALBUM);
2119 }
2120 
JSIsDirectoryCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)2121 static void JSIsDirectoryCallbackComplete(napi_env env, napi_status status,
2122                                           FileAssetAsyncContext* context)
2123 {
2124     MediaLibraryTracer tracer;
2125     tracer.Start("JSIsDirectoryCallbackComplete");
2126 
2127     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2128     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2129     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2130     jsContext->status = false;
2131 
2132     if (context->status) {
2133         napi_get_boolean(env, context->isDirectory, &jsContext->data);
2134         napi_get_undefined(env, &jsContext->error);
2135         jsContext->status = true;
2136     } else {
2137         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
2138                                                      "UserFileClient is invalid");
2139         napi_get_undefined(env, &jsContext->data);
2140     }
2141 
2142     tracer.Finish();
2143     if (context->work != nullptr) {
2144         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2145                                                    context->work, *jsContext);
2146     }
2147 
2148     delete context;
2149 }
2150 
GetJSArgsForIsDirectory(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2151 static napi_value GetJSArgsForIsDirectory(napi_env env, size_t argc, const napi_value argv[],
2152                                           FileAssetAsyncContext &asyncContext)
2153 {
2154     const int32_t refCount = 1;
2155     napi_value result;
2156     auto context = &asyncContext;
2157     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2158     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2159     for (size_t i = PARAM0; i < argc; i++) {
2160         napi_valuetype valueType = napi_undefined;
2161         napi_typeof(env, argv[i], &valueType);
2162         if (i == PARAM0 && valueType == napi_function) {
2163             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2164             break;
2165         } else {
2166             NAPI_ASSERT(env, false, "type mismatch");
2167         }
2168     }
2169     napi_get_boolean(env, true, &result);
2170     return result;
2171 }
2172 
JSIsDirectory(napi_env env,napi_callback_info info)2173 napi_value FileAssetNapi::JSIsDirectory(napi_env env, napi_callback_info info)
2174 {
2175     size_t argc = ARGS_ONE;
2176     napi_value argv[ARGS_ONE] = {0};
2177     napi_value thisVar = nullptr;
2178     napi_value resource = nullptr;
2179 
2180     MediaLibraryTracer tracer;
2181     tracer.Start("JSisDirectory");
2182 
2183     GET_JS_ARGS(env, info, argc, argv, thisVar);
2184     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 2 parameters maximum");
2185     napi_value result = nullptr;
2186     napi_get_undefined(env, &result);
2187     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2188     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2189     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2190     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2191         result = GetJSArgsForIsDirectory(env, argc, argv, *asyncContext);
2192         ASSERT_NULLPTR_CHECK(env, result);
2193         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2194         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsDirectory", asyncContext);
2195         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2196         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2197         status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
2198                 FileAssetAsyncContext* context = static_cast<FileAssetAsyncContext*>(data);
2199                 context->status = false;
2200                 context->isDirectory = GetIsDirectoryiteNative(env, *context);
2201             },
2202             reinterpret_cast<CompleteCallback>(JSIsDirectoryCallbackComplete),
2203             static_cast<void *>(asyncContext.get()), &asyncContext->work);
2204         if (status != napi_ok) {
2205             napi_get_undefined(env, &result);
2206         } else {
2207             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
2208             asyncContext.release();
2209         }
2210     }
2211     return result;
2212 }
2213 
JSIsFavoriteExecute(FileAssetAsyncContext * context)2214 static void JSIsFavoriteExecute(FileAssetAsyncContext* context)
2215 {
2216     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2217     context->isFavorite = context->objectPtr->IsFavorite();
2218     return;
2219 }
2220 
JSIsFavoriteCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)2221 static void JSIsFavoriteCallbackComplete(napi_env env, napi_status status,
2222                                          FileAssetAsyncContext* context)
2223 {
2224     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2225     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2226     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2227     jsContext->status = false;
2228     if (context->error == ERR_DEFAULT) {
2229         napi_get_boolean(env, context->isFavorite, &jsContext->data);
2230         napi_get_undefined(env, &jsContext->error);
2231         jsContext->status = true;
2232     } else {
2233         NAPI_ERR_LOG("Get IsFavorite failed, ret: %{public}d", context->error);
2234         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2235             "UserFileClient is invalid");
2236         napi_get_undefined(env, &jsContext->data);
2237     }
2238     if (context->work != nullptr) {
2239         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2240                                                    context->work, *jsContext);
2241     }
2242     delete context;
2243 }
2244 
GetJSArgsForFavorite(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2245 napi_value GetJSArgsForFavorite(napi_env env, size_t argc, const napi_value argv[],
2246                                 FileAssetAsyncContext &asyncContext)
2247 {
2248     const int32_t refCount = 1;
2249     napi_value result = nullptr;
2250     auto context = &asyncContext;
2251     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2252     bool isFavorite = false;
2253     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2254     for (size_t i = PARAM0; i < argc; i++) {
2255         napi_valuetype valueType = napi_undefined;
2256         napi_typeof(env, argv[i], &valueType);
2257         if (i == PARAM0 && valueType == napi_boolean) {
2258             napi_get_value_bool(env, argv[i], &isFavorite);
2259         } else if (i == PARAM1 && valueType == napi_function) {
2260             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2261             break;
2262         } else {
2263             NAPI_ASSERT(env, false, "type mismatch");
2264         }
2265     }
2266     context->isFavorite = isFavorite;
2267     napi_get_boolean(env, true, &result);
2268     return result;
2269 }
2270 
2271 #ifdef MEDIALIBRARY_COMPATIBILITY
FavoriteByUpdate(FileAssetAsyncContext * context)2272 static void FavoriteByUpdate(FileAssetAsyncContext *context)
2273 {
2274     DataShareValuesBucket valuesBucket;
2275     string uriString;
2276     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2277         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
2278         uriString = URI_UPDATE_PHOTO;
2279     } else {
2280         uriString = URI_UPDATE_AUDIO;
2281     }
2282     valuesBucket.Put(MEDIA_DATA_DB_IS_FAV, (context->isFavorite ? IS_FAV : NOT_FAV));
2283     NAPI_INFO_LOG("Update asset %{public}d favorite to %{public}d", context->objectPtr->GetId(),
2284         context->isFavorite ? IS_FAV : NOT_FAV);
2285     DataSharePredicates predicates;
2286     int32_t fileId = context->objectPtr->GetId();
2287     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
2288     predicates.SetWhereArgs({ to_string(fileId) });
2289     Uri uri(uriString);
2290     context->changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
2291 }
2292 #endif
2293 
FavoriteByInsert(FileAssetAsyncContext * context)2294 static void FavoriteByInsert(FileAssetAsyncContext *context)
2295 {
2296     DataShareValuesBucket valuesBucket;
2297     string uriString = MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/";
2298     uriString += context->isFavorite ? MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM : MEDIA_SMARTALBUMMAPOPRN_REMOVESMARTALBUM;
2299     valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, FAVOURITE_ALBUM_ID_VALUES);
2300     valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, context->objectPtr->GetId());
2301     Uri uri(uriString);
2302     context->changedRows = UserFileClient::Insert(uri, valuesBucket);
2303 }
2304 
JSFavouriteExecute(napi_env env,void * data)2305 static void JSFavouriteExecute(napi_env env, void *data)
2306 {
2307     MediaLibraryTracer tracer;
2308     tracer.Start("JSFavouriteExecute");
2309 
2310     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2311     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2312 
2313 #ifdef MEDIALIBRARY_COMPATIBILITY
2314     string uriString = MEDIALIBRARY_DATA_URI + "/";
2315     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2316         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO) ||
2317         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO)) {
2318         if (MediaFileUtils::IsFileTablePath(context->objectPtr->GetPath())) {
2319             FavoriteByInsert(context);
2320         } else {
2321             FavoriteByUpdate(context);
2322         }
2323     } else {
2324         FavoriteByInsert(context);
2325     }
2326 #else
2327     FavoriteByInsert(context);
2328 #endif
2329     if (context->changedRows >= 0) {
2330         context->objectPtr->SetFavorite(context->isFavorite);
2331     }
2332     context->SaveError(context->changedRows);
2333 }
2334 
JSFavorite(napi_env env,napi_callback_info info)2335 napi_value FileAssetNapi::JSFavorite(napi_env env, napi_callback_info info)
2336 {
2337     size_t argc = ARGS_TWO;
2338     napi_value argv[ARGS_TWO] = {0};
2339     napi_value thisVar = nullptr;
2340 
2341     MediaLibraryTracer tracer;
2342     tracer.Start("JSFavorite");
2343 
2344     GET_JS_ARGS(env, info, argc, argv, thisVar);
2345     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2346     napi_value result = nullptr;
2347     napi_get_undefined(env, &result);
2348 
2349     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2350     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2351     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
2352     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2353     if ((status != napi_ok) || (asyncContext->objectInfo == nullptr)) {
2354         NAPI_DEBUG_LOG("get this Var fail");
2355         return result;
2356     }
2357 
2358     result = GetJSArgsForFavorite(env, argc, argv, *asyncContext);
2359     if (asyncContext->isFavorite == asyncContext->objectInfo->IsFavorite()) {
2360         NAPI_DEBUG_LOG("favorite state is the same");
2361         return result;
2362     }
2363     ASSERT_NULLPTR_CHECK(env, result);
2364     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2365     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2366 
2367     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSFavorite", JSFavouriteExecute,
2368         JSFavoriteCallbackComplete);
2369 }
2370 
GetJSArgsForIsFavorite(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2371 static napi_value GetJSArgsForIsFavorite(napi_env env, size_t argc, const napi_value argv[],
2372                                          FileAssetAsyncContext &asyncContext)
2373 {
2374     const int32_t refCount = 1;
2375     napi_value result;
2376     auto context = &asyncContext;
2377     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2378     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2379     for (size_t i = PARAM0; i < argc; i++) {
2380         napi_valuetype valueType = napi_undefined;
2381         napi_typeof(env, argv[i], &valueType);
2382         if (i == PARAM0 && valueType == napi_function) {
2383             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2384             break;
2385         } else {
2386             NAPI_ASSERT(env, false, "type mismatch");
2387         }
2388     }
2389     napi_get_boolean(env, true, &result);
2390     return result;
2391 }
2392 
JSIsFavorite(napi_env env,napi_callback_info info)2393 napi_value FileAssetNapi::JSIsFavorite(napi_env env, napi_callback_info info)
2394 {
2395     MediaLibraryTracer tracer;
2396     tracer.Start("JSIsFavorite");
2397 
2398     napi_status status;
2399     napi_value result = nullptr;
2400     size_t argc = ARGS_ONE;
2401     napi_value argv[ARGS_ONE] = {0};
2402     napi_value thisVar = nullptr;
2403     napi_value resource = nullptr;
2404     GET_JS_ARGS(env, info, argc, argv, thisVar);
2405     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameters maximum");
2406     napi_get_undefined(env, &result);
2407     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2408     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2409     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2410     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2411         result = GetJSArgsForIsFavorite(env, argc, argv, *asyncContext);
2412         ASSERT_NULLPTR_CHECK(env, result);
2413         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2414         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsFavorite", asyncContext);
2415         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2416         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2417 
2418         status = napi_create_async_work(
2419             env, nullptr, resource, [](napi_env env, void *data) {
2420                 auto context = static_cast<FileAssetAsyncContext*>(data);
2421                 JSIsFavoriteExecute(context);
2422             },
2423             reinterpret_cast<CompleteCallback>(JSIsFavoriteCallbackComplete),
2424             static_cast<void *>(asyncContext.get()), &asyncContext->work);
2425         if (status != napi_ok) {
2426             napi_get_undefined(env, &result);
2427         } else {
2428             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
2429             asyncContext.release();
2430         }
2431     }
2432     return result;
2433 }
2434 
TrashByUpdate(FileAssetAsyncContext * context)2435 static void TrashByUpdate(FileAssetAsyncContext *context)
2436 {
2437     DataShareValuesBucket valuesBucket;
2438     string uriString;
2439     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2440         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
2441         uriString = URI_UPDATE_PHOTO;
2442     } else {
2443         uriString = URI_UPDATE_AUDIO;
2444     }
2445     valuesBucket.Put(MEDIA_DATA_DB_DATE_TRASHED,
2446         (context->isTrash ? MediaFileUtils::UTCTimeMilliSeconds() : NOT_TRASH));
2447     DataSharePredicates predicates;
2448     int32_t fileId = context->objectPtr->GetId();
2449     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
2450     predicates.SetWhereArgs({ to_string(fileId) });
2451     Uri uri(uriString);
2452     context->changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
2453 }
2454 
TrashByInsert(FileAssetAsyncContext * context)2455 static void TrashByInsert(FileAssetAsyncContext *context)
2456 {
2457     DataShareValuesBucket valuesBucket;
2458     string uriString = MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/";
2459     uriString += context->isTrash ? MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM : MEDIA_SMARTALBUMMAPOPRN_REMOVESMARTALBUM;
2460     valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, TRASH_ALBUM_ID_VALUES);
2461     valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, context->objectPtr->GetId());
2462     Uri uri(uriString);
2463     context->changedRows = UserFileClient::Insert(uri, valuesBucket);
2464 }
2465 
JSTrashExecute(napi_env env,void * data)2466 static void JSTrashExecute(napi_env env, void *data)
2467 {
2468     MediaLibraryTracer tracer;
2469     tracer.Start("JSTrashExecute");
2470 
2471     auto *context = static_cast<FileAssetAsyncContext*>(data);
2472 
2473 #ifdef MEDIALIBRARY_COMPATIBILITY
2474     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2475         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO) ||
2476         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO)) {
2477         if (MediaFileUtils::IsFileTablePath(context->objectPtr->GetPath())) {
2478             TrashByInsert(context);
2479         } else {
2480             TrashByUpdate(context);
2481         }
2482     } else {
2483         TrashByInsert(context);
2484     }
2485 #else
2486     TrashByInsert(context);
2487 #endif
2488     if (context->changedRows >= 0) {
2489         int32_t trashFlag = (context->isTrash ? IS_TRASH : NOT_TRASH);
2490         context->objectPtr->SetIsTrash(trashFlag);
2491     }
2492     context->SaveError(context->changedRows);
2493 }
2494 
JSTrashCallbackComplete(napi_env env,napi_status status,void * data)2495 static void JSTrashCallbackComplete(napi_env env, napi_status status, void *data)
2496 {
2497     MediaLibraryTracer tracer;
2498     tracer.Start("JSTrashCallbackComplete");
2499 
2500     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2501     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2502     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2503     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2504     jsContext->status = false;
2505     napi_get_undefined(env, &jsContext->data);
2506     if (context->error == ERR_DEFAULT) {
2507         jsContext->status = true;
2508         Media::MediaType mediaType = context->objectPtr->GetMediaType();
2509         string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
2510         Uri modifyNotify(notifyUri);
2511         UserFileClient::NotifyChange(modifyNotify);
2512         NAPI_DEBUG_LOG("JSTrashCallbackComplete success");
2513     } else {
2514         context->HandleError(env, jsContext->error);
2515     }
2516 
2517     tracer.Finish();
2518     if (context->work != nullptr) {
2519         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2520                                                    context->work, *jsContext);
2521     }
2522 
2523     delete context;
2524 }
2525 
GetJSArgsForTrash(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2526 napi_value GetJSArgsForTrash(napi_env env, size_t argc, const napi_value argv[],
2527                              FileAssetAsyncContext &asyncContext)
2528 {
2529     const int32_t refCount = 1;
2530     napi_value result = nullptr;
2531     auto context = &asyncContext;
2532     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2533     bool isTrash = false;
2534     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2535     for (size_t i = PARAM0; i < argc; i++) {
2536         napi_valuetype valueType = napi_undefined;
2537         napi_typeof(env, argv[i], &valueType);
2538         if (i == PARAM0 && valueType == napi_boolean) {
2539             napi_get_value_bool(env, argv[i], &isTrash);
2540         } else if (i == PARAM1 && valueType == napi_function) {
2541             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2542             break;
2543         } else {
2544             NAPI_ASSERT(env, false, "type mismatch");
2545         }
2546     }
2547     context->isTrash = isTrash;
2548     napi_get_boolean(env, true, &result);
2549     return result;
2550 }
2551 
JSTrash(napi_env env,napi_callback_info info)2552 napi_value FileAssetNapi::JSTrash(napi_env env, napi_callback_info info)
2553 {
2554     napi_status status;
2555     napi_value result = nullptr;
2556     size_t argc = ARGS_TWO;
2557     napi_value argv[ARGS_TWO] = {0};
2558     napi_value thisVar = nullptr;
2559 
2560     MediaLibraryTracer tracer;
2561     tracer.Start("JSTrash");
2562 
2563     GET_JS_ARGS(env, info, argc, argv, thisVar);
2564     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2565 
2566     napi_get_undefined(env, &result);
2567     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2568     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2569     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
2570     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2571     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2572         result = GetJSArgsForTrash(env, argc, argv, *asyncContext);
2573         ASSERT_NULLPTR_CHECK(env, result);
2574         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2575         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2576         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSTrash", JSTrashExecute,
2577             JSTrashCallbackComplete);
2578     }
2579     return result;
2580 }
2581 
JSIsTrashExecute(FileAssetAsyncContext * context)2582 static void JSIsTrashExecute(FileAssetAsyncContext* context)
2583 {
2584     MediaLibraryTracer tracer;
2585     tracer.Start("JSIsTrashExecute");
2586 
2587     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2588     context->isTrash = (context->objectPtr->GetIsTrash() != NOT_TRASH);
2589     return;
2590 }
2591 
JSIsTrashCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)2592 static void JSIsTrashCallbackComplete(napi_env env, napi_status status,
2593                                       FileAssetAsyncContext* context)
2594 {
2595     MediaLibraryTracer tracer;
2596     tracer.Start("JSIsTrashCallbackComplete");
2597 
2598     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2599     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2600     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2601     jsContext->status = false;
2602     if (context->error == ERR_DEFAULT) {
2603         napi_get_boolean(env, context->isTrash, &jsContext->data);
2604         napi_get_undefined(env, &jsContext->error);
2605         jsContext->status = true;
2606     } else {
2607         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2608             "UserFileClient is invalid");
2609         napi_get_undefined(env, &jsContext->data);
2610     }
2611 
2612     tracer.Finish();
2613     if (context->work != nullptr) {
2614         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2615                                                    context->work, *jsContext);
2616     }
2617 
2618     delete context;
2619 }
2620 
GetJSArgsForIsTrash(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2621 static napi_value GetJSArgsForIsTrash(napi_env env, size_t argc, const napi_value argv[],
2622                                       FileAssetAsyncContext &asyncContext)
2623 {
2624     const int32_t refCount = 1;
2625     napi_value result;
2626     auto context = &asyncContext;
2627     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2628     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2629     for (size_t i = PARAM0; i < argc; i++) {
2630         napi_valuetype valueType = napi_undefined;
2631         napi_typeof(env, argv[i], &valueType);
2632         if (i == PARAM0 && valueType == napi_function) {
2633             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2634             break;
2635         } else {
2636             NAPI_ASSERT(env, false, "type mismatch");
2637         }
2638     }
2639     napi_get_boolean(env, true, &result);
2640     return result;
2641 }
2642 
JSIsTrash(napi_env env,napi_callback_info info)2643 napi_value FileAssetNapi::JSIsTrash(napi_env env, napi_callback_info info)
2644 {
2645     napi_status status;
2646     napi_value result = nullptr;
2647     size_t argc = ARGS_ONE;
2648     napi_value argv[ARGS_ONE] = {0};
2649     napi_value thisVar = nullptr;
2650     napi_value resource = nullptr;
2651 
2652     MediaLibraryTracer tracer;
2653     tracer.Start("JSIsTrash");
2654 
2655     GET_JS_ARGS(env, info, argc, argv, thisVar);
2656     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameters maximum");
2657     napi_get_undefined(env, &result);
2658     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2659     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2660     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2661     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2662         result = GetJSArgsForIsTrash(env, argc, argv, *asyncContext);
2663         ASSERT_NULLPTR_CHECK(env, result);
2664         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2665         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsTrash", asyncContext);
2666         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2667         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2668 
2669         status = napi_create_async_work(
2670             env, nullptr, resource, [](napi_env env, void *data) {
2671                 auto context = static_cast<FileAssetAsyncContext*>(data);
2672                 JSIsTrashExecute(context);
2673             },
2674             reinterpret_cast<CompleteCallback>(JSIsTrashCallbackComplete),
2675             static_cast<void *>(asyncContext.get()), &asyncContext->work);
2676         if (status != napi_ok) {
2677             napi_get_undefined(env, &result);
2678         } else {
2679             napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
2680             asyncContext.release();
2681         }
2682     }
2683 
2684     return result;
2685 }
2686 
UpdateFileAssetInfo()2687 void FileAssetNapi::UpdateFileAssetInfo()
2688 {
2689     fileAssetPtr = sFileAsset_;
2690 }
2691 
GetFileAssetInstance() const2692 shared_ptr<FileAsset> FileAssetNapi::GetFileAssetInstance() const
2693 {
2694     return fileAssetPtr;
2695 }
2696 
CheckSystemApiKeys(napi_env env,const string & key)2697 static int32_t CheckSystemApiKeys(napi_env env, const string &key)
2698 {
2699     static const set<string> SYSTEM_API_KEYS = {
2700         PhotoColumn::PHOTO_POSITION,
2701         MediaColumn::MEDIA_DATE_TRASHED,
2702         MediaColumn::MEDIA_HIDDEN,
2703         PhotoColumn::PHOTO_USER_COMMENT,
2704         PhotoColumn::CAMERA_SHOT_KEY,
2705         PhotoColumn::MOVING_PHOTO_EFFECT_MODE,
2706         PhotoColumn::SUPPORTED_WATERMARK_TYPE,
2707         PENDING_STATUS,
2708         MEDIA_DATA_DB_DATE_TRASHED_MS,
2709     };
2710 
2711     if (SYSTEM_API_KEYS.find(key) != SYSTEM_API_KEYS.end() && !MediaLibraryNapiUtils::IsSystemApp()) {
2712         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This key can only be used by system apps");
2713         return E_CHECK_SYSTEMAPP_FAIL;
2714     }
2715     return E_SUCCESS;
2716 }
2717 
IsSpecialKey(const string & key)2718 static bool IsSpecialKey(const string &key)
2719 {
2720     static const set<string> SPECIAL_KEY = {
2721         PENDING_STATUS
2722     };
2723 
2724     if (SPECIAL_KEY.find(key) != SPECIAL_KEY.end()) {
2725         return true;
2726     }
2727     return false;
2728 }
2729 
HandleGettingSpecialKey(napi_env env,const string & key,const shared_ptr<FileAsset> & fileAssetPtr)2730 static napi_value HandleGettingSpecialKey(napi_env env, const string &key, const shared_ptr<FileAsset> &fileAssetPtr)
2731 {
2732     napi_value jsResult = nullptr;
2733     if (key == PENDING_STATUS) {
2734         if (fileAssetPtr->GetTimePending() == 0) {
2735             napi_get_boolean(env, false, &jsResult);
2736         } else {
2737             napi_get_boolean(env, true, &jsResult);
2738         }
2739     }
2740 
2741     return jsResult;
2742 }
2743 
GetDateTakenFromResultSet(const shared_ptr<DataShare::DataShareResultSet> & resultSet,int64_t & dateTaken)2744 static bool GetDateTakenFromResultSet(const shared_ptr<DataShare::DataShareResultSet> &resultSet,
2745     int64_t &dateTaken)
2746 {
2747     if (resultSet == nullptr) {
2748         NAPI_ERR_LOG("ResultSet is null");
2749         return false;
2750     }
2751     int32_t count = 0;
2752     int32_t errCode = resultSet->GetRowCount(count);
2753     if (errCode != DataShare::E_OK) {
2754         NAPI_ERR_LOG("Can not get row count from resultSet, errCode=%{public}d", errCode);
2755         return false;
2756     }
2757     if (count == 0) {
2758         NAPI_ERR_LOG("Can not find photo edit time from database");
2759         return false;
2760     }
2761     errCode = resultSet->GoToFirstRow();
2762     if (errCode != DataShare::E_OK) {
2763         NAPI_ERR_LOG("ResultSet GotoFirstRow failed, errCode=%{public}d", errCode);
2764         return false;
2765     }
2766     int32_t index = 0;
2767     errCode = resultSet->GetColumnIndex(PhotoColumn::MEDIA_DATE_TAKEN, index);
2768     if (errCode != DataShare::E_OK) {
2769         NAPI_ERR_LOG("ResultSet GetColumnIndex failed, errCode=%{public}d", errCode);
2770         return false;
2771     }
2772     errCode = resultSet->GetLong(index, dateTaken);
2773     if (errCode != DataShare::E_OK) {
2774         NAPI_ERR_LOG("ResultSet GetLong failed, errCode=%{public}d", errCode);
2775         return false;
2776     }
2777     return true;
2778 }
2779 
UpdateDetailTimeByDateTaken(napi_env env,const shared_ptr<FileAsset> & fileAssetPtr,const string & detailTime)2780 static void UpdateDetailTimeByDateTaken(napi_env env, const shared_ptr<FileAsset> &fileAssetPtr,
2781     const string &detailTime)
2782 {
2783     string uri = PAH_UPDATE_PHOTO;
2784     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2785     Uri updateAssetUri(uri);
2786     DataSharePredicates predicates;
2787     DataShareValuesBucket valuesBucket;
2788     valuesBucket.Put(PhotoColumn::PHOTO_DETAIL_TIME, detailTime);
2789     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
2790     predicates.SetWhereArgs({ MediaFileUtils::GetIdFromUri(fileAssetPtr->GetUri()) });
2791     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
2792     if (changedRows < 0) {
2793         NAPI_ERR_LOG("Failed to modify detail time, err: %{public}d", changedRows);
2794         NapiError::ThrowError(env, JS_INNER_FAIL);
2795     }
2796 }
2797 
HandleGettingDetailTimeKey(napi_env env,const shared_ptr<FileAsset> & fileAssetPtr)2798 static napi_value HandleGettingDetailTimeKey(napi_env env, const shared_ptr<FileAsset> &fileAssetPtr)
2799 {
2800     napi_value jsResult = nullptr;
2801     auto detailTimeValue = fileAssetPtr->GetMemberMap().at(PhotoColumn::PHOTO_DETAIL_TIME);
2802     if (detailTimeValue.index() == MEMBER_TYPE_STRING && !get<string>(detailTimeValue).empty()) {
2803         napi_create_string_utf8(env, get<string>(detailTimeValue).c_str(), NAPI_AUTO_LENGTH, &jsResult);
2804     } else {
2805         string fileId = MediaFileUtils::GetIdFromUri(fileAssetPtr->GetUri());
2806         string queryUriStr = PAH_QUERY_PHOTO;
2807         MediaLibraryNapiUtils::UriAppendKeyValue(queryUriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2808         Uri uri(queryUriStr);
2809         DataShare::DataSharePredicates predicates;
2810         predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
2811         DataShare::DataShareValuesBucket values;
2812         vector<string> columns = { MediaColumn::MEDIA_DATE_TAKEN };
2813         int32_t errCode = 0;
2814         int64_t dateTaken = 0;
2815         shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
2816         if (GetDateTakenFromResultSet(resultSet, dateTaken)) {
2817             if (dateTaken > SECONDS_LEVEL_LIMIT) {
2818                 dateTaken = dateTaken / MSEC_TO_SEC;
2819             }
2820             string detailTime = MediaFileUtils::StrCreateTime(PhotoColumn::PHOTO_DETAIL_TIME_FORMAT, dateTaken);
2821             napi_create_string_utf8(env, detailTime.c_str(), NAPI_AUTO_LENGTH, &jsResult);
2822             UpdateDetailTimeByDateTaken(env, fileAssetPtr, detailTime);
2823         } else {
2824             NapiError::ThrowError(env, JS_INNER_FAIL);
2825         }
2826     }
2827     return jsResult;
2828 }
2829 
HandleDateTransitionKey(napi_env env,const string & key,const shared_ptr<FileAsset> & fileAssetPtr)2830 static napi_value HandleDateTransitionKey(napi_env env, const string &key, const shared_ptr<FileAsset> &fileAssetPtr)
2831 {
2832     napi_value jsResult = nullptr;
2833     if (fileAssetPtr->GetMemberMap().count(key) == 0) {
2834         NapiError::ThrowError(env, JS_E_FILE_KEY);
2835         return jsResult;
2836     }
2837 
2838     auto m = fileAssetPtr->GetMemberMap().at(key);
2839     if (m.index() == MEMBER_TYPE_INT64) {
2840         napi_create_int64(env, get<int64_t>(m), &jsResult);
2841     } else {
2842         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2843         return jsResult;
2844     }
2845     return jsResult;
2846 }
2847 
GetCompatDate(const string inputKey,const int64_t date)2848 static inline int64_t GetCompatDate(const string inputKey, const int64_t date)
2849 {
2850     if (inputKey == MEDIA_DATA_DB_DATE_ADDED || inputKey == MEDIA_DATA_DB_DATE_MODIFIED ||
2851         inputKey == MEDIA_DATA_DB_DATE_TRASHED || inputKey == MEDIA_DATA_DB_DATE_TAKEN) {
2852             return date / MSEC_TO_SEC;
2853         }
2854     return date;
2855 }
2856 
UserFileMgrGet(napi_env env,napi_callback_info info)2857 napi_value FileAssetNapi::UserFileMgrGet(napi_env env, napi_callback_info info)
2858 {
2859     napi_value ret = nullptr;
2860     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2861     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
2862 
2863     string inputKey;
2864     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, inputKey),
2865         JS_ERR_PARAMETER_INVALID);
2866 
2867     if (CheckSystemApiKeys(env, inputKey) < 0) {
2868         return nullptr;
2869     }
2870 
2871     napi_value jsResult = nullptr;
2872     auto obj = asyncContext->objectInfo;
2873     napi_get_undefined(env, &jsResult);
2874     if (DATE_TRANSITION_MAP.count(inputKey) != 0) {
2875         return HandleDateTransitionKey(env, DATE_TRANSITION_MAP.at(inputKey), obj->fileAssetPtr);
2876     }
2877 
2878     if (obj->fileAssetPtr->GetMemberMap().count(inputKey) == 0) {
2879         // no exist throw error
2880         NapiError::ThrowError(env, JS_E_FILE_KEY);
2881         return jsResult;
2882     }
2883 
2884     if (IsSpecialKey(inputKey)) {
2885         return HandleGettingSpecialKey(env, inputKey, obj->fileAssetPtr);
2886     }
2887     if (inputKey == PhotoColumn::PHOTO_DETAIL_TIME) {
2888         return HandleGettingDetailTimeKey(env, obj->fileAssetPtr);
2889     }
2890     auto m = obj->fileAssetPtr->GetMemberMap().at(inputKey);
2891     if (m.index() == MEMBER_TYPE_STRING) {
2892         napi_create_string_utf8(env, get<string>(m).c_str(), NAPI_AUTO_LENGTH, &jsResult);
2893     } else if (m.index() == MEMBER_TYPE_INT32) {
2894         napi_create_int32(env, get<int32_t>(m), &jsResult);
2895     } else if (m.index() == MEMBER_TYPE_INT64) {
2896         napi_create_int64(env, GetCompatDate(inputKey, get<int64_t>(m)), &jsResult);
2897     } else {
2898         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2899         return jsResult;
2900     }
2901     return jsResult;
2902 }
2903 
HandleParamSet(const string & inputKey,const string & value,ResultNapiType resultNapiType)2904 bool FileAssetNapi::HandleParamSet(const string &inputKey, const string &value, ResultNapiType resultNapiType)
2905 {
2906     if (resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
2907         if (inputKey == MediaColumn::MEDIA_TITLE) {
2908             fileAssetPtr->SetTitle(value);
2909         } else {
2910             NAPI_ERR_LOG("invalid key %{private}s, no support key", inputKey.c_str());
2911             return false;
2912         }
2913     } else if (resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
2914         if (inputKey == MediaColumn::MEDIA_NAME) {
2915             fileAssetPtr->SetDisplayName(value);
2916             fileAssetPtr->SetTitle(MediaFileUtils::GetTitleFromDisplayName(value));
2917         } else if (inputKey == MediaColumn::MEDIA_TITLE) {
2918             fileAssetPtr->SetTitle(value);
2919             string displayName = fileAssetPtr->GetDisplayName();
2920             if (!displayName.empty()) {
2921                 string extention = MediaFileUtils::SplitByChar(displayName, '.');
2922                 fileAssetPtr->SetDisplayName(value + "." + extention);
2923             }
2924         } else {
2925             NAPI_ERR_LOG("invalid key %{private}s, no support key", inputKey.c_str());
2926             return false;
2927         }
2928     } else {
2929         NAPI_ERR_LOG("invalid resultNapiType");
2930         return false;
2931     }
2932     return true;
2933 }
2934 
UserFileMgrSet(napi_env env,napi_callback_info info)2935 napi_value FileAssetNapi::UserFileMgrSet(napi_env env, napi_callback_info info)
2936 {
2937     MediaLibraryTracer tracer;
2938     tracer.Start("UserFileMgrSet");
2939 
2940     napi_value ret = nullptr;
2941     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2942     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
2943     string inputKey;
2944     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, inputKey),
2945         JS_ERR_PARAMETER_INVALID);
2946     string value;
2947     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[ARGS_ONE], value),
2948         JS_ERR_PARAMETER_INVALID);
2949     napi_value jsResult = nullptr;
2950     napi_get_undefined(env, &jsResult);
2951     auto obj = asyncContext->objectInfo;
2952     if (!obj->HandleParamSet(inputKey, value, obj->fileAssetPtr->GetResultNapiType())) {
2953         NapiError::ThrowError(env, JS_E_FILE_KEY);
2954         return jsResult;
2955     }
2956     return jsResult;
2957 }
2958 
UserFileMgrCommitModify(napi_env env,napi_callback_info info)2959 napi_value FileAssetNapi::UserFileMgrCommitModify(napi_env env, napi_callback_info info)
2960 {
2961     MediaLibraryTracer tracer;
2962     tracer.Start("UserFileMgrCommitModify");
2963 
2964     napi_value ret = nullptr;
2965     auto asyncContext = make_unique<FileAssetAsyncContext>();
2966     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
2967     NAPI_ASSERT(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
2968         "Failed to parse js args");
2969     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2970     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
2971 
2972     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCommitModify",
2973         JSCommitModifyExecute, JSCommitModifyCompleteCallback);
2974 }
2975 
UserFileMgrFavoriteComplete(napi_env env,napi_status status,void * data)2976 static void UserFileMgrFavoriteComplete(napi_env env, napi_status status, void *data)
2977 {
2978     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2979     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2980     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2981     jsContext->status = false;
2982 
2983     if (context->error == ERR_DEFAULT) {
2984         napi_create_int32(env, context->changedRows, &jsContext->data);
2985         jsContext->status = true;
2986         napi_get_undefined(env, &jsContext->error);
2987     } else {
2988         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
2989             "Failed to modify favorite state");
2990         napi_get_undefined(env, &jsContext->data);
2991     }
2992 
2993     if (context->work != nullptr) {
2994         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2995             context->work, *jsContext);
2996     }
2997     delete context;
2998 }
2999 
UserFileMgrFavoriteExecute(napi_env env,void * data)3000 static void UserFileMgrFavoriteExecute(napi_env env, void *data)
3001 {
3002     MediaLibraryTracer tracer;
3003     tracer.Start("UserFileMgrFavoriteExecute");
3004 
3005     auto *context = static_cast<FileAssetAsyncContext *>(data);
3006 
3007     string uri;
3008     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3009         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3010         uri = UFM_UPDATE_PHOTO;
3011     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
3012         uri = UFM_UPDATE_AUDIO;
3013     }
3014 
3015     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3016     Uri updateAssetUri(uri);
3017     DataSharePredicates predicates;
3018     DataShareValuesBucket valuesBucket;
3019     int32_t changedRows;
3020     valuesBucket.Put(MediaColumn::MEDIA_IS_FAV, context->isFavorite ? IS_FAV : NOT_FAV);
3021     NAPI_INFO_LOG("update asset %{public}d favorite to %{public}d", context->objectPtr->GetId(),
3022         context->isFavorite ? IS_FAV : NOT_FAV);
3023     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3024     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
3025 
3026     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3027     if (changedRows < 0) {
3028         context->SaveError(changedRows);
3029         NAPI_ERR_LOG("Failed to modify favorite state, err: %{public}d", changedRows);
3030     } else {
3031         context->objectPtr->SetFavorite(context->isFavorite);
3032         context->changedRows = changedRows;
3033     }
3034 }
3035 
UserFileMgrFavorite(napi_env env,napi_callback_info info)3036 napi_value FileAssetNapi::UserFileMgrFavorite(napi_env env, napi_callback_info info)
3037 {
3038     auto asyncContext = make_unique<FileAssetAsyncContext>();
3039     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3040     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isFavorite),
3041         JS_ERR_PARAMETER_INVALID);
3042     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3043     CHECK_NULLPTR_RET(asyncContext->objectPtr);
3044 
3045     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrFavorite",
3046         UserFileMgrFavoriteExecute, UserFileMgrFavoriteComplete);
3047 }
UserFileMgrGetThumbnail(napi_env env,napi_callback_info info)3048 napi_value FileAssetNapi::UserFileMgrGetThumbnail(napi_env env, napi_callback_info info)
3049 {
3050     MediaLibraryTracer tracer;
3051     tracer.Start("UserFileMgrGetThumbnail");
3052 
3053     auto asyncContext = make_unique<FileAssetAsyncContext>();
3054     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_TWO),
3055         JS_INNER_FAIL);
3056     CHECK_NULLPTR_RET(GetJSArgsForGetThumbnail(env, asyncContext->argc, asyncContext->argv, asyncContext));
3057 
3058     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3059     CHECK_NULLPTR_RET(asyncContext->objectPtr);
3060     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3061 
3062     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetThumbnail",
3063         [](napi_env env, void *data) {
3064             auto context = static_cast<FileAssetAsyncContext*>(data);
3065             JSGetThumbnailExecute(context);
3066         },
3067         reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback));
3068 }
3069 
ParseArgsUserFileMgrOpen(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context,bool isReadOnly)3070 static napi_value ParseArgsUserFileMgrOpen(napi_env env, napi_callback_info info,
3071     unique_ptr<FileAssetAsyncContext> &context, bool isReadOnly)
3072 {
3073     if (!isReadOnly && !MediaLibraryNapiUtils::IsSystemApp()) {
3074         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3075         return nullptr;
3076     }
3077 
3078     size_t minArgs = ARGS_ZERO;
3079     size_t maxArgs = ARGS_ONE;
3080     if (!isReadOnly) {
3081         minArgs++;
3082         maxArgs++;
3083     }
3084     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3085         JS_ERR_PARAMETER_INVALID);
3086     auto fileUri = context->objectInfo->GetFileUri();
3087     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3088     context->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
3089 
3090     if (isReadOnly) {
3091         context->valuesBucket.Put(MEDIA_FILEMODE, MEDIA_FILEMODE_READONLY);
3092     } else {
3093         string mode;
3094         CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], mode),
3095             JS_ERR_PARAMETER_INVALID);
3096         transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
3097         if (!MediaFileUtils::CheckMode(mode)) {
3098             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3099             return nullptr;
3100         }
3101         context->valuesBucket.Put(MEDIA_FILEMODE, mode);
3102     }
3103 
3104     napi_value result = nullptr;
3105     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3106     return result;
3107 }
3108 
UserFileMgrOpenExecute(napi_env env,void * data)3109 static void UserFileMgrOpenExecute(napi_env env, void *data)
3110 {
3111     MediaLibraryTracer tracer;
3112     tracer.Start("JSOpenExecute");
3113 
3114     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3115     bool isValid = false;
3116     string mode = context->valuesBucket.Get(MEDIA_FILEMODE, isValid);
3117     if (!isValid) {
3118         context->SaveError(-EINVAL);
3119         return;
3120     }
3121     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
3122     if (!isValid) {
3123         context->SaveError(-EINVAL);
3124         return ;
3125     }
3126 
3127     MediaFileUtils::UriAppendKeyValue(fileUri, MediaColumn::MEDIA_TIME_PENDING,
3128         to_string(context->objectPtr->GetTimePending()));
3129     Uri openFileUri(fileUri);
3130     int32_t retVal = UserFileClient::OpenFile(openFileUri, mode);
3131     if (retVal <= 0) {
3132         context->SaveError(retVal);
3133         NAPI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
3134     } else {
3135         context->fd = retVal;
3136         if (mode.find('w') != string::npos) {
3137             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
3138         } else {
3139             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
3140         }
3141         if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
3142             context->objectPtr->SetTimePending(UNCLOSE_FILE_TIMEPENDING);
3143         }
3144     }
3145 }
3146 
UserFileMgrOpenCallbackComplete(napi_env env,napi_status status,void * data)3147 static void UserFileMgrOpenCallbackComplete(napi_env env, napi_status status, void *data)
3148 {
3149     MediaLibraryTracer tracer;
3150     tracer.Start("UserFileMgrOpenCallbackComplete");
3151 
3152     auto *context = static_cast<FileAssetAsyncContext *>(data);
3153     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3154 
3155     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3156     jsContext->status = false;
3157 
3158     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3159     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3160     if (context->error == ERR_DEFAULT) {
3161         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->fd, &jsContext->data), JS_INNER_FAIL);
3162         jsContext->status = true;
3163     } else {
3164         context->HandleError(env, jsContext->error);
3165     }
3166 
3167     tracer.Finish();
3168     if (context->work != nullptr) {
3169         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3170                                                    context->work, *jsContext);
3171     }
3172     delete context;
3173 }
3174 
JSGetAnalysisDataCompleteCallback(napi_env env,napi_status status,void * data)3175 static void JSGetAnalysisDataCompleteCallback(napi_env env, napi_status status, void *data)
3176 {
3177     MediaLibraryTracer tracer;
3178     tracer.Start("JSGetAnalysisDataCompleteCallback");
3179 
3180     auto *context = static_cast<FileAssetAsyncContext *>(data);
3181     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3182 
3183     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3184     jsContext->status = false;
3185 
3186     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3187     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3188     if (context->error == ERR_DEFAULT) {
3189         CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, context->analysisData.c_str(),
3190             NAPI_AUTO_LENGTH, &jsContext->data), JS_INNER_FAIL);
3191         jsContext->status = true;
3192     } else {
3193         context->HandleError(env, jsContext->error);
3194     }
3195 
3196     tracer.Finish();
3197     if (context->work != nullptr) {
3198         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3199                                                    context->work, *jsContext);
3200     }
3201     delete context;
3202 }
3203 
UserFileMgrOpen(napi_env env,napi_callback_info info)3204 napi_value FileAssetNapi::UserFileMgrOpen(napi_env env, napi_callback_info info)
3205 {
3206     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3207     CHECK_NULLPTR_RET(ParseArgsUserFileMgrOpen(env, info, asyncContext, false));
3208     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3209         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3210         return nullptr;
3211     }
3212     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3213 
3214     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrOpen",
3215         UserFileMgrOpenExecute, UserFileMgrOpenCallbackComplete);
3216 }
3217 
JSGetReadOnlyFd(napi_env env,napi_callback_info info)3218 napi_value FileAssetNapi::JSGetReadOnlyFd(napi_env env, napi_callback_info info)
3219 {
3220     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3221     CHECK_NULLPTR_RET(ParseArgsUserFileMgrOpen(env, info, asyncContext, true));
3222     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3223         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3224         return nullptr;
3225     }
3226     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3227 
3228     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets", UserFileMgrOpenExecute,
3229         UserFileMgrOpenCallbackComplete);
3230 }
3231 
ParseArgsUserFileMgrClose(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context)3232 static napi_value ParseArgsUserFileMgrClose(napi_env env, napi_callback_info info,
3233     unique_ptr<FileAssetAsyncContext> &context)
3234 {
3235     size_t minArgs = ARGS_ONE;
3236     size_t maxArgs = ARGS_TWO;
3237     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3238         JS_ERR_PARAMETER_INVALID);
3239     context->valuesBucket.Put(MEDIA_DATA_DB_URI, context->objectInfo->GetFileUri());
3240 
3241     int32_t fd = 0;
3242     CHECK_COND(env, MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], fd), JS_ERR_PARAMETER_INVALID);
3243     if (fd <= 0) {
3244         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3245         return nullptr;
3246     }
3247     context->fd = fd;
3248 
3249     napi_value result = nullptr;
3250     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3251     return result;
3252 }
3253 
UserFileMgrCloseExecute(napi_env env,void * data)3254 static void UserFileMgrCloseExecute(napi_env env, void *data)
3255 {
3256     MediaLibraryTracer tracer;
3257     tracer.Start("UserFileMgrCloseExecute");
3258 
3259     auto *context = static_cast<FileAssetAsyncContext*>(data);
3260     UniqueFd unifd(context->fd);
3261     if (!CheckFileOpenStatus(context, unifd.Get())) {
3262         return;
3263     }
3264     string closeUri;
3265     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3266         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3267         closeUri = UFM_CLOSE_PHOTO;
3268     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
3269         closeUri = UFM_CLOSE_AUDIO;
3270     } else {
3271         context->SaveError(-EINVAL);
3272         return;
3273     }
3274     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3275     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, MediaColumn::MEDIA_TIME_PENDING,
3276         to_string(context->objectPtr->GetTimePending()));
3277     Uri closeAssetUri(closeUri);
3278     int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
3279     if (ret != E_SUCCESS) {
3280         context->SaveError(ret);
3281     } else {
3282         if (context->objectPtr->GetTimePending() == UNCLOSE_FILE_TIMEPENDING) {
3283             context->objectPtr->SetTimePending(0);
3284         }
3285     }
3286 }
3287 
UserFileMgrCloseCallbackComplete(napi_env env,napi_status status,void * data)3288 static void UserFileMgrCloseCallbackComplete(napi_env env, napi_status status, void *data)
3289 {
3290     MediaLibraryTracer tracer;
3291     tracer.Start("UserFileMgrCloseCallbackComplete");
3292 
3293     auto context = static_cast<FileAssetAsyncContext *>(data);
3294     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3295 
3296     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3297     jsContext->status = false;
3298 
3299     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3300     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3301     if (context->error == ERR_DEFAULT) {
3302         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, E_SUCCESS, &jsContext->data), JS_INNER_FAIL);
3303         jsContext->status = true;
3304     } else {
3305         context->HandleError(env, jsContext->error);
3306     }
3307 
3308     tracer.Finish();
3309     if (context->work != nullptr) {
3310         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3311                                                    context->work, *jsContext);
3312     }
3313     delete context;
3314 }
3315 
UserFileMgrClose(napi_env env,napi_callback_info info)3316 napi_value FileAssetNapi::UserFileMgrClose(napi_env env, napi_callback_info info)
3317 {
3318     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3319     CHECK_NULLPTR_RET(ParseArgsUserFileMgrClose(env, info, asyncContext));
3320     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3321         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3322         return nullptr;
3323     }
3324     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3325 
3326     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets", UserFileMgrCloseExecute,
3327         UserFileMgrCloseCallbackComplete);
3328 }
3329 
UserFileMgrSetHiddenExecute(napi_env env,void * data)3330 static void UserFileMgrSetHiddenExecute(napi_env env, void *data)
3331 {
3332     MediaLibraryTracer tracer;
3333     tracer.Start("UserFileMgrSetHiddenExecute");
3334 
3335     auto *context = static_cast<FileAssetAsyncContext *>(data);
3336     if (context->objectPtr->GetMediaType() != MEDIA_TYPE_IMAGE &&
3337         context->objectPtr->GetMediaType() != MEDIA_TYPE_VIDEO) {
3338         context->SaveError(-EINVAL);
3339         return;
3340     }
3341 
3342     string uri = UFM_HIDE_PHOTO;
3343     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3344     Uri updateAssetUri(uri);
3345     DataSharePredicates predicates;
3346     predicates.In(MediaColumn::MEDIA_ID, vector<string>({ context->objectPtr->GetUri() }));
3347     DataShareValuesBucket valuesBucket;
3348     valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, context->isHidden ? IS_HIDDEN : NOT_HIDDEN);
3349 
3350     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3351     if (changedRows < 0) {
3352         context->SaveError(changedRows);
3353         NAPI_ERR_LOG("Failed to modify hidden state, err: %{public}d", changedRows);
3354     } else {
3355         context->objectPtr->SetHidden(context->isHidden);
3356         context->changedRows = changedRows;
3357     }
3358 }
3359 
UserFileMgrSetHiddenComplete(napi_env env,napi_status status,void * data)3360 static void UserFileMgrSetHiddenComplete(napi_env env, napi_status status, void *data)
3361 {
3362     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3363     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3364     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3365     jsContext->status = false;
3366 
3367     if (context->error == ERR_DEFAULT) {
3368         napi_create_int32(env, context->changedRows, &jsContext->data);
3369         jsContext->status = true;
3370         napi_get_undefined(env, &jsContext->error);
3371     } else {
3372         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3373             "Failed to modify hidden state");
3374         napi_get_undefined(env, &jsContext->data);
3375     }
3376 
3377     if (context->work != nullptr) {
3378         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3379             context->work, *jsContext);
3380     }
3381     delete context;
3382 }
3383 
UserFileMgrSetHidden(napi_env env,napi_callback_info info)3384 napi_value FileAssetNapi::UserFileMgrSetHidden(napi_env env, napi_callback_info info)
3385 {
3386     MediaLibraryTracer tracer;
3387     tracer.Start("UserFileMgrSetHidden");
3388 
3389     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3390     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3391     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isHidden),
3392         JS_ERR_PARAMETER_INVALID);
3393     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3394     CHECK_NULLPTR_RET(asyncContext->objectPtr);
3395 
3396     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetHidden",
3397         UserFileMgrSetHiddenExecute, UserFileMgrSetHiddenComplete);
3398 }
3399 
UserFileMgrSetPendingExecute(napi_env env,void * data)3400 static void UserFileMgrSetPendingExecute(napi_env env, void *data)
3401 {
3402     MediaLibraryTracer tracer;
3403     tracer.Start("UserFileMgrSetPendingExecute");
3404     auto *context = static_cast<FileAssetAsyncContext*>(data);
3405 
3406     string uri = MEDIALIBRARY_DATA_URI + "/";
3407     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3408         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3409         uri += UFM_PHOTO + "/" + OPRN_PENDING;
3410     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
3411         uri += UFM_AUDIO + "/" + OPRN_PENDING;
3412     } else {
3413         context->error = OHOS_INVALID_PARAM_CODE;
3414         return;
3415     }
3416 
3417     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3418     Uri updateAssetUri(uri);
3419     DataSharePredicates predicates;
3420     DataShareValuesBucket valuesBucket;
3421     int32_t changedRows;
3422     valuesBucket.Put(MediaColumn::MEDIA_TIME_PENDING, context->isPending ? 1 : 0);
3423     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3424     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
3425 
3426     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3427     if (changedRows < 0) {
3428         context->SaveError(E_FAIL);
3429         NAPI_ERR_LOG("Failed to modify pending state, err: %{public}d", changedRows);
3430     } else {
3431         context->changedRows = changedRows;
3432         context->objectPtr->SetTimePending((context->isPending) ? 1 : 0);
3433     }
3434 }
3435 
UserFileMgrSetPendingComplete(napi_env env,napi_status status,void * data)3436 static void UserFileMgrSetPendingComplete(napi_env env, napi_status status, void *data)
3437 {
3438     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3439     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3440     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3441     jsContext->status = false;
3442 
3443     if (context->error == ERR_DEFAULT) {
3444         napi_create_int32(env, context->changedRows, &jsContext->data);
3445         jsContext->status = true;
3446         napi_get_undefined(env, &jsContext->error);
3447     } else {
3448         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3449             "Failed to modify pending state");
3450         napi_get_undefined(env, &jsContext->data);
3451     }
3452 
3453     if (context->work != nullptr) {
3454         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3455             context->work, *jsContext);
3456     }
3457     delete context;
3458 }
3459 
UserFileMgrSetPending(napi_env env,napi_callback_info info)3460 napi_value FileAssetNapi::UserFileMgrSetPending(napi_env env, napi_callback_info info)
3461 {
3462     MediaLibraryTracer tracer;
3463     tracer.Start("UserFileMgrSetPending");
3464 
3465     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3466     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3467     CHECK_ARGS_THROW_INVALID_PARAM(env,
3468         MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isPending));
3469     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3470     CHECK_NULLPTR_RET(asyncContext->objectPtr);
3471 
3472     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetPending",
3473         UserFileMgrSetPendingExecute, UserFileMgrSetPendingComplete);
3474 }
3475 
UserFileMgrGetExifExecute(napi_env env,void * data)3476 static void UserFileMgrGetExifExecute(napi_env env, void *data) {}
3477 
CheckNapiCallerPermission(const std::string & permission)3478 static bool CheckNapiCallerPermission(const std::string &permission)
3479 {
3480     MediaLibraryTracer tracer;
3481     tracer.Start("CheckNapiCallerPermission");
3482 
3483     AccessTokenID tokenCaller = IPCSkeleton::GetSelfTokenID();
3484     int res = AccessTokenKit::VerifyAccessToken(tokenCaller, permission);
3485     if (res != PermissionState::PERMISSION_GRANTED) {
3486         NAPI_ERR_LOG("Have no media permission: %{public}s", permission.c_str());
3487         return false;
3488     }
3489 
3490     return true;
3491 }
3492 
UserFileMgrGetExifComplete(napi_env env,napi_status status,void * data)3493 static void UserFileMgrGetExifComplete(napi_env env, napi_status status, void *data)
3494 {
3495     auto *context = static_cast<FileAssetAsyncContext*>(data);
3496     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3497     auto jsContext = make_unique<JSAsyncContextOutput>();
3498     jsContext->status = false;
3499 
3500     auto *obj = context->objectInfo;
3501     nlohmann::json allExifJson;
3502     if (!obj->GetAllExif().empty() && nlohmann::json::accept(obj->GetAllExif())) {
3503         allExifJson = nlohmann::json::parse(obj->GetAllExif());
3504     }
3505     if (allExifJson.is_discarded() || obj->GetAllExif().empty()) {
3506         NAPI_ERR_LOG("parse json failed");
3507         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
3508             "parse json failed");
3509         napi_get_undefined(env, &jsContext->data);
3510     } else {
3511         const std::string PERMISSION_NAME_MEDIA_LOCATION = "ohos.permission.MEDIA_LOCATION";
3512         auto err = CheckNapiCallerPermission(PERMISSION_NAME_MEDIA_LOCATION);
3513         if (err == false) {
3514             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LATITUDE);
3515             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LONGITUDE);
3516             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LATITUDE_REF);
3517             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LONGITUDE_REF);
3518         }
3519         allExifJson[PHOTO_DATA_IMAGE_USER_COMMENT] = obj->GetUserComment();
3520         allExifJson[PHOTO_DATA_IMAGE_IMAGE_DESCRIPTION] =
3521             AppFileService::SandboxHelper::Decode(allExifJson[PHOTO_DATA_IMAGE_IMAGE_DESCRIPTION]);
3522         string allExifJsonStr = allExifJson.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
3523         napi_create_string_utf8(env, allExifJsonStr.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
3524         jsContext->status = true;
3525         napi_get_undefined(env, &jsContext->error);
3526     }
3527 
3528     if (context->work != nullptr) {
3529         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3530             context->work, *jsContext);
3531     }
3532     delete context;
3533 }
3534 
JSGetExif(napi_env env,napi_callback_info info)3535 napi_value FileAssetNapi::JSGetExif(napi_env env, napi_callback_info info)
3536 {
3537     MediaLibraryTracer tracer;
3538     tracer.Start("JSGetExif");
3539 
3540     if (!MediaLibraryNapiUtils::IsSystemApp()) {
3541         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3542         return nullptr;
3543     }
3544 
3545     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3546     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_ONE),
3547         JS_ERR_PARAMETER_INVALID);
3548     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3549     CHECK_NULLPTR_RET(asyncContext->objectPtr);
3550 
3551     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetExif", UserFileMgrGetExifExecute,
3552         UserFileMgrGetExifComplete);
3553 }
3554 
UserFileMgrSetUserCommentComplete(napi_env env,napi_status status,void * data)3555 static void UserFileMgrSetUserCommentComplete(napi_env env, napi_status status, void *data)
3556 {
3557     auto *context = static_cast<FileAssetAsyncContext*>(data);
3558     auto jsContext = make_unique<JSAsyncContextOutput>();
3559     jsContext->status = false;
3560 
3561     if (context->error == ERR_DEFAULT) {
3562         napi_create_int32(env, context->changedRows, &jsContext->data);
3563         jsContext->status = true;
3564         napi_get_undefined(env, &jsContext->error);
3565     } else {
3566         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3567             "Failed to edit user comment");
3568         napi_get_undefined(env, &jsContext->data);
3569     }
3570 
3571     if (context->work != nullptr) {
3572         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3573             context->work, *jsContext);
3574     }
3575     delete context;
3576 }
3577 
UserFileMgrSetUserCommentExecute(napi_env env,void * data)3578 static void UserFileMgrSetUserCommentExecute(napi_env env, void *data)
3579 {
3580     MediaLibraryTracer tracer;
3581     tracer.Start("UserFileMgrSetUserCommentExecute");
3582 
3583     auto *context = static_cast<FileAssetAsyncContext *>(data);
3584     string uri = UFM_SET_USER_COMMENT;
3585     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3586     Uri editUserCommentUri(uri);
3587     DataSharePredicates predicates;
3588     DataShareValuesBucket valuesBucket;
3589     valuesBucket.Put(PhotoColumn::PHOTO_USER_COMMENT, context->userComment);
3590     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3591     predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
3592     int32_t changedRows = UserFileClient::Update(editUserCommentUri, predicates, valuesBucket);
3593     if (changedRows < 0) {
3594         context->SaveError(changedRows);
3595         NAPI_ERR_LOG("Failed to modify user comment, err: %{public}d", changedRows);
3596     } else {
3597         context->objectPtr->SetUserComment(context->userComment);
3598         context->changedRows = changedRows;
3599     }
3600 }
3601 
UserFileMgrSetUserComment(napi_env env,napi_callback_info info)3602 napi_value FileAssetNapi::UserFileMgrSetUserComment(napi_env env, napi_callback_info info)
3603 {
3604     MediaLibraryTracer tracer;
3605     tracer.Start("UserFileMgrSetUserComment");
3606 
3607     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3608     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3609     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->userComment),
3610         JS_ERR_PARAMETER_INVALID);
3611     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3612     if (asyncContext->objectPtr == nullptr) {
3613         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3614         return nullptr;
3615     }
3616 
3617     if (asyncContext->userComment.length() > USER_COMMENT_MAX_LEN) {
3618         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "user comment too long");
3619         return nullptr;
3620     }
3621 
3622     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetUserComment",
3623         UserFileMgrSetUserCommentExecute, UserFileMgrSetUserCommentComplete);
3624 }
3625 
ParseArgsPhotoAccessHelperOpen(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context,bool isReadOnly)3626 static napi_value ParseArgsPhotoAccessHelperOpen(napi_env env, napi_callback_info info,
3627     unique_ptr<FileAssetAsyncContext> &context, bool isReadOnly)
3628 {
3629     if (!isReadOnly && !MediaLibraryNapiUtils::IsSystemApp()) {
3630         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
3631         return nullptr;
3632     }
3633     size_t minArgs = ARGS_ZERO;
3634     size_t maxArgs = ARGS_ONE;
3635     if (!isReadOnly) {
3636         minArgs++;
3637         maxArgs++;
3638     }
3639     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3640         JS_ERR_PARAMETER_INVALID);
3641     auto fileUri = context->objectInfo->GetFileUri();
3642     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3643     context->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
3644 
3645     if (isReadOnly) {
3646         context->valuesBucket.Put(MEDIA_FILEMODE, MEDIA_FILEMODE_READONLY);
3647     } else {
3648         string mode;
3649         CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], mode),
3650             JS_ERR_PARAMETER_INVALID);
3651         transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
3652         if (!MediaFileUtils::CheckMode(mode)) {
3653             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3654             return nullptr;
3655         }
3656         context->valuesBucket.Put(MEDIA_FILEMODE, mode);
3657     }
3658 
3659     napi_value result = nullptr;
3660     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3661     return result;
3662 }
3663 
PhotoAccessHelperOpenExecute(napi_env env,void * data)3664 static void PhotoAccessHelperOpenExecute(napi_env env, void *data)
3665 {
3666     MediaLibraryTracer tracer;
3667     tracer.Start("PhotoAccessHelperOpenExecute");
3668 
3669     auto *context = static_cast<FileAssetAsyncContext*>(data);
3670     bool isValid = false;
3671     string mode = context->valuesBucket.Get(MEDIA_FILEMODE, isValid);
3672     if (!isValid) {
3673         context->SaveError(-EINVAL);
3674         return;
3675     }
3676     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
3677     if (!isValid) {
3678         context->SaveError(-EINVAL);
3679         return ;
3680     }
3681 
3682     if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
3683         MediaFileUtils::UriAppendKeyValue(fileUri, MediaColumn::MEDIA_TIME_PENDING,
3684             to_string(context->objectPtr->GetTimePending()));
3685     }
3686     Uri openFileUri(fileUri);
3687     int32_t retVal = UserFileClient::OpenFile(openFileUri, mode);
3688     if (retVal <= 0) {
3689         context->SaveError(retVal);
3690         NAPI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
3691     } else {
3692         context->fd = retVal;
3693         if (mode.find('w') != string::npos) {
3694             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
3695         } else {
3696             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
3697         }
3698         if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
3699             context->objectPtr->SetTimePending(UNCLOSE_FILE_TIMEPENDING);
3700         }
3701     }
3702 }
3703 
PhotoAccessHelperOpenCallbackComplete(napi_env env,napi_status status,void * data)3704 static void PhotoAccessHelperOpenCallbackComplete(napi_env env, napi_status status, void *data)
3705 {
3706     MediaLibraryTracer tracer;
3707     tracer.Start("PhotoAccessHelperOpenCallbackComplete");
3708 
3709     auto context = static_cast<FileAssetAsyncContext *>(data);
3710     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3711 
3712     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3713     jsContext->status = false;
3714 
3715     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3716     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3717     if (context->error == ERR_DEFAULT) {
3718         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->fd, &jsContext->data), JS_INNER_FAIL);
3719         jsContext->status = true;
3720     } else {
3721         context->HandleError(env, jsContext->error);
3722     }
3723 
3724     tracer.Finish();
3725     if (context->work != nullptr) {
3726         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3727                                                    context->work, *jsContext);
3728     }
3729     delete context;
3730 }
3731 
PhotoAccessHelperOpen(napi_env env,napi_callback_info info)3732 napi_value FileAssetNapi::PhotoAccessHelperOpen(napi_env env, napi_callback_info info)
3733 {
3734     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3735     CHECK_NULLPTR_RET(ParseArgsPhotoAccessHelperOpen(env, info, asyncContext, false));
3736     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3737         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3738         return nullptr;
3739     }
3740     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3741 
3742     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperOpen",
3743         PhotoAccessHelperOpenExecute, PhotoAccessHelperOpenCallbackComplete);
3744 }
3745 
ParseArgsPhotoAccessHelperClose(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context)3746 static napi_value ParseArgsPhotoAccessHelperClose(napi_env env, napi_callback_info info,
3747     unique_ptr<FileAssetAsyncContext> &context)
3748 {
3749     size_t minArgs = ARGS_ONE;
3750     size_t maxArgs = ARGS_TWO;
3751     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3752         JS_ERR_PARAMETER_INVALID);
3753     context->valuesBucket.Put(MEDIA_DATA_DB_URI, context->objectInfo->GetFileUri());
3754 
3755     int32_t fd = 0;
3756     CHECK_COND(env, MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], fd), JS_ERR_PARAMETER_INVALID);
3757     if (fd <= 0) {
3758         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3759         return nullptr;
3760     }
3761     context->fd = fd;
3762 
3763     napi_value result = nullptr;
3764     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3765     return result;
3766 }
3767 
PhotoAccessHelperCloseExecute(napi_env env,void * data)3768 static void PhotoAccessHelperCloseExecute(napi_env env, void *data)
3769 {
3770     MediaLibraryTracer tracer;
3771     tracer.Start("PhotoAccessHelperCloseExecute");
3772 
3773     auto *context = static_cast<FileAssetAsyncContext*>(data);
3774     UniqueFd unifd(context->fd);
3775     if (!CheckFileOpenStatus(context, unifd.Get())) {
3776         return;
3777     }
3778     string closeUri;
3779     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3780         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3781         closeUri = PAH_CLOSE_PHOTO;
3782     } else {
3783         context->SaveError(-EINVAL);
3784         return;
3785     }
3786     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3787     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, MediaColumn::MEDIA_TIME_PENDING,
3788         to_string(context->objectPtr->GetTimePending()));
3789     Uri closeAssetUri(closeUri);
3790     int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
3791     if (ret != E_SUCCESS) {
3792         context->SaveError(ret);
3793     } else {
3794         if (context->objectPtr->GetTimePending() == UNCLOSE_FILE_TIMEPENDING) {
3795             context->objectPtr->SetTimePending(0);
3796         }
3797     }
3798 }
3799 
PhotoAccessHelperCloseCallbackComplete(napi_env env,napi_status status,void * data)3800 static void PhotoAccessHelperCloseCallbackComplete(napi_env env, napi_status status, void *data)
3801 {
3802     MediaLibraryTracer tracer;
3803     tracer.Start("PhotoAccessHelperCloseCallbackComplete");
3804 
3805     auto context = static_cast<FileAssetAsyncContext *>(data);
3806     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3807 
3808     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3809     jsContext->status = false;
3810 
3811     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3812     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3813     if (context->error == ERR_DEFAULT) {
3814         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, E_SUCCESS, &jsContext->data), JS_INNER_FAIL);
3815         jsContext->status = true;
3816     } else {
3817         context->HandleError(env, jsContext->error);
3818     }
3819 
3820     tracer.Finish();
3821     if (context->work != nullptr) {
3822         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3823                                                    context->work, *jsContext);
3824     }
3825     delete context;
3826 }
3827 
PhotoAccessHelperClose(napi_env env,napi_callback_info info)3828 napi_value FileAssetNapi::PhotoAccessHelperClose(napi_env env, napi_callback_info info)
3829 {
3830     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3831     CHECK_NULLPTR_RET(ParseArgsPhotoAccessHelperClose(env, info, asyncContext));
3832     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3833         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3834         return nullptr;
3835     }
3836     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3837 
3838     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperClose",
3839         PhotoAccessHelperCloseExecute, PhotoAccessHelperCloseCallbackComplete);
3840 }
3841 
getFileAsset(const std::string fileAssetId)3842 static shared_ptr<FileAsset> getFileAsset(const std::string fileAssetId)
3843 {
3844     DataSharePredicates predicates;
3845     predicates.EqualTo(MediaColumn::MEDIA_ID, fileAssetId);
3846     vector<string> columns = { MediaColumn::MEDIA_ID, MediaColumn::MEDIA_NAME, MediaColumn::MEDIA_FILE_PATH,
3847         MediaColumn::MEDIA_TITLE, MediaColumn::MEDIA_TYPE };
3848     int32_t errCode = 0;
3849     Uri uri(PAH_QUERY_PHOTO_MAP);
3850     auto resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
3851     if (resultSet == nullptr) {
3852         NAPI_INFO_LOG("Failed to get file asset, err: %{public}d", errCode);
3853         return nullptr;
3854     }
3855     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
3856     shared_ptr<FileAsset> newFileAsset = fetchResult->GetFirstObject();
3857     string newFileAssetUri = MediaFileUtils::GetFileAssetUri(newFileAsset->GetPath(), newFileAsset->GetDisplayName(),
3858         newFileAsset->GetId());
3859     newFileAsset->SetUri(newFileAssetUri);
3860     NAPI_INFO_LOG("New asset, file_id: %{public}d, uri:%{private}s", newFileAsset->GetId(),
3861         newFileAsset->GetUri().c_str());
3862     return newFileAsset;
3863 }
3864 
CloneAssetHandlerCompleteCallback(napi_env env,napi_status status,void * data)3865 static void CloneAssetHandlerCompleteCallback(napi_env env, napi_status status, void* data)
3866 {
3867     auto* context = static_cast<FileAssetAsyncContext*>(data);
3868     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3869     auto jsContext = make_unique<JSAsyncContextOutput>();
3870     jsContext->status = false;
3871     if (context->error == ERR_DEFAULT) {
3872         napi_value jsFileAsset = nullptr;
3873         int64_t assetId = context->assetId;
3874         if (assetId == 0) {
3875             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
3876                 "Clone file asset failed");
3877             napi_get_undefined(env, &jsContext->data);
3878         } else {
3879             shared_ptr<FileAsset> newFileAsset = getFileAsset(to_string(assetId));
3880             CHECK_NULL_PTR_RETURN_VOID(newFileAsset, "newFileAset is null.");
3881 
3882             newFileAsset->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
3883             jsFileAsset = FileAssetNapi::CreatePhotoAsset(env, newFileAsset);
3884             if (jsFileAsset == nullptr) {
3885                 NAPI_ERR_LOG("Failed to clone file asset napi object");
3886                 napi_get_undefined(env, &jsContext->data);
3887                 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL, "System inner fail");
3888             } else {
3889                 NAPI_DEBUG_LOG("JSCreateAssetCompleteCallback jsFileAsset != nullptr");
3890                 jsContext->data = jsFileAsset;
3891                 napi_get_undefined(env, &jsContext->error);
3892                 jsContext->status = true;
3893             }
3894         }
3895     } else {
3896         context->HandleError(env, jsContext->error);
3897         napi_get_undefined(env, &jsContext->data);
3898     }
3899 
3900     if (context->work != nullptr) {
3901         MediaLibraryNapiUtils::InvokeJSAsyncMethod(
3902             env, context->deferred, context->callbackRef, context->work, *jsContext);
3903     }
3904     delete context;
3905 }
3906 
CloneAssetHandlerExecute(napi_env env,void * data)3907 static void CloneAssetHandlerExecute(napi_env env, void *data)
3908 {
3909     MediaLibraryTracer tracer;
3910     tracer.Start("CloneAssetHandlerExecute");
3911 
3912     auto* context = static_cast<FileAssetAsyncContext*>(data);
3913     auto fileAsset = context->objectInfo->GetFileAssetInstance();
3914     if (fileAsset == nullptr) {
3915         context->SaveError(E_FAIL);
3916         NAPI_ERR_LOG("fileAsset is null");
3917         return;
3918     }
3919 
3920     DataShare::DataShareValuesBucket valuesBucket;
3921     string uri = PAH_CLONE_ASSET;
3922     MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3923     valuesBucket.Put(MediaColumn::MEDIA_ID, fileAsset->GetId());
3924     valuesBucket.Put(MediaColumn::MEDIA_TITLE, context->title);
3925     Uri cloneAssetUri(uri);
3926     int32_t newAssetId = UserFileClient::Insert(cloneAssetUri, valuesBucket);
3927     if (newAssetId < 0) {
3928         context->SaveError(newAssetId);
3929         NAPI_ERR_LOG("Failed to clone asset, ret: %{public}d", newAssetId);
3930         return;
3931     }
3932     context->assetId = newAssetId;
3933 }
3934 
PhotoAccessHelperCloneAsset(napi_env env,napi_callback_info info)3935 napi_value FileAssetNapi::PhotoAccessHelperCloneAsset(napi_env env, napi_callback_info info)
3936 {
3937     NAPI_INFO_LOG("PhotoAccessHelperCloneAsset in");
3938 
3939     auto asyncContext = make_unique<FileAssetAsyncContext>();
3940     CHECK_COND_WITH_MESSAGE(env,
3941         MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ONE, ARGS_ONE) == napi_ok,
3942         "Failed to get object info");
3943 
3944     auto changeRequest = asyncContext->objectInfo;
3945     auto fileAsset = changeRequest->GetFileAssetInstance();
3946     CHECK_COND(env, fileAsset != nullptr, JS_INNER_FAIL);
3947 
3948     string title;
3949     MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[ARGS_ZERO], title);
3950 
3951     string extension = MediaFileUtils::SplitByChar(fileAsset->GetDisplayName(), '.');
3952     string displayName = title + "." + extension;
3953     CHECK_COND_WITH_MESSAGE(env, MediaFileUtils::CheckDisplayName(displayName) == E_OK, "Input title is invalid");
3954 
3955     asyncContext->title = title;
3956     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "CloneAssetHandlerExecute",
3957         CloneAssetHandlerExecute, CloneAssetHandlerCompleteCallback);
3958 }
3959 
PhotoAccessHelperCommitModify(napi_env env,napi_callback_info info)3960 napi_value FileAssetNapi::PhotoAccessHelperCommitModify(napi_env env, napi_callback_info info)
3961 {
3962     MediaLibraryTracer tracer;
3963     tracer.Start("PhotoAccessHelperCommitModify");
3964 
3965     napi_value ret = nullptr;
3966     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3967     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3968     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
3969     NAPI_ASSERT(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
3970         "Failed to parse js args");
3971     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3972     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
3973 
3974     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCommitModify",
3975         JSCommitModifyExecute, JSCommitModifyCompleteCallback);
3976 }
3977 
PhotoAccessHelperFavoriteComplete(napi_env env,napi_status status,void * data)3978 static void PhotoAccessHelperFavoriteComplete(napi_env env, napi_status status, void *data)
3979 {
3980     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3981     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3982     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3983     jsContext->status = false;
3984 
3985     if (context->error == ERR_DEFAULT) {
3986         napi_create_int32(env, context->changedRows, &jsContext->data);
3987         jsContext->status = true;
3988         napi_get_undefined(env, &jsContext->error);
3989     } else {
3990         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3991             "Failed to modify favorite state");
3992         napi_get_undefined(env, &jsContext->data);
3993     }
3994 
3995     if (context->work != nullptr) {
3996         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3997             context->work, *jsContext);
3998     }
3999     delete context;
4000 }
4001 
PhotoAccessHelperFavoriteExecute(napi_env env,void * data)4002 static void PhotoAccessHelperFavoriteExecute(napi_env env, void *data)
4003 {
4004     MediaLibraryTracer tracer;
4005     tracer.Start("PhotoAccessHelperFavoriteExecute");
4006 
4007     auto *context = static_cast<FileAssetAsyncContext *>(data);
4008     string uri;
4009     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
4010         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
4011         uri = PAH_UPDATE_PHOTO;
4012     } else {
4013         context->SaveError(-EINVAL);
4014         return;
4015     }
4016 
4017     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4018     Uri updateAssetUri(uri);
4019     DataSharePredicates predicates;
4020     DataShareValuesBucket valuesBucket;
4021     int32_t changedRows = 0;
4022     valuesBucket.Put(MediaColumn::MEDIA_IS_FAV, context->isFavorite ? IS_FAV : NOT_FAV);
4023     NAPI_INFO_LOG("update asset %{public}d favorite to %{public}d", context->objectPtr->GetId(),
4024         context->isFavorite ? IS_FAV : NOT_FAV);
4025     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
4026     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
4027 
4028     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
4029     if (changedRows < 0) {
4030         context->SaveError(changedRows);
4031         NAPI_ERR_LOG("Failed to modify favorite state, err: %{public}d", changedRows);
4032     } else {
4033         context->objectPtr->SetFavorite(context->isFavorite);
4034         context->changedRows = changedRows;
4035     }
4036 }
4037 
PhotoAccessHelperFavorite(napi_env env,napi_callback_info info)4038 napi_value FileAssetNapi::PhotoAccessHelperFavorite(napi_env env, napi_callback_info info)
4039 {
4040     MediaLibraryTracer tracer;
4041     tracer.Start("PhotoAccessHelperFavorite");
4042 
4043     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4044         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4045         return nullptr;
4046     }
4047 
4048     napi_value ret = nullptr;
4049     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4050     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4051     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4052     NAPI_ASSERT(
4053         env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isFavorite) == napi_ok,
4054         "Failed to parse js args");
4055     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4056     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
4057 
4058     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperFavorite",
4059         PhotoAccessHelperFavoriteExecute, PhotoAccessHelperFavoriteComplete);
4060 }
4061 
PhotoAccessHelperGetThumbnail(napi_env env,napi_callback_info info)4062 napi_value FileAssetNapi::PhotoAccessHelperGetThumbnail(napi_env env, napi_callback_info info)
4063 {
4064     MediaLibraryTracer tracer;
4065     tracer.Start("PhotoAccessHelperGetThumbnail");
4066 
4067     napi_value result = nullptr;
4068     NAPI_CALL(env, napi_get_undefined(env, &result));
4069     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4070     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
4071 
4072     CHECK_COND_RET(MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_TWO) ==
4073         napi_ok, result, "Failed to get object info");
4074     result = GetJSArgsForGetThumbnail(env, asyncContext->argc, asyncContext->argv, asyncContext);
4075     ASSERT_NULLPTR_CHECK(env, result);
4076     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4077     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
4078     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4079     result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetThumbnail",
4080         [](napi_env env, void *data) {
4081             auto context = static_cast<FileAssetAsyncContext*>(data);
4082             JSGetThumbnailExecute(context);
4083         },
4084         reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback));
4085 
4086     return result;
4087 }
4088 
PhotoAccessHelperRequestPhoto(napi_env env,napi_callback_info info)4089 napi_value FileAssetNapi::PhotoAccessHelperRequestPhoto(napi_env env, napi_callback_info info)
4090 {
4091     MediaLibraryTracer tracer;
4092     tracer.Start("PhotoAccessHelperRequestPhoto");
4093 
4094     // request Photo function in API11 is system api, maybe public soon
4095     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4096         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4097         return nullptr;
4098     }
4099 
4100     napi_value result = nullptr;
4101     NAPI_CALL(env, napi_get_undefined(env, &result));
4102     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4103     CHECK_COND_WITH_MESSAGE(env, asyncContext != nullptr, "asyncContext context is null");
4104     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext,
4105         ARGS_ONE, ARGS_TWO) == napi_ok, "Failed to get object info");
4106     if (asyncContext->callbackRef == nullptr) {
4107         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Can not get callback function");
4108         return nullptr;
4109     }
4110     // use current parse args function temporary
4111     RequestPhotoType type = RequestPhotoType::REQUEST_ALL_THUMBNAILS;
4112     result = GetPhotoRequestArgs(env, asyncContext->argc, asyncContext->argv, asyncContext, type);
4113     ASSERT_NULLPTR_CHECK(env, result);
4114     auto obj = asyncContext->objectInfo;
4115     napi_value ret = nullptr;
4116     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectInfo, ret, "FileAsset is nullptr");
4117 
4118     RequestPhotoParams params = {
4119         .uri = obj->fileAssetPtr->GetUri(),
4120         .path = obj->fileAssetPtr->GetFilePath(),
4121         .size = asyncContext->size,
4122         .type = type
4123     };
4124     static std::once_flag onceFlag;
4125     std::call_once(onceFlag, []() mutable {
4126         thumbnailManager_ = ThumbnailManager::GetInstance();
4127         if (thumbnailManager_ != nullptr) {
4128             thumbnailManager_->Init();
4129         }
4130     });
4131     string requestId;
4132     if (thumbnailManager_ != nullptr) {
4133         requestId = thumbnailManager_->AddPhotoRequest(params, env, asyncContext->callbackRef);
4134     }
4135     napi_create_string_utf8(env, requestId.c_str(), NAPI_AUTO_LENGTH, &result);
4136     return result;
4137 }
4138 
PhotoAccessHelperCancelPhotoRequest(napi_env env,napi_callback_info info)4139 napi_value FileAssetNapi::PhotoAccessHelperCancelPhotoRequest(napi_env env, napi_callback_info info)
4140 {
4141     MediaLibraryTracer tracer;
4142     tracer.Start("PhotoAccessHelperCancelPhotoRequest");
4143 
4144     // request Photo function in API11 is system api, maybe public soon
4145     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4146         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4147         return nullptr;
4148     }
4149 
4150     napi_value ret = nullptr;
4151     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4152     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4153 
4154     string requestKey;
4155     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ONE,
4156         ARGS_ONE), OHOS_INVALID_PARAM_CODE);
4157     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[ARGS_ZERO], requestKey),
4158         OHOS_INVALID_PARAM_CODE);
4159     napi_value jsResult = nullptr;
4160     napi_get_undefined(env, &jsResult);
4161 
4162     if (thumbnailManager_ != nullptr) {
4163         thumbnailManager_->RemovePhotoRequest(requestKey);
4164     }
4165     return jsResult;
4166 }
4167 
PhotoAccessHelperSetHiddenExecute(napi_env env,void * data)4168 static void PhotoAccessHelperSetHiddenExecute(napi_env env, void *data)
4169 {
4170     MediaLibraryTracer tracer;
4171     tracer.Start("PhotoAccessHelperSetHiddenExecute");
4172 
4173     auto *context = static_cast<FileAssetAsyncContext *>(data);
4174     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4175     if (context->objectPtr->GetMediaType() != MEDIA_TYPE_IMAGE &&
4176         context->objectPtr->GetMediaType() != MEDIA_TYPE_VIDEO) {
4177         context->SaveError(-EINVAL);
4178         return;
4179     }
4180 
4181     string uri = PAH_HIDE_PHOTOS;
4182     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4183     Uri updateAssetUri(uri);
4184     DataSharePredicates predicates;
4185     predicates.In(MediaColumn::MEDIA_ID, vector<string>({ context->objectPtr->GetUri() }));
4186     DataShareValuesBucket valuesBucket;
4187     valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, context->isHidden ? IS_HIDDEN : NOT_HIDDEN);
4188 
4189     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
4190     if (changedRows < 0) {
4191         context->SaveError(changedRows);
4192         NAPI_ERR_LOG("Failed to modify hidden state, err: %{public}d", changedRows);
4193     } else {
4194         context->objectPtr->SetHidden(context->isHidden);
4195         context->changedRows = changedRows;
4196     }
4197 }
4198 
PhotoAccessHelperSetHiddenComplete(napi_env env,napi_status status,void * data)4199 static void PhotoAccessHelperSetHiddenComplete(napi_env env, napi_status status, void *data)
4200 {
4201     auto *context = static_cast<FileAssetAsyncContext*>(data);
4202     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4203     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4204     jsContext->status = false;
4205 
4206     if (context->error == ERR_DEFAULT) {
4207         napi_create_int32(env, context->changedRows, &jsContext->data);
4208         jsContext->status = true;
4209         napi_get_undefined(env, &jsContext->error);
4210     } else {
4211         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
4212             "Failed to modify hidden state");
4213         napi_get_undefined(env, &jsContext->data);
4214     }
4215 
4216     if (context->work != nullptr) {
4217         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4218             context->work, *jsContext);
4219     }
4220     delete context;
4221 }
4222 
PhotoAccessHelperSetHidden(napi_env env,napi_callback_info info)4223 napi_value FileAssetNapi::PhotoAccessHelperSetHidden(napi_env env, napi_callback_info info)
4224 {
4225     MediaLibraryTracer tracer;
4226     tracer.Start("PhotoAccessHelperSetHidden");
4227 
4228     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4229         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4230         return nullptr;
4231     }
4232 
4233     napi_value ret = nullptr;
4234     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4235     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4236     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4237     NAPI_ASSERT(
4238         env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isHidden) == napi_ok,
4239         "Failed to parse js args");
4240     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4241     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
4242 
4243     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetHidden",
4244         PhotoAccessHelperSetHiddenExecute, PhotoAccessHelperSetHiddenComplete);
4245 }
4246 
PhotoAccessHelperSetPendingExecute(napi_env env,void * data)4247 static void PhotoAccessHelperSetPendingExecute(napi_env env, void *data)
4248 {
4249     MediaLibraryTracer tracer;
4250     tracer.Start("PhotoAccessHelperSetPendingExecute");
4251 
4252     auto *context = static_cast<FileAssetAsyncContext *>(data);
4253     string uri = MEDIALIBRARY_DATA_URI + "/";
4254     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
4255         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
4256         uri += PAH_PHOTO + "/" + OPRN_PENDING;
4257     } else {
4258         context->SaveError(-EINVAL);
4259         return;
4260     }
4261 
4262     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4263     Uri updateAssetUri(uri);
4264     DataSharePredicates predicates;
4265     DataShareValuesBucket valuesBucket;
4266     int32_t changedRows = 0;
4267     valuesBucket.Put(MediaColumn::MEDIA_TIME_PENDING, context->isPending ? 1 : 0);
4268     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
4269     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
4270 
4271     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
4272     if (changedRows < 0) {
4273         if (changedRows == E_PERMISSION_DENIED) {
4274             context->error = OHOS_PERMISSION_DENIED_CODE;
4275         } else {
4276             context->SaveError(changedRows);
4277         }
4278 
4279         NAPI_ERR_LOG("Failed to modify pending state, err: %{public}d", changedRows);
4280     } else {
4281         context->changedRows = changedRows;
4282         context->objectPtr->SetTimePending((context->isPending) ? 1 : 0);
4283     }
4284 }
4285 
PhotoAccessHelperSetPendingComplete(napi_env env,napi_status status,void * data)4286 static void PhotoAccessHelperSetPendingComplete(napi_env env, napi_status status, void *data)
4287 {
4288     auto *context = static_cast<FileAssetAsyncContext*>(data);
4289     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4290     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4291     jsContext->status = false;
4292 
4293     if (context->error == ERR_DEFAULT) {
4294         napi_create_int32(env, context->changedRows, &jsContext->data);
4295         jsContext->status = true;
4296         napi_get_undefined(env, &jsContext->error);
4297     } else {
4298         context->HandleError(env, jsContext->error);
4299         napi_get_undefined(env, &jsContext->data);
4300     }
4301 
4302     if (context->work != nullptr) {
4303         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4304             context->work, *jsContext);
4305     }
4306     delete context;
4307 }
4308 
PhotoAccessHelperSetPending(napi_env env,napi_callback_info info)4309 napi_value FileAssetNapi::PhotoAccessHelperSetPending(napi_env env, napi_callback_info info)
4310 {
4311     MediaLibraryTracer tracer;
4312     tracer.Start("PhotoAccessHelperSetPending");
4313 
4314     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4315         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4316         return nullptr;
4317     }
4318 
4319     napi_value ret = nullptr;
4320     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4321     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
4322     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4323     CHECK_COND_WITH_MESSAGE(env,
4324         MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isPending) == napi_ok,
4325         "Failed to parse js args");
4326     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4327     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
4328 
4329     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetPending",
4330         PhotoAccessHelperSetPendingExecute, PhotoAccessHelperSetPendingComplete);
4331 }
4332 
PhotoAccessHelperSetUserCommentComplete(napi_env env,napi_status status,void * data)4333 static void PhotoAccessHelperSetUserCommentComplete(napi_env env, napi_status status, void *data)
4334 {
4335     auto *context = static_cast<FileAssetAsyncContext*>(data);
4336     auto jsContext = make_unique<JSAsyncContextOutput>();
4337     jsContext->status = false;
4338 
4339     if (context->error == ERR_DEFAULT) {
4340         napi_create_int32(env, context->changedRows, &jsContext->data);
4341         jsContext->status = true;
4342         napi_get_undefined(env, &jsContext->error);
4343     } else {
4344         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4345             "Failed to edit user comment");
4346         napi_get_undefined(env, &jsContext->data);
4347     }
4348 
4349     if (context->work != nullptr) {
4350         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4351             context->work, *jsContext);
4352     }
4353     delete context;
4354 }
4355 
UserFileMgrGetJsonComplete(napi_env env,napi_status status,void * data)4356 static void UserFileMgrGetJsonComplete(napi_env env, napi_status status, void *data)
4357 {
4358     MediaLibraryTracer tracer;
4359     tracer.Start("UserFileMgrGetJsonComplete");
4360     auto *context = static_cast<FileAssetAsyncContext *>(data);
4361     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4362     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4363     jsContext->status = false;
4364     if (context->error == ERR_DEFAULT) {
4365         napi_create_string_utf8(env, context->jsonStr.c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
4366         napi_get_undefined(env, &jsContext->error);
4367         jsContext->status = true;
4368     } else {
4369         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
4370             "UserFileClient is invalid");
4371         napi_get_undefined(env, &jsContext->data);
4372     }
4373 
4374     tracer.Finish();
4375     if (context->work != nullptr) {
4376         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4377                                                    context->work, *jsContext);
4378     }
4379     delete context;
4380 }
4381 
PhotoAccessHelperSetUserCommentExecute(napi_env env,void * data)4382 static void PhotoAccessHelperSetUserCommentExecute(napi_env env, void *data)
4383 {
4384     MediaLibraryTracer tracer;
4385     tracer.Start("PhotoAccessHelperSetUserCommentExecute");
4386 
4387     auto *context = static_cast<FileAssetAsyncContext *>(data);
4388 
4389     string uri = PAH_EDIT_USER_COMMENT_PHOTO;
4390     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4391     Uri editUserCommentUri(uri);
4392     DataSharePredicates predicates;
4393     DataShareValuesBucket valuesBucket;
4394     valuesBucket.Put(PhotoColumn::PHOTO_USER_COMMENT, context->userComment);
4395     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
4396     predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
4397     int32_t changedRows = UserFileClient::Update(editUserCommentUri, predicates, valuesBucket);
4398     if (changedRows < 0) {
4399         context->SaveError(changedRows);
4400         NAPI_ERR_LOG("Failed to modify user comment, err: %{public}d", changedRows);
4401     } else {
4402         context->objectPtr->SetUserComment(context->userComment);
4403         context->changedRows = changedRows;
4404     }
4405 }
4406 
PhotoAccessHelperSetUserComment(napi_env env,napi_callback_info info)4407 napi_value FileAssetNapi::PhotoAccessHelperSetUserComment(napi_env env, napi_callback_info info)
4408 {
4409     MediaLibraryTracer tracer;
4410     tracer.Start("PhotoAccessHelperSetUserComment");
4411 
4412     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4413         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4414         return nullptr;
4415     }
4416 
4417     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4418     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4419     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->userComment),
4420         JS_ERR_PARAMETER_INVALID);
4421     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4422     if (asyncContext->objectPtr == nullptr) {
4423         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
4424         return nullptr;
4425     }
4426 
4427     if (asyncContext->userComment.length() > USER_COMMENT_MAX_LEN) {
4428         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "user comment too long");
4429         return nullptr;
4430     }
4431 
4432     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetUserComment",
4433         PhotoAccessHelperSetUserCommentExecute, PhotoAccessHelperSetUserCommentComplete);
4434 }
4435 
PhotoAccessHelperGetAnalysisData(napi_env env,napi_callback_info info)4436 napi_value FileAssetNapi::PhotoAccessHelperGetAnalysisData(napi_env env, napi_callback_info info)
4437 {
4438     MediaLibraryTracer tracer;
4439     tracer.Start("PhotoAccessHelperGetAnalysisData");
4440 
4441     napi_value result = nullptr;
4442     NAPI_CALL(env, napi_get_undefined(env, &result));
4443     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
4444     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
4445     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsNumberCallback(env, info, asyncContext, asyncContext->analysisType),
4446         JS_ERR_PARAMETER_INVALID);
4447     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4448     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
4449     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4450     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetAnalysisData",
4451         [](napi_env env, void *data) {
4452             auto context = static_cast<FileAssetAsyncContext*>(data);
4453             JSGetAnalysisDataExecute(context);
4454         },
4455         reinterpret_cast<CompleteCallback>(JSGetAnalysisDataCompleteCallback));
4456 }
4457 
UserFileMgrGetJsonExecute(napi_env env,void * data)4458 static void UserFileMgrGetJsonExecute(napi_env env, void *data)
4459 {
4460     MediaLibraryTracer tracer;
4461     tracer.Start("UserFileMgrGetJsonExecute");
4462     auto *context = static_cast<FileAssetAsyncContext *>(data);
4463     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4464     context->jsonStr = context->objectPtr->GetAssetJson();
4465     return;
4466 }
4467 
UserFileMgrGetJson(napi_env env,napi_callback_info info)4468 napi_value FileAssetNapi::UserFileMgrGetJson(napi_env env, napi_callback_info info)
4469 {
4470     MediaLibraryTracer tracer;
4471     tracer.Start("UserFileMgrGetJson");
4472     auto asyncContext = make_unique<FileAssetAsyncContext>();
4473     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
4474     NAPI_ASSERT(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4475         "Failed to parse js args");
4476     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4477     napi_value ret = nullptr;
4478     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
4479     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetJson",
4480         UserFileMgrGetJsonExecute, UserFileMgrGetJsonComplete);
4481 }
4482 
GetEditTimeFromResultSet(const shared_ptr<DataShare::DataShareResultSet> & resultSet,int64_t & editTime)4483 static bool GetEditTimeFromResultSet(const shared_ptr<DataShare::DataShareResultSet> &resultSet,
4484     int64_t &editTime)
4485 {
4486     if (resultSet == nullptr) {
4487         NAPI_ERR_LOG("ResultSet is null");
4488         return false;
4489     }
4490     int32_t count = 0;
4491     int32_t errCode = resultSet->GetRowCount(count);
4492     if (errCode != DataShare::E_OK) {
4493         NAPI_ERR_LOG("Can not get row count from resultSet, errCode=%{public}d", errCode);
4494         return false;
4495     }
4496     if (count == 0) {
4497         NAPI_ERR_LOG("Can not find photo edit time from database");
4498         return false;
4499     }
4500     errCode = resultSet->GoToFirstRow();
4501     if (errCode != DataShare::E_OK) {
4502         NAPI_ERR_LOG("ResultSet GotoFirstRow failed, errCode=%{public}d", errCode);
4503         return false;
4504     }
4505     int32_t index = 0;
4506     errCode = resultSet->GetColumnIndex(PhotoColumn::PHOTO_EDIT_TIME, index);
4507     if (errCode != DataShare::E_OK) {
4508         NAPI_ERR_LOG("ResultSet GetColumnIndex failed, errCode=%{public}d", errCode);
4509         return false;
4510     }
4511     errCode = resultSet->GetLong(index, editTime);
4512     if (errCode != DataShare::E_OK) {
4513         NAPI_ERR_LOG("ResultSet GetLong failed, errCode=%{public}d", errCode);
4514         return false;
4515     }
4516     return true;
4517 }
4518 
PhotoAccessHelperIsEditedExecute(napi_env env,void * data)4519 static void PhotoAccessHelperIsEditedExecute(napi_env env, void *data)
4520 {
4521     MediaLibraryTracer tracer;
4522     tracer.Start("PhotoAccessHelperIsEditedExecute");
4523     auto *context = static_cast<FileAssetAsyncContext *>(data);
4524     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4525     int32_t fileId = context->objectPtr->GetId();
4526     string queryUriStr = PAH_QUERY_PHOTO;
4527     MediaLibraryNapiUtils::UriAppendKeyValue(queryUriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4528     Uri uri(queryUriStr);
4529     DataShare::DataSharePredicates predicates;
4530     predicates.EqualTo(MediaColumn::MEDIA_ID, to_string(fileId));
4531     DataShare::DataShareValuesBucket values;
4532     vector<string> columns = { PhotoColumn::PHOTO_EDIT_TIME };
4533     int32_t errCode = 0;
4534     int64_t editTime = 0;
4535     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
4536     if (!GetEditTimeFromResultSet(resultSet, editTime)) {
4537         if (errCode == E_PERMISSION_DENIED) {
4538             context->error = OHOS_PERMISSION_DENIED_CODE;
4539         } else {
4540             context->SaveError(E_FAIL);
4541         }
4542     } else {
4543         if (editTime == 0) {
4544             context->hasEdit = false;
4545         } else {
4546             context->hasEdit = true;
4547         }
4548     }
4549 }
4550 
PhotoAccessHelperIsEditedComplete(napi_env env,napi_status status,void * data)4551 static void PhotoAccessHelperIsEditedComplete(napi_env env, napi_status status, void *data)
4552 {
4553     auto *context = static_cast<FileAssetAsyncContext *>(data);
4554     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4555 
4556     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4557     jsContext->status = false;
4558     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4559     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4560 
4561     if (context->error == ERR_DEFAULT) {
4562         CHECK_ARGS_RET_VOID(env, napi_get_boolean(env, context->hasEdit, &jsContext->data), JS_INNER_FAIL);
4563         jsContext->status = true;
4564     } else {
4565         context->HandleError(env, jsContext->error);
4566     }
4567 
4568     if (context->work != nullptr) {
4569         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4570                                                    context->work, *jsContext);
4571     }
4572     delete context;
4573 }
4574 
PhotoAccessHelperIsEdited(napi_env env,napi_callback_info info)4575 napi_value FileAssetNapi::PhotoAccessHelperIsEdited(napi_env env, napi_callback_info info)
4576 {
4577     MediaLibraryTracer tracer;
4578     tracer.Start("PhotoAccessHelperIsEdited");
4579 
4580     // edit function in API11 is system api, maybe public soon
4581     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4582         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4583         return nullptr;
4584     }
4585 
4586     auto asyncContext = make_unique<FileAssetAsyncContext>();
4587     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4588     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4589         "Failed to parse js args");
4590     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4591     napi_value ret = nullptr;
4592     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
4593     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperIsEdited",
4594         PhotoAccessHelperIsEditedExecute, PhotoAccessHelperIsEditedComplete);
4595 }
4596 
ProcessEditData(FileAssetAsyncContext * context,const UniqueFd & uniqueFd)4597 static void ProcessEditData(FileAssetAsyncContext *context, const UniqueFd &uniqueFd)
4598 {
4599     if (context == nullptr) {
4600         NAPI_ERR_LOG("context nullptr");
4601         return;
4602     }
4603     struct stat fileInfo;
4604     if (fstat(uniqueFd.Get(), &fileInfo) == 0) {
4605         off_t fileSize = fileInfo.st_size;
4606         if (fileSize < 0 || fileSize + 1 < 0) {
4607             NAPI_ERR_LOG("fileBuffer error : %{public}ld", static_cast<long>(fileSize));
4608             context->SaveError(E_FAIL);
4609             return;
4610         }
4611         context->editDataBuffer = static_cast<char *>(malloc(fileSize + 1));
4612         if (!context->editDataBuffer) {
4613             NAPI_ERR_LOG("Photo request edit data failed, fd: %{public}d", uniqueFd.Get());
4614             context->SaveError(E_FAIL);
4615             return;
4616         }
4617         ssize_t bytes = read(uniqueFd.Get(), context->editDataBuffer, fileSize);
4618         if (bytes < 0) {
4619             NAPI_ERR_LOG("Read edit data failed, errno: %{public}d", errno);
4620             free(context->editDataBuffer);
4621             context->editDataBuffer = nullptr;
4622             context->SaveError(E_FAIL);
4623             return;
4624         }
4625         context->editDataBuffer[bytes] = '\0';
4626     } else {
4627         NAPI_ERR_LOG("can not get stat errno:%{public}d", errno);
4628         context->SaveError(E_FAIL);
4629     }
4630 }
4631 
PhotoAccessHelperRequestEditDataExecute(napi_env env,void * data)4632 static void PhotoAccessHelperRequestEditDataExecute(napi_env env, void *data)
4633 {
4634     MediaLibraryTracer tracer;
4635     tracer.Start("PhotoAccessHelperRequestEditDataExecute");
4636     auto *context = static_cast<FileAssetAsyncContext *>(data);
4637     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4638     bool isValid = false;
4639     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
4640     if (!isValid) {
4641         context->error = OHOS_INVALID_PARAM_CODE;
4642         return;
4643     }
4644     MediaFileUtils::UriAppendKeyValue(fileUri, MEDIA_OPERN_KEYWORD, EDIT_DATA_REQUEST);
4645     Uri uri(fileUri);
4646     UniqueFd uniqueFd(UserFileClient::OpenFile(uri, "r"));
4647     if (uniqueFd.Get() <= 0) {
4648         if (uniqueFd.Get() == E_PERMISSION_DENIED) {
4649             context->error = OHOS_PERMISSION_DENIED_CODE;
4650         } else {
4651             context->SaveError(uniqueFd.Get());
4652         }
4653         NAPI_ERR_LOG("Photo request edit data failed, ret: %{public}d", uniqueFd.Get());
4654     } else {
4655         ProcessEditData(context, uniqueFd);
4656     }
4657 }
4658 
GetEditDataString(char * editDataBuffer,string & result)4659 static void GetEditDataString(char* editDataBuffer, string& result)
4660 {
4661     if (editDataBuffer == nullptr) {
4662         result = "";
4663         NAPI_WARN_LOG("editDataBuffer is nullptr");
4664         return;
4665     }
4666 
4667     string editDataStr(editDataBuffer);
4668     if (!nlohmann::json::accept(editDataStr)) {
4669         result = editDataStr;
4670         return;
4671     }
4672 
4673     nlohmann::json editDataJson = nlohmann::json::parse(editDataStr);
4674     if (editDataJson.contains(COMPATIBLE_FORMAT) && editDataJson.contains(FORMAT_VERSION) &&
4675         editDataJson.contains(EDIT_DATA) && editDataJson.contains(APP_ID)) {
4676         // edit data saved by media change request
4677         result = editDataJson.at(EDIT_DATA);
4678     } else {
4679         // edit data saved by commitEditedAsset
4680         result = editDataStr;
4681     }
4682 }
4683 
GetEditDataObject(napi_env env,char * editDataBuffer)4684 static napi_value GetEditDataObject(napi_env env, char* editDataBuffer)
4685 {
4686     if (editDataBuffer == nullptr) {
4687         NAPI_WARN_LOG("editDataBuffer is nullptr");
4688         return MediaAssetEditDataNapi::CreateMediaAssetEditData(env, "", "", "");
4689     }
4690 
4691     string editDataStr(editDataBuffer);
4692     if (!nlohmann::json::accept(editDataStr)) {
4693         return MediaAssetEditDataNapi::CreateMediaAssetEditData(env, "", "", editDataStr);
4694     }
4695 
4696     nlohmann::json editDataJson = nlohmann::json::parse(editDataStr);
4697     if (editDataJson.contains(COMPATIBLE_FORMAT) && editDataJson.contains(FORMAT_VERSION) &&
4698         editDataJson.contains(EDIT_DATA) && editDataJson.contains(APP_ID)) {
4699         // edit data saved by media change request
4700         return MediaAssetEditDataNapi::CreateMediaAssetEditData(env,
4701             editDataJson.at(COMPATIBLE_FORMAT), editDataJson.at(FORMAT_VERSION), editDataJson.at(EDIT_DATA));
4702     }
4703 
4704     // edit data saved by commitEditedAsset
4705     return MediaAssetEditDataNapi::CreateMediaAssetEditData(env, "", "", editDataStr);
4706 }
4707 
PhotoAccessHelperRequestEditDataComplete(napi_env env,napi_status status,void * data)4708 static void PhotoAccessHelperRequestEditDataComplete(napi_env env, napi_status status, void *data)
4709 {
4710     auto *context = static_cast<FileAssetAsyncContext *>(data);
4711     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4712 
4713     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4714     jsContext->status = false;
4715     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4716     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4717 
4718     if (context->error == ERR_DEFAULT) {
4719         string editDataStr;
4720         GetEditDataString(context->editDataBuffer, editDataStr);
4721         CHECK_ARGS_RET_VOID(env, napi_create_string_utf8(env, editDataStr.c_str(),
4722             NAPI_AUTO_LENGTH, &jsContext->data), JS_INNER_FAIL);
4723         jsContext->status = true;
4724     } else {
4725         context->HandleError(env, jsContext->error);
4726     }
4727 
4728     if (context->work != nullptr) {
4729         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4730                                                    context->work, *jsContext);
4731     }
4732     if (context->editDataBuffer != nullptr) {
4733         free(context->editDataBuffer);
4734     }
4735     delete context;
4736 }
4737 
PhotoAccessHelperGetEditDataComplete(napi_env env,napi_status status,void * data)4738 static void PhotoAccessHelperGetEditDataComplete(napi_env env, napi_status status, void* data)
4739 {
4740     auto* context = static_cast<FileAssetAsyncContext*>(data);
4741     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4742 
4743     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4744     jsContext->status = false;
4745     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4746     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4747     if (context->error == ERR_DEFAULT) {
4748         jsContext->data = GetEditDataObject(env, context->editDataBuffer);
4749         jsContext->status = true;
4750     } else {
4751         context->HandleError(env, jsContext->error);
4752     }
4753 
4754     if (context->work != nullptr) {
4755         MediaLibraryNapiUtils::InvokeJSAsyncMethod(
4756             env, context->deferred, context->callbackRef, context->work, *jsContext);
4757     }
4758     if (context->editDataBuffer != nullptr) {
4759         free(context->editDataBuffer);
4760     }
4761     delete context;
4762 }
4763 
PhotoAccessHelperRequestEditData(napi_env env,napi_callback_info info)4764 napi_value FileAssetNapi::PhotoAccessHelperRequestEditData(napi_env env, napi_callback_info info)
4765 {
4766     MediaLibraryTracer tracer;
4767     tracer.Start("PhotoAccessHelperRequestEditData");
4768 
4769     // edit function in API11 is system api, maybe public soon
4770     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4771         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4772         return nullptr;
4773     }
4774 
4775     auto asyncContext = make_unique<FileAssetAsyncContext>();
4776     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4777     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4778         "Failed to parse js args");
4779     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4780     napi_value ret = nullptr;
4781     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
4782     auto fileUri = asyncContext->objectInfo->GetFileUri();
4783     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4784     asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
4785     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperRequestEditData",
4786         PhotoAccessHelperRequestEditDataExecute, PhotoAccessHelperRequestEditDataComplete);
4787 }
4788 
PhotoAccessHelperGetEditData(napi_env env,napi_callback_info info)4789 napi_value FileAssetNapi::PhotoAccessHelperGetEditData(napi_env env, napi_callback_info info)
4790 {
4791     MediaLibraryTracer tracer;
4792     tracer.Start("PhotoAccessHelperGetEditData");
4793 
4794     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4795         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4796         return nullptr;
4797     }
4798 
4799     auto asyncContext = make_unique<FileAssetAsyncContext>();
4800     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4801     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4802         "Failed to parse js args");
4803     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4804     napi_value ret = nullptr;
4805     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is null");
4806     auto fileUri = asyncContext->objectInfo->GetFileUri();
4807     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4808     asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
4809     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetEditData",
4810         PhotoAccessHelperRequestEditDataExecute, PhotoAccessHelperGetEditDataComplete);
4811 }
4812 
PhotoAccessHelperRequestSourceExecute(napi_env env,void * data)4813 static void PhotoAccessHelperRequestSourceExecute(napi_env env, void *data)
4814 {
4815     MediaLibraryTracer tracer;
4816     tracer.Start("PhotoAccessHelperRequestSourceExecute");
4817     auto *context = static_cast<FileAssetAsyncContext *>(data);
4818     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4819     bool isValid = false;
4820     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
4821     if (!isValid) {
4822         context->error = OHOS_INVALID_PARAM_CODE;
4823         return;
4824     }
4825     MediaFileUtils::UriAppendKeyValue(fileUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
4826     Uri uri(fileUri);
4827     int32_t retVal = UserFileClient::OpenFile(uri, "r");
4828     if (retVal <= 0) {
4829         if (retVal == E_PERMISSION_DENIED) {
4830             context->error = OHOS_PERMISSION_DENIED_CODE;
4831         } else {
4832             context->SaveError(retVal);
4833         }
4834         NAPI_ERR_LOG("Photo request edit data failed, ret: %{public}d", retVal);
4835     } else {
4836         context->fd = retVal;
4837         context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
4838     }
4839 }
4840 
PhotoAccessHelperRequestSourceComplete(napi_env env,napi_status status,void * data)4841 static void PhotoAccessHelperRequestSourceComplete(napi_env env, napi_status status, void *data)
4842 {
4843     auto *context = static_cast<FileAssetAsyncContext *>(data);
4844     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4845 
4846     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4847     jsContext->status = false;
4848 
4849     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4850     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4851     if (context->error == ERR_DEFAULT) {
4852         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->fd, &jsContext->data), JS_INNER_FAIL);
4853         jsContext->status = true;
4854     } else {
4855         context->HandleError(env, jsContext->error);
4856     }
4857 
4858     if (context->work != nullptr) {
4859         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4860                                                    context->work, *jsContext);
4861     }
4862     delete context;
4863 }
4864 
PhotoAccessHelperRequestSource(napi_env env,napi_callback_info info)4865 napi_value FileAssetNapi::PhotoAccessHelperRequestSource(napi_env env, napi_callback_info info)
4866 {
4867     MediaLibraryTracer tracer;
4868     tracer.Start("PhotoAccessHelperRequestSource");
4869 
4870     // edit function in API11 is system api, maybe public soon
4871     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4872         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4873         return nullptr;
4874     }
4875 
4876     auto asyncContext = make_unique<FileAssetAsyncContext>();
4877     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4878     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
4879         "Failed to parse js args");
4880     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
4881     napi_value ret = nullptr;
4882     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
4883     auto fileUri = asyncContext->objectInfo->GetFileUri();
4884     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4885     asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
4886     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperRequestSource",
4887         PhotoAccessHelperRequestSourceExecute, PhotoAccessHelperRequestSourceComplete);
4888 }
4889 
GetFileUriFd(FileAssetAsyncContext * context)4890 static int32_t GetFileUriFd(FileAssetAsyncContext *context)
4891 {
4892     string uriRealPath = AppFileService::ModuleFileUri::FileUri(context->uri).GetRealPath();
4893     if (uriRealPath.empty()) {
4894         NAPI_ERR_LOG("Can not get file in path by uri %{private}s", context->uri.c_str());
4895         context->SaveError(E_FAIL);
4896         return E_FAIL;
4897     }
4898     int32_t fd = open(uriRealPath.c_str(), O_RDONLY);
4899     if (fd < 0) {
4900         NAPI_ERR_LOG("Can not open fileUri, ret: %{public}d, errno:%{public}d", fd, errno);
4901         context->SaveError(E_FAIL);
4902         return E_FAIL;
4903     }
4904     return fd;
4905 }
4906 
PhotoAccessHelperCommitEditExecute(napi_env env,void * data)4907 static void PhotoAccessHelperCommitEditExecute(napi_env env, void *data)
4908 {
4909     MediaLibraryTracer tracer;
4910     tracer.Start("PhotoAccessHelperCommitEditExecute");
4911     auto *context = static_cast<FileAssetAsyncContext *>(data);
4912     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4913     UniqueFd uriFd(GetFileUriFd(context));
4914     CHECK_IF_EQUAL(uriFd.Get() > 0, "Can not open fileUri");
4915 
4916     bool isValid = false;
4917     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
4918     if (!isValid) {
4919         context->error = OHOS_INVALID_PARAM_CODE;
4920         return;
4921     }
4922     MediaFileUtils::UriAppendKeyValue(fileUri, MEDIA_OPERN_KEYWORD, COMMIT_REQUEST);
4923     Uri uri(fileUri);
4924     UniqueFd fd(UserFileClient::OpenFile(uri, "rw"));
4925     if (fd.Get() <= 0) {
4926         if (fd.Get() == E_PERMISSION_DENIED) {
4927             context->error = OHOS_PERMISSION_DENIED_CODE;
4928         } else {
4929             context->SaveError(fd.Get());
4930         }
4931         NAPI_ERR_LOG("File request edit data failed, ret: %{public}d", fd.Get());
4932     } else {
4933         if (ftruncate(fd.Get(), 0) == -1) {
4934             NAPI_ERR_LOG("Can not erase content from old file, errno:%{public}d", errno);
4935             context->SaveError(E_FAIL);
4936             return;
4937         }
4938         if (!MediaFileUtils::CopyFile(uriFd.Get(), fd.Get())) {
4939             NAPI_ERR_LOG("Failed to copy file: rfd:%{public}d, wfd:%{public}d, errno:%{public}d",
4940                 uriFd.Get(), fd.Get(), errno);
4941             context->SaveError(E_FAIL);
4942             return;
4943         }
4944         NAPI_INFO_LOG("commit edit asset copy file finished, fileUri:%{public}s", fileUri.c_str());
4945         string insertUriStr = PAH_COMMIT_EDIT_PHOTOS;
4946         MediaLibraryNapiUtils::UriAppendKeyValue(insertUriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
4947         Uri insertUri(insertUriStr);
4948         int32_t ret = UserFileClient::Insert(insertUri, context->valuesBucket);
4949         if (ret != E_SUCCESS) {
4950             if (ret == E_PERMISSION_DENIED) {
4951                 context->error = OHOS_PERMISSION_DENIED_CODE;
4952             } else {
4953                 context->SaveError(ret);
4954             }
4955             NAPI_ERR_LOG("File commit edit execute failed");
4956         }
4957     }
4958 }
4959 
PhotoAccessHelperCommitEditComplete(napi_env env,napi_status status,void * data)4960 static void PhotoAccessHelperCommitEditComplete(napi_env env, napi_status status, void *data)
4961 {
4962     auto *context = static_cast<FileAssetAsyncContext *>(data);
4963     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
4964 
4965     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
4966     jsContext->status = false;
4967 
4968     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
4969     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
4970     if (context->error == ERR_DEFAULT) {
4971         jsContext->status = true;
4972     } else {
4973         context->HandleError(env, jsContext->error);
4974     }
4975 
4976     if (context->work != nullptr) {
4977         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
4978                                                    context->work, *jsContext);
4979     }
4980     delete context;
4981 }
4982 
PhotoAccessHelperCommitEditedAsset(napi_env env,napi_callback_info info)4983 napi_value FileAssetNapi::PhotoAccessHelperCommitEditedAsset(napi_env env, napi_callback_info info)
4984 {
4985     MediaLibraryTracer tracer;
4986     tracer.Start("PhotoAccessHelperCommitEditedAsset");
4987 
4988     // edit function in API11 is system api, maybe public soon
4989     if (!MediaLibraryNapiUtils::IsSystemApp()) {
4990         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
4991         return nullptr;
4992     }
4993 
4994     auto asyncContext = make_unique<FileAssetAsyncContext>();
4995     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
4996     CHECK_ARGS_THROW_INVALID_PARAM(env,
4997         MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_TWO, ARGS_THREE));
4998     string editData;
4999     const static int32_t EDIT_DATA_MAX_LENGTH = 5 * 1024 * 1024;
5000     CHECK_ARGS_THROW_INVALID_PARAM(env,
5001         MediaLibraryNapiUtils::GetParamStringWithLength(env, asyncContext->argv[0], EDIT_DATA_MAX_LENGTH, editData));
5002     CHECK_ARGS_THROW_INVALID_PARAM(env,
5003         MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[1], asyncContext->uri));
5004     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
5005     napi_value ret = nullptr;
5006     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
5007     auto fileUri = asyncContext->objectInfo->GetFileUri();
5008     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5009     asyncContext->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
5010     asyncContext->valuesBucket.Put(EDIT_DATA, editData);
5011     asyncContext->valuesBucket.Put(MediaColumn::MEDIA_ID, asyncContext->objectPtr->GetId());
5012     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCommitEditedAsset",
5013         PhotoAccessHelperCommitEditExecute, PhotoAccessHelperCommitEditComplete);
5014 }
5015 
PhotoAccessHelperRevertToOriginalExecute(napi_env env,void * data)5016 static void PhotoAccessHelperRevertToOriginalExecute(napi_env env, void *data)
5017 {
5018     MediaLibraryTracer tracer;
5019     tracer.Start("PhotoAccessHelperRevertToOriginalExecute");
5020     auto *context = static_cast<FileAssetAsyncContext *>(data);
5021     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5022     string uriString = PAH_REVERT_EDIT_PHOTOS;
5023     MediaFileUtils::UriAppendKeyValue(uriString, API_VERSION, to_string(MEDIA_API_VERSION_V10));
5024     Uri uri(uriString);
5025     int32_t ret = UserFileClient::Insert(uri, context->valuesBucket);
5026     if (ret < 0) {
5027         if (ret == E_PERMISSION_DENIED) {
5028             context->error = OHOS_PERMISSION_DENIED_CODE;
5029         } else {
5030             context->SaveError(ret);
5031         }
5032         NAPI_ERR_LOG("Photo revert edit data failed, ret: %{public}d", ret);
5033     }
5034 }
5035 
PhotoAccessHelperRevertToOriginalComplete(napi_env env,napi_status status,void * data)5036 static void PhotoAccessHelperRevertToOriginalComplete(napi_env env, napi_status status, void *data)
5037 {
5038     auto *context = static_cast<FileAssetAsyncContext *>(data);
5039     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
5040 
5041     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
5042     jsContext->status = false;
5043     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
5044     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
5045 
5046     if (context->error == ERR_DEFAULT) {
5047         jsContext->status = true;
5048     } else {
5049         context->HandleError(env, jsContext->error);
5050     }
5051 
5052     if (context->work != nullptr) {
5053         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
5054                                                    context->work, *jsContext);
5055     }
5056     delete context;
5057 }
5058 
PhotoAccessHelperRevertToOriginal(napi_env env,napi_callback_info info)5059 napi_value FileAssetNapi::PhotoAccessHelperRevertToOriginal(napi_env env, napi_callback_info info)
5060 {
5061     MediaLibraryTracer tracer;
5062     tracer.Start("PhotoAccessHelperRevertToOriginal");
5063 
5064     // edit function in API11 is system api, maybe public soon
5065     if (!MediaLibraryNapiUtils::IsSystemApp()) {
5066         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
5067         return nullptr;
5068     }
5069 
5070     auto asyncContext = make_unique<FileAssetAsyncContext>();
5071     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
5072     CHECK_COND_WITH_MESSAGE(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
5073         "Failed to parse js args");
5074     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
5075     napi_value ret = nullptr;
5076     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "PhotoAsset is nullptr");
5077     asyncContext->valuesBucket.Put(MediaColumn::MEDIA_ID, asyncContext->objectPtr->GetId());
5078     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperRevertToOriginal",
5079         PhotoAccessHelperRevertToOriginalExecute, PhotoAccessHelperRevertToOriginalComplete);
5080 }
5081 } // namespace Media
5082 } // namespace OHOS
5083