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