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