• 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 #define MLOG_TAG "FileAssetNapi"
16 
17 #include "file_asset_napi.h"
18 
19 #include <algorithm>
20 #include <cstring>
21 #include <fcntl.h>
22 #include <sys/stat.h>
23 
24 #include "abs_shared_result_set.h"
25 #include "hitrace_meter.h"
26 #include "fetch_result.h"
27 #include "hilog/log.h"
28 #include "media_exif.h"
29 #include "medialibrary_asset_operations.h"
30 #include "media_column.h"
31 #include "media_file_utils.h"
32 #include "media_file_uri.h"
33 #include "medialibrary_client_errno.h"
34 #include "medialibrary_data_manager_utils.h"
35 #include "medialibrary_errno.h"
36 #include "medialibrary_napi_log.h"
37 #include "medialibrary_napi_utils.h"
38 #include "medialibrary_tracer.h"
39 #include "nlohmann/json.hpp"
40 #include "permission_utils.h"
41 #include "rdb_errno.h"
42 #include "string_ex.h"
43 #include "thumbnail_const.h"
44 #include "thumbnail_utils.h"
45 #include "unique_fd.h"
46 #include "userfile_client.h"
47 #include "userfilemgr_uri.h"
48 
49 #ifdef IMAGE_PURGEABLE_PIXELMAP
50 #include "purgeable_pixelmap_builder.h"
51 #endif
52 
53 using OHOS::HiviewDFX::HiLog;
54 using OHOS::HiviewDFX::HiLogLabel;
55 using namespace std;
56 using namespace OHOS::AppExecFwk;
57 using namespace OHOS::NativeRdb;
58 using namespace OHOS::DataShare;
59 using std::string;
60 
61 namespace OHOS {
62 namespace Media {
63 static const std::string MEDIA_FILEDESCRIPTOR = "fd";
64 static const std::string MEDIA_FILEMODE = "mode";
65 
66 thread_local napi_ref FileAssetNapi::sConstructor_ = nullptr;
67 thread_local FileAsset *FileAssetNapi::sFileAsset_ = nullptr;
68 
69 constexpr int32_t IS_TRASH = 1;
70 constexpr int32_t NOT_TRASH = 0;
71 
72 constexpr int32_t IS_FAV = 1;
73 constexpr int32_t NOT_FAV = 0;
74 
75 constexpr int32_t IS_HIDDEN = 1;
76 constexpr int32_t NOT_HIDDEN = 0;
77 
78 constexpr int32_t USER_COMMENT_MAX_LEN = 140;
79 
80 using CompleteCallback = napi_async_complete_callback;
81 
82 thread_local napi_ref FileAssetNapi::userFileMgrConstructor_ = nullptr;
83 thread_local napi_ref FileAssetNapi::photoAccessHelperConstructor_ = nullptr;
84 
FileAssetNapi()85 FileAssetNapi::FileAssetNapi()
86     : env_(nullptr) {}
87 
88 FileAssetNapi::~FileAssetNapi() = default;
89 
FileAssetNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)90 void FileAssetNapi::FileAssetNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
91 {
92     FileAssetNapi *fileAssetObj = reinterpret_cast<FileAssetNapi*>(nativeObject);
93     if (fileAssetObj != nullptr) {
94         delete fileAssetObj;
95         fileAssetObj = nullptr;
96     }
97 }
98 
Init(napi_env env,napi_value exports)99 napi_value FileAssetNapi::Init(napi_env env, napi_value exports)
100 {
101     napi_status status;
102     napi_value ctorObj;
103     int32_t refCount = 1;
104     napi_property_descriptor file_asset_props[] = {
105         DECLARE_NAPI_GETTER("id", JSGetFileId),
106         DECLARE_NAPI_GETTER("uri", JSGetFileUri),
107         DECLARE_NAPI_GETTER("mediaType", JSGetMediaType),
108         DECLARE_NAPI_GETTER_SETTER("displayName", JSGetFileDisplayName, JSSetFileDisplayName),
109         DECLARE_NAPI_GETTER_SETTER("relativePath", JSGetRelativePath, JSSetRelativePath),
110         DECLARE_NAPI_GETTER("parent", JSParent),
111         DECLARE_NAPI_GETTER("size", JSGetSize),
112         DECLARE_NAPI_GETTER("dateAdded", JSGetDateAdded),
113         DECLARE_NAPI_GETTER("dateTrashed", JSGetDateTrashed),
114         DECLARE_NAPI_GETTER("dateModified", JSGetDateModified),
115         DECLARE_NAPI_GETTER("dateTaken", JSGetDateTaken),
116         DECLARE_NAPI_GETTER("mimeType", JSGetMimeType),
117         DECLARE_NAPI_GETTER_SETTER("title", JSGetTitle, JSSetTitle),
118         DECLARE_NAPI_GETTER("artist", JSGetArtist),
119         DECLARE_NAPI_GETTER("audioAlbum", JSGetAlbum),
120         DECLARE_NAPI_GETTER("width", JSGetWidth),
121         DECLARE_NAPI_GETTER("height", JSGetHeight),
122         DECLARE_NAPI_GETTER_SETTER("orientation", JSGetOrientation, JSSetOrientation),
123         DECLARE_NAPI_GETTER("duration", JSGetDuration),
124         DECLARE_NAPI_GETTER("albumId", JSGetAlbumId),
125         DECLARE_NAPI_GETTER("albumUri", JSGetAlbumUri),
126         DECLARE_NAPI_GETTER("albumName", JSGetAlbumName),
127         DECLARE_NAPI_GETTER("count", JSGetCount),
128         DECLARE_NAPI_FUNCTION("isDirectory", JSIsDirectory),
129         DECLARE_NAPI_FUNCTION("commitModify", JSCommitModify),
130         DECLARE_NAPI_FUNCTION("open", JSOpen),
131         DECLARE_NAPI_FUNCTION("close", JSClose),
132         DECLARE_NAPI_FUNCTION("getThumbnail", JSGetThumbnail),
133         DECLARE_NAPI_FUNCTION("favorite", JSFavorite),
134         DECLARE_NAPI_FUNCTION("isFavorite", JSIsFavorite),
135         DECLARE_NAPI_FUNCTION("trash", JSTrash),
136         DECLARE_NAPI_FUNCTION("isTrash", JSIsTrash),
137     };
138 
139     status = napi_define_class(env, FILE_ASSET_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
140                                FileAssetNapiConstructor, nullptr,
141                                sizeof(file_asset_props) / sizeof(file_asset_props[PARAM0]),
142                                file_asset_props, &ctorObj);
143     if (status == napi_ok) {
144         status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
145         if (status == napi_ok) {
146             status = napi_set_named_property(env, exports, FILE_ASSET_NAPI_CLASS_NAME.c_str(), ctorObj);
147             if (status == napi_ok) {
148                 return exports;
149             }
150         }
151     }
152     return nullptr;
153 }
154 
UserFileMgrInit(napi_env env,napi_value exports)155 napi_value FileAssetNapi::UserFileMgrInit(napi_env env, napi_value exports)
156 {
157     NapiClassInfo info = {
158         .name = USERFILEMGR_FILEASSET_NAPI_CLASS_NAME,
159         .ref = &userFileMgrConstructor_,
160         .constructor = FileAssetNapiConstructor,
161         .props = {
162             DECLARE_NAPI_FUNCTION("get", UserFileMgrGet),
163             DECLARE_NAPI_FUNCTION("set", UserFileMgrSet),
164             DECLARE_NAPI_FUNCTION("open", UserFileMgrOpen),
165             DECLARE_NAPI_FUNCTION("close", UserFileMgrClose),
166             DECLARE_NAPI_FUNCTION("commitModify", UserFileMgrCommitModify),
167             DECLARE_NAPI_FUNCTION("favorite", UserFileMgrFavorite),
168             DECLARE_NAPI_GETTER("uri", JSGetFileUri),
169             DECLARE_NAPI_GETTER("fileType", JSGetMediaType),
170             DECLARE_NAPI_GETTER_SETTER("displayName", JSGetFileDisplayName, JSSetFileDisplayName),
171             DECLARE_NAPI_FUNCTION("getThumbnail", UserFileMgrGetThumbnail),
172             DECLARE_NAPI_FUNCTION("getReadOnlyFd", JSGetReadOnlyFd),
173             DECLARE_NAPI_FUNCTION("setHidden", UserFileMgrSetHidden),
174             DECLARE_NAPI_FUNCTION("setPending", UserFileMgrSetPending),
175             DECLARE_NAPI_FUNCTION("getExif", JSGetExif),
176             DECLARE_NAPI_FUNCTION("setUserComment", UserFileMgrSetUserComment),
177         }
178     };
179     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
180 
181     return exports;
182 }
183 
PhotoAccessHelperInit(napi_env env,napi_value exports)184 napi_value FileAssetNapi::PhotoAccessHelperInit(napi_env env, napi_value exports)
185 {
186     NapiClassInfo info = {
187         .name = PHOTOACCESSHELPER_FILEASSET_NAPI_CLASS_NAME,
188         .ref = &photoAccessHelperConstructor_,
189         .constructor = FileAssetNapiConstructor,
190         .props = {
191             DECLARE_NAPI_FUNCTION("get", UserFileMgrGet),
192             DECLARE_NAPI_FUNCTION("set", UserFileMgrSet),
193             DECLARE_NAPI_FUNCTION("open", PhotoAccessHelperOpen),
194             DECLARE_NAPI_FUNCTION("close", PhotoAccessHelperClose),
195             DECLARE_NAPI_FUNCTION("commitModify", PhotoAccessHelperCommitModify),
196             DECLARE_NAPI_FUNCTION("setFavorite", PhotoAccessHelperFavorite),
197             DECLARE_NAPI_GETTER("uri", JSGetFileUri),
198             DECLARE_NAPI_GETTER("photoType", JSGetMediaType),
199             DECLARE_NAPI_GETTER_SETTER("displayName", JSGetFileDisplayName, JSSetFileDisplayName),
200             DECLARE_NAPI_FUNCTION("getThumbnail", PhotoAccessHelperGetThumbnail),
201             DECLARE_NAPI_FUNCTION("getReadOnlyFd", JSGetReadOnlyFd),
202             DECLARE_NAPI_FUNCTION("setHidden", PhotoAccessHelperSetHidden),
203             DECLARE_NAPI_FUNCTION("setPending", PhotoAccessHelperSetPending),
204             DECLARE_NAPI_FUNCTION("getExif", JSGetExif),
205             DECLARE_NAPI_FUNCTION("setUserComment", PhotoAccessHelperSetUserComment),
206         }
207     };
208     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
209     return exports;
210 }
211 
212 // Constructor callback
FileAssetNapiConstructor(napi_env env,napi_callback_info info)213 napi_value FileAssetNapi::FileAssetNapiConstructor(napi_env env, napi_callback_info info)
214 {
215     napi_status status;
216     napi_value result = nullptr;
217     napi_value thisVar = nullptr;
218 
219     napi_get_undefined(env, &result);
220     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
221     if (status == napi_ok && thisVar != nullptr) {
222         std::unique_ptr<FileAssetNapi> obj = std::make_unique<FileAssetNapi>();
223         if (obj != nullptr) {
224             obj->env_ = env;
225             if (sFileAsset_ != nullptr) {
226                 obj->UpdateFileAssetInfo();
227             }
228 
229             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
230                                FileAssetNapi::FileAssetNapiDestructor, nullptr, nullptr);
231             if (status == napi_ok) {
232                 obj.release();
233                 return thisVar;
234             } else {
235                 NAPI_ERR_LOG("Failure wrapping js to native napi, status: %{public}d", status);
236             }
237         }
238     }
239 
240     return result;
241 }
242 
CreateFileAsset(napi_env env,unique_ptr<FileAsset> & iAsset)243 napi_value FileAssetNapi::CreateFileAsset(napi_env env, unique_ptr<FileAsset> &iAsset)
244 {
245     if (iAsset == nullptr) {
246         return nullptr;
247     }
248 
249     napi_value constructor = nullptr;
250     napi_ref constructorRef;
251     if (iAsset->GetResultNapiType() == ResultNapiType::TYPE_USERFILE_MGR) {
252         constructorRef = userFileMgrConstructor_;
253     } else if (iAsset->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
254         constructorRef = photoAccessHelperConstructor_;
255     } else {
256         constructorRef = sConstructor_;
257     }
258 
259     NAPI_CALL(env, napi_get_reference_value(env, constructorRef, &constructor));
260 
261     sFileAsset_ = iAsset.release();
262 
263     napi_value result = nullptr;
264     NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result));
265 
266     sFileAsset_ = nullptr;
267     return result;
268 }
269 
GetFileDisplayName() const270 std::string FileAssetNapi::GetFileDisplayName() const
271 {
272     return fileAssetPtr->GetDisplayName();
273 }
274 
GetRelativePath() const275 std::string FileAssetNapi::GetRelativePath() const
276 {
277     return fileAssetPtr->GetRelativePath();
278 }
279 
GetFilePath() const280 std::string FileAssetNapi::GetFilePath() const
281 {
282     return fileAssetPtr->GetPath();
283 }
284 
GetTitle() const285 std::string FileAssetNapi::GetTitle() const
286 {
287     return fileAssetPtr->GetTitle();
288 }
289 
GetFileUri() const290 std::string FileAssetNapi::GetFileUri() const
291 {
292     return fileAssetPtr->GetUri();
293 }
294 
GetFileId() const295 int32_t FileAssetNapi::GetFileId() const
296 {
297     return fileAssetPtr->GetId();
298 }
299 
GetMediaType() const300 Media::MediaType FileAssetNapi::GetMediaType() const
301 {
302     return fileAssetPtr->GetMediaType();
303 }
304 
GetOrientation() const305 int32_t FileAssetNapi::GetOrientation() const
306 {
307     return fileAssetPtr->GetOrientation();
308 }
309 
GetNetworkId() const310 std::string FileAssetNapi::GetNetworkId() const
311 {
312     return MediaFileUtils::GetNetworkIdFromUri(GetFileUri());
313 }
314 
IsFavorite() const315 bool FileAssetNapi::IsFavorite() const
316 {
317     return fileAssetPtr->IsFavorite();
318 }
319 
SetFavorite(bool isFavorite)320 void FileAssetNapi::SetFavorite(bool isFavorite)
321 {
322     fileAssetPtr->SetFavorite(isFavorite);
323 }
324 
IsTrash() const325 bool FileAssetNapi::IsTrash() const
326 {
327     return (fileAssetPtr->GetIsTrash() != NOT_TRASH);
328 }
329 
SetTrash(bool isTrash)330 void FileAssetNapi::SetTrash(bool isTrash)
331 {
332     int32_t trashFlag = (isTrash ? IS_TRASH : NOT_TRASH);
333     fileAssetPtr->SetIsTrash(trashFlag);
334 }
335 
IsHidden() const336 bool FileAssetNapi::IsHidden() const
337 {
338     return fileAssetPtr->IsHidden();
339 }
340 
SetHidden(bool isHidden)341 void FileAssetNapi::SetHidden(bool isHidden)
342 {
343     fileAssetPtr->SetHidden(isHidden);
344 }
345 
GetAllExif() const346 std::string FileAssetNapi::GetAllExif() const
347 {
348     return fileAssetPtr->GetAllExif();
349 }
350 
GetUserComment() const351 std::string FileAssetNapi::GetUserComment() const
352 {
353     return fileAssetPtr->GetUserComment();
354 }
355 
GetNapiObject(napi_env env,napi_callback_info info,FileAssetNapi ** obj)356 napi_status GetNapiObject(napi_env env, napi_callback_info info, FileAssetNapi **obj)
357 {
358     napi_value thisVar = nullptr;
359     CHECK_STATUS_RET(napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), "Failed to get cb info");
360     CHECK_STATUS_RET(napi_unwrap(env, thisVar, reinterpret_cast<void **>(obj)), "Failed to unwrap thisVar");
361     CHECK_COND_RET(*obj != nullptr, napi_invalid_arg, "Failed to get napi object!");
362     return napi_ok;
363 }
364 
JSGetFileId(napi_env env,napi_callback_info info)365 napi_value FileAssetNapi::JSGetFileId(napi_env env, napi_callback_info info)
366 {
367     napi_status status;
368     napi_value jsResult = nullptr;
369     FileAssetNapi *obj = nullptr;
370     int32_t id;
371     napi_value thisVar = nullptr;
372 
373     napi_get_undefined(env, &jsResult);
374     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
375     if (status != napi_ok || thisVar == nullptr) {
376         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
377         return jsResult;
378     }
379 
380     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
381     if (status == napi_ok && obj != nullptr) {
382         id = obj->GetFileId();
383 #ifdef MEDIALIBRARY_COMPATIBILITY
384         int64_t virtualId = 0;
385         if (MediaFileUtils::IsFileTablePath(obj->GetFilePath())) {
386             virtualId = MediaFileUtils::GetVirtualIdByType(id, MediaType::MEDIA_TYPE_FILE);
387         } else {
388             virtualId = MediaFileUtils::GetVirtualIdByType(id, obj->GetMediaType());
389         }
390         napi_create_int64(env, virtualId, &jsResult);
391 #else
392         napi_create_int32(env, id, &jsResult);
393 #endif
394     }
395 
396     return jsResult;
397 }
398 
JSGetFileUri(napi_env env,napi_callback_info info)399 napi_value FileAssetNapi::JSGetFileUri(napi_env env, napi_callback_info info)
400 {
401     FileAssetNapi *obj = nullptr;
402     CHECK_ARGS(env, GetNapiObject(env, info, &obj), JS_INNER_FAIL);
403 
404     napi_value jsResult = nullptr;
405     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetFileUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
406         JS_INNER_FAIL);
407     return jsResult;
408 }
409 
JSGetFilePath(napi_env env,napi_callback_info info)410 napi_value FileAssetNapi::JSGetFilePath(napi_env env, napi_callback_info info)
411 {
412     napi_status status;
413     napi_value jsResult = nullptr;
414     FileAssetNapi *obj = nullptr;
415     string path = "";
416     napi_value thisVar = nullptr;
417 
418     napi_get_undefined(env, &jsResult);
419     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
420     if (status != napi_ok || thisVar == nullptr) {
421         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
422         return jsResult;
423     }
424 
425     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
426     if (status == napi_ok && obj != nullptr) {
427         path = obj->GetFilePath();
428         napi_create_string_utf8(env, path.c_str(), NAPI_AUTO_LENGTH, &jsResult);
429     }
430 
431     return jsResult;
432 }
433 
JSGetFileDisplayName(napi_env env,napi_callback_info info)434 napi_value FileAssetNapi::JSGetFileDisplayName(napi_env env, napi_callback_info info)
435 {
436     napi_status status;
437     napi_value jsResult = nullptr;
438     FileAssetNapi *obj = nullptr;
439     string displayName = "";
440     napi_value thisVar = nullptr;
441 
442     napi_get_undefined(env, &jsResult);
443     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
444     if (status != napi_ok || thisVar == nullptr) {
445         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
446         return jsResult;
447     }
448 
449     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
450     if (status == napi_ok && obj != nullptr) {
451         displayName = obj->GetFileDisplayName();
452         napi_create_string_utf8(env, displayName.c_str(), NAPI_AUTO_LENGTH, &jsResult);
453     }
454 
455     return jsResult;
456 }
457 
JSSetFileDisplayName(napi_env env,napi_callback_info info)458 napi_value FileAssetNapi::JSSetFileDisplayName(napi_env env, napi_callback_info info)
459 {
460     napi_status status;
461     napi_value undefinedResult = nullptr;
462     FileAssetNapi *obj = nullptr;
463     napi_valuetype valueType = napi_undefined;
464     size_t res = 0;
465     char buffer[FILENAME_MAX];
466     size_t argc = ARGS_ONE;
467     napi_value argv[ARGS_ONE] = {0};
468     napi_value thisVar = nullptr;
469 
470     napi_get_undefined(env, &undefinedResult);
471 
472     GET_JS_ARGS(env, info, argc, argv, thisVar);
473     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
474 
475     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
476     if (status == napi_ok && obj != nullptr) {
477         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
478             NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
479             return undefinedResult;
480         }
481         status = napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res);
482         if (status == napi_ok) {
483             string displayName = string(buffer);
484             obj->fileAssetPtr->SetDisplayName(displayName);
485 #ifdef MEDIALIBRARY_COMPATIBILITY
486             obj->fileAssetPtr->SetTitle(MediaFileUtils::GetTitleFromDisplayName(displayName));
487 #endif
488         }
489     }
490 
491     return undefinedResult;
492 }
493 
JSGetMimeType(napi_env env,napi_callback_info info)494 napi_value FileAssetNapi::JSGetMimeType(napi_env env, napi_callback_info info)
495 {
496     napi_status status;
497     napi_value jsResult = nullptr;
498     FileAssetNapi *obj = nullptr;
499     string mimeType = "";
500     napi_value thisVar = nullptr;
501 
502     napi_get_undefined(env, &jsResult);
503     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
504     if (status != napi_ok || thisVar == nullptr) {
505         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
506         return jsResult;
507     }
508 
509     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
510     if (status == napi_ok && obj != nullptr) {
511         mimeType = obj->fileAssetPtr->GetMimeType();
512         napi_create_string_utf8(env, mimeType.c_str(), NAPI_AUTO_LENGTH, &jsResult);
513     }
514 
515     return jsResult;
516 }
517 
JSGetMediaType(napi_env env,napi_callback_info info)518 napi_value FileAssetNapi::JSGetMediaType(napi_env env, napi_callback_info info)
519 {
520     napi_status status;
521     napi_value jsResult = nullptr;
522     FileAssetNapi *obj = nullptr;
523     int32_t mediaType;
524     napi_value thisVar = nullptr;
525 
526     napi_get_undefined(env, &jsResult);
527     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
528     if (status != napi_ok || thisVar == nullptr) {
529         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
530         return jsResult;
531     }
532 
533     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
534     if (status == napi_ok && obj != nullptr) {
535         mediaType = static_cast<int32_t>(obj->GetMediaType());
536         napi_create_int32(env, mediaType, &jsResult);
537     }
538 
539     return jsResult;
540 }
541 
JSGetTitle(napi_env env,napi_callback_info info)542 napi_value FileAssetNapi::JSGetTitle(napi_env env, napi_callback_info info)
543 {
544     napi_status status;
545     napi_value jsResult = nullptr;
546     FileAssetNapi *obj = nullptr;
547     string title = "";
548     napi_value thisVar = nullptr;
549 
550     napi_get_undefined(env, &jsResult);
551     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
552     if (status != napi_ok || thisVar == nullptr) {
553         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
554         return jsResult;
555     }
556 
557     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
558     if (status == napi_ok && obj != nullptr) {
559         title = obj->GetTitle();
560         napi_create_string_utf8(env, title.c_str(), NAPI_AUTO_LENGTH, &jsResult);
561     }
562 
563     return jsResult;
564 }
JSSetTitle(napi_env env,napi_callback_info info)565 napi_value FileAssetNapi::JSSetTitle(napi_env env, napi_callback_info info)
566 {
567     napi_status status;
568     napi_value undefinedResult = nullptr;
569     FileAssetNapi *obj = nullptr;
570     napi_valuetype valueType = napi_undefined;
571     size_t res = 0;
572     char buffer[FILENAME_MAX];
573     size_t argc = ARGS_ONE;
574     napi_value argv[ARGS_ONE] = {0};
575     napi_value thisVar = nullptr;
576     napi_get_undefined(env, &undefinedResult);
577     GET_JS_ARGS(env, info, argc, argv, thisVar);
578     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
579     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
580     if (status == napi_ok && obj != nullptr) {
581         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
582             NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
583             return undefinedResult;
584         }
585         status = napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res);
586         if (status == napi_ok) {
587             string title = string(buffer);
588             obj->fileAssetPtr->SetTitle(title);
589 #ifdef MEDIALIBRARY_COMPATIBILITY
590             string oldDisplayName = obj->fileAssetPtr->GetDisplayName();
591             string ext = MediaFileUtils::SplitByChar(oldDisplayName, '.');
592             string newDisplayName = title + "." + ext;
593             obj->fileAssetPtr->SetDisplayName(newDisplayName);
594 #endif
595         }
596     }
597     return undefinedResult;
598 }
599 
JSGetSize(napi_env env,napi_callback_info info)600 napi_value FileAssetNapi::JSGetSize(napi_env env, napi_callback_info info)
601 {
602     napi_status status;
603     napi_value jsResult = nullptr;
604     FileAssetNapi *obj = nullptr;
605     int64_t size;
606     napi_value thisVar = nullptr;
607 
608     napi_get_undefined(env, &jsResult);
609     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
610     if (status != napi_ok || thisVar == nullptr) {
611         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
612         return jsResult;
613     }
614 
615     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
616     if (status == napi_ok && obj != nullptr) {
617         size = obj->fileAssetPtr->GetSize();
618         napi_create_int64(env, size, &jsResult);
619     }
620 
621     return jsResult;
622 }
623 
JSGetAlbumId(napi_env env,napi_callback_info info)624 napi_value FileAssetNapi::JSGetAlbumId(napi_env env, napi_callback_info info)
625 {
626     napi_status status;
627     napi_value jsResult = nullptr;
628     FileAssetNapi *obj = nullptr;
629     int32_t albumId;
630     napi_value thisVar = nullptr;
631 
632     napi_get_undefined(env, &jsResult);
633     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
634     if (status != napi_ok || thisVar == nullptr) {
635         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
636         return jsResult;
637     }
638 
639     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
640     if (status == napi_ok && obj != nullptr) {
641         albumId = obj->fileAssetPtr->GetAlbumId();
642         napi_create_int32(env, albumId, &jsResult);
643     }
644 
645     return jsResult;
646 }
647 
JSGetAlbumName(napi_env env,napi_callback_info info)648 napi_value FileAssetNapi::JSGetAlbumName(napi_env env, napi_callback_info info)
649 {
650     napi_status status;
651     napi_value jsResult = nullptr;
652     FileAssetNapi *obj = nullptr;
653     string albumName = "";
654     napi_value thisVar = nullptr;
655 
656     napi_get_undefined(env, &jsResult);
657     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
658     if (status != napi_ok || thisVar == nullptr) {
659         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
660         return jsResult;
661     }
662 
663     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
664     if (status == napi_ok && obj != nullptr) {
665         albumName = obj->fileAssetPtr->GetAlbumName();
666         napi_create_string_utf8(env, albumName.c_str(), NAPI_AUTO_LENGTH, &jsResult);
667     }
668 
669     return jsResult;
670 }
671 
JSGetCount(napi_env env,napi_callback_info info)672 napi_value FileAssetNapi::JSGetCount(napi_env env, napi_callback_info info)
673 {
674     napi_status status;
675     napi_value jsResult = nullptr;
676     napi_value thisVar = nullptr;
677 
678     napi_get_undefined(env, &jsResult);
679     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
680     if ((status != napi_ok) || (thisVar == nullptr)) {
681         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
682         return jsResult;
683     }
684 
685     FileAssetNapi *obj = nullptr;
686     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
687     if ((status == napi_ok) && (obj != nullptr)) {
688         napi_create_int32(env, obj->fileAssetPtr->GetCount(), &jsResult);
689     }
690 
691     return jsResult;
692 }
693 
JSGetDateAdded(napi_env env,napi_callback_info info)694 napi_value FileAssetNapi::JSGetDateAdded(napi_env env, napi_callback_info info)
695 {
696     napi_status status;
697     napi_value jsResult = nullptr;
698     FileAssetNapi *obj = nullptr;
699     int64_t dateAdded;
700     napi_value thisVar = nullptr;
701 
702     napi_get_undefined(env, &jsResult);
703     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
704     if (status != napi_ok || thisVar == nullptr) {
705         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
706         return jsResult;
707     }
708 
709     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
710     if (status == napi_ok && obj != nullptr) {
711         dateAdded = obj->fileAssetPtr->GetDateAdded();
712         napi_create_int64(env, dateAdded, &jsResult);
713     }
714 
715     return jsResult;
716 }
717 
JSGetDateTrashed(napi_env env,napi_callback_info info)718 napi_value FileAssetNapi::JSGetDateTrashed(napi_env env, napi_callback_info info)
719 {
720     napi_status status;
721     napi_value jsResult = nullptr;
722     FileAssetNapi *obj = nullptr;
723     int64_t dateTrashed;
724     napi_value thisVar = nullptr;
725 
726     napi_get_undefined(env, &jsResult);
727     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
728     if (status != napi_ok || thisVar == nullptr) {
729         NAPI_ERR_LOG("Invalid arguments! status: %{private}d", status);
730         return jsResult;
731     }
732 
733     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
734     if (status == napi_ok && obj != nullptr) {
735         dateTrashed = obj->fileAssetPtr->GetDateTrashed();
736         napi_create_int64(env, dateTrashed, &jsResult);
737     }
738 
739     return jsResult;
740 }
741 
JSGetDateModified(napi_env env,napi_callback_info info)742 napi_value FileAssetNapi::JSGetDateModified(napi_env env, napi_callback_info info)
743 {
744     napi_status status;
745     napi_value jsResult = nullptr;
746     FileAssetNapi *obj = nullptr;
747     int64_t dateModified;
748     napi_value thisVar = nullptr;
749 
750     napi_get_undefined(env, &jsResult);
751     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
752     if (status != napi_ok || thisVar == nullptr) {
753         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
754         return jsResult;
755     }
756 
757     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
758     if (status == napi_ok && obj != nullptr) {
759         dateModified = obj->fileAssetPtr->GetDateModified();
760         napi_create_int64(env, dateModified, &jsResult);
761     }
762 
763     return jsResult;
764 }
765 
JSGetOrientation(napi_env env,napi_callback_info info)766 napi_value FileAssetNapi::JSGetOrientation(napi_env env, napi_callback_info info)
767 {
768     napi_status status;
769     napi_value jsResult = nullptr;
770     FileAssetNapi *obj = nullptr;
771     int32_t orientation;
772     napi_value thisVar = nullptr;
773 
774     napi_get_undefined(env, &jsResult);
775     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
776     if (status != napi_ok || thisVar == nullptr) {
777         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
778         return jsResult;
779     }
780 
781     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
782     if (status == napi_ok && obj != nullptr) {
783         orientation = obj->GetOrientation();
784         napi_create_int32(env, orientation, &jsResult);
785     }
786 
787     return jsResult;
788 }
JSSetOrientation(napi_env env,napi_callback_info info)789 napi_value FileAssetNapi::JSSetOrientation(napi_env env, napi_callback_info info)
790 {
791     napi_status status;
792     napi_value undefinedResult = nullptr;
793     FileAssetNapi *obj = nullptr;
794     napi_valuetype valueType = napi_undefined;
795     int32_t orientation;
796     size_t argc = ARGS_ONE;
797     napi_value argv[ARGS_ONE] = {0};
798     napi_value thisVar = nullptr;
799     napi_get_undefined(env, &undefinedResult);
800 
801     GET_JS_ARGS(env, info, argc, argv, thisVar);
802     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
803 
804     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
805     if (status == napi_ok && obj != nullptr) {
806         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_number) {
807             NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
808             return undefinedResult;
809         }
810 
811         status = napi_get_value_int32(env, argv[PARAM0], &orientation);
812         if (status == napi_ok) {
813             obj->fileAssetPtr->SetOrientation(orientation);
814         }
815     }
816 
817     return undefinedResult;
818 }
819 
JSGetWidth(napi_env env,napi_callback_info info)820 napi_value FileAssetNapi::JSGetWidth(napi_env env, napi_callback_info info)
821 {
822     napi_status status;
823     napi_value jsResult = nullptr;
824     FileAssetNapi *obj = nullptr;
825     int32_t width;
826     napi_value thisVar = nullptr;
827 
828     napi_get_undefined(env, &jsResult);
829     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
830     if (status != napi_ok || thisVar == nullptr) {
831         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
832         return jsResult;
833     }
834 
835     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
836     if (status == napi_ok && obj != nullptr) {
837         width = obj->fileAssetPtr->GetWidth();
838         napi_create_int32(env, width, &jsResult);
839     }
840 
841     return jsResult;
842 }
843 
JSGetHeight(napi_env env,napi_callback_info info)844 napi_value FileAssetNapi::JSGetHeight(napi_env env, napi_callback_info info)
845 {
846     napi_status status;
847     napi_value jsResult = nullptr;
848     FileAssetNapi *obj = nullptr;
849     int32_t height;
850     napi_value thisVar = nullptr;
851 
852     napi_get_undefined(env, &jsResult);
853     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
854     if (status != napi_ok || thisVar == nullptr) {
855         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
856         return jsResult;
857     }
858 
859     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
860     if (status == napi_ok && obj != nullptr) {
861         height = obj->fileAssetPtr->GetHeight();
862         napi_create_int32(env, height, &jsResult);
863     }
864 
865     return jsResult;
866 }
867 
JSGetRelativePath(napi_env env,napi_callback_info info)868 napi_value FileAssetNapi::JSGetRelativePath(napi_env env, napi_callback_info info)
869 {
870     napi_status status;
871     napi_value jsResult = nullptr;
872     FileAssetNapi *obj = nullptr;
873     string relativePath = "";
874     napi_value thisVar = nullptr;
875 
876     napi_get_undefined(env, &jsResult);
877     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
878     if (status != napi_ok || thisVar == nullptr) {
879         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
880         return jsResult;
881     }
882 
883     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
884     if (status == napi_ok && obj != nullptr) {
885         relativePath = obj->GetRelativePath();
886         napi_create_string_utf8(env, relativePath.c_str(), NAPI_AUTO_LENGTH, &jsResult);
887     }
888 
889     return jsResult;
890 }
891 
JSSetRelativePath(napi_env env,napi_callback_info info)892 napi_value FileAssetNapi::JSSetRelativePath(napi_env env, napi_callback_info info)
893 {
894     napi_status status;
895     napi_value undefinedResult = nullptr;
896     FileAssetNapi *obj = nullptr;
897     napi_valuetype valueType = napi_undefined;
898     size_t res = 0;
899     char buffer[ARG_BUF_SIZE];
900     size_t argc = ARGS_ONE;
901     napi_value argv[ARGS_ONE] = {0};
902     napi_value thisVar = nullptr;
903     napi_get_undefined(env, &undefinedResult);
904     GET_JS_ARGS(env, info, argc, argv, thisVar);
905     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
906     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
907     if (status == napi_ok && obj != nullptr) {
908         if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
909             NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
910             return undefinedResult;
911         }
912         status = napi_get_value_string_utf8(env, argv[PARAM0], buffer, ARG_BUF_SIZE, &res);
913         if (status == napi_ok) {
914             obj->fileAssetPtr->SetRelativePath(string(buffer));
915         }
916     }
917     return undefinedResult;
918 }
JSGetAlbum(napi_env env,napi_callback_info info)919 napi_value FileAssetNapi::JSGetAlbum(napi_env env, napi_callback_info info)
920 {
921     napi_status status;
922     napi_value jsResult = nullptr;
923     FileAssetNapi *obj = nullptr;
924     string album = "";
925     napi_value thisVar = nullptr;
926 
927     napi_get_undefined(env, &jsResult);
928     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
929     if (status != napi_ok || thisVar == nullptr) {
930         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
931         return jsResult;
932     }
933 
934     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
935     if (status == napi_ok && obj != nullptr) {
936         album = obj->fileAssetPtr->GetAlbum();
937         napi_create_string_utf8(env, album.c_str(), NAPI_AUTO_LENGTH, &jsResult);
938     }
939 
940     return jsResult;
941 }
942 
JSGetArtist(napi_env env,napi_callback_info info)943 napi_value FileAssetNapi::JSGetArtist(napi_env env, napi_callback_info info)
944 {
945     napi_status status;
946     napi_value jsResult = nullptr;
947     FileAssetNapi *obj = nullptr;
948     string artist = "";
949     napi_value thisVar = nullptr;
950 
951     napi_get_undefined(env, &jsResult);
952     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
953     if (status != napi_ok || thisVar == nullptr) {
954         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
955         return jsResult;
956     }
957 
958     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
959     if (status == napi_ok && obj != nullptr) {
960         artist = obj->fileAssetPtr->GetArtist();
961         napi_create_string_utf8(env, artist.c_str(), NAPI_AUTO_LENGTH, &jsResult);
962     }
963 
964     return jsResult;
965 }
966 
JSGetDuration(napi_env env,napi_callback_info info)967 napi_value FileAssetNapi::JSGetDuration(napi_env env, napi_callback_info info)
968 {
969     napi_status status;
970     napi_value jsResult = nullptr;
971     FileAssetNapi *obj = nullptr;
972     int32_t duration;
973     napi_value thisVar = nullptr;
974 
975     napi_get_undefined(env, &jsResult);
976     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
977     if (status != napi_ok || thisVar == nullptr) {
978         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
979         return jsResult;
980     }
981 
982     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
983     if (status == napi_ok && obj != nullptr) {
984         duration = obj->fileAssetPtr->GetDuration();
985         napi_create_int32(env, duration, &jsResult);
986     }
987 
988     return jsResult;
989 }
990 
JSParent(napi_env env,napi_callback_info info)991 napi_value FileAssetNapi::JSParent(napi_env env, napi_callback_info info)
992 {
993     napi_status status;
994     napi_value jsResult = nullptr;
995     FileAssetNapi *obj = nullptr;
996     int32_t parent;
997     napi_value thisVar = nullptr;
998     napi_get_undefined(env, &jsResult);
999     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1000     if (status != napi_ok || thisVar == nullptr) {
1001         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1002         return jsResult;
1003     }
1004     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1005     if (status == napi_ok && obj != nullptr) {
1006         parent = obj->fileAssetPtr->GetParent();
1007         napi_create_int32(env, parent, &jsResult);
1008     }
1009     return jsResult;
1010 }
JSGetAlbumUri(napi_env env,napi_callback_info info)1011 napi_value FileAssetNapi::JSGetAlbumUri(napi_env env, napi_callback_info info)
1012 {
1013     napi_status status;
1014     napi_value jsResult = nullptr;
1015     FileAssetNapi *obj = nullptr;
1016     string albumUri = "";
1017     napi_value thisVar = nullptr;
1018     napi_get_undefined(env, &jsResult);
1019     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1020     if (status != napi_ok || thisVar == nullptr) {
1021         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1022         return jsResult;
1023     }
1024     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1025     if (status == napi_ok && obj != nullptr) {
1026         albumUri = obj->fileAssetPtr->GetAlbumUri();
1027         napi_create_string_utf8(env, albumUri.c_str(), NAPI_AUTO_LENGTH, &jsResult);
1028     }
1029     return jsResult;
1030 }
JSGetDateTaken(napi_env env,napi_callback_info info)1031 napi_value FileAssetNapi::JSGetDateTaken(napi_env env, napi_callback_info info)
1032 {
1033     napi_status status;
1034     napi_value jsResult = nullptr;
1035     FileAssetNapi *obj = nullptr;
1036     int64_t dateTaken;
1037     napi_value thisVar = nullptr;
1038     napi_get_undefined(env, &jsResult);
1039     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
1040     if (status != napi_ok || thisVar == nullptr) {
1041         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
1042         return jsResult;
1043     }
1044     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
1045     if (status == napi_ok && obj != nullptr) {
1046         dateTaken = obj->fileAssetPtr->GetDateTaken();
1047         napi_create_int64(env, dateTaken, &jsResult);
1048     }
1049     return jsResult;
1050 }
1051 
BuildCommitModifyValuesBucket(FileAssetAsyncContext * context,DataShareValuesBucket & valuesBucket)1052 void BuildCommitModifyValuesBucket(FileAssetAsyncContext* context, DataShareValuesBucket &valuesBucket)
1053 {
1054     const auto fileAsset = context->objectPtr;
1055     if (context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1056         valuesBucket.Put(MediaColumn::MEDIA_TITLE, fileAsset->GetTitle());
1057     } else if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1058         valuesBucket.Put(MediaColumn::MEDIA_NAME, fileAsset->GetDisplayName());
1059     } else {
1060 #ifdef MEDIALIBRARY_COMPATIBILITY
1061         valuesBucket.Put(MEDIA_DATA_DB_TITLE, fileAsset->GetTitle());
1062         valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, fileAsset->GetRelativePath());
1063         if (fileAsset->GetMediaType() != MediaType::MEDIA_TYPE_AUDIO) {
1064             // IMAGE, VIDEO AND FILES
1065             if (fileAsset->GetOrientation() >= 0) {
1066                 valuesBucket.Put(MEDIA_DATA_DB_ORIENTATION, fileAsset->GetOrientation());
1067             }
1068             if ((fileAsset->GetMediaType() != MediaType::MEDIA_TYPE_IMAGE) &&
1069                 (fileAsset->GetMediaType() != MediaType::MEDIA_TYPE_VIDEO)) {
1070                 // ONLY FILES
1071                 valuesBucket.Put(MEDIA_DATA_DB_URI, fileAsset->GetUri());
1072                 valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileAsset->GetMediaType());
1073             }
1074         }
1075 #else
1076         valuesBucket.Put(MEDIA_DATA_DB_URI, fileAsset->GetUri());
1077         valuesBucket.Put(MEDIA_DATA_DB_TITLE, fileAsset->GetTitle());
1078 
1079         if (fileAsset->GetOrientation() >= 0) {
1080             valuesBucket.Put(MEDIA_DATA_DB_ORIENTATION, fileAsset->GetOrientation());
1081         }
1082         valuesBucket.Put(MEDIA_DATA_DB_RELATIVE_PATH, fileAsset->GetRelativePath());
1083         valuesBucket.Put(MEDIA_DATA_DB_MEDIA_TYPE, fileAsset->GetMediaType());
1084 #endif
1085         valuesBucket.Put(MEDIA_DATA_DB_NAME, fileAsset->GetDisplayName());
1086     }
1087 }
1088 
1089 #ifdef MEDIALIBRARY_COMPATIBILITY
BuildCommitModifyUriApi9(FileAssetAsyncContext * context,string & uri)1090 static void BuildCommitModifyUriApi9(FileAssetAsyncContext *context, string &uri)
1091 {
1092     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
1093         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
1094         uri = URI_UPDATE_PHOTO;
1095     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
1096         uri = URI_UPDATE_AUDIO;
1097     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_FILE) {
1098         uri = URI_UPDATE_FILE;
1099     }
1100 }
1101 #endif
1102 
BuildCommitModifyUriApi10(FileAssetAsyncContext * context,string & uri)1103 static void BuildCommitModifyUriApi10(FileAssetAsyncContext *context, string &uri)
1104 {
1105     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
1106         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
1107         uri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ? UFM_UPDATE_PHOTO : PAH_UPDATE_PHOTO;
1108     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
1109         uri = UFM_UPDATE_AUDIO;
1110     }
1111 }
1112 
CheckDisplayNameInCommitModify(FileAssetAsyncContext * context)1113 static bool CheckDisplayNameInCommitModify(FileAssetAsyncContext *context)
1114 {
1115     if (context->resultNapiType != ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1116         if (context->objectPtr->GetMediaType() != MediaType::MEDIA_TYPE_FILE) {
1117             if (MediaFileUtils::CheckDisplayName(context->objectPtr->GetDisplayName()) != E_OK) {
1118                 context->error = JS_E_DISPLAYNAME;
1119                 return false;
1120             }
1121         } else {
1122             if (MediaFileUtils::CheckFileDisplayName(context->objectPtr->GetDisplayName()) != E_OK) {
1123                 context->error = JS_E_DISPLAYNAME;
1124                 return false;
1125             }
1126         }
1127     }
1128     return true;
1129 }
1130 
JSCommitModifyExecute(napi_env env,void * data)1131 static void JSCommitModifyExecute(napi_env env, void *data)
1132 {
1133     auto *context = static_cast<FileAssetAsyncContext*>(data);
1134     MediaLibraryTracer tracer;
1135     tracer.Start("JSCommitModifyExecute");
1136     if (!CheckDisplayNameInCommitModify(context)) {
1137         return;
1138     }
1139     string uri;
1140     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1141         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
1142         BuildCommitModifyUriApi10(context, uri);
1143         MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1144     } else {
1145 #ifdef MEDIALIBRARY_COMPATIBILITY
1146         BuildCommitModifyUriApi9(context, uri);
1147 #else
1148         uri = URI_UPDATE_FILE;
1149 #endif
1150     }
1151 
1152     Uri updateAssetUri(uri);
1153     MediaType mediaType = context->objectPtr->GetMediaType();
1154     string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
1155     DataSharePredicates predicates;
1156     DataShareValuesBucket valuesBucket;
1157     BuildCommitModifyValuesBucket(context, valuesBucket);
1158     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
1159     predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
1160 
1161     int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
1162     if (changedRows < 0) {
1163         context->SaveError(changedRows);
1164         NAPI_ERR_LOG("File asset modification failed, err: %{public}d", changedRows);
1165     } else {
1166         context->changedRows = changedRows;
1167         Uri modifyNotify(notifyUri);
1168         UserFileClient::NotifyChange(modifyNotify);
1169     }
1170 }
1171 
JSCommitModifyCompleteCallback(napi_env env,napi_status status,void * data)1172 static void JSCommitModifyCompleteCallback(napi_env env, napi_status status, void *data)
1173 {
1174     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
1175     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1176     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1177     jsContext->status = false;
1178 
1179     MediaLibraryTracer tracer;
1180     tracer.Start("JSCommitModifyCompleteCallback");
1181 
1182     if (context->error == ERR_DEFAULT) {
1183         if (context->changedRows < 0) {
1184             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
1185                                                          "File asset modification failed");
1186             napi_get_undefined(env, &jsContext->data);
1187         } else {
1188             napi_create_int32(env, context->changedRows, &jsContext->data);
1189             jsContext->status = true;
1190             napi_get_undefined(env, &jsContext->error);
1191         }
1192     } else {
1193         NAPI_ERR_LOG("JSCommitModify fail %{public}d", context->error);
1194         context->HandleError(env, jsContext->error);
1195         napi_get_undefined(env, &jsContext->data);
1196     }
1197     tracer.Finish();
1198     if (context->work != nullptr) {
1199         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1200                                                    context->work, *jsContext);
1201     }
1202     delete context;
1203 }
GetJSArgsForCommitModify(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)1204 napi_value GetJSArgsForCommitModify(napi_env env, size_t argc, const napi_value argv[],
1205                                     FileAssetAsyncContext &asyncContext)
1206 {
1207     const int32_t refCount = 1;
1208     napi_value result = nullptr;
1209     auto context = &asyncContext;
1210     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1211     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1212     for (size_t i = PARAM0; i < argc; i++) {
1213         napi_valuetype valueType = napi_undefined;
1214         napi_typeof(env, argv[i], &valueType);
1215         if (i == PARAM0 && valueType == napi_function) {
1216             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1217             break;
1218         } else {
1219             NAPI_ASSERT(env, false, "type mismatch");
1220         }
1221     }
1222     napi_get_boolean(env, true, &result);
1223     return result;
1224 }
1225 
JSCommitModify(napi_env env,napi_callback_info info)1226 napi_value FileAssetNapi::JSCommitModify(napi_env env, napi_callback_info info)
1227 {
1228     napi_status status;
1229     napi_value result = nullptr;
1230     size_t argc = ARGS_ONE;
1231     napi_value argv[ARGS_ONE] = {0};
1232     napi_value thisVar = nullptr;
1233     MediaLibraryTracer tracer;
1234     tracer.Start("JSCommitModify");
1235 
1236     GET_JS_ARGS(env, info, argc, argv, thisVar);
1237     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameters maximum");
1238     napi_get_undefined(env, &result);
1239 
1240     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1241     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1242     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1243     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1244         result = GetJSArgsForCommitModify(env, argc, argv, *asyncContext);
1245         ASSERT_NULLPTR_CHECK(env, result);
1246         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1247         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1248 
1249         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
1250             JSCommitModifyCompleteCallback);
1251     }
1252 
1253     return result;
1254 }
1255 
JSOpenExecute(napi_env env,void * data)1256 static void JSOpenExecute(napi_env env, void *data)
1257 {
1258     MediaLibraryTracer tracer;
1259     tracer.Start("JSOpenExecute");
1260 
1261     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
1262     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1263 
1264     bool isValid = false;
1265     string mode = context->valuesBucket.Get(MEDIA_FILEMODE, isValid);
1266     if (!isValid) {
1267         context->error = ERR_INVALID_OUTPUT;
1268         NAPI_ERR_LOG("getting mode invalid");
1269         return;
1270     }
1271     transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
1272 
1273     string fileUri = context->objectPtr->GetUri();
1274     Uri openFileUri(fileUri);
1275     int32_t retVal = UserFileClient::OpenFile(openFileUri, mode);
1276     if (retVal <= 0) {
1277         context->SaveError(retVal);
1278         NAPI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
1279     } else {
1280         context->fd = retVal;
1281         if (mode.find('w') != string::npos) {
1282             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
1283         } else {
1284             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
1285         }
1286     }
1287 }
1288 
JSOpenCompleteCallback(napi_env env,napi_status status,void * data)1289 static void JSOpenCompleteCallback(napi_env env, napi_status status, void *data)
1290 {
1291     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
1292     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1293 
1294     MediaLibraryTracer tracer;
1295     tracer.Start("JSOpenCompleteCallback");
1296 
1297     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1298     jsContext->status = false;
1299 
1300     if (context->error == ERR_DEFAULT) {
1301         NAPI_DEBUG_LOG("return fd = %{public}d", context->fd);
1302         napi_create_int32(env, context->fd, &jsContext->data);
1303         napi_get_undefined(env, &jsContext->error);
1304         jsContext->status = true;
1305     } else {
1306         context->HandleError(env, jsContext->error);
1307         napi_get_undefined(env, &jsContext->data);
1308     }
1309 
1310     tracer.Finish();
1311     if (context->work != nullptr) {
1312         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1313                                                    context->work, *jsContext);
1314     }
1315 
1316     delete context;
1317 }
1318 
GetJSArgsForOpen(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)1319 napi_value GetJSArgsForOpen(napi_env env, size_t argc, const napi_value argv[],
1320                             FileAssetAsyncContext &asyncContext)
1321 {
1322     const int32_t refCount = 1;
1323     napi_value result = nullptr;
1324     auto context = &asyncContext;
1325     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1326     size_t res = 0;
1327     char buffer[ARG_BUF_SIZE];
1328 
1329     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1330 
1331     for (size_t i = PARAM0; i < argc; i++) {
1332         napi_valuetype valueType = napi_undefined;
1333         napi_typeof(env, argv[i], &valueType);
1334 
1335         if (i == PARAM0 && valueType == napi_string) {
1336             napi_get_value_string_utf8(env, argv[i], buffer, ARG_BUF_SIZE, &res);
1337         } else if (i == PARAM1 && valueType == napi_function) {
1338             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1339             break;
1340         } else {
1341             NAPI_ASSERT(env, false, "type mismatch");
1342         }
1343     }
1344     context->valuesBucket.Put(MEDIA_FILEMODE, string(buffer));
1345     // Return true napi_value if params are successfully obtained
1346     napi_get_boolean(env, true, &result);
1347     return result;
1348 }
1349 
JSOpen(napi_env env,napi_callback_info info)1350 napi_value FileAssetNapi::JSOpen(napi_env env, napi_callback_info info)
1351 {
1352     napi_status status;
1353     napi_value result = nullptr;
1354     size_t argc = ARGS_TWO;
1355     napi_value argv[ARGS_TWO] = {0};
1356     napi_value thisVar = nullptr;
1357 
1358     MediaLibraryTracer tracer;
1359     tracer.Start("JSOpen");
1360 
1361     GET_JS_ARGS(env, info, argc, argv, thisVar);
1362     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1363     napi_get_undefined(env, &result);
1364 
1365     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1366     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1367     if ((status == napi_ok) && (asyncContext->objectInfo != nullptr)) {
1368         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1369         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1370         result = GetJSArgsForOpen(env, argc, argv, *asyncContext);
1371         ASSERT_NULLPTR_CHECK(env, result);
1372         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSOpen", JSOpenExecute,
1373             JSOpenCompleteCallback);
1374     }
1375 
1376     return result;
1377 }
1378 
CheckFileOpenStatus(FileAssetAsyncContext * context,int fd)1379 static bool CheckFileOpenStatus(FileAssetAsyncContext *context, int fd)
1380 {
1381     auto fileAssetPtr = context->objectPtr;
1382     int ret = fileAssetPtr->GetOpenStatus(fd);
1383     if (ret < 0) {
1384         return false;
1385     } else {
1386         fileAssetPtr->RemoveOpenStatus(fd);
1387         if (ret == OPEN_TYPE_READONLY) {
1388             return false;
1389         } else {
1390             return true;
1391         }
1392     }
1393 }
1394 
JSCloseExecute(FileAssetAsyncContext * context)1395 static void JSCloseExecute(FileAssetAsyncContext *context)
1396 {
1397     MediaLibraryTracer tracer;
1398     tracer.Start("JSCloseExecute");
1399 
1400 #ifdef MEDIALIBRARY_COMPATIBILITY
1401     string closeUri;
1402     if (MediaFileUtils::IsFileTablePath(context->objectPtr->GetPath()) ||
1403         MediaFileUtils::StartsWith(context->objectPtr->GetRelativePath(), DOC_DIR_VALUES) ||
1404         MediaFileUtils::StartsWith(context->objectPtr->GetRelativePath(), DOWNLOAD_DIR_VALUES)) {
1405         closeUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CLOSEASSET;
1406     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
1407         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
1408         closeUri = URI_CLOSE_PHOTO;
1409     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
1410         closeUri = URI_CLOSE_AUDIO;
1411     } else {
1412         closeUri = URI_CLOSE_FILE;
1413     }
1414 #else
1415     string closeUri = URI_CLOSE_FILE;
1416 #endif
1417     Uri closeAssetUri(closeUri);
1418     bool isValid = false;
1419     UniqueFd unifd(context->valuesBucket.Get(MEDIA_FILEDESCRIPTOR, isValid));
1420     if (!isValid) {
1421         context->error = ERR_INVALID_OUTPUT;
1422         NAPI_ERR_LOG("getting fd is invalid");
1423         return;
1424     }
1425 
1426     if (!CheckFileOpenStatus(context, unifd.Get())) {
1427         return;
1428     }
1429 
1430     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
1431     if (!isValid) {
1432         context->error = ERR_INVALID_OUTPUT;
1433         NAPI_ERR_LOG("getting file uri is invalid");
1434         return;
1435     }
1436     if (!MediaFileUtils::GetNetworkIdFromUri(fileUri).empty()) {
1437         return;
1438     }
1439 
1440     auto retVal = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
1441     if (retVal != E_SUCCESS) {
1442         context->SaveError(retVal);
1443         NAPI_ERR_LOG("File close asset failed %{public}d", retVal);
1444     }
1445 }
1446 
JSCloseCompleteCallback(napi_env env,napi_status status,FileAssetAsyncContext * context)1447 static void JSCloseCompleteCallback(napi_env env, napi_status status,
1448                                     FileAssetAsyncContext *context)
1449 {
1450     MediaLibraryTracer tracer;
1451     tracer.Start("JSCloseCompleteCallback");
1452 
1453     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1454     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1455     jsContext->status = false;
1456 
1457     if (context->error == ERR_DEFAULT) {
1458         napi_create_int32(env, E_SUCCESS, &jsContext->data);
1459         napi_get_undefined(env, &jsContext->error);
1460         jsContext->status = true;
1461     } else {
1462         context->HandleError(env, jsContext->error);
1463         napi_get_undefined(env, &jsContext->data);
1464     }
1465 
1466     tracer.Finish();
1467     if (context->work != nullptr) {
1468         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1469                                                    context->work, *jsContext);
1470     }
1471 
1472     delete context;
1473 }
1474 
GetJSArgsForClose(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)1475 napi_value GetJSArgsForClose(napi_env env, size_t argc, const napi_value argv[],
1476                              FileAssetAsyncContext &asyncContext)
1477 {
1478     const int32_t refCount = 1;
1479     napi_value result = nullptr;
1480     auto context = &asyncContext;
1481     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1482     int32_t fd = 0;
1483 
1484     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1485 
1486     for (size_t i = PARAM0; i < argc; i++) {
1487         napi_valuetype valueType = napi_undefined;
1488         napi_typeof(env, argv[i], &valueType);
1489 
1490         if (i == PARAM0 && valueType == napi_number) {
1491             napi_get_value_int32(env, argv[i], &fd);
1492             if (fd <= 0) {
1493                 NAPI_ASSERT(env, false, "fd <= 0");
1494             }
1495         } else if (i == PARAM1 && valueType == napi_function) {
1496             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1497             break;
1498         } else {
1499             NAPI_ASSERT(env, false, "type mismatch");
1500         }
1501     }
1502     context->valuesBucket.Put(MEDIA_FILEDESCRIPTOR, fd);
1503     context->valuesBucket.Put(MEDIA_DATA_DB_URI, context->objectInfo->GetFileUri());
1504     // Return true napi_value if params are successfully obtained
1505     napi_get_boolean(env, true, &result);
1506     return result;
1507 }
1508 
JSClose(napi_env env,napi_callback_info info)1509 napi_value FileAssetNapi::JSClose(napi_env env, napi_callback_info info)
1510 {
1511     napi_status status;
1512     napi_value result = nullptr;
1513     size_t argc = ARGS_TWO;
1514     napi_value argv[ARGS_TWO] = {0};
1515     napi_value thisVar = nullptr;
1516     napi_value resource = nullptr;
1517 
1518     MediaLibraryTracer tracer;
1519     tracer.Start("JSClose");
1520 
1521     GET_JS_ARGS(env, info, argc, argv, thisVar);
1522     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
1523     napi_get_undefined(env, &result);
1524     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1525     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1526     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1527         result = GetJSArgsForClose(env, argc, argv, *asyncContext);
1528         ASSERT_NULLPTR_CHECK(env, result);
1529         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
1530         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSClose", asyncContext);
1531 
1532         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1533         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1534 
1535         status = napi_create_async_work(
1536             env, nullptr, resource, [](napi_env env, void *data) {
1537                 auto context = static_cast<FileAssetAsyncContext*>(data);
1538                 JSCloseExecute(context);
1539             },
1540             reinterpret_cast<CompleteCallback>(JSCloseCompleteCallback),
1541             static_cast<void *>(asyncContext.get()), &asyncContext->work);
1542         if (status != napi_ok) {
1543             napi_get_undefined(env, &result);
1544         } else {
1545             napi_queue_async_work(env, asyncContext->work);
1546             asyncContext.release();
1547         }
1548     }
1549 
1550     return result;
1551 }
1552 
OpenThumbnail(string & uriStr,const string & path,const Size & size)1553 static int OpenThumbnail(string &uriStr, const string &path, const Size &size)
1554 {
1555     if (!path.empty()) {
1556         string sandboxPath = GetSandboxPath(path, IsThumbnail(size.width, size.height));
1557         int fd = -1;
1558         if (!sandboxPath.empty()) {
1559             fd = open(sandboxPath.c_str(), O_RDONLY);
1560         }
1561         if (fd > 0) {
1562             return fd;
1563         }
1564         if (IsAsciiString(path)) {
1565             uriStr += "&" + THUMBNAIL_PATH + "=" + path;
1566         }
1567     }
1568     Uri openUri(uriStr);
1569     return UserFileClient::OpenFile(openUri, "R");
1570 }
1571 
QueryThumbnail(const std::string & uri,Size & size,const bool isApiVersion10,const string & path)1572 static unique_ptr<PixelMap> QueryThumbnail(const std::string &uri, Size &size,
1573     const bool isApiVersion10, const string &path)
1574 {
1575     MediaLibraryTracer tracer;
1576     tracer.Start("QueryThumbnail uri:" + uri);
1577 
1578     string openUriStr = uri + "?" + MEDIA_OPERN_KEYWORD + "=" + MEDIA_DATA_DB_THUMBNAIL + "&" + MEDIA_DATA_DB_WIDTH +
1579         "=" + to_string(size.width) + "&" + MEDIA_DATA_DB_HEIGHT + "=" + to_string(size.height);
1580     if (isApiVersion10) {
1581         MediaLibraryNapiUtils::UriAppendKeyValue(openUriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1582     }
1583     tracer.Start("DataShare::OpenFile");
1584     UniqueFd uniqueFd(OpenThumbnail(openUriStr, path, size));
1585     if (uniqueFd.Get() < 0) {
1586         NAPI_ERR_LOG("queryThumb is null, errCode is %{public}d", uniqueFd.Get());
1587         return nullptr;
1588     }
1589     tracer.Finish();
1590     tracer.Start("ImageSource::CreateImageSource");
1591     SourceOptions opts;
1592     uint32_t err = 0;
1593     unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(uniqueFd.Get(), opts, err);
1594     if (imageSource  == nullptr) {
1595         NAPI_ERR_LOG("CreateImageSource err %{public}d", err);
1596         return nullptr;
1597     }
1598 
1599     DecodeOptions decodeOpts;
1600     decodeOpts.desiredSize = size;
1601     decodeOpts.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
1602 #ifndef IMAGE_PURGEABLE_PIXELMAP
1603     return imageSource->CreatePixelMap(decodeOpts, err);
1604 #else
1605     unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, err);
1606     PurgeableBuilder::MakePixelMapToBePurgeable(pixelMap, uniqueFd.Get(), opts, decodeOpts);
1607     return pixelMap;
1608 #endif
1609 }
1610 
JSGetThumbnailExecute(FileAssetAsyncContext * context)1611 static void JSGetThumbnailExecute(FileAssetAsyncContext* context)
1612 {
1613     MediaLibraryTracer tracer;
1614     tracer.Start("JSGetThumbnailExecute");
1615 
1616     Size size = { .width = context->thumbWidth, .height = context->thumbHeight };
1617     bool isApiVersion10 = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR ||
1618         context->resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1619     string path = context->objectPtr->GetPath();
1620 #ifndef MEDIALIBRARY_COMPATIBILITY
1621     if (path.empty()
1622             && !context->objectPtr->GetRelativePath().empty() && !context->objectPtr->GetDisplayName().empty()) {
1623         path = ROOT_MEDIA_DIR + context->objectPtr->GetRelativePath() + context->objectPtr->GetDisplayName();
1624     }
1625 #endif
1626     context->pixelmap = QueryThumbnail(context->objectPtr->GetUri(), size, isApiVersion10, path);
1627 }
1628 
JSGetThumbnailCompleteCallback(napi_env env,napi_status status,FileAssetAsyncContext * context)1629 static void JSGetThumbnailCompleteCallback(napi_env env, napi_status status,
1630                                            FileAssetAsyncContext* context)
1631 {
1632     MediaLibraryTracer tracer;
1633     tracer.Start("JSGetThumbnailCompleteCallback");
1634 
1635     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1636 
1637     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1638     jsContext->status = false;
1639 
1640     if (context->error == ERR_DEFAULT) {
1641         if (context->pixelmap != nullptr) {
1642             jsContext->data = Media::PixelMapNapi::CreatePixelMap(env, context->pixelmap);
1643             napi_get_undefined(env, &jsContext->error);
1644             jsContext->status = true;
1645         } else {
1646             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1647                 "Get thumbnail failed");
1648             napi_get_undefined(env, &jsContext->data);
1649         }
1650     } else {
1651         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1652             "Ability helper or thumbnail helper is null");
1653         napi_get_undefined(env, &jsContext->data);
1654     }
1655 
1656     tracer.Finish();
1657     if (context->work != nullptr) {
1658         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1659                                                    context->work, *jsContext);
1660     }
1661 
1662     delete context;
1663 }
1664 
GetSizeInfo(napi_env env,napi_value configObj,std::string type,int32_t & result)1665 static void GetSizeInfo(napi_env env, napi_value configObj, std::string type, int32_t &result)
1666 {
1667     napi_value item = nullptr;
1668     bool exist = false;
1669     napi_status status = napi_has_named_property(env, configObj, type.c_str(), &exist);
1670     if (status != napi_ok || !exist) {
1671         NAPI_ERR_LOG("can not find named property, status: %{public}d", status);
1672         return;
1673     }
1674 
1675     if (napi_get_named_property(env, configObj, type.c_str(), &item) != napi_ok) {
1676         NAPI_ERR_LOG("get named property fail");
1677         return;
1678     }
1679 
1680     if (napi_get_value_int32(env, item, &result) != napi_ok) {
1681         NAPI_ERR_LOG("get property value fail");
1682     }
1683 }
1684 
GetJSArgsForGetThumbnail(napi_env env,size_t argc,const napi_value argv[],unique_ptr<FileAssetAsyncContext> & asyncContext)1685 napi_value GetJSArgsForGetThumbnail(napi_env env, size_t argc, const napi_value argv[],
1686                                     unique_ptr<FileAssetAsyncContext> &asyncContext)
1687 {
1688     asyncContext->thumbWidth = DEFAULT_THUMB_SIZE;
1689     asyncContext->thumbHeight = DEFAULT_THUMB_SIZE;
1690 
1691     if (argc == ARGS_ONE) {
1692         napi_valuetype valueType = napi_undefined;
1693         if (napi_typeof(env, argv[PARAM0], &valueType) == napi_ok &&
1694             (valueType == napi_undefined || valueType == napi_null)) {
1695             argc -= 1;
1696         }
1697     }
1698 
1699     for (size_t i = PARAM0; i < argc; i++) {
1700         napi_valuetype valueType = napi_undefined;
1701         napi_typeof(env, argv[i], &valueType);
1702 
1703         if (i == PARAM0 && valueType == napi_object) {
1704             GetSizeInfo(env, argv[PARAM0], "width", asyncContext->thumbWidth);
1705             GetSizeInfo(env, argv[PARAM0], "height", asyncContext->thumbHeight);
1706         } else if (i == PARAM0 && valueType == napi_function) {
1707             napi_create_reference(env, argv[i], NAPI_INIT_REF_COUNT, &asyncContext->callbackRef);
1708             break;
1709         } else if (i == PARAM1 && valueType == napi_function) {
1710             napi_create_reference(env, argv[i], NAPI_INIT_REF_COUNT, &asyncContext->callbackRef);
1711             break;
1712         } else {
1713             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Invalid parameter type");
1714             return nullptr;
1715         }
1716     }
1717 
1718     napi_value result = nullptr;
1719     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1720     return result;
1721 }
1722 
JSGetThumbnail(napi_env env,napi_callback_info info)1723 napi_value FileAssetNapi::JSGetThumbnail(napi_env env, napi_callback_info info)
1724 {
1725     napi_status status;
1726     napi_value result = nullptr;
1727     size_t argc = ARGS_TWO;
1728     napi_value argv[ARGS_TWO] = {0};
1729     napi_value thisVar = nullptr;
1730     napi_value resource = nullptr;
1731 
1732     MediaLibraryTracer tracer;
1733     tracer.Start("JSGetThumbnail");
1734 
1735     GET_JS_ARGS(env, info, argc, argv, thisVar);
1736     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE || argc == ARGS_TWO),
1737         "requires 2 parameters maximum");
1738     napi_get_undefined(env, &result);
1739     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1740     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1741     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1742         result = GetJSArgsForGetThumbnail(env, argc, argv, asyncContext);
1743         CHECK_NULLPTR_RET(result);
1744         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
1745         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSGetThumbnail", asyncContext);
1746         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1747         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1748 
1749         status = napi_create_async_work(
1750             env, nullptr, resource, [](napi_env env, void *data) {
1751                 auto context = static_cast<FileAssetAsyncContext*>(data);
1752                 JSGetThumbnailExecute(context);
1753             },
1754             reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback),
1755             static_cast<void *>(asyncContext.get()), &asyncContext->work);
1756         if (status != napi_ok) {
1757             napi_get_undefined(env, &result);
1758         } else {
1759             napi_queue_async_work(env, asyncContext->work);
1760             asyncContext.release();
1761         }
1762     }
1763 
1764     return result;
1765 }
1766 
JSFavoriteCallbackComplete(napi_env env,napi_status status,void * data)1767 static void JSFavoriteCallbackComplete(napi_env env, napi_status status, void *data)
1768 {
1769     MediaLibraryTracer tracer;
1770     tracer.Start("JSFavoriteCallbackComplete");
1771 
1772     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
1773     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1774     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1775     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
1776     jsContext->status = false;
1777     napi_get_undefined(env, &jsContext->data);
1778     if (context->error == ERR_DEFAULT) {
1779         jsContext->status = true;
1780         Media::MediaType mediaType = context->objectPtr->GetMediaType();
1781         string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
1782         Uri modifyNotify(notifyUri);
1783         UserFileClient::NotifyChange(modifyNotify);
1784     } else {
1785         context->HandleError(env, jsContext->error);
1786         napi_get_undefined(env, &jsContext->data);
1787     }
1788 
1789     tracer.Finish();
1790     if (context->work != nullptr) {
1791         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1792                                                    context->work, *jsContext);
1793     }
1794 
1795     delete context;
1796 }
1797 
GetIsDirectoryiteNative(napi_env env,const FileAssetAsyncContext & fileContext)1798 static bool GetIsDirectoryiteNative(napi_env env, const FileAssetAsyncContext &fileContext)
1799 {
1800     MediaLibraryTracer tracer;
1801     tracer.Start("GetIsDirectoryiteNative");
1802 
1803     FileAssetAsyncContext *context = const_cast<FileAssetAsyncContext *>(&fileContext);
1804     if (context == nullptr) {
1805         NAPI_ERR_LOG("Async context is null");
1806         return false;
1807     }
1808 
1809 #ifdef MEDIALIBRARY_COMPATIBILITY
1810     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO) ||
1811         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
1812         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
1813         context->status = true;
1814         return false;
1815     }
1816 
1817     int64_t virtualId = MediaFileUtils::GetVirtualIdByType(context->objectPtr->GetId(), MediaType::MEDIA_TYPE_FILE);
1818     vector<string> selectionArgs = { to_string(virtualId) };
1819 #else
1820     vector<string> selectionArgs = { to_string(context->objectPtr->GetId()) };
1821 #endif
1822     vector<string> columns = { MEDIA_DATA_DB_MEDIA_TYPE };
1823     DataSharePredicates predicates;
1824     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ?");
1825     predicates.SetWhereArgs(selectionArgs);
1826     string queryUri = MEDIALIBRARY_DATA_URI;
1827     Uri uri(queryUri);
1828     int errCode = 0;
1829     shared_ptr<DataShare::DataShareResultSet> resultSet = UserFileClient::Query(uri, predicates, columns, errCode);
1830     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1831         NAPI_ERR_LOG("Query IsDirectory failed");
1832         return false;
1833     }
1834     int32_t index = 0;
1835     if (resultSet->GetColumnIndex(MEDIA_DATA_DB_MEDIA_TYPE, index) != NativeRdb::E_OK) {
1836         NAPI_ERR_LOG("Query Directory failed");
1837         return false;
1838     }
1839     int32_t mediaType = 0;
1840     if (resultSet->GetInt(index, mediaType) != NativeRdb::E_OK) {
1841         NAPI_ERR_LOG("Can not get file path");
1842         return false;
1843     }
1844     context->status = true;
1845     return  mediaType == static_cast<int>(MediaType::MEDIA_TYPE_ALBUM);
1846 }
1847 
JSIsDirectoryCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)1848 static void JSIsDirectoryCallbackComplete(napi_env env, napi_status status,
1849                                           FileAssetAsyncContext* context)
1850 {
1851     MediaLibraryTracer tracer;
1852     tracer.Start("JSIsDirectoryCallbackComplete");
1853 
1854     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1855     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1856     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
1857     jsContext->status = false;
1858 
1859     if (context->status) {
1860         napi_get_boolean(env, context->isDirectory, &jsContext->data);
1861         napi_get_undefined(env, &jsContext->error);
1862         jsContext->status = true;
1863     } else {
1864         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1865                                                      "UserFileClient is invalid");
1866         napi_get_undefined(env, &jsContext->data);
1867     }
1868 
1869     tracer.Finish();
1870     if (context->work != nullptr) {
1871         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1872                                                    context->work, *jsContext);
1873     }
1874 
1875     delete context;
1876 }
1877 
GetJSArgsForIsDirectory(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)1878 static napi_value GetJSArgsForIsDirectory(napi_env env, size_t argc, const napi_value argv[],
1879                                           FileAssetAsyncContext &asyncContext)
1880 {
1881     const int32_t refCount = 1;
1882     napi_value result;
1883     auto context = &asyncContext;
1884     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1885     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1886     for (size_t i = PARAM0; i < argc; i++) {
1887         napi_valuetype valueType = napi_undefined;
1888         napi_typeof(env, argv[i], &valueType);
1889         if (i == PARAM0 && valueType == napi_function) {
1890             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1891             break;
1892         } else {
1893             NAPI_ASSERT(env, false, "type mismatch");
1894         }
1895     }
1896     napi_get_boolean(env, true, &result);
1897     return result;
1898 }
1899 
JSIsDirectory(napi_env env,napi_callback_info info)1900 napi_value FileAssetNapi::JSIsDirectory(napi_env env, napi_callback_info info)
1901 {
1902     size_t argc = ARGS_ONE;
1903     napi_value argv[ARGS_ONE] = {0};
1904     napi_value thisVar = nullptr;
1905     napi_value resource = nullptr;
1906 
1907     MediaLibraryTracer tracer;
1908     tracer.Start("JSisDirectory");
1909 
1910     GET_JS_ARGS(env, info, argc, argv, thisVar);
1911     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 2 parameters maximum");
1912     napi_value result = nullptr;
1913     napi_get_undefined(env, &result);
1914     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
1915     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
1916     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1917     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1918         result = GetJSArgsForIsDirectory(env, argc, argv, *asyncContext);
1919         ASSERT_NULLPTR_CHECK(env, result);
1920         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
1921         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsDirectory", asyncContext);
1922         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
1923         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
1924         status = napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
1925                 FileAssetAsyncContext* context = static_cast<FileAssetAsyncContext*>(data);
1926                 context->status = false;
1927                 context->isDirectory = GetIsDirectoryiteNative(env, *context);
1928             },
1929             reinterpret_cast<CompleteCallback>(JSIsDirectoryCallbackComplete),
1930             static_cast<void *>(asyncContext.get()), &asyncContext->work);
1931         if (status != napi_ok) {
1932             napi_get_undefined(env, &result);
1933         } else {
1934             napi_queue_async_work(env, asyncContext->work);
1935             asyncContext.release();
1936         }
1937     }
1938     return result;
1939 }
1940 
JSIsFavoriteExecute(FileAssetAsyncContext * context)1941 static void JSIsFavoriteExecute(FileAssetAsyncContext* context)
1942 {
1943     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1944     context->isFavorite = context->objectPtr->IsFavorite();
1945     return;
1946 }
1947 
JSIsFavoriteCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)1948 static void JSIsFavoriteCallbackComplete(napi_env env, napi_status status,
1949                                          FileAssetAsyncContext* context)
1950 {
1951     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1952     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1953     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
1954     jsContext->status = false;
1955     if (context->error == ERR_DEFAULT) {
1956         napi_get_boolean(env, context->isFavorite, &jsContext->data);
1957         napi_get_undefined(env, &jsContext->error);
1958         jsContext->status = true;
1959     } else {
1960         NAPI_ERR_LOG("Get IsFavorite failed, ret: %{public}d", context->error);
1961         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
1962             "UserFileClient is invalid");
1963         napi_get_undefined(env, &jsContext->data);
1964     }
1965     if (context->work != nullptr) {
1966         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1967                                                    context->work, *jsContext);
1968     }
1969     delete context;
1970 }
1971 
GetJSArgsForFavorite(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)1972 napi_value GetJSArgsForFavorite(napi_env env, size_t argc, const napi_value argv[],
1973                                 FileAssetAsyncContext &asyncContext)
1974 {
1975     const int32_t refCount = 1;
1976     napi_value result = nullptr;
1977     auto context = &asyncContext;
1978     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
1979     bool isFavorite = false;
1980     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1981     for (size_t i = PARAM0; i < argc; i++) {
1982         napi_valuetype valueType = napi_undefined;
1983         napi_typeof(env, argv[i], &valueType);
1984         if (i == PARAM0 && valueType == napi_boolean) {
1985             napi_get_value_bool(env, argv[i], &isFavorite);
1986         } else if (i == PARAM1 && valueType == napi_function) {
1987             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1988             break;
1989         } else {
1990             NAPI_ASSERT(env, false, "type mismatch");
1991         }
1992     }
1993     context->isFavorite = isFavorite;
1994     napi_get_boolean(env, true, &result);
1995     return result;
1996 }
1997 
1998 #ifdef MEDIALIBRARY_COMPATIBILITY
FavoriteByUpdate(FileAssetAsyncContext * context)1999 static void FavoriteByUpdate(FileAssetAsyncContext *context)
2000 {
2001     DataShareValuesBucket valuesBucket;
2002     string uriString;
2003     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2004         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
2005         uriString = URI_UPDATE_PHOTO;
2006     } else {
2007         uriString = URI_UPDATE_AUDIO;
2008     }
2009     valuesBucket.Put(MEDIA_DATA_DB_IS_FAV, (context->isFavorite ? IS_FAV : NOT_FAV));
2010     DataSharePredicates predicates;
2011     int32_t fileId = context->objectPtr->GetId();
2012     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
2013     predicates.SetWhereArgs({ to_string(fileId) });
2014     Uri uri(uriString);
2015     context->changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
2016 }
2017 #endif
2018 
FavoriteByInsert(FileAssetAsyncContext * context)2019 static void FavoriteByInsert(FileAssetAsyncContext *context)
2020 {
2021     DataShareValuesBucket valuesBucket;
2022     string uriString = MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/";
2023     uriString += context->isFavorite ? MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM : MEDIA_SMARTALBUMMAPOPRN_REMOVESMARTALBUM;
2024     valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, FAVOURITE_ALBUM_ID_VALUES);
2025     valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, context->objectPtr->GetId());
2026     Uri uri(uriString);
2027     context->changedRows = UserFileClient::Insert(uri, valuesBucket);
2028 }
2029 
JSFavouriteExecute(napi_env env,void * data)2030 static void JSFavouriteExecute(napi_env env, void *data)
2031 {
2032     MediaLibraryTracer tracer;
2033     tracer.Start("JSFavouriteExecute");
2034 
2035     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2036     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2037 
2038 #ifdef MEDIALIBRARY_COMPATIBILITY
2039     string uriString = MEDIALIBRARY_DATA_URI + "/";
2040     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2041         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO) ||
2042         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO)) {
2043         if (MediaFileUtils::IsFileTablePath(context->objectPtr->GetPath())) {
2044             FavoriteByInsert(context);
2045         } else {
2046             FavoriteByUpdate(context);
2047         }
2048     } else {
2049         FavoriteByInsert(context);
2050     }
2051 #else
2052     FavoriteByInsert(context);
2053 #endif
2054     if (context->changedRows >= 0) {
2055         context->objectPtr->SetFavorite(context->isFavorite);
2056     }
2057     context->SaveError(context->changedRows);
2058 }
2059 
JSFavorite(napi_env env,napi_callback_info info)2060 napi_value FileAssetNapi::JSFavorite(napi_env env, napi_callback_info info)
2061 {
2062     size_t argc = ARGS_TWO;
2063     napi_value argv[ARGS_TWO] = {0};
2064     napi_value thisVar = nullptr;
2065 
2066     MediaLibraryTracer tracer;
2067     tracer.Start("JSFavorite");
2068 
2069     GET_JS_ARGS(env, info, argc, argv, thisVar);
2070     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2071     napi_value result = nullptr;
2072     napi_get_undefined(env, &result);
2073 
2074     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2075     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2076     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
2077     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2078     if ((status != napi_ok) || (asyncContext->objectInfo == nullptr)) {
2079         NAPI_DEBUG_LOG("get this Var fail");
2080         return result;
2081     }
2082 
2083     result = GetJSArgsForFavorite(env, argc, argv, *asyncContext);
2084     if (asyncContext->isFavorite == asyncContext->objectInfo->IsFavorite()) {
2085         NAPI_DEBUG_LOG("favorite state is the same");
2086         return result;
2087     }
2088     ASSERT_NULLPTR_CHECK(env, result);
2089     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2090     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2091 
2092     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSFavorite", JSFavouriteExecute,
2093         JSFavoriteCallbackComplete);
2094 }
2095 
GetJSArgsForIsFavorite(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2096 static napi_value GetJSArgsForIsFavorite(napi_env env, size_t argc, const napi_value argv[],
2097                                          FileAssetAsyncContext &asyncContext)
2098 {
2099     const int32_t refCount = 1;
2100     napi_value result;
2101     auto context = &asyncContext;
2102     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2103     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2104     for (size_t i = PARAM0; i < argc; i++) {
2105         napi_valuetype valueType = napi_undefined;
2106         napi_typeof(env, argv[i], &valueType);
2107         if (i == PARAM0 && valueType == napi_function) {
2108             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2109             break;
2110         } else {
2111             NAPI_ASSERT(env, false, "type mismatch");
2112         }
2113     }
2114     napi_get_boolean(env, true, &result);
2115     return result;
2116 }
2117 
JSIsFavorite(napi_env env,napi_callback_info info)2118 napi_value FileAssetNapi::JSIsFavorite(napi_env env, napi_callback_info info)
2119 {
2120     MediaLibraryTracer tracer;
2121     tracer.Start("JSIsFavorite");
2122 
2123     napi_status status;
2124     napi_value result = nullptr;
2125     size_t argc = ARGS_ONE;
2126     napi_value argv[ARGS_ONE] = {0};
2127     napi_value thisVar = nullptr;
2128     napi_value resource = nullptr;
2129     GET_JS_ARGS(env, info, argc, argv, thisVar);
2130     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameters maximum");
2131     napi_get_undefined(env, &result);
2132     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2133     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2134     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2135     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2136         result = GetJSArgsForIsFavorite(env, argc, argv, *asyncContext);
2137         ASSERT_NULLPTR_CHECK(env, result);
2138         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2139         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsFavorite", asyncContext);
2140         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2141         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2142 
2143         status = napi_create_async_work(
2144             env, nullptr, resource, [](napi_env env, void *data) {
2145                 auto context = static_cast<FileAssetAsyncContext*>(data);
2146                 JSIsFavoriteExecute(context);
2147             },
2148             reinterpret_cast<CompleteCallback>(JSIsFavoriteCallbackComplete),
2149             static_cast<void *>(asyncContext.get()), &asyncContext->work);
2150         if (status != napi_ok) {
2151             napi_get_undefined(env, &result);
2152         } else {
2153             napi_queue_async_work(env, asyncContext->work);
2154             asyncContext.release();
2155         }
2156     }
2157     return result;
2158 }
2159 
2160 #ifdef MEDIALIBRARY_COMPATIBILITY
TrashByUpdate(FileAssetAsyncContext * context)2161 static void TrashByUpdate(FileAssetAsyncContext *context)
2162 {
2163     DataShareValuesBucket valuesBucket;
2164     string uriString;
2165     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2166         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO)) {
2167         uriString = URI_UPDATE_PHOTO;
2168     } else {
2169         uriString = URI_UPDATE_AUDIO;
2170     }
2171     valuesBucket.Put(MEDIA_DATA_DB_DATE_TRASHED, (context->isTrash ? MediaFileUtils::UTCTimeSeconds() : NOT_TRASH));
2172     DataSharePredicates predicates;
2173     int32_t fileId = context->objectPtr->GetId();
2174     predicates.SetWhereClause(MEDIA_DATA_DB_ID + " = ? ");
2175     predicates.SetWhereArgs({ to_string(fileId) });
2176     Uri uri(uriString);
2177     context->changedRows = UserFileClient::Update(uri, predicates, valuesBucket);
2178 }
2179 #endif
2180 
TrashByInsert(FileAssetAsyncContext * context)2181 static void TrashByInsert(FileAssetAsyncContext *context)
2182 {
2183     DataShareValuesBucket valuesBucket;
2184     string uriString = MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/";
2185     uriString += context->isTrash ? MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM : MEDIA_SMARTALBUMMAPOPRN_REMOVESMARTALBUM;
2186     valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, TRASH_ALBUM_ID_VALUES);
2187     valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, context->objectPtr->GetId());
2188     Uri uri(uriString);
2189     context->changedRows = UserFileClient::Insert(uri, valuesBucket);
2190 }
2191 
JSTrashExecute(napi_env env,void * data)2192 static void JSTrashExecute(napi_env env, void *data)
2193 {
2194     MediaLibraryTracer tracer;
2195     tracer.Start("JSTrashExecute");
2196 
2197     auto *context = static_cast<FileAssetAsyncContext*>(data);
2198 
2199 #ifdef MEDIALIBRARY_COMPATIBILITY
2200     if ((context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE) ||
2201         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO) ||
2202         (context->objectPtr->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO)) {
2203         if (MediaFileUtils::IsFileTablePath(context->objectPtr->GetPath())) {
2204             TrashByInsert(context);
2205         } else {
2206             TrashByUpdate(context);
2207         }
2208     } else {
2209         TrashByInsert(context);
2210     }
2211 #else
2212     TrashByInsert(context);
2213 #endif
2214     if (context->changedRows >= 0) {
2215         int32_t trashFlag = (context->isTrash ? IS_TRASH : NOT_TRASH);
2216         context->objectPtr->SetIsTrash(trashFlag);
2217     }
2218     context->SaveError(context->changedRows);
2219 }
2220 
JSTrashCallbackComplete(napi_env env,napi_status status,void * data)2221 static void JSTrashCallbackComplete(napi_env env, napi_status status, void *data)
2222 {
2223     MediaLibraryTracer tracer;
2224     tracer.Start("JSTrashCallbackComplete");
2225 
2226     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2227     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2228     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2229     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2230     jsContext->status = false;
2231     napi_get_undefined(env, &jsContext->data);
2232     if (context->error == ERR_DEFAULT) {
2233         jsContext->status = true;
2234         Media::MediaType mediaType = context->objectPtr->GetMediaType();
2235         string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
2236         Uri modifyNotify(notifyUri);
2237         UserFileClient::NotifyChange(modifyNotify);
2238         NAPI_DEBUG_LOG("JSTrashCallbackComplete success");
2239     } else {
2240         context->HandleError(env, jsContext->error);
2241     }
2242 
2243     tracer.Finish();
2244     if (context->work != nullptr) {
2245         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2246                                                    context->work, *jsContext);
2247     }
2248 
2249     delete context;
2250 }
2251 
GetJSArgsForTrash(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2252 napi_value GetJSArgsForTrash(napi_env env, size_t argc, const napi_value argv[],
2253                              FileAssetAsyncContext &asyncContext)
2254 {
2255     const int32_t refCount = 1;
2256     napi_value result = nullptr;
2257     auto context = &asyncContext;
2258     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2259     bool isTrash = false;
2260     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2261     for (size_t i = PARAM0; i < argc; i++) {
2262         napi_valuetype valueType = napi_undefined;
2263         napi_typeof(env, argv[i], &valueType);
2264         if (i == PARAM0 && valueType == napi_boolean) {
2265             napi_get_value_bool(env, argv[i], &isTrash);
2266         } else if (i == PARAM1 && valueType == napi_function) {
2267             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2268             break;
2269         } else {
2270             NAPI_ASSERT(env, false, "type mismatch");
2271         }
2272     }
2273     context->isTrash = isTrash;
2274     napi_get_boolean(env, true, &result);
2275     return result;
2276 }
2277 
JSTrash(napi_env env,napi_callback_info info)2278 napi_value FileAssetNapi::JSTrash(napi_env env, napi_callback_info info)
2279 {
2280     napi_status status;
2281     napi_value result = nullptr;
2282     size_t argc = ARGS_TWO;
2283     napi_value argv[ARGS_TWO] = {0};
2284     napi_value thisVar = nullptr;
2285 
2286     MediaLibraryTracer tracer;
2287     tracer.Start("JSTrash");
2288 
2289     GET_JS_ARGS(env, info, argc, argv, thisVar);
2290     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameters maximum");
2291 
2292     napi_get_undefined(env, &result);
2293     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2294     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2295     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
2296     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2297     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2298         result = GetJSArgsForTrash(env, argc, argv, *asyncContext);
2299         ASSERT_NULLPTR_CHECK(env, result);
2300         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2301         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2302         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSTrash", JSTrashExecute,
2303             JSTrashCallbackComplete);
2304     }
2305     return result;
2306 }
2307 
JSIsTrashExecute(FileAssetAsyncContext * context)2308 static void JSIsTrashExecute(FileAssetAsyncContext* context)
2309 {
2310     MediaLibraryTracer tracer;
2311     tracer.Start("JSIsTrashExecute");
2312 
2313     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2314     context->isTrash = (context->objectPtr->GetIsTrash() != NOT_TRASH);
2315     return;
2316 }
2317 
JSIsTrashCallbackComplete(napi_env env,napi_status status,FileAssetAsyncContext * context)2318 static void JSIsTrashCallbackComplete(napi_env env, napi_status status,
2319                                       FileAssetAsyncContext* context)
2320 {
2321     MediaLibraryTracer tracer;
2322     tracer.Start("JSIsTrashCallbackComplete");
2323 
2324     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2325     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2326     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
2327     jsContext->status = false;
2328     if (context->error == ERR_DEFAULT) {
2329         napi_get_boolean(env, context->isTrash, &jsContext->data);
2330         napi_get_undefined(env, &jsContext->error);
2331         jsContext->status = true;
2332     } else {
2333         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
2334             "UserFileClient is invalid");
2335         napi_get_undefined(env, &jsContext->data);
2336     }
2337 
2338     tracer.Finish();
2339     if (context->work != nullptr) {
2340         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2341                                                    context->work, *jsContext);
2342     }
2343 
2344     delete context;
2345 }
2346 
GetJSArgsForIsTrash(napi_env env,size_t argc,const napi_value argv[],FileAssetAsyncContext & asyncContext)2347 static napi_value GetJSArgsForIsTrash(napi_env env, size_t argc, const napi_value argv[],
2348                                       FileAssetAsyncContext &asyncContext)
2349 {
2350     const int32_t refCount = 1;
2351     napi_value result;
2352     auto context = &asyncContext;
2353     CHECK_NULL_PTR_RETURN_UNDEFINED(env, context, result, "Async context is null");
2354     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
2355     for (size_t i = PARAM0; i < argc; i++) {
2356         napi_valuetype valueType = napi_undefined;
2357         napi_typeof(env, argv[i], &valueType);
2358         if (i == PARAM0 && valueType == napi_function) {
2359             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
2360             break;
2361         } else {
2362             NAPI_ASSERT(env, false, "type mismatch");
2363         }
2364     }
2365     napi_get_boolean(env, true, &result);
2366     return result;
2367 }
2368 
JSIsTrash(napi_env env,napi_callback_info info)2369 napi_value FileAssetNapi::JSIsTrash(napi_env env, napi_callback_info info)
2370 {
2371     napi_status status;
2372     napi_value result = nullptr;
2373     size_t argc = ARGS_ONE;
2374     napi_value argv[ARGS_ONE] = {0};
2375     napi_value thisVar = nullptr;
2376     napi_value resource = nullptr;
2377 
2378     MediaLibraryTracer tracer;
2379     tracer.Start("JSIsTrash");
2380 
2381     GET_JS_ARGS(env, info, argc, argv, thisVar);
2382     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameters maximum");
2383     napi_get_undefined(env, &result);
2384     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2385     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
2386     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
2387     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
2388         result = GetJSArgsForIsTrash(env, argc, argv, *asyncContext);
2389         ASSERT_NULLPTR_CHECK(env, result);
2390         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
2391         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSIsTrash", asyncContext);
2392         asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2393         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
2394 
2395         status = napi_create_async_work(
2396             env, nullptr, resource, [](napi_env env, void *data) {
2397                 auto context = static_cast<FileAssetAsyncContext*>(data);
2398                 JSIsTrashExecute(context);
2399             },
2400             reinterpret_cast<CompleteCallback>(JSIsTrashCallbackComplete),
2401             static_cast<void *>(asyncContext.get()), &asyncContext->work);
2402         if (status != napi_ok) {
2403             napi_get_undefined(env, &result);
2404         } else {
2405             napi_queue_async_work(env, asyncContext->work);
2406             asyncContext.release();
2407         }
2408     }
2409 
2410     return result;
2411 }
2412 
UpdateFileAssetInfo()2413 void FileAssetNapi::UpdateFileAssetInfo()
2414 {
2415     fileAssetPtr = std::shared_ptr<FileAsset>(sFileAsset_);
2416 }
2417 
UserFileMgrGet(napi_env env,napi_callback_info info)2418 napi_value FileAssetNapi::UserFileMgrGet(napi_env env, napi_callback_info info)
2419 {
2420     MediaLibraryTracer tracer;
2421     tracer.Start("UserFileMgrGet");
2422 
2423     napi_value ret = nullptr;
2424     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2425     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
2426 
2427     string inputKey;
2428     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, inputKey),
2429         JS_ERR_PARAMETER_INVALID);
2430     napi_value jsResult = nullptr;
2431     auto obj = asyncContext->objectInfo;
2432     napi_get_undefined(env, &jsResult);
2433     if (obj->fileAssetPtr->GetMemberMap().count(inputKey) == 0) {
2434         // no exist throw error
2435         NapiError::ThrowError(env, JS_E_FILE_KEY);
2436         return jsResult;
2437     }
2438     auto m = obj->fileAssetPtr->GetMemberMap().at(inputKey);
2439     if (m.index() == MEMBER_TYPE_STRING) {
2440         napi_create_string_utf8(env, get<string>(m).c_str(), NAPI_AUTO_LENGTH, &jsResult);
2441     } else if (m.index() == MEMBER_TYPE_INT32) {
2442         napi_create_int32(env, get<int32_t>(m), &jsResult);
2443     } else if (m.index() == MEMBER_TYPE_INT64) {
2444         napi_create_int64(env, get<int64_t>(m), &jsResult);
2445     } else {
2446         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2447         return jsResult;
2448     }
2449     return jsResult;
2450 }
2451 
HandleParamSet(const string & inputKey,const string & value,ResultNapiType resultNapiType)2452 bool FileAssetNapi::HandleParamSet(const string &inputKey, const string &value, ResultNapiType resultNapiType)
2453 {
2454     if (resultNapiType == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
2455         if (inputKey == MediaColumn::MEDIA_TITLE) {
2456             fileAssetPtr->SetTitle(value);
2457         } else {
2458             NAPI_ERR_LOG("invalid key %{public}s, no support key", inputKey.c_str());
2459             return false;
2460         }
2461     } else if (resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
2462         if (inputKey == MediaColumn::MEDIA_NAME) {
2463             fileAssetPtr->SetDisplayName(value);
2464             fileAssetPtr->SetTitle(MediaFileUtils::GetTitleFromDisplayName(value));
2465         } else if (inputKey == MediaColumn::MEDIA_TITLE) {
2466             fileAssetPtr->SetTitle(value);
2467             string displayName = fileAssetPtr->GetDisplayName();
2468             if (!displayName.empty()) {
2469                 string extention = MediaFileUtils::SplitByChar(displayName, '.');
2470                 fileAssetPtr->SetDisplayName(value + "." + extention);
2471             }
2472         } else {
2473             NAPI_ERR_LOG("invalid key %{public}s, no support key", inputKey.c_str());
2474             return false;
2475         }
2476     } else {
2477         NAPI_ERR_LOG("invalid resultNapiType");
2478         return false;
2479     }
2480     return true;
2481 }
2482 
UserFileMgrSet(napi_env env,napi_callback_info info)2483 napi_value FileAssetNapi::UserFileMgrSet(napi_env env, napi_callback_info info)
2484 {
2485     MediaLibraryTracer tracer;
2486     tracer.Start("UserFileMgrSet");
2487 
2488     napi_value ret = nullptr;
2489     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2490     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
2491     string inputKey;
2492     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, inputKey),
2493         JS_ERR_PARAMETER_INVALID);
2494     string value;
2495     CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, asyncContext->argv[ARGS_ONE], value),
2496         JS_ERR_PARAMETER_INVALID);
2497     napi_value jsResult = nullptr;
2498     napi_get_undefined(env, &jsResult);
2499     auto obj = asyncContext->objectInfo;
2500     if (!obj->HandleParamSet(inputKey, value, obj->fileAssetPtr->GetResultNapiType())) {
2501         NapiError::ThrowError(env, JS_E_FILE_KEY);
2502         return jsResult;
2503     }
2504     return jsResult;
2505 }
2506 
UserFileMgrCommitModify(napi_env env,napi_callback_info info)2507 napi_value FileAssetNapi::UserFileMgrCommitModify(napi_env env, napi_callback_info info)
2508 {
2509     MediaLibraryTracer tracer;
2510     tracer.Start("UserFileMgrCommitModify");
2511 
2512     napi_value ret = nullptr;
2513     auto asyncContext = make_unique<FileAssetAsyncContext>();
2514     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
2515     NAPI_ASSERT(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
2516         "Failed to parse js args");
2517     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2518     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
2519 
2520     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrCommitModify",
2521         JSCommitModifyExecute, JSCommitModifyCompleteCallback);
2522 }
2523 
UserFileMgrFavoriteComplete(napi_env env,napi_status status,void * data)2524 static void UserFileMgrFavoriteComplete(napi_env env, napi_status status, void *data)
2525 {
2526     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2527     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2528     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2529     jsContext->status = false;
2530 
2531     if (context->error == ERR_DEFAULT) {
2532         napi_create_int32(env, context->changedRows, &jsContext->data);
2533         jsContext->status = true;
2534         napi_get_undefined(env, &jsContext->error);
2535     } else {
2536         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
2537             "Failed to modify favorite state");
2538         napi_get_undefined(env, &jsContext->data);
2539     }
2540 
2541     if (context->work != nullptr) {
2542         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2543             context->work, *jsContext);
2544     }
2545     delete context;
2546 }
2547 
UserFileMgrFavoriteExecute(napi_env env,void * data)2548 static void UserFileMgrFavoriteExecute(napi_env env, void *data)
2549 {
2550     MediaLibraryTracer tracer;
2551     tracer.Start("UserFileMgrFavoriteExecute");
2552 
2553     auto *context = static_cast<FileAssetAsyncContext *>(data);
2554 
2555     string uri;
2556     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
2557         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
2558         uri = UFM_UPDATE_PHOTO;
2559     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
2560         uri = UFM_UPDATE_AUDIO;
2561     }
2562 
2563     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2564     Uri updateAssetUri(uri);
2565     DataSharePredicates predicates;
2566     DataShareValuesBucket valuesBucket;
2567     int32_t changedRows;
2568     valuesBucket.Put(MediaColumn::MEDIA_IS_FAV, context->isFavorite ? IS_FAV : NOT_FAV);
2569     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
2570     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
2571 
2572     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
2573     if (changedRows < 0) {
2574         context->SaveError(changedRows);
2575         NAPI_ERR_LOG("Failed to modify favorite state, err: %{public}d", changedRows);
2576     } else {
2577         context->objectPtr->SetFavorite(context->isFavorite);
2578         context->changedRows = changedRows;
2579     }
2580 }
2581 
UserFileMgrFavorite(napi_env env,napi_callback_info info)2582 napi_value FileAssetNapi::UserFileMgrFavorite(napi_env env, napi_callback_info info)
2583 {
2584     auto asyncContext = make_unique<FileAssetAsyncContext>();
2585     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
2586     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isFavorite),
2587         JS_ERR_PARAMETER_INVALID);
2588     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2589     CHECK_NULLPTR_RET(asyncContext->objectPtr);
2590 
2591     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrFavorite",
2592         UserFileMgrFavoriteExecute, UserFileMgrFavoriteComplete);
2593 }
UserFileMgrGetThumbnail(napi_env env,napi_callback_info info)2594 napi_value FileAssetNapi::UserFileMgrGetThumbnail(napi_env env, napi_callback_info info)
2595 {
2596     MediaLibraryTracer tracer;
2597     tracer.Start("UserFileMgrGetThumbnail");
2598 
2599     auto asyncContext = make_unique<FileAssetAsyncContext>();
2600     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_TWO),
2601         JS_INNER_FAIL);
2602     CHECK_NULLPTR_RET(GetJSArgsForGetThumbnail(env, asyncContext->argc, asyncContext->argv, asyncContext));
2603 
2604     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2605     CHECK_NULLPTR_RET(asyncContext->objectPtr);
2606     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
2607 
2608     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetThumbnail",
2609         [](napi_env env, void *data) {
2610             auto context = static_cast<FileAssetAsyncContext*>(data);
2611             JSGetThumbnailExecute(context);
2612         },
2613         reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback));
2614 }
2615 
ParseArgsUserFileMgrOpen(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context,bool isReadOnly)2616 static napi_value ParseArgsUserFileMgrOpen(napi_env env, napi_callback_info info,
2617     unique_ptr<FileAssetAsyncContext> &context, bool isReadOnly)
2618 {
2619     size_t minArgs = ARGS_ZERO;
2620     size_t maxArgs = ARGS_ONE;
2621     if (!isReadOnly) {
2622         minArgs++;
2623         maxArgs++;
2624     }
2625     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
2626         JS_ERR_PARAMETER_INVALID);
2627     auto fileUri = context->objectInfo->GetFileUri();
2628     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2629     context->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
2630 
2631     if (isReadOnly) {
2632         context->valuesBucket.Put(MEDIA_FILEMODE, MEDIA_FILEMODE_READONLY);
2633     } else {
2634         string mode;
2635         CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], mode),
2636             JS_ERR_PARAMETER_INVALID);
2637         transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
2638         if (!MediaFileUtils::CheckMode(mode)) {
2639             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2640             return nullptr;
2641         }
2642         context->valuesBucket.Put(MEDIA_FILEMODE, mode);
2643     }
2644 
2645     napi_value result = nullptr;
2646     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
2647     return result;
2648 }
2649 
UserFileMgrOpenExecute(napi_env env,void * data)2650 static void UserFileMgrOpenExecute(napi_env env, void *data)
2651 {
2652     MediaLibraryTracer tracer;
2653     tracer.Start("JSOpenExecute");
2654 
2655     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2656     bool isValid = false;
2657     string mode = context->valuesBucket.Get(MEDIA_FILEMODE, isValid);
2658     if (!isValid) {
2659         context->SaveError(-EINVAL);
2660         return;
2661     }
2662     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
2663     if (!isValid) {
2664         context->SaveError(-EINVAL);
2665         return ;
2666     }
2667 
2668     MediaFileUtils::UriAppendKeyValue(fileUri, MediaColumn::MEDIA_TIME_PENDING,
2669         to_string(context->objectPtr->GetTimePending()));
2670     Uri openFileUri(fileUri);
2671     int32_t retVal = UserFileClient::OpenFile(openFileUri, mode);
2672     if (retVal <= 0) {
2673         context->SaveError(retVal);
2674         NAPI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
2675     } else {
2676         context->fd = retVal;
2677         if (mode.find('w') != string::npos) {
2678             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
2679         } else {
2680             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
2681         }
2682         if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
2683             context->objectPtr->SetTimePending(UNCLOSE_FILE_TIMEPENDING);
2684         }
2685     }
2686 }
2687 
UserFileMgrOpenCallbackComplete(napi_env env,napi_status status,void * data)2688 static void UserFileMgrOpenCallbackComplete(napi_env env, napi_status status, void *data)
2689 {
2690     MediaLibraryTracer tracer;
2691     tracer.Start("UserFileMgrOpenCallbackComplete");
2692 
2693     auto *context = static_cast<FileAssetAsyncContext *>(data);
2694     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2695 
2696     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2697     jsContext->status = false;
2698 
2699     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
2700     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
2701     if (context->error == ERR_DEFAULT) {
2702         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->fd, &jsContext->data), JS_INNER_FAIL);
2703         jsContext->status = true;
2704     } else {
2705         context->HandleError(env, jsContext->error);
2706     }
2707 
2708     tracer.Finish();
2709     if (context->work != nullptr) {
2710         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2711                                                    context->work, *jsContext);
2712     }
2713     delete context;
2714 }
2715 
UserFileMgrOpen(napi_env env,napi_callback_info info)2716 napi_value FileAssetNapi::UserFileMgrOpen(napi_env env, napi_callback_info info)
2717 {
2718     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2719     CHECK_NULLPTR_RET(ParseArgsUserFileMgrOpen(env, info, asyncContext, false));
2720     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
2721         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2722         return nullptr;
2723     }
2724     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2725 
2726     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrOpen",
2727         UserFileMgrOpenExecute, UserFileMgrOpenCallbackComplete);
2728 }
2729 
JSGetReadOnlyFd(napi_env env,napi_callback_info info)2730 napi_value FileAssetNapi::JSGetReadOnlyFd(napi_env env, napi_callback_info info)
2731 {
2732     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2733     CHECK_NULLPTR_RET(ParseArgsUserFileMgrOpen(env, info, asyncContext, true));
2734     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
2735         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2736         return nullptr;
2737     }
2738     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2739 
2740     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets", UserFileMgrOpenExecute,
2741         UserFileMgrOpenCallbackComplete);
2742 }
2743 
ParseArgsUserFileMgrClose(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context)2744 static napi_value ParseArgsUserFileMgrClose(napi_env env, napi_callback_info info,
2745     unique_ptr<FileAssetAsyncContext> &context)
2746 {
2747     size_t minArgs = ARGS_ONE;
2748     size_t maxArgs = ARGS_TWO;
2749     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
2750         JS_ERR_PARAMETER_INVALID);
2751     context->valuesBucket.Put(MEDIA_DATA_DB_URI, context->objectInfo->GetFileUri());
2752 
2753     int32_t fd = 0;
2754     CHECK_COND(env, MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], fd), JS_ERR_PARAMETER_INVALID);
2755     if (fd <= 0) {
2756         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2757         return nullptr;
2758     }
2759     context->fd = fd;
2760 
2761     napi_value result = nullptr;
2762     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
2763     return result;
2764 }
2765 
UserFileMgrCloseExecute(napi_env env,void * data)2766 static void UserFileMgrCloseExecute(napi_env env, void *data)
2767 {
2768     MediaLibraryTracer tracer;
2769     tracer.Start("UserFileMgrCloseExecute");
2770 
2771     auto *context = static_cast<FileAssetAsyncContext*>(data);
2772     UniqueFd unifd(context->fd);
2773     if (!CheckFileOpenStatus(context, unifd.Get())) {
2774         return;
2775     }
2776     string closeUri;
2777     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
2778         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
2779         closeUri = UFM_CLOSE_PHOTO;
2780     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
2781         closeUri = UFM_CLOSE_AUDIO;
2782     } else {
2783         context->SaveError(-EINVAL);
2784         return;
2785     }
2786     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2787     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, MediaColumn::MEDIA_TIME_PENDING,
2788         to_string(context->objectPtr->GetTimePending()));
2789     Uri closeAssetUri(closeUri);
2790     int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
2791     if (ret != E_SUCCESS) {
2792         context->SaveError(ret);
2793     } else {
2794         if (context->objectPtr->GetTimePending() == UNCLOSE_FILE_TIMEPENDING) {
2795             context->objectPtr->SetTimePending(0);
2796         }
2797     }
2798 }
2799 
UserFileMgrCloseCallbackComplete(napi_env env,napi_status status,void * data)2800 static void UserFileMgrCloseCallbackComplete(napi_env env, napi_status status, void *data)
2801 {
2802     MediaLibraryTracer tracer;
2803     tracer.Start("UserFileMgrCloseCallbackComplete");
2804 
2805     auto context = static_cast<FileAssetAsyncContext *>(data);
2806     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2807 
2808     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2809     jsContext->status = false;
2810 
2811     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
2812     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
2813     if (context->error == ERR_DEFAULT) {
2814         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, E_SUCCESS, &jsContext->data), JS_INNER_FAIL);
2815         jsContext->status = true;
2816     } else {
2817         context->HandleError(env, jsContext->error);
2818     }
2819 
2820     tracer.Finish();
2821     if (context->work != nullptr) {
2822         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2823                                                    context->work, *jsContext);
2824     }
2825     delete context;
2826 }
2827 
UserFileMgrClose(napi_env env,napi_callback_info info)2828 napi_value FileAssetNapi::UserFileMgrClose(napi_env env, napi_callback_info info)
2829 {
2830     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2831     CHECK_NULLPTR_RET(ParseArgsUserFileMgrClose(env, info, asyncContext));
2832     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
2833         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
2834         return nullptr;
2835     }
2836     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2837 
2838     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets", UserFileMgrCloseExecute,
2839         UserFileMgrCloseCallbackComplete);
2840 }
2841 
UserFileMgrSetHiddenExecute(napi_env env,void * data)2842 static void UserFileMgrSetHiddenExecute(napi_env env, void *data)
2843 {
2844     MediaLibraryTracer tracer;
2845     tracer.Start("UserFileMgrSetHiddenExecute");
2846 
2847     auto *context = static_cast<FileAssetAsyncContext *>(data);
2848     if (context->objectPtr->GetMediaType() != MEDIA_TYPE_IMAGE &&
2849         context->objectPtr->GetMediaType() != MEDIA_TYPE_VIDEO) {
2850         context->SaveError(-EINVAL);
2851         return;
2852     }
2853 
2854     string uri = UFM_UPDATE_PHOTO;
2855     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2856     Uri updateAssetUri(uri);
2857     DataSharePredicates predicates;
2858     DataShareValuesBucket valuesBucket;
2859     int32_t changedRows;
2860     valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, context->isHidden ? IS_HIDDEN : NOT_HIDDEN);
2861     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
2862     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
2863 
2864     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
2865     if (changedRows < 0) {
2866         context->SaveError(changedRows);
2867         NAPI_ERR_LOG("Failed to modify hidden state, err: %{public}d", changedRows);
2868     } else {
2869         context->objectPtr->SetHidden(context->isHidden);
2870         context->changedRows = changedRows;
2871     }
2872 }
2873 
UserFileMgrSetHiddenComplete(napi_env env,napi_status status,void * data)2874 static void UserFileMgrSetHiddenComplete(napi_env env, napi_status status, void *data)
2875 {
2876     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2877     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2878     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2879     jsContext->status = false;
2880 
2881     if (context->error == ERR_DEFAULT) {
2882         napi_create_int32(env, context->changedRows, &jsContext->data);
2883         jsContext->status = true;
2884         napi_get_undefined(env, &jsContext->error);
2885     } else {
2886         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
2887             "Failed to modify hidden state");
2888         napi_get_undefined(env, &jsContext->data);
2889     }
2890 
2891     if (context->work != nullptr) {
2892         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2893             context->work, *jsContext);
2894     }
2895     delete context;
2896 }
2897 
UserFileMgrSetHidden(napi_env env,napi_callback_info info)2898 napi_value FileAssetNapi::UserFileMgrSetHidden(napi_env env, napi_callback_info info)
2899 {
2900     MediaLibraryTracer tracer;
2901     tracer.Start("UserFileMgrSetHidden");
2902 
2903     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2904     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
2905     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isHidden),
2906         JS_ERR_PARAMETER_INVALID);
2907     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2908     CHECK_NULLPTR_RET(asyncContext->objectPtr);
2909 
2910     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetHidden",
2911         UserFileMgrSetHiddenExecute, UserFileMgrSetHiddenComplete);
2912 }
2913 
UserFileMgrSetPendingExecute(napi_env env,void * data)2914 static void UserFileMgrSetPendingExecute(napi_env env, void *data)
2915 {
2916     MediaLibraryTracer tracer;
2917     tracer.Start("UserFileMgrSetPendingExecute");
2918     auto *context = static_cast<FileAssetAsyncContext*>(data);
2919 
2920     string uri = MEDIALIBRARY_DATA_URI + "/";
2921     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
2922         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
2923         uri += UFM_PHOTO + "/" + OPRN_PENDING;
2924     } else if (context->objectPtr->GetMediaType() == MEDIA_TYPE_AUDIO) {
2925         uri += UFM_AUDIO + "/" + OPRN_PENDING;
2926     } else {
2927         context->SaveError(-EINVAL);
2928         return;
2929     }
2930 
2931     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
2932     Uri updateAssetUri(uri);
2933     DataSharePredicates predicates;
2934     DataShareValuesBucket valuesBucket;
2935     int32_t changedRows;
2936     valuesBucket.Put(MediaColumn::MEDIA_TIME_PENDING, context->isPending ? 1 : 0);
2937     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
2938     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
2939 
2940     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
2941     if (changedRows < 0) {
2942         context->SaveError(changedRows);
2943         NAPI_ERR_LOG("Failed to modify pending state, err: %{public}d", changedRows);
2944     } else {
2945         context->changedRows = changedRows;
2946         context->objectPtr->SetTimePending((context->isPending) ? 1 : 0);
2947     }
2948 }
2949 
UserFileMgrSetPendingComplete(napi_env env,napi_status status,void * data)2950 static void UserFileMgrSetPendingComplete(napi_env env, napi_status status, void *data)
2951 {
2952     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
2953     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2954     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
2955     jsContext->status = false;
2956 
2957     if (context->error == ERR_DEFAULT) {
2958         napi_create_int32(env, context->changedRows, &jsContext->data);
2959         jsContext->status = true;
2960         napi_get_undefined(env, &jsContext->error);
2961     } else {
2962         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
2963             "Failed to modify pending state");
2964         napi_get_undefined(env, &jsContext->data);
2965     }
2966 
2967     if (context->work != nullptr) {
2968         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2969             context->work, *jsContext);
2970     }
2971     delete context;
2972 }
2973 
UserFileMgrSetPending(napi_env env,napi_callback_info info)2974 napi_value FileAssetNapi::UserFileMgrSetPending(napi_env env, napi_callback_info info)
2975 {
2976     MediaLibraryTracer tracer;
2977     tracer.Start("UserFileMgrSetPending");
2978 
2979     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
2980     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
2981     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isPending),
2982         JS_ERR_PARAMETER_INVALID);
2983     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
2984     CHECK_NULLPTR_RET(asyncContext->objectPtr);
2985 
2986     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetPending",
2987         UserFileMgrSetPendingExecute, UserFileMgrSetPendingComplete);
2988 }
2989 
UserFileMgrGetExifExecute(napi_env env,void * data)2990 static void UserFileMgrGetExifExecute(napi_env env, void *data) {}
2991 
UserFileMgrGetExifComplete(napi_env env,napi_status status,void * data)2992 static void UserFileMgrGetExifComplete(napi_env env, napi_status status, void *data)
2993 {
2994     auto *context = static_cast<FileAssetAsyncContext*>(data);
2995     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
2996     auto jsContext = make_unique<JSAsyncContextOutput>();
2997     jsContext->status = false;
2998 
2999     auto *obj = context->objectInfo;
3000     nlohmann::json allExifJson;
3001     if (!obj->GetAllExif().empty()) {
3002         allExifJson = nlohmann::json::parse(obj->GetAllExif());
3003     }
3004     if (allExifJson.is_discarded() || obj->GetAllExif().empty()) {
3005         NAPI_ERR_LOG("parse json failed");
3006         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, JS_INNER_FAIL,
3007             "parse json failed");
3008         napi_get_undefined(env, &jsContext->data);
3009     } else {
3010         auto err = PermissionUtils::CheckNapiCallerPermission(PERMISSION_NAME_MEDIA_LOCATION);
3011         if (err == false) {
3012             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LATITUDE);
3013             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LONGITUDE);
3014             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LATITUDE_REF);
3015             allExifJson.erase(PHOTO_DATA_IMAGE_GPS_LONGITUDE_REF);
3016         }
3017         allExifJson[PHOTO_DATA_IMAGE_USER_COMMENT] = obj->GetUserComment();
3018         napi_create_string_utf8(env, allExifJson.dump().c_str(), NAPI_AUTO_LENGTH, &jsContext->data);
3019         jsContext->status = true;
3020         napi_get_undefined(env, &jsContext->error);
3021     }
3022 
3023     if (context->work != nullptr) {
3024         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3025             context->work, *jsContext);
3026     }
3027     delete context;
3028 }
3029 
JSGetExif(napi_env env,napi_callback_info info)3030 napi_value FileAssetNapi::JSGetExif(napi_env env, napi_callback_info info)
3031 {
3032     MediaLibraryTracer tracer;
3033     tracer.Start("JSGetExif");
3034     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3035     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_ONE),
3036         JS_ERR_PARAMETER_INVALID);
3037     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3038     CHECK_NULLPTR_RET(asyncContext->objectPtr);
3039 
3040     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetExif", UserFileMgrGetExifExecute,
3041         UserFileMgrGetExifComplete);
3042 }
3043 
UserFileMgrSetUserCommentComplete(napi_env env,napi_status status,void * data)3044 static void UserFileMgrSetUserCommentComplete(napi_env env, napi_status status, void *data)
3045 {
3046     auto *context = static_cast<FileAssetAsyncContext*>(data);
3047     auto jsContext = make_unique<JSAsyncContextOutput>();
3048     jsContext->status = false;
3049 
3050     if (context->error == ERR_DEFAULT) {
3051         napi_create_int32(env, context->changedRows, &jsContext->data);
3052         jsContext->status = true;
3053         napi_get_undefined(env, &jsContext->error);
3054     } else {
3055         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3056             "Failed to edit user comment");
3057         napi_get_undefined(env, &jsContext->data);
3058     }
3059 
3060     if (context->work != nullptr) {
3061         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3062             context->work, *jsContext);
3063     }
3064     delete context;
3065 }
3066 
UserFileMgrSetUserCommentExecute(napi_env env,void * data)3067 static void UserFileMgrSetUserCommentExecute(napi_env env, void *data)
3068 {
3069     MediaLibraryTracer tracer;
3070     tracer.Start("UserFileMgrSetUserCommentExecute");
3071 
3072     auto *context = static_cast<FileAssetAsyncContext *>(data);
3073     string uri = UFM_SET_USER_COMMENT;
3074     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3075     Uri editUserCommentUri(uri);
3076     DataSharePredicates predicates;
3077     DataShareValuesBucket valuesBucket;
3078     valuesBucket.Put(PhotoColumn::PHOTO_USER_COMMENT, context->userComment);
3079     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3080     predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
3081     int32_t changedRows = UserFileClient::Update(editUserCommentUri, predicates, valuesBucket);
3082     if (changedRows < 0) {
3083         context->SaveError(changedRows);
3084         NAPI_ERR_LOG("Failed to modify user comment, err: %{public}d", changedRows);
3085     } else {
3086         context->objectPtr->SetUserComment(context->userComment);
3087         context->changedRows = changedRows;
3088     }
3089 }
3090 
UserFileMgrSetUserComment(napi_env env,napi_callback_info info)3091 napi_value FileAssetNapi::UserFileMgrSetUserComment(napi_env env, napi_callback_info info)
3092 {
3093     MediaLibraryTracer tracer;
3094     tracer.Start("UserFileMgrSetUserComment");
3095 
3096     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3097     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
3098     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->userComment),
3099         JS_ERR_PARAMETER_INVALID);
3100     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3101     if (asyncContext->objectPtr == nullptr) {
3102         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3103         return nullptr;
3104     }
3105 
3106     if (asyncContext->userComment.length() > USER_COMMENT_MAX_LEN) {
3107         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "user comment too long");
3108         return nullptr;
3109     }
3110 
3111     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrSetUserComment",
3112         UserFileMgrSetUserCommentExecute, UserFileMgrSetUserCommentComplete);
3113 }
3114 
ParseArgsPhotoAccessHelperOpen(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context,bool isReadOnly)3115 static napi_value ParseArgsPhotoAccessHelperOpen(napi_env env, napi_callback_info info,
3116     unique_ptr<FileAssetAsyncContext> &context, bool isReadOnly)
3117 {
3118     size_t minArgs = ARGS_ZERO;
3119     size_t maxArgs = ARGS_ONE;
3120     if (!isReadOnly) {
3121         minArgs++;
3122         maxArgs++;
3123     }
3124     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3125         JS_ERR_PARAMETER_INVALID);
3126     auto fileUri = context->objectInfo->GetFileUri();
3127     MediaLibraryNapiUtils::UriAppendKeyValue(fileUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3128     context->valuesBucket.Put(MEDIA_DATA_DB_URI, fileUri);
3129 
3130     if (isReadOnly) {
3131         context->valuesBucket.Put(MEDIA_FILEMODE, MEDIA_FILEMODE_READONLY);
3132     } else {
3133         string mode;
3134         CHECK_ARGS(env, MediaLibraryNapiUtils::GetParamStringPathMax(env, context->argv[PARAM0], mode),
3135             JS_ERR_PARAMETER_INVALID);
3136         transform(mode.begin(), mode.end(), mode.begin(), ::tolower);
3137         if (!MediaFileUtils::CheckMode(mode)) {
3138             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3139             return nullptr;
3140         }
3141         context->valuesBucket.Put(MEDIA_FILEMODE, mode);
3142     }
3143 
3144     napi_value result = nullptr;
3145     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3146     return result;
3147 }
3148 
PhotoAccessHelperOpenExecute(napi_env env,void * data)3149 static void PhotoAccessHelperOpenExecute(napi_env env, void *data)
3150 {
3151     MediaLibraryTracer tracer;
3152     tracer.Start("PhotoAccessHelperOpenExecute");
3153 
3154     auto *context = static_cast<FileAssetAsyncContext*>(data);
3155     bool isValid = false;
3156     string mode = context->valuesBucket.Get(MEDIA_FILEMODE, isValid);
3157     if (!isValid) {
3158         context->SaveError(-EINVAL);
3159         return;
3160     }
3161     string fileUri = context->valuesBucket.Get(MEDIA_DATA_DB_URI, isValid);
3162     if (!isValid) {
3163         context->SaveError(-EINVAL);
3164         return ;
3165     }
3166 
3167     if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
3168         MediaFileUtils::UriAppendKeyValue(fileUri, MediaColumn::MEDIA_TIME_PENDING,
3169             to_string(context->objectPtr->GetTimePending()));
3170     }
3171     Uri openFileUri(fileUri);
3172     int32_t retVal = UserFileClient::OpenFile(openFileUri, mode);
3173     if (retVal <= 0) {
3174         context->SaveError(retVal);
3175         NAPI_ERR_LOG("File open asset failed, ret: %{public}d", retVal);
3176     } else {
3177         context->fd = retVal;
3178         if (mode.find('w') != string::npos) {
3179             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_WRITE);
3180         } else {
3181             context->objectPtr->SetOpenStatus(retVal, OPEN_TYPE_READONLY);
3182         }
3183         if (context->objectPtr->GetTimePending() == UNCREATE_FILE_TIMEPENDING) {
3184             context->objectPtr->SetTimePending(UNCLOSE_FILE_TIMEPENDING);
3185         }
3186     }
3187 }
3188 
PhotoAccessHelperOpenCallbackComplete(napi_env env,napi_status status,void * data)3189 static void PhotoAccessHelperOpenCallbackComplete(napi_env env, napi_status status, void *data)
3190 {
3191     MediaLibraryTracer tracer;
3192     tracer.Start("PhotoAccessHelperOpenCallbackComplete");
3193 
3194     auto context = static_cast<FileAssetAsyncContext *>(data);
3195     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3196 
3197     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3198     jsContext->status = false;
3199 
3200     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3201     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3202     if (context->error == ERR_DEFAULT) {
3203         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, context->fd, &jsContext->data), JS_INNER_FAIL);
3204         jsContext->status = true;
3205     } else {
3206         context->HandleError(env, jsContext->error);
3207     }
3208 
3209     tracer.Finish();
3210     if (context->work != nullptr) {
3211         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3212                                                    context->work, *jsContext);
3213     }
3214     delete context;
3215 }
3216 
PhotoAccessHelperOpen(napi_env env,napi_callback_info info)3217 napi_value FileAssetNapi::PhotoAccessHelperOpen(napi_env env, napi_callback_info info)
3218 {
3219     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3220     CHECK_NULLPTR_RET(ParseArgsPhotoAccessHelperOpen(env, info, asyncContext, false));
3221     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3222         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3223         return nullptr;
3224     }
3225     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3226 
3227     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperOpen",
3228         PhotoAccessHelperOpenExecute, PhotoAccessHelperOpenCallbackComplete);
3229 }
3230 
ParseArgsPhotoAccessHelperClose(napi_env env,napi_callback_info info,unique_ptr<FileAssetAsyncContext> & context)3231 static napi_value ParseArgsPhotoAccessHelperClose(napi_env env, napi_callback_info info,
3232     unique_ptr<FileAssetAsyncContext> &context)
3233 {
3234     size_t minArgs = ARGS_ONE;
3235     size_t maxArgs = ARGS_TWO;
3236     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
3237         JS_ERR_PARAMETER_INVALID);
3238     context->valuesBucket.Put(MEDIA_DATA_DB_URI, context->objectInfo->GetFileUri());
3239 
3240     int32_t fd = 0;
3241     CHECK_COND(env, MediaLibraryNapiUtils::GetInt32Arg(env, context->argv[PARAM0], fd), JS_ERR_PARAMETER_INVALID);
3242     if (fd <= 0) {
3243         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3244         return nullptr;
3245     }
3246     context->fd = fd;
3247 
3248     napi_value result = nullptr;
3249     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
3250     return result;
3251 }
3252 
PhotoAccessHelperCloseExecute(napi_env env,void * data)3253 static void PhotoAccessHelperCloseExecute(napi_env env, void *data)
3254 {
3255     MediaLibraryTracer tracer;
3256     tracer.Start("PhotoAccessHelperCloseExecute");
3257 
3258     auto *context = static_cast<FileAssetAsyncContext*>(data);
3259     UniqueFd unifd(context->fd);
3260     if (!CheckFileOpenStatus(context, unifd.Get())) {
3261         return;
3262     }
3263     string closeUri;
3264     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3265         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3266         closeUri = PAH_CLOSE_PHOTO;
3267     } else {
3268         context->SaveError(-EINVAL);
3269         return;
3270     }
3271     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3272     MediaLibraryNapiUtils::UriAppendKeyValue(closeUri, MediaColumn::MEDIA_TIME_PENDING,
3273         to_string(context->objectPtr->GetTimePending()));
3274     Uri closeAssetUri(closeUri);
3275     int32_t ret = UserFileClient::Insert(closeAssetUri, context->valuesBucket);
3276     if (ret != E_SUCCESS) {
3277         context->SaveError(ret);
3278     } else {
3279         if (context->objectPtr->GetTimePending() == UNCLOSE_FILE_TIMEPENDING) {
3280             context->objectPtr->SetTimePending(0);
3281         }
3282     }
3283 }
3284 
PhotoAccessHelperCloseCallbackComplete(napi_env env,napi_status status,void * data)3285 static void PhotoAccessHelperCloseCallbackComplete(napi_env env, napi_status status, void *data)
3286 {
3287     MediaLibraryTracer tracer;
3288     tracer.Start("PhotoAccessHelperCloseCallbackComplete");
3289 
3290     auto context = static_cast<FileAssetAsyncContext *>(data);
3291     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3292 
3293     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3294     jsContext->status = false;
3295 
3296     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
3297     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
3298     if (context->error == ERR_DEFAULT) {
3299         CHECK_ARGS_RET_VOID(env, napi_create_int32(env, E_SUCCESS, &jsContext->data), JS_INNER_FAIL);
3300         jsContext->status = true;
3301     } else {
3302         context->HandleError(env, jsContext->error);
3303     }
3304 
3305     tracer.Finish();
3306     if (context->work != nullptr) {
3307         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3308                                                    context->work, *jsContext);
3309     }
3310     delete context;
3311 }
3312 
PhotoAccessHelperClose(napi_env env,napi_callback_info info)3313 napi_value FileAssetNapi::PhotoAccessHelperClose(napi_env env, napi_callback_info info)
3314 {
3315     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3316     CHECK_NULLPTR_RET(ParseArgsPhotoAccessHelperClose(env, info, asyncContext));
3317     if (asyncContext->objectInfo->fileAssetPtr == nullptr) {
3318         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3319         return nullptr;
3320     }
3321     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3322 
3323     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperClose",
3324         PhotoAccessHelperCloseExecute, PhotoAccessHelperCloseCallbackComplete);
3325 }
3326 
PhotoAccessHelperCommitModify(napi_env env,napi_callback_info info)3327 napi_value FileAssetNapi::PhotoAccessHelperCommitModify(napi_env env, napi_callback_info info)
3328 {
3329     MediaLibraryTracer tracer;
3330     tracer.Start("PhotoAccessHelperCommitModify");
3331 
3332     napi_value ret = nullptr;
3333     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3334     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3335     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
3336     NAPI_ASSERT(env, MediaLibraryNapiUtils::ParseArgsOnlyCallBack(env, info, asyncContext) == napi_ok,
3337         "Failed to parse js args");
3338     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3339     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
3340 
3341     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperCommitModify",
3342         JSCommitModifyExecute, JSCommitModifyCompleteCallback);
3343 }
3344 
PhotoAccessHelperFavoriteComplete(napi_env env,napi_status status,void * data)3345 static void PhotoAccessHelperFavoriteComplete(napi_env env, napi_status status, void *data)
3346 {
3347     FileAssetAsyncContext *context = static_cast<FileAssetAsyncContext*>(data);
3348     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3349     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3350     jsContext->status = false;
3351 
3352     if (context->error == ERR_DEFAULT) {
3353         napi_create_int32(env, context->changedRows, &jsContext->data);
3354         jsContext->status = true;
3355         napi_get_undefined(env, &jsContext->error);
3356     } else {
3357         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3358             "Failed to modify favorite state");
3359         napi_get_undefined(env, &jsContext->data);
3360     }
3361 
3362     if (context->work != nullptr) {
3363         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3364             context->work, *jsContext);
3365     }
3366     delete context;
3367 }
3368 
PhotoAccessHelperFavoriteExecute(napi_env env,void * data)3369 static void PhotoAccessHelperFavoriteExecute(napi_env env, void *data)
3370 {
3371     MediaLibraryTracer tracer;
3372     tracer.Start("PhotoAccessHelperFavoriteExecute");
3373 
3374     auto *context = static_cast<FileAssetAsyncContext *>(data);
3375     string uri;
3376     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3377         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3378         uri = PAH_UPDATE_PHOTO;
3379     } else {
3380         context->SaveError(-EINVAL);
3381         return;
3382     }
3383 
3384     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3385     Uri updateAssetUri(uri);
3386     DataSharePredicates predicates;
3387     DataShareValuesBucket valuesBucket;
3388     int32_t changedRows = 0;
3389     valuesBucket.Put(MediaColumn::MEDIA_IS_FAV, context->isFavorite ? IS_FAV : NOT_FAV);
3390     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3391     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
3392 
3393     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3394     if (changedRows < 0) {
3395         context->SaveError(changedRows);
3396         NAPI_ERR_LOG("Failed to modify favorite state, err: %{public}d", changedRows);
3397     } else {
3398         context->objectPtr->SetFavorite(context->isFavorite);
3399         context->changedRows = changedRows;
3400     }
3401 }
3402 
PhotoAccessHelperFavorite(napi_env env,napi_callback_info info)3403 napi_value FileAssetNapi::PhotoAccessHelperFavorite(napi_env env, napi_callback_info info)
3404 {
3405     MediaLibraryTracer tracer;
3406     tracer.Start("PhotoAccessHelperFavorite");
3407 
3408     napi_value ret = nullptr;
3409     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3410     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3411     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
3412     NAPI_ASSERT(
3413         env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isFavorite) == napi_ok,
3414         "Failed to parse js args");
3415     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3416     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
3417 
3418     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperFavorite",
3419         PhotoAccessHelperFavoriteExecute, PhotoAccessHelperFavoriteComplete);
3420 }
3421 
PhotoAccessHelperGetThumbnail(napi_env env,napi_callback_info info)3422 napi_value FileAssetNapi::PhotoAccessHelperGetThumbnail(napi_env env, napi_callback_info info)
3423 {
3424     MediaLibraryTracer tracer;
3425     tracer.Start("PhotoAccessHelperGetThumbnail");
3426 
3427     napi_value result = nullptr;
3428     NAPI_CALL(env, napi_get_undefined(env, &result));
3429     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3430     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, result, "asyncContext context is null");
3431 
3432     CHECK_COND_RET(MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, ARGS_ZERO, ARGS_TWO) ==
3433         napi_ok, result, "Failed to get object info");
3434     result = GetJSArgsForGetThumbnail(env, asyncContext->argc, asyncContext->argv, asyncContext);
3435     ASSERT_NULLPTR_CHECK(env, result);
3436     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3437     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "FileAsset is nullptr");
3438     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
3439     result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperGetThumbnail",
3440         [](napi_env env, void *data) {
3441             auto context = static_cast<FileAssetAsyncContext*>(data);
3442             JSGetThumbnailExecute(context);
3443         },
3444         reinterpret_cast<CompleteCallback>(JSGetThumbnailCompleteCallback));
3445 
3446     return result;
3447 }
3448 
PhotoAccessHelperSetHiddenExecute(napi_env env,void * data)3449 static void PhotoAccessHelperSetHiddenExecute(napi_env env, void *data)
3450 {
3451     MediaLibraryTracer tracer;
3452     tracer.Start("PhotoAccessHelperSetHiddenExecute");
3453 
3454     auto *context = static_cast<FileAssetAsyncContext *>(data);
3455     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3456     if (context->objectPtr->GetMediaType() != MEDIA_TYPE_IMAGE &&
3457         context->objectPtr->GetMediaType() != MEDIA_TYPE_VIDEO) {
3458         context->SaveError(-EINVAL);
3459         return;
3460     }
3461 
3462     string uri = PAH_UPDATE_PHOTO;
3463     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3464     Uri updateAssetUri(uri);
3465     DataSharePredicates predicates;
3466     DataShareValuesBucket valuesBucket;
3467     int32_t changedRows = 0;
3468     valuesBucket.Put(MediaColumn::MEDIA_HIDDEN, context->isHidden ? IS_HIDDEN : NOT_HIDDEN);
3469     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3470     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
3471 
3472     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3473     if (changedRows < 0) {
3474         context->SaveError(changedRows);
3475         NAPI_ERR_LOG("Failed to modify hidden state, err: %{public}d", changedRows);
3476     } else {
3477         context->objectPtr->SetHidden(context->isHidden);
3478         context->changedRows = changedRows;
3479     }
3480 }
3481 
PhotoAccessHelperSetHiddenComplete(napi_env env,napi_status status,void * data)3482 static void PhotoAccessHelperSetHiddenComplete(napi_env env, napi_status status, void *data)
3483 {
3484     auto *context = static_cast<FileAssetAsyncContext*>(data);
3485     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3486     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3487     jsContext->status = false;
3488 
3489     if (context->error == ERR_DEFAULT) {
3490         napi_create_int32(env, context->changedRows, &jsContext->data);
3491         jsContext->status = true;
3492         napi_get_undefined(env, &jsContext->error);
3493     } else {
3494         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3495             "Failed to modify hidden state");
3496         napi_get_undefined(env, &jsContext->data);
3497     }
3498 
3499     if (context->work != nullptr) {
3500         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3501             context->work, *jsContext);
3502     }
3503     delete context;
3504 }
3505 
PhotoAccessHelperSetHidden(napi_env env,napi_callback_info info)3506 napi_value FileAssetNapi::PhotoAccessHelperSetHidden(napi_env env, napi_callback_info info)
3507 {
3508     MediaLibraryTracer tracer;
3509     tracer.Start("PhotoAccessHelperSetHidden");
3510 
3511     napi_value ret = nullptr;
3512     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3513     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3514     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
3515     NAPI_ASSERT(
3516         env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isHidden) == napi_ok,
3517         "Failed to parse js args");
3518     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3519     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
3520 
3521     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetHidden",
3522         PhotoAccessHelperSetHiddenExecute, PhotoAccessHelperSetHiddenComplete);
3523 }
3524 
PhotoAccessHelperSetPendingExecute(napi_env env,void * data)3525 static void PhotoAccessHelperSetPendingExecute(napi_env env, void *data)
3526 {
3527     MediaLibraryTracer tracer;
3528     tracer.Start("PhotoAccessHelperSetPendingExecute");
3529 
3530     auto *context = static_cast<FileAssetAsyncContext *>(data);
3531     string uri = MEDIALIBRARY_DATA_URI + "/";
3532     if (context->objectPtr->GetMediaType() == MEDIA_TYPE_IMAGE ||
3533         context->objectPtr->GetMediaType() == MEDIA_TYPE_VIDEO) {
3534         uri += PAH_PHOTO + "/" + OPRN_PENDING;
3535     } else {
3536         context->SaveError(-EINVAL);
3537         return;
3538     }
3539 
3540     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3541     Uri updateAssetUri(uri);
3542     DataSharePredicates predicates;
3543     DataShareValuesBucket valuesBucket;
3544     int32_t changedRows = 0;
3545     valuesBucket.Put(MediaColumn::MEDIA_TIME_PENDING, context->isPending ? 1 : 0);
3546     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3547     predicates.SetWhereArgs({ std::to_string(context->objectPtr->GetId()) });
3548 
3549     changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
3550     if (changedRows < 0) {
3551         context->SaveError(changedRows);
3552         NAPI_ERR_LOG("Failed to modify pending state, err: %{public}d", changedRows);
3553     } else {
3554         context->changedRows = changedRows;
3555         context->objectPtr->SetTimePending((context->isPending) ? 1 : 0);
3556     }
3557 }
3558 
PhotoAccessHelperSetPendingComplete(napi_env env,napi_status status,void * data)3559 static void PhotoAccessHelperSetPendingComplete(napi_env env, napi_status status, void *data)
3560 {
3561     auto *context = static_cast<FileAssetAsyncContext*>(data);
3562     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
3563     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
3564     jsContext->status = false;
3565 
3566     if (context->error == ERR_DEFAULT) {
3567         napi_create_int32(env, context->changedRows, &jsContext->data);
3568         jsContext->status = true;
3569         napi_get_undefined(env, &jsContext->error);
3570     } else {
3571         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->changedRows,
3572             "Failed to modify pending state");
3573         napi_get_undefined(env, &jsContext->data);
3574     }
3575 
3576     if (context->work != nullptr) {
3577         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3578             context->work, *jsContext);
3579     }
3580     delete context;
3581 }
3582 
PhotoAccessHelperSetPending(napi_env env,napi_callback_info info)3583 napi_value FileAssetNapi::PhotoAccessHelperSetPending(napi_env env, napi_callback_info info)
3584 {
3585     MediaLibraryTracer tracer;
3586     tracer.Start("PhotoAccessHelperSetPending");
3587 
3588     napi_value ret = nullptr;
3589     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3590     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "asyncContext context is null");
3591     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
3592     NAPI_ASSERT(
3593         env, MediaLibraryNapiUtils::ParseArgsBoolCallBack(env, info, asyncContext, asyncContext->isPending) == napi_ok,
3594         "Failed to parse js args");
3595     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3596     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "FileAsset is nullptr");
3597 
3598     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetPending",
3599         PhotoAccessHelperSetPendingExecute, PhotoAccessHelperSetPendingComplete);
3600 }
3601 
PhotoAccessHelperSetUserCommentComplete(napi_env env,napi_status status,void * data)3602 static void PhotoAccessHelperSetUserCommentComplete(napi_env env, napi_status status, void *data)
3603 {
3604     auto *context = static_cast<FileAssetAsyncContext*>(data);
3605     auto jsContext = make_unique<JSAsyncContextOutput>();
3606     jsContext->status = false;
3607 
3608     if (context->error == ERR_DEFAULT) {
3609         napi_create_int32(env, context->changedRows, &jsContext->data);
3610         jsContext->status = true;
3611         napi_get_undefined(env, &jsContext->error);
3612     } else {
3613         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
3614             "Failed to edit user comment");
3615         napi_get_undefined(env, &jsContext->data);
3616     }
3617 
3618     if (context->work != nullptr) {
3619         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
3620             context->work, *jsContext);
3621     }
3622     delete context;
3623 }
3624 
PhotoAccessHelperSetUserCommentExecute(napi_env env,void * data)3625 static void PhotoAccessHelperSetUserCommentExecute(napi_env env, void *data)
3626 {
3627     MediaLibraryTracer tracer;
3628     tracer.Start("PhotoAccessHelperSetUserCommentExecute");
3629 
3630     auto *context = static_cast<FileAssetAsyncContext *>(data);
3631     if (context->objectPtr->GetMediaType() != MEDIA_TYPE_IMAGE) {
3632         context->error = -EINVAL;
3633         return;
3634     }
3635 
3636     string uri = PAH_EDIT_USER_COMMENT_PHOTO;
3637     MediaLibraryNapiUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
3638     Uri editUserCommentUri(uri);
3639     DataSharePredicates predicates;
3640     DataShareValuesBucket valuesBucket;
3641     valuesBucket.Put(PhotoColumn::PHOTO_USER_COMMENT, context->userComment);
3642     predicates.SetWhereClause(MediaColumn::MEDIA_ID + " = ? ");
3643     predicates.SetWhereArgs({std::to_string(context->objectPtr->GetId())});
3644     int32_t changedRows = UserFileClient::Update(editUserCommentUri, predicates, valuesBucket);
3645     if (changedRows < 0) {
3646         context->SaveError(changedRows);
3647         NAPI_ERR_LOG("Failed to modify user comment, err: %{public}d", changedRows);
3648     } else {
3649         context->objectPtr->SetUserComment(context->userComment);
3650         context->changedRows = changedRows;
3651     }
3652 }
3653 
PhotoAccessHelperSetUserComment(napi_env env,napi_callback_info info)3654 napi_value FileAssetNapi::PhotoAccessHelperSetUserComment(napi_env env, napi_callback_info info)
3655 {
3656     MediaLibraryTracer tracer;
3657     tracer.Start("PhotoAccessHelperSetUserComment");
3658 
3659     unique_ptr<FileAssetAsyncContext> asyncContext = make_unique<FileAssetAsyncContext>();
3660     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
3661     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->userComment),
3662         JS_ERR_PARAMETER_INVALID);
3663     asyncContext->objectPtr = asyncContext->objectInfo->fileAssetPtr;
3664     if (asyncContext->objectPtr == nullptr) {
3665         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
3666         return nullptr;
3667     }
3668 
3669     if (asyncContext->userComment.length() > USER_COMMENT_MAX_LEN) {
3670         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "user comment too long");
3671         return nullptr;
3672     }
3673 
3674     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PhotoAccessHelperSetUserComment",
3675         PhotoAccessHelperSetUserCommentExecute, PhotoAccessHelperSetUserCommentComplete);
3676 }
3677 
3678 } // namespace Media
3679 } // namespace OHOS
3680