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