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