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